comparison core/modules/file/tests/src/Functional/SaveUploadTest.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents a9cd425dd02b
children
comparison
equal deleted inserted replaced
4:a9cd425dd02b 5:12f9dff5fda9
1 <?php 1 <?php
2 2
3 namespace Drupal\Tests\file\Functional; 3 namespace Drupal\Tests\file\Functional;
4 4
5 use Drupal\Component\Render\FormattableMarkup;
6 use Drupal\Core\File\FileSystemInterface;
7 use Drupal\Core\Url;
5 use Drupal\file\Entity\File; 8 use Drupal\file\Entity\File;
6 use Drupal\Tests\TestFileCreationTrait; 9 use Drupal\Tests\TestFileCreationTrait;
7 10
8 /** 11 /**
9 * Tests the file_save_upload() function. 12 * Tests the file_save_upload() function.
59 $this->assertTrue(is_file($this->image->getFileUri()), "The image file we're going to upload exists."); 62 $this->assertTrue(is_file($this->image->getFileUri()), "The image file we're going to upload exists.");
60 63
61 $this->phpfile = current($this->drupalGetTestFiles('php')); 64 $this->phpfile = current($this->drupalGetTestFiles('php'));
62 $this->assertTrue(is_file($this->phpfile->uri), 'The PHP file we are going to upload exists.'); 65 $this->assertTrue(is_file($this->phpfile->uri), 'The PHP file we are going to upload exists.');
63 66
64 $this->maxFidBefore = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); 67 $this->maxFidBefore = (int) \Drupal::entityQueryAggregate('file')->aggregate('fid', 'max')->execute()[0]['fid_max'];
65 68
66 // Upload with replace to guarantee there's something there. 69 // Upload with replace to guarantee there's something there.
67 $edit = [ 70 $edit = [
68 'file_test_replace' => FILE_EXISTS_REPLACE, 71 'file_test_replace' => FILE_EXISTS_REPLACE,
69 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()), 72 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()),
80 83
81 /** 84 /**
82 * Test the file_save_upload() function. 85 * Test the file_save_upload() function.
83 */ 86 */
84 public function testNormal() { 87 public function testNormal() {
85 $max_fid_after = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); 88 $max_fid_after = (int) \Drupal::entityQueryAggregate('file')->aggregate('fid', 'max')->execute()[0]['fid_max'];
86 $this->assertTrue($max_fid_after > $this->maxFidBefore, 'A new file was created.'); 89 $this->assertTrue($max_fid_after > $this->maxFidBefore, 'A new file was created.');
87 $file1 = File::load($max_fid_after); 90 $file1 = File::load($max_fid_after);
88 $this->assertTrue($file1, 'Loaded the file.'); 91 $this->assertTrue($file1, 'Loaded the file.');
89 // MIME type of the uploaded image may be either image/jpeg or image/png. 92 // MIME type of the uploaded image may be either image/jpeg or image/png.
90 $this->assertEqual(substr($file1->getMimeType(), 0, 5), 'image', 'A MIME type was set.'); 93 $this->assertEqual(substr($file1->getMimeType(), 0, 5), 'image', 'A MIME type was set.');
96 $image2 = current($this->drupalGetTestFiles('image')); 99 $image2 = current($this->drupalGetTestFiles('image'));
97 $edit = ['files[file_test_upload]' => \Drupal::service('file_system')->realpath($image2->uri)]; 100 $edit = ['files[file_test_upload]' => \Drupal::service('file_system')->realpath($image2->uri)];
98 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 101 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
99 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 102 $this->assertResponse(200, 'Received a 200 response for posted test file.');
100 $this->assertRaw(t('You WIN!')); 103 $this->assertRaw(t('You WIN!'));
101 $max_fid_after = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); 104 $max_fid_after = (int) \Drupal::entityQueryAggregate('file')->aggregate('fid', 'max')->execute()[0]['fid_max'];
102 105
103 // Check that the correct hooks were called. 106 // Check that the correct hooks were called.
104 $this->assertFileHooksCalled(['validate', 'insert']); 107 $this->assertFileHooksCalled(['validate', 'insert']);
105 108
106 $file2 = File::load($max_fid_after); 109 $file2 = File::load($max_fid_after);
122 'file_subdir' => $dir, 125 'file_subdir' => $dir,
123 ]; 126 ];
124 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 127 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
125 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 128 $this->assertResponse(200, 'Received a 200 response for posted test file.');
126 $this->assertRaw(t('You WIN!')); 129 $this->assertRaw(t('You WIN!'));
127 $this->assertTrue(is_file('temporary://' . $dir . '/' . trim(drupal_basename($image3_realpath)))); 130 $this->assertTrue(is_file('temporary://' . $dir . '/' . trim(\Drupal::service('file_system')->basename($image3_realpath))));
128 } 131 }
129 132
130 /** 133 /**
131 * Test extension handling. 134 * Test extension handling.
132 */ 135 */
204 207
205 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 208 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
206 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 209 $this->assertResponse(200, 'Received a 200 response for posted test file.');
207 $message = t('For security reasons, your upload has been renamed to') . ' <em class="placeholder">' . $this->phpfile->filename . '.txt' . '</em>'; 210 $message = t('For security reasons, your upload has been renamed to') . ' <em class="placeholder">' . $this->phpfile->filename . '.txt' . '</em>';
208 $this->assertRaw($message, 'Dangerous file was renamed.'); 211 $this->assertRaw($message, 'Dangerous file was renamed.');
212 $this->assertSession()->pageTextContains('File name is php-2.php.txt.');
209 $this->assertRaw(t('File MIME type is text/plain.'), "Dangerous file's MIME type was changed."); 213 $this->assertRaw(t('File MIME type is text/plain.'), "Dangerous file's MIME type was changed.");
210 $this->assertRaw(t('You WIN!'), 'Found the success message.'); 214 $this->assertRaw(t('You WIN!'), 'Found the success message.');
211 215
212 // Check that the correct hooks were called. 216 // Check that the correct hooks were called.
213 $this->assertFileHooksCalled(['validate', 'insert']); 217 $this->assertFileHooksCalled(['validate', 'insert']);
219 file_test_reset(); 223 file_test_reset();
220 224
221 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 225 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
222 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 226 $this->assertResponse(200, 'Received a 200 response for posted test file.');
223 $this->assertNoRaw(t('For security reasons, your upload has been renamed'), 'Found no security message.'); 227 $this->assertNoRaw(t('For security reasons, your upload has been renamed'), 'Found no security message.');
224 $this->assertRaw(t('File name is @filename', ['@filename' => $this->phpfile->filename]), 'Dangerous file was not renamed when insecure uploads is TRUE.'); 228 $this->assertSession()->pageTextContains('File name is php-2.php.');
225 $this->assertRaw(t('You WIN!'), 'Found the success message.'); 229 $this->assertRaw(t('You WIN!'), 'Found the success message.');
226 230
227 // Check that the correct hooks were called. 231 // Check that the correct hooks were called.
228 $this->assertFileHooksCalled(['validate', 'insert']); 232 $this->assertFileHooksCalled(['validate', 'insert']);
229 233
283 /** 287 /**
284 * Test renaming when uploading over a file that already exists. 288 * Test renaming when uploading over a file that already exists.
285 */ 289 */
286 public function testExistingRename() { 290 public function testExistingRename() {
287 $edit = [ 291 $edit = [
288 'file_test_replace' => FILE_EXISTS_RENAME, 292 'file_test_replace' => FileSystemInterface::EXISTS_RENAME,
289 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()), 293 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()),
290 ]; 294 ];
291 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 295 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
292 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 296 $this->assertResponse(200, 'Received a 200 response for posted test file.');
293 $this->assertRaw(t('You WIN!'), 'Found the success message.'); 297 $this->assertRaw(t('You WIN!'), 'Found the success message.');
298 $this->assertSession()->pageTextContains('File name is image-test_0.png.');
294 299
295 // Check that the correct hooks were called. 300 // Check that the correct hooks were called.
296 $this->assertFileHooksCalled(['validate', 'insert']); 301 $this->assertFileHooksCalled(['validate', 'insert']);
297 } 302 }
298 303
305 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()), 310 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()),
306 ]; 311 ];
307 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 312 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
308 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 313 $this->assertResponse(200, 'Received a 200 response for posted test file.');
309 $this->assertRaw(t('You WIN!'), 'Found the success message.'); 314 $this->assertRaw(t('You WIN!'), 'Found the success message.');
315 $this->assertSession()->pageTextContains('File name is image-test.png.');
310 316
311 // Check that the correct hooks were called. 317 // Check that the correct hooks were called.
312 $this->assertFileHooksCalled(['validate', 'load', 'update']); 318 $this->assertFileHooksCalled(['validate', 'load', 'update']);
313 } 319 }
314 320
340 * Tests for log entry on failing destination. 346 * Tests for log entry on failing destination.
341 */ 347 */
342 public function testDrupalMovingUploadedFileError() { 348 public function testDrupalMovingUploadedFileError() {
343 // Create a directory and make it not writable. 349 // Create a directory and make it not writable.
344 $test_directory = 'test_drupal_move_uploaded_file_fail'; 350 $test_directory = 'test_drupal_move_uploaded_file_fail';
345 drupal_mkdir('temporary://' . $test_directory, 0000); 351 /** @var \Drupal\Core\File\FileSystemInterface $file_system */
352 $file_system = \Drupal::service('file_system');
353 $file_system->mkdir('temporary://' . $test_directory, 0000);
346 $this->assertTrue(is_dir('temporary://' . $test_directory)); 354 $this->assertTrue(is_dir('temporary://' . $test_directory));
347 355
348 $edit = [ 356 $edit = [
349 'file_subdir' => $test_directory, 357 'file_subdir' => $test_directory,
350 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()), 358 'files[file_test_upload]' => $file_system->realpath($this->image->getFileUri()),
351 ]; 359 ];
352 360
353 \Drupal::state()->set('file_test.disable_error_collection', TRUE); 361 \Drupal::state()->set('file_test.disable_error_collection', TRUE);
354 $this->drupalPostForm('file-test/upload', $edit, t('Submit')); 362 $this->drupalPostForm('file-test/upload', $edit, t('Submit'));
355 $this->assertResponse(200, 'Received a 200 response for posted test file.'); 363 $this->assertResponse(200, 'Received a 200 response for posted test file.');
363 '@file' => $this->image->getFilename(), 371 '@file' => $this->image->getFilename(),
364 '@destination' => 'temporary://' . $test_directory . '/' . $this->image->getFilename(), 372 '@destination' => 'temporary://' . $test_directory . '/' . $this->image->getFilename(),
365 ]), 'Found upload error log entry.'); 373 ]), 'Found upload error log entry.');
366 } 374 }
367 375
376 /**
377 * Tests that filenames containing invalid UTF-8 are rejected.
378 */
379 public function testInvalidUtf8FilenameUpload() {
380 $this->drupalGet('file-test/upload');
381
382 // Filename containing invalid UTF-8.
383 $filename = "x\xc0xx.gif";
384
385 $page = $this->getSession()->getPage();
386 $data = [
387 'multipart' => [
388 [
389 'name' => 'file_test_replace',
390 'contents' => FileSystemInterface::EXISTS_RENAME,
391 ],
392 [
393 'name' => 'form_id',
394 'contents' => '_file_test_form',
395 ],
396 [
397 'name' => 'form_build_id',
398 'contents' => $page->find('hidden_field_selector', ['hidden_field', 'form_build_id'])->getAttribute('value'),
399 ],
400 [
401 'name' => 'form_token',
402 'contents' => $page->find('hidden_field_selector', ['hidden_field', 'form_token'])->getAttribute('value'),
403 ],
404 [
405 'name' => 'op',
406 'contents' => 'Submit',
407 ],
408 [
409 'name' => 'files[file_test_upload]',
410 'contents' => 'Test content',
411 'filename' => $filename,
412 ],
413 ],
414 'cookies' => $this->getSessionCookies(),
415 'http_errors' => FALSE,
416 ];
417
418 $this->assertFileNotExists('temporary://' . $filename);
419 // Use Guzzle's HTTP client directly so we can POST files without having to
420 // write them to disk. Not all filesystem support writing files with invalid
421 // UTF-8 filenames.
422 $response = $this->getHttpClient()->request('POST', Url::fromUri('base:file-test/upload')->setAbsolute()->toString(), $data);
423
424 $content = (string) $response->getBody();
425 $this->htmlOutput($content);
426 $error_text = new FormattableMarkup('The file %filename could not be uploaded because the name is invalid.', ['%filename' => $filename]);
427 $this->assertContains((string) $error_text, $content);
428 $this->assertContains('Epic upload FAIL!', $content);
429 $this->assertFileNotExists('temporary://' . $filename);
430 }
431
368 } 432 }