/library/Zend/Http/Response/Stream.php

https://github.com/necrogami/zf2 · PHP · 291 lines · 127 code · 39 blank · 125 comment · 27 complexity · a29bd09e38fb8c3457e2376e1eaa6a6f MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Http
  17. * @subpackage Response
  18. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. namespace Zend\Http\Response;
  22. use Zend\Http\Response,
  23. Zend\Http\Exception;
  24. /**
  25. * Zend_Http_Response represents an HTTP 1.0 / 1.1 response message. It
  26. * includes easy access to all the response's different elemts, as well as some
  27. * convenience methods for parsing and validating HTTP responses.
  28. *
  29. * @package Zend_Http
  30. * @subpackage Response
  31. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. */
  34. class Stream extends Response
  35. {
  36. /**
  37. * The Content-Length value, if set
  38. *
  39. * @var int
  40. */
  41. protected $contentLength = null;
  42. /**
  43. * The portion of the body that has alredy been streamed
  44. *
  45. * @var int
  46. */
  47. protected $contentStreamed = 0;
  48. /**
  49. * Response as stream
  50. *
  51. * @var resource
  52. */
  53. protected $stream;
  54. /**
  55. * The name of the file containing the stream
  56. *
  57. * Will be empty if stream is not file-based.
  58. *
  59. * @var string
  60. */
  61. protected $streamName;
  62. /**
  63. * Should we clean up the stream file when this response is closed?
  64. *
  65. * @var boolean
  66. */
  67. protected $cleanup;
  68. /**
  69. * Get the response as stream
  70. *
  71. * @return resourse
  72. */
  73. public function getStream()
  74. {
  75. return $this->stream;
  76. }
  77. /**
  78. * Set the response stream
  79. *
  80. * @param resourse $stream
  81. * @return Stream
  82. */
  83. public function setStream($stream)
  84. {
  85. $this->stream = $stream;
  86. return $this;
  87. }
  88. /**
  89. * Get the cleanup trigger
  90. *
  91. * @return boolean
  92. */
  93. public function getCleanup()
  94. {
  95. return $this->cleanup;
  96. }
  97. /**
  98. * Set the cleanup trigger
  99. *
  100. * @param $cleanup Set cleanup trigger
  101. */
  102. public function setCleanup($cleanup = true)
  103. {
  104. $this->cleanup = $cleanup;
  105. }
  106. /**
  107. * Get file name associated with the stream
  108. *
  109. * @return string
  110. */
  111. public function getStreamName()
  112. {
  113. return $this->streamName;
  114. }
  115. /**
  116. * Set file name associated with the stream
  117. *
  118. * @param string $streamName Name to set
  119. * @return Stream
  120. */
  121. public function setStreamName($streamName)
  122. {
  123. $this->streamName = $streamName;
  124. return $this;
  125. }
  126. /**
  127. * Create a new Zend\Http\Response\Stream object from a stream
  128. *
  129. * @param string $responseString
  130. * @param resource $stream
  131. * @return Stream
  132. */
  133. public static function fromStream($responseString, $stream)
  134. {
  135. if (!is_resource($stream)) {
  136. throw new Exception\InvalidArgumentException('A valid stream is required');
  137. }
  138. $headerComplete = false;
  139. $headersString = '';
  140. $responseArray = explode("\n",$responseString);
  141. while (count($responseArray)) {
  142. $nextLine = array_shift($responseArray);
  143. $headersString .= $nextLine."\n";
  144. $nextLineTrimmed = trim($nextLine);
  145. if ($nextLineTrimmed == "") {
  146. $headerComplete = true;
  147. break;
  148. }
  149. }
  150. if (!$headerComplete) {
  151. while (false !== ($nextLine = fgets($stream))) {
  152. $headersString .= trim($nextLine)."\r\n";
  153. if ($nextLine == "\r\n" || $nextLine == "\n") {
  154. $headerComplete = true;
  155. break;
  156. }
  157. }
  158. }
  159. if (!$headerComplete) {
  160. throw new Exception\OutOfRangeException('End of header not found');
  161. }
  162. $response = static::fromString($headersString);
  163. if (is_resource($stream)) {
  164. $response->setStream($stream);
  165. }
  166. if (count($responseArray)) {
  167. $response->content = implode("\n", $responseArray);
  168. }
  169. $headers = $response->headers();
  170. foreach($headers as $header) {
  171. if ($header instanceof \Zend\Http\Header\ContentLength) {
  172. $response->contentLength = (int) $header->getFieldValue();
  173. if (strlen($response->content) > $response->contentLength) {
  174. throw new Exception\OutOfRangeException(
  175. sprintf('Too much content was extracted from the stream (%d instead of %d bytes)',
  176. strlen($this->content), $this->contentLength));
  177. }
  178. break;
  179. }
  180. }
  181. return $response;
  182. }
  183. /**
  184. * Get the response body as string
  185. *
  186. * This method returns the body of the HTTP response (the content), as it
  187. * should be in it's readable version - that is, after decoding it (if it
  188. * was decoded), deflating it (if it was gzip compressed), etc.
  189. *
  190. * If you want to get the raw body (as transfered on wire) use
  191. * $this->getRawBody() instead.
  192. *
  193. * @return string
  194. */
  195. public function getBody()
  196. {
  197. if ($this->stream != null) {
  198. $this->readStream();
  199. }
  200. return parent::getBody();
  201. }
  202. /**
  203. * Get the raw response body (as transfered "on wire") as string
  204. *
  205. * If the body is encoded (with Transfer-Encoding, not content-encoding -
  206. * IE "chunked" body), gzip compressed, etc. it will not be decoded.
  207. *
  208. * @return string
  209. */
  210. public function getRawBody()
  211. {
  212. if ($this->stream) {
  213. $this->readStream();
  214. }
  215. return $this->content;
  216. }
  217. /**
  218. * Read stream content and return it as string
  219. *
  220. * Function reads the remainder of the body from the stream and closes the stream.
  221. *
  222. * @return string
  223. */
  224. protected function readStream()
  225. {
  226. if (!is_null($this->contentLength)) {
  227. $bytes = $this->contentLength - $this->contentStreamed;
  228. } else {
  229. $bytes = -1; //Read the whole buffer
  230. }
  231. if (!is_resource($this->stream) || $bytes == 0) {
  232. return '';
  233. }
  234. $this->content .= stream_get_contents($this->stream, $bytes);
  235. $this->contentStreamed += strlen($this->content);
  236. if ($this->contentLength == $this->contentStreamed) {
  237. $this->stream = null;
  238. }
  239. }
  240. /**
  241. * Destructor
  242. */
  243. public function __destruct()
  244. {
  245. if (is_resource($this->stream)) {
  246. $this->stream = null; //Could be listened by others
  247. }
  248. if ($this->cleanup) {
  249. @unlink($this->stream_name);
  250. }
  251. }
  252. }