GuzzleHttpPsr7CachingStream

Stream decorator that can cache previously read bytes from a sequentially read stream.

Defined (1)

The class is defined in the following location(s).

/lib/Azure/GuzzleHttp/Psr7/CachingStream.php  
  1. class CachingStream implements StreamInterface 
  2. use StreamDecoratorTrait; 
  3.  
  4. /** @var StreamInterface Stream being wrapped */ 
  5. private $remoteStream; 
  6.  
  7. /** @var int Number of bytes to skip reading due to a write on the buffer */ 
  8. private $skipReadBytes = 0; 
  9.  
  10. /** 
  11. * We will treat the buffer object as the body of the stream 
  12. * @param StreamInterface $stream Stream to cache 
  13. * @param StreamInterface $target Optionally specify where data is cached 
  14. */ 
  15. public function __construct( 
  16. StreamInterface $stream,  
  17. StreamInterface $target = null 
  18. ) { 
  19. $this->remoteStream = $stream; 
  20. $this->stream = $target ?: new Stream(fopen('php://temp', 'r+')); 
  21.  
  22. public function getSize() 
  23. return max($this->stream->getSize(), $this->remoteStream->getSize()); 
  24.  
  25. public function rewind() 
  26. $this->seek(0); 
  27.  
  28. public function seek($offset, $whence = SEEK_SET) 
  29. if ($whence == SEEK_SET) { 
  30. $byte = $offset; 
  31. } elseif ($whence == SEEK_CUR) { 
  32. $byte = $offset + $this->tell(); 
  33. } elseif ($whence == SEEK_END) { 
  34. $size = $this->remoteStream->getSize(); 
  35. if ($size === null) { 
  36. $size = $this->cacheEntireStream(); 
  37. $byte = $size + $offset; 
  38. } else { 
  39. throw new \InvalidArgumentException('Invalid whence'); 
  40.  
  41. $diff = $byte - $this->stream->getSize(); 
  42.  
  43. if ($diff > 0) { 
  44. // Read the remoteStream until we have read in at least the amount 
  45. // of bytes requested, or we reach the end of the file. 
  46. while ($diff > 0 && !$this->remoteStream->eof()) { 
  47. $this->read($diff); 
  48. $diff = $byte - $this->stream->getSize(); 
  49. } else { 
  50. // We can just do a normal seek since we've already seen this byte. 
  51. $this->stream->seek($byte); 
  52.  
  53. public function read($length) 
  54. // Perform a regular read on any previously read data from the buffer 
  55. $data = $this->stream->read($length); 
  56. $remaining = $length - strlen($data); 
  57.  
  58. // More data was requested so read from the remote stream 
  59. if ($remaining) { 
  60. // If data was written to the buffer in a position that would have 
  61. // been filled from the remote stream, then we must skip bytes on 
  62. // the remote stream to emulate overwriting bytes from that 
  63. // position. This mimics the behavior of other PHP stream wrappers. 
  64. $remoteData = $this->remoteStream->read( 
  65. $remaining + $this->skipReadBytes 
  66. ); 
  67.  
  68. if ($this->skipReadBytes) { 
  69. $len = strlen($remoteData); 
  70. $remoteData = substr($remoteData, $this->skipReadBytes); 
  71. $this->skipReadBytes = max(0, $this->skipReadBytes - $len); 
  72.  
  73. $data .= $remoteData; 
  74. $this->stream->write($remoteData); 
  75.  
  76. return $data; 
  77.  
  78. public function write($string) 
  79. // When appending to the end of the currently read stream, you'll want 
  80. // to skip bytes from being read from the remote stream to emulate 
  81. // other stream wrappers. Basically replacing bytes of data of a fixed 
  82. // length. 
  83. $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell(); 
  84. if ($overflow > 0) { 
  85. $this->skipReadBytes += $overflow; 
  86.  
  87. return $this->stream->write($string); 
  88.  
  89. public function eof() 
  90. return $this->stream->eof() && $this->remoteStream->eof(); 
  91.  
  92. /** 
  93. * Close both the remote stream and buffer stream 
  94. */ 
  95. public function close() 
  96. $this->remoteStream->close() && $this->stream->close(); 
  97.  
  98. private function cacheEntireStream() 
  99. $target = new FnStream(['write' => 'strlen']); 
  100. copy_to_stream($this, $target); 
  101.  
  102. return $this->tell();