public function get_photo_types_by_extension_test() { $this->assert_equal("image/jpeg", legal_file::get_photo_types_by_extension("jpg")); // regular $this->assert_equal("image/jpeg", legal_file::get_photo_types_by_extension("JPG")); // all caps $this->assert_equal("image/png", legal_file::get_photo_types_by_extension("Png")); // some caps $this->assert_equal(null, legal_file::get_photo_types_by_extension("php")); // invalid $this->assert_equal(null, legal_file::get_photo_types_by_extension("php.jpg")); // invalid w/ . // No extension returns full array $this->assert_equal(4, count(legal_file::get_photo_types_by_extension())); }
/** * Return the width, height, mime_type and extension of the given image file. */ static function get_file_metadata($file_path) { $image_info = getimagesize($file_path); if ($image_info) { $width = $image_info[0]; $height = $image_info[1]; $mime_type = $image_info["mime"]; $extension = image_type_to_extension($image_info[2], false); return array($width, $height, $mime_type, $extension); } else { // getimagesize failed - use legal_file mapping instead. $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); $mime_type = legal_file::get_photo_types_by_extension($extension); return array(0, 0, $mime_type, $extension); } }
/** * Resize an image. Valid options are width, height and master. Master is one of the Image * master dimension constants. * * @param string $input_file * @param string $output_file * @param array $options * @param Item_Model $item (optional) */ static function resize($input_file, $output_file, $options, $item = null) { graphics::init_toolkit(); $temp_file = system::temp_filename("resize_", pathinfo($output_file, PATHINFO_EXTENSION)); module::event("graphics_resize", $input_file, $temp_file, $options, $item); if (@filesize($temp_file) > 0) { // A graphics_resize event made an image - move it to output_file and use it. @rename($temp_file, $output_file); } else { // No events made an image - proceed with standard process. if (@filesize($input_file) == 0) { throw new Exception("@todo EMPTY_INPUT_FILE"); } list($input_width, $input_height, $input_mime, $input_extension) = photo::get_file_metadata($input_file); if ($input_width && $input_height && (empty($options["width"]) || empty($options["height"]) || empty($options["master"]) || max($input_width, $input_height) <= min($options["width"], $options["height"]))) { // Photo dimensions well-defined, but options not well-defined or would upscale the image. // Do not resize. Check mimes to see if we can copy the file or if we need to convert it. // (checking mimes avoids needlessly converting jpg to jpeg, etc.) $output_mime = legal_file::get_photo_types_by_extension(pathinfo($output_file, PATHINFO_EXTENSION)); if ($input_mime && $output_mime && $input_mime == $output_mime) { // Mimes well-defined and identical - copy input to output copy($input_file, $output_file); } else { // Mimes not well-defined or not the same - convert input to output $image = Image::factory($input_file)->quality(module::get_var("gallery", "image_quality"))->save($output_file); } } else { // Resize the image. This also implicitly converts its format if needed. $image = Image::factory($input_file)->resize($options["width"], $options["height"], $options["master"])->quality(module::get_var("gallery", "image_quality")); if (graphics::can("sharpen")) { $image->sharpen(module::get_var("gallery", "image_sharpen")); } $image->save($output_file); } } module::event("graphics_resize_completed", $input_file, $output_file, $options, $item); }
/** * Sanitize a filename for a given type (given as "photo" or "movie") and a target file format * (given as an extension). This returns a completely legal and valid filename, * or throws an exception if the type or extension given is invalid or illegal. It tries to * maintain the filename's original extension even if it's not identical to the given extension * (e.g. don't change "JPG" or "jpeg" to "jpg"). * * Note: it is not okay if the extension given is legal but does not match the type (e.g. if * extension is "mp4" and type is "photo", it will throw an exception) * * @param string $filename (with no directory) * @param string $extension (can be uppercase or lowercase) * @param string $type (as "photo" or "movie") * @return string sanitized filename (or null if bad extension argument) */ static function sanitize_filename($filename, $extension, $type) { // Check if the type is valid - if so, get the mime types of the // original and target extensions; if not, throw an exception. $original_extension = pathinfo($filename, PATHINFO_EXTENSION); switch ($type) { case "photo": $mime_type = legal_file::get_photo_types_by_extension($extension); $original_mime_type = legal_file::get_photo_types_by_extension($original_extension); break; case "movie": $mime_type = legal_file::get_movie_types_by_extension($extension); $original_mime_type = legal_file::get_movie_types_by_extension($original_extension); break; default: throw new Exception("@todo INVALID_TYPE"); } // Check if the target extension is blank or invalid - if so, throw an exception. if (!$extension || !$mime_type) { throw new Exception("@todo ILLEGAL_EXTENSION"); } // Check if the mime types of the original and target extensions match - if not, fix it. if (!$original_extension || $mime_type != $original_mime_type) { $filename = legal_file::change_extension($filename, $extension); } // It should be a filename without a directory - remove all slashes (and backslashes). $filename = str_replace("/", "_", $filename); $filename = str_replace("\\", "_", $filename); // Remove extra dots from the filename. This will also remove extraneous underscores. $filename = legal_file::smash_extensions($filename); // It's possible that the filename has no base (e.g. ".jpg") - if so, give it a generic one. if (empty($filename) || substr($filename, 0, 1) == ".") { $filename = $type . $filename; // e.g. "photo.jpg" or "movie.mp4" } return $filename; }
/** * Create a default list of allowed photo MIME types and then let modules modify it. * Can be used to add legal alternatives for default MIME types. * (e.g. flv maps to video/x-flv by default, but video/flv is still legal). */ static function get_photo_types() { $types_wrapper = new stdClass(); $types_wrapper->types = array_values(legal_file::get_photo_types_by_extension()); module::event("legal_photo_types", $types_wrapper); return $types_wrapper->types; }
/** * Return the width, height, mime_type and extension of the given image file. * Metadata is first generated using getimagesize (or the legal_file mapping if it fails), * then can be modified by other modules using photo_get_file_metadata events. * * This function and its use cases are symmetric to those of photo::get_file_metadata. * * @param string $file_path * @return array array($width, $height, $mime_type, $extension) * * Use cases in detail: * Input is standard photo type (jpg/png/gif) * -> return metadata from getimagesize() * Input is *not* standard photo type that is supported by getimagesize (e.g. tif, bmp...) * -> return metadata from getimagesize() * Input is *not* standard photo type that is *not* supported by getimagesize but is legal * -> return metadata if found by photo_get_file_metadata events * Input is illegal, unidentifiable, unreadable, or does not exist * -> throw exception * Note: photo_get_file_metadata events can change any of the above cases (except the last one). */ static function get_file_metadata($file_path) { if (!is_readable($file_path)) { throw new Exception("@todo UNREADABLE_FILE"); } $metadata = new stdClass(); if ($image_info = getimagesize($file_path)) { // getimagesize worked - use its results. $metadata->width = $image_info[0]; $metadata->height = $image_info[1]; $metadata->mime_type = $image_info["mime"]; $metadata->extension = image_type_to_extension($image_info[2], false); // We prefer jpg instead of jpeg (which is returned by image_type_to_extension). if ($metadata->extension == "jpeg") { $metadata->extension = "jpg"; } } else { // getimagesize failed - try to use legal_file mapping instead. $extension = pathinfo($file_path, PATHINFO_EXTENSION); if (!$extension || !($metadata->mime_type = legal_file::get_photo_types_by_extension($extension))) { // Extension is empty or illegal. $metadata->extension = null; $metadata->mime_type = null; } else { // Extension is legal (and mime is already set above). $metadata->extension = strtolower($extension); } $metadata->width = 0; $metadata->height = 0; } // Run photo_get_file_metadata events which can modify the class. module::event("photo_get_file_metadata", $file_path, $metadata); // If the post-events results are invalid, throw an exception. if (!$metadata->width || !$metadata->height || !$metadata->mime_type || !$metadata->extension || $metadata->mime_type != legal_file::get_photo_types_by_extension($metadata->extension)) { throw new Exception("@todo ILLEGAL_OR_UNINDENTIFIABLE_FILE"); } return array($metadata->width, $metadata->height, $metadata->mime_type, $metadata->extension); }