/lib/horde/framework/Horde/Stream/Wrapper/Combine.php
https://github.com/markn86/moodle · PHP · 315 lines · 162 code · 38 blank · 115 comment · 19 complexity · 819f32e45d5813a919c4d63b055e45ea MD5 · raw file
- <?php
- /**
- * Copyright 2009-2017 Horde LLC (http://www.horde.org/)
- *
- * See the enclosed file LICENSE for license information (BSD). If you
- * did not receive this file, see http://www.horde.org/licenses/bsd.
- *
- * @category Horde
- * @copyright 2009-2017 Horde LLC
- * @license http://www.horde.org/licenses/bsd BSD
- * @package Stream_Wrapper
- */
- /**
- * A stream wrapper that will combine multiple strings/streams into a single
- * stream.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @copyright 2009-2017 Horde LLC
- * @license http://www.horde.org/licenses/bsd BSD
- * @package Stream_Wrapper
- */
- class Horde_Stream_Wrapper_Combine
- {
- /**/
- const WRAPPER_NAME = '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;
- /**
- * Unique ID tracker for the streams.
- *
- * @var integer
- */
- private static $_id = 0;
- /**
- * Create a stream from multiple data sources.
- *
- * @since 2.1.0
- *
- * @param array $data An array of strings and/or streams to combine into
- * a single stream.
- *
- * @return resource A PHP stream.
- */
- public static function getStream($data)
- {
- if (!self::$_id) {
- stream_wrapper_register(self::WRAPPER_NAME, __CLASS__);
- }
- return fopen(
- self::WRAPPER_NAME . '://' . ++self::$_id,
- 'wb',
- false,
- stream_context_create(array(
- self::WRAPPER_NAME => array(
- 'data' => $data
- )
- ))
- );
- }
- /**
- * @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 (isset($opts[self::WRAPPER_NAME]['data'])) {
- $data = $opts[self::WRAPPER_NAME]['data'];
- } elseif (isset($opts['horde-combine']['data'])) {
- // @deprecated
- $data = $opts['horde-combine']['data']->getData();
- } else {
- throw new Exception('Use ' . __CLASS__ . '::getStream() to initialize the stream.');
- }
- foreach ($data as $val) {
- 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 = '';
- $tmp = &$this->_data[$this->_datapos];
- while ($count) {
- if (!is_resource($tmp['fp'])) {
- return false;
- }
- $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;
- }
- } elseif ($count) {
- if (!isset($this->_data[++$this->_datapos])) {
- return false;
- }
- $tmp = &$this->_data[$this->_datapos];
- rewind($tmp['fp']);
- $tmp['p'] = 0;
- } else {
- $tmp['p'] += $curr_read;
- }
- }
- 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_stat()
- *
- * @return array
- */
- public function stream_stat()
- {
- return array(
- 'dev' => 0,
- 'ino' => 0,
- 'mode' => 0,
- 'nlink' => 0,
- 'uid' => 0,
- 'gid' => 0,
- 'rdev' => 0,
- 'size' => $this->_length,
- 'atime' => 0,
- 'mtime' => 0,
- 'ctime' => 0,
- 'blksize' => 0,
- 'blocks' => 0
- );
- }
- /**
- * @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);
- }
- }