This repository has been archived by the owner on Jan 29, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
631 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<?php | ||
/** | ||
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository | ||
* @copyright Copyright (c) 2015-2018 Zend Technologies USA Inc. (https://www.zend.com) | ||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Zend\Diactoros\Response; | ||
|
||
use Psr\Http\Message\StreamInterface; | ||
use Zend\Diactoros\Exception; | ||
use Zend\Diactoros\Response; | ||
use Zend\Diactoros\Stream; | ||
|
||
use function get_class; | ||
use function gettype; | ||
use function is_object; | ||
use function is_string; | ||
use function sprintf; | ||
|
||
/** | ||
* CSV response. | ||
* | ||
* Allows creating a CSV response by passing a string to the constructor; | ||
* by default, sets a status code of 200 and sets the Content-Type header to | ||
* text/csv. | ||
*/ | ||
class CsvResponse extends Response | ||
{ | ||
use InjectContentTypeTrait; | ||
|
||
/** | ||
* Create a CSV response. | ||
* | ||
* Produces a CSV response with a Content-Type of text/csv and a default | ||
* status of 200. | ||
* | ||
* @param string|StreamInterface $text String or stream for the message body. | ||
* @param int $status Integer status code for the response; 200 by default. | ||
* @param string $filename | ||
* @param array $headers Array of headers to use at initialization. | ||
*/ | ||
public function __construct($text, int $status = 200, string $filename = '', array $headers = []) | ||
{ | ||
if (is_string($filename) && $filename !== '') { | ||
$headers = $this->prepareDownloadHeaders($filename, $headers); | ||
} | ||
|
||
parent::__construct( | ||
$this->createBody($text), | ||
$status, | ||
$this->injectContentType('text/csv; charset=utf-8', $headers) | ||
); | ||
} | ||
|
||
/** | ||
* Create the CSV message body. | ||
* | ||
* @param string|StreamInterface $text | ||
* @return StreamInterface | ||
* @throws Exception\InvalidArgumentException if $text is neither a string or stream. | ||
*/ | ||
private function createBody($text) : StreamInterface | ||
{ | ||
if ($text instanceof StreamInterface) { | ||
return $text; | ||
} | ||
|
||
if (! is_string($text)) { | ||
throw new Exception\InvalidArgumentException(sprintf( | ||
'Invalid CSV content (%s) provided to %s', | ||
(is_object($text) ? get_class($text) : gettype($text)), | ||
__CLASS__ | ||
)); | ||
} | ||
|
||
$body = new Stream('php://temp', 'wb+'); | ||
$body->write($text); | ||
$body->rewind(); | ||
return $body; | ||
} | ||
|
||
/** | ||
* Get download headers | ||
* | ||
* @param string $filename | ||
* @return array | ||
*/ | ||
private function getDownloadHeaders(string $filename): array | ||
{ | ||
$headers = []; | ||
$headers['cache-control'] = ['must-revalidate']; | ||
$headers['content-description'] = ['File Transfer']; | ||
$headers['content-disposition'] = [sprintf('attachment; filename=%s', $filename)]; | ||
$headers['content-transfer-encoding'] = ['Binary']; | ||
$headers['content-type'] = ['text/csv; charset=utf-8']; | ||
$headers['expires'] = ['0']; | ||
$headers['pragma'] = ['Public']; | ||
|
||
return $headers; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
<?php | ||
/** | ||
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository | ||
* @copyright Copyright (c) 2015-2018 Zend Technologies USA Inc. (https://www.zend.com) | ||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Zend\Diactoros\Response; | ||
|
||
use Psr\Http\Message\StreamInterface; | ||
use Zend\Diactoros\Exception\InvalidArgumentException; | ||
use Zend\Diactoros\Response; | ||
|
||
use Zend\Diactoros\Stream; | ||
use function array_keys; | ||
use function array_merge; | ||
use function implode; | ||
use function in_array; | ||
use function sprintf; | ||
|
||
/** | ||
* Class DownloadResponse | ||
* @package Zend\Diactoros\Response | ||
*/ | ||
class DownloadResponse extends Response | ||
{ | ||
const DEFAULT_CONTENT_TYPE = 'application/octet-stream'; | ||
const DEFAULT_DOWNLOAD_FILENAME = 'download'; | ||
|
||
/** | ||
* A list of header keys required to be sent with a download response | ||
* | ||
* @var array | ||
*/ | ||
private $downloadResponseHeaders = [ | ||
'cache-control', | ||
'content-description', | ||
'content-disposition', | ||
'content-transfer-encoding', | ||
'expires', | ||
'pragma' | ||
]; | ||
|
||
/** | ||
* @var string The filename to be sent with the response | ||
*/ | ||
private $filename; | ||
|
||
/** | ||
* @var string The content type to be sent with the response | ||
*/ | ||
private $contentType; | ||
|
||
/** | ||
* DownloadResponse constructor. | ||
* | ||
* @param string|StreamInterface $body String or stream for the message body. | ||
* @param int $status Integer status code for the response; 200 by default. | ||
* @param string $filename The file name to be sent with the response | ||
* @param string $contentType The content type to be sent with the response | ||
* @param array $headers An array of optional headers. These cannot override those set in getDownloadHeaders */ | ||
public function __construct( | ||
$body, | ||
int $status = 200, | ||
string $filename = self::DEFAULT_DOWNLOAD_FILENAME, | ||
string $contentType = self::DEFAULT_CONTENT_TYPE, | ||
array $headers = [] | ||
) { | ||
$this->filename = $filename; | ||
$this->contentType = $contentType; | ||
|
||
parent::__construct( | ||
$this->createBody($body), | ||
$status, | ||
$this->prepareDownloadHeaders($headers) | ||
); | ||
} | ||
|
||
/** | ||
* Get download headers | ||
* | ||
* @return array | ||
*/ | ||
private function getDownloadHeaders(): array | ||
{ | ||
$headers = []; | ||
$headers['cache-control'] = 'must-revalidate'; | ||
$headers['content-description'] = 'File Transfer'; | ||
$headers['content-disposition'] = sprintf('attachment; filename=%s', self::DEFAULT_DOWNLOAD_FILENAME); | ||
$headers['content-transfer-encoding'] = 'Binary'; | ||
$headers['content-type'] = 'application/octet-stream'; | ||
$headers['expires'] = '0'; | ||
$headers['pragma'] = 'Public'; | ||
|
||
return $headers; | ||
} | ||
|
||
/** | ||
* Check if the extra headers contain any of the download headers | ||
* | ||
* The download headers cannot be overridden. | ||
* | ||
* @param array $downloadHeaders | ||
* @param array $headers | ||
* @return bool | ||
*/ | ||
public function overridesDownloadHeaders(array $downloadHeaders, array $headers = []) : bool | ||
{ | ||
$overridesDownloadHeaders = false; | ||
|
||
foreach (array_keys($headers) as $header) { | ||
if (in_array($header, $downloadHeaders)) { | ||
$overridesDownloadHeaders = true; | ||
break; | ||
} | ||
} | ||
|
||
return $overridesDownloadHeaders; | ||
} | ||
|
||
/** | ||
* Prepare download response headers | ||
* | ||
* This function prepares the download response headers. It does so by: | ||
* - Merging the optional with over the default ones (the default ones cannot be overridden) | ||
* - Set the content-type and content-disposition headers from $filename and $contentType passed | ||
* to the constructor. | ||
* | ||
* @param array $headers | ||
* @return array | ||
* @throws InvalidArgumentException if an attempt is made to override a default header | ||
*/ | ||
private function prepareDownloadHeaders(array $headers = []) : array | ||
{ | ||
if ($this->overridesDownloadHeaders($this->downloadResponseHeaders, $headers)) { | ||
throw new InvalidArgumentException( | ||
sprintf( | ||
'Cannot override download headers (%s) when download response is being sent', | ||
implode(', ', $this->downloadResponseHeaders) | ||
) | ||
); | ||
} | ||
|
||
return array_merge( | ||
$headers, | ||
$this->getDownloadHeaders(), | ||
[ | ||
'content-disposition' => sprintf('attachment; filename=%s', $this->filename), | ||
'content-type' => $this->contentType, | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* @param string|StreamInterface $content | ||
* @return StreamInterface | ||
* @throws InvalidArgumentException if $body is neither a string nor a Stream | ||
*/ | ||
private function createBody($content): StreamInterface | ||
{ | ||
if ($content instanceof StreamInterface) { | ||
return $content; | ||
} | ||
|
||
if (!is_string($content)) { | ||
throw new InvalidArgumentException(sprintf( | ||
'Invalid content (%s) provided to %s', | ||
(is_object($content) ? get_class($content) : gettype($content)), | ||
__CLASS__ | ||
)); | ||
} | ||
|
||
$body = new Stream('php://temp', 'wb+'); | ||
$body->write($content); | ||
$body->rewind(); | ||
return $body; | ||
} | ||
} |
Oops, something went wrong.