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

Last change on this file since 14221 was 14221, checked in by plg, 12 years ago

feature 2606: second step on multiple size configuration screen redesign.

Configuration settings are saved on form submission.

The old screen is still available for tests.

Default resize quality set to 95 instead of 85.

File size: 14.0 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
250  if (pwg_image::get_library() != 'gd')
251  {
252    if ($conf['original_resize'])
253    {
254      $need_resize = need_resize($file_path, $conf['original_resize_maxwidth'], $conf['original_resize_maxheight']);
255
256      if ($need_resize)
257      {
258        $img = new pwg_image($file_path);
259
260        $img->pwg_resize(
261          $file_path,
262          $conf['original_resize_maxwidth'],
263          $conf['original_resize_maxheight'],
264          $conf['original_resize_quality'],
265          $conf['upload_form_automatic_rotation'],
266          false
267          );
268
269        $img->destroy();
270      }
271    }
272  }
273
274  // we need to save the rotation angle in the database to compute
275  // width/height of "multisizes"
276  $rotation_angle = pwg_image::get_rotation_angle($file_path);
277  $rotation = pwg_image::get_rotation_code_from_angle($rotation_angle);
278 
279  $file_infos = pwg_image_infos($file_path);
280
281  if (isset($image_id))
282  {
283    $update = array(
284      'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)),
285      'filesize' => $file_infos['filesize'],
286      'width' => $file_infos['width'],
287      'height' => $file_infos['height'],
288      'md5sum' => $md5sum,
289      'added_by' => $user['id'],
290      'rotation' => $rotation,
291      );
292
293    if (isset($level))
294    {
295      $update['level'] = $level;
296    }
297
298    single_update(
299      IMAGES_TABLE,
300      $update,
301      array('id' => $image_id)
302      );
303  }
304  else
305  {
306    // database registration
307    $file = pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path));
308    $insert = array(
309      'file' => $file,
310      'name' => get_name_from_file($file),
311      'date_available' => $dbnow,
312      'path' => preg_replace('#^'.preg_quote(PHPWG_ROOT_PATH).'#', '', $file_path),
313      'filesize' => $file_infos['filesize'],
314      'width' => $file_infos['width'],
315      'height' => $file_infos['height'],
316      'md5sum' => $md5sum,
317      'added_by' => $user['id'],
318      'rotation' => $rotation,
319      );
320
321    if (isset($level))
322    {
323      $insert['level'] = $level;
324    }
325
326    single_insert(IMAGES_TABLE, $insert);
327
328    $image_id = pwg_db_insert_id(IMAGES_TABLE);
329  }
330
331  if (isset($categories) and count($categories) > 0)
332  {
333    associate_images_to_categories(
334      array($image_id),
335      $categories
336      );
337  }
338
339  // update metadata from the uploaded file (exif/iptc)
340  if ($conf['use_exif'] and !function_exists('read_exif_data'))
341  {
342    $conf['use_exif'] = false;
343  }
344  sync_metadata(array($image_id));
345
346  invalidate_user_cache();
347
348  // cache thumbnail
349  $query = '
350SELECT
351    id,
352    path
353  FROM '.IMAGES_TABLE.'
354  WHERE id = '.$image_id.'
355;';
356  $image_infos = pwg_db_fetch_assoc(pwg_query($query));
357
358  set_make_full_url();
359  // in case we are on uploadify.php, we have to replace the false path
360  $thumb_url = preg_replace('#admin/include/i#', 'i', DerivativeImage::thumb_url($image_infos));
361  unset_make_full_url();
362 
363  fetchRemote($thumb_url, $dest);
364 
365
366  return $image_id;
367}
368
369function prepare_directory($directory)
370{
371  if (!is_dir($directory)) {
372    if (substr(PHP_OS, 0, 3) == 'WIN')
373    {
374      $directory = str_replace('/', DIRECTORY_SEPARATOR, $directory);
375    }
376    umask(0000);
377    $recursive = true;
378    if (!@mkdir($directory, 0777, $recursive))
379    {
380      die('[prepare_directory] cannot create directory "'.$directory.'"');
381    }
382  }
383
384  if (!is_writable($directory))
385  {
386    // last chance to make the directory writable
387    @chmod($directory, 0777);
388
389    if (!is_writable($directory))
390    {
391      die('[prepare_directory] directory "'.$directory.'" has no write access');
392    }
393  }
394
395  secure_directory($directory);
396}
397
398function need_resize($image_filepath, $max_width, $max_height)
399{
400  // TODO : the resize check should take the orientation into account. If a
401  // rotation must be applied to the resized photo, then we should test
402  // invert width and height.
403  list($width, $height) = getimagesize($image_filepath);
404
405  if ($width > $max_width or $height > $max_height)
406  {
407    return true;
408  }
409
410  return false;
411}
412
413function pwg_image_infos($path)
414{
415  list($width, $height) = getimagesize($path);
416  $filesize = floor(filesize($path)/1024);
417
418  return array(
419    'width'  => $width,
420    'height' => $height,
421    'filesize' => $filesize,
422    );
423}
424
425function is_valid_image_extension($extension)
426{
427  return in_array(strtolower($extension), array('jpg', 'jpeg', 'png', 'gif'));
428}
429
430function file_upload_error_message($error_code)
431{
432  switch ($error_code) {
433    case UPLOAD_ERR_INI_SIZE:
434      return sprintf(
435        l10n('The uploaded file exceeds the upload_max_filesize directive in php.ini: %sB'),
436        get_ini_size('upload_max_filesize', false)
437        );
438    case UPLOAD_ERR_FORM_SIZE:
439      return l10n('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form');
440    case UPLOAD_ERR_PARTIAL:
441      return l10n('The uploaded file was only partially uploaded');
442    case UPLOAD_ERR_NO_FILE:
443      return l10n('No file was uploaded');
444    case UPLOAD_ERR_NO_TMP_DIR:
445      return l10n('Missing a temporary folder');
446    case UPLOAD_ERR_CANT_WRITE:
447      return l10n('Failed to write file to disk');
448    case UPLOAD_ERR_EXTENSION:
449      return l10n('File upload stopped by extension');
450    default:
451      return l10n('Unknown upload error');
452  }
453}
454
455function get_ini_size($ini_key, $in_bytes=true)
456{
457  $size = ini_get($ini_key);
458
459  if ($in_bytes)
460  {
461    $size = convert_shorthand_notation_to_bytes($size);
462  }
463
464  return $size;
465}
466
467function convert_shorthand_notation_to_bytes($value)
468{
469  $suffix = substr($value, -1);
470  $multiply_by = null;
471
472  if ('K' == $suffix)
473  {
474    $multiply_by = 1024;
475  }
476  else if ('M' == $suffix)
477  {
478    $multiply_by = 1024*1024;
479  }
480  else if ('G' == $suffix)
481  {
482    $multiply_by = 1024*1024*1024;
483  }
484
485  if (isset($multiply_by))
486  {
487    $value = substr($value, 0, -1);
488    $value*= $multiply_by;
489  }
490
491  return $value;
492}
493
494function add_upload_error($upload_id, $error_message)
495{
496  if (!isset($_SESSION['uploads_error']))
497  {
498    $_SESSION['uploads_error'] = array();
499  }
500  if (!isset($_SESSION['uploads_error'][$upload_id]))
501  {
502    $_SESSION['uploads_error'][$upload_id] = array();
503  }
504
505  array_push($_SESSION['uploads_error'][$upload_id], $error_message);
506}
507
508function ready_for_upload_message()
509{
510  global $conf;
511
512  $relative_dir = preg_replace('#^'.PHPWG_ROOT_PATH.'#', '', $conf['upload_dir']);
513
514  if (!is_dir($conf['upload_dir']))
515  {
516    if (!is_writable(dirname($conf['upload_dir'])))
517    {
518      return sprintf(
519        l10n('Create the "%s" directory at the root of your Piwigo installation'),
520        $relative_dir
521        );
522    }
523  }
524  else
525  {
526    if (!is_writable($conf['upload_dir']))
527    {
528      @chmod($conf['upload_dir'], 0777);
529
530      if (!is_writable($conf['upload_dir']))
531      {
532        return sprintf(
533          l10n('Give write access (chmod 777) to "%s" directory at the root of your Piwigo installation'),
534          $relative_dir
535          );
536      }
537    }
538  }
539
540  return null;
541}
542
543function file_path_for_type($file_path, $type='thumb')
544{
545  // resolve the $file_path depending on the $type
546  if ('thumb' == $type) {
547    $file_path = get_thumbnail_location(
548      array(
549        'path' => $file_path,
550        'tn_ext' => 'jpg',
551        )
552      );
553  }
554
555  if ('high' == $type) {
556    @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
557    $file_path = get_high_location(
558      array(
559        'path' => $file_path,
560        'has_high' => 'true'
561        )
562      );
563  }
564
565  return $file_path;
566}
567
568?>
Note: See TracBrowser for help on using the repository browser.