ReadLimitEntityBody.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. <?php
  2. namespace Guzzle\Http;
  3. /**
  4. * EntityBody decorator used to return only a subset of an entity body
  5. */
  6. class ReadLimitEntityBody extends AbstractEntityBodyDecorator
  7. {
  8. /** @var int Limit the number of bytes that can be read */
  9. protected $limit;
  10. /** @var int Offset to start reading from */
  11. protected $offset;
  12. /**
  13. * @param EntityBodyInterface $body Body to wrap
  14. * @param int $limit Total number of bytes to allow to be read from the stream
  15. * @param int $offset Position to seek to before reading (only works on seekable streams)
  16. */
  17. public function __construct(EntityBodyInterface $body, $limit, $offset = 0)
  18. {
  19. parent::__construct($body);
  20. $this->setLimit($limit)->setOffset($offset);
  21. }
  22. /**
  23. * Returns only a subset of the decorated entity body when cast as a string
  24. * {@inheritdoc}
  25. */
  26. public function __toString()
  27. {
  28. return substr((string) $this->body, $this->offset, $this->limit) ?: '';
  29. }
  30. public function isConsumed()
  31. {
  32. return $this->body->isConsumed() ||
  33. ($this->body->ftell() >= $this->offset + $this->limit);
  34. }
  35. /**
  36. * Returns the Content-Length of the limited subset of data
  37. * {@inheritdoc}
  38. */
  39. public function getContentLength()
  40. {
  41. $length = $this->body->getContentLength();
  42. return $length === false
  43. ? $this->limit
  44. : min($this->limit, min($length, $this->offset + $this->limit) - $this->offset);
  45. }
  46. /**
  47. * Allow for a bounded seek on the read limited entity body
  48. * {@inheritdoc}
  49. */
  50. public function seek($offset, $whence = SEEK_SET)
  51. {
  52. return $whence === SEEK_SET
  53. ? $this->body->seek(max($this->offset, min($this->offset + $this->limit, $offset)))
  54. : false;
  55. }
  56. /**
  57. * Set the offset to start limiting from
  58. *
  59. * @param int $offset Offset to seek to and begin byte limiting from
  60. *
  61. * @return self
  62. */
  63. public function setOffset($offset)
  64. {
  65. $this->body->seek($offset);
  66. $this->offset = $offset;
  67. return $this;
  68. }
  69. /**
  70. * Set the limit of bytes that the decorator allows to be read from the stream
  71. *
  72. * @param int $limit Total number of bytes to allow to be read from the stream
  73. *
  74. * @return self
  75. */
  76. public function setLimit($limit)
  77. {
  78. $this->limit = $limit;
  79. return $this;
  80. }
  81. public function read($length)
  82. {
  83. // Check if the current position is less than the total allowed bytes + original offset
  84. $remaining = ($this->offset + $this->limit) - $this->body->ftell();
  85. if ($remaining > 0) {
  86. // Only return the amount of requested data, ensuring that the byte limit is not exceeded
  87. return $this->body->read(min($remaining, $length));
  88. } else {
  89. return false;
  90. }
  91. }
  92. }