aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--phpBB/config/default/container/services.yml3
-rw-r--r--phpBB/config/default/container/services_avatar.yml3
-rw-r--r--phpBB/includes/functions_upload.php24
-rw-r--r--phpBB/includes/message_parser.php9
-rw-r--r--phpBB/phpbb/avatar/driver/driver.php7
-rw-r--r--phpBB/phpbb/avatar/driver/gravatar.php12
-rw-r--r--phpBB/phpbb/avatar/driver/local.php8
-rw-r--r--phpBB/phpbb/avatar/driver/remote.php33
-rw-r--r--phpBB/phpbb/upload/imagesize.php549
-rw-r--r--tests/avatar/manager_test.php5
-rw-r--r--tests/upload/fixture/bmpbin0 -> 64 bytes
-rw-r--r--tests/upload/fixture/iffbin0 -> 120 bytes
-rw-r--r--tests/upload/fixture/iff_mayabin0 -> 88 bytes
-rw-r--r--tests/upload/fixture/jp2bin0 -> 528 bytes
-rw-r--r--tests/upload/fixture/jpxbin0 -> 528 bytes
-rw-r--r--tests/upload/fixture/psdbin0 -> 6374 bytes
-rw-r--r--tests/upload/fixture/tif_compressedbin0 -> 236 bytes
-rw-r--r--tests/upload/fixture/tif_msbbin0 -> 222 bytes
-rw-r--r--tests/upload/fixture/wbmpbin0 -> 5 bytes
-rw-r--r--tests/upload/imagesize_test.php99
20 files changed, 706 insertions, 46 deletions
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;
- }
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ return false;
+ }
- $width = ($width && $height) ? $width : $image_data[0];
- $height = ($width && $height) ? $height : $image_data[1];
+ 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 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @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 0000000000..04bff561ab
--- /dev/null
+++ b/tests/upload/fixture/bmp
Binary files differ
diff --git a/tests/upload/fixture/iff b/tests/upload/fixture/iff
new file mode 100644
index 0000000000..24eda8f593
--- /dev/null
+++ b/tests/upload/fixture/iff
Binary files differ
diff --git a/tests/upload/fixture/iff_maya b/tests/upload/fixture/iff_maya
new file mode 100644
index 0000000000..b6fb85101b
--- /dev/null
+++ b/tests/upload/fixture/iff_maya
Binary files differ
diff --git a/tests/upload/fixture/jp2 b/tests/upload/fixture/jp2
new file mode 100644
index 0000000000..adca6ecf0e
--- /dev/null
+++ b/tests/upload/fixture/jp2
Binary files differ
diff --git a/tests/upload/fixture/jpx b/tests/upload/fixture/jpx
new file mode 100644
index 0000000000..adca6ecf0e
--- /dev/null
+++ b/tests/upload/fixture/jpx
Binary files differ
diff --git a/tests/upload/fixture/psd b/tests/upload/fixture/psd
new file mode 100644
index 0000000000..d1bc9a6a70
--- /dev/null
+++ b/tests/upload/fixture/psd
Binary files differ
diff --git a/tests/upload/fixture/tif_compressed b/tests/upload/fixture/tif_compressed
new file mode 100644
index 0000000000..133b50c4f0
--- /dev/null
+++ b/tests/upload/fixture/tif_compressed
Binary files differ
diff --git a/tests/upload/fixture/tif_msb b/tests/upload/fixture/tif_msb
new file mode 100644
index 0000000000..32eb8abfbb
--- /dev/null
+++ b/tests/upload/fixture/tif_msb
Binary files differ
diff --git a/tests/upload/fixture/wbmp b/tests/upload/fixture/wbmp
new file mode 100644
index 0000000000..708c86ccee
--- /dev/null
+++ b/tests/upload/fixture/wbmp
Binary files differ
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 @@
+<?php
+
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @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'));
+ }
+}