See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 /** 3 * Copyright 2009-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file LICENSE for license information (BSD). If you 6 * did not receive this file, see http://www.horde.org/licenses/bsd. 7 * 8 * @category Horde 9 * @copyright 2009-2017 Horde LLC 10 * @license http://www.horde.org/licenses/bsd BSD 11 * @package Stream_Wrapper 12 */ 13 14 /** 15 * A stream wrapper that will combine multiple strings/streams into a single 16 * stream. 17 * 18 * @author Michael Slusarz <slusarz@horde.org> 19 * @category Horde 20 * @copyright 2009-2017 Horde LLC 21 * @license http://www.horde.org/licenses/bsd BSD 22 * @package Stream_Wrapper 23 */ 24 class Horde_Stream_Wrapper_Combine 25 { 26 /**/ 27 const WRAPPER_NAME = 'horde-stream-wrapper-combine'; 28 29 /** 30 * Context. 31 * 32 * @var resource 33 */ 34 public $context; 35 36 /** 37 * Array that holds the various streams. 38 * 39 * @var array 40 */ 41 protected $_data = array(); 42 43 /** 44 * The combined length of the stream. 45 * 46 * @var integer 47 */ 48 protected $_length = 0; 49 50 /** 51 * The current position in the string. 52 * 53 * @var integer 54 */ 55 protected $_position = 0; 56 57 /** 58 * The current position in the data array. 59 * 60 * @var integer 61 */ 62 protected $_datapos = 0; 63 64 /** 65 * Have we reached EOF? 66 * 67 * @var boolean 68 */ 69 protected $_ateof = false; 70 71 /** 72 * Unique ID tracker for the streams. 73 * 74 * @var integer 75 */ 76 private static $_id = 0; 77 78 /** 79 * Create a stream from multiple data sources. 80 * 81 * @since 2.1.0 82 * 83 * @param array $data An array of strings and/or streams to combine into 84 * a single stream. 85 * 86 * @return resource A PHP stream. 87 */ 88 public static function getStream($data) 89 { 90 if (!self::$_id) { 91 stream_wrapper_register(self::WRAPPER_NAME, __CLASS__); 92 } 93 94 return fopen( 95 self::WRAPPER_NAME . '://' . ++self::$_id, 96 'wb', 97 false, 98 stream_context_create(array( 99 self::WRAPPER_NAME => array( 100 'data' => $data 101 ) 102 )) 103 ); 104 } 105 /** 106 * @see streamWrapper::stream_open() 107 * 108 * @param string $path 109 * @param string $mode 110 * @param integer $options 111 * @param string &$opened_path 112 * 113 * @throws Exception 114 */ 115 public function stream_open($path, $mode, $options, &$opened_path) 116 { 117 $opts = stream_context_get_options($this->context); 118 119 if (isset($opts[self::WRAPPER_NAME]['data'])) { 120 $data = $opts[self::WRAPPER_NAME]['data']; 121 } elseif (isset($opts['horde-combine']['data'])) { 122 // @deprecated 123 $data = $opts['horde-combine']['data']->getData(); 124 } else { 125 throw new Exception('Use ' . __CLASS__ . '::getStream() to initialize the stream.'); 126 } 127 128 foreach ($data as $val) { 129 if (is_string($val)) { 130 $fp = fopen('php://temp', 'r+'); 131 fwrite($fp, $val); 132 } else { 133 $fp = $val; 134 } 135 136 fseek($fp, 0, SEEK_END); 137 $length = ftell($fp); 138 rewind($fp); 139 140 $this->_data[] = array( 141 'fp' => $fp, 142 'l' => $length, 143 'p' => 0 144 ); 145 146 $this->_length += $length; 147 } 148 149 return true; 150 } 151 152 /** 153 * @see streamWrapper::stream_read() 154 * 155 * @param integer $count 156 * 157 * @return mixed 158 */ 159 public function stream_read($count) 160 { 161 if ($this->stream_eof()) { 162 return false; 163 } 164 165 $out = ''; 166 $tmp = &$this->_data[$this->_datapos]; 167 168 while ($count) { 169 if (!is_resource($tmp['fp'])) { 170 return false; 171 } 172 173 $curr_read = min($count, $tmp['l'] - $tmp['p']); 174 if ($curr_read > 0) { 175 $out .= fread($tmp['fp'], $curr_read); 176 $count -= $curr_read; 177 $this->_position += $curr_read; 178 } 179 180 if ($this->_position == $this->_length) { 181 if ($count) { 182 $this->_ateof = true; 183 break; 184 } else { 185 $tmp['p'] += $curr_read; 186 } 187 } elseif ($count) { 188 if (!isset($this->_data[++$this->_datapos])) { 189 return false; 190 } 191 $tmp = &$this->_data[$this->_datapos]; 192 rewind($tmp['fp']); 193 $tmp['p'] = 0; 194 } else { 195 $tmp['p'] += $curr_read; 196 } 197 } 198 199 return $out; 200 } 201 202 /** 203 * @see streamWrapper::stream_write() 204 * 205 * @param string $data 206 * 207 * @return integer 208 */ 209 public function stream_write($data) 210 { 211 $tmp = &$this->_data[$this->_datapos]; 212 213 $oldlen = $tmp['l']; 214 $res = fwrite($tmp['fp'], $data); 215 if ($res === false) { 216 return false; 217 } 218 219 $tmp['p'] = ftell($tmp['fp']); 220 if ($tmp['p'] > $oldlen) { 221 $tmp['l'] = $tmp['p']; 222 $this->_length += ($tmp['l'] - $oldlen); 223 } 224 225 return $res; 226 } 227 228 /** 229 * @see streamWrapper::stream_tell() 230 * 231 * @return integer 232 */ 233 public function stream_tell() 234 { 235 return $this->_position; 236 } 237 238 /** 239 * @see streamWrapper::stream_eof() 240 * 241 * @return boolean 242 */ 243 public function stream_eof() 244 { 245 return $this->_ateof; 246 } 247 248 /** 249 * @see streamWrapper::stream_stat() 250 * 251 * @return array 252 */ 253 public function stream_stat() 254 { 255 return array( 256 'dev' => 0, 257 'ino' => 0, 258 'mode' => 0, 259 'nlink' => 0, 260 'uid' => 0, 261 'gid' => 0, 262 'rdev' => 0, 263 'size' => $this->_length, 264 'atime' => 0, 265 'mtime' => 0, 266 'ctime' => 0, 267 'blksize' => 0, 268 'blocks' => 0 269 ); 270 } 271 272 /** 273 * @see streamWrapper::stream_seek() 274 * 275 * @param integer $offset 276 * @param integer $whence SEEK_SET, SEEK_CUR, or SEEK_END 277 * 278 * @return boolean 279 */ 280 public function stream_seek($offset, $whence) 281 { 282 $oldpos = $this->_position; 283 $this->_ateof = false; 284 285 switch ($whence) { 286 case SEEK_SET: 287 $offset = $offset; 288 break; 289 290 case SEEK_CUR: 291 $offset = $this->_position + $offset; 292 break; 293 294 case SEEK_END: 295 $offset = $this->_length + $offset; 296 break; 297 298 default: 299 return false; 300 } 301 302 $count = $this->_position = min($this->_length, $offset); 303 304 foreach ($this->_data as $key => $val) { 305 if ($count < $val['l']) { 306 $this->_datapos = $key; 307 $val['p'] = $count; 308 fseek($val['fp'], $count, SEEK_SET); 309 break; 310 } 311 $count -= $val['l']; 312 } 313 314 return ($oldpos != $this->_position); 315 } 316 317 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body