1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* Implements a base class for Resource Stream Wrappers.
|
6
|
*/
|
7
|
|
8
|
/**
|
9
|
* A base class for Resource Stream Wrappers.
|
10
|
*
|
11
|
* This class provides a complete stream wrapper implementation. It passes
|
12
|
* incoming URL's through an interpolation method then recursively calls
|
13
|
* the invoking PHP filesystem function.
|
14
|
*
|
15
|
* MediaReadOnlyStreamWrapper implementations need to override at least the
|
16
|
* interpolateUrl method to rewrite the URL before is it passed back into the
|
17
|
* calling function.
|
18
|
*/
|
19
|
abstract class MediaReadOnlyStreamWrapper implements DrupalStreamWrapperInterface {
|
20
|
protected $parameters = array();
|
21
|
protected $base_url = NULL;
|
22
|
private $_DEBUG_MODE = NULL;
|
23
|
|
24
|
/**
|
25
|
* Utility function to return paramenters.
|
26
|
*/
|
27
|
public function get_parameters() {
|
28
|
return $this->parameters;
|
29
|
}
|
30
|
|
31
|
// As part of the inode protection mode returned by stat(), identifies the
|
32
|
// file as a regular file, as opposed to a directory, symbolic link, or other
|
33
|
// type of "file".
|
34
|
// @see http://linux.die.net/man/2/stat
|
35
|
const S_IFREG = 0100000;
|
36
|
|
37
|
/**
|
38
|
* Template for stat calls.
|
39
|
*
|
40
|
* All elements must be initialized.
|
41
|
*/
|
42
|
protected $_stat = array(
|
43
|
0 => 0, // Device number
|
44
|
'dev' => 0,
|
45
|
1 => 0, // Inode number
|
46
|
'ino' => 0,
|
47
|
// Inode protection mode. file_unmanaged_delete() requires is_file() to
|
48
|
// return TRUE.
|
49
|
2 => self::S_IFREG,
|
50
|
'mode' => self::S_IFREG,
|
51
|
3 => 0, // Number of links.
|
52
|
'nlink' => 0,
|
53
|
4 => 0, // Userid of owner.
|
54
|
'uid' => 0,
|
55
|
5 => 0, // Groupid of owner.
|
56
|
'gid' => 0,
|
57
|
6 => -1, // Device type, if inode device *
|
58
|
'rdev' => -1,
|
59
|
7 => 0, // Size in bytes.
|
60
|
'size' => 0,
|
61
|
8 => 0, // Time of last access (Unix timestamp).
|
62
|
'atime' => 0,
|
63
|
9 => 0, // Time of last modification (Unix timestamp).
|
64
|
'mtime' => 0,
|
65
|
10 => 0, // Time of last inode change (Unix timestamp).
|
66
|
'ctime' => 0,
|
67
|
11 => -1, // Blocksize of filesystem IO.
|
68
|
'blksize' => -1,
|
69
|
12 => -1, // Number of blocks allocated.
|
70
|
'blocks' => -1,
|
71
|
);
|
72
|
|
73
|
/**
|
74
|
* Handles parameters on the URL string.
|
75
|
*/
|
76
|
public function interpolateUrl() {
|
77
|
if ($parameters = $this->get_parameters()) {
|
78
|
return $this->base_url . '?' . http_build_query($parameters);
|
79
|
}
|
80
|
}
|
81
|
|
82
|
/**
|
83
|
* Returns a web accessible URL for the resource.
|
84
|
*
|
85
|
* This function should return a URL that can be embedded in a web page
|
86
|
* and accessed from a browser. For example, the external URL of
|
87
|
* "youtube://xIpLd0WQKCY" might be
|
88
|
* "http://www.youtube.com/watch?v=xIpLd0WQKCY".
|
89
|
*
|
90
|
* @return string
|
91
|
* Returns a string containing a web accessible URL for the resource.
|
92
|
*/
|
93
|
public function getExternalUrl() {
|
94
|
return $this->interpolateUrl();
|
95
|
}
|
96
|
|
97
|
/**
|
98
|
* Base implementation of getMimeType().
|
99
|
*/
|
100
|
public static function getMimeType($uri, $mapping = NULL) {
|
101
|
return 'application/octet-stream';
|
102
|
}
|
103
|
|
104
|
/**
|
105
|
* Base implementation of realpath().
|
106
|
*/
|
107
|
public function realpath() {
|
108
|
return $this->getExternalUrl();
|
109
|
}
|
110
|
|
111
|
/**
|
112
|
* Stream context resource.
|
113
|
*
|
114
|
* @var Resource
|
115
|
*/
|
116
|
public $context;
|
117
|
|
118
|
/**
|
119
|
* A generic resource handle.
|
120
|
*
|
121
|
* @var Resource
|
122
|
*/
|
123
|
public $handle = NULL;
|
124
|
|
125
|
/**
|
126
|
* Instance URI (stream).
|
127
|
*
|
128
|
* A stream is referenced as "scheme://target".
|
129
|
*
|
130
|
* @var String
|
131
|
*/
|
132
|
protected $uri;
|
133
|
|
134
|
/**
|
135
|
* Base implementation of setUri().
|
136
|
*/
|
137
|
public function setUri($uri) {
|
138
|
$this->uri = $uri;
|
139
|
$this->parameters = $this->_parse_url($uri);
|
140
|
}
|
141
|
|
142
|
/**
|
143
|
* Base implementation of getUri().
|
144
|
*/
|
145
|
public function getUri() {
|
146
|
return $this->uri;
|
147
|
}
|
148
|
|
149
|
/**
|
150
|
* Report an error.
|
151
|
*
|
152
|
* @param string $message
|
153
|
* The untranslated string to report.
|
154
|
* @param array $options
|
155
|
* An optional array of options to send to t().
|
156
|
* @param bool $display
|
157
|
* If TRUE, then we display the error to the user.
|
158
|
*
|
159
|
* @return bool
|
160
|
* We return FALSE, since we sometimes pass that back from the reporting
|
161
|
* function.
|
162
|
*/
|
163
|
private function _report_error($message, $options = array(), $display = FALSE) {
|
164
|
watchdog('resource', $message, $options, WATCHDOG_ERROR);
|
165
|
if ($display) {
|
166
|
drupal_set_message(t($message, $options), 'error');
|
167
|
}
|
168
|
return FALSE;
|
169
|
}
|
170
|
|
171
|
/**
|
172
|
* Sets the debug mode.
|
173
|
*/
|
174
|
private function _debug($message, $type = 'status') {
|
175
|
if ($this->_DEBUG_MODE) {
|
176
|
drupal_set_message($message, $type);
|
177
|
}
|
178
|
}
|
179
|
|
180
|
/**
|
181
|
* Returns an array of any parameters stored in the URL's path.
|
182
|
*
|
183
|
* @param string $url
|
184
|
* The URL to parse, such as youtube://v/[video-code]/t/[tags+more-tags].
|
185
|
*
|
186
|
* @return array
|
187
|
* An associative array of all the parameters in the path,
|
188
|
* or FALSE if the $url is ill-formed.
|
189
|
*/
|
190
|
protected function _parse_url($url) {
|
191
|
$path = explode('://', $url);
|
192
|
$parts = explode('/', $path[1]);
|
193
|
$params = array();
|
194
|
$count = 0;
|
195
|
$total = count($parts);
|
196
|
if (!$total || ($total % 2)) {
|
197
|
// If we have no parts, or an odd number of parts, it's malformed.
|
198
|
return FALSE;
|
199
|
}
|
200
|
while ($count < $total) {
|
201
|
// We iterate count for each step of the assignment to keep us honest.
|
202
|
$params[$parts[$count++]] = $parts[$count++];
|
203
|
}
|
204
|
return $params;
|
205
|
}
|
206
|
|
207
|
/**
|
208
|
* Support for fopen(), file_get_contents(), file_put_contents() etc.
|
209
|
*
|
210
|
* @param string $url
|
211
|
* A string containing the path to the file to open.
|
212
|
* @param string $mode
|
213
|
* The file mode ("r", "wb" etc.).
|
214
|
* @param bitmask $options
|
215
|
* A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
|
216
|
* @param string &$opened_url
|
217
|
* A string containing the path actually opened.
|
218
|
*
|
219
|
* @return bool
|
220
|
* TRUE if file was opened successfully.
|
221
|
*/
|
222
|
public function stream_open($url, $mode, $options, &$opened_url) {
|
223
|
$this->_debug(t('Stream open: %url', array('%url' => $url)));
|
224
|
|
225
|
// We only handle Read-Only mode by default.
|
226
|
if ($mode != 'r' && $mode != 'rb') {
|
227
|
return $this->_report_error('Attempted to open %url as mode: %mode.', array('%url' => $url, '%mode' => $mode), ($options & STREAM_REPORT_ERRORS));
|
228
|
}
|
229
|
|
230
|
// We parse a URL as youtube://v/dsyiufo34/t/cats+dogs to store
|
231
|
// the relevant code(s) in our private array of parameters.
|
232
|
$this->parameters = $this->_parse_url($url);
|
233
|
|
234
|
if ($this->parameters === FALSE) {
|
235
|
return $this->_report_error('Attempted to parse an ill-formed url: %url.', array('%url' => $url), ($options & STREAM_REPORT_ERRORS));
|
236
|
}
|
237
|
|
238
|
if ((bool) $this->parameters && ($options & STREAM_USE_PATH)) {
|
239
|
$opened_url = $url;
|
240
|
}
|
241
|
|
242
|
$this->_debug(t('Stream opened: %parameters', array('%parameters' => print_r($this->parameters, TRUE))));
|
243
|
|
244
|
return (bool) $this->parameters;
|
245
|
}
|
246
|
|
247
|
/**
|
248
|
* Undocumented PHP stream wrapper method.
|
249
|
*/
|
250
|
function stream_lock($operation) {
|
251
|
return FALSE;
|
252
|
}
|
253
|
|
254
|
/**
|
255
|
* Support for fread(), file_get_contents() etc.
|
256
|
*
|
257
|
* @param int $count
|
258
|
* Maximum number of bytes to be read.
|
259
|
*
|
260
|
* @return bool
|
261
|
* The string that was read, or FALSE in case of an error.
|
262
|
*/
|
263
|
public function stream_read($count) {
|
264
|
return FALSE;
|
265
|
}
|
266
|
|
267
|
/**
|
268
|
* Support for fwrite(), file_put_contents() etc.
|
269
|
*
|
270
|
* Since this is a read only stream wrapper this always returns false.
|
271
|
*
|
272
|
* @param string $data
|
273
|
* The string to be written.
|
274
|
*
|
275
|
* @return bool
|
276
|
* Returns FALSE.
|
277
|
*/
|
278
|
public function stream_write($data) {
|
279
|
return FALSE;
|
280
|
}
|
281
|
|
282
|
/**
|
283
|
* Support for feof().
|
284
|
*
|
285
|
* @return bool
|
286
|
* TRUE if end-of-file has been reached.
|
287
|
*/
|
288
|
public function stream_eof() {
|
289
|
return FALSE;
|
290
|
}
|
291
|
|
292
|
/**
|
293
|
* Support for fseek().
|
294
|
*
|
295
|
* @todo document why this returns false.
|
296
|
*
|
297
|
* @param int $offset
|
298
|
* The byte offset to got to.
|
299
|
* @param string $whence
|
300
|
* SEEK_SET, SEEK_CUR, or SEEK_END.
|
301
|
*
|
302
|
* @return bool
|
303
|
* TRUE on success
|
304
|
*/
|
305
|
public function stream_seek($offset, $whence) {
|
306
|
return FALSE;
|
307
|
}
|
308
|
|
309
|
/**
|
310
|
* Support for fflush().
|
311
|
*
|
312
|
* @todo document why this returns false.
|
313
|
*
|
314
|
* @return bool
|
315
|
* TRUE if data was successfully stored (or there was no data to store).
|
316
|
*/
|
317
|
public function stream_flush() {
|
318
|
return FALSE;
|
319
|
}
|
320
|
|
321
|
/**
|
322
|
* Support for ftell().
|
323
|
*
|
324
|
* @todo document why this returns false.
|
325
|
*
|
326
|
* @return bool
|
327
|
* The current offset in bytes from the beginning of file.
|
328
|
*/
|
329
|
public function stream_tell() {
|
330
|
return FALSE;
|
331
|
}
|
332
|
|
333
|
/**
|
334
|
* Support for fstat().
|
335
|
*
|
336
|
* @return array
|
337
|
* An array with file status, or FALSE in case of an error - see fstat()
|
338
|
* for a description of this array.
|
339
|
*/
|
340
|
public function stream_stat() {
|
341
|
return $this->_stat;
|
342
|
}
|
343
|
|
344
|
/**
|
345
|
* Support for fclose().
|
346
|
*
|
347
|
* @todo document why this returns TRUE.
|
348
|
*
|
349
|
* @return bool
|
350
|
* TRUE if stream was successfully closed.
|
351
|
*/
|
352
|
public function stream_close() {
|
353
|
return TRUE;
|
354
|
}
|
355
|
|
356
|
/**
|
357
|
* Support for stat().
|
358
|
*
|
359
|
* @param string $url
|
360
|
* A string containing the url to get information about.
|
361
|
* @param bitmask $flags
|
362
|
* A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
|
363
|
*
|
364
|
* @return array
|
365
|
* An array with file status, or FALSE in case of an error - see fstat()
|
366
|
* for a description of this array.
|
367
|
*/
|
368
|
public function url_stat($url, $flags) {
|
369
|
return $this->stream_stat();
|
370
|
}
|
371
|
|
372
|
/**
|
373
|
* Support for opendir().
|
374
|
*
|
375
|
* @param string $url
|
376
|
* A string containing the url to the directory to open.
|
377
|
* @param int $options
|
378
|
* Whether or not to enforce safe_mode (0x04).
|
379
|
*
|
380
|
* @return bool
|
381
|
* TRUE on success.
|
382
|
*/
|
383
|
public function dir_opendir($url, $options) {
|
384
|
return FALSE;
|
385
|
}
|
386
|
|
387
|
/**
|
388
|
* Support for readdir().
|
389
|
*
|
390
|
* @return bool
|
391
|
* The next filename, or FALSE if there are no more files in the directory.
|
392
|
*/
|
393
|
public function dir_readdir() {
|
394
|
return FALSE;
|
395
|
}
|
396
|
|
397
|
/**
|
398
|
* Support for rewinddir().
|
399
|
*
|
400
|
* @return bool
|
401
|
* TRUE on success.
|
402
|
*/
|
403
|
public function dir_rewinddir() {
|
404
|
return FALSE;
|
405
|
}
|
406
|
|
407
|
/**
|
408
|
* Support for closedir().
|
409
|
*
|
410
|
* @return bool
|
411
|
* TRUE on success.
|
412
|
*/
|
413
|
public function dir_closedir() {
|
414
|
return FALSE;
|
415
|
}
|
416
|
|
417
|
/**
|
418
|
* Undocumented.
|
419
|
*
|
420
|
* @todo document.
|
421
|
*/
|
422
|
public function getDirectoryPath() {
|
423
|
return '';
|
424
|
}
|
425
|
|
426
|
/**
|
427
|
* DrupalStreamWrapperInterface requires that these methods be implemented,
|
428
|
* but none of them apply to a read-only stream wrapper. On failure they
|
429
|
* are expected to return FALSE.
|
430
|
*/
|
431
|
|
432
|
/**
|
433
|
* Implements DrupalStreamWrapperInterface::unlink().
|
434
|
*/
|
435
|
public function unlink($uri) {
|
436
|
// Although the remote file itself can't be deleted, return TRUE so that
|
437
|
// file_delete() can remove the file record from the Drupal database.
|
438
|
return TRUE;
|
439
|
}
|
440
|
|
441
|
/**
|
442
|
* Implements DrupalStreamWrapperInterface::rename().
|
443
|
*/
|
444
|
public function rename($from_uri, $to_uri) {
|
445
|
return FALSE;
|
446
|
}
|
447
|
|
448
|
/**
|
449
|
* Implements DrupalStreamWrapperInterface::mkdir().
|
450
|
*/
|
451
|
public function mkdir($uri, $mode, $options) {
|
452
|
return FALSE;
|
453
|
}
|
454
|
|
455
|
/**
|
456
|
* Implements DrupalStreamWrapperInterface::rmdir().
|
457
|
*/
|
458
|
public function rmdir($uri, $options) {
|
459
|
return FALSE;
|
460
|
}
|
461
|
|
462
|
/**
|
463
|
* Implements DrupalStreamWrapperInterface::chmod().
|
464
|
*/
|
465
|
public function chmod($mode) {
|
466
|
return FALSE;
|
467
|
}
|
468
|
|
469
|
/**
|
470
|
* Implements DrupalStreamWrapperInterface::dirname().
|
471
|
*/
|
472
|
public function dirname($uri = NULL) {
|
473
|
return FALSE;
|
474
|
}
|
475
|
|
476
|
}
|