source: branches/2.4/admin/include/functions_upload.inc.php @ 17676

Last change on this file since 17676 was 17676, checked in by rvelices, 12 years ago

bug 2725: Piwigo isn't compatible with suPHP + better handling of watermark upload errors merge from trunk to branch 2.4

File size: 13.5 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
25include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
26
27// add default event handler for image and thumbnail resize
28add_event_handler('upload_image_resize', 'pwg_image_resize', EVENT_HANDLER_PRIORITY_NEUTRAL, 7);
29add_event_handler('upload_thumbnail_resize', 'pwg_image_resize', EVENT_HANDLER_PRIORITY_NEUTRAL, 9);
30
31function get_upload_form_config()
32{
33  // default configuration for upload
34  $upload_form_config = array(
35    'original_resize' => array(
36      'default' => false,
37      'can_be_null' => false,
38      ),
39
40    'original_resize_maxwidth' => array(
41      'default' => 2000,
42      'min' => 500,
43      'max' => 20000,
44      'pattern' => '/^\d+$/',
45      'can_be_null' => false,
46      'error_message' => l10n('The original maximum width must be a number between %d and %d'),
47      ),
48
49    'original_resize_maxheight' => array(
50      'default' => 2000,
51      'min' => 300,
52      'max' => 20000,
53      'pattern' => '/^\d+$/',
54      'can_be_null' => false,
55      'error_message' => l10n('The original maximum height must be a number between %d and %d'),
56      ),
57
58    'original_resize_quality' => array(
59      'default' => 95,
60      'min' => 50,
61      'max' => 98,
62      'pattern' => '/^\d+$/',
63      'can_be_null' => false,
64      'error_message' => l10n('The original image quality must be a number between %d and %d'),
65      ),
66    );
67
68  return $upload_form_config;
69}
70
71function save_upload_form_config($data, &$errors=array(), &$form_errors=array())
72{
73  if (!is_array($data) or empty($data))
74  {
75    return false;
76  }
77
78  $upload_form_config = get_upload_form_config();
79  $updates = array();
80
81  foreach ($data as $field => $value)
82  {
83    if (!isset($upload_form_config[$field]))
84    {
85      continue;
86    }
87    if (is_bool($upload_form_config[$field]['default']))
88    {
89      if (isset($value))
90      {
91        $value = true;
92      }
93      else
94      {
95        $value = false;
96      }
97
98      $updates[] = array(
99        'param' => $field,
100        'value' => boolean_to_string($value)
101        );
102    }
103    elseif ($upload_form_config[$field]['can_be_null'] and empty($value))
104    {
105      $updates[] = array(
106        'param' => $field,
107        'value' => 'false'
108        );
109    }
110    else
111    {
112      $min = $upload_form_config[$field]['min'];
113      $max = $upload_form_config[$field]['max'];
114      $pattern = $upload_form_config[$field]['pattern'];
115
116      if (preg_match($pattern, $value) and $value >= $min and $value <= $max)
117      {
118         $updates[] = array(
119          'param' => $field,
120          'value' => $value
121          );
122      }
123      else
124      {
125        array_push(
126          $errors,
127          sprintf(
128            $upload_form_config[$field]['error_message'],
129            $min,
130            $max
131            )
132          );
133       
134        $form_errors[$field] = '['.$min.' .. '.$max.']';
135      }
136    }
137  }
138
139  if (count($errors) == 0)
140  {
141    mass_updates(
142      CONFIG_TABLE,
143      array(
144        'primary' => array('param'),
145        'update' => array('value')
146        ),
147      $updates
148      );
149    return true;
150  }
151
152  return false;
153}
154
155function add_uploaded_file($source_filepath, $original_filename=null, $categories=null, $level=null, $image_id=null, $original_md5sum=null)
156{
157  // 1) move uploaded file to upload/2010/01/22/20100122003814-449ada00.jpg
158  //
159  // 2) keep/resize original
160  //
161  // 3) register in database
162
163  // TODO
164  // * check md5sum (already exists?)
165
166  global $conf, $user;
167
168  if (isset($original_md5sum))
169  {
170    $md5sum = $original_md5sum;
171  }
172  else
173  {
174    $md5sum = md5_file($source_filepath);
175  }
176
177  $file_path = null;
178
179  if (isset($image_id))
180  {
181    // this photo already exists, we update it
182    $query = '
183SELECT
184    path
185  FROM '.IMAGES_TABLE.'
186  WHERE id = '.$image_id.'
187;';
188    $result = pwg_query($query);
189    while ($row = pwg_db_fetch_assoc($result))
190    {
191      $file_path = $row['path'];
192    }
193
194    if (!isset($file_path))
195    {
196      die('['.__FUNCTION__.'] this photo does not exist in the database');
197    }
198
199    // delete all physical files related to the photo (thumbnail, web site, HD)
200    delete_element_files(array($image_id));
201  }
202  else
203  {
204    // this photo is new
205
206    // current date
207    list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
208    list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4);
209
210    // upload directory hierarchy
211    $upload_dir = sprintf(
212      PHPWG_ROOT_PATH.$conf['upload_dir'].'/%s/%s/%s',
213      $year,
214      $month,
215      $day
216      );
217
218    // compute file path
219    $date_string = preg_replace('/[^\d]/', '', $dbnow);
220    $random_string = substr($md5sum, 0, 8);
221    $filename_wo_ext = $date_string.'-'.$random_string;
222    $file_path = $upload_dir.'/'.$filename_wo_ext.'.';
223
224    list($width, $height, $type) = getimagesize($source_filepath);
225    if (IMAGETYPE_PNG == $type)
226    {
227      $file_path.= 'png';
228    }
229    elseif (IMAGETYPE_GIF == $type)
230    {
231      $file_path.= 'gif';
232    }
233    else
234    {
235      $file_path.= 'jpg';
236    }
237
238    prepare_directory($upload_dir);
239  }
240
241  if (is_uploaded_file($source_filepath))
242  {
243    move_uploaded_file($source_filepath, $file_path);
244  }
245  else
246  {
247    rename($source_filepath, $file_path);
248  }
249  @chmod($file_path, 0644);
250
251  if (pwg_image::get_library() != 'gd')
252  {
253    if ($conf['original_resize'])
254    {
255      $need_resize = need_resize($file_path, $conf['original_resize_maxwidth'], $conf['original_resize_maxheight']);
256
257      if ($need_resize)
258      {
259        $img = new pwg_image($file_path);
260
261        $img->pwg_resize(
262          $file_path,
263          $conf['original_resize_maxwidth'],
264          $conf['original_resize_maxheight'],
265          $conf['original_resize_quality'],
266          $conf['upload_form_automatic_rotation'],
267          false
268          );
269
270        $img->destroy();
271      }
272    }
273  }
274
275  // we need to save the rotation angle in the database to compute
276  // width/height of "multisizes"
277  $rotation_angle = pwg_image::get_rotation_angle($file_path);
278  $rotation = pwg_image::get_rotation_code_from_angle($rotation_angle);
279 
280  $file_infos = pwg_image_infos($file_path);
281
282  if (isset($image_id))
283  {
284    $update = array(
285      'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)),
286      'filesize' => $file_infos['filesize'],
287      'width' => $file_infos['width'],
288      'height' => $file_infos['height'],
289      'md5sum' => $md5sum,
290      'added_by' => $user['id'],
291      'rotation' => $rotation,
292      );
293
294    if (isset($level))
295    {
296      $update['level'] = $level;
297    }
298
299    single_update(
300      IMAGES_TABLE,
301      $update,
302      array('id' => $image_id)
303      );
304  }
305  else
306  {
307    // database registration
308    $file = pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path));
309    $insert = array(
310      'file' => $file,
311      'name' => get_name_from_file($file),
312      'date_available' => $dbnow,
313      'path' => preg_replace('#^'.preg_quote(PHPWG_ROOT_PATH).'#', '', $file_path),
314      'filesize' => $file_infos['filesize'],
315      'width' => $file_infos['width'],
316      'height' => $file_infos['height'],
317      'md5sum' => $md5sum,
318      'added_by' => $user['id'],
319      'rotation' => $rotation,
320      );
321
322    if (isset($level))
323    {
324      $insert['level'] = $level;
325    }
326
327    single_insert(IMAGES_TABLE, $insert);
328
329    $image_id = pwg_db_insert_id(IMAGES_TABLE);
330  }
331
332  if (isset($categories) and count($categories) > 0)
333  {
334    associate_images_to_categories(
335      array($image_id),
336      $categories
337      );
338  }
339
340  // update metadata from the uploaded file (exif/iptc)
341  if ($conf['use_exif'] and !function_exists('read_exif_data'))
342  {
343    $conf['use_exif'] = false;
344  }
345  sync_metadata(array($image_id));
346
347  invalidate_user_cache();
348
349  // cache thumbnail
350  $query = '
351SELECT
352    id,
353    path
354  FROM '.IMAGES_TABLE.'
355  WHERE id = '.$image_id.'
356;';
357  $image_infos = pwg_db_fetch_assoc(pwg_query($query));
358
359  set_make_full_url();
360  // in case we are on uploadify.php, we have to replace the false path
361  $thumb_url = preg_replace('#admin/include/i#', 'i', DerivativeImage::thumb_url($image_infos));
362  unset_make_full_url();
363 
364  fetchRemote($thumb_url, $dest);
365 
366
367  return $image_id;
368}
369
370function prepare_directory($directory)
371{
372  if (!is_dir($directory)) {
373    if (substr(PHP_OS, 0, 3) == 'WIN')
374    {
375      $directory = str_replace('/', DIRECTORY_SEPARATOR, $directory);
376    }
377    umask(0000);
378    $recursive = true;
379    if (!@mkdir($directory, 0777, $recursive))
380    {
381      die('[prepare_directory] cannot create directory "'.$directory.'"');
382    }
383  }
384
385  if (!is_writable($directory))
386  {
387    // last chance to make the directory writable
388    @chmod($directory, 0777);
389
390    if (!is_writable($directory))
391    {
392      die('[prepare_directory] directory "'.$directory.'" has no write access');
393    }
394  }
395
396  secure_directory($directory);
397}
398
399function need_resize($image_filepath, $max_width, $max_height)
400{
401  // TODO : the resize check should take the orientation into account. If a
402  // rotation must be applied to the resized photo, then we should test
403  // invert width and height.
404  list($width, $height) = getimagesize($image_filepath);
405
406  if ($width > $max_width or $height > $max_height)
407  {
408    return true;
409  }
410
411  return false;
412}
413
414function pwg_image_infos($path)
415{
416  list($width, $height) = getimagesize($path);
417  $filesize = floor(filesize($path)/1024);
418
419  return array(
420    'width'  => $width,
421    'height' => $height,
422    'filesize' => $filesize,
423    );
424}
425
426function is_valid_image_extension($extension)
427{
428  return in_array(strtolower($extension), array('jpg', 'jpeg', 'png', 'gif'));
429}
430
431function file_upload_error_message($error_code)
432{
433  switch ($error_code) {
434    case UPLOAD_ERR_INI_SIZE:
435      return sprintf(
436        l10n('The uploaded file exceeds the upload_max_filesize directive in php.ini: %sB'),
437        get_ini_size('upload_max_filesize', false)
438        );
439    case UPLOAD_ERR_FORM_SIZE:
440      return l10n('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form');
441    case UPLOAD_ERR_PARTIAL:
442      return l10n('The uploaded file was only partially uploaded');
443    case UPLOAD_ERR_NO_FILE:
444      return l10n('No file was uploaded');
445    case UPLOAD_ERR_NO_TMP_DIR:
446      return l10n('Missing a temporary folder');
447    case UPLOAD_ERR_CANT_WRITE:
448      return l10n('Failed to write file to disk');
449    case UPLOAD_ERR_EXTENSION:
450      return l10n('File upload stopped by extension');
451    default:
452      return l10n('Unknown upload error');
453  }
454}
455
456function get_ini_size($ini_key, $in_bytes=true)
457{
458  $size = ini_get($ini_key);
459
460  if ($in_bytes)
461  {
462    $size = convert_shorthand_notation_to_bytes($size);
463  }
464
465  return $size;
466}
467
468function convert_shorthand_notation_to_bytes($value)
469{
470  $suffix = substr($value, -1);
471  $multiply_by = null;
472
473  if ('K' == $suffix)
474  {
475    $multiply_by = 1024;
476  }
477  else if ('M' == $suffix)
478  {
479    $multiply_by = 1024*1024;
480  }
481  else if ('G' == $suffix)
482  {
483    $multiply_by = 1024*1024*1024;
484  }
485
486  if (isset($multiply_by))
487  {
488    $value = substr($value, 0, -1);
489    $value*= $multiply_by;
490  }
491
492  return $value;
493}
494
495function add_upload_error($upload_id, $error_message)
496{
497  if (!isset($_SESSION['uploads_error']))
498  {
499    $_SESSION['uploads_error'] = array();
500  }
501  if (!isset($_SESSION['uploads_error'][$upload_id]))
502  {
503    $_SESSION['uploads_error'][$upload_id] = array();
504  }
505
506  array_push($_SESSION['uploads_error'][$upload_id], $error_message);
507}
508
509function ready_for_upload_message()
510{
511  global $conf;
512
513  $relative_dir = preg_replace('#^'.PHPWG_ROOT_PATH.'#', '', $conf['upload_dir']);
514
515  if (!is_dir($conf['upload_dir']))
516  {
517    if (!is_writable(dirname($conf['upload_dir'])))
518    {
519      return sprintf(
520        l10n('Create the "%s" directory at the root of your Piwigo installation'),
521        $relative_dir
522        );
523    }
524  }
525  else
526  {
527    if (!is_writable($conf['upload_dir']))
528    {
529      @chmod($conf['upload_dir'], 0777);
530
531      if (!is_writable($conf['upload_dir']))
532      {
533        return sprintf(
534          l10n('Give write access (chmod 777) to "%s" directory at the root of your Piwigo installation'),
535          $relative_dir
536          );
537      }
538    }
539  }
540
541  return null;
542}
543?>
Note: See TracBrowser for help on using the repository browser.