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

https://github.com/shevron/zf2 · PHP · 277 lines · 127 code · 38 blank · 112 comment · 27 complexity · cdd5344a4cd039bc2f7d2408b5df14b7 MD5 · raw file

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