From: Michael M Slusarz Date: Sat, 24 Oct 2009 23:56:44 +0000 (-0600) Subject: Add Horde_Stream_Wrapper_Combine:: X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=5d899576b1003200d6d6d80cda26a188ed4643ce;p=horde.git Add Horde_Stream_Wrapper_Combine:: --- diff --git a/framework/Stream_Wrapper/lib/Horde/Stream/Wrapper/Combine.php b/framework/Stream_Wrapper/lib/Horde/Stream/Wrapper/Combine.php new file mode 100644 index 000000000..68553b579 --- /dev/null +++ b/framework/Stream_Wrapper/lib/Horde/Stream/Wrapper/Combine.php @@ -0,0 +1,239 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Stream_Wrapper + */ + +/** + * @author Michael Slusarz + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Stream_Wrapper + */ +class Horde_Stream_Wrapper_Combine +{ + /** + * Context. + * + * @var resource + */ + public $context; + + /** + * Array that holds the various streams. + * + * @var array + */ + protected $_data = array(); + + /** + * The combined length of the stream. + * + * @var integer + */ + protected $_length = 0; + + /** + * The current position in the string. + * + * @var integer + */ + protected $_position = 0; + + /** + * The current position in the data array. + * + * @var integer + */ + protected $_datapos = 0; + + /** + * Have we reached EOF? + * + * @var boolean + */ + protected $_ateof = false; + + /** + * @see streamWrapper::stream_open() + * + * @param string $path + * @param string $mode + * @param integer $options + * @param string &$opened_path + * + * @throws Exception + */ + public function stream_open($path, $mode, $options, &$opened_path) + { + $opts = stream_context_get_options($this->context); + if (empty($opts['horde-combine']['data']) || + !($opts['horde-combine']['data'] instanceof Horde_Support_CombineStream)) { + throw new Exception('A combined stream must be created using the Horde_Support_CombineStream class.'); + } + + $data = &$opts['horde-combine']['data']->getData(); + + reset($data); + while (list(,$val) = each($data)) { + if (is_string($val)) { + $fp = fopen('php://temp', 'r+'); + fwrite($fp, $val); + } else { + $fp = $val; + } + + fseek($fp, 0, SEEK_END); + $length = ftell($fp); + rewind($fp); + + $this->_data[] = array( + 'fp' => $fp, + 'l' => $length, + 'p' => 0 + ); + + $this->_length += $length; + } + + return true; + } + + /** + * @see streamWrapper::stream_read() + * + * @param integer $count + * + * @return mixed + */ + public function stream_read($count) + { + if ($this->stream_eof()) { + return false; + } + + $out = ''; + + while ($count) { + $tmp = &$this->_data[$this->_datapos]; + $curr_read = min($count, $tmp['l'] - $tmp['p']); + $out .= fread($tmp['fp'], $curr_read); + $count -= $curr_read; + $this->_position += $curr_read; + + if ($this->_position == $this->_length) { + if ($count) { + $this->_ateof = true; + break; + } else { + $tmp['p'] += $curr_read; + } + } else { + $tmp = &$this->_data[++$this->_datapos]; + rewind($tmp['fp']); + $tmp['p'] = 0; + } + } + + return $out; + } + + /** + * @see streamWrapper::stream_write() + * + * @param string $data + * + * @return integer + */ + public function stream_write($data) + { + $tmp = &$this->_data[$this->_datapos]; + + $oldlen = $tmp['l']; + $res = fwrite($tmp['fp'], $data); + if ($res === false) { + return false; + } + + $tmp['p'] = ftell($tmp['fp']); + if ($tmp['p'] > $oldlen) { + $tmp['l'] = $tmp['p']; + $this->_length += ($tmp['l'] - $oldlen); + } + + return $res; + } + + /** + * @see streamWrapper::stream_tell() + * + * @return integer + */ + public function stream_tell() + { + return $this->_position; + } + + /** + * @see streamWrapper::stream_eof() + * + * @return boolean + */ + public function stream_eof() + { + return $this->_ateof; + } + + /** + * @see streamWrapper::stream_seek() + * + * @param integer $offset + * @param integer $whence SEEK_SET, SEEK_CUR, or SEEK_END + * + * @return boolean + */ + public function stream_seek($offset, $whence) + { + $oldpos = $this->_position; + $this->_ateof = false; + + switch ($whence) { + case SEEK_SET: + $offset = $offset; + break; + + case SEEK_CUR: + $offset = $this->_position + $offset; + break; + + case SEEK_END: + $offset = $this->_length + $offset; + break; + + default: + return false; + } + + $count = $this->_position = min($this->_length, $offset); + + foreach ($this->_data as $key => $val) { + if ($count < $val['l']) { + $this->_datapos = $key; + $val['p'] = $count; + fseek($val['fp'], $count, SEEK_SET); + break; + } + $count -= $val['l']; + } + + return ($oldpos != $this->_position); + } + +} diff --git a/framework/Stream_Wrapper/package.xml b/framework/Stream_Wrapper/package.xml index a97b9329a..287e84421 100644 --- a/framework/Stream_Wrapper/package.xml +++ b/framework/Stream_Wrapper/package.xml @@ -36,7 +36,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> beta LGPL - * Initial release. + * Add Combine wrapper. + * Initial release. @@ -44,6 +45,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + @@ -68,6 +70,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + diff --git a/framework/Support/lib/Horde/Support/CombineStream.php b/framework/Support/lib/Horde/Support/CombineStream.php new file mode 100644 index 000000000..ebf429724 --- /dev/null +++ b/framework/Support/lib/Horde/Support/CombineStream.php @@ -0,0 +1,86 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Support + */ + +/** + * @author Michael Slusarz + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Support + */ +class Horde_Support_CombineStream +{ + /** + * Data. + * + * @var array + */ + protected $_data; + + /** + * Constructor + * + * @param array $data An array of strings and/or streams to combine into + * a single stream. + */ + public function __construct($data) + { + $this->installWrapper(); + $this->_data = $data; + } + + /** + * Return a stream handle to this stream. + * + * @return resource + */ + public function fopen() + { + $context = stream_context_create(array('horde-combine' => array('data' => $this))); + return fopen('horde-combine://' . spl_object_hash($this), 'rb', false, $context); + } + + /** + * Return an SplFileObject representing this stream + * + * @return SplFileObject + */ + public function getFileObject() + { + $context = stream_context_create(array('horde-combine' => array('data' => $this))); + return new SplFileObject('horde-combine://' . spl_object_hash($this), 'rb', false, $context); + } + + /** + * Install the horde-combine stream wrapper if it isn't already + * registered. + * + * @throws Exception + */ + public function installWrapper() + { + if (!in_array('horde-combine', stream_get_wrappers()) && + !stream_wrapper_register('horde-combine', 'Horde_Stream_Wrapper_Combine')) { + throw new Exception('Unable to register horde-combine stream wrapper.'); + } + } + + /** + * Return a reference to the data. + * + * @return array + */ + public function getData() + { + return $this->_data; + } + +} diff --git a/framework/Support/package.xml b/framework/Support/package.xml index 06a6f33ca..e6f8270d7 100644 --- a/framework/Support/package.xml +++ b/framework/Support/package.xml @@ -25,6 +25,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> BSD + * Add Horde_Support_CombineStream::. * Initial horde/support package * Initial Horde_Support_Array object * Initial Horde_Support_Backtrace object @@ -50,6 +51,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + @@ -82,6 +84,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + diff --git a/framework/Support/test/Horde/Support/CombineStreamTest.php b/framework/Support/test/Horde/Support/CombineStreamTest.php new file mode 100644 index 000000000..b102cf598 --- /dev/null +++ b/framework/Support/test/Horde/Support/CombineStreamTest.php @@ -0,0 +1,43 @@ +fopen(); + + $this->assertEquals('ABCDE12345fghij', fread($stream, 1024)); + $this->assertEquals(true, feof($stream)); + $this->assertEquals(0, fseek($stream, 0)); + $this->assertEquals(-1, fseek($stream, 0)); + $this->assertEquals(0, ftell($stream)); + $this->assertEquals(0, fseek($stream, 5, SEEK_CUR)); + $this->assertEquals(5, ftell($stream)); + $this->assertEquals(10, fwrite($stream, '0000000000')); + $this->assertEquals(0, fseek($stream, 0, SEEK_END)); + $this->assertEquals(20, ftell($stream)); + $this->assertEquals(false, feof($stream)); + + fclose($stream); + } +}