friendship ended with social-app. php is my new best friend
1<?php
2
3namespace React\Http\Io;
4
5use Psr\Http\Message\StreamInterface;
6
7/**
8 * [Internal] PSR-7 message body implementation using an in-memory buffer
9 *
10 * @internal
11 */
12class BufferedBody implements StreamInterface
13{
14 private $buffer = '';
15 private $position = 0;
16 private $closed = false;
17
18 /**
19 * @param string $buffer
20 */
21 public function __construct($buffer)
22 {
23 $this->buffer = $buffer;
24 }
25
26 public function __toString()
27 {
28 if ($this->closed) {
29 return '';
30 }
31
32 $this->seek(0);
33
34 return $this->getContents();
35 }
36
37 public function close()
38 {
39 $this->buffer = '';
40 $this->position = 0;
41 $this->closed = true;
42 }
43
44 public function detach()
45 {
46 $this->close();
47
48 return null;
49 }
50
51 public function getSize()
52 {
53 return $this->closed ? null : \strlen($this->buffer);
54 }
55
56 public function tell()
57 {
58 if ($this->closed) {
59 throw new \RuntimeException('Unable to tell position of closed stream');
60 }
61
62 return $this->position;
63 }
64
65 public function eof()
66 {
67 return $this->position >= \strlen($this->buffer);
68 }
69
70 public function isSeekable()
71 {
72 return !$this->closed;
73 }
74
75 public function seek($offset, $whence = \SEEK_SET)
76 {
77 if ($this->closed) {
78 throw new \RuntimeException('Unable to seek on closed stream');
79 }
80
81 $old = $this->position;
82
83 if ($whence === \SEEK_SET) {
84 $this->position = $offset;
85 } elseif ($whence === \SEEK_CUR) {
86 $this->position += $offset;
87 } elseif ($whence === \SEEK_END) {
88 $this->position = \strlen($this->buffer) + $offset;
89 } else {
90 throw new \InvalidArgumentException('Invalid seek mode given');
91 }
92
93 if (!\is_int($this->position) || $this->position < 0) {
94 $this->position = $old;
95 throw new \RuntimeException('Unable to seek to position');
96 }
97 }
98
99 public function rewind()
100 {
101 $this->seek(0);
102 }
103
104 public function isWritable()
105 {
106 return !$this->closed;
107 }
108
109 public function write($string)
110 {
111 if ($this->closed) {
112 throw new \RuntimeException('Unable to write to closed stream');
113 }
114
115 if ($string === '') {
116 return 0;
117 }
118
119 if ($this->position > 0 && !isset($this->buffer[$this->position - 1])) {
120 $this->buffer = \str_pad($this->buffer, $this->position, "\0");
121 }
122
123 $len = \strlen($string);
124 $this->buffer = \substr($this->buffer, 0, $this->position) . $string . \substr($this->buffer, $this->position + $len);
125 $this->position += $len;
126
127 return $len;
128 }
129
130 public function isReadable()
131 {
132 return !$this->closed;
133 }
134
135 public function read($length)
136 {
137 if ($this->closed) {
138 throw new \RuntimeException('Unable to read from closed stream');
139 }
140
141 if ($length < 1) {
142 throw new \InvalidArgumentException('Invalid read length given');
143 }
144
145 if ($this->position + $length > \strlen($this->buffer)) {
146 $length = \strlen($this->buffer) - $this->position;
147 }
148
149 if (!isset($this->buffer[$this->position])) {
150 return '';
151 }
152
153 $pos = $this->position;
154 $this->position += $length;
155
156 return \substr($this->buffer, $pos, $length);
157 }
158
159 public function getContents()
160 {
161 if ($this->closed) {
162 throw new \RuntimeException('Unable to read from closed stream');
163 }
164
165 if (!isset($this->buffer[$this->position])) {
166 return '';
167 }
168
169 $pos = $this->position;
170 $this->position = \strlen($this->buffer);
171
172 return \substr($this->buffer, $pos);
173 }
174
175 public function getMetadata($key = null)
176 {
177 return $key === null ? array() : null;
178 }
179}