stream_wrappers.inc

You are here

Drupal stream wrapper interface.

Provides a Drupal interface and classes to implement PHP stream wrappers for public, private, and temporary files.

A stream wrapper is an abstraction of a file system that allows Drupal to use the same set of methods to access both local files and remote resources.

Note that PHP 5.2 fopen() only supports URIs of the form "scheme://target" despite the fact that according to RFC 3986 a URI's scheme component delimiter is in general just ":", not "://". Because of this PHP limitation and for consistency Drupal will only accept URIs of form "scheme://target".

See also

http://www.faqs.org/rfcs/rfc3986.html

http://bugs.php.net/bug.php?id=47070

Constants

Namesort descending Description
STREAM_WRAPPERS_ALL Stream wrapper bit flag -- a filter that matches all wrappers.
STREAM_WRAPPERS_HIDDEN Stream wrapper type flag -- not visible in the UI or accessible via web, but readable and writable. E.g. the temporary directory for uploads.
STREAM_WRAPPERS_LOCAL Stream wrapper bit flag -- refers to a local file system location.
STREAM_WRAPPERS_LOCAL_HIDDEN Stream wrapper type flag -- hidden, readable and writeable using local files.
STREAM_WRAPPERS_LOCAL_NORMAL Stream wrapper type flag -- visible, readable and writeable using local files.
STREAM_WRAPPERS_NORMAL Stream wrapper type flag -- the default when 'type' is omitted from hook_stream_wrappers(). This does not include STREAM_WRAPPERS_LOCAL, because PHP grants a greater trust level to local files (for example, they can be used in an…
STREAM_WRAPPERS_READ Stream wrapper bit flag -- wrapper is readable (almost always true).
STREAM_WRAPPERS_READ_VISIBLE Stream wrapper type flag -- visible and read-only.
STREAM_WRAPPERS_VISIBLE Stream wrapper bit flag -- exposed in the UI and potentially web accessible.
STREAM_WRAPPERS_WRITE Stream wrapper bit flag -- wrapper is writeable.
STREAM_WRAPPERS_WRITE_VISIBLE Stream wrapper type flag -- visible, readable and writeable.

Classes

Namesort descending Description
DrupalLocalStreamWrapper Drupal stream wrapper base class for local files.
DrupalPrivateStreamWrapper Drupal private (private://) stream wrapper class.
DrupalPublicStreamWrapper Drupal public (public://) stream wrapper class.
DrupalTemporaryStreamWrapper Drupal temporary (temporary://) stream wrapper class.

Interfaces

Namesort descending Description
DrupalStreamWrapperInterface Drupal stream wrapper extension.
StreamWrapperInterface Generic PHP stream wrapper interface.

File

includes/stream_wrappers.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Drupal stream wrapper interface.
  5. *
  6. * Provides a Drupal interface and classes to implement PHP stream wrappers for
  7. * public, private, and temporary files.
  8. *
  9. * A stream wrapper is an abstraction of a file system that allows Drupal to
  10. * use the same set of methods to access both local files and remote resources.
  11. *
  12. * Note that PHP 5.2 fopen() only supports URIs of the form "scheme://target"
  13. * despite the fact that according to RFC 3986 a URI's scheme component
  14. * delimiter is in general just ":", not "://". Because of this PHP limitation
  15. * and for consistency Drupal will only accept URIs of form "scheme://target".
  16. *
  17. * @see http://www.faqs.org/rfcs/rfc3986.html
  18. * @see http://bugs.php.net/bug.php?id=47070
  19. */
  20. /**
  21. * Stream wrapper bit flags that are the basis for composite types.
  22. *
  23. * Note that 0x0002 is skipped, because it was the value of a constant that has
  24. * since been removed.
  25. */
  26. /**
  27. * Stream wrapper bit flag -- a filter that matches all wrappers.
  28. */
  29. define('STREAM_WRAPPERS_ALL', 0x0000);
  30. /**
  31. * Stream wrapper bit flag -- refers to a local file system location.
  32. */
  33. define('STREAM_WRAPPERS_LOCAL', 0x0001);
  34. /**
  35. * Stream wrapper bit flag -- wrapper is readable (almost always true).
  36. */
  37. define('STREAM_WRAPPERS_READ', 0x0004);
  38. /**
  39. * Stream wrapper bit flag -- wrapper is writeable.
  40. */
  41. define('STREAM_WRAPPERS_WRITE', 0x0008);
  42. /**
  43. * Stream wrapper bit flag -- exposed in the UI and potentially web accessible.
  44. */
  45. define('STREAM_WRAPPERS_VISIBLE', 0x0010);
  46. /**
  47. * Composite stream wrapper bit flags that are usually used as the types.
  48. */
  49. /**
  50. * Stream wrapper type flag -- not visible in the UI or accessible via web,
  51. * but readable and writable. E.g. the temporary directory for uploads.
  52. */
  53. define('STREAM_WRAPPERS_HIDDEN', STREAM_WRAPPERS_READ | STREAM_WRAPPERS_WRITE);
  54. /**
  55. * Stream wrapper type flag -- hidden, readable and writeable using local files.
  56. */
  57. define('STREAM_WRAPPERS_LOCAL_HIDDEN', STREAM_WRAPPERS_LOCAL | STREAM_WRAPPERS_HIDDEN);
  58. /**
  59. * Stream wrapper type flag -- visible, readable and writeable.
  60. */
  61. define('STREAM_WRAPPERS_WRITE_VISIBLE', STREAM_WRAPPERS_READ | STREAM_WRAPPERS_WRITE | STREAM_WRAPPERS_VISIBLE);
  62. /**
  63. * Stream wrapper type flag -- visible and read-only.
  64. */
  65. define('STREAM_WRAPPERS_READ_VISIBLE', STREAM_WRAPPERS_READ | STREAM_WRAPPERS_VISIBLE);
  66. /**
  67. * Stream wrapper type flag -- the default when 'type' is omitted from
  68. * hook_stream_wrappers(). This does not include STREAM_WRAPPERS_LOCAL,
  69. * because PHP grants a greater trust level to local files (for example, they
  70. * can be used in an "include" statement, regardless of the "allow_url_include"
  71. * setting), so stream wrappers need to explicitly opt-in to this.
  72. */
  73. define('STREAM_WRAPPERS_NORMAL', STREAM_WRAPPERS_WRITE_VISIBLE);
  74. /**
  75. * Stream wrapper type flag -- visible, readable and writeable using local files.
  76. */
  77. define('STREAM_WRAPPERS_LOCAL_NORMAL', STREAM_WRAPPERS_LOCAL | STREAM_WRAPPERS_NORMAL);
  78. /**
  79. * Generic PHP stream wrapper interface.
  80. *
  81. * @see http://www.php.net/manual/class.streamwrapper.php
  82. */
  83. interface StreamWrapperInterface {
  84. public function stream_open($uri, $mode, $options, &$opened_url);
  85. public function stream_close();
  86. public function stream_lock($operation);
  87. public function stream_read($count);
  88. public function stream_write($data);
  89. public function stream_eof();
  90. public function stream_seek($offset, $whence);
  91. public function stream_flush();
  92. public function stream_tell();
  93. public function stream_stat();
  94. public function unlink($uri);
  95. public function rename($from_uri, $to_uri);
  96. public function mkdir($uri, $mode, $options);
  97. public function rmdir($uri, $options);
  98. public function url_stat($uri, $flags);
  99. public function dir_opendir($uri, $options);
  100. public function dir_readdir();
  101. public function dir_rewinddir();
  102. public function dir_closedir();
  103. }
  104. /**
  105. * Drupal stream wrapper extension.
  106. *
  107. * Extend the StreamWrapperInterface with methods expected by Drupal stream
  108. * wrapper classes.
  109. */
  110. interface DrupalStreamWrapperInterface extends StreamWrapperInterface {
  111. /**
  112. * Set the absolute stream resource URI.
  113. *
  114. * This allows you to set the URI. Generally is only called by the factory
  115. * method.
  116. *
  117. * @param $uri
  118. * A string containing the URI that should be used for this instance.
  119. */
  120. function setUri($uri);
  121. /**
  122. * Returns the stream resource URI.
  123. *
  124. * @return
  125. * Returns the current URI of the instance.
  126. */
  127. public function getUri();
  128. /**
  129. * Returns a web accessible URL for the resource.
  130. *
  131. * This function should return a URL that can be embedded in a web page
  132. * and accessed from a browser. For example, the external URL of
  133. * "youtube://xIpLd0WQKCY" might be
  134. * "http://www.youtube.com/watch?v=xIpLd0WQKCY".
  135. *
  136. * @return
  137. * Returns a string containing a web accessible URL for the resource.
  138. */
  139. public function getExternalUrl();
  140. /**
  141. * Returns the MIME type of the resource.
  142. *
  143. * @param $uri
  144. * The URI, path, or filename.
  145. * @param $mapping
  146. * An optional map of extensions to their mimetypes, in the form:
  147. * - 'mimetypes': a list of mimetypes, keyed by an identifier,
  148. * - 'extensions': the mapping itself, an associative array in which
  149. * the key is the extension and the value is the mimetype identifier.
  150. *
  151. * @return
  152. * Returns a string containing the MIME type of the resource.
  153. */
  154. public static function getMimeType($uri, $mapping = NULL);
  155. /**
  156. * Changes permissions of the resource.
  157. *
  158. * PHP lacks this functionality and it is not part of the official stream
  159. * wrapper interface. This is a custom implementation for Drupal.
  160. *
  161. * @param $mode
  162. * Integer value for the permissions. Consult PHP chmod() documentation
  163. * for more information.
  164. *
  165. * @return
  166. * Returns TRUE on success or FALSE on failure.
  167. */
  168. public function chmod($mode);
  169. /**
  170. * Returns canonical, absolute path of the resource.
  171. *
  172. * Implementation placeholder. PHP's realpath() does not support stream
  173. * wrappers. We provide this as a default so that individual wrappers may
  174. * implement their own solutions.
  175. *
  176. * @return
  177. * Returns a string with absolute pathname on success (implemented
  178. * by core wrappers), or FALSE on failure or if the registered
  179. * wrapper does not provide an implementation.
  180. */
  181. public function realpath();
  182. /**
  183. * Gets the name of the directory from a given path.
  184. *
  185. * This method is usually accessed through drupal_dirname(), which wraps
  186. * around the normal PHP dirname() function, which does not support stream
  187. * wrappers.
  188. *
  189. * @param $uri
  190. * An optional URI.
  191. *
  192. * @return
  193. * A string containing the directory name, or FALSE if not applicable.
  194. *
  195. * @see drupal_dirname()
  196. */
  197. public function dirname($uri = NULL);
  198. }
  199. /**
  200. * Drupal stream wrapper base class for local files.
  201. *
  202. * This class provides a complete stream wrapper implementation. URIs such as
  203. * "public://example.txt" are expanded to a normal filesystem path such as
  204. * "sites/default/files/example.txt" and then PHP filesystem functions are
  205. * invoked.
  206. *
  207. * DrupalLocalStreamWrapper implementations need to implement at least the
  208. * getDirectoryPath() and getExternalUrl() methods.
  209. */
  210. abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface {
  211. /**
  212. * Stream context resource.
  213. *
  214. * @var Resource
  215. */
  216. public $context;
  217. /**
  218. * A generic resource handle.
  219. *
  220. * @var Resource
  221. */
  222. public $handle = NULL;
  223. /**
  224. * Instance URI (stream).
  225. *
  226. * A stream is referenced as "scheme://target".
  227. *
  228. * @var String
  229. */
  230. protected $uri;
  231. /**
  232. * Gets the path that the wrapper is responsible for.
  233. * @TODO: Review this method name in D8 per http://drupal.org/node/701358
  234. *
  235. * @return
  236. * String specifying the path.
  237. */
  238. abstract function getDirectoryPath();
  239. /**
  240. * Base implementation of setUri().
  241. */
  242. function setUri($uri) {
  243. $this->uri = $uri;
  244. }
  245. /**
  246. * Base implementation of getUri().
  247. */
  248. function getUri() {
  249. return $this->uri;
  250. }
  251. /**
  252. * Returns the local writable target of the resource within the stream.
  253. *
  254. * This function should be used in place of calls to realpath() or similar
  255. * functions when attempting to determine the location of a file. While
  256. * functions like realpath() may return the location of a read-only file, this
  257. * method may return a URI or path suitable for writing that is completely
  258. * separate from the URI used for reading.
  259. *
  260. * @param $uri
  261. * Optional URI.
  262. *
  263. * @return
  264. * Returns a string representing a location suitable for writing of a file,
  265. * or FALSE if unable to write to the file such as with read-only streams.
  266. */
  267. protected function getTarget($uri = NULL) {
  268. if (!isset($uri)) {
  269. $uri = $this->uri;
  270. }
  271. list($scheme, $target) = explode('://', $uri, 2);
  272. // Remove erroneous leading or trailing, forward-slashes and backslashes.
  273. return trim($target, '\/');
  274. }
  275. /**
  276. * Base implementation of getMimeType().
  277. */
  278. static function getMimeType($uri, $mapping = NULL) {
  279. if (!isset($mapping)) {
  280. // The default file map, defined in file.mimetypes.inc is quite big.
  281. // We only load it when necessary.
  282. include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
  283. $mapping = file_mimetype_mapping();
  284. }
  285. $extension = '';
  286. $file_parts = explode('.', drupal_basename($uri));
  287. // Remove the first part: a full filename should not match an extension.
  288. array_shift($file_parts);
  289. // Iterate over the file parts, trying to find a match.
  290. // For my.awesome.image.jpeg, we try:
  291. // - jpeg
  292. // - image.jpeg, and
  293. // - awesome.image.jpeg
  294. while ($additional_part = array_pop($file_parts)) {
  295. $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
  296. if (isset($mapping['extensions'][$extension])) {
  297. return $mapping['mimetypes'][$mapping['extensions'][$extension]];
  298. }
  299. }
  300. return 'application/octet-stream';
  301. }
  302. /**
  303. * Base implementation of chmod().
  304. */
  305. function chmod($mode) {
  306. $output = @chmod($this->getLocalPath(), $mode);
  307. // We are modifying the underlying file here, so we have to clear the stat
  308. // cache so that PHP understands that URI has changed too.
  309. clearstatcache();
  310. return $output;
  311. }
  312. /**
  313. * Base implementation of realpath().
  314. */
  315. function realpath() {
  316. return $this->getLocalPath();
  317. }
  318. /**
  319. * Returns the canonical absolute path of the URI, if possible.
  320. *
  321. * @param string $uri
  322. * (optional) The stream wrapper URI to be converted to a canonical
  323. * absolute path. This may point to a directory or another type of file.
  324. *
  325. * @return string|false
  326. * If $uri is not set, returns the canonical absolute path of the URI
  327. * previously set by the DrupalStreamWrapperInterface::setUri() function.
  328. * If $uri is set and valid for this class, returns its canonical absolute
  329. * path, as determined by the realpath() function. If $uri is set but not
  330. * valid, returns FALSE.
  331. */
  332. protected function getLocalPath($uri = NULL) {
  333. if (!isset($uri)) {
  334. $uri = $this->uri;
  335. }
  336. $path = $this->getDirectoryPath() . '/' . $this->getTarget($uri);
  337. $realpath = realpath($path);
  338. if (!$realpath) {
  339. // This file does not yet exist.
  340. $realpath = realpath(dirname($path)) . '/' . drupal_basename($path);
  341. }
  342. $directory = realpath($this->getDirectoryPath());
  343. if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
  344. return FALSE;
  345. }
  346. return $realpath;
  347. }
  348. /**
  349. * Support for fopen(), file_get_contents(), file_put_contents() etc.
  350. *
  351. * @param $uri
  352. * A string containing the URI to the file to open.
  353. * @param $mode
  354. * The file mode ("r", "wb" etc.).
  355. * @param $options
  356. * A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
  357. * @param $opened_path
  358. * A string containing the path actually opened.
  359. *
  360. * @return
  361. * Returns TRUE if file was opened successfully.
  362. *
  363. * @see http://php.net/manual/streamwrapper.stream-open.php
  364. */
  365. public function stream_open($uri, $mode, $options, &$opened_path) {
  366. $this->uri = $uri;
  367. $path = $this->getLocalPath();
  368. $this->handle = ($options & STREAM_REPORT_ERRORS) ? fopen($path, $mode) : @fopen($path, $mode);
  369. if ((bool) $this->handle && $options & STREAM_USE_PATH) {
  370. $opened_path = $path;
  371. }
  372. return (bool) $this->handle;
  373. }
  374. /**
  375. * Support for flock().
  376. *
  377. * @param $operation
  378. * One of the following:
  379. * - LOCK_SH to acquire a shared lock (reader).
  380. * - LOCK_EX to acquire an exclusive lock (writer).
  381. * - LOCK_UN to release a lock (shared or exclusive).
  382. * - LOCK_NB if you don't want flock() to block while locking (not
  383. * supported on Windows).
  384. *
  385. * @return
  386. * Always returns TRUE at the present time.
  387. *
  388. * @see http://php.net/manual/streamwrapper.stream-lock.php
  389. */
  390. public function stream_lock($operation) {
  391. if (in_array($operation, array(LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB))) {
  392. return flock($this->handle, $operation);
  393. }
  394. return TRUE;
  395. }
  396. /**
  397. * Support for fread(), file_get_contents() etc.
  398. *
  399. * @param $count
  400. * Maximum number of bytes to be read.
  401. *
  402. * @return
  403. * The string that was read, or FALSE in case of an error.
  404. *
  405. * @see http://php.net/manual/streamwrapper.stream-read.php
  406. */
  407. public function stream_read($count) {
  408. return fread($this->handle, $count);
  409. }
  410. /**
  411. * Support for fwrite(), file_put_contents() etc.
  412. *
  413. * @param $data
  414. * The string to be written.
  415. *
  416. * @return
  417. * The number of bytes written (integer).
  418. *
  419. * @see http://php.net/manual/streamwrapper.stream-write.php
  420. */
  421. public function stream_write($data) {
  422. return fwrite($this->handle, $data);
  423. }
  424. /**
  425. * Support for feof().
  426. *
  427. * @return
  428. * TRUE if end-of-file has been reached.
  429. *
  430. * @see http://php.net/manual/streamwrapper.stream-eof.php
  431. */
  432. public function stream_eof() {
  433. return feof($this->handle);
  434. }
  435. /**
  436. * Support for fseek().
  437. *
  438. * @param $offset
  439. * The byte offset to got to.
  440. * @param $whence
  441. * SEEK_SET, SEEK_CUR, or SEEK_END.
  442. *
  443. * @return
  444. * TRUE on success.
  445. *
  446. * @see http://php.net/manual/streamwrapper.stream-seek.php
  447. */
  448. public function stream_seek($offset, $whence) {
  449. // fseek returns 0 on success and -1 on a failure.
  450. // stream_seek 1 on success and 0 on a failure.
  451. return !fseek($this->handle, $offset, $whence);
  452. }
  453. /**
  454. * Support for fflush().
  455. *
  456. * @return
  457. * TRUE if data was successfully stored (or there was no data to store).
  458. *
  459. * @see http://php.net/manual/streamwrapper.stream-flush.php
  460. */
  461. public function stream_flush() {
  462. return fflush($this->handle);
  463. }
  464. /**
  465. * Support for ftell().
  466. *
  467. * @return
  468. * The current offset in bytes from the beginning of file.
  469. *
  470. * @see http://php.net/manual/streamwrapper.stream-tell.php
  471. */
  472. public function stream_tell() {
  473. return ftell($this->handle);
  474. }
  475. /**
  476. * Support for fstat().
  477. *
  478. * @return
  479. * An array with file status, or FALSE in case of an error - see fstat()
  480. * for a description of this array.
  481. *
  482. * @see http://php.net/manual/streamwrapper.stream-stat.php
  483. */
  484. public function stream_stat() {
  485. return fstat($this->handle);
  486. }
  487. /**
  488. * Support for fclose().
  489. *
  490. * @return
  491. * TRUE if stream was successfully closed.
  492. *
  493. * @see http://php.net/manual/streamwrapper.stream-close.php
  494. */
  495. public function stream_close() {
  496. return fclose($this->handle);
  497. }
  498. /**
  499. * Support for unlink().
  500. *
  501. * @param $uri
  502. * A string containing the URI to the resource to delete.
  503. *
  504. * @return
  505. * TRUE if resource was successfully deleted.
  506. *
  507. * @see http://php.net/manual/streamwrapper.unlink.php
  508. */
  509. public function unlink($uri) {
  510. $this->uri = $uri;
  511. return drupal_unlink($this->getLocalPath());
  512. }
  513. /**
  514. * Support for rename().
  515. *
  516. * @param $from_uri,
  517. * The URI to the file to rename.
  518. * @param $to_uri
  519. * The new URI for file.
  520. *
  521. * @return
  522. * TRUE if file was successfully renamed.
  523. *
  524. * @see http://php.net/manual/streamwrapper.rename.php
  525. */
  526. public function rename($from_uri, $to_uri) {
  527. return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri));
  528. }
  529. /**
  530. * Gets the name of the directory from a given path.
  531. *
  532. * This method is usually accessed through drupal_dirname(), which wraps
  533. * around the PHP dirname() function because it does not support stream
  534. * wrappers.
  535. *
  536. * @param $uri
  537. * A URI or path.
  538. *
  539. * @return
  540. * A string containing the directory name.
  541. *
  542. * @see drupal_dirname()
  543. */
  544. public function dirname($uri = NULL) {
  545. list($scheme, $target) = explode('://', $uri, 2);
  546. $target = $this->getTarget($uri);
  547. $dirname = dirname($target);
  548. if ($dirname == '.') {
  549. $dirname = '';
  550. }
  551. return $scheme . '://' . $dirname;
  552. }
  553. /**
  554. * Support for mkdir().
  555. *
  556. * @param $uri
  557. * A string containing the URI to the directory to create.
  558. * @param $mode
  559. * Permission flags - see mkdir().
  560. * @param $options
  561. * A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
  562. *
  563. * @return
  564. * TRUE if directory was successfully created.
  565. *
  566. * @see http://php.net/manual/streamwrapper.mkdir.php
  567. */
  568. public function mkdir($uri, $mode, $options) {
  569. $this->uri = $uri;
  570. $recursive = (bool) ($options & STREAM_MKDIR_RECURSIVE);
  571. if ($recursive) {
  572. // $this->getLocalPath() fails if $uri has multiple levels of directories
  573. // that do not yet exist.
  574. $localpath = $this->getDirectoryPath() . '/' . $this->getTarget($uri);
  575. }
  576. else {
  577. $localpath = $this->getLocalPath($uri);
  578. }
  579. if ($options & STREAM_REPORT_ERRORS) {
  580. return mkdir($localpath, $mode, $recursive);
  581. }
  582. else {
  583. return @mkdir($localpath, $mode, $recursive);
  584. }
  585. }
  586. /**
  587. * Support for rmdir().
  588. *
  589. * @param $uri
  590. * A string containing the URI to the directory to delete.
  591. * @param $options
  592. * A bit mask of STREAM_REPORT_ERRORS.
  593. *
  594. * @return
  595. * TRUE if directory was successfully removed.
  596. *
  597. * @see http://php.net/manual/streamwrapper.rmdir.php
  598. */
  599. public function rmdir($uri, $options) {
  600. $this->uri = $uri;
  601. if ($options & STREAM_REPORT_ERRORS) {
  602. return drupal_rmdir($this->getLocalPath());
  603. }
  604. else {
  605. return @drupal_rmdir($this->getLocalPath());
  606. }
  607. }
  608. /**
  609. * Support for stat().
  610. *
  611. * @param $uri
  612. * A string containing the URI to get information about.
  613. * @param $flags
  614. * A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
  615. *
  616. * @return
  617. * An array with file status, or FALSE in case of an error - see fstat()
  618. * for a description of this array.
  619. *
  620. * @see http://php.net/manual/streamwrapper.url-stat.php
  621. */
  622. public function url_stat($uri, $flags) {
  623. $this->uri = $uri;
  624. $path = $this->getLocalPath();
  625. // Suppress warnings if requested or if the file or directory does not
  626. // exist. This is consistent with PHP's plain filesystem stream wrapper.
  627. if ($flags & STREAM_URL_STAT_QUIET || !file_exists($path)) {
  628. return @stat($path);
  629. }
  630. else {
  631. return stat($path);
  632. }
  633. }
  634. /**
  635. * Support for opendir().
  636. *
  637. * @param $uri
  638. * A string containing the URI to the directory to open.
  639. * @param $options
  640. * Unknown (parameter is not documented in PHP Manual).
  641. *
  642. * @return
  643. * TRUE on success.
  644. *
  645. * @see http://php.net/manual/streamwrapper.dir-opendir.php
  646. */
  647. public function dir_opendir($uri, $options) {
  648. $this->uri = $uri;
  649. $this->handle = opendir($this->getLocalPath());
  650. return (bool) $this->handle;
  651. }
  652. /**
  653. * Support for readdir().
  654. *
  655. * @return
  656. * The next filename, or FALSE if there are no more files in the directory.
  657. *
  658. * @see http://php.net/manual/streamwrapper.dir-readdir.php
  659. */
  660. public function dir_readdir() {
  661. return readdir($this->handle);
  662. }
  663. /**
  664. * Support for rewinddir().
  665. *
  666. * @return
  667. * TRUE on success.
  668. *
  669. * @see http://php.net/manual/streamwrapper.dir-rewinddir.php
  670. */
  671. public function dir_rewinddir() {
  672. rewinddir($this->handle);
  673. // We do not really have a way to signal a failure as rewinddir() does not
  674. // have a return value and there is no way to read a directory handler
  675. // without advancing to the next file.
  676. return TRUE;
  677. }
  678. /**
  679. * Support for closedir().
  680. *
  681. * @return
  682. * TRUE on success.
  683. *
  684. * @see http://php.net/manual/streamwrapper.dir-closedir.php
  685. */
  686. public function dir_closedir() {
  687. closedir($this->handle);
  688. // We do not really have a way to signal a failure as closedir() does not
  689. // have a return value.
  690. return TRUE;
  691. }
  692. }
  693. /**
  694. * Drupal public (public://) stream wrapper class.
  695. *
  696. * Provides support for storing publicly accessible files with the Drupal file
  697. * interface.
  698. */
  699. class DrupalPublicStreamWrapper extends DrupalLocalStreamWrapper {
  700. /**
  701. * Implements abstract public function getDirectoryPath()
  702. */
  703. public function getDirectoryPath() {
  704. return variable_get('file_public_path', conf_path() . '/files');
  705. }
  706. /**
  707. * Overrides getExternalUrl().
  708. *
  709. * Return the HTML URI of a public file.
  710. */
  711. function getExternalUrl() {
  712. $path = str_replace('\\', '/', $this->getTarget());
  713. return $GLOBALS['base_url'] . '/' . self::getDirectoryPath() . '/' . drupal_encode_path($path);
  714. }
  715. }
  716. /**
  717. * Drupal private (private://) stream wrapper class.
  718. *
  719. * Provides support for storing privately accessible files with the Drupal file
  720. * interface.
  721. */
  722. class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
  723. /**
  724. * Implements abstract public function getDirectoryPath()
  725. */
  726. public function getDirectoryPath() {
  727. return variable_get('file_private_path', '');
  728. }
  729. /**
  730. * Overrides getExternalUrl().
  731. *
  732. * Return the HTML URI of a private file.
  733. */
  734. function getExternalUrl() {
  735. $path = str_replace('\\', '/', $this->getTarget());
  736. return url('system/files/' . $path, array('absolute' => TRUE));
  737. }
  738. }
  739. /**
  740. * Drupal temporary (temporary://) stream wrapper class.
  741. *
  742. * Provides support for storing temporarily accessible files with the Drupal
  743. * file interface.
  744. *
  745. * Extends DrupalPublicStreamWrapper.
  746. */
  747. class DrupalTemporaryStreamWrapper extends DrupalLocalStreamWrapper {
  748. /**
  749. * Implements abstract public function getDirectoryPath()
  750. */
  751. public function getDirectoryPath() {
  752. return variable_get('file_temporary_path', file_directory_temp());
  753. }
  754. /**
  755. * Overrides getExternalUrl().
  756. */
  757. public function getExternalUrl() {
  758. $path = str_replace('\\', '/', $this->getTarget());
  759. return url('system/temporary/' . $path, array('absolute' => TRUE));
  760. }
  761. }