Skip to content

Commit 2d6ff41

Browse files
committed
initial commit
0 parents  commit 2d6ff41

File tree

7 files changed

+2196
-0
lines changed

7 files changed

+2196
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
.idea/

composer.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "papertower/wp-rest-api-psr7",
3+
"description": "Provides PSR-7 and WP REST API Response and Request classes",
4+
"type": "library",
5+
"license": "MIT",
6+
"require": {
7+
"psr/http-message": "^1.0.1"
8+
},
9+
"repositories": [
10+
{
11+
"type": "git",
12+
"url": "git@github.com:papertower/WP-REST-API-PSR7.git"
13+
}
14+
],
15+
"keywords": [
16+
"wp rest api",
17+
"wordpress",
18+
"psr-7"
19+
],
20+
"authors": [
21+
{
22+
"name": "Jason Adams",
23+
"email": "jason@papertower.com"
24+
}
25+
],
26+
"autoload": {
27+
"psr-4": {
28+
"WPRestApi\\PSR7\\": "src/"
29+
}
30+
}
31+
}

src/BodyStream.php

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
<?php
2+
3+
4+
namespace WPRestApi\PSR7;
5+
6+
use Psr\Http\Message\StreamInterface;
7+
8+
class BodyStream implements StreamInterface
9+
{
10+
private $stream;
11+
private $size;
12+
private $seekable;
13+
private $readable;
14+
private $writable;
15+
private $uri;
16+
private $customMetadata;
17+
18+
/** @var array Hash of readable and writable stream types */
19+
private static $readWriteHash = [
20+
'read' => [
21+
'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
22+
'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
23+
'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
24+
'x+t' => true, 'c+t' => true, 'a+' => true
25+
],
26+
'write' => [
27+
'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
28+
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
29+
'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
30+
'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
31+
]
32+
];
33+
34+
/**
35+
* This constructor accepts an associative array of options.
36+
*
37+
* - size: (int) If a read stream would otherwise have an indeterminate
38+
* size, but the size is known due to foreknowledge, then you can
39+
* provide that size, in bytes.
40+
* - metadata: (array) Any additional metadata to return when the metadata
41+
* of the stream is accessed.
42+
*
43+
* @param resource $stream Stream resource to wrap.
44+
* @param array $options Associative array of options.
45+
*
46+
* @throws \InvalidArgumentException if the stream is not a stream resource
47+
*/
48+
public function __construct($stream, $options = [])
49+
{
50+
if (!is_resource($stream)) {
51+
throw new \InvalidArgumentException('Stream must be a resource');
52+
}
53+
54+
if (isset($options['size'])) {
55+
$this->size = $options['size'];
56+
}
57+
58+
59+
$this->customMetadata = isset($options['metadata'])
60+
? $options['metadata']
61+
: [];
62+
63+
$this->stream = $stream;
64+
$meta = stream_get_meta_data($this->stream);
65+
$this->seekable = $meta['seekable'];
66+
$this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
67+
$this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
68+
$this->uri = $this->getMetadata('uri');
69+
}
70+
71+
public function __get($name)
72+
{
73+
if ($name == 'stream') {
74+
throw new \RuntimeException('The stream is detached');
75+
}
76+
77+
throw new \BadMethodCallException('No value for ' . $name);
78+
}
79+
80+
/**
81+
* Closes the stream when the destructed
82+
*/
83+
public function __destruct()
84+
{
85+
$this->close();
86+
}
87+
88+
public function __toString()
89+
{
90+
try {
91+
$this->seek(0);
92+
return (string) stream_get_contents($this->stream);
93+
} catch (\Exception $e) {
94+
return '';
95+
}
96+
}
97+
98+
public function getContents()
99+
{
100+
$contents = stream_get_contents($this->stream);
101+
102+
if ($contents === false) {
103+
throw new \RuntimeException('Unable to read stream contents');
104+
}
105+
106+
return $contents;
107+
}
108+
109+
public function close()
110+
{
111+
if (isset($this->stream)) {
112+
if (is_resource($this->stream)) {
113+
fclose($this->stream);
114+
}
115+
$this->detach();
116+
}
117+
}
118+
119+
public function detach()
120+
{
121+
if (!isset($this->stream)) {
122+
return null;
123+
}
124+
125+
$result = $this->stream;
126+
unset($this->stream);
127+
$this->size = $this->uri = null;
128+
$this->readable = $this->writable = $this->seekable = false;
129+
130+
return $result;
131+
}
132+
133+
public function getSize()
134+
{
135+
if ($this->size !== null) {
136+
return $this->size;
137+
}
138+
139+
if (!isset($this->stream)) {
140+
return null;
141+
}
142+
143+
// Clear the stat cache if the stream has a URI
144+
if ($this->uri) {
145+
clearstatcache(true, $this->uri);
146+
}
147+
148+
$stats = fstat($this->stream);
149+
if (isset($stats['size'])) {
150+
$this->size = $stats['size'];
151+
return $this->size;
152+
}
153+
154+
return null;
155+
}
156+
157+
public function isReadable()
158+
{
159+
return $this->readable;
160+
}
161+
162+
public function isWritable()
163+
{
164+
return $this->writable;
165+
}
166+
167+
public function isSeekable()
168+
{
169+
return $this->seekable;
170+
}
171+
172+
public function eof()
173+
{
174+
return !$this->stream || feof($this->stream);
175+
}
176+
177+
public function tell()
178+
{
179+
$result = ftell($this->stream);
180+
181+
if ($result === false) {
182+
throw new \RuntimeException('Unable to determine stream position');
183+
}
184+
185+
return $result;
186+
}
187+
188+
public function rewind()
189+
{
190+
$this->seek(0);
191+
}
192+
193+
public function seek($offset, $whence = SEEK_SET)
194+
{
195+
if (!$this->seekable) {
196+
throw new \RuntimeException('Stream is not seekable');
197+
} elseif (fseek($this->stream, $offset, $whence) === -1) {
198+
throw new \RuntimeException('Unable to seek to stream position '
199+
. $offset . ' with whence ' . var_export($whence, true));
200+
}
201+
}
202+
203+
public function read($length)
204+
{
205+
if (!$this->readable) {
206+
throw new \RuntimeException('Cannot read from non-readable stream');
207+
}
208+
if ($length < 0) {
209+
throw new \RuntimeException('Length parameter cannot be negative');
210+
}
211+
212+
if (0 === $length) {
213+
return '';
214+
}
215+
216+
$string = fread($this->stream, $length);
217+
if (false === $string) {
218+
throw new \RuntimeException('Unable to read from stream');
219+
}
220+
221+
return $string;
222+
}
223+
224+
public function write($string)
225+
{
226+
if (!$this->writable) {
227+
throw new \RuntimeException('Cannot write to a non-writable stream');
228+
}
229+
230+
// We can't know the size after writing anything
231+
$this->size = null;
232+
$result = fwrite($this->stream, $string);
233+
234+
if ($result === false) {
235+
throw new \RuntimeException('Unable to write to stream');
236+
}
237+
238+
return $result;
239+
}
240+
241+
public function getMetadata($key = null)
242+
{
243+
if (!isset($this->stream)) {
244+
return $key ? null : [];
245+
} elseif (!$key) {
246+
return $this->customMetadata + stream_get_meta_data($this->stream);
247+
} elseif (isset($this->customMetadata[$key])) {
248+
return $this->customMetadata[$key];
249+
}
250+
251+
$meta = stream_get_meta_data($this->stream);
252+
253+
return isset($meta[$key]) ? $meta[$key] : null;
254+
}
255+
}

0 commit comments

Comments
 (0)