source: trunk/admin/include/functions_upload.inc.php @ 8020

Last change on this file since 8020 was 7868, checked in by plg, 14 years ago

feature 2040 added: automatic rotation of the photo based on EXIF Orientation.

The code could have been shorter but this one 1) checks the resize dimension
with the rotation in mind 2) rotates the photo once resized to reduce memory
used.

File size: 10.8 KB
Line 
1<?php
2// TODO
3// * check md5sum (already exists?)
4
5include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
6include_once(PHPWG_ROOT_PATH.'include/ws_functions.inc.php');
7include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
8
9// Here is the plan
10//
11// 1) move uploaded file to upload/2010/01/22/20100122003814-449ada00.jpg
12//
13// 2) if taller than max_height or wider than max_width, move to pwg_high
14//    + web sized creation
15//
16// 3) thumbnail creation from web sized
17//
18// 4) register in database
19
20// add default event handler for image and thumbnail resize
21add_event_handler('upload_image_resize', 'pwg_image_resize', EVENT_HANDLER_PRIORITY_NEUTRAL, 6);
22add_event_handler('upload_thumbnail_resize', 'pwg_image_resize', EVENT_HANDLER_PRIORITY_NEUTRAL, 6);
23
24function add_uploaded_file($source_filepath, $original_filename=null, $categories=null, $level=null)
25{
26  global $conf;
27
28  // current date
29  list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
30  list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4);
31 
32  // upload directory hierarchy
33  $upload_dir = sprintf(
34    PHPWG_ROOT_PATH.$conf['upload_dir'].'/%s/%s/%s',
35    $year,
36    $month,
37    $day
38    );
39
40  // compute file path
41  $md5sum = md5_file($source_filepath);
42  $date_string = preg_replace('/[^\d]/', '', $dbnow);
43  $random_string = substr($md5sum, 0, 8);
44  $filename_wo_ext = $date_string.'-'.$random_string;
45  $file_path = $upload_dir.'/'.$filename_wo_ext.'.';
46
47  list($width, $height, $type) = getimagesize($source_filepath);
48  if (IMAGETYPE_PNG == $type)
49  {
50    $file_path.= 'png';
51  }
52  else
53  {
54    $file_path.= 'jpg';
55  }
56
57  prepare_directory($upload_dir);
58  if (is_uploaded_file($source_filepath))
59  {
60    move_uploaded_file($source_filepath, $file_path);
61  }
62  else
63  {
64    copy($source_filepath, $file_path);
65  }
66
67  if ($conf['upload_form_websize_resize']
68      and need_resize($file_path, $conf['upload_form_websize_maxwidth'], $conf['upload_form_websize_maxheight']))
69  {
70    $high_path = file_path_for_type($file_path, 'high');
71    $high_dir = dirname($high_path);
72    prepare_directory($high_dir);
73   
74    rename($file_path, $high_path);
75    $high_infos = pwg_image_infos($high_path);
76   
77    trigger_event('upload_image_resize',
78      false,
79      $high_path,
80      $file_path,
81      $conf['upload_form_websize_maxwidth'],
82      $conf['upload_form_websize_maxheight'],
83      $conf['upload_form_websize_quality']
84      );
85  }
86
87  $file_infos = pwg_image_infos($file_path);
88 
89  $thumb_path = file_path_for_type($file_path, 'thumb');
90  $thumb_dir = dirname($thumb_path);
91  prepare_directory($thumb_dir);
92 
93  trigger_event('upload_thumbnail_resize',
94    false,
95    $file_path,
96    $thumb_path,
97    $conf['upload_form_thumb_maxwidth'],
98    $conf['upload_form_thumb_maxheight'],
99    $conf['upload_form_thumb_quality']
100    );
101 
102  $thumb_infos = pwg_image_infos($thumb_path);
103
104  // database registration
105  $insert = array(
106    'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)),
107    'date_available' => $dbnow,
108    'tn_ext' => 'jpg',
109    'path' => preg_replace('#^'.preg_quote(PHPWG_ROOT_PATH).'#', '', $file_path),
110    'filesize' => $file_infos['filesize'],
111    'width' => $file_infos['width'],
112    'height' => $file_infos['height'],
113    'md5sum' => $md5sum,
114    );
115
116  if (isset($high_infos))
117  {
118    $insert['has_high'] = 'true';
119    $insert['high_filesize'] = $high_infos['filesize'];
120  }
121
122  if (isset($level))
123  {
124    $insert['level'] = $level;
125  }
126 
127  mass_inserts(
128    IMAGES_TABLE,
129    array_keys($insert),
130    array($insert)
131    );
132 
133  $image_id = pwg_db_insert_id(IMAGES_TABLE);
134
135  if (isset($categories) and count($categories) > 0)
136  {
137    associate_images_to_categories(
138      array($image_id),
139      $categories
140      );
141  }
142 
143  // update metadata from the uploaded file (exif/iptc)
144  if ($conf['use_exif'] and !function_exists('read_exif_data'))
145  {
146    $conf['use_exif'] = false;
147  }
148  update_metadata(array($image_id=>$file_path));
149 
150  invalidate_user_cache();
151
152  return $image_id;
153}
154
155function prepare_directory($directory)
156{
157  if (!is_dir($directory)) {
158    if (substr(PHP_OS, 0, 3) == 'WIN')
159    {
160      $directory = str_replace('/', DIRECTORY_SEPARATOR, $directory);
161    }
162    umask(0000);
163    $recursive = true;
164    if (!@mkdir($directory, 0777, $recursive))
165    {
166      die('[prepare_directory] cannot create directory "'.$directory.'"');
167    }
168  }
169
170  if (!is_writable($directory))
171  {
172    // last chance to make the directory writable
173    @chmod($directory, 0777);
174
175    if (!is_writable($directory))
176    {
177      die('[prepare_directory] directory "'.$directory.'" has no write access');
178    }
179  }
180
181  secure_directory($directory);
182}
183
184function need_resize($image_filepath, $max_width, $max_height)
185{
186  // TODO : the resize check should take the orientation into account. If a
187  // rotation must be applied to the resized photo, then we should test
188  // invert width and height.
189  list($width, $height) = getimagesize($image_filepath);
190 
191  if ($width > $max_width or $height > $max_height)
192  {
193    return true;
194  }
195
196  return false;
197}
198
199function get_resize_dimensions($width, $height, $max_width, $max_height, $rotation=null)
200{
201  $rotate_for_dimensions = false;
202  if (isset($rotation) and in_array(abs($rotation), array(90, 270)))
203  {
204    $rotate_for_dimensions = true;
205  }
206
207  if ($rotate_for_dimensions)
208  {
209    list($width, $height) = array($height, $width);
210  }
211 
212  $ratio_width  = $width / $max_width;
213  $ratio_height = $height / $max_height;
214 
215  // maximal size exceeded ?
216  if ($ratio_width > 1 or $ratio_height > 1)
217  {
218    if ($ratio_width < $ratio_height)
219    { 
220      $destination_width = ceil($width / $ratio_height);
221      $destination_height = $max_height;
222    }
223    else
224    { 
225      $destination_width = $max_width; 
226      $destination_height = ceil($height / $ratio_width);
227    }
228  }
229
230  if ($rotate_for_dimensions)
231  {
232    list($destination_width, $destination_height) = array($destination_height, $destination_width);
233  }
234 
235  return array(
236    'width' => $destination_width,
237    'height'=> $destination_height,
238    );
239}
240
241function pwg_image_resize($result, $source_filepath, $destination_filepath, $max_width, $max_height, $quality)
242{
243  if ($result !== false)
244  {
245    //someone hooked us - so we skip
246    return $result;
247  }
248
249  if (!function_exists('gd_info'))
250  {
251    return false;
252  }
253
254  // extension of the picture filename
255  $extension = strtolower(get_extension($source_filepath));
256
257  $source_image = null;
258  if (in_array($extension, array('jpg', 'jpeg')))
259  {
260    $source_image = imagecreatefromjpeg($source_filepath);
261  }
262  else if ($extension == 'png')
263  {
264    $source_image = imagecreatefrompng($source_filepath);
265  }
266  else
267  {
268    die('unsupported file extension');
269  }
270
271  $rotation = null;
272  if (function_exists('imagerotate'))
273  {
274    $exif = exif_read_data($source_filepath);
275    if (isset($exif['Orientation']) and preg_match('/^\s*(\d)/', $exif['Orientation'], $matches))
276    {
277      $orientation = $matches[1];
278      if (in_array($orientation, array(3, 4)))
279      {
280        $rotation = 180;
281      }
282      elseif (in_array($orientation, array(5, 6)))
283      {
284        $rotation = 270;
285      }
286      elseif (in_array($orientation, array(7, 8)))
287      {
288        $rotation = 90;
289      }
290    }
291  }
292 
293  // width/height
294  $source_width  = imagesx($source_image); 
295  $source_height = imagesy($source_image);
296 
297  $resize_dimensions = get_resize_dimensions($source_width, $source_height, $max_width, $max_height, $rotation);
298
299  // testing on height is useless in theory: if width is unchanged, there
300  // should be no resize, because width/height ratio is not modified.
301  if ($resize_dimensions['width'] == $source_width and $resize_dimensions['height'] == $source_height)
302  {
303    // the image doesn't need any resize! We just copy it to the destination
304    copy($source_filepath, $destination_filepath);
305    return true;
306  }
307 
308  $destination_image = imagecreatetruecolor($resize_dimensions['width'], $resize_dimensions['height']);
309 
310  imagecopyresampled(
311    $destination_image,
312    $source_image,
313    0,
314    0,
315    0,
316    0,
317    $resize_dimensions['width'],
318    $resize_dimensions['height'],
319    $source_width,
320    $source_height
321    );
322
323  // rotation occurs only on resized photo to avoid useless memory use
324  if (isset($rotation))
325  {
326    $destination_image = imagerotate($destination_image, $rotation, 0);
327  }
328 
329  $extension = strtolower(get_extension($destination_filepath));
330  if ($extension == 'png')
331  {
332    imagepng($destination_image, $destination_filepath);
333  }
334  else
335  {
336    imagejpeg($destination_image, $destination_filepath, $quality);
337  }
338  // freeing memory ressources
339  imagedestroy($source_image);
340  imagedestroy($destination_image);
341
342  // everything should be OK if we are here!
343  return true;
344}
345
346function pwg_image_infos($path)
347{
348  list($width, $height) = getimagesize($path);
349  $filesize = floor(filesize($path)/1024);
350 
351  return array(
352    'width'  => $width,
353    'height' => $height,
354    'filesize' => $filesize,
355    );
356}
357
358function is_valid_image_extension($extension)
359{
360  return in_array(strtolower($extension), array('jpg', 'jpeg', 'png'));
361}
362
363function file_upload_error_message($error_code)
364{
365  switch ($error_code) {
366    case UPLOAD_ERR_INI_SIZE:
367      return sprintf(
368        l10n('The uploaded file exceeds the upload_max_filesize directive in php.ini: %sB'),
369        get_ini_size('upload_max_filesize', false)
370        );
371    case UPLOAD_ERR_FORM_SIZE:
372      return l10n('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form');
373    case UPLOAD_ERR_PARTIAL:
374      return l10n('The uploaded file was only partially uploaded');
375    case UPLOAD_ERR_NO_FILE:
376      return l10n('No file was uploaded');
377    case UPLOAD_ERR_NO_TMP_DIR:
378      return l10n('Missing a temporary folder');
379    case UPLOAD_ERR_CANT_WRITE:
380      return l10n('Failed to write file to disk');
381    case UPLOAD_ERR_EXTENSION:
382      return l10n('File upload stopped by extension');
383    default:
384      return l10n('Unknown upload error');
385  }
386}
387
388function get_ini_size($ini_key, $in_bytes=true)
389{
390  $size = ini_get($ini_key);
391
392  if ($in_bytes)
393  {
394    $size = convert_shortand_notation_to_bytes($size);
395  }
396 
397  return $size;
398}
399
400function convert_shortand_notation_to_bytes($value)
401{
402  $suffix = substr($value, -1);
403  $multiply_by = null;
404 
405  if ('K' == $suffix)
406  {
407    $multiply_by = 1024;
408  }
409  else if ('M' == $suffix)
410  {
411    $multiply_by = 1024*1024;
412  }
413  else if ('G' == $suffix)
414  {
415    $multiply_by = 1024*1024*1024;
416  }
417 
418  if (isset($multiply_by))
419  {
420    $value = substr($value, 0, -1);
421    $value*= $multiply_by;
422  }
423
424  return $value;
425}
426
427function add_upload_error($upload_id, $error_message)
428{
429  if (!isset($_SESSION['uploads_error']))
430  {
431    $_SESSION['uploads_error'] = array();
432  }
433  if (!isset($_SESSION['uploads_error'][$upload_id]))
434  {
435    $_SESSION['uploads_error'][$upload_id] = array();
436  }
437
438  array_push($_SESSION['uploads_error'][$upload_id], $error_message);
439}
440?>
Note: See TracBrowser for help on using the repository browser.