Skip to content

Commit 604ca0b

Browse files
committed
Initial commit
0 parents  commit 604ca0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+5272
-0
lines changed

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
phpunit.xml
2+
composer.phar
3+
composer.lock
4+
composer-test.lock
5+
vendor/
6+
build/artifacts/
7+
artifacts/
8+
docs/_build
9+
docs/*.pyc
10+
.idea
11+
.DS_STORE

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# CHANGELOG
2+
3+
## 0.1.0 - TBD
4+
5+
Initial release

LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling <[email protected]>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
all: clean test
2+
3+
test:
4+
vendor/bin/phpunit
5+
6+
coverage:
7+
vendor/bin/phpunit --coverage-html=artifacts/coverage
8+
9+
view-coverage:
10+
open artifacts/coverage/index.html
11+
12+
clean:
13+
rm -rf artifacts/*

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# PSR-7 Message Implementation
2+
3+
This repository contains PSR-7 messages implementations, several stream
4+
decorators, and some helpful functionality like query string parsing.

composer.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "guzzlehttp/psr7",
3+
"type": "library",
4+
"description": "PSR-7 message implementation",
5+
"keywords": ["message", "stream", "http", "uri"],
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Michael Dowling",
10+
"email": "[email protected]",
11+
"homepage": "https://github.com/mtdowling"
12+
}
13+
],
14+
"require": {
15+
"php": ">=5.4.0"
16+
},
17+
"require-dev": {
18+
"phpunit/phpunit": "~4.0",
19+
"psr/http-message": "^0.9"
20+
},
21+
"autoload": {
22+
"psr-4": {
23+
"GuzzleHttp\\Psr7\\": "src/"
24+
}
25+
}
26+
}

phpunit.xml.dist

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit bootstrap="./vendor/autoload.php"
3+
colors="true">
4+
<testsuites>
5+
<testsuite>
6+
<directory>tests</directory>
7+
</testsuite>
8+
</testsuites>
9+
<filter>
10+
<whitelist>
11+
<directory suffix=".php">src</directory>
12+
<exclude>
13+
<directory suffix="Interface.php">src/</directory>
14+
</exclude>
15+
</whitelist>
16+
</filter>
17+
</phpunit>

src/AppendStream.php

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
<?php
2+
namespace GuzzleHttp\Psr7;
3+
4+
use Psr\Http\Message\StreamableInterface;
5+
6+
/**
7+
* Reads from multiple streams, one after the other.
8+
*
9+
* This is a read-only stream decorator.
10+
*/
11+
class AppendStream implements StreamableInterface
12+
{
13+
/** @var StreamableInterface[] Streams being decorated */
14+
private $streams = [];
15+
16+
private $seekable = true;
17+
private $current = 0;
18+
private $pos = 0;
19+
private $detached = false;
20+
21+
/**
22+
* @param StreamableInterface[] $streams Streams to decorate. Each stream must
23+
* be readable.
24+
*/
25+
public function __construct(array $streams = [])
26+
{
27+
foreach ($streams as $stream) {
28+
$this->addStream($stream);
29+
}
30+
}
31+
32+
public function __toString()
33+
{
34+
try {
35+
$this->seek(0);
36+
return $this->getContents();
37+
} catch (\Exception $e) {
38+
return '';
39+
}
40+
}
41+
42+
/**
43+
* Add a stream to the AppendStream
44+
*
45+
* @param StreamableInterface $stream Stream to append. Must be readable.
46+
*
47+
* @throws \InvalidArgumentException if the stream is not readable
48+
*/
49+
public function addStream(StreamableInterface $stream)
50+
{
51+
if (!$stream->isReadable()) {
52+
throw new \InvalidArgumentException('Each stream must be readable');
53+
}
54+
55+
// The stream is only seekable if all streams are seekable
56+
if (!$stream->isSeekable()) {
57+
$this->seekable = false;
58+
}
59+
60+
$this->streams[] = $stream;
61+
}
62+
63+
public function getContents()
64+
{
65+
return Utils::copyToString($this);
66+
}
67+
68+
/**
69+
* Closes each attached stream.
70+
*
71+
* {@inheritdoc}
72+
*/
73+
public function close()
74+
{
75+
$this->pos = $this->current = 0;
76+
77+
foreach ($this->streams as $stream) {
78+
$stream->close();
79+
}
80+
81+
$this->streams = [];
82+
}
83+
84+
/**
85+
* Detaches each attached stream
86+
*
87+
* {@inheritdoc}
88+
*/
89+
public function detach()
90+
{
91+
$this->close();
92+
$this->detached = true;
93+
}
94+
95+
public function tell()
96+
{
97+
return $this->pos;
98+
}
99+
100+
/**
101+
* Tries to calculate the size by adding the size of each stream.
102+
*
103+
* If any of the streams do not return a valid number, then the size of the
104+
* append stream cannot be determined and null is returned.
105+
*
106+
* {@inheritdoc}
107+
*/
108+
public function getSize()
109+
{
110+
$size = 0;
111+
112+
foreach ($this->streams as $stream) {
113+
$s = $stream->getSize();
114+
if ($s === null) {
115+
return null;
116+
}
117+
$size += $s;
118+
}
119+
120+
return $size;
121+
}
122+
123+
public function eof()
124+
{
125+
return !$this->streams ||
126+
($this->current >= count($this->streams) - 1 &&
127+
$this->streams[$this->current]->eof());
128+
}
129+
130+
public function rewind()
131+
{
132+
return $this->seek(0);
133+
}
134+
135+
/**
136+
* Attempts to seek to the given position. Only supports SEEK_SET.
137+
*
138+
* {@inheritdoc}
139+
*/
140+
public function seek($offset, $whence = SEEK_SET)
141+
{
142+
if (!$this->seekable || $whence !== SEEK_SET) {
143+
return false;
144+
}
145+
146+
$success = true;
147+
$this->pos = $this->current = 0;
148+
149+
// Rewind each stream
150+
foreach ($this->streams as $stream) {
151+
if (!$stream->seek(0)) {
152+
$success = false;
153+
}
154+
}
155+
156+
if (!$success) {
157+
return false;
158+
}
159+
160+
// Seek to the actual position by reading from each stream
161+
while ($this->pos < $offset && !$this->eof()) {
162+
$this->read(min(8096, $offset - $this->pos));
163+
}
164+
165+
return $this->pos == $offset;
166+
}
167+
168+
/**
169+
* Reads from all of the appended streams until the length is met or EOF.
170+
*
171+
* {@inheritdoc}
172+
*/
173+
public function read($length)
174+
{
175+
$buffer = '';
176+
$total = count($this->streams) - 1;
177+
$remaining = $length;
178+
179+
while ($remaining > 0) {
180+
// Progress to the next stream if needed.
181+
if ($this->streams[$this->current]->eof()) {
182+
if ($this->current == $total) {
183+
break;
184+
}
185+
$this->current++;
186+
}
187+
$buffer .= $this->streams[$this->current]->read($remaining);
188+
$remaining = $length - strlen($buffer);
189+
}
190+
191+
$this->pos += strlen($buffer);
192+
193+
return $buffer;
194+
}
195+
196+
public function isReadable()
197+
{
198+
return true;
199+
}
200+
201+
public function isWritable()
202+
{
203+
return false;
204+
}
205+
206+
public function isSeekable()
207+
{
208+
return $this->seekable;
209+
}
210+
211+
public function write($string)
212+
{
213+
return false;
214+
}
215+
216+
public function getMetadata($key = null)
217+
{
218+
return $key ? null : [];
219+
}
220+
}

0 commit comments

Comments
 (0)