filebackend: use self:: instead of FileBackend:: for some constant uses
[lhc/web/wiklou.git] / includes / libs / filebackend / FileBackend.php
index 4cacb7a..6ab1707 100644 (file)
@@ -131,6 +131,29 @@ abstract class FileBackend implements LoggerAwareInterface {
        const ATTR_METADATA = 2; // files can be stored with metadata key/values
        const ATTR_UNICODE_PATHS = 4; // files can have Unicode paths (not just ASCII)
 
+       /** @var false Idiom for "no info; non-existant file" (since 1.34) */
+       const STAT_ABSENT = false;
+
+       /** @var null Idiom for "no info; I/O errors" (since 1.34) */
+       const STAT_ERROR = null;
+       /** @var null Idiom for "no file/directory list; I/O errors" (since 1.34) */
+       const LIST_ERROR = null;
+       /** @var null Idiom for "no temp URL; not supported or I/O errors" (since 1.34) */
+       const TEMPURL_ERROR = null;
+       /** @var null Idiom for "existence unknown; I/O errors" (since 1.34) */
+       const EXISTENCE_ERROR = null;
+
+       /** @var false Idiom for "no timestamp; missing file or I/O errors" (since 1.34) */
+       const TIMESTAMP_FAIL = false;
+       /** @var false Idiom for "no content; missing file or I/O errors" (since 1.34) */
+       const CONTENT_FAIL = false;
+       /** @var false Idiom for "no metadata; missing file or I/O errors" (since 1.34) */
+       const XATTRS_FAIL = false;
+       /** @var false Idiom for "no size; missing file or I/O errors" (since 1.34) */
+       const SIZE_FAIL = false;
+       /** @var false Idiom for "no SHA1 hash; missing file or I/O errors" (since 1.34) */
+       const SHA1_FAIL = false;
+
        /**
         * Create a new backend instance from configuration.
         * This should only be called from within FileBackendGroup.
@@ -154,9 +177,9 @@ abstract class FileBackend implements LoggerAwareInterface {
         *      Allowed values are "implicit", "explicit" and "off".
         *   - concurrency : How many file operations can be done in parallel.
         *   - tmpDirectory : Directory to use for temporary files.
-        *   - tmpFileFactory : Optional TempFSFileFactory object. Only has an effect if tmpDirectory is
-        *      not set. If both are unset or null, then the backend will try to discover a usable
-        *      temporary directory.
+        *   - tmpFileFactory : Optional TempFSFileFactory object. Only has an effect if
+        *      tmpDirectory is not set. If both are unset or null, then the backend will
+        *      try to discover a usable temporary directory.
         *   - obResetFunc : alternative callback to clear the output buffer
         *   - streamMimeFunc : alternative method to determine the content type from the path
         *   - logger : Optional PSR logger object.
@@ -209,7 +232,8 @@ abstract class FileBackend implements LoggerAwareInterface {
        }
 
        /**
-        * Get the unique backend name.
+        * Get the unique backend name
+        *
         * We may have multiple different backends of the same type.
         * For example, we can have two Swift backends using different proxies.
         *
@@ -231,6 +255,7 @@ abstract class FileBackend implements LoggerAwareInterface {
 
        /**
         * Alias to getDomainId()
+        *
         * @return string
         * @since 1.20
         * @deprecated Since 1.34 Use getDomainId()
@@ -423,7 +448,11 @@ abstract class FileBackend implements LoggerAwareInterface {
         *   - b) predicted operation errors occurred and 'force' was not set
         *
         * @param array $ops List of operations to execute in order
+        * @codingStandardsIgnoreStart
+        * @phan-param array{ignoreMissingSource?:bool,overwrite?:bool,overwriteSame?:bool,headers?:bool} $ops
         * @param array $opts Batch operation options
+        * @phan-param array{force?:bool,nonLocking?:bool,nonJournaled?:bool,parallelize?:bool,bypassReadOnly?:bool,preserveCache?:bool} $opts
+        * @codingStandardsIgnoreEnd
         * @return StatusValue
         */
        final public function doOperations( array $ops, array $opts = [] ) {
@@ -661,7 +690,9 @@ abstract class FileBackend implements LoggerAwareInterface {
         * considered "OK" as long as no fatal errors occurred.
         *
         * @param array $ops Set of operations to execute
+        * @phan-param array{ignoreMissingSource?:bool,headers?:bool} $ops
         * @param array $opts Batch operation options
+        * @phan-param array{bypassReadOnly?:bool} $opts
         * @return StatusValue
         * @since 1.20
         */
@@ -935,20 +966,29 @@ abstract class FileBackend implements LoggerAwareInterface {
         * Check if a file exists at a storage path in the backend.
         * This returns false if only a directory exists at the path.
         *
+        * Callers that only care if a file is readily accessible can use non-strict
+        * comparisons on the result. If "does not exist" and "existence is unknown"
+        * must be distinguished, then strict comparisons to true/null should be used.
+        *
+        * @see FileBackend::EXISTENCE_ERROR
+        * @see FileBackend::directoryExists()
+        *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return bool|null Returns null on failure
+        * @return bool|null Whether the file exists or null (I/O error)
         */
        abstract public function fileExists( array $params );
 
        /**
         * Get the last-modified timestamp of the file at a storage path.
         *
+        * @see FileBackend::TIMESTAMP_FAIL
+        *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return string|bool TS_MW timestamp or false on failure
+        * @return string|false TS_MW timestamp or false (missing file or I/O error)
         */
        abstract public function getFileTimestamp( array $params );
 
@@ -956,22 +996,22 @@ abstract class FileBackend implements LoggerAwareInterface {
         * Get the contents of a file at a storage path in the backend.
         * This should be avoided for potentially large files.
         *
+        * @see FileBackend::CONTENT_FAIL
+        *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return string|bool Returns false on failure
+        * @return string|false Content string or false (missing file or I/O error)
         */
        final public function getFileContents( array $params ) {
-               $contents = $this->getFileContentsMulti(
-                       [ 'srcs' => [ $params['src'] ] ] + $params );
+               $contents = $this->getFileContentsMulti( [ 'srcs' => [ $params['src'] ] ] + $params );
 
                return $contents[$params['src']];
        }
 
        /**
         * Like getFileContents() except it takes an array of storage paths
-        * and returns a map of storage paths to strings (or null on failure).
-        * The map keys (paths) are in the same order as the provided list of paths.
+        * and returns an order preserved map of storage paths to their content.
         *
         * @see FileBackend::getFileContents()
         *
@@ -979,7 +1019,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         *   - srcs        : list of source storage paths
         *   - latest      : use the latest available data
         *   - parallelize : try to do operations in parallel when possible
-        * @return array Map of (path name => string or false on failure)
+        * @return string[]|false[] Map of (path name => file content or false on failure)
         * @since 1.20
         */
        abstract public function getFileContentsMulti( array $params );
@@ -995,11 +1035,13 @@ abstract class FileBackend implements LoggerAwareInterface {
         *
         * Use FileBackend::hasFeatures() to check how well this is supported.
         *
+        * @see FileBackend::XATTRS_FAIL
+        *
         * @param array $params
         * $params include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return array|bool Returns false on failure
+        * @return array|false File metadata array or false (missing file or I/O error)
         * @since 1.23
         */
        abstract public function getFileXAttributes( array $params );
@@ -1007,10 +1049,12 @@ abstract class FileBackend implements LoggerAwareInterface {
        /**
         * Get the size (bytes) of a file at a storage path in the backend.
         *
+        * @see FileBackend::SIZE_FAIL
+        *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return int|bool Returns false on failure
+        * @return int|false File size in bytes or false (missing file or I/O error)
         */
        abstract public function getFileSize( array $params );
 
@@ -1022,36 +1066,41 @@ abstract class FileBackend implements LoggerAwareInterface {
         *   - size   : the file size (bytes)
         * Additional values may be included for internal use only.
         *
+        * @see FileBackend::STAT_ABSENT
+        * @see FileBackend::STAT_ERROR
+        *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return array|bool|null Returns null on failure
+        * @return array|false|null Attribute map, false (missing file), or null (I/O error)
         */
        abstract public function getFileStat( array $params );
 
        /**
-        * Get a SHA-1 hash of the file at a storage path in the backend.
+        * Get a SHA-1 hash of the content of the file at a storage path in the backend.
+        *
+        * @see FileBackend::SHA1_FAIL
         *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return string|bool Hash string or false on failure
+        * @return string|false Hash string or false (missing file or I/O error)
         */
        abstract public function getFileSha1Base36( array $params );
 
        /**
-        * Get the properties of the file at a storage path in the backend.
+        * Get the properties of the content of the file at a storage path in the backend.
         * This gives the result of FSFile::getProps() on a local copy of the file.
         *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return array Returns FSFile::placeholderProps() on failure
+        * @return array Properties map; FSFile::placeholderProps() if file missing or on I/O error
         */
        abstract public function getFileProps( array $params );
 
        /**
-        * Stream the file at a storage path in the backend.
+        * Stream the content of the file at a storage path in the backend.
         *
         * If the file does not exists, an HTTP 404 error will be given.
         * Appropriate HTTP headers (Status, Content-Type, Content-Length)
@@ -1072,34 +1121,36 @@ abstract class FileBackend implements LoggerAwareInterface {
        abstract public function streamFile( array $params );
 
        /**
-        * Returns a file system file, identical to the file at a storage path.
+        * Returns a file system file, identical in content to the file at a storage path.
         * The file returned is either:
-        *   - a) A local copy of the file at a storage path in the backend.
+        *   - a) A TempFSFile local copy of the file at a storage path in the backend.
         *        The temporary copy will have the same extension as the source.
-        *   - b) An original of the file at a storage path in the backend.
-        * Temporary files may be purged when the file object falls out of scope.
+        *        Temporary files may be purged when the file object falls out of scope.
+        *   - b) An FSFile pointing to the original file at a storage path in the backend.
+        *        This is applicable for backends layered directly on top of file systems.
         *
-        * Write operations should *never* be done on this file as some backends
-        * may do internal tracking or may be instances of FileBackendMultiWrite.
-        * In that latter case, there are copies of the file that must stay in sync.
-        * Additionally, further calls to this function may return the same file.
+        * Never modify the returned file since it might be the original, it might be shared
+        * among multiple callers of this method, or the backend might internally keep FSFile
+        * references for deferred operations.
         *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return FSFile|null Returns null on failure
+        * @return FSFile|null Local file copy or null (missing file or I/O error)
         */
        final public function getLocalReference( array $params ) {
-               $fsFiles = $this->getLocalReferenceMulti(
-                       [ 'srcs' => [ $params['src'] ] ] + $params );
+               $fsFiles = $this->getLocalReferenceMulti( [ 'srcs' => [ $params['src'] ] ] + $params );
 
                return $fsFiles[$params['src']];
        }
 
        /**
-        * Like getLocalReference() except it takes an array of storage paths
-        * and returns a map of storage paths to FSFile objects (or null on failure).
-        * The map keys (paths) are in the same order as the provided list of paths.
+        * Like getLocalReference() except it takes an array of storage paths and
+        * yields an order-preserved map of storage paths to temporary local file copies.
+        *
+        * Never modify the returned files since they might be originals, they might be shared
+        * among multiple callers of this method, or the backend might internally keep FSFile
+        * references for deferred operations.
         *
         * @see FileBackend::getLocalReference()
         *
@@ -1117,22 +1168,24 @@ abstract class FileBackend implements LoggerAwareInterface {
         * The temporary copy will have the same file extension as the source.
         * Temporary files may be purged when the file object falls out of scope.
         *
+        * Multiple calls to this method for the same path will create new copies.
+        *
         * @param array $params Parameters include:
         *   - src    : source storage path
         *   - latest : use the latest available data
-        * @return TempFSFile|null Returns null on failure
+        * @return TempFSFile|null Temporary local file copy or null (missing file or I/O error)
         */
        final public function getLocalCopy( array $params ) {
-               $tmpFiles = $this->getLocalCopyMulti(
-                       [ 'srcs' => [ $params['src'] ] ] + $params );
+               $tmpFiles = $this->getLocalCopyMulti( [ 'srcs' => [ $params['src'] ] ] + $params );
 
                return $tmpFiles[$params['src']];
        }
 
        /**
-        * Like getLocalCopy() except it takes an array of storage paths and
-        * returns a map of storage paths to TempFSFile objects (or null on failure).
-        * The map keys (paths) are in the same order as the provided list of paths.
+        * Like getLocalCopy() except it takes an array of storage paths and yields
+        * an order preserved-map of storage paths to temporary local file copies.
+        *
+        * Multiple calls to this method for the same path will create new copies.
         *
         * @see FileBackend::getLocalCopy()
         *
@@ -1155,30 +1208,46 @@ abstract class FileBackend implements LoggerAwareInterface {
         * Otherwise, one would need to use getLocalReference(), which involves loading
         * the entire file on to local disk.
         *
+        * @see FileBackend::TEMPURL_ERROR
+        *
         * @param array $params Parameters include:
         *   - src : source storage path
         *   - ttl : lifetime (seconds) if pre-authenticated; default is 1 day
-        * @return string|null
+        * @return string|null URL or null (not supported or I/O error)
         * @since 1.21
         */
        abstract public function getFileHttpUrl( array $params );
 
        /**
-        * Check if a directory exists at a given storage path.
-        * Backends using key/value stores will check if the path is a
-        * virtual directory, meaning there are files under the given directory.
+        * Check if a directory exists at a given storage path
+        *
+        * For backends using key/value stores, a directory is said to exist whenever
+        * there exist any files with paths using the given directory path as a prefix
+        * followed by a forward slash. For example, if there is a file called
+        * "mwstore://backend/container/dir/path.svg" then directories are said to exist
+        * at "mwstore://backend/container" and "mwstore://backend/container/dir". These
+        * can be thought of as "virtual" directories.
+        *
+        * Backends that directly use a filesystem layer might enumerate empty directories.
+        * The clean() method should always be used when files are deleted or moved if this
+        * is a concern. This is a trade-off to avoid write amplication/contention on file
+        * changes or read amplification when calling this method.
         *
         * Storage backends with eventual consistency might return stale data.
         *
+        * @see FileBackend::EXISTENCE_ERROR
+        * @see FileBackend::clean()
+        *
         * @param array $params Parameters include:
         *   - dir : storage directory
-        * @return bool|null Returns null on failure
+        * @return bool|null Whether a directory exists or null (I/O error)
         * @since 1.20
         */
        abstract public function directoryExists( array $params );
 
        /**
-        * Get an iterator to list *all* directories under a storage directory.
+        * Get an iterator to list *all* directories under a storage directory
+        *
         * If the directory is of the form "mwstore://backend/container",
         * then all directories in the container will be listed.
         * If the directory is of form "mwstore://backend/container/dir",
@@ -1189,10 +1258,13 @@ abstract class FileBackend implements LoggerAwareInterface {
         *
         * Failures during iteration can result in FileBackendError exceptions (since 1.22).
         *
+        * @see FileBackend::LIST_ERROR
+        * @see FileBackend::directoryExists()
+        *
         * @param array $params Parameters include:
         *   - dir     : storage directory
         *   - topOnly : only return direct child dirs of the directory
-        * @return Traversable|array|null Returns null on failure
+        * @return Traversable|array|null Directory list enumerator or null (initial I/O error)
         * @since 1.20
         */
        abstract public function getDirectoryList( array $params );
@@ -1205,9 +1277,12 @@ abstract class FileBackend implements LoggerAwareInterface {
         *
         * Failures during iteration can result in FileBackendError exceptions (since 1.22).
         *
+        * @see FileBackend::LIST_ERROR
+        * @see FileBackend::directoryExists()
+        *
         * @param array $params Parameters include:
         *   - dir : storage directory
-        * @return Traversable|array|null Returns null on failure
+        * @return Traversable|array|null Directory list enumerator or null (initial I/O error)
         * @since 1.20
         */
        final public function getTopDirectoryList( array $params ) {
@@ -1215,22 +1290,24 @@ abstract class FileBackend implements LoggerAwareInterface {
        }
 
        /**
-        * Get an iterator to list *all* stored files under a storage directory.
-        * If the directory is of the form "mwstore://backend/container",
-        * then all files in the container will be listed.
-        * If the directory is of form "mwstore://backend/container/dir",
-        * then all files under that directory will be listed.
-        * Results will be storage paths relative to the given directory.
+        * Get an iterator to list *all* stored files under a storage directory
+        *
+        * If the directory is of the form "mwstore://backend/container", then all
+        * files in the container will be listed. If the directory is of form
+        * "mwstore://backend/container/dir", then all files under that directory will
+        * be listed. Results will be storage paths relative to the given directory.
         *
         * Storage backends with eventual consistency might return stale data.
         *
         * Failures during iteration can result in FileBackendError exceptions (since 1.22).
         *
+        * @see FileBackend::LIST_ERROR
+        *
         * @param array $params Parameters include:
         *   - dir        : storage directory
         *   - topOnly    : only return direct child files of the directory (since 1.20)
         *   - adviseStat : set to true if stat requests will be made on the files (since 1.22)
-        * @return Traversable|array|null Returns null on failure
+        * @return Traversable|array|null File list enumerator or null (initial I/O error)
         */
        abstract public function getFileList( array $params );
 
@@ -1242,10 +1319,12 @@ abstract class FileBackend implements LoggerAwareInterface {
         *
         * Failures during iteration can result in FileBackendError exceptions (since 1.22).
         *
+        * @see FileBackend::LIST_ERROR
+        *
         * @param array $params Parameters include:
         *   - dir        : storage directory
         *   - adviseStat : set to true if stat requests will be made on the files (since 1.22)
-        * @return Traversable|array|null Returns null on failure
+        * @return Traversable|array|null File list enumerator or null on failure
         * @since 1.20
         */
        final public function getTopFileList( array $params ) {
@@ -1283,7 +1362,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         * @param array $params Parameters include:
         *   - srcs        : list of source storage paths
         *   - latest      : use the latest available data
-        * @return bool All requests proceeded without I/O errors (since 1.24)
+        * @return bool Whether all requests proceeded without I/O errors (since 1.24)
         * @since 1.23
         */
        abstract public function preloadFileStat( array $params );
@@ -1332,7 +1411,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         * @param int|string $type LockManager::LOCK_* constant or "mixed"
         * @param StatusValue $status StatusValue to update on lock/unlock
         * @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.24)
-        * @return ScopedLock|null Returns null on failure
+        * @return ScopedLock|null RAII-style self-unlocking lock or null on failure
         */
        final public function getScopedFileLocks(
                array $paths, $type, StatusValue $status, $timeout = 0
@@ -1361,7 +1440,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         *
         * @param array $ops List of file operations to FileBackend::doOperations()
         * @param StatusValue $status StatusValue to update on lock/unlock
-        * @return ScopedLock|null
+        * @return ScopedLock|null RAII-style self-unlocking lock or null on failure
         * @since 1.20
         */
        abstract public function getScopedLocksForOps( array $ops, StatusValue $status );
@@ -1459,7 +1538,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         * Returns null if the path is not of the format of a valid storage path.
         *
         * @param string $storagePath
-        * @return string|null
+        * @return string|null Normalized storage path or null on failure
         */
        final public static function normalizeStoragePath( $storagePath ) {
                list( $backend, $container, $relPath ) = self::splitStoragePath( $storagePath );
@@ -1481,7 +1560,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         * "mwstore://backend/container/...", or null if there is no parent.
         *
         * @param string $storagePath
-        * @return string|null
+        * @return string|null Parent storage path or null on failure
         */
        final public static function parentStoragePath( $storagePath ) {
                $storagePath = dirname( $storagePath );
@@ -1526,7 +1605,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         *
         * @param string $type One of (attachment, inline)
         * @param string $filename Suggested file name (should not contain slashes)
-        * @throws FileBackendError
+        * @throws InvalidArgumentException
         * @return string
         * @since 1.20
         */
@@ -1554,7 +1633,7 @@ abstract class FileBackend implements LoggerAwareInterface {
         * This uses the same traversal protection as Title::secureAndSplit().
         *
         * @param string $path Storage path relative to a container
-        * @return string|null
+        * @return string|null Normalized container path or null on failure
         */
        final protected static function normalizeContainerPath( $path ) {
                // Normalize directory separators