Overview

Packages

  • Stream
    • Wrapper

Classes

  • Horde_Stream_Wrapper_Combine
  • Horde_Stream_Wrapper_String

Interfaces

  • Horde_Stream_Wrapper_CombineStream
  • Horde_Stream_Wrapper_StringStream
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * A stream wrapper that will combine multiple strings/streams into a single
  4:  * stream.
  5:  *
  6:  * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * @author   Michael Slusarz <slusarz@horde.org>
  9:  * @license  http://www.horde.org/licenses/bsd BSD
 10:  * @category Horde
 11:  * @package  Stream_Wrapper
 12:  */
 13: 
 14: /**
 15:  * @author   Michael Slusarz <slusarz@horde.org>
 16:  * @license  http://www.horde.org/licenses/bsd BSD
 17:  * @category Horde
 18:  * @package  Stream_Wrapper
 19:  */
 20: class Horde_Stream_Wrapper_Combine
 21: {
 22:     /**
 23:      * Context.
 24:      *
 25:      * @var resource
 26:      */
 27:     public $context;
 28: 
 29:     /**
 30:      * Array that holds the various streams.
 31:      *
 32:      * @var array
 33:      */
 34:     protected $_data = array();
 35: 
 36:     /**
 37:      * The combined length of the stream.
 38:      *
 39:      * @var integer
 40:      */
 41:     protected $_length = 0;
 42: 
 43:     /**
 44:      * The current position in the string.
 45:      *
 46:      * @var integer
 47:      */
 48:     protected $_position = 0;
 49: 
 50:     /**
 51:      * The current position in the data array.
 52:      *
 53:      * @var integer
 54:      */
 55:     protected $_datapos = 0;
 56: 
 57:     /**
 58:      * Have we reached EOF?
 59:      *
 60:      * @var boolean
 61:      */
 62:     protected $_ateof = false;
 63: 
 64:     /**
 65:      * @see streamWrapper::stream_open()
 66:      *
 67:      * @param string $path
 68:      * @param string $mode
 69:      * @param integer $options
 70:      * @param string &$opened_path
 71:      *
 72:      * @throws Exception
 73:      */
 74:     public function stream_open($path, $mode, $options, &$opened_path)
 75:     {
 76:         $opts = stream_context_get_options($this->context);
 77:         if (empty($opts['horde-combine']['data']) ||
 78:             !($opts['horde-combine']['data'] instanceof Horde_Stream_Wrapper_CombineStream)) {
 79:             throw new Exception('A combined stream must be created using the Horde_Stream_Wrapper_CombineStream interface.');
 80:         }
 81: 
 82:         $data = $opts['horde-combine']['data']->getData();
 83: 
 84:         reset($data);
 85:         while (list(,$val) = each($data)) {
 86:             if (is_string($val)) {
 87:                 $fp = fopen('php://temp', 'r+');
 88:                 fwrite($fp, $val);
 89:             } else {
 90:                 $fp = $val;
 91:             }
 92: 
 93:             fseek($fp, 0, SEEK_END);
 94:             $length = ftell($fp);
 95:             rewind($fp);
 96: 
 97:             $this->_data[] = array(
 98:                 'fp' => $fp,
 99:                 'l' => $length,
100:                 'p' => 0
101:             );
102: 
103:             $this->_length += $length;
104:         }
105: 
106:         return true;
107:     }
108: 
109:     /**
110:      * @see streamWrapper::stream_read()
111:      *
112:      * @param integer $count
113:      *
114:      * @return mixed
115:      */
116:     public function stream_read($count)
117:     {
118:         if ($this->stream_eof()) {
119:             return false;
120:         }
121: 
122:         $out = '';
123: 
124:         while ($count) {
125:             $tmp = &$this->_data[$this->_datapos];
126:             $curr_read = min($count, $tmp['l'] - $tmp['p']);
127:             $out .= fread($tmp['fp'], $curr_read);
128:             $count -= $curr_read;
129:             $this->_position += $curr_read;
130: 
131:             if ($this->_position == $this->_length) {
132:                 if ($count) {
133:                     $this->_ateof = true;
134:                     break;
135:                 } else {
136:                     $tmp['p'] += $curr_read;
137:                 }
138:             } elseif ($count) {
139:                 $tmp = &$this->_data[++$this->_datapos];
140:                 rewind($tmp['fp']);
141:                 $tmp['p'] = 0;
142:             } else {
143:                 $tmp['p'] += $curr_read;
144:             }
145:         }
146: 
147:         return $out;
148:     }
149: 
150:     /**
151:      * @see streamWrapper::stream_write()
152:      *
153:      * @param string $data
154:      *
155:      * @return integer
156:      */
157:     public function stream_write($data)
158:     {
159:         $tmp = &$this->_data[$this->_datapos];
160: 
161:         $oldlen = $tmp['l'];
162:         $res = fwrite($tmp['fp'], $data);
163:         if ($res === false) {
164:             return false;
165:         }
166: 
167:         $tmp['p'] = ftell($tmp['fp']);
168:         if ($tmp['p'] > $oldlen) {
169:             $tmp['l'] = $tmp['p'];
170:             $this->_length += ($tmp['l'] - $oldlen);
171:         }
172: 
173:         return $res;
174:     }
175: 
176:     /**
177:      * @see streamWrapper::stream_tell()
178:      *
179:      * @return integer
180:      */
181:     public function stream_tell()
182:     {
183:         return $this->_position;
184:     }
185: 
186:     /**
187:      * @see streamWrapper::stream_eof()
188:      *
189:      * @return boolean
190:      */
191:     public function stream_eof()
192:     {
193:         return $this->_ateof;
194:     }
195: 
196:     /**
197:      * @see streamWrapper::stream_stat()
198:      *
199:      * @return array
200:      */
201:     public function stream_stat()
202:     {
203:         return array(
204:             'dev' => 0,
205:             'ino' => 0,
206:             'mode' => 0,
207:             'nlink' => 0,
208:             'uid' => 0,
209:             'gid' => 0,
210:             'rdev' => 0,
211:             'size' => $this->_length,
212:             'atime' => 0,
213:             'mtime' => 0,
214:             'ctime' => 0,
215:             'blksize' => 0,
216:             'blocks' => 0
217:         );
218:     }
219: 
220:     /**
221:      * @see streamWrapper::stream_seek()
222:      *
223:      * @param integer $offset
224:      * @param integer $whence  SEEK_SET, SEEK_CUR, or SEEK_END
225:      *
226:      * @return boolean
227:      */
228:     public function stream_seek($offset, $whence)
229:     {
230:         $oldpos = $this->_position;
231:         $this->_ateof = false;
232: 
233:         switch ($whence) {
234:         case SEEK_SET:
235:             $offset = $offset;
236:             break;
237: 
238:         case SEEK_CUR:
239:             $offset = $this->_position + $offset;
240:             break;
241: 
242:         case SEEK_END:
243:             $offset = $this->_length + $offset;
244:             break;
245: 
246:         default:
247:             return false;
248:         }
249: 
250:         $count = $this->_position = min($this->_length, $offset);
251: 
252:         foreach ($this->_data as $key => $val) {
253:             if ($count < $val['l']) {
254:                 $this->_datapos = $key;
255:                 $val['p'] = $count;
256:                 fseek($val['fp'], $count, SEEK_SET);
257:                 break;
258:             }
259:             $count -= $val['l'];
260:         }
261: 
262:         return ($oldpos != $this->_position);
263:     }
264: 
265: }
266: 
API documentation generated by ApiGen