リビジョン b821d57d
app/Config/bootstrap.php | ||
---|---|---|
63 | 63 |
* Uncomment one of the lines below, as you need. Make sure you read the documentation on CakePlugin to use more |
64 | 64 |
* advanced ways of loading plugins |
65 | 65 |
* |
66 |
*CakePlugin::load('DebugKit'); // Loads a single plugin named DebugKit |
|
66 | 67 |
* CakePlugin::loadAll(); // Loads all plugins at once |
67 | 68 |
*/ |
68 |
CakePlugin::load('DebugKit'); // Loads a single plugin named DebugKit
|
|
69 |
CakePlugin::loadAll(); // Loads all plugins at once
|
|
69 | 70 |
|
70 | 71 |
/** |
71 | 72 |
* To prefer app translation over plugin translation, you can set |
app/Plugin/UploadPack/Model/Behavior/UploadBehavior.php | ||
---|---|---|
1 |
<?php |
|
2 |
App::uses('HttpSocket', 'Network/Http'); |
|
3 |
/** |
|
4 |
* This file is a part of UploadPack - a plugin that makes file uploads in CakePHP as easy as possible. |
|
5 |
* |
|
6 |
* UploadBehavior |
|
7 |
* |
|
8 |
* UploadBehavior does all the job of saving files to disk while saving records to database. For more info read UploadPack documentation. |
|
9 |
* |
|
10 |
* joe bartlett's lovingly handcrafted tweaks add several resize modes. see "more on styles" in the documentation. |
|
11 |
* |
|
12 |
* @author Michał Szajbe (michal.szajbe@gmail.com) and joe bartlett (contact@jdbartlett.com) |
|
13 |
* @link http://github.com/szajbus/uploadpack |
|
14 |
*/ |
|
15 |
class UploadBehavior extends ModelBehavior { |
|
16 |
|
|
17 |
private static $__settings = array(); |
|
18 |
|
|
19 |
private $toWrite = array(); |
|
20 |
|
|
21 |
private $toDelete = array(); |
|
22 |
|
|
23 |
private $maxWidthSize = false; |
|
24 |
|
|
25 |
public function setup(Model $model, $settings = array()) { |
|
26 |
$defaults = array( |
|
27 |
'path' => ':webroot/upload/:model/:id/:basename_:style.:extension', |
|
28 |
'styles' => array(), |
|
29 |
'resizeToMaxWidth' => false, |
|
30 |
'quality' => 75, |
|
31 |
'alpha' => false |
|
32 |
); |
|
33 |
|
|
34 |
foreach ($settings as $field => $array) { |
|
35 |
self::$__settings[$model->name][$field] = array_merge($defaults, $array); |
|
36 |
} |
|
37 |
} |
|
38 |
|
|
39 |
public function beforeSave(Model $model, $options = array()) { |
|
40 |
$this->_reset(); |
|
41 |
foreach (self::$__settings[$model->name] as $field => $settings) { |
|
42 |
if (!empty($model->data[$model->name][$field]) && is_array($model->data[$model->name][$field]) && file_exists($model->data[$model->name][$field]['tmp_name'])) { |
|
43 |
if (!empty($model->id)) { |
|
44 |
$this->_prepareToDeleteFiles($model, $field, true); |
|
45 |
} |
|
46 |
$this->_prepareToWriteFiles($model, $field); |
|
47 |
unset($model->data[$model->name][$field]); |
|
48 |
$model->data[$model->name][$field.'_file_name'] = $this->toWrite[$field]['name']; |
|
49 |
$model->data[$model->name][$field.'_file_size'] = $this->toWrite[$field]['size']; |
|
50 |
$model->data[$model->name][$field.'_content_type'] = $this->toWrite[$field]['type']; |
|
51 |
} elseif (array_key_exists($field, $model->data[$model->name]) && $model->data[$model->name][$field] === null) { |
|
52 |
if (!empty($model->id)) { |
|
53 |
$this->_prepareToDeleteFiles($model, $field, true); |
|
54 |
} |
|
55 |
unset($model->data[$model->name][$field]); |
|
56 |
$model->data[$model->name][$field.'_file_name'] = null; |
|
57 |
$model->data[$model->name][$field.'_file_size'] = null; |
|
58 |
$model->data[$model->name][$field.'_content_type'] = null; |
|
59 |
} |
|
60 |
} |
|
61 |
return true; |
|
62 |
} |
|
63 |
|
|
64 |
public function afterSave(Model $model, $create, $options = array()) { |
|
65 |
if (!$create) { |
|
66 |
$this->_deleteFiles($model); |
|
67 |
} |
|
68 |
$this->_writeFiles($model); |
|
69 |
} |
|
70 |
|
|
71 |
public function beforeDelete(Model $model, $cascade = true) { |
|
72 |
$this->_reset(); |
|
73 |
$this->_prepareToDeleteFiles($model); |
|
74 |
return true; |
|
75 |
} |
|
76 |
|
|
77 |
public function afterDelete(Model $model) { |
|
78 |
$this->_deleteFiles($model); |
|
79 |
} |
|
80 |
|
|
81 |
public function beforeValidate(Model $model, $options = array()) { |
|
82 |
foreach (self::$__settings[$model->name] as $field => $settings) { |
|
83 |
if (isset($model->data[$model->name][$field])) { |
|
84 |
$data = $model->data[$model->name][$field]; |
|
85 |
|
|
86 |
if ((empty($data) || is_array($data) && empty($data['tmp_name'])) && !empty($settings['urlField']) && !empty($model->data[$model->name][$settings['urlField']])) { |
|
87 |
$data = $model->data[$model->name][$settings['urlField']]; |
|
88 |
} |
|
89 |
|
|
90 |
if (!is_array($data)) { |
|
91 |
$model->data[$model->name][$field] = $this->_fetchFromUrl($data); |
|
92 |
} |
|
93 |
} |
|
94 |
} |
|
95 |
return true; |
|
96 |
} |
|
97 |
|
|
98 |
private function _reset() { |
|
99 |
$this->toWrite = null; |
|
100 |
$this->toDelete = null; |
|
101 |
} |
|
102 |
|
|
103 |
private function _fetchFromUrl($url) { |
|
104 |
$path_chunks = explode('/', $url); |
|
105 |
$filename_chunks = explode('.', $url); |
|
106 |
|
|
107 |
$data = array('remote' => true); |
|
108 |
$data['name'] = end($path_chunks); |
|
109 |
$data['tmp_name'] = tempnam(sys_get_temp_dir(), $data['name']) . '.' . end($filename_chunks); |
|
110 |
|
|
111 |
$httpSocket = new HttpSocket(); |
|
112 |
$raw = $httpSocket->get($url); |
|
113 |
$response = $httpSocket->response; |
|
114 |
$content_types = explode(';', $response['header']['Content-Type']); |
|
115 |
$data['size'] = strlen($raw); |
|
116 |
$data['type'] = reset($content_types); |
|
117 |
|
|
118 |
file_put_contents($data['tmp_name'], $raw); |
|
119 |
return $data; |
|
120 |
} |
|
121 |
|
|
122 |
private function _prepareToWriteFiles(&$model, $field) { |
|
123 |
$this->toWrite[$field] = $model->data[$model->name][$field]; |
|
124 |
// make filename URL friendly by using Cake's Inflector |
|
125 |
$this->toWrite[$field]['name'] = |
|
126 |
Inflector::slug(substr($this->toWrite[$field]['name'], 0, strrpos($this->toWrite[$field]['name'], '.'))). // filename |
|
127 |
substr($this->toWrite[$field]['name'], strrpos($this->toWrite[$field]['name'], '.')); // extension |
|
128 |
} |
|
129 |
|
|
130 |
protected function afterMove($file) { |
|
131 |
// do nothing here |
|
132 |
} |
|
133 |
|
|
134 |
private function _writeFiles(&$model) { |
|
135 |
if (!empty($this->toWrite)) { |
|
136 |
foreach ($this->toWrite as $field => $toWrite) { |
|
137 |
$settings = $this->_interpolate($model, $field, $toWrite['name'], 'original'); |
|
138 |
$destDir = dirname($settings['path']); |
|
139 |
if (!file_exists($destDir)) { |
|
140 |
@mkdir($destDir, 0777, true); |
|
141 |
@chmod($destDir, 0777); |
|
142 |
} |
|
143 |
if (is_dir($destDir) && is_writable($destDir)) { |
|
144 |
$move = !empty($toWrite['remote']) ? 'rename' : 'move_uploaded_file'; |
|
145 |
if (@$move($toWrite['tmp_name'], $settings['path'])) { |
|
146 |
$this->afterMove($settings['path']); // <==== Calling afterMove() callback method |
|
147 |
if($this->maxWidthSize) { |
|
148 |
$this->_resize($settings['path'], $settings['path'], $this->maxWidthSize.'w', $settings['quality'], $settings['alpha']); |
|
149 |
} |
|
150 |
foreach ($settings['styles'] as $style => $geometry) { |
|
151 |
$newSettings = $this->_interpolate($model, $field, $toWrite['name'], $style); |
|
152 |
$this->_resize($settings['path'], $newSettings['path'], $geometry, $settings['quality'], $settings['alpha']); |
|
153 |
} |
|
154 |
} |
|
155 |
} |
|
156 |
} |
|
157 |
} |
|
158 |
} |
|
159 |
|
|
160 |
private function _prepareToDeleteFiles(&$model, $field = null, $forceRead = false) { |
|
161 |
$needToRead = true; |
|
162 |
if ($field === null) { |
|
163 |
$fields = array_keys(self::$__settings[$model->name]); |
|
164 |
foreach ($fields as &$field) { |
|
165 |
$field .= '_file_name'; |
|
166 |
} |
|
167 |
} else { |
|
168 |
$field .= '_file_name'; |
|
169 |
$fields = array($field); |
|
170 |
} |
|
171 |
|
|
172 |
if (!$forceRead && !empty($model->data[$model->alias])) { |
|
173 |
$needToRead = false; |
|
174 |
foreach ($fields as $field) { |
|
175 |
if (!array_key_exists($field, $model->data[$model->alias])) { |
|
176 |
$needToRead = true; |
|
177 |
break; |
|
178 |
} |
|
179 |
} |
|
180 |
} |
|
181 |
if ($needToRead) { |
|
182 |
$data = $model->find('first', array('conditions' => array($model->alias.'.'.$model->primaryKey => $model->id), 'fields' => $fields, 'callbacks' => false)); |
|
183 |
} else { |
|
184 |
$data = $model->data; |
|
185 |
} |
|
186 |
if (is_array($this->toDelete)) { |
|
187 |
$this->toDelete = array_merge($this->toDelete, $data[$model->alias]); |
|
188 |
} else { |
|
189 |
$this->toDelete = $data[$model->alias]; |
|
190 |
} |
|
191 |
$this->toDelete['id'] = $model->id; |
|
192 |
} |
|
193 |
|
|
194 |
private function _deleteFiles(&$model) { |
|
195 |
foreach (self::$__settings[$model->name] as $field => $settings) { |
|
196 |
if (!empty($this->toDelete[$field.'_file_name'])) { |
|
197 |
$styles = array_keys($settings['styles']); |
|
198 |
$styles[] = 'original'; |
|
199 |
foreach ($styles as $style) { |
|
200 |
$settings = $this->_interpolate($model, $field, $this->toDelete[$field.'_file_name'], $style); |
|
201 |
if (file_exists($settings['path'])) { |
|
202 |
@unlink($settings['path']); |
|
203 |
} |
|
204 |
} |
|
205 |
} |
|
206 |
} |
|
207 |
} |
|
208 |
|
|
209 |
private function _interpolate(&$model, $field, $filename, $style) { |
|
210 |
return self::interpolate($model->name, $model->id, $field, $filename, $style); |
|
211 |
} |
|
212 |
|
|
213 |
static public function interpolate($modelName, $modelId, $field, $filename, $style = 'original', $defaults = array()) { |
|
214 |
$pathinfo = UploadBehavior::_pathinfo($filename); |
|
215 |
$interpolations = array_merge(array( |
|
216 |
'app' => preg_replace('/\/$/', '', APP), |
|
217 |
'webroot' => preg_replace('/\/$/', '', WWW_ROOT), |
|
218 |
'model' => Inflector::tableize($modelName), |
|
219 |
'basename' => !empty($filename) ? $pathinfo['filename'] : null, |
|
220 |
'extension' => !empty($filename) ? $pathinfo['extension'] : null, |
|
221 |
'id' => $modelId, |
|
222 |
'style' => $style, |
|
223 |
'attachment' => Inflector::pluralize($field), |
|
224 |
'hash' => md5((!empty($filename) ? $pathinfo['filename'] : "") . Configure::read('Security.salt')) |
|
225 |
), $defaults); |
|
226 |
$settings = self::$__settings[$modelName][$field]; |
|
227 |
$keys = array('path', 'url', 'default_url'); |
|
228 |
foreach ($interpolations as $k => $v) { |
|
229 |
foreach ($keys as $key) { |
|
230 |
if (isset($settings[$key])) { |
|
231 |
$settings[$key] = preg_replace('/\/{2,}/', '/', str_replace(":$k", $v, $settings[$key])); |
|
232 |
} |
|
233 |
} |
|
234 |
} |
|
235 |
return $settings; |
|
236 |
} |
|
237 |
|
|
238 |
static private function _pathinfo($filename) { |
|
239 |
$pathinfo = pathinfo($filename); |
|
240 |
// PHP < 5.2.0 doesn't include 'filename' key in pathinfo. Let's try to fix this. |
|
241 |
if (empty($pathinfo['filename'])) { |
|
242 |
$suffix = !empty($pathinfo['extension']) ? '.'.$pathinfo['extension'] : ''; |
|
243 |
$pathinfo['filename'] = basename($pathinfo['basename'], $suffix); |
|
244 |
} |
|
245 |
return $pathinfo; |
|
246 |
} |
|
247 |
|
|
248 |
private function _resize($srcFile, $destFile, $geometry, $quality = 75, $alpha = false) { |
|
249 |
copy($srcFile, $destFile); |
|
250 |
@chmod($destFile, 0777); |
|
251 |
$pathinfo = UploadBehavior::_pathinfo($srcFile); |
|
252 |
$src = null; |
|
253 |
$createHandler = null; |
|
254 |
$outputHandler = null; |
|
255 |
switch (strtolower($pathinfo['extension'])) { |
|
256 |
case 'gif': |
|
257 |
$createHandler = 'imagecreatefromgif'; |
|
258 |
$outputHandler = 'imagegif'; |
|
259 |
break; |
|
260 |
case 'jpg': |
|
261 |
case 'jpeg': |
|
262 |
$createHandler = 'imagecreatefromjpeg'; |
|
263 |
$outputHandler = 'imagejpeg'; |
|
264 |
break; |
|
265 |
case 'png': |
|
266 |
$createHandler = 'imagecreatefrompng'; |
|
267 |
$outputHandler = 'imagepng'; |
|
268 |
$quality = null; |
|
269 |
break; |
|
270 |
default: |
|
271 |
return false; |
|
272 |
} |
|
273 |
if ($src = $createHandler($destFile)) { |
|
274 |
$srcW = imagesx($src); |
|
275 |
$srcH = imagesy($src); |
|
276 |
|
|
277 |
// determine destination dimensions and resize mode from provided geometry |
|
278 |
if (preg_match('/^\\[[\\d]+x[\\d]+\\]$/', $geometry)) { |
|
279 |
// resize with banding |
|
280 |
list($destW, $destH) = explode('x', substr($geometry, 1, strlen($geometry)-2)); |
|
281 |
$resizeMode = 'band'; |
|
282 |
} elseif (preg_match('/^[\\d]+x[\\d]+$/', $geometry)) { |
|
283 |
// cropped resize (best fit) |
|
284 |
list($destW, $destH) = explode('x', $geometry); |
|
285 |
$resizeMode = 'best'; |
|
286 |
} elseif (preg_match('/^[\\d]+w$/', $geometry)) { |
|
287 |
// calculate heigh according to aspect ratio |
|
288 |
$destW = (int)$geometry-1; |
|
289 |
$resizeMode = false; |
|
290 |
} elseif (preg_match('/^[\\d]+h$/', $geometry)) { |
|
291 |
// calculate width according to aspect ratio |
|
292 |
$destH = (int)$geometry-1; |
|
293 |
$resizeMode = false; |
|
294 |
} elseif (preg_match('/^[\\d]+l$/', $geometry)) { |
|
295 |
// calculate shortest side according to aspect ratio |
|
296 |
if ($srcW > $srcH) $destW = (int)$geometry-1; |
|
297 |
else $destH = (int)$geometry-1; |
|
298 |
$resizeMode = false; |
|
299 |
} |
|
300 |
if (!isset($destW)) $destW = ($destH/$srcH) * $srcW; |
|
301 |
if (!isset($destH)) $destH = ($destW/$srcW) * $srcH; |
|
302 |
|
|
303 |
// determine resize dimensions from appropriate resize mode and ratio |
|
304 |
if ($resizeMode == 'best') { |
|
305 |
// "best fit" mode |
|
306 |
if ($srcW > $srcH) { |
|
307 |
if ($srcH/$destH > $srcW/$destW) $ratio = $destW/$srcW; |
|
308 |
else $ratio = $destH/$srcH; |
|
309 |
} else { |
|
310 |
if ($srcH/$destH < $srcW/$destW) $ratio = $destH/$srcH; |
|
311 |
else $ratio = $destW/$srcW; |
|
312 |
} |
|
313 |
$resizeW = $srcW*$ratio; |
|
314 |
$resizeH = $srcH*$ratio; |
|
315 |
} |
|
316 |
elseif ($resizeMode == 'band') { |
|
317 |
// "banding" mode |
|
318 |
if ($srcW > $srcH) $ratio = $destW/$srcW; |
|
319 |
else $ratio = $destH/$srcH; |
|
320 |
$resizeW = $srcW*$ratio; |
|
321 |
$resizeH = $srcH*$ratio; |
|
322 |
} |
|
323 |
else { |
|
324 |
// no resize ratio |
|
325 |
$resizeW = $destW; |
|
326 |
$resizeH = $destH; |
|
327 |
} |
|
328 |
|
|
329 |
$img = imagecreatetruecolor($destW, $destH); |
|
330 |
if ($alpha === true) { |
|
331 |
switch (strtolower($pathinfo['extension'])) { |
|
332 |
case 'gif': |
|
333 |
$alphaColor = imagecolortransparent($src); |
|
334 |
imagefill($img, 0, 0, $alphaColor); |
|
335 |
imagecolortransparent($img, $alphaColor); |
|
336 |
break; |
|
337 |
case 'png': |
|
338 |
imagealphablending($img, false); |
|
339 |
imagesavealpha($img, true); |
|
340 |
break; |
|
341 |
default: |
|
342 |
imagefill($img, 0, 0, imagecolorallocate($img, 255, 255, 255)); |
|
343 |
break; |
|
344 |
} |
|
345 |
} else { |
|
346 |
imagefill($img, 0, 0, imagecolorallocate($img, 255, 255, 255)); |
|
347 |
} |
|
348 |
imagecopyresampled($img, $src, ($destW-$resizeW)/2, ($destH-$resizeH)/2, 0, 0, $resizeW, $resizeH, $srcW, $srcH); |
|
349 |
$outputHandler($img, $destFile, $quality); |
|
350 |
return true; |
|
351 |
} |
|
352 |
return false; |
|
353 |
} |
|
354 |
|
|
355 |
public function attachmentMinSize(Model $model, $value, $min, $options = array()) { |
|
356 |
$value = array_shift($value); |
|
357 |
if (!empty($value['tmp_name'])) { |
|
358 |
return (int)$min <= (int)$value['size']; |
|
359 |
} else if (isset($options['allowEmpty']) && $options['allowEmpty'] === false) { |
|
360 |
return false; |
|
361 |
} |
|
362 |
return true; |
|
363 |
} |
|
364 |
|
|
365 |
public function attachmentMaxSize(Model $model, $value, $max, $options = array()) { |
|
366 |
$value = array_shift($value); |
|
367 |
if (!empty($value['tmp_name'])) { |
|
368 |
return (int)$value['size'] <= (int)$max; |
|
369 |
} else if (isset($options['allowEmpty']) && $options['allowEmpty'] === false) { |
|
370 |
return false; |
|
371 |
} |
|
372 |
return true; |
|
373 |
} |
|
374 |
|
|
375 |
public function attachmentContentType(Model $model, $value, $contentTypes, $options = array()) { |
|
376 |
$value = array_shift($value); |
|
377 |
if (!is_array($contentTypes)) { |
|
378 |
$contentTypes = array($contentTypes); |
|
379 |
} |
|
380 |
if (!empty($value['tmp_name'])) { |
|
381 |
foreach ($contentTypes as $contentType) { |
|
382 |
if (substr($contentType, 0, 1) == '/') { |
|
383 |
if (preg_match($contentType, $value['type'])) { |
|
384 |
return true; |
|
385 |
} |
|
386 |
} elseif ($contentType == $value['type']) { |
|
387 |
return true; |
|
388 |
} |
|
389 |
} |
|
390 |
return false; |
|
391 |
} else if (isset($options['allowEmpty']) && $options['allowEmpty'] === false) { |
|
392 |
return false; |
|
393 |
} |
|
394 |
return true; |
|
395 |
} |
|
396 |
|
|
397 |
public function attachmentPresence(Model $model, $value, $options = array()) { |
|
398 |
$keys = array_keys($value); |
|
399 |
$field = $keys[0]; |
|
400 |
$value = array_shift($value); |
|
401 |
|
|
402 |
if (!empty($value['tmp_name'])) { |
|
403 |
return true; |
|
404 |
} |
|
405 |
|
|
406 |
if (!empty($model->id)) { |
|
407 |
if (!empty($model->data[$model->alias][$field.'_file_name'])) { |
|
408 |
return true; |
|
409 |
} elseif (!isset($model->data[$model->alias][$field.'_file_name'])) { |
|
410 |
$existingFile = $model->field($field.'_file_name', array($model->primaryKey => $model->id)); |
|
411 |
if (!empty($existingFile)) { |
|
412 |
return true; |
|
413 |
} |
|
414 |
} |
|
415 |
} |
|
416 |
return false; |
|
417 |
} |
|
418 |
|
|
419 |
public function minWidth(Model $model, $value, $minWidth, $options = array()) { |
|
420 |
return $this->_validateDimension($value, 'min', 'x', $minWidth, $options); |
|
421 |
} |
|
422 |
|
|
423 |
public function minHeight(Model $model, $value, $minHeight, $options = array()) { |
|
424 |
return $this->_validateDimension($value, 'min', 'y', $minHeight, $options); |
|
425 |
} |
|
426 |
|
|
427 |
public function maxWidth(Model $model, $value, $maxWidth, $options = array()) { |
|
428 |
$keys = array_keys($value); |
|
429 |
$field = $keys[0]; |
|
430 |
$settings = self::$__settings[$model->name][$field]; |
|
431 |
if($settings['resizeToMaxWidth'] && !$this->_validateDimension($value, 'max', 'x', $maxWidth, $options)) { |
|
432 |
$this->maxWidthSize = $maxWidth; |
|
433 |
return true; |
|
434 |
} else { |
|
435 |
return $this->_validateDimension($value, 'max', 'x', $maxWidth, $options); |
|
436 |
} |
|
437 |
} |
|
438 |
|
|
439 |
public function maxHeight(Model $model, $value, $maxHeight, $options = array()) { |
|
440 |
return $this->_validateDimension($value, 'max', 'y', $maxHeight, $options); |
|
441 |
} |
|
442 |
|
|
443 |
private function _validateDimension($upload, $mode, $axis, $value, $options) { |
|
444 |
$upload = array_shift($upload); |
|
445 |
$func = 'images'.$axis; |
|
446 |
if(!empty($upload['tmp_name'])) { |
|
447 |
$createHandler = null; |
|
448 |
if($upload['type'] == 'image/jpeg') { |
|
449 |
$createHandler = 'imagecreatefromjpeg'; |
|
450 |
} else if($upload['type'] == 'image/gif') { |
|
451 |
$createHandler = 'imagecreatefromgif'; |
|
452 |
} else if($upload['type'] == 'image/png') { |
|
453 |
$createHandler = 'imagecreatefrompng'; |
|
454 |
} else { |
|
455 |
return false; |
|
456 |
} |
|
457 |
|
|
458 |
if($img = $createHandler($upload['tmp_name'])) { |
|
459 |
switch ($mode) { |
|
460 |
case 'min': |
|
461 |
return $func($img) >= $value; |
|
462 |
break; |
|
463 |
case 'max': |
|
464 |
return $func($img) <= $value; |
|
465 |
break; |
|
466 |
} |
|
467 |
} |
|
468 |
} else if (isset($options['allowEmpty']) && $options['allowEmpty'] === true) { |
|
469 |
return true; |
|
470 |
} |
|
471 |
return false; |
|
472 |
} |
|
473 |
|
|
474 |
public function phpUploadError(Model $model, $value, $uploadErrors = array('UPLOAD_ERR_INI_SIZE', 'UPLOAD_ERR_FORM_SIZE', 'UPLOAD_ERR_PARTIAL', 'UPLOAD_ERR_NO_FILE', 'UPLOAD_ERR_NO_TMP_DIR', 'UPLOAD_ERR_CANT_WRITE', 'UPLOAD_ERR_EXTENSION'), $options = array()) { |
|
475 |
$value = array_shift($value); |
|
476 |
if (!is_array($uploadErrors)) { |
|
477 |
$uploadErrors = array($uploadErrors); |
|
478 |
} |
|
479 |
if (!empty($value['error'])) { |
|
480 |
return !in_array($value['error'], $uploadErrors); |
|
481 |
} else if (isset($options['allowEmpty']) && $options['allowEmpty'] === false) { |
|
482 |
return false; |
|
483 |
} |
|
484 |
return true; |
|
485 |
} |
|
486 |
} |
app/Plugin/UploadPack/README.textile | ||
---|---|---|
1 |
h1. UploadPack |
|
2 |
|
|
3 |
"!https://pledgie.com/campaigns/7880.png?skin_name=chrome!(Using it in production? Share some love...)":https://www.pledgie.com/campaigns/7880 |
|
4 |
|
|
5 |
UploadPack is a plugin that makes file uploads in CakePHP as easy as possible. It works with almost no configuration, but if you need more flexibility you can easily override default settings. |
|
6 |
|
|
7 |
What's included: |
|
8 |
|
|
9 |
h4. UploadBehavior |
|
10 |
|
|
11 |
Attach it to your model, it will detect any uploaded file and save it to disk. It can even automatically generate thumbnails of uploaded images. |
|
12 |
|
|
13 |
h4. UploadHelper |
|
14 |
|
|
15 |
Use it in your views to display uploaded images or links to files in general. |
|
16 |
|
|
17 |
h2. Installation |
|
18 |
|
|
19 |
# Download this: _http://github.com/szajbus/uploadpack/zipball/master_ |
|
20 |
# Unzip that download. |
|
21 |
# Copy the resulting folder to _app/plugins_ |
|
22 |
# Rename the folder you just copied to _upload_pack_ |
|
23 |
|
|
24 |
h2. Usage |
|
25 |
|
|
26 |
Look at an example. |
|
27 |
|
|
28 |
Scenario: Let users upload their avatars and then display them in two styles - original size and thumbnail. |
|
29 |
|
|
30 |
Solution: |
|
31 |
|
|
32 |
We'll need @User@ model with @avatar_file_name@ field. |
|
33 |
|
|
34 |
<pre><code>CREATE table users ( |
|
35 |
id int(10) unsigned NOT NULL auto_increment, |
|
36 |
login varchar(20) NOT NULL, |
|
37 |
avatar_file_name varchar(255) |
|
38 |
); |
|
39 |
</code></pre> |
|
40 |
|
|
41 |
Attach @UploadBehavior@ to @User@ model and set it up to handle avatars. |
|
42 |
|
|
43 |
<pre><code><?php |
|
44 |
class User extends AppModel { |
|
45 |
var $name = 'User'; |
|
46 |
var $actsAs = array( |
|
47 |
'UploadPack.Upload' => array( |
|
48 |
'avatar' => array( |
|
49 |
'styles' => array( |
|
50 |
'thumb' => '80x80' |
|
51 |
) |
|
52 |
) |
|
53 |
) |
|
54 |
); |
|
55 |
} |
|
56 |
?> |
|
57 |
</code></pre> |
|
58 |
|
|
59 |
That's all we need to do with our model. We defined one thumbnail style named 'thumb' which means that uploaded image's thumnbnail of 80x80 pixels size will be generated and saved to disk together with original image. |
|
60 |
|
|
61 |
We didn't touch any other configuration settings so files will be saved as @webroot/upload/:model/:id/:basename_:style.:extension@ (with :keys appropriately substituted at run time). Make sure that @webroot/upload/users@ folder is writeable. |
|
62 |
|
|
63 |
Let's upload a file now. We need to add a file field to a standard "create user" form. Your form must have the right enctype attribute to support file uploads, e.g. @$form->create('Users', array('type' => 'file'));@. Note that we omit the field's @_file_name@ suffix here. |
|
64 |
|
|
65 |
<pre><code><?php echo $form->file('User.avatar') ?></code></pre> |
|
66 |
|
|
67 |
The last thing to do is to handle form-submit in a controller. |
|
68 |
|
|
69 |
<pre><code><?php |
|
70 |
class UsersController extends AppController { |
|
71 |
var $name = 'Users'; |
|
72 |
var $uses = array('User'); |
|
73 |
var $helpers = array('Form', 'UploadPack.Upload'); |
|
74 |
|
|
75 |
function create() { |
|
76 |
if (!empty($this->data)) { |
|
77 |
$this->User->create($this->data); |
|
78 |
if ($this->User->save()) { |
|
79 |
$this->redirect('/users/show/'.$this->User->id); |
|
80 |
} |
|
81 |
} |
|
82 |
} |
|
83 |
|
|
84 |
function show($id) { |
|
85 |
$this->set('user', $this->User->findById($id)); |
|
86 |
} |
|
87 |
} |
|
88 |
?> |
|
89 |
</code></pre> |
|
90 |
|
|
91 |
Let's create @users/show.ctp@ view to see the results. Note that we've included UploadHelper in controller's $helpers. |
|
92 |
|
|
93 |
<pre><code>That would be the original file: |
|
94 |
<?php echo $this->Upload->uploadImage($user, 'User.avatar') ?> |
|
95 |
|
|
96 |
And now it's thumbnail: |
|
97 |
<?php echo $this->Upload->uploadImage($user, 'User.avatar', array('style' => 'thumb')) ?> |
|
98 |
</code></pre> |
|
99 |
|
|
100 |
That's how you create new records with uploaded files. Updating existing record would delete a file attached to it from disk. |
|
101 |
|
|
102 |
Could it be any easier? Probably not. Is there more to offer? Yes. |
|
103 |
|
|
104 |
h3. Advanced configuration |
|
105 |
|
|
106 |
h4. You can validate uploaded files |
|
107 |
|
|
108 |
@UploadBehavior@ provides some validation rules for you to use together with standard CakePHP validation mechanism. |
|
109 |
|
|
110 |
Validate attachment's size: |
|
111 |
|
|
112 |
<pre><code>var $validate = array( |
|
113 |
'avatar' => array( |
|
114 |
'maxSize' => array( |
|
115 |
'rule' => array('attachmentMaxSize', 1048576), |
|
116 |
'message' => 'Avatar can\'t be larger than 1MB' |
|
117 |
), |
|
118 |
'minSize' => array( |
|
119 |
'rule' => array('attachmentMinSize', 1024), |
|
120 |
'message' => 'Avatar can\'t be smaller than 1KB' |
|
121 |
) |
|
122 |
) |
|
123 |
); |
|
124 |
</code></pre> |
|
125 |
|
|
126 |
Validate attachment's content type: |
|
127 |
|
|
128 |
<pre><code>var $validate = array( |
|
129 |
'avatar' => array( |
|
130 |
'image1 => array( |
|
131 |
'rule' => array('attachmentContentType', 'image/jpeg'), |
|
132 |
'message' => 'Only jpegs please' |
|
133 |
), |
|
134 |
'image2' => array( |
|
135 |
'rule' => array('attachmentContentType', array('image/jpeg', 'image/gif')), |
|
136 |
'message' => 'Only jpegs or gifs please' |
|
137 |
), |
|
138 |
'image3' => array( |
|
139 |
'rule' => array('attachmentContentType', array('document/pdf', '/^image\/.+/')), |
|
140 |
'message' => 'Only pdfs or images please' |
|
141 |
) |
|
142 |
) |
|
143 |
); |
|
144 |
</code></pre> |
|
145 |
|
|
146 |
Validate attachment's presence: |
|
147 |
|
|
148 |
<pre><code>var $validate = array( |
|
149 |
'avatar' => array( |
|
150 |
'rule' => array('attachmentPresence'), |
|
151 |
'message' => 'Avatar is required' |
|
152 |
) |
|
153 |
); |
|
154 |
</code></pre> |
|
155 |
|
|
156 |
Validate image size: |
|
157 |
<pre><code>var $validate = array( |
|
158 |
'avatar' => array( |
|
159 |
'minWidth' => array( |
|
160 |
'rule' => array('minWidth', '100'), |
|
161 |
'message' => 'Photo must be at least 100 pixels wide' |
|
162 |
), |
|
163 |
'maxWidth' => array( |
|
164 |
'rule' => array('maxWidth', '600'), |
|
165 |
'message' => 'Photo can\'t be over 600 pixels wide' |
|
166 |
), |
|
167 |
'minHeight' => array( |
|
168 |
'rule' => array('minHeight', '100'), |
|
169 |
'message' => 'Photo must be at least 100 pixels wide' |
|
170 |
), |
|
171 |
'maxHeight' => array( |
|
172 |
'rule' => array('maxHeight', '600'), |
|
173 |
'message' => 'Photo can\'t be over 600 pixels wide' |
|
174 |
) |
|
175 |
) |
|
176 |
); |
|
177 |
</code></pre> |
|
178 |
|
|
179 |
If you're editing a record that already has avatar attached and you don't supply a new one, record will be valid. |
|
180 |
|
|
181 |
Validate php upload errors: |
|
182 |
PHP: Error Messages Explained - Manual (http://www.php.net/manual/features.file-upload.errors.php) |
|
183 |
<pre><code>var $validate = array( |
|
184 |
'avatar' => array( |
|
185 |
'checkIniSizeError' => array( |
|
186 |
'rule' => array('phpUploadError', UPLOAD_ERR_INI_SIZE), |
|
187 |
'message' => 'The uploaded file exceeds the upload_max_filesize directive in php.ini' |
|
188 |
), |
|
189 |
'checkSizesError' => array( |
|
190 |
'rule' => array('phpUploadError', array(UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE)), |
|
191 |
'message' => 'The uploaded file exceeds the upload_max_filesize directive in php.ini or MAX_FILE_SIZE directive that was specified in the HTML form' |
|
192 |
), |
|
193 |
'checkAllError' => array( |
|
194 |
'rule' => array('phpUploadError'), |
|
195 |
'message' => 'Can\'t upload' |
|
196 |
) |
|
197 |
) |
|
198 |
); |
|
199 |
</code></pre> |
|
200 |
|
|
201 |
Validation options: |
|
202 |
|
|
203 |
You can pass additional options to validation rules: |
|
204 |
|
|
205 |
* *allowEmpty* - if set to _false_ will cause validation to fail if the file is not present. This option is not available for _attachmentPresence_ rule. |
|
206 |
|
|
207 |
The example below return true if there is no upload files or jpeg. |
|
208 |
<pre><code>var $validate = array( |
|
209 |
'avatar' => array( |
|
210 |
'rule' => array('attachmentContentType', 'image/jpeg'), |
|
211 |
'message' => 'Only jpegs please', |
|
212 |
'allowEmpty' => true |
|
213 |
) |
|
214 |
); |
|
215 |
</code></pre> |
|
216 |
|
|
217 |
h4. You can change the path where the files are saved |
|
218 |
|
|
219 |
<pre><code>var $actsAs = array( |
|
220 |
'UploadPack.Upload' => array( |
|
221 |
'avatar' => array( |
|
222 |
'path' => 'your/new/path' |
|
223 |
) |
|
224 |
) |
|
225 |
); |
|
226 |
</code></pre> |
|
227 |
|
|
228 |
The path string can contain special :keys that will be substituted at run time with appropriate values. Here's the list of available @:keys@ with the values they're substituted with. |
|
229 |
|
|
230 |
* *:app* - path to your app dir |
|
231 |
* *:webroot* - path to your app's webroot dir |
|
232 |
* *:model* - name of the model tableized with Inflector::tableize (would be 'users' for User model) |
|
233 |
* *:id* - ID of the record |
|
234 |
* *:basename* - basename of the uploaded file's original name (would be 'photo' for photo.jpg) |
|
235 |
* *:extension* - extension of the uploaded file's original name (would be 'jpg' for photo.jpg) |
|
236 |
* *:style* - name of the thumbnail's style |
|
237 |
* *:attachment* - pluralized name of the attachment (for example 'avatars') |
|
238 |
* *:hash* - md5 hash of the original filename + Security.salt |
|
239 |
|
|
240 |
Default value for path is @:webroot/upload/:model/:id/:basename_:style.:extension@. |
|
241 |
|
|
242 |
h4. You can change the url the helper points to when displaying or linking to uploaded files |
|
243 |
|
|
244 |
This setting accepts all the :keys mentioned above and it's default value depends on path setting. For default path it would be defaults @/upload/:model/:id/:basename_:style.:extension@. |
|
245 |
|
|
246 |
You probably won't need to change it too often, though. |
|
247 |
|
|
248 |
h4. You can point to default url if the uploaded file is missing |
|
249 |
|
|
250 |
If uploading an avatar is only a option to your users, you would probably want to have some default image being displayed if no image is uploaded by a user. |
|
251 |
|
|
252 |
<pre><code>var $actsAs = array( |
|
253 |
'UploadPack.Upload' => array( |
|
254 |
'avatar' => array( |
|
255 |
'default_url' => 'path/to/default/image' |
|
256 |
) |
|
257 |
) |
|
258 |
); |
|
259 |
</code></pre> |
|
260 |
|
|
261 |
This setting accepts all the @:keys@ mentioned above, but it's not set by default which results in usual url being returned even it the file does not exist. |
|
262 |
|
|
263 |
h4. You can choose to automatically scale down images that are wider than the <code>maxWidth</code> specified in validation. |
|
264 |
|
|
265 |
<pre><code>var $actsAs = array( |
|
266 |
'UploadPack.Upload' => array( |
|
267 |
'avatar' => array( |
|
268 |
'resizeToMaxWidth' => true |
|
269 |
) |
|
270 |
) |
|
271 |
); |
|
272 |
</code></pre> |
|
273 |
|
|
274 |
h4. JPEG Quality |
|
275 |
|
|
276 |
The jpeg quality can be set with the <code>quality</code> setting. |
|
277 |
|
|
278 |
<pre><code>var $actsAs = array( |
|
279 |
'UploadPack.Upload' => array( |
|
280 |
'avatar' => array( |
|
281 |
'quality' => 95 |
|
282 |
) |
|
283 |
) |
|
284 |
); |
|
285 |
</code></pre> |
|
286 |
|
|
287 |
h4. Alpha Channel(PNG, GIF only) |
|
288 |
|
|
289 |
The png and gif can use alpha channel <code>alpha</code> setting. |
|
290 |
|
|
291 |
<pre><code>var $actsAs = array( |
|
292 |
'UploadPack.Upload' => array( |
|
293 |
'avatar' => array( |
|
294 |
'alpha' => true |
|
295 |
) |
|
296 |
) |
|
297 |
); |
|
298 |
</code></pre> |
|
299 |
|
|
300 |
h4. You can choose another field for an external url |
|
301 |
|
|
302 |
<pre><code>var $actsAs = array( |
|
303 |
'UploadPack.Upload' => array( |
|
304 |
'avatar' => array( |
|
305 |
'urlField' => 'gravatar' |
|
306 |
) |
|
307 |
) |
|
308 |
); |
|
309 |
</code></pre> |
|
310 |
|
|
311 |
This way the user can paste an url or choose a file from their filesystem. The url will mimick usual uploading so it will still be validated and resized. |
|
312 |
|
|
313 |
h4. Deleting a file attached to field |
|
314 |
|
|
315 |
<pre><code>$model->data['avatar'] = null; |
|
316 |
$model->save(); |
|
317 |
</code></pre> |
|
318 |
|
|
319 |
h3. More on styles |
|
320 |
|
|
321 |
Styles are the definition of thumbnails that will be generated for original image. You can define as many as you want. |
|
322 |
|
|
323 |
<pre><code>var $actsAs = array( |
|
324 |
'UploadPack.Upload' => array( |
|
325 |
'avatar' => array( |
|
326 |
'styles' => array( |
|
327 |
'big' => '200x200', |
|
328 |
'small' => '120x120', |
|
329 |
'thumb' => '80x80' |
|
330 |
) |
|
331 |
) |
|
332 |
) |
|
333 |
); |
|
334 |
</code></pre> |
|
335 |
|
|
336 |
Be sure to have @:style@ key included in your path setting to differentiate file names. The original file is also saved and has 'original' as @:style@ value, so you don't need it to define it yourself. |
|
337 |
|
|
338 |
If you want non-image files to be uploaded, define no styles at all. It does not make much sense to generate thumbnails for zip or pdf files. |
|
339 |
|
|
340 |
You can specify any of the following resize modes for your styles: |
|
341 |
|
|
342 |
* *100x80* - resize for best fit into these dimensions, with overlapping edges trimmed if original aspect ratio differs |
|
343 |
* *[100x80]* - resize to fit these dimensions, with white banding if original aspect ratio differs (Michał's original resize method) |
|
344 |
* *100w* - maintain original aspect ratio, resize to 100 pixels wide |
|
345 |
* *80h* - maintain original aspect ratio, resize to 80 pixels high |
|
346 |
* *80l* - maintain original aspect ratio, resize so that longest side is 80 pixels |
|
347 |
|
|
348 |
h3. More on database table structure |
|
349 |
|
|
350 |
The only database field you need to add to your model's table is @[field]_file_name@. Replace @[field]@ with chosen name (avatar for example). |
|
351 |
|
|
352 |
There are two optional fields you can add: @[field]_content_type@ and @[field]_file_size@. If they're present they will be populated with uploaded file's content type and size in bytes respectively. |
|
353 |
|
|
354 |
Model can have many uploaded files at once. For example define two fields in database table: @avatar_file_name@ and @logo_file_name@. Set up behavior: |
|
355 |
|
|
356 |
<pre><code>var $actsAs = array( |
|
357 |
'UploadPack.Upload' => array( |
|
358 |
'avatar' => array(), |
|
359 |
'logo' => array() |
|
360 |
) |
|
361 |
) |
|
362 |
); |
|
363 |
</code></pre> |
|
364 |
|
|
365 |
h3. Using the helper |
|
366 |
|
|
367 |
There are two methods of UploadHelper you can use: |
|
368 |
|
|
369 |
h4. UploadHelper::uploadUrl($data, $field, $options = array()) |
|
370 |
|
|
371 |
Returns url to the uploaded file |
|
372 |
|
|
373 |
* *$data* - record from database (would be @$user@ here) |
|
374 |
* *$field* - name of a field, like this @Modelname.fieldname@ (would be @User.avatar@ here) |
|
375 |
* *$options* - url options |
|
376 |
** *'style'* - name of a thumbnail's style |
|
377 |
** *'urlize'* - if true returned url is wrapped with @$html->url()@ |
|
378 |
|
|
379 |
h4. UploadHelper::uploadImage($data, $field, $options = array(), $htmlOptions = array()) |
|
380 |
|
|
381 |
Returns image tag pointing to uploaded file. |
|
382 |
|
|
383 |
* *$data* - record from database (would be @$user@ here) |
|
384 |
* *$field* - name of a field, like this @Modelname.fieldname@ (would be @User.avatar@ here) |
|
385 |
* *$options* - url options |
|
386 |
** *'style'* - name of a thumbnail's style |
|
387 |
** *'urlize'* - if true returned url is wrapped with @$html->url()@ |
|
388 |
* *$htmlOptions* - array of HTML attributes passed to @$html->image()@ |
|
389 |
|
|
390 |
Assuming that you have read a user from database and it's available in @$user@ variable in view. |
|
391 |
|
|
392 |
<pre><code><?php echo $this->Upload->uploadImage($user, 'User.avatar', array('style' => 'thumb')); ?></code></pre> |
|
393 |
|
|
394 |
When you fetch user from database you would usually get: |
|
395 |
|
|
396 |
<pre><code>$user = array( |
|
397 |
'User' => array( |
|
398 |
'id' => 1, |
|
399 |
'avatar_file_name' => 'photo.jpg' |
|
400 |
) |
|
401 |
); |
|
402 |
</code></pre> |
|
403 |
|
|
404 |
But when the user is fetched as one of many users associated by hasMany association to another model it could be something like: |
|
405 |
|
|
406 |
<pre><code>$data = array( |
|
407 |
'User' => array( |
|
408 |
0 => array( |
|
409 |
'id' => 1, |
|
410 |
'avatar_file_name' => 'photo.jpg' |
|
411 |
), |
|
412 |
1 => array( |
|
413 |
'id' => 2, |
|
414 |
'avatar_file_name' => 'photo2.jpg' |
|
415 |
) |
|
416 |
) |
|
417 |
); |
|
418 |
</code></pre> |
|
419 |
|
|
420 |
Then you should do: |
|
421 |
|
|
422 |
<pre><code><?php echo $this->Upload->uploadImage($data['User'][0], 'User.avatar', array('style' => 'thumb')) ?></code></pre> |
|
423 |
|
|
424 |
The helper is smart enough to figure out the structure of data you pass to it. |
|
425 |
|
|
426 |
h3. Requirements |
|
427 |
|
|
428 |
UploadPack was developed with CakePHP 1.2 RC3, so it's not guaranteed to work with previous versions. You'll need GD library if you plan to generate image thumbnails. It works OK with 2.0.34 version at least, earlier versions may work too. |
|
429 |
|
|
430 |
h2. Plans for future |
|
431 |
|
|
432 |
There is still something missing in UploadPack, here's what will be added soon: |
|
433 |
|
|
434 |
* file name normalization |
|
435 |
|
|
436 |
The plans for more distant future: |
|
437 |
|
|
438 |
* test coverage |
|
439 |
* allow uploads to S3 |
|
440 |
* provide a method to regenerate all thumbnails, helpful if you later decide to have different sizes of thumbnails or more styles |
|
441 |
|
|
442 |
I you want to help implementing these features, feel free to submit your patches. |
|
443 |
|
|
444 |
h2. Copyright |
|
445 |
|
|
446 |
Copyright (c) 2008 Michał Szajbe (http://codetunes.com), released under the MIT license. |
|
447 |
|
|
448 |
joe bartlett's (http://jdbartlett.com) tweaks aren't under copyright. Run free, little tweaks! |
app/Plugin/UploadPack/VERSION | ||
---|---|---|
1 |
UploadPack 0.7.2 |
app/Plugin/UploadPack/View/Helper/UploadHelper.php | ||
---|---|---|
1 |
<?php |
|
2 |
App::uses('UploadBehavior', 'UploadPack.Model/Behavior'); |
|
3 |
/** |
|
4 |
* This file is a part of UploadPack - a plugin that makes file uploads in CakePHP as easy as possible. |
|
5 |
* |
|
6 |
* UploadHelper |
|
7 |
* |
|
8 |
* UploadHelper provides fine access to files uploaded with UploadBehavior. It generates url for those files and can display image tags of uploaded images. For more info read UploadPack documentation. |
|
9 |
* |
|
10 |
* @author Michał Szajbe (michal.szajbe@gmail.com) |
|
11 |
* @link http://github.com/szajbus/uploadpack |
|
12 |
*/ |
|
13 |
class UploadHelper extends AppHelper { |
|
14 |
|
|
15 |
public $helpers = array('Html'); |
|
16 |
|
|
17 |
public function uploadImage($data, $path, $options = array(), $htmlOptions = array()) |
|
18 |
{ |
|
19 |
$options += array('urlize' => false); |
|
20 |
return $this->output($this->Html->image($this->uploadUrl($data, $path, $options), $htmlOptions)); |
|
21 |
} |
|
22 |
|
|
23 |
public function uploadLink($title, $data, $field, $urlOptions = array(), $htmlOptions = array()) |
|
24 |
{ |
|
25 |
$urlOptions += array('style' => 'original', 'urlize' => true); |
|
26 |
return $this->Html->link($title, $this->uploadUrl($data, $field, $urlOptions), $htmlOptions); |
|
27 |
} |
|
28 |
|
|
29 |
public function uploadUrl($data, $field, $options = array()) |
|
30 |
{ |
|
31 |
$options += array('style' => 'original', 'urlize' => true); |
|
32 |
list($model, $field) = explode('.', $field); |
|
33 |
if(is_array($data)) |
|
34 |
{ |
|
35 |
if(isset($data[$model])) |
|
36 |
{ |
|
37 |
if(isset($data[$model]['id'])) |
|
38 |
{ |
|
39 |
$id = $data[$model]['id']; |
|
40 |
$filename = $data[$model][$field.'_file_name']; |
|
41 |
} |
|
42 |
} |
|
43 |
elseif(isset($data['id'])) |
|
44 |
{ |
|
45 |
$id = $data['id']; |
|
46 |
$filename = $data[$field.'_file_name']; |
|
47 |
} |
|
48 |
} |
|
49 |
|
|
50 |
if(isset($id) && !empty($filename)) |
|
51 |
{ |
|
52 |
$settings = UploadBehavior::interpolate($model, $id, $field, $filename, $options['style'], array('webroot' => '')); |
|
53 |
$url = isset($settings['url']) ? $settings['url'] : $settings['path']; |
|
54 |
} |
|
55 |
else |
|
56 |
{ |
|
57 |
$settings = UploadBehavior::interpolate($model, null, $field, null, $options['style'], array('webroot' => '')); |
|
58 |
$url = isset($settings['default_url']) ? $settings['default_url'] : null; |
|
59 |
} |
|
60 |
|
|
61 |
return $options['urlize'] ? $this->Html->url($url) : $url; |
|
62 |
} |
|
63 |
|
|
64 |
/** |
|
65 |
* Returns appropriate extension for given mimetype. |
|
66 |
* |
|
67 |
* @param string $mime Mimetype |
|
68 |
* @return void |
|
69 |
* @author Bjorn Post |
|
70 |
*/ |
|
71 |
public function extension($mimeType = null) |
|
72 |
{ |
|
73 |
$knownMimeTypes = array( |
|
74 |
'ai' => 'application/postscript', 'bcpio' => 'application/x-bcpio', 'bin' => 'application/octet-stream', |
|
75 |
'ccad' => 'application/clariscad', 'cdf' => 'application/x-netcdf', 'class' => 'application/octet-stream', |
|
76 |
'cpio' => 'application/x-cpio', 'cpt' => 'application/mac-compactpro', 'csh' => 'application/x-csh', |
|
77 |
'csv' => 'application/csv', 'dcr' => 'application/x-director', 'dir' => 'application/x-director', |
|
78 |
'dms' => 'application/octet-stream', 'doc' => 'application/msword', 'drw' => 'application/drafting', |
|
79 |
'dvi' => 'application/x-dvi', 'dwg' => 'application/acad', 'dxf' => 'application/dxf', 'dxr' => 'application/x-director', |
|
80 |
'eps' => 'application/postscript', 'exe' => 'application/octet-stream', 'ez' => 'application/andrew-inset', |
|
81 |
'flv' => 'video/x-flv', 'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip', |
|
82 |
'bz2' => 'application/x-bzip', '7z' => 'application/x-7z-compressed', 'hdf' => 'application/x-hdf', |
|
83 |
'hqx' => 'application/mac-binhex40', 'ips' => 'application/x-ipscript', 'ipx' => 'application/x-ipix', |
|
84 |
'js' => 'application/x-javascript', 'latex' => 'application/x-latex', 'lha' => 'application/octet-stream', |
|
85 |
'lsp' => 'application/x-lisp', 'lzh' => 'application/octet-stream', 'man' => 'application/x-troff-man', |
|
86 |
'me' => 'application/x-troff-me', 'mif' => 'application/vnd.mif', 'ms' => 'application/x-troff-ms', |
|
87 |
'nc' => 'application/x-netcdf', 'oda' => 'application/oda', 'pdf' => 'application/pdf', |
|
88 |
'pgn' => 'application/x-chess-pgn', 'pot' => 'application/mspowerpoint', 'pps' => 'application/mspowerpoint', |
|
89 |
'ppt' => 'application/mspowerpoint', 'ppz' => 'application/mspowerpoint', 'pre' => 'application/x-freelance', |
|
90 |
'prt' => 'application/pro_eng', 'ps' => 'application/postscript', 'roff' => 'application/x-troff', |
|
91 |
'scm' => 'application/x-lotusscreencam', 'set' => 'application/set', 'sh' => 'application/x-sh', |
|
92 |
'shar' => 'application/x-shar', 'sit' => 'application/x-stuffit', 'skd' => 'application/x-koan', |
|
93 |
'skm' => 'application/x-koan', 'skp' => 'application/x-koan', 'skt' => 'application/x-koan', |
|
94 |
'smi' => 'application/smil', 'smil' => 'application/smil', 'sol' => 'application/solids', |
|
95 |
'spl' => 'application/x-futuresplash', 'src' => 'application/x-wais-source', 'step' => 'application/STEP', |
|
96 |
'stl' => 'application/SLA', 'stp' => 'application/STEP', 'sv4cpio' => 'application/x-sv4cpio', |
|
97 |
'sv4crc' => 'application/x-sv4crc', 'svg' => 'image/svg+xml', 'svgz' => 'image/svg+xml', |
|
98 |
'swf' => 'application/x-shockwave-flash', 't' => 'application/x-troff', |
|
99 |
'tar' => 'application/x-tar', 'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex', |
|
100 |
'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', 'tr' => 'application/x-troff', |
|
101 |
'tsp' => 'application/dsptype', 'unv' => 'application/i-deas', 'ustar' => 'application/x-ustar', |
|
102 |
'vcd' => 'application/x-cdlink', 'vda' => 'application/vda', 'xlc' => 'application/vnd.ms-excel', |
|
103 |
'xll' => 'application/vnd.ms-excel', 'xlm' => 'application/vnd.ms-excel', 'xls' => 'application/vnd.ms-excel', |
|
104 |
'xlw' => 'application/vnd.ms-excel', 'zip' => 'application/zip', 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', |
|
105 |
'aiff' => 'audio/x-aiff', 'au' => 'audio/basic', 'kar' => 'audio/midi', 'mid' => 'audio/midi', |
|
106 |
'midi' => 'audio/midi', 'mp2' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'mpga' => 'audio/mpeg', |
|
107 |
'ra' => 'audio/x-realaudio', 'ram' => 'audio/x-pn-realaudio', 'rm' => 'audio/x-pn-realaudio', |
|
108 |
'rpm' => 'audio/x-pn-realaudio-plugin', 'snd' => 'audio/basic', 'tsi' => 'audio/TSP-audio', 'wav' => 'audio/x-wav', |
|
109 |
'asc' => 'text/plain', 'c' => 'text/plain', 'cc' => 'text/plain', 'css' => 'text/css', 'etx' => 'text/x-setext', |
|
110 |
'f' => 'text/plain', 'f90' => 'text/plain', 'h' => 'text/plain', 'hh' => 'text/plain', 'htm' => 'text/html', |
|
111 |
'html' => 'text/html', 'm' => 'text/plain', 'rtf' => 'text/rtf', 'rtx' => 'text/richtext', 'sgm' => 'text/sgml', |
|
112 |
'sgml' => 'text/sgml', 'tsv' => 'text/tab-separated-values', 'tpl' => 'text/template', 'txt' => 'text/plain', |
|
113 |
'xml' => 'text/xml', 'avi' => 'video/x-msvideo', 'fli' => 'video/x-fli', 'mov' => 'video/quicktime', |
|
114 |
'movie' => 'video/x-sgi-movie', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', |
|
115 |
'qt' => 'video/quicktime', 'viv' => 'video/vnd.vivo', 'vivo' => 'video/vnd.vivo', 'gif' => 'image/gif', |
|
116 |
'ief' => 'image/ief', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', |
|
117 |
'pbm' => 'image/x-portable-bitmap', 'pgm' => 'image/x-portable-graymap', 'png' => 'image/png', |
|
118 |
'pnm' => 'image/x-portable-anymap', 'ppm' => 'image/x-portable-pixmap', 'ras' => 'image/cmu-raster', |
|
119 |
'rgb' => 'image/x-rgb', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'xbm' => 'image/x-xbitmap', |
|
120 |
'xpm' => 'image/x-xpixmap', 'xwd' => 'image/x-xwindowdump', 'ice' => 'x-conference/x-cooltalk', |
|
121 |
'iges' => 'model/iges', 'igs' => 'model/iges', 'mesh' => 'model/mesh', 'msh' => 'model/mesh', |
|
122 |
'silo' => 'model/mesh', 'vrml' => 'model/vrml', 'wrl' => 'model/vrml', |
|
123 |
'mime' => 'www/mime', 'pdb' => 'chemical/x-pdb', 'xyz' => 'chemical/x-pdb' |
|
124 |
); |
|
125 |
|
|
126 |
return array_search($mimeType, $knownMimeTypes); |
|
127 |
} |
|
128 |
} |
app/Plugin/UploadPack/composer.json | ||
---|---|---|
1 |
{ |
|
2 |
"name": "szajbus/uploadpack", |
|
3 |
"description": "Easy way to handle file uploads in CakePHP", |
|
4 |
"version": "0.7.2", |
|
5 |
"type": "library", |
|
6 |
"keywords": ["upload", "cakephp", "image processing"], |
|
7 |
"homepage": "https://github.com/szajbus/uploadpack", |
|
8 |
"license": "MIT", |
|
9 |
"authors": [ |
|
10 |
{ |
|
11 |
"name": "Michał Szajbe", |
|
12 |
"email": "michal.szajbe@gmail.com" |
|
13 |
} |
|
14 |
], |
|
15 |
"support": { |
|
16 |
"issues": "https://github.com/szajbus/uploadpack/issues", |
|
17 |
"source": "https://github.com/szajbus/uploadpack" |
|
18 |
}, |
|
19 |
"require": { |
|
20 |
"cakephp/cakephp": ">=1.2" |
|
21 |
}, |
|
22 |
"require-dev": { |
|
23 |
"phpunit/phpunit": "*", |
|
24 |
"cakephp/cakephp-codesniffer": "dev-master" |
|
25 |
} |
|
26 |
} |
app/Plugin/UploadPack/license | ||
---|---|---|
1 |
Copyright (c) 2010 Michał Szajbe |
|
2 |
|
|
3 |
Permission is hereby granted, free of charge, to any person |
|
4 |
obtaining a copy of this software and associated documentation |
|
5 |
files (the "Software"), to deal in the Software without |
|
6 |
restriction, including without limitation the rights to use, |
|
7 |
copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
8 |
copies of the Software, and to permit persons to whom the |
|
9 |
Software is furnished to do so, subject to the following |
|
10 |
conditions: |
|
11 |
|
|
12 |
The above copyright notice and this permission notice shall be |
|
13 |
included in all copies or substantial portions of the Software. |
|
14 |
|
|
15 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
16 |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
17 |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
18 |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
19 |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
20 |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
21 |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
22 |
OTHER DEALINGS IN THE SOFTWARE. |
他の形式にエクスポート: Unified diff