Overview

Namespaces

  • Contrib
    • Bundle
      • CoverallsBundle
        • Console
        • Entity
      • CoverallsV1Bundle
        • Api
        • Collector
        • Command
        • Config
        • Entity
          • Git
    • Component
      • File
      • Log
      • System
        • Git
  • Guzzle
    • Batch
      • Exception
    • Cache
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
      • QueryAggregator
    • Inflection
    • Iterator
    • Log
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Async
      • Backoff
      • Cache
      • Cookie
        • CookieJar
        • Exception
      • CurlAuth
      • ErrorResponse
        • Exception
      • History
      • Log
      • Md5
      • Mock
      • Oauth
    • Service
      • Builder
      • Command
        • Factory
        • LocationVisitor
          • Request
          • Response
      • Description
      • Exception
      • Resource
    • Stream
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Config
        • Definition
          • Builder
          • Exception
        • Exception
        • Loader
        • Resource
        • Util
      • Console
        • Command
        • Formatter
        • Helper
        • Input
        • Output
        • Tester
      • EventDispatcher
        • Debug
      • Finder
        • Adapter
        • Comparator
        • Exception
        • Expression
        • Iterator
        • Shell
      • Stopwatch
      • Yaml
        • Exception

Classes

  • AbstractEntityBodyDecorator
  • CachingEntityBody
  • Client
  • EntityBody
  • IoEmittingEntityBody
  • Mimetypes
  • QueryString
  • ReadLimitEntityBody
  • RedirectPlugin
  • Url

Interfaces

  • ClientInterface
  • EntityBodyInterface
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: namespace Guzzle\Http;
  4: 
  5: use Guzzle\Common\Exception\RuntimeException;
  6: 
  7: /**
  8:  * EntityBody decorator that can cache previously read bytes from a sequentially read tstream
  9:  */
 10: class CachingEntityBody extends AbstractEntityBodyDecorator
 11: {
 12:     /**
 13:      * @var EntityBody Remote stream used to actually pull data onto the buffer
 14:      */
 15:     protected $remoteStream;
 16: 
 17:     /**
 18:      * @var int The number of bytes to skip reading due to a write on the temporary buffer
 19:      */
 20:     protected $skipReadBytes = 0;
 21: 
 22:     /**
 23:      * We will treat the buffer object as the body of the entity body
 24:      * {@inheritdoc}
 25:      */
 26:     public function __construct(EntityBodyInterface $body)
 27:     {
 28:         $this->remoteStream = $body;
 29:         $this->body = new EntityBody(fopen('php://temp', 'r+'));
 30:     }
 31: 
 32:     /**
 33:      * Will give the contents of the buffer followed by the exhausted remote stream.
 34:      *
 35:      * Warning: Loads the entire stream into memory
 36:      *
 37:      * @return string
 38:      */
 39:     public function __toString()
 40:     {
 41:         $pos = $this->ftell();
 42:         $this->rewind();
 43: 
 44:         $str = '';
 45:         while (!$this->isConsumed()) {
 46:             $str .= $this->read(16384);
 47:         }
 48: 
 49:         $this->seek($pos);
 50: 
 51:         return $str;
 52:     }
 53: 
 54:     /**
 55:      * {@inheritdoc}
 56:      */
 57:     public function getSize()
 58:     {
 59:         return max($this->body->getSize(), $this->remoteStream->getSize());
 60:     }
 61: 
 62:     /**
 63:      * {@inheritdoc}
 64:      * @throws RuntimeException When seeking with SEEK_END or when seeking past the total size of the buffer stream
 65:      */
 66:     public function seek($offset, $whence = SEEK_SET)
 67:     {
 68:         if ($whence == SEEK_SET) {
 69:             $byte = $offset;
 70:         } elseif ($whence == SEEK_CUR) {
 71:             $byte = $offset + $this->ftell();
 72:         } else {
 73:             throw new RuntimeException(__CLASS__ . ' supports only SEEK_SET and SEEK_CUR seek operations');
 74:         }
 75: 
 76:         // You cannot skip ahead past where you've read from the remote stream
 77:         if ($byte > $this->body->getSize()) {
 78:             throw new RuntimeException(
 79:                 "Cannot seek to byte {$byte} when the buffered stream only contains {$this->body->getSize()} bytes"
 80:             );
 81:         }
 82: 
 83:         return $this->body->seek($byte);
 84:     }
 85: 
 86:     /**
 87:      * {@inheritdoc}
 88:      */
 89:     public function rewind()
 90:     {
 91:         return $this->seek(0);
 92:     }
 93: 
 94:     /**
 95:      * Does not support custom rewind functions
 96:      *
 97:      * @throws RuntimeException
 98:      */
 99:     public function setRewindFunction($callable)
100:     {
101:         throw new RuntimeException(__CLASS__ . ' does not support custom stream rewind functions');
102:     }
103: 
104:     /**
105:      * {@inheritdoc}
106:      */
107:     public function read($length)
108:     {
109:         // Perform a regular read on any previously read data from the buffer
110:         $data = $this->body->read($length);
111:         $remaining = $length - strlen($data);
112: 
113:         // More data was requested so read from the remote stream
114:         if ($remaining) {
115:             // If data was written to the buffer in a position that would have been filled from the remote stream,
116:             // then we must skip bytes on the remote stream to emulate overwriting bytes from that position. This
117:             // mimics the behavior of other PHP stream wrappers.
118:             $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes);
119: 
120:             if ($this->skipReadBytes) {
121:                 $len = strlen($remoteData);
122:                 $remoteData = substr($remoteData, $this->skipReadBytes);
123:                 $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
124:             }
125: 
126:             $data .= $remoteData;
127:             $this->body->write($remoteData);
128:         }
129: 
130:         return $data;
131:     }
132: 
133:     /**
134:      * {@inheritdoc}
135:      */
136:     public function write($string)
137:     {
138:         // When appending to the end of the currently read stream, you'll want to skip bytes from being read from
139:         // the remote stream to emulate other stream wrappers. Basically replacing bytes of data of a fixed length.
140:         $overflow = (strlen($string) + $this->ftell()) - $this->remoteStream->ftell();
141:         if ($overflow > 0) {
142:             $this->skipReadBytes += $overflow;
143:         }
144: 
145:         return $this->body->write($string);
146:     }
147: 
148:     /**
149:      * {@inheritdoc}
150:      * @link http://php.net/manual/en/function.fgets.php
151:      */
152:     public function readLine($maxLength = null)
153:     {
154:         $buffer = '';
155:         $size = 0;
156:         while (!$this->isConsumed()) {
157:             $byte = $this->read(1);
158:             $buffer .= $byte;
159:             // Break when a new line is found or the max length - 1 is reached
160:             if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
161:                 break;
162:             }
163:         }
164: 
165:         return $buffer;
166:     }
167: 
168:     /**
169:      * {@inheritdoc}
170:      */
171:     public function isConsumed()
172:     {
173:         return $this->body->isConsumed() && $this->remoteStream->isConsumed();
174:     }
175: 
176:     /**
177:      * Close both the remote stream and buffer stream
178:      */
179:     public function close()
180:     {
181:         return $this->remoteStream->close() && $this->body->close();
182:     }
183: 
184:     /**
185:      * {@inheritdoc}
186:      */
187:     public function setStream($stream, $size = 0)
188:     {
189:         $this->remoteStream->setStream($stream, $size);
190:     }
191: 
192:     /**
193:      * {@inheritdoc}
194:      */
195:     public function getContentType()
196:     {
197:         return $this->remoteStream->getContentType();
198:     }
199: 
200:     /**
201:      * {@inheritdoc}
202:      */
203:     public function getContentEncoding()
204:     {
205:         return $this->remoteStream->getContentEncoding();
206:     }
207: 
208:     /**
209:      * {@inheritdoc}
210:      */
211:     public function getMetaData($key = null)
212:     {
213:         return $this->remoteStream->getMetaData($key);
214:     }
215: 
216:     /**
217:      * {@inheritdoc}
218:      */
219:     public function getStream()
220:     {
221:         return $this->remoteStream->getStream();
222:     }
223: 
224:     /**
225:      * {@inheritdoc}
226:      */
227:     public function getWrapper()
228:     {
229:         return $this->remoteStream->getWrapper();
230:     }
231: 
232:     /**
233:      * {@inheritdoc}
234:      */
235:     public function getWrapperData()
236:     {
237:         return $this->remoteStream->getWrapperData();
238:     }
239: 
240:     /**
241:      * {@inheritdoc}
242:      */
243:     public function getStreamType()
244:     {
245:         return $this->remoteStream->getStreamType();
246:     }
247: 
248:     /**
249:      * {@inheritdoc}
250:      */
251:     public function getUri()
252:     {
253:         return $this->remoteStream->getUri();
254:     }
255: 
256:     /**
257:      * Always retrieve custom data from the remote stream
258:      *
259:      * {@inheritdoc}
260:      */
261:     public function getCustomData($key)
262:     {
263:         return $this->remoteStream->getCustomData($key);
264:     }
265: 
266:     /**
267:      * Always set custom data on the remote stream
268:      *
269:      * {@inheritdoc}
270:      */
271:     public function setCustomData($key, $value)
272:     {
273:         $this->remoteStream->setCustomData($key, $value);
274: 
275:         return $this;
276:     }
277: }
278: 
php-coveralls API documentation generated by ApiGen 2.8.0