@@ -18,14 +18,24 @@ public function tearDown(): void
1818 if (file_exists ('tmp_name ' )) {
1919 unlink ('tmp_name ' );
2020 }
21+ if (file_exists ('existing.txt ' )) {
22+ unlink ('existing.txt ' );
23+ }
24+ if (file_exists ('real_file ' )) {
25+ unlink ('real_file ' );
26+ }
27+
28+ // not found with file_exists...just delete it brute force
29+ @unlink ('tmp_symlink ' );
2130 }
2231
23- public function testMoveToSuccess (): void
32+ public function testMoveToFalseSuccess (): void
2433 {
34+ // This test would have passed in the real world but we can't actually force a post request in unit tests
2535 file_put_contents ('tmp_name ' , 'test ' );
26- $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK );
36+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK , true );
37+ $ this ->expectExceptionMessage ('Cannot move uploaded file ' );
2738 $ uploadedFile ->moveTo ('file.txt ' );
28- $ this ->assertFileExists ('file.txt ' );
2939 }
3040
3141 public function getFileErrorMessageTests (): array
@@ -53,4 +63,62 @@ public function testMoveToFailureMessages($error, $message)
5363 $ this ->expectExceptionMessage ($ message );
5464 $ uploadedFile ->moveTo ('file.txt ' );
5565 }
66+
67+ public function testMoveToBadLocation (): void
68+ {
69+ file_put_contents ('tmp_name ' , 'test ' );
70+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK , true );
71+ $ this ->expectExceptionMessage ('Target directory is not writable ' );
72+ $ uploadedFile ->moveTo ('/root/file.txt ' );
73+ }
74+
75+ public function testMoveToSuccessNonPost (): void
76+ {
77+ file_put_contents ('tmp_name ' , 'test ' );
78+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK , false );
79+ $ uploadedFile ->moveTo ('file.txt ' );
80+ $ this ->assertFileExists ('file.txt ' );
81+ $ this ->assertEquals ('test ' , file_get_contents ('file.txt ' ));
82+ }
83+
84+ public function testMoveToPathTraversal (): void
85+ {
86+ file_put_contents ('tmp_name ' , 'test ' );
87+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK , false );
88+ $ this ->expectException (Exception::class);
89+ $ this ->expectExceptionMessage ('Invalid target path: contains directory traversal ' );
90+ $ uploadedFile ->moveTo ('../file.txt ' );
91+ }
92+
93+ public function testMoveToAbsolutePath (): void
94+ {
95+ file_put_contents ('tmp_name ' , 'test ' );
96+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK , false );
97+ $ this ->expectException (Exception::class);
98+ $ this ->expectExceptionMessage ('Invalid target path: absolute paths not allowed ' );
99+ $ uploadedFile ->moveTo ('/tmp/file.txt ' );
100+ }
101+
102+ public function testMoveToOverwrite (): void
103+ {
104+ file_put_contents ('tmp_name ' , 'test ' );
105+ file_put_contents ('existing.txt ' , 'existing ' );
106+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_name ' , UPLOAD_ERR_OK , false );
107+ $ this ->expectException (Exception::class);
108+ $ this ->expectExceptionMessage ('Target file already exists ' );
109+ $ uploadedFile ->moveTo ('existing.txt ' );
110+ }
111+
112+ public function testMoveToSymlinkNonPost (): void
113+ {
114+ file_put_contents ('real_file ' , 'test ' );
115+ if (file_exists ('tmp_symlink ' )) {
116+ unlink ('tmp_symlink ' );
117+ }
118+ symlink ('real_file ' , 'tmp_symlink ' );
119+ $ uploadedFile = new UploadedFile ('file.txt ' , 'text/plain ' , 4 , 'tmp_symlink ' , UPLOAD_ERR_OK , false );
120+ $ this ->expectException (Exception::class);
121+ $ this ->expectExceptionMessage ('Invalid temp file: symlink detected ' );
122+ $ uploadedFile ->moveTo ('file.txt ' );
123+ }
56124}
0 commit comments