Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace Guzzle\Stream;
4
 
5
use Guzzle\Common\Exception\InvalidArgumentException;
6
 
7
/**
8
 * PHP stream implementation
9
 */
10
class Stream implements StreamInterface
11
{
12
    const STREAM_TYPE = 'stream_type';
13
    const WRAPPER_TYPE = 'wrapper_type';
14
    const IS_LOCAL = 'is_local';
15
    const IS_READABLE = 'is_readable';
16
    const IS_WRITABLE = 'is_writable';
17
    const SEEKABLE = 'seekable';
18
 
19
    /** @var resource Stream resource */
20
    protected $stream;
21
 
22
    /** @var int Size of the stream contents in bytes */
23
    protected $size;
24
 
25
    /** @var array Stream cached data */
26
    protected $cache = array();
27
 
28
    /** @var array Custom stream data */
29
    protected $customData = array();
30
 
31
    /** @var array Hash table of readable and writeable stream types for fast lookups */
32
    protected static $readWriteHash = array(
33
        'read' => array(
34
            'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
35
            'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true,
36
            'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a+' => true
37
        ),
38
        'write' => array(
39
            'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, 'c+' => true,
40
            'wb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true,
41
            'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
42
        )
43
    );
44
 
45
    /**
46
     * @param resource $stream Stream resource to wrap
47
     * @param int      $size   Size of the stream in bytes. Only pass if the size cannot be obtained from the stream.
48
     *
49
     * @throws InvalidArgumentException if the stream is not a stream resource
50
     */
51
    public function __construct($stream, $size = null)
52
    {
53
        $this->setStream($stream, $size);
54
    }
55
 
56
    /**
57
     * Closes the stream when the helper is destructed
58
     */
59
    public function __destruct()
60
    {
61
        $this->close();
62
    }
63
 
64
    public function __toString()
65
    {
66
        if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) {
67
            return '';
68
        }
69
 
70
        $originalPos = $this->ftell();
71
        $body = stream_get_contents($this->stream, -1, 0);
72
        $this->seek($originalPos);
73
 
74
        return $body;
75
    }
76
 
77
    public function close()
78
    {
79
        if (is_resource($this->stream)) {
80
            fclose($this->stream);
81
        }
82
        $this->cache[self::IS_READABLE] = false;
83
        $this->cache[self::IS_WRITABLE] = false;
84
    }
85
 
86
    /**
87
     * Calculate a hash of a Stream
88
     *
89
     * @param StreamInterface $stream    Stream to calculate the hash for
90
     * @param string          $algo      Hash algorithm (e.g. md5, crc32, etc)
91
     * @param bool            $rawOutput Whether or not to use raw output
92
     *
93
     * @return bool|string Returns false on failure or a hash string on success
94
     */
95
    public static function getHash(StreamInterface $stream, $algo, $rawOutput = false)
96
    {
97
        $pos = $stream->ftell();
98
        if (!$stream->seek(0)) {
99
            return false;
100
        }
101
 
102
        $ctx = hash_init($algo);
103
        while (!$stream->feof()) {
104
            hash_update($ctx, $stream->read(8192));
105
        }
106
 
107
        $out = hash_final($ctx, (bool) $rawOutput);
108
        $stream->seek($pos);
109
 
110
        return $out;
111
    }
112
 
113
    public function getMetaData($key = null)
114
    {
115
        $meta = stream_get_meta_data($this->stream);
116
 
117
        return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null);
118
    }
119
 
120
    public function getStream()
121
    {
122
        return $this->stream;
123
    }
124
 
125
    public function setStream($stream, $size = null)
126
    {
127
        if (!is_resource($stream)) {
128
            throw new InvalidArgumentException('Stream must be a resource');
129
        }
130
 
131
        $this->size = $size;
132
        $this->stream = $stream;
133
        $this->rebuildCache();
134
 
135
        return $this;
136
    }
137
 
138
    public function detachStream()
139
    {
140
        $this->stream = null;
141
 
142
        return $this;
143
    }
144
 
145
    public function getWrapper()
146
    {
147
        return $this->cache[self::WRAPPER_TYPE];
148
    }
149
 
150
    public function getWrapperData()
151
    {
152
        return $this->getMetaData('wrapper_data') ?: array();
153
    }
154
 
155
    public function getStreamType()
156
    {
157
        return $this->cache[self::STREAM_TYPE];
158
    }
159
 
160
    public function getUri()
161
    {
162
        return $this->cache['uri'];
163
    }
164
 
165
    public function getSize()
166
    {
167
        if ($this->size !== null) {
168
            return $this->size;
169
        }
170
 
171
        // If the stream is a file based stream and local, then use fstat
172
        clearstatcache(true, $this->cache['uri']);
173
        $stats = fstat($this->stream);
174
        if (isset($stats['size'])) {
175
            $this->size = $stats['size'];
176
            return $this->size;
177
        } elseif ($this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]) {
178
            // Only get the size based on the content if the the stream is readable and seekable
179
            $pos = $this->ftell();
180
            $this->size = strlen((string) $this);
181
            $this->seek($pos);
182
            return $this->size;
183
        }
184
 
185
        return false;
186
    }
187
 
188
    public function isReadable()
189
    {
190
        return $this->cache[self::IS_READABLE];
191
    }
192
 
193
    public function isRepeatable()
194
    {
195
        return $this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE];
196
    }
197
 
198
    public function isWritable()
199
    {
200
        return $this->cache[self::IS_WRITABLE];
201
    }
202
 
203
    public function isConsumed()
204
    {
205
        return feof($this->stream);
206
    }
207
 
208
    public function feof()
209
    {
210
        return $this->isConsumed();
211
    }
212
 
213
    public function isLocal()
214
    {
215
        return $this->cache[self::IS_LOCAL];
216
    }
217
 
218
    public function isSeekable()
219
    {
220
        return $this->cache[self::SEEKABLE];
221
    }
222
 
223
    public function setSize($size)
224
    {
225
        $this->size = $size;
226
 
227
        return $this;
228
    }
229
 
230
    public function seek($offset, $whence = SEEK_SET)
231
    {
232
        return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false;
233
    }
234
 
235
    public function read($length)
236
    {
237
        return fread($this->stream, $length);
238
    }
239
 
240
    public function write($string)
241
    {
242
        // We can't know the size after writing anything
243
        $this->size = null;
244
 
245
        return fwrite($this->stream, $string);
246
    }
247
 
248
    public function ftell()
249
    {
250
        return ftell($this->stream);
251
    }
252
 
253
    public function rewind()
254
    {
255
        return $this->seek(0);
256
    }
257
 
258
    public function readLine($maxLength = null)
259
    {
260
        if (!$this->cache[self::IS_READABLE]) {
261
            return false;
262
        } else {
263
            return $maxLength ? fgets($this->getStream(), $maxLength) : fgets($this->getStream());
264
        }
265
    }
266
 
267
    public function setCustomData($key, $value)
268
    {
269
        $this->customData[$key] = $value;
270
 
271
        return $this;
272
    }
273
 
274
    public function getCustomData($key)
275
    {
276
        return isset($this->customData[$key]) ? $this->customData[$key] : null;
277
    }
278
 
279
    /**
280
     * Reprocess stream metadata
281
     */
282
    protected function rebuildCache()
283
    {
284
        $this->cache = stream_get_meta_data($this->stream);
285
        $this->cache[self::IS_LOCAL] = stream_is_local($this->stream);
286
        $this->cache[self::IS_READABLE] = isset(self::$readWriteHash['read'][$this->cache['mode']]);
287
        $this->cache[self::IS_WRITABLE] = isset(self::$readWriteHash['write'][$this->cache['mode']]);
288
    }
289
}