FileSystemInterface.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. <?php
  2. namespace Drupal\Core\File;
  3. /**
  4. * Provides an interface for helpers that operate on files and stream wrappers.
  5. */
  6. interface FileSystemInterface {
  7. /**
  8. * Flag for dealing with existing files: Appends number until name is unique.
  9. */
  10. const EXISTS_RENAME = 0;
  11. /**
  12. * Flag for dealing with existing files: Replace the existing file.
  13. */
  14. const EXISTS_REPLACE = 1;
  15. /**
  16. * Flag for dealing with existing files: Do nothing and return FALSE.
  17. */
  18. const EXISTS_ERROR = 2;
  19. /**
  20. * Flag used by ::prepareDirectory() -- create directory if not present.
  21. */
  22. const CREATE_DIRECTORY = 1;
  23. /**
  24. * Flag used by ::prepareDirectory() -- file permissions may be changed.
  25. */
  26. const MODIFY_PERMISSIONS = 2;
  27. /**
  28. * Moves an uploaded file to a new location.
  29. *
  30. * PHP's move_uploaded_file() does not properly support streams if
  31. * open_basedir is enabled, so this function fills that gap.
  32. *
  33. * Compatibility: normal paths and stream wrappers.
  34. *
  35. * @param string $filename
  36. * The filename of the uploaded file.
  37. * @param string $uri
  38. * A string containing the destination URI of the file.
  39. *
  40. * @return bool
  41. * TRUE on success, or FALSE on failure.
  42. *
  43. * @see move_uploaded_file()
  44. * @see https://www.drupal.org/node/515192
  45. * @ingroup php_wrappers
  46. */
  47. public function moveUploadedFile($filename, $uri);
  48. /**
  49. * Sets the permissions on a file or directory.
  50. *
  51. * This function will use the file_chmod_directory and
  52. * file_chmod_file settings for the default modes for directories
  53. * and uploaded/generated files. By default these will give everyone read
  54. * access so that users accessing the files with a user account without the
  55. * webserver group (e.g. via FTP) can read these files, and give group write
  56. * permissions so webserver group members (e.g. a vhost account) can alter
  57. * files uploaded and owned by the webserver.
  58. *
  59. * PHP's chmod does not support stream wrappers so we use our wrapper
  60. * implementation which interfaces with chmod() by default. Contrib wrappers
  61. * may override this behavior in their implementations as needed.
  62. *
  63. * @param string $uri
  64. * A string containing a URI file, or directory path.
  65. * @param int $mode
  66. * Integer value for the permissions. Consult PHP chmod() documentation for
  67. * more information.
  68. *
  69. * @return bool
  70. * TRUE for success, FALSE in the event of an error.
  71. *
  72. * @ingroup php_wrappers
  73. */
  74. public function chmod($uri, $mode = NULL);
  75. /**
  76. * Deletes a file.
  77. *
  78. * PHP's unlink() is broken on Windows, as it can fail to remove a file when
  79. * it has a read-only flag set.
  80. *
  81. * @param string $uri
  82. * A URI or pathname.
  83. * @param resource $context
  84. * Refer to http://php.net/manual/ref.stream.php
  85. *
  86. * @return bool
  87. * Boolean TRUE on success, or FALSE on failure.
  88. *
  89. * @see unlink()
  90. * @ingroup php_wrappers
  91. */
  92. public function unlink($uri, $context = NULL);
  93. /**
  94. * Resolves the absolute filepath of a local URI or filepath.
  95. *
  96. * The use of this method is discouraged, because it does not work for
  97. * remote URIs. Except in rare cases, URIs should not be manually resolved.
  98. *
  99. * Only use this function if you know that the stream wrapper in the URI uses
  100. * the local file system, and you need to pass an absolute path to a function
  101. * that is incompatible with stream URIs.
  102. *
  103. * @param string $uri
  104. * A stream wrapper URI or a filepath, possibly including one or more
  105. * symbolic links.
  106. *
  107. * @return string|false
  108. * The absolute local filepath (with no symbolic links) or FALSE on failure.
  109. *
  110. * @see \Drupal\Core\StreamWrapper\StreamWrapperInterface::realpath()
  111. * @see http://php.net/manual/function.realpath.php
  112. * @ingroup php_wrappers
  113. */
  114. public function realpath($uri);
  115. /**
  116. * Gets the name of the directory from a given path.
  117. *
  118. * PHP's dirname() does not properly pass streams, so this function fills that
  119. * gap. It is backwards compatible with normal paths and will use PHP's
  120. * dirname() as a fallback.
  121. *
  122. * Compatibility: normal paths and stream wrappers.
  123. *
  124. * @param string $uri
  125. * A URI or path.
  126. *
  127. * @return string
  128. * A string containing the directory name.
  129. *
  130. * @see dirname()
  131. * @see https://www.drupal.org/node/515192
  132. * @ingroup php_wrappers
  133. */
  134. public function dirname($uri);
  135. /**
  136. * Gets the filename from a given path.
  137. *
  138. * PHP's basename() does not properly support streams or filenames beginning
  139. * with a non-US-ASCII character.
  140. *
  141. * @see http://bugs.php.net/bug.php?id=37738
  142. * @see basename()
  143. *
  144. * @ingroup php_wrappers
  145. */
  146. public function basename($uri, $suffix = NULL);
  147. /**
  148. * Creates a directory, optionally creating missing components in the path to
  149. * the directory.
  150. *
  151. * When PHP's mkdir() creates a directory, the requested mode is affected by
  152. * the process's umask. This function overrides the umask and sets the mode
  153. * explicitly for all directory components created.
  154. *
  155. * @param string $uri
  156. * A URI or pathname.
  157. * @param int $mode
  158. * Mode given to created directories. Defaults to the directory mode
  159. * configured in the Drupal installation. It must have a leading zero.
  160. * @param bool $recursive
  161. * Create directories recursively, defaults to FALSE. Cannot work with a
  162. * mode which denies writing or execution to the owner of the process.
  163. * @param resource $context
  164. * Refer to http://php.net/manual/ref.stream.php
  165. *
  166. * @return bool
  167. * Boolean TRUE on success, or FALSE on failure.
  168. *
  169. * @see mkdir()
  170. * @see https://www.drupal.org/node/515192
  171. * @ingroup php_wrappers
  172. *
  173. * @todo Update with open_basedir compatible recursion logic from
  174. * \Drupal\Component\PhpStorage\FileStorage::ensureDirectory().
  175. */
  176. public function mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL);
  177. /**
  178. * Removes a directory.
  179. *
  180. * PHP's rmdir() is broken on Windows, as it can fail to remove a directory
  181. * when it has a read-only flag set.
  182. *
  183. * @param string $uri
  184. * A URI or pathname.
  185. * @param resource $context
  186. * Refer to http://php.net/manual/ref.stream.php
  187. *
  188. * @return bool
  189. * Boolean TRUE on success, or FALSE on failure.
  190. *
  191. * @see rmdir()
  192. * @ingroup php_wrappers
  193. */
  194. public function rmdir($uri, $context = NULL);
  195. /**
  196. * Creates a file with a unique filename in the specified directory.
  197. *
  198. * PHP's tempnam() does not return a URI like we want. This function will
  199. * return a URI if given a URI, or it will return a filepath if given a
  200. * filepath.
  201. *
  202. * Compatibility: normal paths and stream wrappers.
  203. *
  204. * @param string $directory
  205. * The directory where the temporary filename will be created.
  206. * @param string $prefix
  207. * The prefix of the generated temporary filename.
  208. * Note: Windows uses only the first three characters of prefix.
  209. *
  210. * @return string|bool
  211. * The new temporary filename, or FALSE on failure.
  212. *
  213. * @see tempnam()
  214. * @see https://www.drupal.org/node/515192
  215. * @ingroup php_wrappers
  216. */
  217. public function tempnam($directory, $prefix);
  218. /**
  219. * Returns the scheme of a URI (e.g. a stream).
  220. *
  221. * @param string $uri
  222. * A stream, referenced as "scheme://target" or "data:target".
  223. *
  224. * @return string|bool
  225. * A string containing the name of the scheme, or FALSE if none. For
  226. * example, the URI "public://example.txt" would return "public".
  227. *
  228. * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use
  229. * Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getScheme()
  230. * instead.
  231. *
  232. * @see https://www.drupal.org/node/3035273
  233. */
  234. public function uriScheme($uri);
  235. /**
  236. * Checks that the scheme of a stream URI is valid.
  237. *
  238. * Confirms that there is a registered stream handler for the provided scheme
  239. * and that it is callable. This is useful if you want to confirm a valid
  240. * scheme without creating a new instance of the registered handler.
  241. *
  242. * @param string $scheme
  243. * A URI scheme, a stream is referenced as "scheme://target".
  244. *
  245. * @return bool
  246. * Returns TRUE if the string is the name of a validated stream, or FALSE if
  247. * the scheme does not have a registered handler.
  248. *
  249. * @deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use
  250. * Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidScheme()
  251. * instead.
  252. *
  253. * @see https://www.drupal.org/node/3035273
  254. */
  255. public function validScheme($scheme);
  256. /**
  257. * Copies a file to a new location without invoking the file API.
  258. *
  259. * This is a powerful function that in many ways performs like an advanced
  260. * version of copy().
  261. * - Checks if $source and $destination are valid and readable/writable.
  262. * - If file already exists in $destination either the call will error out,
  263. * replace the file or rename the file based on the $replace parameter.
  264. * - If the $source and $destination are equal, the behavior depends on the
  265. * $replace parameter. FileSystemInterface::EXISTS_REPLACE will replace the
  266. * existing file. FileSystemInterface::EXISTS_ERROR will error out.
  267. * FileSystemInterface::EXISTS_RENAME will rename the file until the
  268. * $destination is unique.
  269. * - Provides a fallback using realpaths if the move fails using stream
  270. * wrappers. This can occur because PHP's copy() function does not properly
  271. * support streams if open_basedir is enabled. See
  272. * https://bugs.php.net/bug.php?id=60456
  273. *
  274. * @param string $source
  275. * A string specifying the filepath or URI of the source file.
  276. * @param string $destination
  277. * A URI containing the destination that $source should be copied to. The
  278. * URI may be a bare filepath (without a scheme).
  279. * @param int $replace
  280. * Replace behavior when the destination file already exists:
  281. * - FileSystemInterface::EXISTS_REPLACE - Replace the existing file.
  282. * - FileSystemInterface::EXISTS_RENAME - Append _{incrementing number}
  283. * until the filename is unique.
  284. * - FileSystemInterface::EXISTS_ERROR - Throw an exception.
  285. *
  286. * @return string
  287. * The path to the new file.
  288. *
  289. * @throws \Drupal\Core\File\Exception\FileException
  290. * Implementation may throw FileException or its subtype on failure.
  291. */
  292. public function copy($source, $destination, $replace = self::EXISTS_RENAME);
  293. /**
  294. * Deletes a file without database changes or hook invocations.
  295. *
  296. * This function should be used when the file to be deleted does not have an
  297. * entry recorded in the files table.
  298. *
  299. * @param string $path
  300. * A string containing a file path or (streamwrapper) URI.
  301. *
  302. * @throws \Drupal\Core\File\Exception\FileException
  303. * Implementation may throw FileException or its subtype on failure.
  304. */
  305. public function delete($path);
  306. /**
  307. * Deletes all files and directories in the specified filepath recursively.
  308. *
  309. * If the specified path is a directory then the function is called
  310. * recursively to process the contents. Once the contents have been removed
  311. * the directory is also removed.
  312. *
  313. * If the specified path is a file then it will be processed with delete()
  314. * method.
  315. *
  316. * Note that this only deletes visible files with write permission.
  317. *
  318. * @param string $path
  319. * A string containing either an URI or a file or directory path.
  320. * @param callable|null $callback
  321. * Callback function to run on each file prior to deleting it and on each
  322. * directory prior to traversing it. For example, can be used to modify
  323. * permissions.
  324. *
  325. * @throws \Drupal\Core\File\Exception\FileException
  326. * Implementation may throw FileException or its subtype on failure.
  327. */
  328. public function deleteRecursive($path, callable $callback = NULL);
  329. /**
  330. * Moves a file to a new location without database changes or hook invocation.
  331. *
  332. * This is a powerful function that in many ways performs like an advanced
  333. * version of rename().
  334. * - Checks if $source and $destination are valid and readable/writable.
  335. * - Checks that $source is not equal to $destination; if they are an error
  336. * is reported.
  337. * - If file already exists in $destination either the call will error out,
  338. * replace the file or rename the file based on the $replace parameter.
  339. * - Works around a PHP bug where rename() does not properly support streams
  340. * if safe_mode or open_basedir are enabled.
  341. *
  342. * @param string $source
  343. * A string specifying the filepath or URI of the source file.
  344. * @param string $destination
  345. * A URI containing the destination that $source should be moved to. The
  346. * URI may be a bare filepath (without a scheme) and in that case the
  347. * default scheme (public://) will be used.
  348. * @param int $replace
  349. * Replace behavior when the destination file already exists:
  350. * - FileSystemInterface::EXISTS_REPLACE - Replace the existing file.
  351. * - FileSystemInterface::EXISTS_RENAME - Append _{incrementing number}
  352. * until the filename is unique.
  353. * - FileSystemInterface::EXISTS_ERROR - Do nothing and return FALSE.
  354. *
  355. * @return string
  356. * The path to the new file.
  357. *
  358. * @throws \Drupal\Core\File\Exception\FileException
  359. * Implementation may throw FileException or its subtype on failure.
  360. *
  361. * @see https://bugs.php.net/bug.php?id=60456
  362. */
  363. public function move($source, $destination, $replace = self::EXISTS_RENAME);
  364. /**
  365. * Saves a file to the specified destination without invoking file API.
  366. *
  367. * This function is identical to file_save_data() except the file will not be
  368. * saved to the {file_managed} table and none of the file_* hooks will be
  369. * called.
  370. *
  371. * @param string $data
  372. * A string containing the contents of the file.
  373. * @param string $destination
  374. * A string containing the destination location. This must be a stream
  375. * wrapper URI.
  376. * @param int $replace
  377. * Replace behavior when the destination file already exists:
  378. * - FileSystemInterface::EXISTS_REPLACE - Replace the existing file.
  379. * - FileSystemInterface::EXISTS_RENAME - Append _{incrementing number}
  380. * until the filename is unique.
  381. * - FileSystemInterface::EXISTS_ERROR - Do nothing and return FALSE.
  382. *
  383. * @return string
  384. * A string with the path of the resulting file, or FALSE on error.
  385. *
  386. * @throws \Drupal\Core\File\Exception\FileException
  387. * Implementation may throw FileException or its subtype on failure.
  388. *
  389. * @see file_save_data()
  390. */
  391. public function saveData($data, $destination, $replace = self::EXISTS_RENAME);
  392. /**
  393. * Checks that the directory exists and is writable.
  394. *
  395. * Directories need to have execute permissions to be considered a directory
  396. * by FTP servers, etc.
  397. *
  398. * @param string $directory
  399. * A string reference containing the name of a directory path or URI. A
  400. * trailing slash will be trimmed from a path.
  401. * @param int $options
  402. * A bitmask to indicate if the directory should be created if it does
  403. * not exist (FileSystemInterface::CREATE_DIRECTORY) or made writable if it
  404. * is read-only (FileSystemInterface::MODIFY_PERMISSIONS).
  405. *
  406. * @return bool
  407. * TRUE if the directory exists (or was created) and is writable. FALSE
  408. * otherwise.
  409. */
  410. public function prepareDirectory(&$directory, $options = self::MODIFY_PERMISSIONS);
  411. /**
  412. * Creates a full file path from a directory and filename.
  413. *
  414. * If a file with the specified name already exists, an alternative will be
  415. * used.
  416. *
  417. * @param string $basename
  418. * The filename.
  419. * @param string $directory
  420. * The directory or parent URI.
  421. *
  422. * @return string
  423. * File path consisting of $directory and a unique filename based off
  424. * of $basename.
  425. *
  426. * @throws \Drupal\Core\File\Exception\FileException
  427. * Implementation may throw FileException or its subtype on failure.
  428. */
  429. public function createFilename($basename, $directory);
  430. /**
  431. * Determines the destination path for a file.
  432. *
  433. * @param string $destination
  434. * The desired final URI or filepath.
  435. * @param int $replace
  436. * Replace behavior when the destination file already exists.
  437. * - FileSystemInterface::EXISTS_REPLACE - Replace the existing file.
  438. * - FileSystemInterface::EXISTS_RENAME - Append _{incrementing number}
  439. * until the filename is unique.
  440. * - FileSystemInterface::EXISTS_ERROR - Do nothing and return FALSE.
  441. *
  442. * @return string|bool
  443. * The destination filepath, or FALSE if the file already exists
  444. * and FileSystemInterface::EXISTS_ERROR is specified.
  445. *
  446. * @throws \Drupal\Core\File\Exception\FileException
  447. * Implementation may throw FileException or its subtype on failure.
  448. */
  449. public function getDestinationFilename($destination, $replace);
  450. /**
  451. * Gets the path of the configured temporary directory.
  452. *
  453. * If the path is not set, it will fall back to the OS-specific default if
  454. * set, otherwise a directory under the public files directory. It will then
  455. * set this as the configured directory.
  456. *
  457. * @return string
  458. * A string containing the path to the temporary directory.
  459. */
  460. public function getTempDirectory();
  461. /**
  462. * Finds all files that match a given mask in a given directory.
  463. *
  464. * Directories and files beginning with a dot are excluded; this prevents
  465. * hidden files and directories (such as SVN working directories) from being
  466. * scanned. Use the umask option to skip configuration directories to
  467. * eliminate the possibility of accidentally exposing configuration
  468. * information. Also, you can use the base directory, recurse, and min_depth
  469. * options to improve performance by limiting how much of the filesystem has
  470. * to be traversed.
  471. *
  472. * @param string $dir
  473. * The base directory or URI to scan, without trailing slash.
  474. * @param string $mask
  475. * The preg_match() regular expression for files to be included.
  476. * @param array $options
  477. * An associative array of additional options, with the following elements:
  478. * - 'nomask': The preg_match() regular expression for files to be excluded.
  479. * Defaults to the 'file_scan_ignore_directories' setting.
  480. * - 'callback': The callback function to call for each match. There is no
  481. * default callback.
  482. * - 'recurse': When TRUE, the directory scan will recurse the entire tree
  483. * starting at the provided directory. Defaults to TRUE.
  484. * - 'key': The key to be used for the returned associative array of files.
  485. * Possible values are 'uri', for the file's URI; 'filename', for the
  486. * basename of the file; and 'name' for the name of the file without the
  487. * extension. Defaults to 'uri'.
  488. * - 'min_depth': Minimum depth of directories to return files from.
  489. * Defaults to 0.
  490. *
  491. * @return array
  492. * An associative array (keyed on the chosen key) of objects with 'uri',
  493. * 'filename', and 'name' properties corresponding to the matched files.
  494. *
  495. * @throws \Drupal\Core\File\Exception\NotRegularDirectoryException
  496. * If the directory does not exist.
  497. */
  498. public function scanDirectory($dir, $mask, array $options = []);
  499. }