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

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. public 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. * Sets metadata on the stream.
  500. *
  501. * WARNING: Do not call this method directly! It will be called internally by
  502. * PHP itself when one of the following functions is called on a stream URL:
  503. *
  504. * @param string $uri
  505. * A string containing the URI to the file to set metadata on.
  506. * @param int $option
  507. * One of:
  508. * - STREAM_META_TOUCH: The method was called in response to touch().
  509. * - STREAM_META_OWNER_NAME: The method was called in response to chown()
  510. * with string parameter.
  511. * - STREAM_META_OWNER: The method was called in response to chown().
  512. * - STREAM_META_GROUP_NAME: The method was called in response to chgrp().
  513. * - STREAM_META_GROUP: The method was called in response to chgrp().
  514. * - STREAM_META_ACCESS: The method was called in response to chmod().
  515. * @param mixed $value
  516. * If option is:
  517. * - STREAM_META_TOUCH: Array consisting of two arguments of the touch()
  518. * function.
  519. * - STREAM_META_OWNER_NAME or STREAM_META_GROUP_NAME: The name of the owner
  520. * user/group as string.
  521. * - STREAM_META_OWNER or STREAM_META_GROUP: The value of the owner
  522. * user/group as integer.
  523. * - STREAM_META_ACCESS: The argument of the chmod() as integer.
  524. *
  525. * @return bool
  526. * Returns TRUE on success or FALSE on failure. If $option is not
  527. * implemented, FALSE should be returned.
  528. *
  529. * @see touch()
  530. * @see chmod()
  531. * @see chown()
  532. * @see chgrp()
  533. * @link http://php.net/manual/streamwrapper.stream-metadata.php
  534. */
  535. public function stream_metadata($uri, $option, $value) {
  536. $target = $this->getLocalPath($uri);
  537. $return = FALSE;
  538. switch ($option) {
  539. case STREAM_META_TOUCH:
  540. if (!empty($value)) {
  541. $return = touch($target, $value[0], $value[1]);
  542. }
  543. else {
  544. $return = touch($target);
  545. }
  546. break;
  547. case STREAM_META_OWNER_NAME:
  548. case STREAM_META_OWNER:
  549. $return = chown($target, $value);
  550. break;
  551. case STREAM_META_GROUP_NAME:
  552. case STREAM_META_GROUP:
  553. $return = chgrp($target, $value);
  554. break;
  555. case STREAM_META_ACCESS:
  556. $return = chmod($target, $value);
  557. break;
  558. }
  559. if ($return) {
  560. // For convenience clear the file status cache of the underlying file,
  561. // since metadata operations are often followed by file status checks.
  562. clearstatcache(TRUE, $target);
  563. }
  564. return $return;
  565. }
  566. /**
  567. * Truncate stream.
  568. *
  569. * Will respond to truncation; e.g., through ftruncate().
  570. *
  571. * @param int $new_size
  572. * The new size.
  573. *
  574. * @return bool
  575. * TRUE on success, FALSE otherwise.
  576. */
  577. public function stream_truncate($new_size) {
  578. return ftruncate($this->handle, $new_size);
  579. }
  580. /**
  581. * Retrieve the underlying stream resource.
  582. *
  583. * This method is called in response to stream_select().
  584. *
  585. * @param int $cast_as
  586. * Can be STREAM_CAST_FOR_SELECT when stream_select() is calling
  587. * stream_cast() or STREAM_CAST_AS_STREAM when stream_cast() is called for
  588. * other uses.
  589. *
  590. * @return resource|false
  591. * The underlying stream resource or FALSE if stream_select() is not
  592. * supported.
  593. *
  594. * @see stream_select()
  595. * @link http://php.net/manual/streamwrapper.stream-cast.php
  596. */
  597. public function stream_cast($cast_as) {
  598. return $this->handle ? $this->handle : FALSE;
  599. }
  600. /**
  601. * Change stream options.
  602. *
  603. * This method is called to set options on the stream.
  604. *
  605. * Since Windows systems do not allow it and it is not needed for most use
  606. * cases anyway, this method is not supported on local files and will trigger
  607. * an error and return false. If needed, custom subclasses can provide
  608. * OS-specific implementations for advanced use cases.
  609. *
  610. * @param int $option
  611. * One of:
  612. * - STREAM_OPTION_BLOCKING: The method was called in response to
  613. * stream_set_blocking().
  614. * - STREAM_OPTION_READ_TIMEOUT: The method was called in response to
  615. * stream_set_timeout().
  616. * - STREAM_OPTION_WRITE_BUFFER: The method was called in response to
  617. * stream_set_write_buffer().
  618. * @param int $arg1
  619. * If option is:
  620. * - STREAM_OPTION_BLOCKING: The requested blocking mode:
  621. * - 1 means blocking.
  622. * - 0 means not blocking.
  623. * - STREAM_OPTION_READ_TIMEOUT: The timeout in seconds.
  624. * - STREAM_OPTION_WRITE_BUFFER: The buffer mode, STREAM_BUFFER_NONE or
  625. * STREAM_BUFFER_FULL.
  626. * @param int $arg2
  627. * If option is:
  628. * - STREAM_OPTION_BLOCKING: This option is not set.
  629. * - STREAM_OPTION_READ_TIMEOUT: The timeout in microseconds.
  630. * - STREAM_OPTION_WRITE_BUFFER: The requested buffer size.
  631. *
  632. * @return bool
  633. * TRUE on success, FALSE otherwise. If $option is not implemented, FALSE
  634. * should be returned.
  635. */
  636. public function stream_set_option($option, $arg1, $arg2) {
  637. trigger_error('stream_set_option() not supported for local file based stream wrappers', E_USER_WARNING);
  638. return FALSE;
  639. }
  640. /**
  641. * Support for unlink().
  642. *
  643. * @param $uri
  644. * A string containing the URI to the resource to delete.
  645. *
  646. * @return
  647. * TRUE if resource was successfully deleted.
  648. *
  649. * @see http://php.net/manual/streamwrapper.unlink.php
  650. */
  651. public function unlink($uri) {
  652. $this->uri = $uri;
  653. return drupal_unlink($this->getLocalPath());
  654. }
  655. /**
  656. * Support for rename().
  657. *
  658. * @param $from_uri,
  659. * The URI to the file to rename.
  660. * @param $to_uri
  661. * The new URI for file.
  662. *
  663. * @return
  664. * TRUE if file was successfully renamed.
  665. *
  666. * @see http://php.net/manual/streamwrapper.rename.php
  667. */
  668. public function rename($from_uri, $to_uri) {
  669. return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri));
  670. }
  671. /**
  672. * Gets the name of the directory from a given path.
  673. *
  674. * This method is usually accessed through drupal_dirname(), which wraps
  675. * around the PHP dirname() function because it does not support stream
  676. * wrappers.
  677. *
  678. * @param $uri
  679. * A URI or path.
  680. *
  681. * @return
  682. * A string containing the directory name.
  683. *
  684. * @see drupal_dirname()
  685. */
  686. public function dirname($uri = NULL) {
  687. list($scheme, $target) = explode('://', $uri, 2);
  688. $target = $this->getTarget($uri);
  689. $dirname = dirname($target);
  690. if ($dirname == '.') {
  691. $dirname = '';
  692. }
  693. return $scheme . '://' . $dirname;
  694. }
  695. /**
  696. * Support for mkdir().
  697. *
  698. * @param $uri
  699. * A string containing the URI to the directory to create.
  700. * @param $mode
  701. * Permission flags - see mkdir().
  702. * @param $options
  703. * A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
  704. *
  705. * @return
  706. * TRUE if directory was successfully created.
  707. *
  708. * @see http://php.net/manual/streamwrapper.mkdir.php
  709. */
  710. public function mkdir($uri, $mode, $options) {
  711. $this->uri = $uri;
  712. $recursive = (bool) ($options & STREAM_MKDIR_RECURSIVE);
  713. if ($recursive) {
  714. // $this->getLocalPath() fails if $uri has multiple levels of directories
  715. // that do not yet exist.
  716. $localpath = $this->getDirectoryPath() . '/' . $this->getTarget($uri);
  717. }
  718. else {
  719. $localpath = $this->getLocalPath($uri);
  720. }
  721. if ($options & STREAM_REPORT_ERRORS) {
  722. return mkdir($localpath, $mode, $recursive);
  723. }
  724. else {
  725. return @mkdir($localpath, $mode, $recursive);
  726. }
  727. }
  728. /**
  729. * Support for rmdir().
  730. *
  731. * @param $uri
  732. * A string containing the URI to the directory to delete.
  733. * @param $options
  734. * A bit mask of STREAM_REPORT_ERRORS.
  735. *
  736. * @return
  737. * TRUE if directory was successfully removed.
  738. *
  739. * @see http://php.net/manual/streamwrapper.rmdir.php
  740. */
  741. public function rmdir($uri, $options) {
  742. $this->uri = $uri;
  743. if ($options & STREAM_REPORT_ERRORS) {
  744. return drupal_rmdir($this->getLocalPath());
  745. }
  746. else {
  747. return @drupal_rmdir($this->getLocalPath());
  748. }
  749. }
  750. /**
  751. * Support for stat().
  752. *
  753. * @param $uri
  754. * A string containing the URI to get information about.
  755. * @param $flags
  756. * A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
  757. *
  758. * @return
  759. * An array with file status, or FALSE in case of an error - see fstat()
  760. * for a description of this array.
  761. *
  762. * @see http://php.net/manual/streamwrapper.url-stat.php
  763. */
  764. public function url_stat($uri, $flags) {
  765. $this->uri = $uri;
  766. $path = $this->getLocalPath();
  767. // Suppress warnings if requested or if the file or directory does not
  768. // exist. This is consistent with PHP's plain filesystem stream wrapper.
  769. if ($flags & STREAM_URL_STAT_QUIET || !file_exists($path)) {
  770. return @stat($path);
  771. }
  772. else {
  773. return stat($path);
  774. }
  775. }
  776. /**
  777. * Support for opendir().
  778. *
  779. * @param $uri
  780. * A string containing the URI to the directory to open.
  781. * @param $options
  782. * Unknown (parameter is not documented in PHP Manual).
  783. *
  784. * @return
  785. * TRUE on success.
  786. *
  787. * @see http://php.net/manual/streamwrapper.dir-opendir.php
  788. */
  789. public function dir_opendir($uri, $options) {
  790. $this->uri = $uri;
  791. $this->handle = opendir($this->getLocalPath());
  792. return (bool) $this->handle;
  793. }
  794. /**
  795. * Support for readdir().
  796. *
  797. * @return
  798. * The next filename, or FALSE if there are no more files in the directory.
  799. *
  800. * @see http://php.net/manual/streamwrapper.dir-readdir.php
  801. */
  802. public function dir_readdir() {
  803. return readdir($this->handle);
  804. }
  805. /**
  806. * Support for rewinddir().
  807. *
  808. * @return
  809. * TRUE on success.
  810. *
  811. * @see http://php.net/manual/streamwrapper.dir-rewinddir.php
  812. */
  813. public function dir_rewinddir() {
  814. rewinddir($this->handle);
  815. // We do not really have a way to signal a failure as rewinddir() does not
  816. // have a return value and there is no way to read a directory handler
  817. // without advancing to the next file.
  818. return TRUE;
  819. }
  820. /**
  821. * Support for closedir().
  822. *
  823. * @return
  824. * TRUE on success.
  825. *
  826. * @see http://php.net/manual/streamwrapper.dir-closedir.php
  827. */
  828. public function dir_closedir() {
  829. closedir($this->handle);
  830. // We do not really have a way to signal a failure as closedir() does not
  831. // have a return value.
  832. return TRUE;
  833. }
  834. }
  835. /**
  836. * Drupal public (public://) stream wrapper class.
  837. *
  838. * Provides support for storing publicly accessible files with the Drupal file
  839. * interface.
  840. */
  841. class DrupalPublicStreamWrapper extends DrupalLocalStreamWrapper {
  842. /**
  843. * Implements abstract public function getDirectoryPath()
  844. */
  845. public function getDirectoryPath() {
  846. return variable_get('file_public_path', conf_path() . '/files');
  847. }
  848. /**
  849. * Overrides getExternalUrl().
  850. *
  851. * Return the HTML URI of a public file.
  852. */
  853. function getExternalUrl() {
  854. $path = str_replace('\\', '/', $this->getTarget());
  855. return $GLOBALS['base_url'] . '/' . self::getDirectoryPath() . '/' . drupal_encode_path($path);
  856. }
  857. }
  858. /**
  859. * Drupal private (private://) stream wrapper class.
  860. *
  861. * Provides support for storing privately accessible files with the Drupal file
  862. * interface.
  863. */
  864. class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
  865. /**
  866. * Implements abstract public function getDirectoryPath()
  867. */
  868. public function getDirectoryPath() {
  869. return variable_get('file_private_path', '');
  870. }
  871. /**
  872. * Overrides getExternalUrl().
  873. *
  874. * Return the HTML URI of a private file.
  875. */
  876. function getExternalUrl() {
  877. $path = str_replace('\\', '/', $this->getTarget());
  878. return url('system/files/' . $path, array('absolute' => TRUE));
  879. }
  880. }
  881. /**
  882. * Drupal temporary (temporary://) stream wrapper class.
  883. *
  884. * Provides support for storing temporarily accessible files with the Drupal
  885. * file interface.
  886. *
  887. * Extends DrupalPublicStreamWrapper.
  888. */
  889. class DrupalTemporaryStreamWrapper extends DrupalLocalStreamWrapper {
  890. /**
  891. * Implements abstract public function getDirectoryPath()
  892. */
  893. public function getDirectoryPath() {
  894. return variable_get('file_temporary_path', file_directory_temp());
  895. }
  896. /**
  897. * Overrides getExternalUrl().
  898. */
  899. public function getExternalUrl() {
  900. $path = str_replace('\\', '/', $this->getTarget());
  901. return url('system/temporary/' . $path, array('absolute' => TRUE));
  902. }
  903. }

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.