From 2fa99602c6f6431e99468ca13f4a58344a401c24 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sun, 8 Feb 2015 20:46:14 +0100 Subject: [PATCH 01/11] [ticket/8672] Add class for retrieving imagesize without download getimagesize() always downloads the complete file before checking the actual image dimensions. This class will be able to do the same without having to download possibly large files. PHPBB3-8672 --- phpBB/config/default/container/services.yml | 3 + .../default/container/services_avatar.yml | 3 + phpBB/includes/functions_upload.php | 24 +- phpBB/includes/message_parser.php | 9 +- phpBB/phpbb/avatar/driver/driver.php | 7 +- phpBB/phpbb/avatar/driver/gravatar.php | 12 +- phpBB/phpbb/avatar/driver/local.php | 8 +- phpBB/phpbb/avatar/driver/remote.php | 35 +- phpBB/phpbb/upload/imagesize.php | 549 ++++++++++++++++++ tests/avatar/manager_test.php | 5 +- tests/upload/fixture/bmp | Bin 0 -> 64 bytes tests/upload/fixture/iff | Bin 0 -> 120 bytes tests/upload/fixture/iff_maya | Bin 0 -> 88 bytes tests/upload/fixture/jp2 | Bin 0 -> 528 bytes tests/upload/fixture/jpx | Bin 0 -> 528 bytes tests/upload/fixture/psd | Bin 0 -> 6374 bytes tests/upload/fixture/tif_compressed | Bin 0 -> 236 bytes tests/upload/fixture/tif_msb | Bin 0 -> 222 bytes tests/upload/fixture/wbmp | Bin 0 -> 5 bytes tests/upload/imagesize_test.php | 99 ++++ 20 files changed, 707 insertions(+), 47 deletions(-) create mode 100644 phpBB/phpbb/upload/imagesize.php create mode 100644 tests/upload/fixture/bmp create mode 100644 tests/upload/fixture/iff create mode 100644 tests/upload/fixture/iff_maya create mode 100644 tests/upload/fixture/jp2 create mode 100644 tests/upload/fixture/jpx create mode 100644 tests/upload/fixture/psd create mode 100644 tests/upload/fixture/tif_compressed create mode 100644 tests/upload/fixture/tif_msb create mode 100644 tests/upload/fixture/wbmp create mode 100644 tests/upload/imagesize_test.php diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml index a7a7703982..11bc6728a6 100644 --- a/phpBB/config/default/container/services.yml +++ b/phpBB/config/default/container/services.yml @@ -202,6 +202,9 @@ services: template_context: class: phpbb\template\context + upload_imagesize: + class: phpbb\upload\imagesize + version_helper: class: phpbb\version_helper scope: prototype diff --git a/phpBB/config/default/container/services_avatar.yml b/phpBB/config/default/container/services_avatar.yml index e80d57cb59..c74bef3d66 100644 --- a/phpBB/config/default/container/services_avatar.yml +++ b/phpBB/config/default/container/services_avatar.yml @@ -17,6 +17,7 @@ services: class: phpbb\avatar\driver\gravatar arguments: - @config + - @upload_imagesize - %core.root_path% - %core.php_ext% - @path_helper @@ -30,6 +31,7 @@ services: class: phpbb\avatar\driver\local arguments: - @config + - @upload_imagesize - %core.root_path% - %core.php_ext% - @path_helper @@ -43,6 +45,7 @@ services: class: phpbb\avatar\driver\remote arguments: - @config + - @upload_imagesize - %core.root_path% - %core.php_ext% - @path_helper diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 21a6de7a41..f605f89d4d 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -400,28 +400,28 @@ class filespec { $this->width = $this->height = 0; - if (($this->image_info = @getimagesize($this->destination_file)) !== false) - { - $this->width = $this->image_info[0]; - $this->height = $this->image_info[1]; + // Get imagesize class + $imagesize = new \phpbb\upload\imagesize(); - if (!empty($this->image_info['mime'])) - { - $this->mimetype = $this->image_info['mime']; - } + $this->image_info = $imagesize->get_imagesize($this->destination_file, $this->mimetype); + + if ($this->image_info !== false) + { + $this->width = $this->image_info['width']; + $this->height = $this->image_info['height']; // Check image type $types = fileupload::image_types(); - if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]])) + if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']])) { - if (!isset($types[$this->image_info[2]])) + if (!isset($types[$this->image_info['type']])) { - $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info[2], $this->mimetype); + $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info['type'], $this->mimetype); } else { - $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info[2]][0], $this->extension); + $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info['type']][0], $this->extension); } } diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 8353ae6843..3d263748cb 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -339,22 +339,23 @@ class bbcode_firstpass extends bbcode if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) { - $stats = @getimagesize(htmlspecialchars_decode($in)); + $imagesize = new \phpbb\upload\imagesize(); + $size_info = $imagesize->get_imagesize(htmlspecialchars_decode($in)); - if ($stats === false) + if ($size_info === false) { $error = true; $this->warn_msg[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; } else { - if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $stats[1]) + if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $size_info['height']) { $error = true; $this->warn_msg[] = $user->lang('MAX_IMG_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']); } - if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $stats[0]) + if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $size_info['width']) { $error = true; $this->warn_msg[] = $user->lang('MAX_IMG_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); diff --git a/phpBB/phpbb/avatar/driver/driver.php b/phpBB/phpbb/avatar/driver/driver.php index b3ced7edf7..aa92ba2012 100644 --- a/phpBB/phpbb/avatar/driver/driver.php +++ b/phpBB/phpbb/avatar/driver/driver.php @@ -30,6 +30,9 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface */ protected $config; + /** @var \phpbb\upload\imagesize */ + protected $imagesize; + /** * Current $phpbb_root_path * @var string @@ -73,14 +76,16 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface * Construct a driver object * * @param \phpbb\config\config $config phpBB configuration + * @param \phpbb\upload\imagesize $imagesize phpBB imagesize class * @param string $phpbb_root_path Path to the phpBB root * @param string $php_ext PHP file extension * @param \phpbb\path_helper $path_helper phpBB path helper * @param \phpbb\cache\driver\driver_interface $cache Cache driver */ - public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null) + public function __construct(\phpbb\config\config $config, \phpbb\upload\imagesize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null) { $this->config = $config; + $this->imagesize = $imagesize; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; $this->path_helper = $path_helper; diff --git a/phpBB/phpbb/avatar/driver/gravatar.php b/phpBB/phpbb/avatar/driver/gravatar.php index 2082e0fd02..73effadc18 100644 --- a/phpBB/phpbb/avatar/driver/gravatar.php +++ b/phpBB/phpbb/avatar/driver/gravatar.php @@ -98,8 +98,8 @@ class gravatar extends \phpbb\avatar\driver\driver return false; } - // Make sure getimagesize works... - if (function_exists('getimagesize') && ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)) + // Get image dimensions if they are not set + if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) { /** * default to the minimum of the maximum allowed avatar size if the size @@ -108,20 +108,20 @@ class gravatar extends \phpbb\avatar\driver\driver $row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']); $url = $this->get_gravatar_url($row); - if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = getimagesize($url)) === false)) + if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = $this->imagesize->get_imagesize($url)) === false)) { $error[] = 'UNABLE_GET_IMAGE_SIZE'; return false; } - if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0)) + if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['width'] <= 0)) { $error[] = 'AVATAR_NO_SIZE'; return false; } - $row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data[0]; - $row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data[1]; + $row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data['width']; + $row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data['height']; } if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php index 36087f8ba0..abb07469de 100644 --- a/phpBB/phpbb/avatar/driver/local.php +++ b/phpBB/phpbb/avatar/driver/local.php @@ -172,13 +172,15 @@ class local extends \phpbb\avatar\driver\driver // Match all images in the gallery folder if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image)) { - if (function_exists('getimagesize')) + $dims = $this->imagesize->get_imagesize($file_path . '/' . $image); + + if ($dims === false) { - $dims = getimagesize($file_path . '/' . $image); + $dims = array(0, 0); } else { - $dims = array(0, 0); + $dims = array($dims['width'], $dims['height']); } $cat = ($path == $file_path) ? $user->lang['NO_AVATAR_CATEGORY'] : str_replace("$path/", '', $file_path); $avatar_list[$cat][$image] = array( diff --git a/phpBB/phpbb/avatar/driver/remote.php b/phpBB/phpbb/avatar/driver/remote.php index 4b0ee3f06f..d04f95905d 100644 --- a/phpBB/phpbb/avatar/driver/remote.php +++ b/phpBB/phpbb/avatar/driver/remote.php @@ -92,25 +92,22 @@ class remote extends \phpbb\avatar\driver\driver return false; } - // Make sure getimagesize works... - if (function_exists('getimagesize')) + // Get image dimensions + if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->get_imagesize($url)) === false)) { - if (($width <= 0 || $height <= 0) && (($image_data = @getimagesize($url)) === false)) - { - $error[] = 'UNABLE_GET_IMAGE_SIZE'; - return false; - } - - if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0)) - { - $error[] = 'AVATAR_NO_SIZE'; - return false; - } - - $width = ($width && $height) ? $width : $image_data[0]; - $height = ($width && $height) ? $height : $image_data[1]; + $error[] = 'UNABLE_GET_IMAGE_SIZE'; + return false; } + if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['height'] <= 0)) + { + $error[] = 'AVATAR_NO_SIZE'; + return false; + } + + $width = ($width && $height) ? $width : $image_data['width']; + $height = ($width && $height) ? $height : $image_data['height']; + if ($width <= 0 || $height <= 0) { $error[] = 'AVATAR_NO_SIZE'; @@ -172,15 +169,15 @@ class remote extends \phpbb\avatar\driver\driver return false; } - if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]]))) + if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']]))) { - if (!isset($types[$image_data[2]])) + if (!isset($types[$image_data['type']])) { $error[] = 'UNABLE_GET_IMAGE_SIZE'; } else { - $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data[2]][0], $extension); + $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension); } return false; diff --git a/phpBB/phpbb/upload/imagesize.php b/phpBB/phpbb/upload/imagesize.php new file mode 100644 index 0000000000..3ef258f0a2 --- /dev/null +++ b/phpBB/phpbb/upload/imagesize.php @@ -0,0 +1,549 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\upload; + +/** + * This class handles the retrieval of image dimensions + */ +class imagesize +{ + /** @var int 4-byte long size */ + const LONG_SIZE = 4; + + /** @var int 2-byte short size */ + const SHORT_SIZE = 2; + + /** @var string PNG header */ + const PNG_HEADER = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; + + /** @var int PNG IHDR offset */ + const PNG_IHDR_OFFSET = 12; + + /** @var string GIF87a header */ + const GIF87A_HEADER = "\x47\x49\x46\x38\x37\x61"; + + /** @var string GIF89a header */ + const GIF89A_HEADER = "\x47\x49\x46\x38\x39\x61"; + + /** @var int GIF header size */ + const GIF_HEADER_SIZE = 6; + + /** @var int JPG max header size. Headers can be bigger, but we'll abort + * going throught he header after this */ + const JPG_MAX_HEADER_SIZE = 24576; + + /** @var string PSD signature */ + const PSD_SIGNATURE = "8BPS"; + + /** @var int PSD header size */ + const PSD_HEADER_SIZE = 22; + + /** @var int PSD dimensions info offset */ + const PSD_DIMENSIONS_OFFSET = 14; + + /** @var int BMP header size needed for retrieving dimensions */ + const BMP_HEADER_SIZE = 26; + + /** @var string BMP signature */ + const BMP_SIGNATURE = "\x42\x4D"; + + /** qvar int BMP dimensions offset */ + const BMP_DIMENSIONS_OFFSET = 18; + + /** @var int TIF header size. The header might be larger but the dimensions + * should be in the first 512 bytes */ + const TIF_HEADER_SIZE = 512; + + /** @var int TIF tag for image height */ + const TIF_TAG_IMAGE_HEIGHT = 257; + + /** @var int TIF tag for image width */ + const TIF_TAG_IMAGE_WIDTH = 256; + + /** @var int TIF tag type for short */ + const TIF_TAG_TYPE_SHORT = 3; + + /** @var int TIF IFD entry size */ + const TIF_IFD_ENTRY_SIZE = 12; + + /** @var int IFF header size. Grab more than what should be needed to make + * sure we have the necessary data */ + const IFF_HEADER_SIZE = 32; + + /** @var string JPEG 2000 signature */ + const JPEG_2000_SIGNATURE = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; + + /** @var array Size info that is returned */ + protected $size = array(); + + /** @var string Data retrieved from remote */ + protected $data = ''; + + /** + * Get image dimensions of supplied image + * + * @param string $file Path to image that should be checked + * @param string $type Mimetype of image + * @return array|bool Array with image dimensions if successful, false if not + */ + public function get_imagesize($file, $type = '') + { + // Reset values + $this->reset_values(); + + // Treat image type as unknown if extension or mime type is unknown + if (!preg_match('/\.([a-z0-9]+)$/i', $file, $match) && empty($type)) + { + $this->get_imagesize_unknown_type($file); + } + else + { + $extension = (isset($match[1])) ? $match[1] : preg_replace('/.+\/([a-z0-9-.]+)$/i', '$1', $type); + + // Reset size info + $this->size = array(); + + switch ($extension) + { + case 'png': + $this->get_png_size($file); + break; + + case 'gif': + $this->get_gif_size($file); + break; + + case 'jpeg': + case 'jpg': + case 'jpe': + case 'jif': + case 'jfif': + case 'jfi': + $this->get_jpeg_size($file); + break; + + case 'jp2': + case 'j2k': + case 'jpf': + case 'jpg2': + case 'jpx': + case 'jpm': + $this->get_jp2_size($file); + break; + + case 'psd': + case 'photoshop': + $this->get_psd_size($file); + break; + + case 'bmp': + $this->get_bmp_size($file); + break; + + case 'tif': + case 'tiff': + // get_tif_size() sets mime type + $this->get_tif_size($file); + break; + + case 'wbm': + case 'wbmp': + case 'vnd.wap.wbmp': + $this->get_wbmp_size($file); + break; + + case 'iff': + case 'x-iff': + $this->get_iff_size($file); + break; + + default: + return false; + } + } + + return sizeof($this->size) > 1 ? $this->size : false; + } + + /** + * Get dimensions of image if type is unknown + * + * @param string $filename Path to file + */ + protected function get_imagesize_unknown_type($filename) + { + // Grab the maximum amount of bytes we might need + $data = $this->get_image($filename, 0, self::JPG_MAX_HEADER_SIZE, false); + + if ($data !== false) + { + $class_methods = preg_grep('/get_([a-z0-9]+)_size/i', get_class_methods($this)); + + foreach ($class_methods as $method) + { + call_user_func_array(array($this, $method), array($filename)); + + if (sizeof($this->size) > 1) + { + break; + } + } + } + } + + /** + * Reset values to default + */ + protected function reset_values() + { + $this->size = array(); + $this->data = ''; + } + + /** + * Set mime type based on supplied image + * + * @param int $type Type of image + */ + protected function set_image_type($type) + { + $this->size['type'] = $type; + } + + /** + * Get image from specified path/source + * + * @param string $filename Path to image + * @param int $offset Offset at which reading of the image should start + * @param int $length Maximum length that should be read + * @param bool $force_length True if the length needs to be the specified + * length, false if not. Default: true + * + * @return bool|string Image data or false if result was empty + */ + protected function get_image($filename, $offset, $length, $force_length = true) + { + if (empty($this->data)) + { + $this->data = @file_get_contents($filename, null, null, $offset, $length); + } + + // Force length to expected one. Return false if data length + // is smaller than expected length + if ($force_length === true) + { + return (strlen($this->data) < $length) ? false : substr($this->data, $offset, $length) ; + } + + return empty($this->data) ? false : $this->data; + } + + /** + * Get dimensions of PNG image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_png_size($filename) + { + // Retrieve image data including the header, the IHDR tag, and the + // following 2 chunks for the image width and height + $data = $this->get_image($filename, 0, self::PNG_IHDR_OFFSET + 3 * self::LONG_SIZE); + + // Check if header fits expected format specified by RFC 2083 + if (substr($data, 0, self::PNG_IHDR_OFFSET - self::LONG_SIZE) !== self::PNG_HEADER || substr($data, self::PNG_IHDR_OFFSET, self::LONG_SIZE) !== 'IHDR') + { + return; + } + + $this->size = unpack('Nwidth/Nheight', substr($data, self::PNG_IHDR_OFFSET + self::LONG_SIZE, self::LONG_SIZE * 2)); + + $this->set_image_type(IMAGETYPE_PNG); + } + + /** + * Get dimensions of GIF image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_gif_size($filename) + { + // Get data needed for reading image dimensions as outlined by GIF87a + // and GIF89a specifications + $data = $this->get_image($filename, 0, self::GIF_HEADER_SIZE + self::SHORT_SIZE * 2); + + $type = substr($data, 0, self::GIF_HEADER_SIZE); + if ($type !== self::GIF87A_HEADER && $type !== self::GIF89A_HEADER) + { + return; + } + + $this->size = unpack('vwidth/vheight', substr($data, self::GIF_HEADER_SIZE, self::SHORT_SIZE * 2)); + + $this->set_image_type(IMAGETYPE_GIF); + } + + /** + * Get dimensions of JPG image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_jpeg_size($filename) + { + // Do not force the data length + $data = $this->get_image($filename, 0, self::JPG_MAX_HEADER_SIZE, false); + + // Check if file is jpeg + if ($data[0] !== "\xFF" || $data[1] !== "\xD8") + { + return; + } + + // Look through file for SOF marker + for ($i = 2 * self::SHORT_SIZE; $i < strlen($data); $i++) + { + if ($data[$i] === "\xFF" && in_array($data[$i+1], array("\xC0", "\xC1", "\xC2", "\xC3", "\xC5", "\xC6", "\xC7", "\xC8", "\xC9", "\xCA", "\xCB", "\xCD", "\xCE", "\xCF"))) + { + // Extract size info from SOF marker + list(, $unpacked) = unpack("H*", substr($data, $i + self::SHORT_SIZE, 7)); + + // Get width and height from unpacked size info + $this->size = array( + 'width' => hexdec(substr($unpacked, 10, 4)), + 'height' => hexdec(substr($unpacked, 6, 4)), + ); + + break; + } + } + + $this->set_image_type(IMAGETYPE_JPEG); + } + + /** + * Get dimensions of PSD image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_psd_size($filename) + { + $data = $this->get_image($filename, 0, self::PSD_HEADER_SIZE); + + if ($data === false) + { + return; + } + + // Offset for version info is length of header but version is only a + // 16-bit unsigned value + $version = unpack('n', substr($data, self::LONG_SIZE, 2)); + + // Check if supplied file is a PSD file + if (substr($data, 0, self::LONG_SIZE) !== self::PSD_SIGNATURE || $version[1] !== 1) + { + return; + } + + $this->size = unpack('Nheight/Nwidth', substr($data, self::PSD_DIMENSIONS_OFFSET, 2 * self::LONG_SIZE)); + + $this->set_image_type(IMAGETYPE_PSD); + } + + /** + * Get dimensions of BMP image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_bmp_size($filename) + { + $data = $this->get_image($filename, 0, self::BMP_HEADER_SIZE); + + // Check if supplied file is a BMP file + if (substr($data, 0, 2) !== self::BMP_SIGNATURE) + { + return; + } + + $this->size = unpack('lwidth/lheight', substr($data, self::BMP_DIMENSIONS_OFFSET, 2 * self::LONG_SIZE)); + + $this->set_image_type(IMAGETYPE_BMP); + } + + /** + * Get dimensions of TIF/TIFF image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_tif_size($filename) + { + // Do not force length of header + $data = $this->get_image($filename, 0, self::TIF_HEADER_SIZE, false); + + $signature = substr($data, 0, self::SHORT_SIZE); + + if ($signature !== "II" && $signature !== "MM") + { + return; + } + + if ($signature === "II") + { + $type_long = 'V'; + $type_short = 'v'; + $this->set_image_type(IMAGETYPE_TIFF_II); + } + else + { + $type_long = 'N'; + $type_short = 'n'; + $this->set_image_type(IMAGETYPE_TIFF_MM); + } + + // Get offset of IFD + list(, $offset) = unpack($type_long, substr($data, self::LONG_SIZE, self::LONG_SIZE)); + + // Get size of IFD + list(, $size_ifd) = unpack($type_short, substr($data, $offset, self::SHORT_SIZE)); + + // Skip 2 bytes that define the IFD size + $offset += self::SHORT_SIZE; + + // Filter through IFD + for ($i = 0; $i < $size_ifd; $i++) + { + // Get IFD tag + $type = unpack($type_short, substr($data, $offset, self::SHORT_SIZE)); + + // Get field type of tag + $field_type = unpack($type_short . 'type', substr($data, $offset + self::SHORT_SIZE, self::SHORT_SIZE)); + + // Get IFD entry + $ifd_value = substr($data, $offset + 2 * self::LONG_SIZE, self::LONG_SIZE); + + // Get actual dimensions from IFD + if ($type[1] === self::TIF_TAG_IMAGE_HEIGHT) + { + $this->size = array_merge($this->size, ($field_type['type'] === self::TIF_TAG_TYPE_SHORT) ? unpack($type_short . 'height', $ifd_value) : unpack($type_long . 'height', $ifd_value)); + } + else if ($type[1] === self::TIF_TAG_IMAGE_WIDTH) + { + $this->size = array_merge($this->size, ($field_type['type'] === self::TIF_TAG_TYPE_SHORT) ? unpack($type_short .'width', $ifd_value) : unpack($type_long . 'width', $ifd_value)); + } + + $offset += self::TIF_IFD_ENTRY_SIZE; + } + } + + /** + * Get dimensions of WBMP image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_wbmp_size($filename) + { + $data = $this->get_image($filename, 0, self::LONG_SIZE); + + // Check if image is WBMP + if (ord($data[0]) !== 0 || ord($data[1]) !== 0 || $data === substr(self::JPEG_2000_SIGNATURE, 0, 4)) + { + return; + } + + $this->size = unpack('Cwidth/Cheight', substr($data, self::SHORT_SIZE, self::SHORT_SIZE)); + + $this->set_image_type(IMAGETYPE_WBMP); + } + + /** + * Get dimensions of IFF image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_iff_size($filename) + { + $data = $this->get_image($filename, 0, self::IFF_HEADER_SIZE); + + $signature = substr($data, 0, self::LONG_SIZE ); + + // Check if image is IFF + if ($signature !== 'FORM' && $signature !== 'FOR4') + { + return; + } + + // Amiga version of IFF + if ($signature === 'FORM') + { + $btmhd_position = strpos($data, 'BMHD'); + $this->size = unpack('nwidth/nheight', substr($data, $btmhd_position + 2 * self::LONG_SIZE, self::LONG_SIZE)); + } + // Maya version + else + { + $btmhd_position = strpos($data, 'BHD'); + $this->size = unpack('Nwidth/Nheight', substr($data, $btmhd_position + 2 * self::LONG_SIZE - 1, self::LONG_SIZE * 2)); + } + + $this->set_image_type(IMAGETYPE_IFF); + } + + /** + * Get dimensions of JPEG 2000 image + * + * @param string $filename Filename of image + * + * @return array|bool Array with image dimensions if successful, false if not + */ + protected function get_jp2_size($filename) + { + $data = $this->get_image($filename, 0, self::JPG_MAX_HEADER_SIZE, false); + + // Check if file is jpeg 2000 + if (substr($data, 0, strlen(self::JPEG_2000_SIGNATURE)) !== self::JPEG_2000_SIGNATURE) + { + return; + } + + // Get SOC position before starting to search for SIZ + $soc_position = strpos($data, "\xFF\x4F"); + + // Make sure we do not get SIZ before SOC + $data = substr($data, $soc_position); + + $siz_position = strpos($data, "\xFF\x51"); + + // Remove SIZ and everything before + $data = substr($data, $siz_position + self::SHORT_SIZE); + + // Acquire size info from data + $this->size = unpack('Nwidth/Nheight', substr($data, self::LONG_SIZE, self::LONG_SIZE * 2)); + + $this->set_image_type(IMAGETYPE_JPEG2000); + } +} diff --git a/tests/avatar/manager_test.php b/tests/avatar/manager_test.php index 4befbfc1fc..14c88c8da5 100644 --- a/tests/avatar/manager_test.php +++ b/tests/avatar/manager_test.php @@ -57,9 +57,10 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case new \phpbb\mimetype\content_guesser, ); $guesser = new \phpbb\mimetype\guesser($guessers); + $imagesize = new \phpbb\upload\imagesize(); // $this->avatar_foobar will be needed later on - $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $cache)); + $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache)); $this->avatar_foobar->expects($this->any()) ->method('get_name') ->will($this->returnValue('avatar.driver.foobar')); @@ -74,7 +75,7 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case { if ($driver !== 'upload') { - $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $cache)); + $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache)); } else { diff --git a/tests/upload/fixture/bmp b/tests/upload/fixture/bmp new file mode 100644 index 0000000000000000000000000000000000000000..04bff561abb60aa55c55dffabbc966bc06f70b2a GIT binary patch literal 64 pcmZ?rbzp!1Ga#h_#7scU2*wgXl7WE>h=sTz7%TuJ{(}LC2LOG{2Z#Uw literal 0 HcmV?d00001 diff --git a/tests/upload/fixture/iff b/tests/upload/fixture/iff new file mode 100644 index 0000000000000000000000000000000000000000..24eda8f593f270038b1de32859587e2c04b5b6e0 GIT binary patch literal 120 ycmZ?s5AtPTU?}kPaq@NY^>6{QMHrYE7=bi{1ejuE1o55xT_S-(9*hSVsDc2^pBJY9 literal 0 HcmV?d00001 diff --git a/tests/upload/fixture/iff_maya b/tests/upload/fixture/iff_maya new file mode 100644 index 0000000000000000000000000000000000000000..b6fb85101b80e427a136e1ea30c81728e92c3f3e GIT binary patch literal 88 zcmZ?s4>Dn3Ud?Tzqu{_GB%r{c%OSwPV#UiO!S&KnbaR>aDaUhsg)A)YCw0zTTrcix(^`K+D{LmS+HI zvCNE=A|TBO#7qp#?Cc;01AlUUP7xzmPyoo4DoQO@0MbH0I+KtyzyowFBO@y_GXvxQ7zSYn2M><`Wb}Um11N477(^M^{!c!?g@a*3Ljzn;kP#>d Yltc(Hp$jmh3$UOIumS}dfQH@#09mnxvH$=8 literal 0 HcmV?d00001 diff --git a/tests/upload/fixture/jpx b/tests/upload/fixture/jpx new file mode 100644 index 0000000000000000000000000000000000000000..adca6ecf0e6fba37b18af99b02ab533a83709e34 GIT binary patch literal 528 zcmZQzVBpCLP*C9IYUg5LV30{GsVvAUFj4@r89;PaK}8Y}gZQ~cMX7~M|NsB^z`)AD z*ucQR>d?Tzqu{_GB%r{c%OSwPV#UiO!S&KnbaR>aDaUhsg)A)YCw0zTTrcix(^`K+D{LmS+HI zvCNE=A|TBO#7qp#?Cc;01AlUUP7xzmPyoo4DoQO@0MbH0I+KtyzyowFBO@y_GXvxQ7zSYn2M><`Wb}Um11N477(^M^{!c!?g@a*3Ljzn;kP#>d Yltc(Hp$jmh3$UOIumS}dfQH@#09mnxvH$=8 literal 0 HcmV?d00001 diff --git a/tests/upload/fixture/psd b/tests/upload/fixture/psd new file mode 100644 index 0000000000000000000000000000000000000000..d1bc9a6a709d5b1a64b513f8c243af06db190a86 GIT binary patch literal 6374 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 bloZTR9eK9341(~U+uGVjhwqQ}SHu4UQ3u5M literal 0 HcmV?d00001 diff --git a/tests/upload/fixture/tif_compressed b/tests/upload/fixture/tif_compressed new file mode 100644 index 0000000000000000000000000000000000000000..133b50c4f0948c97c9bbf7f12c9e0980f5e202fc GIT binary patch literal 236 zcmebD)MDUZU|?8yLfIfWCLo&`NS^~@W~ewTkj;jqUXT%D z&J&=x5RzU|C>x|-3`txZs-7JvF2%?Sw)YBPx# literal 0 HcmV?d00001 diff --git a/tests/upload/fixture/wbmp b/tests/upload/fixture/wbmp new file mode 100644 index 0000000000000000000000000000000000000000..708c86ccee4dd58a627667b1fc88eb484b16ad71 GIT binary patch literal 5 McmZQzU}8J~007MZ!~g&Q literal 0 HcmV?d00001 diff --git a/tests/upload/imagesize_test.php b/tests/upload/imagesize_test.php new file mode 100644 index 0000000000..2ce712e5c1 --- /dev/null +++ b/tests/upload/imagesize_test.php @@ -0,0 +1,99 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once(__DIR__ . '/../../phpBB/includes/functions.php'); + +class phpbb_upload_imagesize_test extends \phpbb_test_case +{ + /** @var \phpbb\upload\imagesize */ + protected $imagesize; + + /** @var string Path to fixtures */ + protected $path; + + public function setUp() + { + parent::setUp(); + $this->imagesize = new \phpbb\upload\imagesize(); + $this->path = __DIR__ . '/fixture/'; + } + + public function data_get_imagesize() + { + return array( + array('foobar', 'image/bmp', false), + array('png', 'image/png', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_PNG)), + array('gif', 'image/png', false), + array('png', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_PNG)), + array('gif', 'image/gif', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_GIF)), + array('jpg', 'image/gif', false), + array('gif', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_GIF)), + array('jpg', 'image/jpg', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)), + array('jpg', 'image/jpeg', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)), + array('png', 'image/jpg', false), + array('jpg', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)), + array('psd', 'image/psd', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)), + array('psd', 'image/photoshop', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)), + array('jpg', 'image/psd', false), + array('psd', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)), + array('bmp', 'image/bmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_BMP)), + array('png', 'image/bmp', false), + array('bmp', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_BMP)), + array('tif', 'image/tif', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('png', 'image/tif', false), + array('tif', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('tif_compressed', 'image/tif', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('png', 'image/tiff', false), + array('tif_compressed', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('tif_msb', 'image/tif', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_MM)), + array('tif_msb', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_MM)), + array('wbmp', 'image/wbmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)), + array('wbmp', 'image/vnd.wap.wbmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)), + array('png', 'image/vnd.wap.wbmp', false), + array('wbmp', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)), + array('iff', 'image/iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('iff', 'image/x-iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('iff_maya', 'iamge/iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('png', 'image/iff', false), + array('png', 'image/x-iff', false), + array('iff', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('iff_maya', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('jp2', 'image/jp2', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jp2', 'image/jpx', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jp2', 'image/jpm', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jpg', 'image/jp2', false), + array('jpx', 'image/jpx', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jp2', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jpx', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + ); + } + + /** + * @dataProvider data_get_imagesize + */ + public function test_get_imagesize($file, $mime_type, $expected) + { + $this->assertEquals($expected, $this->imagesize->get_imagesize($this->path . $file, $mime_type)); + } + + public function test_get_imagesize_remote() + { + $this->assertSame(array( + 'width' => 80, + 'height' => 80, + 'type' => IMAGETYPE_JPEG, + ), + $this->imagesize->get_imagesize('https://secure.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0.jpg')); + } +} From 245d042e43374e6467f447507783a68fae186ef1 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Mon, 6 Apr 2015 21:32:22 +0200 Subject: [PATCH 02/11] [ticket/8672] Updated the text_formatter.s9e service PHPBB3-8672 --- phpBB/phpbb/textformatter/s9e/parser.php | 14 +++++--------- tests/test_framework/phpbb_test_case_helpers.php | 4 ++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php index 77328ee4d9..0582f235e0 100644 --- a/phpBB/phpbb/textformatter/s9e/parser.php +++ b/phpBB/phpbb/textformatter/s9e/parser.php @@ -367,7 +367,6 @@ class parser implements \phpbb\textformatter\parser_interface { // Validate the URL $url = BuiltInFilters::filterUrl($url, $url_config, $logger); - if ($url === false) { return false; @@ -375,26 +374,23 @@ class parser implements \phpbb\textformatter\parser_interface if ($max_height || $max_width) { - $stats = @getimagesize($url); - - if ($stats === false) + $imagesize = new \phpbb\upload\imagesize(); + $size_info = $imagesize->get_imagesize($url); + if ($size_info === false) { $logger->err('UNABLE_GET_IMAGE_SIZE'); - return false; } - if ($max_height && $max_height < $stats[1]) + if ($max_height && $max_height < $size_info['height']) { $logger->err('MAX_IMG_HEIGHT_EXCEEDED', array('max_height' => $max_height)); - return false; } - if ($max_width && $max_width < $stats[0]) + if ($max_width && $max_width < $size_info['width']) { $logger->err('MAX_IMG_WIDTH_EXCEEDED', array('max_width' => $max_width)); - return false; } } diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 09fec38013..0f9b049f44 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -458,6 +458,10 @@ class phpbb_test_case_helpers { $dispatcher = new phpbb_mock_event_dispatcher; } + if (!isset($phpbb_dispatcher)) + { + $phpbb_dispatcher = $dispatcher; + } // Create and register the text_formatter.s9e.factory service $factory = new \phpbb\textformatter\s9e\factory($dal, $cache, $dispatcher, $cache_dir, $cache_key_parser, $cache_key_renderer); From 3fc7a352ff308ff4b5a038e807a6f803572242d5 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Tue, 7 Apr 2015 16:11:36 +0200 Subject: [PATCH 03/11] [ticket/8672] Add fast-image-size library to composer.json PHPBB3-8672 --- phpBB/composer.json | 1 + phpBB/composer.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/phpBB/composer.json b/phpBB/composer.json index 46c0e9b361..31462b81eb 100644 --- a/phpBB/composer.json +++ b/phpBB/composer.json @@ -26,6 +26,7 @@ }, "require": { "lusitanian/oauth": "0.2.*", + "marc1706/fast-image-size": "1.0.*", "patchwork/utf8": "1.1.*", "php": ">=5.3.9", "s9e/text-formatter": "dev-release/php5.3", diff --git a/phpBB/composer.lock b/phpBB/composer.lock index adc109b0ee..3bff2429d6 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -69,6 +69,57 @@ ], "time": "2013-08-29 21:40:04" }, + { + "name": "marc1706/fast-image-size", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/marc1706/fast-image-size.git", + "reference": "99fb3c4aab631a39db7e8638450b59f562a47bb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/99fb3c4aab631a39db7e8638450b59f562a47bb1", + "reference": "99fb3c4aab631a39db7e8638450b59f562a47bb1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "fastImageSize\\": "lib", + "fastImageSize\\tests\\": "tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marc Alexander", + "email": "admin@m-a-styles.de", + "homepage": "https://www.m-a-styles.de", + "role": "Developer" + } + ], + "description": "fast-image-size is a PHP library that does almost everything PHP's getimagesize() does but without the large overhead of downloading the complete file.", + "homepage": "https://www.m-a-styles.de", + "keywords": [ + "fast", + "getimagesize", + "image", + "imagesize", + "php", + "size" + ], + "time": "2015-04-07 13:37:04" + }, { "name": "patchwork/utf8", "version": "v1.1.26", From 39d6180c6814996dde84cfcd8c0150bba37354ac Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Tue, 7 Apr 2015 16:19:36 +0200 Subject: [PATCH 04/11] [ticket/8672] Use fastImageSize in classes PHPBB3-8672 --- phpBB/config/default/container/services.yml | 2 +- phpBB/includes/functions_upload.php | 4 ++-- phpBB/includes/message_parser.php | 4 ++-- phpBB/phpbb/avatar/driver/driver.php | 6 +++--- phpBB/phpbb/avatar/driver/gravatar.php | 2 +- phpBB/phpbb/avatar/driver/local.php | 2 +- phpBB/phpbb/avatar/driver/remote.php | 2 +- phpBB/phpbb/textformatter/s9e/parser.php | 4 ++-- tests/avatar/manager_test.php | 2 +- tests/upload/imagesize_test.php | 8 ++++---- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml index 11bc6728a6..682eaeb200 100644 --- a/phpBB/config/default/container/services.yml +++ b/phpBB/config/default/container/services.yml @@ -203,7 +203,7 @@ services: class: phpbb\template\context upload_imagesize: - class: phpbb\upload\imagesize + class: fastImageSize\fastImageSize version_helper: class: phpbb\version_helper diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index f605f89d4d..ea82a23082 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -401,9 +401,9 @@ class filespec $this->width = $this->height = 0; // Get imagesize class - $imagesize = new \phpbb\upload\imagesize(); + $imagesize = new \fastImageSize\fastImageSize(); - $this->image_info = $imagesize->get_imagesize($this->destination_file, $this->mimetype); + $this->image_info = $imagesize->getImageSize($this->destination_file, $this->mimetype); if ($this->image_info !== false) { diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 3d263748cb..bc53336a3f 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -339,8 +339,8 @@ class bbcode_firstpass extends bbcode if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) { - $imagesize = new \phpbb\upload\imagesize(); - $size_info = $imagesize->get_imagesize(htmlspecialchars_decode($in)); + $imagesize = new \fastImageSize\fastImageSize(); + $size_info = $imagesize->getImageSize(htmlspecialchars_decode($in)); if ($size_info === false) { diff --git a/phpBB/phpbb/avatar/driver/driver.php b/phpBB/phpbb/avatar/driver/driver.php index aa92ba2012..b6fd380bda 100644 --- a/phpBB/phpbb/avatar/driver/driver.php +++ b/phpBB/phpbb/avatar/driver/driver.php @@ -30,7 +30,7 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface */ protected $config; - /** @var \phpbb\upload\imagesize */ + /** @var \fastImageSize\fastImageSize */ protected $imagesize; /** @@ -76,13 +76,13 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface * Construct a driver object * * @param \phpbb\config\config $config phpBB configuration - * @param \phpbb\upload\imagesize $imagesize phpBB imagesize class + * @param \fastImageSize\fastImageSize $imagesize fastImageSize class * @param string $phpbb_root_path Path to the phpBB root * @param string $php_ext PHP file extension * @param \phpbb\path_helper $path_helper phpBB path helper * @param \phpbb\cache\driver\driver_interface $cache Cache driver */ - public function __construct(\phpbb\config\config $config, \phpbb\upload\imagesize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null) + public function __construct(\phpbb\config\config $config, \fastImageSize\fastImageSize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null) { $this->config = $config; $this->imagesize = $imagesize; diff --git a/phpBB/phpbb/avatar/driver/gravatar.php b/phpBB/phpbb/avatar/driver/gravatar.php index 73effadc18..badbd9421d 100644 --- a/phpBB/phpbb/avatar/driver/gravatar.php +++ b/phpBB/phpbb/avatar/driver/gravatar.php @@ -108,7 +108,7 @@ class gravatar extends \phpbb\avatar\driver\driver $row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']); $url = $this->get_gravatar_url($row); - if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = $this->imagesize->get_imagesize($url)) === false)) + if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false)) { $error[] = 'UNABLE_GET_IMAGE_SIZE'; return false; diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php index abb07469de..88a139f81e 100644 --- a/phpBB/phpbb/avatar/driver/local.php +++ b/phpBB/phpbb/avatar/driver/local.php @@ -172,7 +172,7 @@ class local extends \phpbb\avatar\driver\driver // Match all images in the gallery folder if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image)) { - $dims = $this->imagesize->get_imagesize($file_path . '/' . $image); + $dims = $this->imagesize->getImageSize($file_path . '/' . $image); if ($dims === false) { diff --git a/phpBB/phpbb/avatar/driver/remote.php b/phpBB/phpbb/avatar/driver/remote.php index d04f95905d..90443c9b4e 100644 --- a/phpBB/phpbb/avatar/driver/remote.php +++ b/phpBB/phpbb/avatar/driver/remote.php @@ -93,7 +93,7 @@ class remote extends \phpbb\avatar\driver\driver } // Get image dimensions - if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->get_imagesize($url)) === false)) + if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false)) { $error[] = 'UNABLE_GET_IMAGE_SIZE'; return false; diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php index 0582f235e0..e46a0578d2 100644 --- a/phpBB/phpbb/textformatter/s9e/parser.php +++ b/phpBB/phpbb/textformatter/s9e/parser.php @@ -374,8 +374,8 @@ class parser implements \phpbb\textformatter\parser_interface if ($max_height || $max_width) { - $imagesize = new \phpbb\upload\imagesize(); - $size_info = $imagesize->get_imagesize($url); + $imagesize = new \fastImageSize\fastImageSize(); + $size_info = $imagesize->getImageSize($url); if ($size_info === false) { $logger->err('UNABLE_GET_IMAGE_SIZE'); diff --git a/tests/avatar/manager_test.php b/tests/avatar/manager_test.php index 14c88c8da5..638ba0aaff 100644 --- a/tests/avatar/manager_test.php +++ b/tests/avatar/manager_test.php @@ -57,7 +57,7 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case new \phpbb\mimetype\content_guesser, ); $guesser = new \phpbb\mimetype\guesser($guessers); - $imagesize = new \phpbb\upload\imagesize(); + $imagesize = new \fastImageSize\fastImageSize(); // $this->avatar_foobar will be needed later on $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache)); diff --git a/tests/upload/imagesize_test.php b/tests/upload/imagesize_test.php index 2ce712e5c1..bfea4b819d 100644 --- a/tests/upload/imagesize_test.php +++ b/tests/upload/imagesize_test.php @@ -16,7 +16,7 @@ require_once(__DIR__ . '/../../phpBB/includes/functions.php'); class phpbb_upload_imagesize_test extends \phpbb_test_case { - /** @var \phpbb\upload\imagesize */ + /** @var \fastImageSize\fastImageSize */ protected $imagesize; /** @var string Path to fixtures */ @@ -25,7 +25,7 @@ class phpbb_upload_imagesize_test extends \phpbb_test_case public function setUp() { parent::setUp(); - $this->imagesize = new \phpbb\upload\imagesize(); + $this->imagesize = new \fastImageSize\fastImageSize(); $this->path = __DIR__ . '/fixture/'; } @@ -84,7 +84,7 @@ class phpbb_upload_imagesize_test extends \phpbb_test_case */ public function test_get_imagesize($file, $mime_type, $expected) { - $this->assertEquals($expected, $this->imagesize->get_imagesize($this->path . $file, $mime_type)); + $this->assertEquals($expected, $this->imagesize->getImageSize($this->path . $file, $mime_type)); } public function test_get_imagesize_remote() @@ -94,6 +94,6 @@ class phpbb_upload_imagesize_test extends \phpbb_test_case 'height' => 80, 'type' => IMAGETYPE_JPEG, ), - $this->imagesize->get_imagesize('https://secure.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0.jpg')); + $this->imagesize->getImageSize('https://secure.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0.jpg')); } } From f92d8944704161668e3fa2a868711730fbcc777d Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Tue, 7 Apr 2015 16:47:10 +0200 Subject: [PATCH 05/11] [ticket/8672] Remove outdated imagesize class PHPBB3-8672 --- phpBB/phpbb/upload/imagesize.php | 549 ------------------------------- 1 file changed, 549 deletions(-) delete mode 100644 phpBB/phpbb/upload/imagesize.php diff --git a/phpBB/phpbb/upload/imagesize.php b/phpBB/phpbb/upload/imagesize.php deleted file mode 100644 index 3ef258f0a2..0000000000 --- a/phpBB/phpbb/upload/imagesize.php +++ /dev/null @@ -1,549 +0,0 @@ - - * @license GNU General Public License, version 2 (GPL-2.0) - * - * For full copyright and license information, please see - * the docs/CREDITS.txt file. - * - */ - -namespace phpbb\upload; - -/** - * This class handles the retrieval of image dimensions - */ -class imagesize -{ - /** @var int 4-byte long size */ - const LONG_SIZE = 4; - - /** @var int 2-byte short size */ - const SHORT_SIZE = 2; - - /** @var string PNG header */ - const PNG_HEADER = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; - - /** @var int PNG IHDR offset */ - const PNG_IHDR_OFFSET = 12; - - /** @var string GIF87a header */ - const GIF87A_HEADER = "\x47\x49\x46\x38\x37\x61"; - - /** @var string GIF89a header */ - const GIF89A_HEADER = "\x47\x49\x46\x38\x39\x61"; - - /** @var int GIF header size */ - const GIF_HEADER_SIZE = 6; - - /** @var int JPG max header size. Headers can be bigger, but we'll abort - * going throught he header after this */ - const JPG_MAX_HEADER_SIZE = 24576; - - /** @var string PSD signature */ - const PSD_SIGNATURE = "8BPS"; - - /** @var int PSD header size */ - const PSD_HEADER_SIZE = 22; - - /** @var int PSD dimensions info offset */ - const PSD_DIMENSIONS_OFFSET = 14; - - /** @var int BMP header size needed for retrieving dimensions */ - const BMP_HEADER_SIZE = 26; - - /** @var string BMP signature */ - const BMP_SIGNATURE = "\x42\x4D"; - - /** qvar int BMP dimensions offset */ - const BMP_DIMENSIONS_OFFSET = 18; - - /** @var int TIF header size. The header might be larger but the dimensions - * should be in the first 512 bytes */ - const TIF_HEADER_SIZE = 512; - - /** @var int TIF tag for image height */ - const TIF_TAG_IMAGE_HEIGHT = 257; - - /** @var int TIF tag for image width */ - const TIF_TAG_IMAGE_WIDTH = 256; - - /** @var int TIF tag type for short */ - const TIF_TAG_TYPE_SHORT = 3; - - /** @var int TIF IFD entry size */ - const TIF_IFD_ENTRY_SIZE = 12; - - /** @var int IFF header size. Grab more than what should be needed to make - * sure we have the necessary data */ - const IFF_HEADER_SIZE = 32; - - /** @var string JPEG 2000 signature */ - const JPEG_2000_SIGNATURE = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; - - /** @var array Size info that is returned */ - protected $size = array(); - - /** @var string Data retrieved from remote */ - protected $data = ''; - - /** - * Get image dimensions of supplied image - * - * @param string $file Path to image that should be checked - * @param string $type Mimetype of image - * @return array|bool Array with image dimensions if successful, false if not - */ - public function get_imagesize($file, $type = '') - { - // Reset values - $this->reset_values(); - - // Treat image type as unknown if extension or mime type is unknown - if (!preg_match('/\.([a-z0-9]+)$/i', $file, $match) && empty($type)) - { - $this->get_imagesize_unknown_type($file); - } - else - { - $extension = (isset($match[1])) ? $match[1] : preg_replace('/.+\/([a-z0-9-.]+)$/i', '$1', $type); - - // Reset size info - $this->size = array(); - - switch ($extension) - { - case 'png': - $this->get_png_size($file); - break; - - case 'gif': - $this->get_gif_size($file); - break; - - case 'jpeg': - case 'jpg': - case 'jpe': - case 'jif': - case 'jfif': - case 'jfi': - $this->get_jpeg_size($file); - break; - - case 'jp2': - case 'j2k': - case 'jpf': - case 'jpg2': - case 'jpx': - case 'jpm': - $this->get_jp2_size($file); - break; - - case 'psd': - case 'photoshop': - $this->get_psd_size($file); - break; - - case 'bmp': - $this->get_bmp_size($file); - break; - - case 'tif': - case 'tiff': - // get_tif_size() sets mime type - $this->get_tif_size($file); - break; - - case 'wbm': - case 'wbmp': - case 'vnd.wap.wbmp': - $this->get_wbmp_size($file); - break; - - case 'iff': - case 'x-iff': - $this->get_iff_size($file); - break; - - default: - return false; - } - } - - return sizeof($this->size) > 1 ? $this->size : false; - } - - /** - * Get dimensions of image if type is unknown - * - * @param string $filename Path to file - */ - protected function get_imagesize_unknown_type($filename) - { - // Grab the maximum amount of bytes we might need - $data = $this->get_image($filename, 0, self::JPG_MAX_HEADER_SIZE, false); - - if ($data !== false) - { - $class_methods = preg_grep('/get_([a-z0-9]+)_size/i', get_class_methods($this)); - - foreach ($class_methods as $method) - { - call_user_func_array(array($this, $method), array($filename)); - - if (sizeof($this->size) > 1) - { - break; - } - } - } - } - - /** - * Reset values to default - */ - protected function reset_values() - { - $this->size = array(); - $this->data = ''; - } - - /** - * Set mime type based on supplied image - * - * @param int $type Type of image - */ - protected function set_image_type($type) - { - $this->size['type'] = $type; - } - - /** - * Get image from specified path/source - * - * @param string $filename Path to image - * @param int $offset Offset at which reading of the image should start - * @param int $length Maximum length that should be read - * @param bool $force_length True if the length needs to be the specified - * length, false if not. Default: true - * - * @return bool|string Image data or false if result was empty - */ - protected function get_image($filename, $offset, $length, $force_length = true) - { - if (empty($this->data)) - { - $this->data = @file_get_contents($filename, null, null, $offset, $length); - } - - // Force length to expected one. Return false if data length - // is smaller than expected length - if ($force_length === true) - { - return (strlen($this->data) < $length) ? false : substr($this->data, $offset, $length) ; - } - - return empty($this->data) ? false : $this->data; - } - - /** - * Get dimensions of PNG image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_png_size($filename) - { - // Retrieve image data including the header, the IHDR tag, and the - // following 2 chunks for the image width and height - $data = $this->get_image($filename, 0, self::PNG_IHDR_OFFSET + 3 * self::LONG_SIZE); - - // Check if header fits expected format specified by RFC 2083 - if (substr($data, 0, self::PNG_IHDR_OFFSET - self::LONG_SIZE) !== self::PNG_HEADER || substr($data, self::PNG_IHDR_OFFSET, self::LONG_SIZE) !== 'IHDR') - { - return; - } - - $this->size = unpack('Nwidth/Nheight', substr($data, self::PNG_IHDR_OFFSET + self::LONG_SIZE, self::LONG_SIZE * 2)); - - $this->set_image_type(IMAGETYPE_PNG); - } - - /** - * Get dimensions of GIF image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_gif_size($filename) - { - // Get data needed for reading image dimensions as outlined by GIF87a - // and GIF89a specifications - $data = $this->get_image($filename, 0, self::GIF_HEADER_SIZE + self::SHORT_SIZE * 2); - - $type = substr($data, 0, self::GIF_HEADER_SIZE); - if ($type !== self::GIF87A_HEADER && $type !== self::GIF89A_HEADER) - { - return; - } - - $this->size = unpack('vwidth/vheight', substr($data, self::GIF_HEADER_SIZE, self::SHORT_SIZE * 2)); - - $this->set_image_type(IMAGETYPE_GIF); - } - - /** - * Get dimensions of JPG image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_jpeg_size($filename) - { - // Do not force the data length - $data = $this->get_image($filename, 0, self::JPG_MAX_HEADER_SIZE, false); - - // Check if file is jpeg - if ($data[0] !== "\xFF" || $data[1] !== "\xD8") - { - return; - } - - // Look through file for SOF marker - for ($i = 2 * self::SHORT_SIZE; $i < strlen($data); $i++) - { - if ($data[$i] === "\xFF" && in_array($data[$i+1], array("\xC0", "\xC1", "\xC2", "\xC3", "\xC5", "\xC6", "\xC7", "\xC8", "\xC9", "\xCA", "\xCB", "\xCD", "\xCE", "\xCF"))) - { - // Extract size info from SOF marker - list(, $unpacked) = unpack("H*", substr($data, $i + self::SHORT_SIZE, 7)); - - // Get width and height from unpacked size info - $this->size = array( - 'width' => hexdec(substr($unpacked, 10, 4)), - 'height' => hexdec(substr($unpacked, 6, 4)), - ); - - break; - } - } - - $this->set_image_type(IMAGETYPE_JPEG); - } - - /** - * Get dimensions of PSD image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_psd_size($filename) - { - $data = $this->get_image($filename, 0, self::PSD_HEADER_SIZE); - - if ($data === false) - { - return; - } - - // Offset for version info is length of header but version is only a - // 16-bit unsigned value - $version = unpack('n', substr($data, self::LONG_SIZE, 2)); - - // Check if supplied file is a PSD file - if (substr($data, 0, self::LONG_SIZE) !== self::PSD_SIGNATURE || $version[1] !== 1) - { - return; - } - - $this->size = unpack('Nheight/Nwidth', substr($data, self::PSD_DIMENSIONS_OFFSET, 2 * self::LONG_SIZE)); - - $this->set_image_type(IMAGETYPE_PSD); - } - - /** - * Get dimensions of BMP image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_bmp_size($filename) - { - $data = $this->get_image($filename, 0, self::BMP_HEADER_SIZE); - - // Check if supplied file is a BMP file - if (substr($data, 0, 2) !== self::BMP_SIGNATURE) - { - return; - } - - $this->size = unpack('lwidth/lheight', substr($data, self::BMP_DIMENSIONS_OFFSET, 2 * self::LONG_SIZE)); - - $this->set_image_type(IMAGETYPE_BMP); - } - - /** - * Get dimensions of TIF/TIFF image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_tif_size($filename) - { - // Do not force length of header - $data = $this->get_image($filename, 0, self::TIF_HEADER_SIZE, false); - - $signature = substr($data, 0, self::SHORT_SIZE); - - if ($signature !== "II" && $signature !== "MM") - { - return; - } - - if ($signature === "II") - { - $type_long = 'V'; - $type_short = 'v'; - $this->set_image_type(IMAGETYPE_TIFF_II); - } - else - { - $type_long = 'N'; - $type_short = 'n'; - $this->set_image_type(IMAGETYPE_TIFF_MM); - } - - // Get offset of IFD - list(, $offset) = unpack($type_long, substr($data, self::LONG_SIZE, self::LONG_SIZE)); - - // Get size of IFD - list(, $size_ifd) = unpack($type_short, substr($data, $offset, self::SHORT_SIZE)); - - // Skip 2 bytes that define the IFD size - $offset += self::SHORT_SIZE; - - // Filter through IFD - for ($i = 0; $i < $size_ifd; $i++) - { - // Get IFD tag - $type = unpack($type_short, substr($data, $offset, self::SHORT_SIZE)); - - // Get field type of tag - $field_type = unpack($type_short . 'type', substr($data, $offset + self::SHORT_SIZE, self::SHORT_SIZE)); - - // Get IFD entry - $ifd_value = substr($data, $offset + 2 * self::LONG_SIZE, self::LONG_SIZE); - - // Get actual dimensions from IFD - if ($type[1] === self::TIF_TAG_IMAGE_HEIGHT) - { - $this->size = array_merge($this->size, ($field_type['type'] === self::TIF_TAG_TYPE_SHORT) ? unpack($type_short . 'height', $ifd_value) : unpack($type_long . 'height', $ifd_value)); - } - else if ($type[1] === self::TIF_TAG_IMAGE_WIDTH) - { - $this->size = array_merge($this->size, ($field_type['type'] === self::TIF_TAG_TYPE_SHORT) ? unpack($type_short .'width', $ifd_value) : unpack($type_long . 'width', $ifd_value)); - } - - $offset += self::TIF_IFD_ENTRY_SIZE; - } - } - - /** - * Get dimensions of WBMP image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_wbmp_size($filename) - { - $data = $this->get_image($filename, 0, self::LONG_SIZE); - - // Check if image is WBMP - if (ord($data[0]) !== 0 || ord($data[1]) !== 0 || $data === substr(self::JPEG_2000_SIGNATURE, 0, 4)) - { - return; - } - - $this->size = unpack('Cwidth/Cheight', substr($data, self::SHORT_SIZE, self::SHORT_SIZE)); - - $this->set_image_type(IMAGETYPE_WBMP); - } - - /** - * Get dimensions of IFF image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_iff_size($filename) - { - $data = $this->get_image($filename, 0, self::IFF_HEADER_SIZE); - - $signature = substr($data, 0, self::LONG_SIZE ); - - // Check if image is IFF - if ($signature !== 'FORM' && $signature !== 'FOR4') - { - return; - } - - // Amiga version of IFF - if ($signature === 'FORM') - { - $btmhd_position = strpos($data, 'BMHD'); - $this->size = unpack('nwidth/nheight', substr($data, $btmhd_position + 2 * self::LONG_SIZE, self::LONG_SIZE)); - } - // Maya version - else - { - $btmhd_position = strpos($data, 'BHD'); - $this->size = unpack('Nwidth/Nheight', substr($data, $btmhd_position + 2 * self::LONG_SIZE - 1, self::LONG_SIZE * 2)); - } - - $this->set_image_type(IMAGETYPE_IFF); - } - - /** - * Get dimensions of JPEG 2000 image - * - * @param string $filename Filename of image - * - * @return array|bool Array with image dimensions if successful, false if not - */ - protected function get_jp2_size($filename) - { - $data = $this->get_image($filename, 0, self::JPG_MAX_HEADER_SIZE, false); - - // Check if file is jpeg 2000 - if (substr($data, 0, strlen(self::JPEG_2000_SIGNATURE)) !== self::JPEG_2000_SIGNATURE) - { - return; - } - - // Get SOC position before starting to search for SIZ - $soc_position = strpos($data, "\xFF\x4F"); - - // Make sure we do not get SIZ before SOC - $data = substr($data, $soc_position); - - $siz_position = strpos($data, "\xFF\x51"); - - // Remove SIZ and everything before - $data = substr($data, $siz_position + self::SHORT_SIZE); - - // Acquire size info from data - $this->size = unpack('Nwidth/Nheight', substr($data, self::LONG_SIZE, self::LONG_SIZE * 2)); - - $this->set_image_type(IMAGETYPE_JPEG2000); - } -} From 0a6ac0226d6f32e2cc22a584f08f69d128f0fd60 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Wed, 8 Apr 2015 15:41:16 +0200 Subject: [PATCH 06/11] [ticket/8672] Update fastImageSize to 1.0.1 PHPBB3-8672 --- phpBB/composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phpBB/composer.lock b/phpBB/composer.lock index 3bff2429d6..5173e3c27b 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -71,16 +71,16 @@ }, { "name": "marc1706/fast-image-size", - "version": "v1.0.0", + "version": "v1.0.1", "source": { "type": "git", "url": "https://github.com/marc1706/fast-image-size.git", - "reference": "99fb3c4aab631a39db7e8638450b59f562a47bb1" + "reference": "8cb57d887542cdbeddd7d7c85eac6b59e4038687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/99fb3c4aab631a39db7e8638450b59f562a47bb1", - "reference": "99fb3c4aab631a39db7e8638450b59f562a47bb1", + "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/8cb57d887542cdbeddd7d7c85eac6b59e4038687", + "reference": "8cb57d887542cdbeddd7d7c85eac6b59e4038687", "shasum": "" }, "require": { @@ -118,7 +118,7 @@ "php", "size" ], - "time": "2015-04-07 13:37:04" + "time": "2015-04-08 13:05:30" }, { "name": "patchwork/utf8", From 19011cb8429bbc09c1e0354038423c53a8424c5b Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Wed, 8 Apr 2015 15:41:52 +0200 Subject: [PATCH 07/11] [ticket/8672] Add fastImageSize to clean-vendor-dir in build.xml PHPBB3-8672 --- build/build.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build/build.xml b/build/build.xml index 2e65539035..4e54de5f87 100644 --- a/build/build.xml +++ b/build/build.xml @@ -436,6 +436,15 @@ + + + + + + + + + From 2665e68592a8d1061de6d8d06043c6bed7220d88 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Wed, 15 Apr 2015 11:32:52 +0200 Subject: [PATCH 08/11] [ticket/8672] Update fastImageSize to 1.0.2 PHPBB3-8672 --- phpBB/composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phpBB/composer.lock b/phpBB/composer.lock index 5173e3c27b..648dffdfbf 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -71,16 +71,16 @@ }, { "name": "marc1706/fast-image-size", - "version": "v1.0.1", + "version": "v1.0.2", "source": { "type": "git", "url": "https://github.com/marc1706/fast-image-size.git", - "reference": "8cb57d887542cdbeddd7d7c85eac6b59e4038687" + "reference": "ab7b594325cdf6b374d50b3934c8d16dd5249a2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/8cb57d887542cdbeddd7d7c85eac6b59e4038687", - "reference": "8cb57d887542cdbeddd7d7c85eac6b59e4038687", + "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/ab7b594325cdf6b374d50b3934c8d16dd5249a2a", + "reference": "ab7b594325cdf6b374d50b3934c8d16dd5249a2a", "shasum": "" }, "require": { @@ -118,7 +118,7 @@ "php", "size" ], - "time": "2015-04-08 13:05:30" + "time": "2015-04-09 11:19:59" }, { "name": "patchwork/utf8", From 31bcdb23a2a00f704efcd58877802ed5ac4507a9 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Wed, 15 Apr 2015 11:33:13 +0200 Subject: [PATCH 09/11] [ticket/8672] Remove unnecessary lines from clean-vendor-dir The new version of fastImageSize already makes sure that these files and/or folders do not exist. PHPBB3-8672 --- build/build.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build/build.xml b/build/build.xml index 4e54de5f87..2e65539035 100644 --- a/build/build.xml +++ b/build/build.xml @@ -436,15 +436,6 @@ - - - - - - - - - From 55c5bc126decffeaa74abdb853eb010cc3dcda8c Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sat, 18 Apr 2015 14:01:21 +0200 Subject: [PATCH 10/11] [ticket/8672] User $user->lang() instead of sprintf PHPBB3-8672 --- phpBB/includes/functions_upload.php | 4 ++-- tests/upload/filespec_test.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index ea82a23082..ac5313ca06 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -417,11 +417,11 @@ class filespec { if (!isset($types[$this->image_info['type']])) { - $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info['type'], $this->mimetype); + $this->error[] = $user->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype); } else { - $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info['type']][0], $this->extension); + $this->error[] = $user->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension); } } diff --git a/tests/upload/filespec_test.php b/tests/upload/filespec_test.php index 8fbb437ef0..f6deb242a2 100644 --- a/tests/upload/filespec_test.php +++ b/tests/upload/filespec_test.php @@ -287,7 +287,7 @@ class phpbb_filespec_test extends phpbb_test_case array('txt_copy', 'txt_as_img', 'image/jpg', 'txt', false, true), array('txt_copy_2', 'txt_moved', 'text/plain', 'txt', false, true), array('jpg_copy', 'jpg_moved', 'image/png', 'jpg', false, true), - array('png_copy', 'png_moved', 'image/png', 'jpg', 'IMAGE_FILETYPE_MISMATCH', true), + array('png_copy', 'png_moved', 'image/png', 'jpg', 'IMAGE_FILETYPE_MISMATCH png jpg', true), ); } From 9088f448633ff42d767afac674324d1e26911ab6 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Fri, 24 Apr 2015 13:38:42 +0200 Subject: [PATCH 11/11] [ticket/8672] Update hash of lock file PHPBB3-8672 --- phpBB/composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/composer.lock b/phpBB/composer.lock index 648dffdfbf..fce3bbc801 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "91cc998d47b703a7bc4f726217d7a3a9", + "hash": "d5368b75d221b5573b30307cb2f25f3b", "packages": [ { "name": "lusitanian/oauth",