201 lines
5.9 KiB
PHP
201 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace Guzzle\Http;
|
|
|
|
use Guzzle\Common\Version;
|
|
use Guzzle\Stream\Stream;
|
|
use Guzzle\Common\Exception\InvalidArgumentException;
|
|
use Guzzle\Http\Mimetypes;
|
|
|
|
/**
|
|
* Entity body used with an HTTP request or response
|
|
*/
|
|
class EntityBody extends Stream implements EntityBodyInterface
|
|
{
|
|
/** @var bool Content-Encoding of the entity body if known */
|
|
protected $contentEncoding = false;
|
|
|
|
/** @var callable Method to invoke for rewinding a stream */
|
|
protected $rewindFunction;
|
|
|
|
/**
|
|
* Create a new EntityBody based on the input type
|
|
*
|
|
* @param resource|string|EntityBody $resource Entity body data
|
|
* @param int $size Size of the data contained in the resource
|
|
*
|
|
* @return EntityBody
|
|
* @throws InvalidArgumentException if the $resource arg is not a resource or string
|
|
*/
|
|
public static function factory($resource = '', $size = null)
|
|
{
|
|
if ($resource instanceof EntityBodyInterface) {
|
|
return $resource;
|
|
}
|
|
|
|
switch (gettype($resource)) {
|
|
case 'string':
|
|
return self::fromString($resource);
|
|
case 'resource':
|
|
return new static($resource, $size);
|
|
case 'object':
|
|
if (method_exists($resource, '__toString')) {
|
|
return self::fromString((string) $resource);
|
|
}
|
|
break;
|
|
case 'array':
|
|
return self::fromString(http_build_query($resource));
|
|
}
|
|
|
|
throw new InvalidArgumentException('Invalid resource type');
|
|
}
|
|
|
|
public function setRewindFunction($callable)
|
|
{
|
|
if (!is_callable($callable)) {
|
|
throw new InvalidArgumentException('Must specify a callable');
|
|
}
|
|
|
|
$this->rewindFunction = $callable;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function rewind()
|
|
{
|
|
return $this->rewindFunction ? call_user_func($this->rewindFunction, $this) : parent::rewind();
|
|
}
|
|
|
|
/**
|
|
* Create a new EntityBody from a string
|
|
*
|
|
* @param string $string String of data
|
|
*
|
|
* @return EntityBody
|
|
*/
|
|
public static function fromString($string)
|
|
{
|
|
$stream = fopen('php://temp', 'r+');
|
|
if ($string !== '') {
|
|
fwrite($stream, $string);
|
|
rewind($stream);
|
|
}
|
|
|
|
return new static($stream);
|
|
}
|
|
|
|
public function compress($filter = 'zlib.deflate')
|
|
{
|
|
$result = $this->handleCompression($filter);
|
|
$this->contentEncoding = $result ? $filter : false;
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function uncompress($filter = 'zlib.inflate')
|
|
{
|
|
$offsetStart = 0;
|
|
|
|
// When inflating gzipped data, the first 10 bytes must be stripped
|
|
// if a gzip header is present
|
|
if ($filter == 'zlib.inflate') {
|
|
// @codeCoverageIgnoreStart
|
|
if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) {
|
|
return false;
|
|
}
|
|
// @codeCoverageIgnoreEnd
|
|
if (stream_get_contents($this->stream, 3, 0) === "\x1f\x8b\x08") {
|
|
$offsetStart = 10;
|
|
}
|
|
}
|
|
|
|
$this->contentEncoding = false;
|
|
|
|
return $this->handleCompression($filter, $offsetStart);
|
|
}
|
|
|
|
public function getContentLength()
|
|
{
|
|
return $this->getSize();
|
|
}
|
|
|
|
public function getContentType()
|
|
{
|
|
return $this->getUri() ? Mimetypes::getInstance()->fromFilename($this->getUri()) : null;
|
|
}
|
|
|
|
public function getContentMd5($rawOutput = false, $base64Encode = false)
|
|
{
|
|
if ($hash = self::getHash($this, 'md5', $rawOutput)) {
|
|
return $hash && $base64Encode ? base64_encode($hash) : $hash;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate the MD5 hash of an entity body
|
|
*
|
|
* @param EntityBodyInterface $body Entity body to calculate the hash for
|
|
* @param bool $rawOutput Whether or not to use raw output
|
|
* @param bool $base64Encode Whether or not to base64 encode raw output (only if raw output is true)
|
|
*
|
|
* @return bool|string Returns an MD5 string on success or FALSE on failure
|
|
* @deprecated This will be deprecated soon
|
|
* @codeCoverageIgnore
|
|
*/
|
|
public static function calculateMd5(EntityBodyInterface $body, $rawOutput = false, $base64Encode = false)
|
|
{
|
|
Version::warn(__CLASS__ . ' is deprecated. Use getContentMd5()');
|
|
return $body->getContentMd5($rawOutput, $base64Encode);
|
|
}
|
|
|
|
public function setStreamFilterContentEncoding($streamFilterContentEncoding)
|
|
{
|
|
$this->contentEncoding = $streamFilterContentEncoding;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getContentEncoding()
|
|
{
|
|
return strtr($this->contentEncoding, array(
|
|
'zlib.deflate' => 'gzip',
|
|
'bzip2.compress' => 'compress'
|
|
)) ?: false;
|
|
}
|
|
|
|
protected function handleCompression($filter, $offsetStart = 0)
|
|
{
|
|
// @codeCoverageIgnoreStart
|
|
if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) {
|
|
return false;
|
|
}
|
|
// @codeCoverageIgnoreEnd
|
|
|
|
$handle = fopen('php://temp', 'r+');
|
|
$filter = @stream_filter_append($handle, $filter, STREAM_FILTER_WRITE);
|
|
if (!$filter) {
|
|
return false;
|
|
}
|
|
|
|
// Seek to the offset start if possible
|
|
$this->seek($offsetStart);
|
|
while ($data = fread($this->stream, 8096)) {
|
|
fwrite($handle, $data);
|
|
}
|
|
|
|
fclose($this->stream);
|
|
$this->stream = $handle;
|
|
stream_filter_remove($filter);
|
|
$stat = fstat($this->stream);
|
|
$this->size = $stat['size'];
|
|
$this->rebuildCache();
|
|
$this->seek(0);
|
|
|
|
// Remove any existing rewind function as the underlying stream has been replaced
|
|
$this->rewindFunction = null;
|
|
|
|
return true;
|
|
}
|
|
}
|