mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-20 00:20:44 +08:00
Fixes issue #276: Enable Response::sendFile() to operate on resources
This commit is contained in:
@@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
namespace yii\base;
|
namespace yii\base;
|
||||||
|
|
||||||
use yii\web\Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HttpException represents an exception caused by an improper request of the end-user.
|
* HttpException represents an exception caused by an improper request of the end-user.
|
||||||
*
|
*
|
||||||
@@ -44,8 +42,9 @@ class HttpException extends UserException
|
|||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
if (isset(Response::$httpStatuses[$this->statusCode])) {
|
// use absolute namespaced class here because PHP will generate a mysterious error otherwise
|
||||||
return Response::$httpStatuses[$this->statusCode];
|
if (isset(\yii\web\Response::$httpStatuses[$this->statusCode])) {
|
||||||
|
return \yii\web\Response::$httpStatuses[$this->statusCode];
|
||||||
} else {
|
} else {
|
||||||
return 'Error';
|
return 'Error';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,22 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new header only if it does not exist yet.
|
||||||
|
* If there is already a header with the same name, the new one will be ignored.
|
||||||
|
* @param string $name the name of the header
|
||||||
|
* @param string $value the value of the header
|
||||||
|
* @return HeaderCollection the collection object itself
|
||||||
|
*/
|
||||||
|
public function addDefault($name, $value)
|
||||||
|
{
|
||||||
|
$name = strtolower($name);
|
||||||
|
if (empty($this->_headers[$name])) {
|
||||||
|
$this->_headers[$name][] = $value;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a value indicating whether the named header exists.
|
* Returns a value indicating whether the named header exists.
|
||||||
* @param string $name the name of the header
|
* @param string $name the name of the header
|
||||||
|
|||||||
@@ -275,141 +275,68 @@ class Response extends \yii\base\Response
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a file to user.
|
* Sends a file to the browser.
|
||||||
* @param string $fileName file name
|
* @param string $filePath the path of the file to be sent.
|
||||||
* @param string $content content to be set.
|
* @param string $mimeType the MIME type of the content. If null, it will be guessed based on `$filePath`
|
||||||
* @param string $mimeType mime type of the content. If null, it will be guessed automatically based on the given file name.
|
* @param string $attachmentName the file name shown to the user. If null, it will be determined from `$filePath`.
|
||||||
* @param boolean $terminate whether to terminate the current application after calling this method
|
|
||||||
* @throws HttpException when range request is not satisfiable.
|
|
||||||
*/
|
*/
|
||||||
public function sendFile($fileName, $content, $mimeType = null, $terminate = true)
|
public function sendFile($filePath, $mimeType = null, $attachmentName = null)
|
||||||
{
|
{
|
||||||
if ($mimeType === null && (($mimeType = FileHelper::getMimeTypeByExtension($fileName)) === null)) {
|
if ($mimeType === null && ($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) {
|
||||||
$mimeType = 'application/octet-stream';
|
$mimeType = 'application/octet-stream';
|
||||||
}
|
}
|
||||||
|
if ($attachmentName === null) {
|
||||||
$fileSize = StringHelper::strlen($content);
|
$attachmentName = basename($filePath);
|
||||||
$contentStart = 0;
|
|
||||||
$contentEnd = $fileSize - 1;
|
|
||||||
|
|
||||||
$headers = $this->getHeaders();
|
|
||||||
|
|
||||||
// tell the client that we accept range requests
|
|
||||||
$headers->set('Accept-Ranges', 'bytes');
|
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_RANGE'])) {
|
|
||||||
// client sent us a multibyte range, can not hold this one for now
|
|
||||||
if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) {
|
|
||||||
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
|
|
||||||
throw new HttpException(416, 'Requested Range Not Satisfiable');
|
|
||||||
}
|
|
||||||
|
|
||||||
$range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']);
|
|
||||||
|
|
||||||
// range requests starts from "-", so it means that data must be dumped the end point.
|
|
||||||
if ($range[0] === '-') {
|
|
||||||
$contentStart = $fileSize - substr($range, 1);
|
|
||||||
} else {
|
|
||||||
$range = explode('-', $range);
|
|
||||||
$contentStart = $range[0];
|
|
||||||
|
|
||||||
// check if the last-byte-pos presents in header
|
|
||||||
if ((isset($range[1]) && is_numeric($range[1]))) {
|
|
||||||
$contentEnd = $range[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the range and make sure it's treated according to the specs.
|
|
||||||
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
|
||||||
*/
|
|
||||||
// End bytes can not be larger than $end.
|
|
||||||
$contentEnd = ($contentEnd > $fileSize) ? $fileSize - 1 : $contentEnd;
|
|
||||||
|
|
||||||
// Validate the requested range and return an error if it's not correct.
|
|
||||||
$wrongContentStart = ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0);
|
|
||||||
|
|
||||||
if ($wrongContentStart) {
|
|
||||||
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
|
|
||||||
throw new HttpException(416, 'Requested Range Not Satisfiable');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setStatusCode(206);
|
|
||||||
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
|
|
||||||
} else {
|
|
||||||
$this->setStatusCode(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
$length = $contentEnd - $contentStart + 1; // Calculate new content length
|
|
||||||
|
|
||||||
$headers->set('Pragma', 'public')
|
|
||||||
->set('Expires', '0')
|
|
||||||
->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
|
||||||
->set('Content-Type', $mimeType)
|
|
||||||
->set('Content-Length', $length)
|
|
||||||
->set('Content-Disposition', "attachment; filename=\"$fileName\"")
|
|
||||||
->set('Content-Transfer-Encoding', 'binary');
|
|
||||||
|
|
||||||
$content = StringHelper::substr($content, $contentStart, $length);
|
|
||||||
|
|
||||||
if ($terminate) {
|
|
||||||
// clean up the application first because the file downloading could take long time
|
|
||||||
// which may cause timeout of some resources (such as DB connection)
|
|
||||||
ob_start();
|
|
||||||
Yii::$app->end(0, false);
|
|
||||||
ob_end_clean();
|
|
||||||
$this->content = $content;
|
|
||||||
exit(0);
|
|
||||||
} else {
|
|
||||||
$this->content = $content;
|
|
||||||
}
|
}
|
||||||
|
$handle = fopen($filePath, 'rb');
|
||||||
|
$this->sendStreamAsFile($handle, $mimeType, $attachmentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendStream($handle, $options = array())
|
/**
|
||||||
|
* Sends the specified content as a file to the browser.
|
||||||
|
* @param string $content the content to be sent. The existing [[content]] will be discarded.
|
||||||
|
* @param string $mimeType the MIME type of the content.
|
||||||
|
* @param string $attachmentName the file name shown to the user.
|
||||||
|
*/
|
||||||
|
public function sendContentAsFile($content, $mimeType = 'application/octet-stream', $attachmentName = 'file')
|
||||||
{
|
{
|
||||||
|
$this->getHeaders()
|
||||||
|
->addDefault('Pragma', 'public')
|
||||||
|
->addDefault('Accept-Ranges', 'bytes')
|
||||||
|
->addDefault('Expires', '0')
|
||||||
|
->addDefault('Content-Type', $mimeType)
|
||||||
|
->addDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||||
|
->addDefault('Content-Transfer-Encoding', 'binary')
|
||||||
|
->addDefault('Content-Length', StringHelper::strlen($content))
|
||||||
|
->addDefault('Content-Disposition', "attachment; filename=\"$attachmentName\"");
|
||||||
|
|
||||||
|
$this->content = $content;
|
||||||
|
$this->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the specified stream as a file to the browser.
|
||||||
|
* @param resource $handle the handle of the stream to be sent.
|
||||||
|
* @param string $mimeType the MIME type of the stream content.
|
||||||
|
* @param string $attachmentName the file name shown to the user.
|
||||||
|
* @throws HttpException if the requested range cannot be satisfied.
|
||||||
|
*/
|
||||||
|
public function sendStreamAsFile($handle, $mimeType = 'application/octet-stream', $attachmentName = 'file')
|
||||||
|
{
|
||||||
|
$headers = $this->getHeaders();
|
||||||
fseek($handle, 0, SEEK_END);
|
fseek($handle, 0, SEEK_END);
|
||||||
$fileSize = ftell($handle);
|
$fileSize = ftell($handle);
|
||||||
|
|
||||||
$contentStart = 0;
|
$range = $this->getHttpRange($fileSize);
|
||||||
$contentEnd = $fileSize - 1;
|
if ($range === false) {
|
||||||
|
$headers->set('Content-Range', "bytes */$fileSize");
|
||||||
$headers = $this->getHeaders();
|
throw new HttpException(416, Yii::t('yii', 'Requested range not satisfiable'));
|
||||||
|
}
|
||||||
if (isset($_SERVER['HTTP_RANGE'])) {
|
|
||||||
// client sent us a multibyte range, can not hold this one for now
|
|
||||||
if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) {
|
|
||||||
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
|
|
||||||
throw new HttpException(416, Yii::t('yii', 'Requested range not satisfiable'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']);
|
|
||||||
|
|
||||||
// range requests starts from "-", so it means that data must be dumped the end point.
|
|
||||||
if ($range[0] === '-') {
|
|
||||||
$contentStart = $fileSize - substr($range, 1);
|
|
||||||
} else {
|
|
||||||
$range = explode('-', $range);
|
|
||||||
$contentStart = $range[0];
|
|
||||||
|
|
||||||
// check if the last-byte-pos presents in header
|
|
||||||
if ((isset($range[1]) && is_numeric($range[1]))) {
|
|
||||||
$contentEnd = $range[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the range and make sure it's treated according to the specs.
|
|
||||||
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
|
||||||
*/
|
|
||||||
// End bytes can not be larger than $end.
|
|
||||||
$contentEnd = $contentEnd > $fileSize ? $fileSize - 1 : $contentEnd;
|
|
||||||
|
|
||||||
// Validate the requested range and return an error if it's not correct.
|
|
||||||
if ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0) {
|
|
||||||
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
|
|
||||||
throw new HttpException(416, Yii::t('yii', 'Requested range not satisfiable'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
list($begin, $end) = $range;
|
||||||
|
if ($begin !=0 || $end != $fileSize - 1) {
|
||||||
$this->setStatusCode(206);
|
$this->setStatusCode(206);
|
||||||
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
|
$headers->set('Content-Range', "bytes $begin-$end/$fileSize");
|
||||||
} else {
|
} else {
|
||||||
$this->setStatusCode(200);
|
$this->setStatusCode(200);
|
||||||
}
|
}
|
||||||
@@ -418,41 +345,65 @@ class Response extends \yii\base\Response
|
|||||||
$headers->set('Content-Type', $options['mimeType']);
|
$headers->set('Content-Type', $options['mimeType']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$length = $contentEnd - $contentStart + 1;
|
$length = $end - $begin + 1;
|
||||||
$disposition = empty($options['disposition']) ? 'attachment' : $options['disposition'];
|
|
||||||
if (!isset($options['saveName'])) {
|
|
||||||
$options['saveName'] = 'data';
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers->set('Pragma', 'public')
|
$headers->addDefault('Pragma', 'public')
|
||||||
->set('Expires', '0')
|
->addDefault('Accept-Ranges', 'bytes')
|
||||||
->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
->addDefault('Expires', '0')
|
||||||
->set('Content-Disposition', "$disposition; filename=\"{$options['saveName']}\"")
|
->addDefault('Content-Type', $mimeType)
|
||||||
->set('Content-Length', $length)
|
->addDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||||
->set('Content-Transfer-Encoding', 'binary');
|
->addDefault('Content-Transfer-Encoding', 'binary')
|
||||||
|
->addDefault('Content-Length', $length)
|
||||||
|
->addDefault('Content-Disposition', "attachment; filename=\"$attachmentName\"");
|
||||||
|
|
||||||
if (isset($options['headers'])) {
|
$this->send();
|
||||||
foreach ($options['headers'] as $header => $value) {
|
|
||||||
$headers->add($header, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek($handle, $contentStart);
|
|
||||||
|
|
||||||
|
fseek($handle, $begin);
|
||||||
set_time_limit(0); // Reset time limit for big files
|
set_time_limit(0); // Reset time limit for big files
|
||||||
|
|
||||||
$chunkSize = 8 * 1024 * 1024; // 8MB per chunk
|
$chunkSize = 8 * 1024 * 1024; // 8MB per chunk
|
||||||
while (!feof($handle) && ($fPointer = ftell($handle)) <= $contentEnd) {
|
while (!feof($handle) && ($pos = ftell($handle)) <= $end) {
|
||||||
if ($fPointer + $chunkSize > $contentEnd) {
|
if ($pos + $chunkSize > $end) {
|
||||||
$chunkSize = $contentEnd - $fPointer + 1;
|
$chunkSize = $end - $pos + 1;
|
||||||
}
|
}
|
||||||
echo fread($handle, $chunkSize);
|
echo fread($handle, $chunkSize);
|
||||||
flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit.
|
flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit.
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the HTTP range given in the request.
|
||||||
|
* @param integer $fileSize the size of the file that will be used to validate the requested HTTP range.
|
||||||
|
* @return array|boolean the range (begin, end), or false if the range request is invalid.
|
||||||
|
*/
|
||||||
|
protected function getHttpRange($fileSize)
|
||||||
|
{
|
||||||
|
if (!isset($_SERVER['HTTP_RANGE']) || $_SERVER['HTTP_RANGE'] === '-') {
|
||||||
|
return array(0, $fileSize - 1);
|
||||||
|
}
|
||||||
|
if (!preg_match('/^bytes=(\d*)-(\d*)$/', $_SERVER['HTTP_RANGE'], $matches)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($matches[1] === '') {
|
||||||
|
$start = $fileSize - $matches[2];
|
||||||
|
$end = $fileSize - 1;
|
||||||
|
} elseif ($matches[2] !== '') {
|
||||||
|
$start = $matches[1];
|
||||||
|
$end = $matches[2];
|
||||||
|
if ($end >= $fileSize) {
|
||||||
|
$end = $fileSize - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$start = $matches[1];
|
||||||
|
$end = $fileSize - 1;
|
||||||
|
}
|
||||||
|
if ($start < 0 || $start > $end) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return array($start, $end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends existing file to a browser as a download using x-sendfile.
|
* Sends existing file to a browser as a download using x-sendfile.
|
||||||
*
|
*
|
||||||
@@ -496,46 +447,27 @@ class Response extends \yii\base\Response
|
|||||||
* **Example**
|
* **Example**
|
||||||
*
|
*
|
||||||
* ~~~
|
* ~~~
|
||||||
* Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg', array(
|
* Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg');
|
||||||
* 'saveName' => 'image1.jpg',
|
* ~~~
|
||||||
* 'mimeType' => 'image/jpeg',
|
|
||||||
* 'terminate' => false,
|
|
||||||
* ));
|
|
||||||
*
|
*
|
||||||
* @param string $filePath file name with full path
|
* @param string $filePath file name with full path
|
||||||
* @param array $options additional options:
|
* @param string $mimeType the MIME type of the file. If null, it will be determined based on `$filePath`.
|
||||||
*
|
* @param string $attachmentName file name shown to the user. If null, it will be determined from `$filePath`.
|
||||||
* - saveName: file name shown to the user. If not set, the name will be determined from `$filePath`.
|
* @param string $xHeader the name of the x-sendfile header.
|
||||||
* - mimeType: MIME type of the file. If not set, it will be determined based on the file name.
|
|
||||||
* - xHeader: appropriate x-sendfile header, defaults to "X-Sendfile".
|
|
||||||
* - disposition: either "attachment" or "inline". This specifies whether the file will be downloaded
|
|
||||||
* or shown inline. Defaults to "attachment".
|
|
||||||
* - headers: an array of additional http headers in name-value pairs.
|
|
||||||
*/
|
*/
|
||||||
public function xSendFile($filePath, $options = array())
|
public function xSendFile($filePath, $mimeType = null, $attachmentName = null, $xHeader = 'X-Sendfile')
|
||||||
{
|
{
|
||||||
$headers = $this->getHeaders();
|
if ($mimeType === null && ($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) {
|
||||||
|
$mimeType = 'application/octet-stream';
|
||||||
$headers->set(empty($options['xHeader']) ? 'X-Sendfile' : $options['xHeader'], $filePath);
|
|
||||||
|
|
||||||
if (!isset($options['mimeType'])) {
|
|
||||||
if (($options['mimeType'] = FileHelper::getMimeTypeByExtension($filePath)) === null) {
|
|
||||||
$options['mimeType'] = 'text/plain';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$headers->set('Content-Type', $options['mimeType']);
|
if ($attachmentName === null) {
|
||||||
|
$attachmentName = basename($filePath);
|
||||||
$disposition = empty($options['disposition']) ? 'attachment' : $options['disposition'];
|
|
||||||
if (!isset($options['saveName'])) {
|
|
||||||
$options['saveName'] = basename($filePath);
|
|
||||||
}
|
}
|
||||||
$headers->set('Content-Disposition', "$disposition; filename=\"{$options['saveName']}\"");
|
|
||||||
|
|
||||||
if (isset($options['headers'])) {
|
$this->getHeaders()
|
||||||
foreach ($options['headers'] as $header => $value) {
|
->addDefault($xHeader, $filePath)
|
||||||
$headers->add($header, $value);
|
->addDefault('Content-Type', $mimeType)
|
||||||
}
|
->addDefault('Content-Disposition', "attachment; filename=\"$attachmentName\"");
|
||||||
}
|
|
||||||
|
|
||||||
$this->send();
|
$this->send();
|
||||||
}
|
}
|
||||||
|
|||||||
1
tests/unit/data/web/data.txt
Normal file
1
tests/unit/data/web/data.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?
|
||||||
@@ -4,10 +4,20 @@ namespace yiiunit\framework\web;
|
|||||||
|
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\helpers\StringHelper;
|
use yii\helpers\StringHelper;
|
||||||
use yii\web\Response;
|
|
||||||
|
class Response extends \yii\web\Response
|
||||||
|
{
|
||||||
|
public function send()
|
||||||
|
{
|
||||||
|
// does nothing to allow testing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ResponseTest extends \yiiunit\TestCase
|
class ResponseTest extends \yiiunit\TestCase
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var Response
|
||||||
|
*/
|
||||||
public $response;
|
public $response;
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
@@ -31,17 +41,20 @@ class ResponseTest extends \yiiunit\TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider rightRanges
|
* @dataProvider rightRanges
|
||||||
*/
|
*/
|
||||||
public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedFile)
|
public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedContent)
|
||||||
{
|
{
|
||||||
$content = $this->generateTestFileContent();
|
$dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt');
|
||||||
|
$fullContent = file_get_contents($dataFile);
|
||||||
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
|
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
|
||||||
$this->response->sendFile('testFile.txt', $content, null, false);
|
ob_start();
|
||||||
|
$this->response->sendFile($dataFile);
|
||||||
|
$content = ob_get_clean();
|
||||||
|
|
||||||
$this->assertEquals($expectedFile, $this->response->content);
|
$this->assertEquals($expectedContent, $content);
|
||||||
$this->assertEquals(206, $this->response->statusCode);
|
$this->assertEquals(206, $this->response->statusCode);
|
||||||
$headers = $this->response->headers;
|
$headers = $this->response->headers;
|
||||||
$this->assertEquals("bytes", $headers->get('Accept-Ranges'));
|
$this->assertEquals("bytes", $headers->get('Accept-Ranges'));
|
||||||
$this->assertEquals("bytes " . $expectedHeader . '/' . StringHelper::strlen($content), $headers->get('Content-Range'));
|
$this->assertEquals("bytes " . $expectedHeader . '/' . StringHelper::strlen($fullContent), $headers->get('Content-Range'));
|
||||||
$this->assertEquals('text/plain', $headers->get('Content-Type'));
|
$this->assertEquals('text/plain', $headers->get('Content-Type'));
|
||||||
$this->assertEquals("$length", $headers->get('Content-Length'));
|
$this->assertEquals("$length", $headers->get('Content-Length'));
|
||||||
}
|
}
|
||||||
@@ -63,11 +76,11 @@ class ResponseTest extends \yiiunit\TestCase
|
|||||||
*/
|
*/
|
||||||
public function testSendFileWrongRanges($rangeHeader)
|
public function testSendFileWrongRanges($rangeHeader)
|
||||||
{
|
{
|
||||||
$this->setExpectedException('yii\base\HttpException', 'Requested Range Not Satisfiable');
|
$this->setExpectedException('yii\base\HttpException');
|
||||||
|
|
||||||
$content = $this->generateTestFileContent();
|
$dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt');
|
||||||
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
|
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
|
||||||
$this->response->sendFile('testFile.txt', $content, null, false);
|
$this->response->sendFile($dataFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function generateTestFileContent()
|
protected function generateTestFileContent()
|
||||||
|
|||||||
Reference in New Issue
Block a user