ResourceStream.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <?php
  2. namespace AsyncAws\Core\Stream;
  3. use AsyncAws\Core\Exception\InvalidArgument;
  4. /**
  5. * Convert a resource into a Stream.
  6. *
  7. * @author Jérémy Derussé <jeremy@derusse.com>
  8. *
  9. * @internal
  10. */
  11. final class ResourceStream implements RequestStream
  12. {
  13. /**
  14. * @var resource
  15. */
  16. private $content;
  17. private $chunkSize;
  18. private function __construct($content, int $chunkSize = 64 * 1024)
  19. {
  20. $this->content = $content;
  21. $this->chunkSize = $chunkSize;
  22. }
  23. public static function create($content, int $chunkSize = 64 * 1024): ResourceStream
  24. {
  25. if ($content instanceof self) {
  26. return $content;
  27. }
  28. if (\is_resource($content)) {
  29. if (!stream_get_meta_data($content)['seekable']) {
  30. throw new InvalidArgument(sprintf('The give body is not seekable.'));
  31. }
  32. return new self($content, $chunkSize);
  33. }
  34. throw new InvalidArgument(sprintf('Expect content to be a "resource". "%s" given.', \is_object($content) ? \get_class($content) : \gettype($content)));
  35. }
  36. public function length(): ?int
  37. {
  38. return fstat($this->content)['size'] ?? null;
  39. }
  40. public function stringify(): string
  41. {
  42. if (-1 === fseek($this->content, 0)) {
  43. throw new InvalidArgument('Unable to seek the content.');
  44. }
  45. return stream_get_contents($this->content);
  46. }
  47. public function getIterator(): \Traversable
  48. {
  49. if (-1 === fseek($this->content, 0)) {
  50. throw new InvalidArgument('Unable to seek the content.');
  51. }
  52. while (!feof($this->content)) {
  53. yield fread($this->content, $this->chunkSize);
  54. }
  55. }
  56. /**
  57. * @return resource
  58. */
  59. public function getResource()
  60. {
  61. return $this->content;
  62. }
  63. public function hash(string $algo = 'sha256', bool $raw = false): string
  64. {
  65. $pos = ftell($this->content);
  66. if ($pos > 0 && -1 === fseek($this->content, 0)) {
  67. throw new InvalidArgument('Unable to seek the content.');
  68. }
  69. $ctx = hash_init($algo);
  70. hash_update_stream($ctx, $this->content);
  71. $out = hash_final($ctx, $raw);
  72. if (-1 === fseek($this->content, $pos)) {
  73. throw new InvalidArgument('Unable to seek the content.');
  74. }
  75. return $out;
  76. }
  77. }