diff options
Diffstat (limited to 'tests/upload/filespec_test.php')
| -rw-r--r-- | tests/upload/filespec_test.php | 331 | 
1 files changed, 331 insertions, 0 deletions
| diff --git a/tests/upload/filespec_test.php b/tests/upload/filespec_test.php new file mode 100644 index 0000000000..d8fa82e2b5 --- /dev/null +++ b/tests/upload/filespec_test.php @@ -0,0 +1,331 @@ +<?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'; +require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_upload.php'; + +class phpbb_filespec_test extends phpbb_test_case +{ +	const TEST_COUNT = 100; +	const PREFIX = 'phpbb_'; +	const MAX_STR_LEN = 50; +	const UPLOAD_MAX_FILESIZE = 1000; + +	private $config; +	public $path; + +	protected function setUp() +	{ +		// Global $config required by unique_id +		// Global $user required by filespec::additional_checks and +		// filespec::move_file +		global $config, $user; + +		if (!is_array($config)) +		{ +			$config = array(); +		} + +		$config['rand_seed'] = ''; +		$config['rand_seed_last_update'] = time() + 600; +		// This config value is normally pulled from the database which is set +		// to this value at install time. +		// See: phpBB/install/schemas/schema_data.sql +		$config['mime_triggers'] = 'body|head|html|img|plaintext|a href|pre|script|table|title'; + +		$user = new phpbb_mock_user(); +		$user->lang = new phpbb_mock_lang(); + +		$this->config = &$config; +		$this->path = __DIR__ . '/fixture/'; + +		// Create copies of the files for use in testing move_file +		$iterator = new DirectoryIterator($this->path); +		foreach ($iterator as $fileinfo) +		{ +			if ($fileinfo->isDot() || $fileinfo->isDir()) +			{ +				continue; +			} + +			copy($fileinfo->getPathname(), $this->path . 'copies/' . $fileinfo->getFilename() . '_copy'); +			if ($fileinfo->getFilename() === 'txt') +			{ +				copy($fileinfo->getPathname(), $this->path . 'copies/' . $fileinfo->getFilename() . '_copy_2'); +			} +		} + +		$guessers = array( +			new \Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser(), +			new \Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser(), +			new \phpbb\mimetype\content_guesser(), +			new \phpbb\mimetype\extension_guesser(), +		); +		$guessers[2]->set_priority(-2); +		$guessers[3]->set_priority(-2); +		$this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers); +	} + +	private function get_filespec($override = array()) +	{ +		// Initialise a blank filespec object for use with trivial methods +		$upload_ary = array( +			'name' => '', +			'type' => '', +			'size' => '', +			'tmp_name' => '', +			'error' => '', +		); + +		return new filespec(array_merge($upload_ary, $override), null, $this->mimetype_guesser); +	} + +	protected function tearDown() +	{ +		global $user; +		$this->config = array(); +		$user = null; + +		$iterator = new DirectoryIterator($this->path . 'copies'); +		foreach ($iterator as $fileinfo) +		{ +			$name = $fileinfo->getFilename(); +			if ($name[0] !== '.') +			{ +				unlink($fileinfo->getPathname()); +			} +		} +	} + +	public function additional_checks_variables() +	{ +		// False here just indicates the file is too large and fails the +		// filespec::additional_checks method because of it. All other code +		// paths in that method are covered elsewhere. +		return array( +			array('gif', true), +			array('jpg', false), +			array('png', true), +			array('tif', false), +			array('txt', false), +		); +	} + +	/** +	 * @dataProvider additional_checks_variables +	 */ +	public function test_additional_checks($filename, $expected) +	{ +		$upload = new phpbb_mock_fileupload(); +		$filespec = $this->get_filespec(); +		$filespec->upload = $upload; +		$filespec->file_moved = true; +		$filespec->filesize = $filespec->get_filesize($this->path . $filename); + +		$this->assertEquals($expected, $filespec->additional_checks()); +	} + +	public function check_content_variables() +	{ +		// False here indicates that a file is non-binary and contains +		// disallowed content that makes IE report the mimetype incorrectly. +		return array( +			array('gif', true), +			array('jpg', true), +			array('png', true), +			array('tif', true), +			array('txt', false), +		); +	} + +	/** +	 * @dataProvider check_content_variables +	 */ +	public function test_check_content($filename, $expected) +	{ +		$disallowed_content = explode('|', $this->config['mime_triggers']); +		$filespec = $this->get_filespec(array('tmp_name' => $this->path . $filename)); +		$this->assertEquals($expected, $filespec->check_content($disallowed_content)); +		// All files should pass if $disallowed_content is empty +		$this->assertEquals(true, $filespec->check_content(array())); +	} + +	public function clean_filename_variables() +	{ +		$chunks = str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\'\\" /:*?<>|[];(){},#+=-_`', 8); +		return array( +			array($chunks[0] . $chunks[7]), +			array($chunks[1] . $chunks[8]), +			array($chunks[2] . $chunks[9]), +			array($chunks[3] . $chunks[4]), +			array($chunks[5] . $chunks[6]), +		); +	} + +	/** +	 * @dataProvider clean_filename_variables +	 */ +	public function test_clean_filename_real($filename) +	{ +		$bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|'); +		$filespec = $this->get_filespec(array('name' => $filename)); +		$filespec->clean_filename('real', self::PREFIX); +		$name = $filespec->realname; + +		$this->assertEquals(0, preg_match('/%(\w{2})/', $name)); +		foreach ($bad_chars as $char) +		{ +			$this->assertFalse(strpos($name, $char)); +		} +	} + +	public function test_clean_filename_unique() +	{ +		$filenames = array(); +		for ($tests = 0; $tests < self::TEST_COUNT; $tests++) +		{ +			$filespec = $this->get_filespec(); +			$filespec->clean_filename('unique', self::PREFIX); +			$name = $filespec->realname; +			 +			$this->assertEquals(strlen($name), 32 + strlen(self::PREFIX)); +			$this->assertRegExp('#^[A-Za-z0-9]+$#', substr($name, strlen(self::PREFIX))); +			$this->assertFalse(isset($filenames[$name])); +			$filenames[$name] = true; +		} +	} + +	public function get_extension_variables() +	{ +		return array( +			array('file.png', 'png'), +			array('file.phpbb.gif', 'gif'), +			array('file..', ''), +			array('.file..jpg.webp', 'webp'), +		); +	} + +	/** +	 * @dataProvider get_extension_variables +	 */ +	public function test_get_extension($filename, $expected) +	{ +		$this->assertEquals($expected, filespec::get_extension($filename)); +	} + +	public function is_image_variables() +	{ +		return array( +			array('gif', 'image/gif', true), +			array('jpg', 'image/jpg', true), +			array('png', 'image/png', true), +			array('tif', 'image/tif', true), +			array('txt', 'text/plain', false), +			array('jpg', 'application/octet-stream', false), +			array('gif', 'application/octetstream', false), +			array('png', 'application/mime', false), +		); +	} + +	/** +	 * @dataProvider is_image_variables +	 */ +	public function test_is_image($filename, $mimetype, $expected) +	{ +		$filespec = $this->get_filespec(array('tmp_name' => $this->path . $filename, 'type' => $mimetype)); +		$this->assertEquals($expected, $filespec->is_image()); +	} + +	public function is_image_get_mimetype() +	{ +		return array( +			array('gif', 'image/gif', true), +			array('jpg', 'image/jpg', true), +			array('png', 'image/png', true), +			array('tif', 'image/tif', true), +			array('txt', 'text/plain', false), +			array('jpg', 'application/octet-stream', true), +			array('gif', 'application/octetstream', true), +			array('png', 'application/mime', true), +		); +	} + +	/** +	 * @dataProvider is_image_get_mimetype +	 */ +	public function test_is_image_get_mimetype($filename, $mimetype, $expected) +	{ +		$filespec = $this->get_filespec(array('tmp_name' => $this->path . $filename, 'type' => $mimetype)); +		$filespec->get_mimetype($this->path . $filename); +		$this->assertEquals($expected, $filespec->is_image()); +	} + +	public function move_file_variables() +	{ +		return array( +			array('gif_copy', 'gif_moved', 'image/gif', 'gif', false, true), +			array('non_existant', 'still_non_existant', 'text/plain', 'txt', 'GENERAL_UPLOAD_ERROR', false), +			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), +		); +	} + +	/** +	 * @dataProvider move_file_variables +	 */ +	public function test_move_file($tmp_name, $realname, $mime_type, $extension, $error, $expected) +	{ +		// Global $phpbb_root_path and $phpEx are required by phpbb_chmod +		global $phpbb_root_path, $phpEx; +		$phpbb_root_path = ''; +		$phpEx = 'php'; + +		$upload = new phpbb_mock_fileupload(); +		$upload->max_filesize = self::UPLOAD_MAX_FILESIZE; + +		$filespec = $this->get_filespec(array( +			'tmp_name' => $this->path . 'copies/' . $tmp_name, +			'name' => $realname, +			'type' => $mime_type, +		)); +		$filespec->extension = $extension; +		$filespec->upload = $upload; +		$filespec->local = true; + +		$this->assertEquals($expected, $filespec->move_file($this->path . 'copies')); +		$this->assertEquals($filespec->file_moved, file_exists($this->path . 'copies/' . $realname)); +		if ($error) +		{ +			$this->assertEquals($error, $filespec->error[0]); +		} + +		$phpEx = ''; +	} + +	/** +	* @dataProvider clean_filename_variables +	*/ +	public function test_uploadname($filename) +	{ +		$type_cast_helper = new \phpbb\request\type_cast_helper(); + +		$upload_name = ''; +		$type_cast_helper->set_var($upload_name, $filename, 'string', true, true); +		$filespec = $this->get_filespec(array('name'=> $upload_name)); + +		$this->assertSame(trim(utf8_basename(htmlspecialchars($filename))), $filespec->uploadname); +	} +} | 
