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

Last change on this file since 10641 was 10641, checked in by patdenice, 14 years ago

feature:2284
Create a class to manipulate images.

File size: 18.0 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2011 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    'websize_resize' => array(
36      'default' => true,
37      'can_be_null' => false,
38      ),
39   
40    'websize_maxwidth' => array(
41      'default' => 800,
42      'min' => 100,
43      'max' => 1600,
44      'pattern' => '/^\d+$/',
45      'can_be_null' => true,
46      'error_message' => l10n('The websize maximum width must be a number between %d and %d'),
47      ),
48 
49    'websize_maxheight' => array(
50      'default' => 600,
51      'min' => 100,
52      'max' => 1200,
53      'pattern' => '/^\d+$/',
54      'can_be_null' => true,
55      'error_message' => l10n('The websize maximum height must be a number between %d and %d'),
56      ),
57 
58    'websize_quality' => array(
59      'default' => 95,
60      'min' => 50,
61      'max' => 100,
62      'pattern' => '/^\d+$/',
63      'can_be_null' => false,
64      'error_message' => l10n('The websize image quality must be a number between %d and %d'),
65      ),
66 
67    'thumb_maxwidth' => array(
68      'default' => 128,
69      'min' => 50,
70      'max' => 300,
71      'pattern' => '/^\d+$/',
72      'can_be_null' => false,
73      'error_message' => l10n('The thumbnail maximum width must be a number between %d and %d'),
74      ),
75 
76    'thumb_maxheight' => array(
77      'default' => 96,
78      'min' => 50,
79      'max' => 300,
80      'pattern' => '/^\d+$/',
81      'can_be_null' => false,
82      'error_message' => l10n('The thumbnail maximum height must be a number between %d and %d'),
83      ),
84 
85    'thumb_quality' => array(
86      'default' => 95,
87      'min' => 50,
88      'max' => 100,
89      'pattern' => '/^\d+$/',
90      'can_be_null' => false,
91      'error_message' => l10n('The thumbnail image quality must be a number between %d and %d'),
92      ),
93
94    'thumb_crop' => array(
95      'default' => false,
96      'can_be_null' => false,
97      ),
98
99    'thumb_follow_orientation' => array(
100      'default' => true,
101      'can_be_null' => false,
102      ),
103 
104    'hd_keep' => array(
105      'default' => true,
106      'can_be_null' => false,
107      ),
108 
109    'hd_resize' => array(
110      'default' => false,
111      'can_be_null' => false,
112      ),
113 
114    'hd_maxwidth' => array(
115      'default' => 2000,
116      'min' => 500,
117      'max' => 20000,
118      'pattern' => '/^\d+$/',
119      'can_be_null' => false,
120      'error_message' => l10n('The high definition maximum width must be a number between %d and %d'),
121      ),
122 
123    'hd_maxheight' => array(
124      'default' => 2000,
125      'min' => 500,
126      'max' => 20000,
127      'pattern' => '/^\d+$/',
128      'can_be_null' => false,
129      'error_message' => l10n('The high definition maximum height must be a number between %d and %d'),
130      ),
131 
132    'hd_quality' => array(
133      'default' => 95,
134      'min' => 50,
135      'max' => 100,
136      'pattern' => '/^\d+$/',
137      'can_be_null' => false,
138      'error_message' => l10n('The high definition image quality must be a number between %d and %d'),
139      ),
140    );
141
142  return $upload_form_config;
143}
144
145/*
146 * automatic fill of configuration parameters
147 */
148function prepare_upload_configuration()
149{
150  global $conf;
151
152  $inserts = array();
153 
154  foreach (get_upload_form_config() as $param_shortname => $param)
155  {
156    $param_name = 'upload_form_'.$param_shortname;
157 
158    if (!isset($conf[$param_name]))
159    {
160      $conf[$param_name] = $param['default'];
161     
162      array_push(
163        $inserts,
164        array(
165          'param' => $param_name,
166          'value' => boolean_to_string($param['default']),
167          )
168        );
169    }
170  }
171 
172  if (count($inserts) > 0)
173  {
174    mass_inserts(
175      CONFIG_TABLE,
176      array_keys($inserts[0]),
177      $inserts
178      );
179  }
180}
181
182function save_upload_form_config($data, &$errors=array())
183{
184  if (!is_array($data) or empty($data))
185  {
186    return false;
187  }
188
189  $upload_form_config = get_upload_form_config();
190  $updates = array();
191
192  foreach ($data as $field => $value)
193  {
194    if (!isset($upload_form_config[$field]))
195    {
196      continue;
197    }
198    if (is_bool($upload_form_config[$field]['default']))
199    {
200      if (isset($value))
201      {
202        $value = true;
203      }
204      else
205      {
206        $value = false;
207      }
208
209      $updates[] = array(
210        'param' => 'upload_form_'.$field,
211        'value' => boolean_to_string($value)
212        );
213    }
214    elseif ($upload_form_config[$field]['can_be_null'] and empty($value))
215    {
216      $updates[] = array(
217        'param' => 'upload_form_'.$field,
218        'value' => 'false'
219        );
220    }
221    else
222    {
223      $min = $upload_form_config[$field]['min'];
224      $max = $upload_form_config[$field]['max'];
225      $pattern = $upload_form_config[$field]['pattern'];
226     
227      if (preg_match($pattern, $value) and $value >= $min and $value <= $max)
228      {
229         $updates[] = array(
230          'param' => 'upload_form_'.$field,
231          'value' => $value
232          );
233      }
234      else
235      {
236        array_push(
237          $errors,
238          sprintf(
239            $upload_form_config[$field]['error_message'],
240            $min,
241            $max
242            )
243          );
244      }
245    }
246  }
247
248  if (count($errors) == 0)
249  {
250    mass_updates(
251      CONFIG_TABLE,
252      array(
253        'primary' => array('param'),
254        'update' => array('value')
255        ),
256      $updates
257      );
258    return true;
259  }
260
261  return false;
262}
263
264function add_uploaded_file($source_filepath, $original_filename=null, $categories=null, $level=null, $image_id=null)
265{
266  // Here is the plan
267  //
268  // 1) move uploaded file to upload/2010/01/22/20100122003814-449ada00.jpg
269  //
270  // 2) if taller than max_height or wider than max_width, move to pwg_high
271  //    + web sized creation
272  //
273  // 3) thumbnail creation from web sized
274  //
275  // 4) register in database
276 
277  // TODO
278  // * check md5sum (already exists?)
279 
280  global $conf, $user;
281
282  $md5sum = md5_file($source_filepath);
283  $file_path = null;
284 
285  if (isset($image_id))
286  {
287    // we are performing an update
288    $query = '
289SELECT
290    path
291  FROM '.IMAGES_TABLE.'
292  WHERE id = '.$image_id.'
293;';
294    $result = pwg_query($query);
295    while ($row = pwg_db_fetch_assoc($result))
296    {
297      $file_path = $row['path'];
298    }
299   
300    if (!isset($file_path))
301    {
302      die('['.__FUNCTION__.'] this photo does not exist in the database');
303    }
304
305    // delete all physical files related to the photo (thumbnail, web site, HD)
306    delete_element_files(array($image_id));
307  }
308  else
309  {
310    // this photo is new
311   
312    // current date
313    list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
314    list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4);
315 
316    // upload directory hierarchy
317    $upload_dir = sprintf(
318      PHPWG_ROOT_PATH.$conf['upload_dir'].'/%s/%s/%s',
319      $year,
320      $month,
321      $day
322      );
323
324    // compute file path
325    $date_string = preg_replace('/[^\d]/', '', $dbnow);
326    $random_string = substr($md5sum, 0, 8);
327    $filename_wo_ext = $date_string.'-'.$random_string;
328    $file_path = $upload_dir.'/'.$filename_wo_ext.'.';
329
330    list($width, $height, $type) = getimagesize($source_filepath);
331    if (IMAGETYPE_PNG == $type)
332    {
333      $file_path.= 'png';
334    }
335    elseif (IMAGETYPE_GIF == $type)
336    {
337      $file_path.= 'gif';
338    }
339    else
340    {
341      $file_path.= 'jpg';
342    }
343
344    prepare_directory($upload_dir);
345  }
346
347  if (is_uploaded_file($source_filepath))
348  {
349    move_uploaded_file($source_filepath, $file_path);
350  }
351  else
352  {
353    copy($source_filepath, $file_path);
354  }
355
356  if ($conf['upload_form_websize_resize']
357      and need_resize($file_path, $conf['upload_form_websize_maxwidth'], $conf['upload_form_websize_maxheight']))
358  {
359    $high_path = file_path_for_type($file_path, 'high');
360    $high_dir = dirname($high_path);
361    prepare_directory($high_dir);
362   
363    rename($file_path, $high_path);
364    $high_infos = pwg_image_infos($high_path);
365   
366    $img = new pwg_image($high_path);
367
368    $img->pwg_resize(
369      $file_path,
370      $conf['upload_form_websize_maxwidth'],
371      $conf['upload_form_websize_maxheight'],
372      $conf['upload_form_websize_quality'],
373      $conf['upload_form_automatic_rotation'],
374      false
375      );
376
377    if ($img->library != 'gd')
378    {
379      if ($conf['upload_form_hd_keep'])
380      {
381        if ($conf['upload_form_hd_resize'])
382        {
383          $need_resize = need_resize($high_path, $conf['upload_form_hd_maxwidth'], $conf['upload_form_hd_maxheight']);
384       
385          if ($need_resize)
386          {
387            $img->pwg_resize(
388              $high_path,
389              $conf['upload_form_hd_maxwidth'],
390              $conf['upload_form_hd_maxheight'],
391              $conf['upload_form_hd_quality'],
392              $conf['upload_form_automatic_rotation'],
393              false
394              );
395            $high_infos = pwg_image_infos($high_path);
396          }
397        }
398      }
399      else
400      {
401        unlink($high_path);
402        $high_infos = null;
403      }
404    }
405    $img->destroy();
406  }
407
408  $file_infos = pwg_image_infos($file_path);
409 
410  $thumb_path = file_path_for_type($file_path, 'thumb');
411  $thumb_dir = dirname($thumb_path);
412  prepare_directory($thumb_dir);
413
414  $img = new pwg_image($file_path);
415  $img->pwg_resize(
416    $thumb_path,
417    $conf['upload_form_thumb_maxwidth'],
418    $conf['upload_form_thumb_maxheight'],
419    $conf['upload_form_thumb_quality'],
420    $conf['upload_form_automatic_rotation'],
421    true
422    );
423  $img->destroy();
424 
425  $thumb_infos = pwg_image_infos($thumb_path);
426
427  if (isset($image_id))
428  {
429    $update = array(
430      'id' => $image_id,
431      'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)),
432      'filesize' => $file_infos['filesize'],
433      'width' => $file_infos['width'],
434      'height' => $file_infos['height'],
435      'md5sum' => $md5sum,
436      'added_by' => $user['id'],
437      );
438   
439    if (isset($high_infos))
440    {
441      $update['has_high'] = 'true';
442      $update['high_filesize'] = $high_infos['filesize'];
443      $update['high_width'] = $high_infos['width'];
444      $update['high_height'] = $high_infos['height'];
445    }
446    else
447    {
448      $update['has_high'] = 'false';
449      $update['high_filesize'] = null;
450      $update['high_width'] = null;
451      $update['high_height'] = null;
452    }
453
454    if (isset($level))
455    {
456      $update['level'] = $level;
457    }
458
459    mass_updates(
460      IMAGES_TABLE,
461      array(
462        'primary' => array('id'),
463        'update' => array_keys($update)
464        ),
465      array($update)
466      );
467  }
468  else
469  {
470    // database registration
471    $insert = array(
472      'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)),
473      'date_available' => $dbnow,
474      'tn_ext' => 'jpg',
475      'path' => preg_replace('#^'.preg_quote(PHPWG_ROOT_PATH).'#', '', $file_path),
476      'filesize' => $file_infos['filesize'],
477      'width' => $file_infos['width'],
478      'height' => $file_infos['height'],
479      'md5sum' => $md5sum,
480      'added_by' => $user['id'],
481      );
482
483    if (isset($high_infos))
484    {
485      $insert['has_high'] = 'true';
486      $insert['high_filesize'] = $high_infos['filesize'];
487      $insert['high_width'] = $high_infos['width'];
488      $insert['high_height'] = $high_infos['height'];
489    }
490
491    if (isset($level))
492    {
493      $insert['level'] = $level;
494    }
495 
496    mass_inserts(
497      IMAGES_TABLE,
498      array_keys($insert),
499      array($insert)
500      );
501 
502    $image_id = pwg_db_insert_id(IMAGES_TABLE);
503  }
504
505  if (isset($categories) and count($categories) > 0)
506  {
507    associate_images_to_categories(
508      array($image_id),
509      $categories
510      );
511  }
512 
513  // update metadata from the uploaded file (exif/iptc)
514  if ($conf['use_exif'] and !function_exists('read_exif_data'))
515  {
516    $conf['use_exif'] = false;
517  }
518  update_metadata(array($image_id=>$file_path));
519
520  invalidate_user_cache();
521
522  return $image_id;
523}
524
525function prepare_directory($directory)
526{
527  if (!is_dir($directory)) {
528    if (substr(PHP_OS, 0, 3) == 'WIN')
529    {
530      $directory = str_replace('/', DIRECTORY_SEPARATOR, $directory);
531    }
532    umask(0000);
533    $recursive = true;
534    if (!@mkdir($directory, 0777, $recursive))
535    {
536      die('[prepare_directory] cannot create directory "'.$directory.'"');
537    }
538  }
539
540  if (!is_writable($directory))
541  {
542    // last chance to make the directory writable
543    @chmod($directory, 0777);
544
545    if (!is_writable($directory))
546    {
547      die('[prepare_directory] directory "'.$directory.'" has no write access');
548    }
549  }
550
551  secure_directory($directory);
552}
553
554function need_resize($image_filepath, $max_width, $max_height)
555{
556  // TODO : the resize check should take the orientation into account. If a
557  // rotation must be applied to the resized photo, then we should test
558  // invert width and height.
559  list($width, $height) = getimagesize($image_filepath);
560 
561  if ($width > $max_width or $height > $max_height)
562  {
563    return true;
564  }
565
566  return false;
567}
568
569function pwg_image_infos($path)
570{
571  list($width, $height) = getimagesize($path);
572  $filesize = floor(filesize($path)/1024);
573 
574  return array(
575    'width'  => $width,
576    'height' => $height,
577    'filesize' => $filesize,
578    );
579}
580
581function is_valid_image_extension($extension)
582{
583  return in_array(strtolower($extension), array('jpg', 'jpeg', 'png', 'gif'));
584}
585
586function file_upload_error_message($error_code)
587{
588  switch ($error_code) {
589    case UPLOAD_ERR_INI_SIZE:
590      return sprintf(
591        l10n('The uploaded file exceeds the upload_max_filesize directive in php.ini: %sB'),
592        get_ini_size('upload_max_filesize', false)
593        );
594    case UPLOAD_ERR_FORM_SIZE:
595      return l10n('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form');
596    case UPLOAD_ERR_PARTIAL:
597      return l10n('The uploaded file was only partially uploaded');
598    case UPLOAD_ERR_NO_FILE:
599      return l10n('No file was uploaded');
600    case UPLOAD_ERR_NO_TMP_DIR:
601      return l10n('Missing a temporary folder');
602    case UPLOAD_ERR_CANT_WRITE:
603      return l10n('Failed to write file to disk');
604    case UPLOAD_ERR_EXTENSION:
605      return l10n('File upload stopped by extension');
606    default:
607      return l10n('Unknown upload error');
608  }
609}
610
611function get_ini_size($ini_key, $in_bytes=true)
612{
613  $size = ini_get($ini_key);
614
615  if ($in_bytes)
616  {
617    $size = convert_shortand_notation_to_bytes($size);
618  }
619 
620  return $size;
621}
622
623function convert_shortand_notation_to_bytes($value)
624{
625  $suffix = substr($value, -1);
626  $multiply_by = null;
627 
628  if ('K' == $suffix)
629  {
630    $multiply_by = 1024;
631  }
632  else if ('M' == $suffix)
633  {
634    $multiply_by = 1024*1024;
635  }
636  else if ('G' == $suffix)
637  {
638    $multiply_by = 1024*1024*1024;
639  }
640 
641  if (isset($multiply_by))
642  {
643    $value = substr($value, 0, -1);
644    $value*= $multiply_by;
645  }
646
647  return $value;
648}
649
650function add_upload_error($upload_id, $error_message)
651{
652  if (!isset($_SESSION['uploads_error']))
653  {
654    $_SESSION['uploads_error'] = array();
655  }
656  if (!isset($_SESSION['uploads_error'][$upload_id]))
657  {
658    $_SESSION['uploads_error'][$upload_id] = array();
659  }
660
661  array_push($_SESSION['uploads_error'][$upload_id], $error_message);
662}
663
664function ready_for_upload_message()
665{
666  global $conf;
667
668  $relative_dir = preg_replace('#^'.PHPWG_ROOT_PATH.'#', '', $conf['upload_dir']);
669
670  if (!is_dir($conf['upload_dir']))
671  {
672    if (!is_writable(dirname($conf['upload_dir'])))
673    {
674      return sprintf(
675        l10n('Create the "%s" directory at the root of your Piwigo installation'),
676        $relative_dir
677        );
678    }
679  }
680  else
681  {
682    if (!is_writable($conf['upload_dir']))
683    {
684      @chmod($conf['upload_dir'], 0777);
685     
686      if (!is_writable($conf['upload_dir']))
687      {
688        return sprintf(
689          l10n('Give write access (chmod 777) to "%s" directory at the root of your Piwigo installation'),
690          $relative_dir
691          );
692      }
693    }
694  }
695
696  return null;
697}
698
699function file_path_for_type($file_path, $type='thumb')
700{
701  // resolve the $file_path depending on the $type
702  if ('thumb' == $type) {
703    $file_path = get_thumbnail_location(
704      array(
705        'path' => $file_path,
706        'tn_ext' => 'jpg',
707        )
708      );
709  }
710
711  if ('high' == $type) {
712    @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
713    $file_path = get_high_location(
714      array(
715        'path' => $file_path,
716        'has_high' => 'true'
717        )
718      );
719  }
720
721  return $file_path;
722}
723
724?>
Note: See TracBrowser for help on using the repository browser.