Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix moving uploaded file crashed when source was stream #171

Closed
wants to merge 7 commits into from

Conversation

raigu
Copy link

@raigu raigu commented Oct 14, 2020

Description

When UploadedFile is created from stream then calling movingTo will throw an exception.

Script to reproduce the bug

require_once __DIR__ . '/vendor/autoload.php';

$file = new \Slim\Psr7\UploadedFile(
    (new \Slim\Psr7\Factory\StreamFactory())->createStream('Hello, World!')
);

$targetPath = tempnam(sys_get_temp_dir(), 'sample');
$file->moveTo($targetPath);

echo file_get_contents($targetPath);

Expected output:

Hello, World!

Actual output:

PHP Warning:  rename(): PHP wrapper does not support renaming in /home/rait/dev/github/Slim-Psr7/src/UploadedFile.php on line 172
PHP Stack trace:
PHP   1. {main}() /home/rait/dev/github/Slim-Psr7/demo.php:0
PHP   2. Slim\Psr7\UploadedFile->moveTo() /home/rait/dev/github/Slim-Psr7/demo.php:10
PHP   3. rename() /home/rait/dev/github/Slim-Psr7/src/UploadedFile.php:172
PHP Fatal error:  Uncaught RuntimeException: Error moving uploaded file  to /tmp/samplezHN38z in /home/rait/dev/github/Slim-Psr7/src/UploadedFile.php:173
Stack trace:
#0 /home/rait/dev/github/Slim-Psr7/demo.php(10): Slim\Psr7\UploadedFile->moveTo('/tmp/samplezHN3...')
#1 {main}
  thrown in /home/rait/dev/github/Slim-Psr7/src/UploadedFile.php on line 173

Motivation

I discovered this bug when I was creating a stub for a test.

Notes on implementation

I used stream_copy_to_stream for copying. I speculate that built-in stream function should be more efficient because it is implemented in C.

My fix also handles php://temp case where huge files might be the case.

@coveralls
Copy link

coveralls commented Oct 14, 2020

Coverage Status

Coverage decreased (-0.1%) to 99.873% when pulling c5fb95a on raigu:fix-uploaded-file-move-to into dea7736 on slimphp:master.

@raigu
Copy link
Author

raigu commented Oct 14, 2020

I have problem of creating meaningful test in order to improve the code coverage. I kind of recognize too much duplications.

I was thinking that maybe I should restructure the moveTo method?

I recognize three possible scenarios how to apply the movement behavior:

SAPI source target method
yes - - move_uploaded_file
no file file rename
no file resource stream_copy_to_stream
no resource file stream_copy_to_stream
no resource resource stream_copy_to_stream
no file uri stream_copy_to_stream
no resource uri stream_copy_to_stream

The SAPI would be first because PSR-7 documentation states:

When used in an SAPI environment where $_FILES is populated, when writing
files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be
used to ensure permissions and upload status are verified correctly.

Then if source and destination are files, then moving file would be most efficient.

All others will be moved as streams. If parameter is file (or uri), it is opened using fopen.

Also noticed that there are test cases that cover cases when $targetPath is uri.
Will make sure that it will not be broken and backward compatibility is guaranteed.
They should also work with fopen.

Before making this effort would like to have blessing from author.

@l0gicgate
Copy link
Member

I think that we should do something similar to:
https://github.com/Nyholm/psr7/blob/master/src/UploadedFile.php#L120-L150

l0gicgate and others added 2 commits November 11, 2020 19:52
In case of error the stream_copy_to_stream will throw it's own exception that tells in more detail what went wrong.
@raigu raigu changed the title Draft: Fix moving uploaded file crashed when source was stream [WIP] Fix moving uploaded file crashed when source was stream Apr 7, 2021
 Line   UploadedFile.php
 ------ -----------------------------------------------------------------------------------------------
  175    Parameter slimphp#1 $source of function stream_copy_to_stream expects resource, resource|null given.
  175    Parameter slimphp#2 $dest of function stream_copy_to_stream expects resource, resource|false given.
 Line   UploadedFile.php
 ------ ----------------------------------------------------------------------------------------------
  179    Parameter slimphp#2 $dest of function stream_copy_to_stream expects resource, resource|false given.
  181    Parameter slimphp#1 $fp of function fclose expects resource, resource|false given.
 ------ ----------------------------------------------------------------------------------------------

Had to force to skip target writability test in order to conduct a test that PHPStan required in a way that the 100% code coverage would be remain intact.
@raigu
Copy link
Author

raigu commented Apr 7, 2021

I think that we should do something similar to:
https://github.com/Nyholm/psr7/blob/master/src/UploadedFile.php#L120-L150

Probably yes, but I decided to fix only the original bug.

Current code works, refactoring has always risks. Better to leave it in case there is major improvement planned.

Currently managed to make tests that covered checks that where required by PHPStan.

@raigu
Copy link
Author

raigu commented Apr 7, 2021

Ready for review and merge.

Only one PHPStan warning remained which, turns out, exists in master also.

$ ./vendor/bin/phpstan analyse src
Note: Using configuration file /home/rait/dev/gs/Slim-Psr7/phpstan.neon.dist.
 18/18 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------- 
  Line   Factory/StreamFactory.php                                                                                                                               
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------- 
  74     Parameter #1 $callback of function set_error_handler expects (callable(int, string, string, int, array): bool)|null, Closure(int, string): null given.  
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------- 

@raigu raigu changed the title [WIP] Fix moving uploaded file crashed when source was stream Fix moving uploaded file crashed when source was stream Apr 7, 2021
@l0gicgate
Copy link
Member

I'm closing this as stale. Feel free to reopen.

@l0gicgate l0gicgate closed this Mar 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants