UploadedFileTest.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpFoundation\Tests\File;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException;
  13. use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException;
  14. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  15. use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
  16. use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException;
  17. use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException;
  18. use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
  19. use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
  20. use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
  21. use Symfony\Component\HttpFoundation\File\UploadedFile;
  22. class UploadedFileTest extends TestCase
  23. {
  24. protected function setUp(): void
  25. {
  26. if (!\ini_get('file_uploads')) {
  27. $this->markTestSkipped('file_uploads is disabled in php.ini');
  28. }
  29. }
  30. public function testConstructWhenFileNotExists()
  31. {
  32. $this->expectException(FileNotFoundException::class);
  33. new UploadedFile(
  34. __DIR__.'/Fixtures/not_here',
  35. 'original.gif',
  36. null
  37. );
  38. }
  39. public function testFileUploadsWithNoMimeType()
  40. {
  41. $file = new UploadedFile(
  42. __DIR__.'/Fixtures/test.gif',
  43. 'original.gif',
  44. null,
  45. \UPLOAD_ERR_OK
  46. );
  47. $this->assertEquals('application/octet-stream', $file->getClientMimeType());
  48. if (\extension_loaded('fileinfo')) {
  49. $this->assertEquals('image/gif', $file->getMimeType());
  50. }
  51. }
  52. public function testFileUploadsWithUnknownMimeType()
  53. {
  54. $file = new UploadedFile(
  55. __DIR__.'/Fixtures/.unknownextension',
  56. 'original.gif',
  57. null,
  58. \UPLOAD_ERR_OK
  59. );
  60. $this->assertEquals('application/octet-stream', $file->getClientMimeType());
  61. }
  62. public function testGuessClientExtension()
  63. {
  64. $file = new UploadedFile(
  65. __DIR__.'/Fixtures/test.gif',
  66. 'original.gif',
  67. 'image/gif',
  68. null
  69. );
  70. $this->assertEquals('gif', $file->guessClientExtension());
  71. }
  72. public function testGuessClientExtensionWithIncorrectMimeType()
  73. {
  74. $file = new UploadedFile(
  75. __DIR__.'/Fixtures/test.gif',
  76. 'original.gif',
  77. 'image/png',
  78. null
  79. );
  80. $this->assertEquals('png', $file->guessClientExtension());
  81. }
  82. public function testCaseSensitiveMimeType()
  83. {
  84. $file = new UploadedFile(
  85. __DIR__.'/Fixtures/case-sensitive-mime-type.xlsm',
  86. 'test.xlsm',
  87. 'application/vnd.ms-excel.sheet.macroEnabled.12',
  88. null
  89. );
  90. $this->assertEquals('xlsm', $file->guessClientExtension());
  91. }
  92. public function testErrorIsOkByDefault()
  93. {
  94. $file = new UploadedFile(
  95. __DIR__.'/Fixtures/test.gif',
  96. 'original.gif',
  97. 'image/gif',
  98. null
  99. );
  100. $this->assertEquals(\UPLOAD_ERR_OK, $file->getError());
  101. }
  102. public function testGetClientOriginalName()
  103. {
  104. $file = new UploadedFile(
  105. __DIR__.'/Fixtures/test.gif',
  106. 'original.gif',
  107. 'image/gif',
  108. null
  109. );
  110. $this->assertEquals('original.gif', $file->getClientOriginalName());
  111. }
  112. public function testGetClientOriginalExtension()
  113. {
  114. $file = new UploadedFile(
  115. __DIR__.'/Fixtures/test.gif',
  116. 'original.gif',
  117. 'image/gif',
  118. null
  119. );
  120. $this->assertEquals('gif', $file->getClientOriginalExtension());
  121. }
  122. public function testMoveLocalFileIsNotAllowed()
  123. {
  124. $this->expectException(FileException::class);
  125. $file = new UploadedFile(
  126. __DIR__.'/Fixtures/test.gif',
  127. 'original.gif',
  128. 'image/gif',
  129. \UPLOAD_ERR_OK
  130. );
  131. $file->move(__DIR__.'/Fixtures/directory');
  132. }
  133. public static function failedUploadedFile()
  134. {
  135. foreach ([\UPLOAD_ERR_INI_SIZE, \UPLOAD_ERR_FORM_SIZE, \UPLOAD_ERR_PARTIAL, \UPLOAD_ERR_NO_FILE, \UPLOAD_ERR_CANT_WRITE, \UPLOAD_ERR_NO_TMP_DIR, \UPLOAD_ERR_EXTENSION, -1] as $error) {
  136. yield [new UploadedFile(
  137. __DIR__.'/Fixtures/test.gif',
  138. 'original.gif',
  139. 'image/gif',
  140. $error
  141. )];
  142. }
  143. }
  144. /**
  145. * @dataProvider failedUploadedFile
  146. */
  147. public function testMoveFailed(UploadedFile $file)
  148. {
  149. switch ($file->getError()) {
  150. case \UPLOAD_ERR_INI_SIZE:
  151. $exceptionClass = IniSizeFileException::class;
  152. break;
  153. case \UPLOAD_ERR_FORM_SIZE:
  154. $exceptionClass = FormSizeFileException::class;
  155. break;
  156. case \UPLOAD_ERR_PARTIAL:
  157. $exceptionClass = PartialFileException::class;
  158. break;
  159. case \UPLOAD_ERR_NO_FILE:
  160. $exceptionClass = NoFileException::class;
  161. break;
  162. case \UPLOAD_ERR_CANT_WRITE:
  163. $exceptionClass = CannotWriteFileException::class;
  164. break;
  165. case \UPLOAD_ERR_NO_TMP_DIR:
  166. $exceptionClass = NoTmpDirFileException::class;
  167. break;
  168. case \UPLOAD_ERR_EXTENSION:
  169. $exceptionClass = ExtensionFileException::class;
  170. break;
  171. default:
  172. $exceptionClass = FileException::class;
  173. }
  174. $this->expectException($exceptionClass);
  175. $file->move(__DIR__.'/Fixtures/directory');
  176. }
  177. public function testMoveLocalFileIsAllowedInTestMode()
  178. {
  179. $path = __DIR__.'/Fixtures/test.copy.gif';
  180. $targetDir = __DIR__.'/Fixtures/directory';
  181. $targetPath = $targetDir.'/test.copy.gif';
  182. @unlink($path);
  183. @unlink($targetPath);
  184. copy(__DIR__.'/Fixtures/test.gif', $path);
  185. $file = new UploadedFile(
  186. $path,
  187. 'original.gif',
  188. 'image/gif',
  189. \UPLOAD_ERR_OK,
  190. true
  191. );
  192. $movedFile = $file->move(__DIR__.'/Fixtures/directory');
  193. $this->assertFileExists($targetPath);
  194. $this->assertFileDoesNotExist($path);
  195. $this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
  196. @unlink($targetPath);
  197. }
  198. public function testGetClientOriginalNameSanitizeFilename()
  199. {
  200. $file = new UploadedFile(
  201. __DIR__.'/Fixtures/test.gif',
  202. '../../original.gif',
  203. 'image/gif'
  204. );
  205. $this->assertEquals('original.gif', $file->getClientOriginalName());
  206. }
  207. public function testGetSize()
  208. {
  209. $file = new UploadedFile(
  210. __DIR__.'/Fixtures/test.gif',
  211. 'original.gif',
  212. 'image/gif'
  213. );
  214. $this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize());
  215. $file = new UploadedFile(
  216. __DIR__.'/Fixtures/test',
  217. 'original.gif',
  218. 'image/gif'
  219. );
  220. $this->assertEquals(filesize(__DIR__.'/Fixtures/test'), $file->getSize());
  221. }
  222. public function testGetExtension()
  223. {
  224. $file = new UploadedFile(
  225. __DIR__.'/Fixtures/test.gif',
  226. 'original.gif'
  227. );
  228. $this->assertEquals('gif', $file->getExtension());
  229. }
  230. public function testIsValid()
  231. {
  232. $file = new UploadedFile(
  233. __DIR__.'/Fixtures/test.gif',
  234. 'original.gif',
  235. null,
  236. \UPLOAD_ERR_OK,
  237. true
  238. );
  239. $this->assertTrue($file->isValid());
  240. }
  241. /**
  242. * @dataProvider uploadedFileErrorProvider
  243. */
  244. public function testIsInvalidOnUploadError($error)
  245. {
  246. $file = new UploadedFile(
  247. __DIR__.'/Fixtures/test.gif',
  248. 'original.gif',
  249. null,
  250. $error
  251. );
  252. $this->assertFalse($file->isValid());
  253. }
  254. public static function uploadedFileErrorProvider()
  255. {
  256. return [
  257. [\UPLOAD_ERR_INI_SIZE],
  258. [\UPLOAD_ERR_FORM_SIZE],
  259. [\UPLOAD_ERR_PARTIAL],
  260. [\UPLOAD_ERR_NO_TMP_DIR],
  261. [\UPLOAD_ERR_EXTENSION],
  262. ];
  263. }
  264. public function testIsInvalidIfNotHttpUpload()
  265. {
  266. $file = new UploadedFile(
  267. __DIR__.'/Fixtures/test.gif',
  268. 'original.gif',
  269. null,
  270. \UPLOAD_ERR_OK
  271. );
  272. $this->assertFalse($file->isValid());
  273. }
  274. public function testGetMaxFilesize()
  275. {
  276. $size = UploadedFile::getMaxFilesize();
  277. if ($size > \PHP_INT_MAX) {
  278. $this->assertIsFloat($size);
  279. } else {
  280. $this->assertIsInt($size);
  281. }
  282. $this->assertGreaterThan(0, $size);
  283. if (0 === (int) \ini_get('post_max_size') && 0 === (int) \ini_get('upload_max_filesize')) {
  284. $this->assertSame(\PHP_INT_MAX, $size);
  285. }
  286. }
  287. }