assertSame($this->tmp . '/uploads', upload_dir()); $this->assertDirectoryExists($this->tmp . '/uploads'); $this->assertSame(0700, fileperms($this->tmp . '/uploads') & 0777); } public function testUploadDirLosesATrailingSlash(): void { $this->setEnv('UPLOAD_DIR', $this->tmp . '/other/'); $this->assertSame($this->tmp . '/other', upload_dir()); } public function testUploadDirDefaultsToTheTempDirectory(): void { $this->setEnv('UPLOAD_DIR', ''); $this->assertSame(sys_get_temp_dir() . '/xxx-uploads', upload_dir()); } public function testUploadNamesAre32HexDigits(): void { $this->assertTrue((bool)is_upload_name(str_repeat('a0', 16))); $this->assertFalse((bool)is_upload_name(str_repeat('a0', 15))); $this->assertFalse((bool)is_upload_name(str_repeat('A0', 16))); $this->assertFalse((bool)is_upload_name('../' . str_repeat('a', 29))); $this->assertFalse((bool)is_upload_name(str_repeat('a', 32) . "\n")); $this->assertFalse((bool)is_upload_name(array())); $this->assertFalse((bool)is_upload_name(NULL)); } public function testStoreUploadRefusesAFileThatWasNotUploaded(): void { $file = $this->tmp . '/local'; file_put_contents($file, 'x'); $this->assertFalse(store_upload($file)); $this->assertFileExists($file); $this->assertArrayNotHasKey('pending_upload', $_SESSION); } public function testPendingUploadFindsTheSessionFile(): void { $file = $this->pending(); $this->assertSame($file, pending_upload()); } public function testPendingUploadNeedsAValidNameAndAFile(): void { $this->assertFalse(pending_upload()); $_SESSION['pending_upload'] = '../../etc/passwd'; $this->assertFalse(pending_upload()); $_SESSION['pending_upload'] = str_repeat('b', 32); $this->assertFalse(pending_upload()); } public function testPendingUploadUrlHasTheStartOfTheName(): void { $_SESSION['pending_upload'] = '0123456789abcdef0123456789abcdef'; $this->assertSame('/display?pending=01234567', pending_upload_url()); unset($_SESSION['pending_upload']); $this->assertSame('/display?pending=', pending_upload_url()); } public function testMimeTypeComesFromTheImage(): void { $this->assertSame('image/png', get_mimetype($this->pending())); $text = $this->tmp . '/text'; file_put_contents($text, 'This is not an image, but it is long enough to read.'); $this->assertNull(get_mimetype($text)); } public function testSaveUploadedFileUsesThePendingUpload(): void { $file = $this->pending(); $this->assertFalse(save_uploaded_file()); $_POST['uploaded'] = 'pending'; $this->assertSame($file, save_uploaded_file()); } public function testSaveUploadedFileIgnoresAFakeUpload(): void { $file = $this->tmp . '/fake'; file_put_contents($file, self::png()); $_FILES['upload'] = array('tmp_name' => $file, 'name' => 'a.png', 'error' => 0); $this->assertFalse(save_uploaded_file()); } public function testPruneDeletesTheSavedFileAndOldUploads(): void { $saved = $this->pending(); $old = upload_dir() . '/' . str_repeat('c', 32); $new = upload_dir() . '/' . str_repeat('d', 32); $other = upload_dir() . '/keep-me'; foreach (array($old, $new, $other) as $file) file_put_contents($file, 'x'); touch($old, time() - 86401); touch($other, time() - 86401); prune_images($saved); $this->assertFileDoesNotExist($saved); $this->assertFileDoesNotExist($old); $this->assertFileExists($new); $this->assertFileExists($other); $this->assertArrayNotHasKey('pending_upload', $_SESSION); } public function testPruneLeavesFilesOutsideTheUploadDirectory(): void { $outside = $this->tmp . '/' . str_repeat('e', 32); file_put_contents($outside, 'x'); prune_images($outside); $this->assertFileExists($outside); } }