array( 'default' => true, 'can_be_null' => false, ), 'websize_maxwidth' => array( 'default' => 800, 'min' => 100, 'max' => 1600, 'pattern' => '/^\d+$/', 'can_be_null' => true, 'error_message' => l10n('The websize maximum width must be a number between %d and %d'), ), 'websize_maxheight' => array( 'default' => 600, 'min' => 100, 'max' => 1200, 'pattern' => '/^\d+$/', 'can_be_null' => true, 'error_message' => l10n('The websize maximum height must be a number between %d and %d'), ), 'websize_quality' => array( 'default' => 95, 'min' => 50, 'max' => 100, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The websize image quality must be a number between %d and %d'), ), 'thumb_maxwidth' => array( 'default' => 128, 'min' => 50, 'max' => 300, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The thumbnail maximum width must be a number between %d and %d'), ), 'thumb_maxheight' => array( 'default' => 96, 'min' => 50, 'max' => 300, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The thumbnail maximum height must be a number between %d and %d'), ), 'thumb_quality' => array( 'default' => 95, 'min' => 50, 'max' => 100, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The thumbnail image quality must be a number between %d and %d'), ), 'thumb_crop' => array( 'default' => false, 'can_be_null' => false, ), 'thumb_follow_orientation' => array( 'default' => true, 'can_be_null' => false, ), 'hd_keep' => array( 'default' => true, 'can_be_null' => false, ), 'hd_resize' => array( 'default' => false, 'can_be_null' => false, ), 'hd_maxwidth' => array( 'default' => 2000, 'min' => 500, 'max' => 20000, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The high definition maximum width must be a number between %d and %d'), ), 'hd_maxheight' => array( 'default' => 2000, 'min' => 500, 'max' => 20000, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The high definition maximum height must be a number between %d and %d'), ), 'hd_quality' => array( 'default' => 95, 'min' => 50, 'max' => 100, 'pattern' => '/^\d+$/', 'can_be_null' => false, 'error_message' => l10n('The high definition image quality must be a number between %d and %d'), ), ); return $upload_form_config; } /* * automatic fill of configuration parameters */ function prepare_upload_configuration() { global $conf; $inserts = array(); foreach (get_upload_form_config() as $param_shortname => $param) { $param_name = 'upload_form_'.$param_shortname; if (!isset($conf[$param_name])) { $conf[$param_name] = $param['default']; array_push( $inserts, array( 'param' => $param_name, 'value' => boolean_to_string($param['default']), ) ); } } if (count($inserts) > 0) { mass_inserts( CONFIG_TABLE, array_keys($inserts[0]), $inserts ); } } function add_uploaded_file($source_filepath, $original_filename=null, $categories=null, $level=null, $image_id=null) { // Here is the plan // // 1) move uploaded file to upload/2010/01/22/20100122003814-449ada00.jpg // // 2) if taller than max_height or wider than max_width, move to pwg_high // + web sized creation // // 3) thumbnail creation from web sized // // 4) register in database // TODO // * check md5sum (already exists?) global $conf, $user; $md5sum = md5_file($source_filepath); $file_path = null; if (isset($image_id)) { // we are performing an update $query = ' SELECT path FROM '.IMAGES_TABLE.' WHERE id = '.$image_id.' ;'; $result = pwg_query($query); while ($row = pwg_db_fetch_assoc($result)) { $file_path = $row['path']; } if (!isset($file_path)) { die('['.__FUNCTION__.'] this photo does not exist in the database'); } // delete all physical files related to the photo (thumbnail, web site, HD) delete_element_files(array($image_id)); } else { // this photo is new // current date list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();')); list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4); // upload directory hierarchy $upload_dir = sprintf( PHPWG_ROOT_PATH.$conf['upload_dir'].'/%s/%s/%s', $year, $month, $day ); // compute file path $date_string = preg_replace('/[^\d]/', '', $dbnow); $random_string = substr($md5sum, 0, 8); $filename_wo_ext = $date_string.'-'.$random_string; $file_path = $upload_dir.'/'.$filename_wo_ext.'.'; list($width, $height, $type) = getimagesize($source_filepath); if (IMAGETYPE_PNG == $type) { $file_path.= 'png'; } elseif (IMAGETYPE_GIF == $type) { $file_path.= 'gif'; } else { $file_path.= 'jpg'; } prepare_directory($upload_dir); } if (is_uploaded_file($source_filepath)) { move_uploaded_file($source_filepath, $file_path); } else { copy($source_filepath, $file_path); } if ($conf['upload_form_websize_resize'] and need_resize($file_path, $conf['upload_form_websize_maxwidth'], $conf['upload_form_websize_maxheight'])) { $high_path = file_path_for_type($file_path, 'high'); $high_dir = dirname($high_path); prepare_directory($high_dir); rename($file_path, $high_path); $high_infos = pwg_image_infos($high_path); trigger_event( 'upload_image_resize', false, $high_path, $file_path, $conf['upload_form_websize_maxwidth'], $conf['upload_form_websize_maxheight'], $conf['upload_form_websize_quality'], false ); if (is_imagick()) { if ($conf['upload_form_hd_keep']) { if ($conf['upload_form_hd_resize']) { $need_resize = need_resize($high_path, $conf['upload_form_hd_maxwidth'], $conf['upload_form_hd_maxheight']); if ($need_resize) { pwg_image_resize( false, $high_path, $high_path, $conf['upload_form_hd_maxwidth'], $conf['upload_form_hd_maxheight'], $conf['upload_form_hd_quality'], false ); $high_infos = pwg_image_infos($high_path); } } } else { unlink($high_path); $high_infos = null; } } } $file_infos = pwg_image_infos($file_path); $thumb_path = file_path_for_type($file_path, 'thumb'); $thumb_dir = dirname($thumb_path); prepare_directory($thumb_dir); trigger_event( 'upload_thumbnail_resize', false, $file_path, $thumb_path, $conf['upload_form_thumb_maxwidth'], $conf['upload_form_thumb_maxheight'], $conf['upload_form_thumb_quality'], true, $conf['upload_form_thumb_crop'], $conf['upload_form_thumb_follow_orientation'] ); $thumb_infos = pwg_image_infos($thumb_path); if (isset($image_id)) { $update = array( 'id' => $image_id, 'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)), 'filesize' => $file_infos['filesize'], 'width' => $file_infos['width'], 'height' => $file_infos['height'], 'md5sum' => $md5sum, 'added_by' => $user['id'], ); if (isset($high_infos)) { $update['has_high'] = 'true'; $update['high_filesize'] = $high_infos['filesize']; $update['high_width'] = $high_infos['width']; $update['high_height'] = $high_infos['height']; } else { $update['has_high'] = 'false'; $update['high_filesize'] = null; $update['high_width'] = null; $update['high_height'] = null; } if (isset($level)) { $update['level'] = $level; } mass_updates( IMAGES_TABLE, array( 'primary' => array('id'), 'update' => array_keys($update) ), array($update) ); } else { // database registration $insert = array( 'file' => pwg_db_real_escape_string(isset($original_filename) ? $original_filename : basename($file_path)), 'date_available' => $dbnow, 'tn_ext' => 'jpg', 'path' => preg_replace('#^'.preg_quote(PHPWG_ROOT_PATH).'#', '', $file_path), 'filesize' => $file_infos['filesize'], 'width' => $file_infos['width'], 'height' => $file_infos['height'], 'md5sum' => $md5sum, 'added_by' => $user['id'], ); if (isset($high_infos)) { $insert['has_high'] = 'true'; $insert['high_filesize'] = $high_infos['filesize']; $insert['high_width'] = $high_infos['width']; $insert['high_height'] = $high_infos['height']; } if (isset($level)) { $insert['level'] = $level; } mass_inserts( IMAGES_TABLE, array_keys($insert), array($insert) ); $image_id = pwg_db_insert_id(IMAGES_TABLE); } if (isset($categories) and count($categories) > 0) { associate_images_to_categories( array($image_id), $categories ); } // update metadata from the uploaded file (exif/iptc) if ($conf['use_exif'] and !function_exists('read_exif_data')) { $conf['use_exif'] = false; } update_metadata(array($image_id=>$file_path)); invalidate_user_cache(); return $image_id; } function prepare_directory($directory) { if (!is_dir($directory)) { if (substr(PHP_OS, 0, 3) == 'WIN') { $directory = str_replace('/', DIRECTORY_SEPARATOR, $directory); } umask(0000); $recursive = true; if (!@mkdir($directory, 0777, $recursive)) { die('[prepare_directory] cannot create directory "'.$directory.'"'); } } if (!is_writable($directory)) { // last chance to make the directory writable @chmod($directory, 0777); if (!is_writable($directory)) { die('[prepare_directory] directory "'.$directory.'" has no write access'); } } secure_directory($directory); } function need_resize($image_filepath, $max_width, $max_height) { // TODO : the resize check should take the orientation into account. If a // rotation must be applied to the resized photo, then we should test // invert width and height. list($width, $height) = getimagesize($image_filepath); if ($width > $max_width or $height > $max_height) { return true; } return false; } function get_resize_dimensions($width, $height, $max_width, $max_height, $rotation=null) { $rotate_for_dimensions = false; if (isset($rotation) and in_array(abs($rotation), array(90, 270))) { $rotate_for_dimensions = true; } if ($rotate_for_dimensions) { list($width, $height) = array($height, $width); } $ratio_width = $width / $max_width; $ratio_height = $height / $max_height; $destination_width = $width; $destination_height = $height; // maximal size exceeded ? if ($ratio_width > 1 or $ratio_height > 1) { if ($ratio_width < $ratio_height) { $destination_width = round($width / $ratio_height); $destination_height = $max_height; } else { $destination_width = $max_width; $destination_height = round($height / $ratio_width); } } if ($rotate_for_dimensions) { list($destination_width, $destination_height) = array($destination_height, $destination_width); } return array( 'width' => $destination_width, 'height'=> $destination_height, ); } function pwg_image_resize($result, $source_filepath, $destination_filepath, $max_width, $max_height, $quality, $strip_metadata=false, $crop=false, $follow_orientation=true) { if ($result !== false) { //someone hooked us - so we skip return $result; } $extension = strtolower(get_extension($source_filepath)); if (is_imagick() and $extension != 'gif') { return pwg_image_resize_im($source_filepath, $destination_filepath, $max_width, $max_height, $quality, $strip_metadata, $crop, $follow_orientation); } else { return pwg_image_resize_gd($source_filepath, $destination_filepath, $max_width, $max_height, $quality, $crop, $follow_orientation); } } function pwg_image_resize_gd($source_filepath, $destination_filepath, $max_width, $max_height, $quality, $crop=false, $follow_orientation=true) { if (!function_exists('gd_info')) { return false; } $gd_info = gd_info(); // extension of the picture filename $extension = strtolower(get_extension($source_filepath)); $source_image = null; if (in_array($extension, array('jpg', 'jpeg'))) { $source_image = imagecreatefromjpeg($source_filepath); } else if ($extension == 'png') { $source_image = imagecreatefrompng($source_filepath); } elseif ($extension == 'gif' and $gd_info['GIF Read Support'] and $gd_info['GIF Create Support']) { $source_image = imagecreatefromgif($source_filepath); } else { die('[GD] unsupported file extension'); } $rotation = null; if (function_exists('imagerotate')) { $rotation = get_rotation_angle($source_filepath); } // width/height $source_width = imagesx($source_image); $source_height = imagesy($source_image); // Crop if ($crop) { $coord = get_crop_coord($source_width, $source_height, $max_width, $max_height, $follow_orientation); } $resize_dimensions = get_resize_dimensions($source_width, $source_height, $max_width, $max_height, $rotation); // testing on height is useless in theory: if width is unchanged, there // should be no resize, because width/height ratio is not modified. if ($resize_dimensions['width'] == $source_width and $resize_dimensions['height'] == $source_height) { // the image doesn't need any resize! We just copy it to the destination copy($source_filepath, $destination_filepath); return true; } $destination_image = imagecreatetruecolor($resize_dimensions['width'], $resize_dimensions['height']); imagecopyresampled( $destination_image, $source_image, 0, 0, $crop ? $coord['x'] : 0, $crop ? $coord['y'] : 0, $resize_dimensions['width'], $resize_dimensions['height'], $source_width, $source_height ); // rotation occurs only on resized photo to avoid useless memory use if (isset($rotation)) { $destination_image = imagerotate($destination_image, $rotation, 0); } $extension = strtolower(get_extension($destination_filepath)); if ($extension == 'png') { imagepng($destination_image, $destination_filepath); } elseif ($extension == 'gif') { imagegif($destination_image, $destination_filepath); } else { imagejpeg($destination_image, $destination_filepath, $quality); } // freeing memory ressources imagedestroy($source_image); imagedestroy($destination_image); // everything should be OK if we are here! return true; } function pwg_image_resize_im($source_filepath, $destination_filepath, $max_width, $max_height, $quality, $strip_metadata=false, $crop=false, $follow_orientation=true) { // extension of the picture filename $extension = strtolower(get_extension($source_filepath)); if (!in_array($extension, array('jpg', 'jpeg', 'png'))) { die('[Imagick] unsupported file extension'); } $image = new Imagick($source_filepath); $rotation = get_rotation_angle($source_filepath); // width/height $source_width = $image->getImageWidth(); $source_height = $image->getImageHeight(); // Crop if ($crop) { $coord = get_crop_coord($source_width, $source_height, $max_width, $max_height, $follow_orientation); $image->cropImage($source_width, $source_height, $coord['x'], $coord['y']); } $resize_dimensions = get_resize_dimensions($source_width, $source_height, $max_width, $max_height, $rotation); // testing on height is useless in theory: if width is unchanged, there // should be no resize, because width/height ratio is not modified. if ($resize_dimensions['width'] == $source_width and $resize_dimensions['height'] == $source_height) { // the image doesn't need any resize! We just copy it to the destination copy($source_filepath, $destination_filepath); return true; } $image->setImageCompressionQuality($quality); $image->setInterlaceScheme(Imagick::INTERLACE_LINE); if ($strip_metadata) { // we save a few kilobytes. For example a thumbnail with metadata // weights 25KB, without metadata 7KB. $image->stripImage(); } $image->resizeImage($resize_dimensions['width'], $resize_dimensions['height'], Imagick::FILTER_LANCZOS, 0.9); if (isset($rotation)) { $image->rotateImage(new ImagickPixel(), -$rotation); $image->setImageOrientation(Imagick::ORIENTATION_TOPLEFT); } $image->writeImage($destination_filepath); $image->destroy(); // everything should be OK if we are here! return true; } function get_rotation_angle($source_filepath) { global $conf; if (!$conf['upload_form_automatic_rotation']) { return null; } list($width, $height, $type) = getimagesize($source_filepath); if (IMAGETYPE_JPEG != $type) { return null; } if (!function_exists('exif_read_data')) { return null; } $rotation = null; $exif = exif_read_data($source_filepath); if (isset($exif['Orientation']) and preg_match('/^\s*(\d)/', $exif['Orientation'], $matches)) { $orientation = $matches[1]; if (in_array($orientation, array(3, 4))) { $rotation = 180; } elseif (in_array($orientation, array(5, 6))) { $rotation = 270; } elseif (in_array($orientation, array(7, 8))) { $rotation = 90; } } return $rotation; } function get_crop_coord(&$source_width, &$source_height, &$max_width, &$max_height, $follow_orientation) { $x = 0; $y = 0; if ($source_width < $source_height and $follow_orientation) { list($width, $height) = array($max_height, $max_width); $max_width = $width; $max_height = $height; } $img_ratio = $source_width / $source_height; $dest_ratio = $max_width / $max_height; if($dest_ratio > $img_ratio) { $destHeight = round($source_width * $max_height / $max_width); $y = round(($source_height - $destHeight) / 2 ); $source_height = $destHeight; } elseif ($dest_ratio < $img_ratio) { $destWidth = round($source_height * $max_width / $max_height); $x = round(($source_width - $destWidth) / 2 ); $source_width = $destWidth; } return array('x' => $x, 'y' => $y); } function pwg_image_infos($path) { list($width, $height) = getimagesize($path); $filesize = floor(filesize($path)/1024); return array( 'width' => $width, 'height' => $height, 'filesize' => $filesize, ); } function is_valid_image_extension($extension) { return in_array(strtolower($extension), array('jpg', 'jpeg', 'png', 'gif')); } function file_upload_error_message($error_code) { switch ($error_code) { case UPLOAD_ERR_INI_SIZE: return sprintf( l10n('The uploaded file exceeds the upload_max_filesize directive in php.ini: %sB'), get_ini_size('upload_max_filesize', false) ); case UPLOAD_ERR_FORM_SIZE: return l10n('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'); case UPLOAD_ERR_PARTIAL: return l10n('The uploaded file was only partially uploaded'); case UPLOAD_ERR_NO_FILE: return l10n('No file was uploaded'); case UPLOAD_ERR_NO_TMP_DIR: return l10n('Missing a temporary folder'); case UPLOAD_ERR_CANT_WRITE: return l10n('Failed to write file to disk'); case UPLOAD_ERR_EXTENSION: return l10n('File upload stopped by extension'); default: return l10n('Unknown upload error'); } } function get_ini_size($ini_key, $in_bytes=true) { $size = ini_get($ini_key); if ($in_bytes) { $size = convert_shortand_notation_to_bytes($size); } return $size; } function convert_shortand_notation_to_bytes($value) { $suffix = substr($value, -1); $multiply_by = null; if ('K' == $suffix) { $multiply_by = 1024; } else if ('M' == $suffix) { $multiply_by = 1024*1024; } else if ('G' == $suffix) { $multiply_by = 1024*1024*1024; } if (isset($multiply_by)) { $value = substr($value, 0, -1); $value*= $multiply_by; } return $value; } function add_upload_error($upload_id, $error_message) { if (!isset($_SESSION['uploads_error'])) { $_SESSION['uploads_error'] = array(); } if (!isset($_SESSION['uploads_error'][$upload_id])) { $_SESSION['uploads_error'][$upload_id] = array(); } array_push($_SESSION['uploads_error'][$upload_id], $error_message); } function is_imagick() { if (class_exists('Imagick')) { return true; } return false; } function ready_for_upload_message() { global $conf; $relative_dir = preg_replace('#^'.PHPWG_ROOT_PATH.'#', '', $conf['upload_dir']); if (!is_dir($conf['upload_dir'])) { if (!is_writable(dirname($conf['upload_dir']))) { return sprintf( l10n('Create the "%s" directory at the root of your Piwigo installation'), $relative_dir ); } } else { if (!is_writable($conf['upload_dir'])) { @chmod($conf['upload_dir'], 0777); if (!is_writable($conf['upload_dir'])) { return sprintf( l10n('Give write access (chmod 777) to "%s" directory at the root of your Piwigo installation'), $relative_dir ); } } } return null; } function file_path_for_type($file_path, $type='thumb') { // resolve the $file_path depending on the $type if ('thumb' == $type) { $file_path = get_thumbnail_location( array( 'path' => $file_path, 'tn_ext' => 'jpg', ) ); } if ('high' == $type) { @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); $file_path = get_high_location( array( 'path' => $file_path, 'has_high' => 'true' ) ); } return $file_path; } ?>