stream_wrappers.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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/en/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. * Extends DrupalPublicStreamWrapper.
  723. */
  724. class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
  725. /**
  726. * Implements abstract public function getDirectoryPath()
  727. */
  728. public function getDirectoryPath() {
  729. return variable_get('file_private_path', '');
  730. }
  731. /**
  732. * Overrides getExternalUrl().
  733. *
  734. * Return the HTML URI of a private file.
  735. */
  736. function getExternalUrl() {
  737. $path = str_replace('\\', '/', $this->getTarget());
  738. return url('system/files/' . $path, array('absolute' => TRUE));
  739. }
  740. }
  741. /**
  742. * Drupal temporary (temporary://) stream wrapper class.
  743. *
  744. * Provides support for storing temporarily accessible files with the Drupal
  745. * file interface.
  746. *
  747. * Extends DrupalPublicStreamWrapper.
  748. */
  749. class DrupalTemporaryStreamWrapper extends DrupalLocalStreamWrapper {
  750. /**
  751. * Implements abstract public function getDirectoryPath()
  752. */
  753. public function getDirectoryPath() {
  754. return variable_get('file_temporary_path', file_directory_temp());
  755. }
  756. /**
  757. * Overrides getExternalUrl().
  758. */
  759. public function getExternalUrl() {
  760. $path = str_replace('\\', '/', $this->getTarget());
  761. return url('system/temporary/' . $path, array('absolute' => TRUE));
  762. }
  763. }