forked from fzaninotto/Streamer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8c34922
Showing
14 changed files
with
821 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
composer.phar | ||
composer.lock | ||
vendor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Copyright (c) 2012 Francois Zaninotto | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is furnished | ||
to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Streamer | ||
|
||
Streamer is an Object-Oriented API for PHP streams. | ||
|
||
## Why should I use Streams? | ||
|
||
A stream is a flow of bytes from one container to the other. You already use streams a lot in PHP, for instance each time you load a file into memory (`file_get_contents()`). You should explicitly use streams each time that: | ||
|
||
* You need to access data from a container, but you don't know the size of this container (e.g. reading from STDIN, or a web service using streaming) | ||
* You need to start processing data from a container before the whole transfer is finished (e.g. start zipping a file before it's all in memory) | ||
* You need to save time and memory | ||
|
||
## What is Streamer? | ||
|
||
PHP has a very elaborate stream API ; unfortunately, it uses functions for most stream operations (except for wrappers - go figure). Streamer is a generic library focusing on offering an object-oriented API to streams, and only that. | ||
|
||
## Example | ||
|
||
```php | ||
use Streamer/Stream; | ||
|
||
// basic usage | ||
$stream = new Stream(fopen('smiley.png', 'r')); | ||
$image = ''; | ||
while (!$stream->isAtEnd()) { | ||
$image .= $stream->read(); | ||
} | ||
|
||
// pipe dreams! | ||
$stream1 = new Stream(fopen('smiley.png', 'r')); | ||
$stream2 = new Stream(fopen('tmp.png', 'w')); | ||
// copy the contents from the first stream to the second one | ||
$stream1->pipe($stream2); | ||
``` | ||
|
||
### Credits | ||
|
||
Streamer is heavily inspired by other Stream class implementations: | ||
|
||
* [Guzzle](https://github.com/guzzle/guzzle/blob/master/src/Guzzle/Common/Stream.php) | ||
* [Joomla's Filesystem Stream](http://api.joomla.org/__filesource/fsource_Joomla-Platform_FileSystem--_librariesjoomlafilesystemstream.php.html) | ||
* [Node.Js Stream API](http://nodejs.org/api/stream.html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Streamer\Exception; | ||
|
||
interface ExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Streamer\Exception; | ||
|
||
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Streamer\Exception; | ||
|
||
class LogicException extends \LogicException implements ExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Streamer\Exception; | ||
|
||
class RuntimeException extends \RuntimeException implements ExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
namespace Streamer; | ||
|
||
class FileStream extends Stream | ||
{ | ||
public static function create($filename, $mode, $use_include_path = false, $context = null) | ||
{ | ||
return new static(fopen($filename, $mode, $use_include_path, $context)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
namespace Streamer; | ||
|
||
class NetworkStream extends Stream | ||
{ | ||
public static function create($address, $timeout = null, $flags = null, $context = null) | ||
{ | ||
return new static(stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context)); | ||
} | ||
|
||
public function getName($remote = true) | ||
{ | ||
return stream_socket_get_name($this->stream, $remote); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
<?php | ||
|
||
namespace Streamer; | ||
|
||
use Streamer\Exception\InvalidArgumentException; | ||
use Streamer\Exception\LogicException; | ||
use Streamer\Exception\RuntimeException; | ||
|
||
class Stream | ||
{ | ||
protected $bufferSize = 4096; | ||
protected $stream; | ||
protected $isOpen; | ||
|
||
protected static $readableModes = array( | ||
'r', 'r+', 'w+', 'a+', 'x+', 'c+', 'rb', 'r+b', 'w+b', 'a+b', 'x+b', 'c+b', 'rt', 'r+t', 'w+t', 'a+t', 'x+t', 'c+t' | ||
); | ||
protected static $writableModes = array( | ||
'r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+', 'r+b', 'wb', 'w+b', 'ab', 'a+b', 'xb', 'x+b', 'cb', 'c+b', 'r+t', 'wt', 'w+t', 'at', 'a+t', 'xt', 'x+t', 'ct', 'c+t' | ||
); | ||
|
||
public function __construct($stream) | ||
{ | ||
if (!is_resource($stream)) { | ||
throw new InvalidArgumentException('A Stream object requires a stream resource as constructor argument'); | ||
} | ||
$this->stream = $stream; | ||
$this->isOpen = true; | ||
} | ||
|
||
public function getResource() | ||
{ | ||
return $this->stream; | ||
} | ||
|
||
public function getMetadata() | ||
{ | ||
return stream_get_meta_data($this->stream); | ||
} | ||
|
||
public function getMetadataForKey($key) | ||
{ | ||
$metadata = $this->getMetadata(); | ||
if (isset($metadata[$key])) { | ||
return $metadata[$key]; | ||
} | ||
} | ||
|
||
public function getUri() | ||
{ | ||
return $this->getMetadataForKey('uri'); | ||
} | ||
|
||
public function getStreamType() | ||
{ | ||
return $this->getMetadataForKey('stream_type'); | ||
} | ||
|
||
public function getWrapperType() | ||
{ | ||
return $this->getMetadataForKey('wrapper_type'); | ||
} | ||
|
||
public function getWrapperData() | ||
{ | ||
return $this->getMetadataForKey('wrapper_data'); | ||
} | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
public function isLocal() | ||
{ | ||
return stream_is_local($this->stream); | ||
} | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
public function isReadable() | ||
{ | ||
return in_array($this->getMetadataForKey('mode'), self::$readableModes); | ||
} | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
public function isWritable() | ||
{ | ||
return in_array($this->getMetadataForKey('mode'), self::$writableModes); | ||
} | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
public function isSeekable() | ||
{ | ||
return $this->getMetadataForKey('seekable'); | ||
} | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
public function isOpen() | ||
{ | ||
return $this->isOpen; | ||
} | ||
|
||
/** | ||
* @param int $bufferSize in Bytes | ||
*/ | ||
public function setBufferSize($bufferSize) | ||
{ | ||
$this->bufferSize = $bufferSize; | ||
} | ||
|
||
/** | ||
* @return int BufferSize in Bytes | ||
*/ | ||
public function getBufferSize() | ||
{ | ||
return $this->bufferSize; | ||
} | ||
|
||
/** | ||
* Read data from the stream. | ||
* Binary-safe. | ||
* | ||
* @param int $length Maximum number of bytes to read. Defaults to self::$bufferSize. | ||
* | ||
* @return string The data read from the stream | ||
*/ | ||
public function read($length = null) | ||
{ | ||
if (!$this->isOpen) { | ||
throw new LogicException('Cannot read from a closed stream'); | ||
} | ||
if (!$this->isReadable()) { | ||
throw new LogicException(sprintf('Cannot read on a non readable stream (current mode is %s)', $this->getMetadataForKey('mode'))); | ||
} | ||
if (null == $length) { | ||
$length = $this->bufferSize; | ||
} | ||
$ret = fread($this->stream, $length); | ||
if (false === $ret) { | ||
throw new RuntimeException('Cannot read stream'); | ||
} | ||
|
||
return $ret; | ||
} | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
public function isAtEnd() | ||
{ | ||
return feof($this->stream); | ||
} | ||
|
||
/** | ||
* Read the remaining data from the stream until its end. | ||
* Binary-safe. | ||
* | ||
* @return string The data read from the stream | ||
*/ | ||
public function getContent() | ||
{ | ||
$contents = ''; | ||
while (!$this->isAtEnd()) { | ||
$contents .= $this->read(); | ||
} | ||
$this->close(); | ||
|
||
return $contents; | ||
} | ||
|
||
/** | ||
* Write data to the stream. | ||
* Binary-safe. | ||
* | ||
* @param string $string The string that is to be written. | ||
* @param int $length If the length argument is given, writing will stop after length bytes have been written or the end of string is reached, whichever comes first. | ||
* | ||
* @return int Number of bytes written | ||
*/ | ||
public function write($string, $length = null) | ||
{ | ||
if (!$this->isOpen) { | ||
throw new LogicException('Cannot write on a closed stream'); | ||
} | ||
if (!$this->isWritable()) { | ||
throw new LogicException(sprintf('Cannot write on a non-writable stream (current mode is %s)', $this->getMetadataForKey('mode'))); | ||
} | ||
if (null === $length) { | ||
$ret = fwrite($this->stream, $string); | ||
} else { | ||
$ret = fwrite($this->stream, $string, $length); | ||
} | ||
if (false === $ret) { | ||
throw new RuntimeException('Cannot write on stream'); | ||
} | ||
|
||
return $ret; | ||
} | ||
|
||
/** | ||
* Read the content of this stream and write it to another stream, by chunks of $bufferSize | ||
* | ||
* @param Stream $stream The destination stream to write to | ||
* | ||
* @return int Number of piped bytes | ||
*/ | ||
public function pipe(Stream $stream) | ||
{ | ||
$nbWrittenBytes = 0; | ||
while (!$this->isAtEnd()) { | ||
$nbWrittenBytes += $stream->write($this->read()); | ||
} | ||
|
||
return $nbWrittenBytes; | ||
} | ||
|
||
public function rewind() | ||
{ | ||
rewind($this->stream); | ||
} | ||
|
||
public function close() | ||
{ | ||
if (!$this->isOpen) { | ||
throw new LogicException('Stream is already closed'); | ||
} | ||
if ($ret = fclose($this->stream)) { | ||
$this->isOpen = false; | ||
} | ||
|
||
return $ret; | ||
} | ||
|
||
public function __destruct() | ||
{ | ||
if (is_resource($this->stream)) { | ||
fclose($this->stream); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"name": "fzaninotto/Streamer", | ||
"description": "Object-oriented API to PHP streams", | ||
"homepage": "https://github.com/fzaninotto/Streamer", | ||
"version": "0.0.1", | ||
"license": "MIT", | ||
"authors": [ | ||
{ "name": "Francois Zaninotto" } | ||
], | ||
"require": { | ||
"php": ">=5.3.0" | ||
}, | ||
"autoload": { | ||
"psr-0": { "Streamer": "." } | ||
} | ||
} |
Oops, something went wrong.