Update UploadedFile's tests for SAPI and use of *_uploaded_file functions
This commit is contained in:
parent
257f2b7610
commit
a93b37a548
|
|
@ -19,11 +19,35 @@ class UploadedFile implements UploadedFileInterface
|
||||||
private $tmpName;
|
private $tmpName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* Create a new Uri. The arguments correspond with keys from arrays
|
||||||
* @param string $type
|
* provided by $_FILES. For example, given this structure for $_FILES:
|
||||||
* @param int $size
|
*
|
||||||
* @param string $tmpName
|
* array(
|
||||||
* @param int $error
|
* 'avatar' => arrary(
|
||||||
|
* 'name' => 'my-avatar.png',
|
||||||
|
* 'type' => 'image/png',
|
||||||
|
* 'size' => 90996,
|
||||||
|
* 'tmp_name' => 'phpUxcOty',
|
||||||
|
* 'error' => 0
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* ...use this call:
|
||||||
|
*
|
||||||
|
* new UploadedFile(
|
||||||
|
* $_FILES['avatar']['name'],
|
||||||
|
* $_FILES['avatar']['type'],
|
||||||
|
* $_FILES['avatar']['size'],
|
||||||
|
* $_FILES['avatar']['tmp_name'],
|
||||||
|
* $_FILES['avatar']['error']
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* @param string $name Name of the file; provided by the client
|
||||||
|
* @param string $type Media type of the file; provided by the client
|
||||||
|
* @param int $size The file size in bytes.
|
||||||
|
* @param string $tmpName Local filesystem name of the file
|
||||||
|
* @param int $error One of PHP's UPLOAD_ERR_XXX constants.
|
||||||
|
* @see http://php.net/manual/en/features.file-upload.errors.php
|
||||||
*/
|
*/
|
||||||
public function __construct($name, $type, $size, $tmpName, $error)
|
public function __construct($name, $type, $size, $tmpName, $error)
|
||||||
{
|
{
|
||||||
|
|
@ -44,31 +68,34 @@ class UploadedFile implements UploadedFileInterface
|
||||||
* Retrieve a stream representing the uploaded file.
|
* Retrieve a stream representing the uploaded file.
|
||||||
*
|
*
|
||||||
* This method returns a StreamInterface instance, representing the
|
* This method returns a StreamInterface instance, representing the
|
||||||
* uploaded file. The purpose of this method is to allow utilizing native PHP
|
* uploaded file. The purpose of this method is to allow using native PHP
|
||||||
* stream functionality to manipulate the file upload, such as
|
* stream functionality to manipulate the file upload, such as
|
||||||
* stream_copy_to_stream() (though the result will need to be decorated in a
|
* stream_copy_to_stream() (though the result will need to be decorated in
|
||||||
* native PHP stream wrapper to work with such functions).
|
* a native PHP stream wrapper to work with such functions).
|
||||||
*
|
*
|
||||||
* If the moveTo() method has been called previously, this method will raise
|
* If the moveTo() method has been called previously, this method will
|
||||||
* an exception.
|
* raise an exception.
|
||||||
*
|
*
|
||||||
* @return StreamInterface Stream representation of the uploaded file.
|
* @return StreamInterface Stream representation of the uploaded file.
|
||||||
* @throws \RuntimeException in cases when no stream is available or can be
|
* @throws \RuntimeException in cases when no stream is available or can
|
||||||
* created.
|
* be created.
|
||||||
*/
|
*/
|
||||||
public function getStream()
|
public function getStream()
|
||||||
{
|
{
|
||||||
if ($this->moved) {
|
if ($this->moved) {
|
||||||
throw new \RuntimeException("File has already been moved");
|
throw new \RuntimeException("File has already been moved");
|
||||||
}
|
}
|
||||||
|
if (php_sapi_name() !== "cli" && !is_uploaded_file($this->tmpName)) {
|
||||||
|
throw new \RuntimeException("File is not an uploaded file.");
|
||||||
|
}
|
||||||
return $this->stream;
|
return $this->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the uploaded file to a new location.
|
* Move the uploaded file to a new location.
|
||||||
*
|
*
|
||||||
* Use this method as an alternative to move_uploaded_file(). This method is
|
* Use this method as an alternative to move_uploaded_file(). This method
|
||||||
* guaranteed to work in both SAPI and non-SAPI environments.
|
* is guaranteed to work in both SAPI and non-SAPI environments.
|
||||||
*
|
*
|
||||||
* The original file or stream will be removed on completion.
|
* The original file or stream will be removed on completion.
|
||||||
*
|
*
|
||||||
|
|
@ -87,14 +114,10 @@ class UploadedFile implements UploadedFileInterface
|
||||||
if ($this->tmpName === null || !file_exists($this->tmpName)) {
|
if ($this->tmpName === null || !file_exists($this->tmpName)) {
|
||||||
throw new \RuntimeException("File " . $this->tmpName . " does not exist.");
|
throw new \RuntimeException("File " . $this->tmpName . " does not exist.");
|
||||||
}
|
}
|
||||||
$sapi = php_sapi_name();
|
if (php_sapi_name() === "cli") {
|
||||||
$whitelist = ["apache", "apache2filter", "apache2handler", "cgi", "fpm-fcgi", "cgi-fcgi"];
|
|
||||||
if (in_array($sapi, $whitelist)) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
move_uploaded_file($this->tmpName, $path);
|
|
||||||
} else {
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
rename($this->tmpName, $path);
|
rename($this->tmpName, $path);
|
||||||
|
} else {
|
||||||
|
move_uploaded_file($this->tmpName, $path);
|
||||||
}
|
}
|
||||||
$this->moved = true;
|
$this->moved = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WellRESTed\Message;
|
||||||
|
|
||||||
|
class UploadedFileState
|
||||||
|
{
|
||||||
|
public static $php_sapi_name;
|
||||||
|
public static $is_uploaded_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
function php_sapi_name()
|
||||||
|
{
|
||||||
|
return UploadedFileState::$php_sapi_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function move_uploaded_file($source, $target)
|
||||||
|
{
|
||||||
|
return rename($source, $target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_uploaded_file($file)
|
||||||
|
{
|
||||||
|
return UploadedFileState::$is_uploaded_file;
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,13 @@
|
||||||
namespace WellRESTed\Test\Message;
|
namespace WellRESTed\Test\Message;
|
||||||
|
|
||||||
use WellRESTed\Message\UploadedFile;
|
use WellRESTed\Message\UploadedFile;
|
||||||
|
use WellRESTed\Message\UploadedFileState;
|
||||||
|
|
||||||
|
// Hides several php core functions for testing.
|
||||||
|
require_once __DIR__ . "/../../../src/UploadedFileState.php";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @coversDefaultClass WellRESTed\Message\UploadedFile
|
||||||
* @uses WellRESTed\Message\UploadedFile
|
* @uses WellRESTed\Message\UploadedFile
|
||||||
* @uses WellRESTed\Message\Stream
|
* @uses WellRESTed\Message\Stream
|
||||||
* @uses WellRESTed\Message\NullStream
|
* @uses WellRESTed\Message\NullStream
|
||||||
|
|
@ -17,6 +22,7 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
UploadedFileState::$php_sapi_name = "cli";
|
||||||
$this->tmpName = tempnam(sys_get_temp_dir(), "tst");
|
$this->tmpName = tempnam(sys_get_temp_dir(), "tst");
|
||||||
$this->movePath = tempnam(sys_get_temp_dir(), "tst");
|
$this->movePath = tempnam(sys_get_temp_dir(), "tst");
|
||||||
}
|
}
|
||||||
|
|
@ -36,8 +42,8 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
|
||||||
// getStream
|
// getStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers WellRESTed\Message\UploadedFile::__construct
|
* @covers ::__construct
|
||||||
* @covers WellRESTed\Message\UploadedFile::getStream
|
* @covers ::getStream
|
||||||
*/
|
*/
|
||||||
public function testGetStreamReturnsStreamInterface()
|
public function testGetStreamReturnsStreamInterface()
|
||||||
{
|
{
|
||||||
|
|
@ -46,22 +52,21 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers WellRESTed\Message\UploadedFile::__construct
|
* @covers ::__construct
|
||||||
* @covers WellRESTed\Message\UploadedFile::getStream
|
* @covers ::getStream
|
||||||
*/
|
*/
|
||||||
public function testGetStreamReturnsStreamWrappingUploadedFile()
|
public function testGetStreamReturnsStreamWrappingUploadedFile()
|
||||||
{
|
{
|
||||||
$content = "Hello, World!";
|
$content = "Hello, World!";
|
||||||
file_put_contents($this->tmpName, $content);
|
file_put_contents($this->tmpName, $content);
|
||||||
|
|
||||||
$file = new UploadedFile("", "", 0, $this->tmpName, "");
|
$file = new UploadedFile("", "", 0, $this->tmpName, "");
|
||||||
$stream = $file->getStream();
|
$stream = $file->getStream();
|
||||||
$this->assertEquals($content, (string) $stream);
|
$this->assertEquals($content, (string) $stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers WellRESTed\Message\UploadedFile::__construct
|
* @covers ::__construct
|
||||||
* @covers WellRESTed\Message\UploadedFile::getStream
|
* @covers ::getStream
|
||||||
*/
|
*/
|
||||||
public function testGetStreamReturnsEmptyStreamForNoFile()
|
public function testGetStreamReturnsEmptyStreamForNoFile()
|
||||||
{
|
{
|
||||||
|
|
@ -70,27 +75,56 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers WellRESTed\Message\UploadedFile::__construct
|
* @covers ::__construct
|
||||||
* @covers WellRESTed\Message\UploadedFile::getStream
|
* @covers ::getStream
|
||||||
* @expectedException \RuntimeException
|
* @expectedException \RuntimeException
|
||||||
*/
|
*/
|
||||||
public function testGetStreamThrowsExceptionAfterMoveTo()
|
public function testGetStreamThrowsExceptionAfterMoveTo()
|
||||||
{
|
{
|
||||||
$content = "Hello, World!";
|
$content = "Hello, World!";
|
||||||
file_put_contents($this->tmpName, $content);
|
file_put_contents($this->tmpName, $content);
|
||||||
|
|
||||||
$file = new UploadedFile("", "", 0, $this->tmpName, "");
|
$file = new UploadedFile("", "", 0, $this->tmpName, "");
|
||||||
$file->moveTo($this->movePath);
|
$file->moveTo($this->movePath);
|
||||||
$file->getStream();
|
$file->getStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::__construct
|
||||||
|
* @covers ::getStream
|
||||||
|
* @expectedException \RuntimeException
|
||||||
|
*/
|
||||||
|
public function testGetStreamThrowsExceptionForNonUploadedFile()
|
||||||
|
{
|
||||||
|
UploadedFileState::$php_sapi_name = "apache";
|
||||||
|
UploadedFileState::$is_uploaded_file = false;
|
||||||
|
$file = new UploadedFile("", "", 0, "", 0);
|
||||||
|
$file->getStream();
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// move
|
// moveTo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers WellRESTed\Message\UploadedFile::moveTo
|
* @covers ::moveTo
|
||||||
*/
|
*/
|
||||||
public function testMoveToRelocatesUploadedFileToDestiationIfExists()
|
public function testMoveToSapiRelocatesUploadedFileToDestiationIfExists()
|
||||||
|
{
|
||||||
|
UploadedFileState::$php_sapi_name = "fpm-fcgi";
|
||||||
|
|
||||||
|
$content = "Hello, World!";
|
||||||
|
file_put_contents($this->tmpName, $content);
|
||||||
|
$originalMd5 = md5_file($this->tmpName);
|
||||||
|
|
||||||
|
$file = new UploadedFile("", "", 0, $this->tmpName, "");
|
||||||
|
$file->moveTo($this->movePath);
|
||||||
|
|
||||||
|
$this->assertEquals($originalMd5, md5_file($this->movePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::moveTo
|
||||||
|
*/
|
||||||
|
public function testMoveToNonSapiRelocatesUploadedFileToDestiationIfExists()
|
||||||
{
|
{
|
||||||
$content = "Hello, World!";
|
$content = "Hello, World!";
|
||||||
file_put_contents($this->tmpName, $content);
|
file_put_contents($this->tmpName, $content);
|
||||||
|
|
@ -103,10 +137,10 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers WellRESTed\Message\UploadedFile::moveTo
|
* @covers ::moveTo
|
||||||
* @expectedException \RuntimeException
|
* @expectedException \RuntimeException
|
||||||
*/
|
*/
|
||||||
public function testThrowsExcpetionOnSubsequentCallToMoveTo()
|
public function testMoveToThrowsExcpetionOnSubsequentCall()
|
||||||
{
|
{
|
||||||
$content = "Hello, World!";
|
$content = "Hello, World!";
|
||||||
file_put_contents($this->tmpName, $content);
|
file_put_contents($this->tmpName, $content);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue