Projet

Général

Profil

Paste
Télécharger (13,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / remote_stream_wrapper / remote_stream_wrapper.inc @ 87dbc3bf

1
<?php
2

    
3
/**
4
 * Stream wrapper to support local files.
5
 */
6
class DrupalRemoteStreamWrapper implements DrupalStreamWrapperInterface {
7
  /**
8
   * Stream context resource.
9
   *
10
   * @var Resource
11
   */
12
  public $context;
13

    
14
  /**
15
   * A generic resource handle.
16
   *
17
   * @var Resource
18
   */
19
  //public $handle = NULL;
20

    
21
  /**
22
   * Instance URI (stream).
23
   *
24
   * A stream is referenced as "scheme://target".
25
   *
26
   * @var String
27
   */
28
  protected $uri;
29

    
30
  /**
31
   * The content of the file.
32
   *
33
   * @var String
34
   */
35
  protected $stream_content = NULL;
36

    
37

    
38
  /**
39
   * The pointer to the next read or write within the content variable.
40
   *
41
   * @var Integer
42
   */
43
  protected $stream_pointer;
44

    
45

    
46
  /**
47
   * Base implementation of setUri().
48
   */
49
  function setUri($uri) {
50
    $this->uri = $uri;
51
  }
52

    
53
  /**
54
   * Base implementation of getUri().
55
   */
56
  function getUri() {
57
    return $this->uri;
58
  }
59

    
60
  /**
61
   * Base implementation of getMimeType().
62
   */
63
  public static function getMimeType($uri, $mapping = NULL) {
64
    if (!isset($mapping)) {
65
      // The default file map, defined in file.mimetypes.inc is quite big.
66
      // We only load it when necessary.
67
      include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
68
      $mapping = file_mimetype_mapping();
69
    }
70

    
71
    if ($path = parse_url($uri, PHP_URL_PATH)) {
72
      $extension = '';
73
      $file_parts = explode('.', drupal_basename($path));
74

    
75
      // Remove the first part: a full filename should not match an extension.
76
      array_shift($file_parts);
77

    
78
      // Iterate over the file parts, trying to find a match.
79
      // For my.awesome.image.jpeg, we try:
80
      //   - jpeg
81
      //   - image.jpeg, and
82
      //   - awesome.image.jpeg
83
      while ($additional_part = array_pop($file_parts)) {
84
        $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
85
        if (isset($mapping['extensions'][$extension])) {
86
          return $mapping['mimetypes'][$mapping['extensions'][$extension]];
87
        }
88
      }
89
    }
90

    
91
    // Fallback to the 'Content-Type' header.
92
    $request = drupal_http_request($uri, array('method' => 'HEAD'));
93
    if (empty($request->error) && !empty($request->headers['content-type'])) {
94
      return $request->headers['content-type'];
95
    }
96

    
97
    return 'application/octet-stream';
98
  }
99

    
100
  /**
101
   * Implements chmod().
102
   *
103
   * Returns a TRUE result since this is a read-only stream wrapper.
104
   */
105
  function chmod($mode) {
106
    return TRUE;
107
  }
108

    
109
  /**
110
   * Implements realpath().
111
   */
112
  function realpath() {
113
    return $this->getLocalPath();
114
  }
115

    
116
  /**
117
   * Support for fopen(), file_get_contents(), file_put_contents() etc.
118
   *
119
   * @param $uri
120
   *   A string containing the URI to the file to open.
121
   * @param $mode
122
   *   The file mode ("r", "wb" etc.).
123
   * @param $options
124
   *   A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
125
   * @param &$opened_path
126
   *   A string containing the path actually opened.
127
   * @return
128
   *   Returns TRUE if file was opened successfully.
129
   *
130
   * @see http://php.net/manual/en/streamwrapper.stream-open.php
131
   */
132
  public function stream_open($uri, $mode, $options, &$opened_path) {
133
    $this->uri = $uri;
134

    
135
    $allowed_modes = array('r', 'rb');
136
    if (!in_array($mode, $allowed_modes)) {
137
      return FALSE;
138
    }
139

    
140
    // Attempt to fetch the URL's data using drupal_http_request().
141
    if (!$this->getStreamContent()) {
142
      return FALSE;
143
    }
144

    
145
    // Reset the stream pointer since this is an open.
146
    $this->stream_pointer = 0;
147
    return TRUE;
148
  }
149

    
150
  /**
151
   * Support for flock().
152
   *
153
   * @param $operation
154
   *   One of the following:
155
   *   - LOCK_SH to acquire a shared lock (reader).
156
   *   - LOCK_EX to acquire an exclusive lock (writer).
157
   *   - LOCK_UN to release a lock (shared or exclusive).
158
   *   - LOCK_NB if you don't want flock() to block while locking (not
159
   *     supported on Windows).
160
   * @return
161
   *   Always returns TRUE at the present time.
162
   *
163
   * @see http://php.net/manual/en/streamwrapper.stream-lock.php
164
   */
165
  public function stream_lock($operation) {
166
    return TRUE;
167
  }
168

    
169
  /**
170
   * Support for fread(), file_get_contents() etc.
171
   *
172
   * @param $count
173
   *   Maximum number of bytes to be read.
174
   * @return
175
   *   The string that was read, or FALSE in case of an error.
176
   *
177
   * @see http://php.net/manual/en/streamwrapper.stream-read.php
178
   */
179
  public function stream_read($count) {
180
    if (is_string($this->stream_content)) {
181
      $remaining_chars = strlen($this->stream_content) - $this->stream_pointer;
182
      $number_to_read = min($count, $remaining_chars);
183
      if ($remaining_chars > 0) {
184
        $buffer = substr($this->stream_content, $this->stream_pointer, $number_to_read);
185
        $this->stream_pointer += $number_to_read;
186
        return $buffer;
187
      }
188
    }
189
    return FALSE;
190
  }
191

    
192
  /**
193
   * Support for fwrite(), file_put_contents() etc.
194
   *
195
   * @param $data
196
   *   The string to be written.
197
   * @return
198
   *   The number of bytes written (integer).
199
   *
200
   * @see http://php.net/manual/en/streamwrapper.stream-write.php
201
   */
202
  public function stream_write($data) {
203
    return FALSE;
204
  }
205

    
206
  /**
207
   * Support for feof().
208
   *
209
   * @return
210
   *   TRUE if end-of-file has been reached.
211
   *
212
   * @see http://php.net/manual/en/streamwrapper.stream-eof.php
213
   */
214
  public function stream_eof() {
215
    return $this->stream_pointer == strlen($this->stream_content);
216
  }
217

    
218
  /**
219
   * Support for fseek().
220
   *
221
   * @param $offset
222
   *   The byte offset to got to.
223
   * @param $whence
224
   *   SEEK_SET, SEEK_CUR, or SEEK_END.
225
   * @return
226
   *   TRUE on success.
227
   *
228
   * @see http://php.net/manual/en/streamwrapper.stream-seek.php
229
   */
230
  public function stream_seek($offset, $whence) {
231
    if (strlen($this->stream_content) >= $offset) {
232
      $this->stream_pointer = $offset;
233
      return TRUE;
234
    }
235
    return FALSE;
236
  }
237

    
238
  /**
239
   * Support for fflush().
240
   *
241
   * @return
242
   *   TRUE if data was successfully stored (or there was no data to store).
243
   *
244
   * @see http://php.net/manual/en/streamwrapper.stream-flush.php
245
   */
246
  public function stream_flush() {
247
    return TRUE;
248
  }
249

    
250
  /**
251
   * Support for ftell().
252
   *
253
   * @return
254
   *   The current offset in bytes from the beginning of file.
255
   *
256
   * @see http://php.net/manual/en/streamwrapper.stream-tell.php
257
   */
258
  public function stream_tell() {
259
    return $this->stream_pointer;
260
  }
261

    
262
  /**
263
   * Support for fstat().
264
   *
265
   * @return
266
   *   An array with file status, or FALSE in case of an error - see fstat()
267
   *   for a description of this array.
268
   *
269
   * @see http://php.net/manual/en/streamwrapper.stream-stat.php
270
   */
271
  public function stream_stat() {
272
    $stat = array();
273
    $request = drupal_http_request($this->uri, array('method' => 'HEAD'));
274
    if (empty($request->error)) {
275
      if (isset($request->headers['content-length'])) {
276
        $stat['size'] = $request->headers['content-length'];
277
      }
278
      elseif ($size = strlen($this->getStreamContent())) {
279
        // If the HEAD request does not return a Content-Length header, fall
280
        // back to performing a full request of the file to determine its file
281
        // size.
282
        $stat['size'] = $size;
283
      }
284
    }
285

    
286
    return !empty($stat) ? $this->getStat($stat) : FALSE;
287
  }
288

    
289
  /**
290
   * Support for fclose().
291
   *
292
   * @return
293
   *   TRUE if stream was successfully closed.
294
   *
295
   * @see http://php.net/manual/en/streamwrapper.stream-close.php
296
   */
297
  public function stream_close() {
298
    $this->stream_pointer = 0;
299
    $this->stream_content = NULL;
300
    return TRUE;
301
  }
302

    
303
  /**
304
   * Support for unlink().
305
   *
306
   * @param $uri
307
   *   A string containing the uri to the resource to delete.
308
   * @return
309
   *   TRUE if resource was successfully deleted.
310
   *
311
   * @see http://php.net/manual/en/streamwrapper.unlink.php
312
   */
313
  public function unlink($uri) {
314
    // We return FALSE rather than TRUE so that managed file records can be
315
    // deleted.
316
    return TRUE;
317
  }
318

    
319
  /**
320
   * Support for rename().
321
   *
322
   * @param $from_uri,
323
   *   The uri to the file to rename.
324
   * @param $to_uri
325
   *   The new uri for file.
326
   * @return
327
   *   TRUE if file was successfully renamed.
328
   *
329
   * @see http://php.net/manual/en/streamwrapper.rename.php
330
   */
331
  public function rename($from_uri, $to_uri) {
332
    return FALSE;
333
  }
334

    
335
  /**
336
   * Support for mkdir().
337
   *
338
   * @param $uri
339
   *   A string containing the URI to the directory to create.
340
   * @param $mode
341
   *   Permission flags - see mkdir().
342
   * @param $options
343
   *   A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
344
   * @return
345
   *   TRUE if directory was successfully created.
346
   *
347
   * @see http://php.net/manual/en/streamwrapper.mkdir.php
348
   */
349
  public function mkdir($uri, $mode, $options) {
350
    return FALSE;
351
  }
352

    
353
  /**
354
   * Support for rmdir().
355
   *
356
   * @param $uri
357
   *   A string containing the URI to the directory to delete.
358
   * @param $options
359
   *   A bit mask of STREAM_REPORT_ERRORS.
360
   * @return
361
   *   TRUE if directory was successfully removed.
362
   *
363
   * @see http://php.net/manual/en/streamwrapper.rmdir.php
364
   */
365
  public function rmdir($uri, $options) {
366
    return FALSE;
367
  }
368

    
369
  /**
370
   * Support for stat().
371
   *
372
   * @param $uri
373
   *   A string containing the URI to get information about.
374
   * @param $flags
375
   *   A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
376
   * @return
377
   *   An array with file status, or FALSE in case of an error - see fstat()
378
   *   for a description of this array.
379
   *
380
   * @see http://php.net/manual/en/streamwrapper.url-stat.php
381
   */
382
  public function url_stat($uri, $flags) {
383
    $this->uri = $uri;
384
    if ($flags & STREAM_URL_STAT_QUIET) {
385
      return @$this->stream_stat();
386
    }
387
    else {
388
      return $this->stream_stat();
389
    }
390
  }
391

    
392
  /**
393
   * Support for opendir().
394
   *
395
   * @param $uri
396
   *   A string containing the URI to the directory to open.
397
   * @param $options
398
   *   Unknown (parameter is not documented in PHP Manual).
399
   * @return
400
   *   TRUE on success.
401
   *
402
   * @see http://php.net/manual/en/streamwrapper.dir-opendir.php
403
   */
404
  public function dir_opendir($uri, $options) {
405
    return FALSE;
406
  }
407

    
408
  /**
409
   * Support for readdir().
410
   *
411
   * @return
412
   *   The next filename, or FALSE if there are no more files in the directory.
413
   * @see http://php.net/manual/en/streamwrapper.dir-readdir.php
414
   */
415
  public function dir_readdir() {
416
    return FALSE;
417
  }
418

    
419
  /**
420
   * Support for rewinddir().
421
   *
422
   * @return
423
   *   TRUE on success.
424
   * @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php
425
   */
426
  public function dir_rewinddir() {
427
    return FALSE;
428
  }
429

    
430
  /**
431
   * Support for closedir().
432
   *
433
   * @return
434
   *   TRUE on success.
435
   * @see http://php.net/manual/en/streamwrapper.dir-closedir.php
436
   */
437
  public function dir_closedir() {
438
    return FALSE;
439
  }
440

    
441
  /**
442
   * Implements abstract public function getDirectoryPath()
443
   */
444
  public function getDirectoryPath() {
445
    return '';
446
  }
447

    
448
  /**
449
   * Overrides getExternalUrl().
450
   *
451
   * Return the HTML URL of a Twitpic image.
452
   */
453
  function getExternalUrl() {
454
    return $this->uri;
455
  }
456

    
457
  /**
458
   * Gets the name of the directory from a given path.
459
   *
460
   * This method is usually accessed through drupal_dirname(), which wraps
461
   * around the PHP dirname() function because it does not support stream
462
   * wrappers.
463
   *
464
   * @param $uri
465
   *   A URI or path.
466
   *
467
   * @return
468
   *   A string containing the directory name.
469
   *
470
   * @see drupal_dirname()
471
   */
472
  public function dirname($uri = NULL) {
473
    list($scheme, $target) = explode('://', $uri, 2);
474
    $dirname = dirname($target);
475

    
476
    if ($dirname == '.') {
477
      $dirname = '';
478
    }
479

    
480
    return $scheme . '://' . $dirname;
481
  }
482

    
483
  /**
484
   * Return the local filesystem path.
485
   *
486
   * @param $uri
487
   *   Optional URI, supplied when doing a move or rename.
488
   */
489
  function getLocalPath($uri = NULL) {
490
    if (!isset($uri)) {
491
      $uri = $this->uri;
492
    }
493

    
494
    return $uri;
495
  }
496

    
497
  /**
498
   * Helper function to return a full array for stat functions.
499
   */
500
  protected function getStat(array $stat = array()) {
501
    $defaults = array(
502
      'dev' => 0,      // device number
503
      'ino' => 0,      // inode number
504
      'mode' => 0100000 | 0444,     // inode protectio
505
      'nlink' => 0,    // number of links
506
      'uid' => 0,      // userid of owner
507
      'gid' => 0,      // groupid of owner
508
      'rdev' => -1,    // device type, if inode device *
509
      'size' => 0,     // size in bytes
510
      'atime' => 0,    // time of last access (Unix timestamp)
511
      'mtime' => 0,    // time of last modification (Unix timestamp)
512
      'ctime' => 0,    // time of last inode change (Unix timestamp)
513
      'blksize' => -1, // blocksize of filesystem IO
514
      'blocks' => -1,  // number of blocks allocated
515
    );
516

    
517
    $return = array();
518
    foreach (array_keys($defaults) as $index => $key) {
519
      if (!isset($stat[$key])) {
520
        $return[$index] = $defaults[$key];
521
        $return[$key] = $defaults[$key];
522
      }
523
      else {
524
        $return[$index] = $stat[$key];
525
        $return[$key] = $stat[$key];
526
      }
527
    }
528

    
529
    return $return;
530
  }
531

    
532
  /**
533
   * Fetch the content of the file using drupal_http_request().
534
   */
535
  protected function getStreamContent() {
536
    if (!isset($this->stream_content)) {
537
      $this->stream_content = NULL;
538

    
539
      $request = drupal_http_request($this->uri);
540
      if (empty($request->error) && !empty($request->data)) {
541
        $this->stream_content = $request->data;
542
      }
543
    }
544

    
545
    return $this->stream_content;
546
  }
547
}