Chris@0: uriScheme($uri); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks that the scheme of a stream URI is valid. Chris@0: * Chris@0: * @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::validScheme(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function file_stream_wrapper_valid_scheme($scheme) { Chris@0: return \Drupal::service('file_system')->validScheme($scheme); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the part of a URI after the schema. Chris@0: * Chris@0: * @param string $uri Chris@0: * A stream, referenced as "scheme://target" or "data:target". Chris@0: * Chris@0: * @return string|bool Chris@0: * A string containing the target (path), or FALSE if none. Chris@0: * For example, the URI "public://sample/test.txt" would return Chris@0: * "sample/test.txt". Chris@0: * Chris@0: * @see file_uri_scheme() Chris@0: */ Chris@0: function file_uri_target($uri) { Chris@0: // Remove the scheme from the URI and remove erroneous leading or trailing, Chris@0: // forward-slashes and backslashes. Chris@0: $target = trim(preg_replace('/^[\w\-]+:\/\/|^data:/', '', $uri), '\/'); Chris@0: Chris@0: // If nothing was replaced, the URI doesn't have a valid scheme. Chris@0: return $target !== $uri ? $target : FALSE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the default file stream implementation. Chris@0: * Chris@0: * @return string Chris@0: * 'public', 'private' or any other file scheme defined as the default. Chris@0: */ Chris@0: function file_default_scheme() { Chris@0: return \Drupal::config('system.file')->get('default_scheme'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Normalizes a URI by making it syntactically correct. Chris@0: * Chris@0: * A stream is referenced as "scheme://target". Chris@0: * Chris@0: * The following actions are taken: Chris@0: * - Remove trailing slashes from target Chris@0: * - Trim erroneous leading slashes from target. e.g. ":///" becomes "://". Chris@0: * Chris@0: * @param string $uri Chris@0: * String reference containing the URI to normalize. Chris@0: * Chris@0: * @return string Chris@0: * The normalized URI. Chris@0: */ Chris@0: function file_stream_wrapper_uri_normalize($uri) { Chris@0: $scheme = \Drupal::service('file_system')->uriScheme($uri); Chris@0: Chris@0: if (file_stream_wrapper_valid_scheme($scheme)) { Chris@0: $target = file_uri_target($uri); Chris@0: Chris@0: if ($target !== FALSE) { Chris@0: $uri = $scheme . '://' . $target; Chris@0: } Chris@0: } Chris@0: Chris@0: return $uri; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a web-accessible URL for a stream to an external or local file. Chris@0: * Chris@0: * Compatibility: normal paths and stream wrappers. Chris@0: * Chris@0: * There are two kinds of local files: Chris@0: * - "managed files", i.e. those stored by a Drupal-compatible stream wrapper. Chris@0: * These are files that have either been uploaded by users or were generated Chris@0: * automatically (for example through CSS aggregation). Chris@0: * - "shipped files", i.e. those outside of the files directory, which ship as Chris@0: * part of Drupal core or contributed modules or themes. Chris@0: * Chris@0: * @param string $uri Chris@0: * The URI to a file for which we need an external URL, or the path to a Chris@0: * shipped file. Chris@0: * Chris@0: * @return string Chris@0: * A string containing a URL that may be used to access the file. Chris@0: * If the provided string already contains a preceding 'http', 'https', or Chris@0: * '/', nothing is done and the same string is returned. If a stream wrapper Chris@0: * could not be found to generate an external URL, then FALSE is returned. Chris@0: * Chris@0: * @see https://www.drupal.org/node/515192 Chris@0: * @see file_url_transform_relative() Chris@0: */ Chris@0: function file_create_url($uri) { Chris@0: // Allow the URI to be altered, e.g. to serve a file from a CDN or static Chris@0: // file server. Chris@0: \Drupal::moduleHandler()->alter('file_url', $uri); Chris@0: Chris@0: $scheme = \Drupal::service('file_system')->uriScheme($uri); Chris@0: Chris@0: if (!$scheme) { Chris@0: // Allow for: Chris@0: // - root-relative URIs (e.g. /foo.jpg in http://example.com/foo.jpg) Chris@0: // - protocol-relative URIs (e.g. //bar.jpg, which is expanded to Chris@0: // http://example.com/bar.jpg by the browser when viewing a page over Chris@0: // HTTP and to https://example.com/bar.jpg when viewing a HTTPS page) Chris@0: // Both types of relative URIs are characterized by a leading slash, hence Chris@0: // we can use a single check. Chris@17: if (mb_substr($uri, 0, 1) == '/') { Chris@0: return $uri; Chris@0: } Chris@0: else { Chris@0: // If this is not a properly formatted stream, then it is a shipped file. Chris@0: // Therefore, return the urlencoded URI with the base URL prepended. Chris@0: $options = UrlHelper::parse($uri); Chris@0: $path = $GLOBALS['base_url'] . '/' . UrlHelper::encodePath($options['path']); Chris@0: // Append the query. Chris@0: if ($options['query']) { Chris@0: $path .= '?' . UrlHelper::buildQuery($options['query']); Chris@0: } Chris@0: Chris@0: // Append fragment. Chris@0: if ($options['fragment']) { Chris@0: $path .= '#' . $options['fragment']; Chris@0: } Chris@0: Chris@0: return $path; Chris@0: } Chris@0: } Chris@0: elseif ($scheme == 'http' || $scheme == 'https' || $scheme == 'data') { Chris@0: // Check for HTTP and data URI-encoded URLs so that we don't have to Chris@0: // implement getExternalUrl() for the HTTP and data schemes. Chris@0: return $uri; Chris@0: } Chris@0: else { Chris@0: // Attempt to return an external URL using the appropriate wrapper. Chris@0: if ($wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($uri)) { Chris@0: return $wrapper->getExternalUrl(); Chris@0: } Chris@0: else { Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Transforms an absolute URL of a local file to a relative URL. Chris@0: * Chris@0: * May be useful to prevent problems on multisite set-ups and prevent mixed Chris@0: * content errors when using HTTPS + HTTP. Chris@0: * Chris@0: * @param string $file_url Chris@0: * A file URL of a local file as generated by file_create_url(). Chris@0: * Chris@0: * @return string Chris@0: * If the file URL indeed pointed to a local file and was indeed absolute, Chris@0: * then the transformed, relative URL to the local file. Otherwise: the Chris@0: * original value of $file_url. Chris@0: * Chris@0: * @see file_create_url() Chris@0: */ Chris@0: function file_url_transform_relative($file_url) { Chris@0: // Unfortunately, we pretty much have to duplicate Symfony's Chris@0: // Request::getHttpHost() method because Request::getPort() may return NULL Chris@0: // instead of a port number. Chris@0: $request = \Drupal::request(); Chris@0: $host = $request->getHost(); Chris@0: $scheme = $request->getScheme(); Chris@0: $port = $request->getPort() ?: 80; Chris@0: if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) { Chris@0: $http_host = $host; Chris@0: } Chris@0: else { Chris@0: $http_host = $host . ':' . $port; Chris@0: } Chris@0: Chris@16: return preg_replace('|^https?://' . preg_quote($http_host, '|') . '|', '', $file_url); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks that the directory exists and is writable. Chris@0: * Chris@0: * Directories need to have execute permissions to be considered a directory by Chris@0: * FTP servers, etc. Chris@0: * Chris@0: * @param $directory Chris@0: * A string reference containing the name of a directory path or URI. A Chris@0: * trailing slash will be trimmed from a path. Chris@0: * @param $options Chris@0: * A bitmask to indicate if the directory should be created if it does Chris@0: * not exist (FILE_CREATE_DIRECTORY) or made writable if it is read-only Chris@0: * (FILE_MODIFY_PERMISSIONS). Chris@0: * Chris@0: * @return Chris@0: * TRUE if the directory exists (or was created) and is writable. FALSE Chris@0: * otherwise. Chris@18: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::prepareDirectory(). Chris@0: */ Chris@18: function file_prepare_directory(&$directory, $options = FileSystemInterface::MODIFY_PERMISSIONS) { Chris@18: @trigger_error('file_prepare_directory() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::prepareDirectory(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: return \Drupal::service('file_system')->prepareDirectory($directory, $options); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a .htaccess file in each Drupal files directory if it is missing. Chris@0: */ Chris@0: function file_ensure_htaccess() { Chris@0: file_save_htaccess('public://', FALSE); Chris@0: $private_path = PrivateStream::basePath(); Chris@0: if (!empty($private_path)) { Chris@0: file_save_htaccess('private://', TRUE); Chris@0: } Chris@0: file_save_htaccess('temporary://', TRUE); Chris@0: Chris@0: // If a staging directory exists then it should contain a .htaccess file. Chris@0: // @todo https://www.drupal.org/node/2696103 catch a more specific exception Chris@0: // and simplify this code. Chris@0: try { Chris@0: $staging = config_get_config_directory(CONFIG_SYNC_DIRECTORY); Chris@0: } Chris@0: catch (\Exception $e) { Chris@0: $staging = FALSE; Chris@0: } Chris@0: if ($staging) { Chris@0: // Note that we log an error here if we can't write the .htaccess file. This Chris@0: // can occur if the staging directory is read-only. If it is then it is the Chris@0: // user's responsibility to create the .htaccess file. Chris@0: file_save_htaccess($staging, TRUE); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a .htaccess file in the given directory. Chris@0: * Chris@0: * @param string $directory Chris@0: * The directory. Chris@0: * @param bool $private Chris@0: * (Optional) FALSE indicates that $directory should be a web-accessible Chris@0: * directory. Defaults to TRUE which indicates a private directory. Chris@0: * @param bool $force_overwrite Chris@0: * (Optional) Set to TRUE to attempt to overwrite the existing .htaccess file Chris@0: * if one is already present. Defaults to FALSE. Chris@0: */ Chris@0: function file_save_htaccess($directory, $private = TRUE, $force_overwrite = FALSE) { Chris@0: if (\Drupal::service('file_system')->uriScheme($directory)) { Chris@0: $htaccess_path = file_stream_wrapper_uri_normalize($directory . '/.htaccess'); Chris@0: } Chris@0: else { Chris@0: $directory = rtrim($directory, '/\\'); Chris@0: $htaccess_path = $directory . '/.htaccess'; Chris@0: } Chris@0: Chris@0: if (file_exists($htaccess_path) && !$force_overwrite) { Chris@0: // Short circuit if the .htaccess file already exists. Chris@0: return TRUE; Chris@0: } Chris@0: $htaccess_lines = FileStorage::htaccessLines($private); Chris@0: Chris@0: // Write the .htaccess file. Chris@0: if (file_exists($directory) && is_writable($directory) && file_put_contents($htaccess_path, $htaccess_lines)) { Chris@18: return \Drupal::service('file_system')->chmod($htaccess_path, 0444); Chris@0: } Chris@0: else { Chris@0: $variables = ['%directory' => $directory, '@htaccess' => $htaccess_lines]; Chris@0: \Drupal::logger('security')->error("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines:
@htaccess
", $variables); Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the standard .htaccess lines that Drupal writes to file directories. Chris@0: * Chris@0: * @param bool $private Chris@0: * (Optional) Set to FALSE to return the .htaccess lines for a web-accessible Chris@0: * public directory. The default is TRUE, which returns the .htaccess lines Chris@0: * for a private directory that should not be web-accessible. Chris@0: * Chris@0: * @return string Chris@0: * The desired contents of the .htaccess file. Chris@0: * Chris@0: * @deprecated in Drupal 8.0.x-dev and will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Component\PhpStorage\FileStorage::htaccessLines(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function file_htaccess_lines($private = TRUE) { Chris@0: return FileStorage::htaccessLines($private); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines whether the URI has a valid scheme for file API operations. Chris@0: * Chris@0: * There must be a scheme and it must be a Drupal-provided scheme like Chris@0: * 'public', 'private', 'temporary', or an extension provided with Chris@0: * hook_stream_wrappers(). Chris@0: * Chris@0: * @param $uri Chris@0: * The URI to be tested. Chris@0: * Chris@0: * @return Chris@0: * TRUE if the URI is allowed. Chris@0: */ Chris@0: function file_valid_uri($uri) { Chris@0: // Assert that the URI has an allowed scheme. Bare paths are not allowed. Chris@0: $uri_scheme = \Drupal::service('file_system')->uriScheme($uri); Chris@0: if (!file_stream_wrapper_valid_scheme($uri_scheme)) { Chris@0: return FALSE; Chris@0: } Chris@0: return TRUE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Copies a file to a new location without database changes or hook invocation. Chris@0: * Chris@0: * This is a powerful function that in many ways performs like an advanced Chris@0: * version of copy(). Chris@0: * - Checks if $source and $destination are valid and readable/writable. Chris@0: * - If file already exists in $destination either the call will error out, Chris@0: * replace the file or rename the file based on the $replace parameter. Chris@0: * - If the $source and $destination are equal, the behavior depends on the Chris@0: * $replace parameter. FILE_EXISTS_REPLACE will error out. FILE_EXISTS_RENAME Chris@0: * will rename the file until the $destination is unique. Chris@0: * - Works around a PHP bug where copy() does not properly support streams if Chris@0: * safe_mode or open_basedir are enabled. Chris@0: * @see https://bugs.php.net/bug.php?id=60456 Chris@0: * Chris@0: * @param $source Chris@0: * A string specifying the filepath or URI of the source file. Chris@0: * @param $destination Chris@0: * A URI containing the destination that $source should be copied to. The Chris@0: * URI may be a bare filepath (without a scheme). If this value is omitted, Chris@0: * Drupal's default files scheme will be used, usually "public://". Chris@0: * @param $replace Chris@0: * Replace behavior when the destination file already exists: Chris@0: * - FILE_EXISTS_REPLACE - Replace the existing file. Chris@0: * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is Chris@0: * unique. Chris@0: * - FILE_EXISTS_ERROR - Do nothing and return FALSE. Chris@0: * Chris@0: * @return Chris@0: * The path to the new file, or FALSE in the event of an error. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::copy(). Chris@18: * Chris@0: * @see file_copy() Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { Chris@18: @trigger_error('file_unmanaged_copy() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::copy(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: try { Chris@18: $file_system = \Drupal::service('file_system'); Chris@18: Chris@18: // Build a destination URI if necessary. Chris@18: if (!isset($destination)) { Chris@18: $destination = file_build_uri($file_system->basename($source)); Chris@18: } Chris@18: return $file_system->copy($source, $destination, $replace); Chris@18: } Chris@18: catch (FileException $e) { Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Internal function that prepares the destination for a file_unmanaged_copy or Chris@0: * file_unmanaged_move operation. Chris@0: * Chris@0: * - Checks if $source and $destination are valid and readable/writable. Chris@0: * - Checks that $source is not equal to $destination; if they are an error Chris@0: * is reported. Chris@0: * - If file already exists in $destination either the call will error out, Chris@0: * replace the file or rename the file based on the $replace parameter. Chris@0: * Chris@0: * @param $source Chris@0: * A string specifying the filepath or URI of the source file. Chris@0: * @param $destination Chris@0: * A URI containing the destination that $source should be moved/copied to. Chris@0: * The URI may be a bare filepath (without a scheme) and in that case the Chris@0: * default scheme (file://) will be used. If this value is omitted, Drupal's Chris@0: * default files scheme will be used, usually "public://". Chris@0: * @param $replace Chris@0: * Replace behavior when the destination file already exists: Chris@0: * - FILE_EXISTS_REPLACE - Replace the existing file. Chris@0: * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is Chris@0: * unique. Chris@0: * - FILE_EXISTS_ERROR - Do nothing and return FALSE. Chris@0: * Chris@0: * @return Chris@0: * TRUE, or FALSE in the event of an error. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename() instead. Chris@18: * Chris@0: * @see file_unmanaged_copy() Chris@0: * @see file_unmanaged_move() Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_unmanaged_prepare($source, &$destination = NULL, $replace = FILE_EXISTS_RENAME) { Chris@18: @trigger_error('file_unmanaged_prepare() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename() instead. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@0: $original_source = $source; Chris@0: $logger = \Drupal::logger('file'); Chris@18: /** @var \Drupal\Core\File\FileSystemInterface $file_system */ Chris@14: $file_system = \Drupal::service('file_system'); Chris@0: Chris@0: // Assert that the source file actually exists. Chris@0: if (!file_exists($source)) { Chris@17: // @todo Replace \Drupal::messenger()->addError() calls with exceptions Chris@17: // instead. Chris@17: \Drupal::messenger()->addError(t('The specified file %file could not be moved/copied because no file by that name exists. Please check that you supplied the correct filename.', ['%file' => $original_source])); Chris@14: if (($realpath = $file_system->realpath($original_source)) !== FALSE) { Chris@0: $logger->notice('File %file (%realpath) could not be moved/copied because it does not exist.', ['%file' => $original_source, '%realpath' => $realpath]); Chris@0: } Chris@0: else { Chris@0: $logger->notice('File %file could not be moved/copied because it does not exist.', ['%file' => $original_source]); Chris@0: } Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: // Build a destination URI if necessary. Chris@0: if (!isset($destination)) { Chris@18: $destination = file_build_uri($file_system->basename($source)); Chris@0: } Chris@0: Chris@0: // Prepare the destination directory. Chris@0: if (file_prepare_directory($destination)) { Chris@0: // The destination is already a directory, so append the source basename. Chris@18: $destination = file_stream_wrapper_uri_normalize($destination . '/' . $file_system->basename($source)); Chris@0: } Chris@0: else { Chris@0: // Perhaps $destination is a dir/file? Chris@18: $dirname = $file_system->dirname($destination); Chris@0: if (!file_prepare_directory($dirname)) { Chris@0: // The destination is not valid. Chris@0: $logger->notice('File %file could not be moved/copied because the destination directory %destination is not configured correctly.', ['%file' => $original_source, '%destination' => $dirname]); Chris@17: \Drupal::messenger()->addError(t('The specified file %file could not be moved/copied because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.', ['%file' => $original_source])); Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: Chris@0: // Determine whether we can perform this operation based on overwrite rules. Chris@0: $destination = file_destination($destination, $replace); Chris@0: if ($destination === FALSE) { Chris@17: \Drupal::messenger()->addError(t('The file %file could not be moved/copied because a file by that name already exists in the destination directory.', ['%file' => $original_source])); Chris@0: $logger->notice('File %file could not be moved/copied because a file by that name already exists in the destination directory (%destination)', ['%file' => $original_source, '%destination' => $destination]); Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: // Assert that the source and destination filenames are not the same. Chris@14: $real_source = $file_system->realpath($source); Chris@14: $real_destination = $file_system->realpath($destination); Chris@0: if ($source == $destination || ($real_source !== FALSE) && ($real_source == $real_destination)) { Chris@17: \Drupal::messenger()->addError(t('The specified file %file was not moved/copied because it would overwrite itself.', ['%file' => $source])); Chris@0: $logger->notice('File %file could not be moved/copied because it would overwrite itself.', ['%file' => $source]); Chris@0: return FALSE; Chris@0: } Chris@0: // Make sure the .htaccess files are present. Chris@0: file_ensure_htaccess(); Chris@0: return TRUE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Constructs a URI to Drupal's default files location given a relative path. Chris@0: */ Chris@0: function file_build_uri($path) { Chris@0: $uri = file_default_scheme() . '://' . $path; Chris@0: return file_stream_wrapper_uri_normalize($uri); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines the destination path for a file. Chris@0: * Chris@0: * @param $destination Chris@0: * A string specifying the desired final URI or filepath. Chris@0: * @param $replace Chris@0: * Replace behavior when the destination file already exists. Chris@0: * - FILE_EXISTS_REPLACE - Replace the existing file. Chris@0: * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is Chris@0: * unique. Chris@0: * - FILE_EXISTS_ERROR - Do nothing and return FALSE. Chris@0: * Chris@0: * @return Chris@0: * The destination filepath, or FALSE if the file already exists Chris@0: * and FILE_EXISTS_ERROR is specified. Chris@18: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename(). Chris@18: * Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_destination($destination, $replace) { Chris@18: @trigger_error('file_destination() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: return \Drupal::service('file_system')->getDestinationFilename($destination, $replace); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Moves a file to a new location without database changes or hook invocation. Chris@0: * Chris@0: * This is a powerful function that in many ways performs like an advanced Chris@0: * version of rename(). Chris@0: * - Checks if $source and $destination are valid and readable/writable. Chris@0: * - Checks that $source is not equal to $destination; if they are an error Chris@0: * is reported. Chris@0: * - If file already exists in $destination either the call will error out, Chris@0: * replace the file or rename the file based on the $replace parameter. Chris@0: * - Works around a PHP bug where rename() does not properly support streams if Chris@0: * safe_mode or open_basedir are enabled. Chris@0: * @see https://bugs.php.net/bug.php?id=60456 Chris@0: * Chris@0: * @param $source Chris@0: * A string specifying the filepath or URI of the source file. Chris@0: * @param $destination Chris@0: * A URI containing the destination that $source should be moved to. The Chris@0: * URI may be a bare filepath (without a scheme) and in that case the default Chris@0: * scheme (file://) will be used. If this value is omitted, Drupal's default Chris@0: * files scheme will be used, usually "public://". Chris@0: * @param $replace Chris@0: * Replace behavior when the destination file already exists: Chris@0: * - FILE_EXISTS_REPLACE - Replace the existing file. Chris@0: * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is Chris@0: * unique. Chris@0: * - FILE_EXISTS_ERROR - Do nothing and return FALSE. Chris@0: * Chris@0: * @return Chris@0: * The path to the new file, or FALSE in the event of an error. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::move(). Chris@18: * Chris@0: * @see file_move() Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { Chris@18: @trigger_error('file_unmanaged_move() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::move(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: try { Chris@18: $file_system = \Drupal::service('file_system'); Chris@18: Chris@18: // Build a destination URI if necessary. Chris@18: if (!isset($destination)) { Chris@18: $destination = file_build_uri($file_system->basename($source)); Chris@18: } Chris@18: return $file_system->move($source, $destination, $replace); Chris@18: } Chris@18: catch (FileException $e) { Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Modifies a filename as needed for security purposes. Chris@0: * Chris@0: * Munging a file name prevents unknown file extensions from masking exploit Chris@0: * files. When web servers such as Apache decide how to process a URL request, Chris@0: * they use the file extension. If the extension is not recognized, Apache Chris@0: * skips that extension and uses the previous file extension. For example, if Chris@0: * the file being requested is exploit.php.pps, and Apache does not recognize Chris@0: * the '.pps' extension, it treats the file as PHP and executes it. To make Chris@0: * this file name safe for Apache and prevent it from executing as PHP, the Chris@0: * .php extension is "munged" into .php_, making the safe file name Chris@0: * exploit.php_.pps. Chris@0: * Chris@0: * Specifically, this function adds an underscore to all extensions that are Chris@0: * between 2 and 5 characters in length, internal to the file name, and not Chris@0: * included in $extensions. Chris@0: * Chris@0: * Function behavior is also controlled by the configuration Chris@0: * 'system.file:allow_insecure_uploads'. If it evaluates to TRUE, no alterations Chris@0: * will be made, if it evaluates to FALSE, the filename is 'munged'. * Chris@0: * @param $filename Chris@0: * File name to modify. Chris@0: * @param $extensions Chris@0: * A space-separated list of extensions that should not be altered. Chris@0: * @param $alerts Chris@17: * If TRUE, \Drupal::messenger()->addStatus() will be called to display Chris@17: * a message if the file name was changed. Chris@0: * Chris@0: * @return string Chris@0: * The potentially modified $filename. Chris@0: */ Chris@0: function file_munge_filename($filename, $extensions, $alerts = TRUE) { Chris@0: $original = $filename; Chris@0: Chris@0: // Allow potentially insecure uploads for very savvy users and admin Chris@0: if (!\Drupal::config('system.file')->get('allow_insecure_uploads')) { Chris@0: // Remove any null bytes. See Chris@0: // http://php.net/manual/security.filesystem.nullbytes.php Chris@0: $filename = str_replace(chr(0), '', $filename); Chris@0: Chris@0: $whitelist = array_unique(explode(' ', strtolower(trim($extensions)))); Chris@0: Chris@0: // Split the filename up by periods. The first part becomes the basename Chris@0: // the last part the final extension. Chris@0: $filename_parts = explode('.', $filename); Chris@0: // Remove file basename. Chris@0: $new_filename = array_shift($filename_parts); Chris@0: // Remove final extension. Chris@0: $final_extension = array_pop($filename_parts); Chris@0: Chris@0: // Loop through the middle parts of the name and add an underscore to the Chris@0: // end of each section that could be a file extension but isn't in the list Chris@0: // of allowed extensions. Chris@0: foreach ($filename_parts as $filename_part) { Chris@0: $new_filename .= '.' . $filename_part; Chris@0: if (!in_array(strtolower($filename_part), $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) { Chris@0: $new_filename .= '_'; Chris@0: } Chris@0: } Chris@0: $filename = $new_filename . '.' . $final_extension; Chris@0: Chris@0: if ($alerts && $original != $filename) { Chris@17: \Drupal::messenger()->addStatus(t('For security reasons, your upload has been renamed to %filename.', ['%filename' => $filename])); Chris@0: } Chris@0: } Chris@0: Chris@0: return $filename; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Undoes the effect of file_munge_filename(). Chris@0: * Chris@0: * @param $filename Chris@0: * String with the filename to be unmunged. Chris@0: * Chris@0: * @return Chris@0: * An unmunged filename string. Chris@0: */ Chris@0: function file_unmunge_filename($filename) { Chris@0: return str_replace('_.', '.', $filename); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a full file path from a directory and filename. Chris@0: * Chris@0: * If a file with the specified name already exists, an alternative will be Chris@0: * used. Chris@0: * Chris@0: * @param $basename Chris@0: * String filename Chris@0: * @param $directory Chris@0: * String containing the directory or parent URI. Chris@0: * Chris@0: * @return Chris@0: * File path consisting of $directory and a unique filename based off Chris@0: * of $basename. Chris@18: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::createFilename(). Chris@18: * Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_create_filename($basename, $directory) { Chris@18: @trigger_error('file_create_filename() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::createFilename(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: return \Drupal::service('file_system')->createFilename($basename, $directory); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes a file and its database record. Chris@0: * Chris@0: * Instead of directly deleting a file, it is strongly recommended to delete Chris@0: * file usages instead. That will automatically mark the file as temporary and Chris@0: * remove it during cleanup. Chris@0: * Chris@0: * @param $fid Chris@0: * The file id. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\Entity\EntityStorageInterface::delete() instead. Chris@18: * Chris@0: * @see file_unmanaged_delete() Chris@0: * @see \Drupal\file\FileUsage\FileUsageBase::delete() Chris@18: * @see \Drupal\Core\Entity\EntityStorageInterface::delete() Chris@18: * @see https://www.drupal.org/node/3021663 Chris@0: */ Chris@0: function file_delete($fid) { Chris@18: @trigger_error('file_delete() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityStorageInterface::delete() instead. See https://www.drupal.org/node/3021663.', E_USER_DEPRECATED); Chris@0: return file_delete_multiple([$fid]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes files. Chris@0: * Chris@0: * Instead of directly deleting a file, it is strongly recommended to delete Chris@0: * file usages instead. That will automatically mark the file as temporary and Chris@0: * remove it during cleanup. Chris@0: * Chris@18: * @param $fids Chris@18: * An array of file ids. Chris@18: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\Entity\EntityStorageInterface::delete() instead. Chris@0: * Chris@0: * @see file_unmanaged_delete() Chris@0: * @see \Drupal\file\FileUsage\FileUsageBase::delete() Chris@18: * @see \Drupal\Core\Entity\EntityStorageInterface::delete() Chris@18: * @see https://www.drupal.org/node/3021663 Chris@0: */ Chris@0: function file_delete_multiple(array $fids) { Chris@18: @trigger_error('file_delete_multiple() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityStorageInterface::delete() instead. See https://www.drupal.org/node/3021663.', E_USER_DEPRECATED); Chris@18: $storage = \Drupal::entityTypeManager()->getStorage('file'); Chris@18: $entities = $storage->loadMultiple($fids); Chris@18: $storage->delete($entities); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes a file without database changes or hook invocations. Chris@0: * Chris@0: * This function should be used when the file to be deleted does not have an Chris@0: * entry recorded in the files table. Chris@0: * Chris@0: * @param $path Chris@0: * A string containing a file path or (streamwrapper) URI. Chris@0: * Chris@0: * @return Chris@0: * TRUE for success or path does not exist, or FALSE in the event of an Chris@0: * error. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::delete(). Chris@18: * Chris@0: * @see file_delete() Chris@0: * @see file_unmanaged_delete_recursive() Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_unmanaged_delete($path) { Chris@18: @trigger_error('file_unmanaged_delete() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::delete(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: try { Chris@18: return \Drupal::service('file_system')->delete($path); Chris@0: } Chris@18: catch (FileException $e) { Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes all files and directories in the specified filepath recursively. Chris@0: * Chris@0: * If the specified path is a directory then the function will call itself Chris@0: * recursively to process the contents. Once the contents have been removed the Chris@0: * directory will also be removed. Chris@0: * Chris@0: * If the specified path is a file then it will be passed to Chris@0: * file_unmanaged_delete(). Chris@0: * Chris@0: * Note that this only deletes visible files with write permission. Chris@0: * Chris@0: * @param $path Chris@0: * A string containing either an URI or a file or directory path. Chris@14: * @param callable $callback Chris@0: * (optional) Callback function to run on each file prior to deleting it and Chris@0: * on each directory prior to traversing it. For example, can be used to Chris@0: * modify permissions. Chris@0: * Chris@0: * @return Chris@0: * TRUE for success or if path does not exist, FALSE in the event of an Chris@0: * error. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::deleteRecursive(). Chris@18: * Chris@0: * @see file_unmanaged_delete() Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_unmanaged_delete_recursive($path, $callback = NULL) { Chris@18: @trigger_error('file_unmanaged_delete_recursive() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::deleteRecursive(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: $callback = is_callable($callback) ? $callback : NULL; Chris@18: try { Chris@18: return \Drupal::service('file_system')->deleteRecursive($path, $callback); Chris@0: } Chris@18: catch (FileException $e) { Chris@18: return FALSE; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Moves an uploaded file to a new location. Chris@0: * Chris@0: * @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::moveUploadedFile(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_move_uploaded_file($filename, $uri) { Chris@18: @trigger_error('drupal_move_uploaded_file() is deprecated in Drupal 8.0.x-dev and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::moveUploadedFile(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->moveUploadedFile($filename, $uri); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Saves a file to the specified destination without invoking file API. Chris@0: * Chris@0: * This function is identical to file_save_data() except the file will not be Chris@0: * saved to the {file_managed} table and none of the file_* hooks will be Chris@0: * called. Chris@0: * Chris@0: * @param $data Chris@0: * A string containing the contents of the file. Chris@0: * @param $destination Chris@0: * A string containing the destination location. This must be a stream wrapper Chris@0: * URI. If no value is provided, a randomized name will be generated and the Chris@0: * file will be saved using Drupal's default files scheme, usually Chris@0: * "public://". Chris@0: * @param $replace Chris@0: * Replace behavior when the destination file already exists: Chris@0: * - FILE_EXISTS_REPLACE - Replace the existing file. Chris@0: * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is Chris@0: * unique. Chris@0: * - FILE_EXISTS_ERROR - Do nothing and return FALSE. Chris@0: * Chris@0: * @return Chris@0: * A string with the path of the resulting file, or FALSE on error. Chris@0: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Core\File\FileSystemInterface::saveData(). Chris@18: * Chris@0: * @see file_save_data() Chris@18: * @see https://www.drupal.org/node/3006851 Chris@0: */ Chris@0: function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) { Chris@18: @trigger_error('file_unmanaged_save_data() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::saveData(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED); Chris@18: try { Chris@18: // Build a destination URI if necessary. Chris@18: if (!isset($destination)) { Chris@18: $destination = file_default_scheme() . '://'; Chris@18: } Chris@18: return \Drupal::service('file_system')->saveData($data, $destination, $replace); Chris@18: } Chris@18: catch (FileWriteException $e) { Chris@17: \Drupal::messenger()->addError(t('The file could not be created.')); Chris@0: return FALSE; Chris@0: } Chris@18: catch (FileException $e) { Chris@18: return FALSE; Chris@18: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Finds all files that match a given mask in a given directory. Chris@0: * Chris@0: * Directories and files beginning with a dot are excluded; this prevents Chris@0: * hidden files and directories (such as SVN working directories) from being Chris@0: * scanned. Use the umask option to skip configuration directories to Chris@0: * eliminate the possibility of accidentally exposing configuration Chris@0: * information. Also, you can use the base directory, recurse, and min_depth Chris@0: * options to improve performance by limiting how much of the filesystem has Chris@0: * to be traversed. Chris@0: * Chris@0: * @param $dir Chris@0: * The base directory or URI to scan, without trailing slash. Chris@0: * @param $mask Chris@0: * The preg_match() regular expression for files to be included. Chris@0: * @param $options Chris@0: * An associative array of additional options, with the following elements: Chris@0: * - 'nomask': The preg_match() regular expression for files to be excluded. Chris@0: * Defaults to the 'file_scan_ignore_directories' setting. Chris@0: * - 'callback': The callback function to call for each match. There is no Chris@0: * default callback. Chris@0: * - 'recurse': When TRUE, the directory scan will recurse the entire tree Chris@0: * starting at the provided directory. Defaults to TRUE. Chris@0: * - 'key': The key to be used for the returned associative array of files. Chris@0: * Possible values are 'uri', for the file's URI; 'filename', for the Chris@0: * basename of the file; and 'name' for the name of the file without the Chris@0: * extension. Defaults to 'uri'. Chris@0: * - 'min_depth': Minimum depth of directories to return files from. Defaults Chris@0: * to 0. Chris@0: * @param $depth Chris@0: * The current depth of recursion. This parameter is only used internally and Chris@0: * should not be passed in. Chris@0: * Chris@0: * @return Chris@0: * An associative array (keyed on the chosen key) of objects with 'uri', Chris@0: * 'filename', and 'name' properties corresponding to the matched files. Chris@0: */ Chris@0: function file_scan_directory($dir, $mask, $options = [], $depth = 0) { Chris@0: // Merge in defaults. Chris@0: $options += [ Chris@0: 'callback' => 0, Chris@0: 'recurse' => TRUE, Chris@0: 'key' => 'uri', Chris@0: 'min_depth' => 0, Chris@0: ]; Chris@0: // Normalize $dir only once. Chris@0: if ($depth == 0) { Chris@0: $dir = file_stream_wrapper_uri_normalize($dir); Chris@0: $dir_has_slash = (substr($dir, -1) === '/'); Chris@0: } Chris@0: Chris@0: // Allow directories specified in settings.php to be ignored. You can use this Chris@0: // to not check for files in common special-purpose directories. For example, Chris@0: // node_modules and bower_components. Ignoring irrelevant directories is a Chris@0: // performance boost. Chris@0: if (!isset($options['nomask'])) { Chris@0: $ignore_directories = Settings::get('file_scan_ignore_directories', []); Chris@0: array_walk($ignore_directories, function (&$value) { Chris@0: $value = preg_quote($value, '/'); Chris@0: }); Chris@0: $default_nomask = '/^' . implode('|', $ignore_directories) . '$/'; Chris@0: } Chris@0: Chris@0: $options['key'] = in_array($options['key'], ['uri', 'filename', 'name']) ? $options['key'] : 'uri'; Chris@0: $files = []; Chris@0: // Avoid warnings when opendir does not have the permissions to open a Chris@0: // directory. Chris@0: if (is_dir($dir)) { Chris@0: if ($handle = @opendir($dir)) { Chris@0: while (FALSE !== ($filename = readdir($handle))) { Chris@0: // Skip this file if it matches the nomask or starts with a dot. Chris@0: if ($filename[0] != '.' Chris@0: && !(isset($options['nomask']) && preg_match($options['nomask'], $filename)) Chris@0: && !(!empty($default_nomask) && preg_match($default_nomask, $filename)) Chris@0: ) { Chris@0: if ($depth == 0 && $dir_has_slash) { Chris@0: $uri = "$dir$filename"; Chris@0: } Chris@0: else { Chris@0: $uri = "$dir/$filename"; Chris@0: } Chris@0: if ($options['recurse'] && is_dir($uri)) { Chris@0: // Give priority to files in this folder by merging them in after Chris@0: // any subdirectory files. Chris@0: $files = array_merge(file_scan_directory($uri, $mask, $options, $depth + 1), $files); Chris@0: } Chris@0: elseif ($depth >= $options['min_depth'] && preg_match($mask, $filename)) { Chris@0: // Always use this match over anything already set in $files with Chris@0: // the same $options['key']. Chris@0: $file = new stdClass(); Chris@0: $file->uri = $uri; Chris@0: $file->filename = $filename; Chris@0: $file->name = pathinfo($filename, PATHINFO_FILENAME); Chris@0: $key = $options['key']; Chris@0: $files[$file->$key] = $file; Chris@0: if ($options['callback']) { Chris@0: $options['callback']($uri); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: closedir($handle); Chris@0: } Chris@0: else { Chris@0: \Drupal::logger('file')->error('@dir can not be opened', ['@dir' => $dir]); Chris@0: } Chris@0: } Chris@0: Chris@0: return $files; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines the maximum file upload size by querying the PHP settings. Chris@0: * Chris@0: * @return Chris@0: * A file size limit in bytes based on the PHP upload_max_filesize and Chris@0: * post_max_size Chris@18: * Chris@18: * @deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Chris@18: * Use \Drupal\Component\Utility\Environment::getUploadMaxSize() instead. Chris@0: */ Chris@0: function file_upload_max_size() { Chris@18: @trigger_error('file_upload_max_size() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Component\Utility\Environment::getUploadMaxSize() instead. See https://www.drupal.org/node/3000058.', E_USER_DEPRECATED); Chris@18: return Environment::getUploadMaxSize(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the permissions on a file or directory. Chris@0: * Chris@18: * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::chmod(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_chmod($uri, $mode = NULL) { Chris@18: @trigger_error('drupal_chmod() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::chmod(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->chmod($uri, $mode); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes a file. Chris@0: * Chris@0: * @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::unlink(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_unlink($uri, $context = NULL) { Chris@0: return \Drupal::service('file_system')->unlink($uri, $context); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Resolves the absolute filepath of a local URI or filepath. Chris@0: * Chris@0: * @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::realpath(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_realpath($uri) { Chris@0: return \Drupal::service('file_system')->realpath($uri); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the name of the directory from a given path. Chris@0: * Chris@18: * @deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::dirname(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_dirname($uri) { Chris@18: @trigger_error('drupal_dirname() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::dirname(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->dirname($uri); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the filename from a given path. Chris@0: * Chris@18: * @deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::basename(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_basename($uri, $suffix = NULL) { Chris@18: @trigger_error('drupal_basename() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::basename(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->basename($uri, $suffix); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a directory, optionally creating missing components in the path to Chris@0: * the directory. Chris@0: * Chris@18: * @deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::mkdir(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) { Chris@18: @trigger_error('drupal_mkdir() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::mkdir(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->mkdir($uri, $mode, $recursive, $context); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes a directory. Chris@0: * Chris@18: * @deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::rmdir(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_rmdir($uri, $context = NULL) { Chris@18: @trigger_error('drupal_rmdir() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::rmdir(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->rmdir($uri, $context); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a file with a unique filename in the specified directory. Chris@0: * Chris@18: * @deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Core\File\FileSystem::tempnam(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function drupal_tempnam($directory, $prefix) { Chris@18: @trigger_error('tempnam() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::tempnam(). See https://www.drupal.org/node/2418133.', E_USER_DEPRECATED); Chris@0: return \Drupal::service('file_system')->tempnam($directory, $prefix); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets and sets the path of the configured temporary directory. Chris@0: * Chris@0: * @return mixed|null Chris@0: * A string containing the path to the temporary directory. Chris@0: */ Chris@0: function file_directory_temp() { Chris@0: $temporary_directory = \Drupal::config('system.file')->get('path.temporary'); Chris@0: if (empty($temporary_directory)) { Chris@0: // Needs set up. Chris@0: $config = \Drupal::configFactory()->getEditable('system.file'); Chris@0: $temporary_directory = ComponentFileSystem::getOsTemporaryDirectory(); Chris@0: Chris@0: if (empty($temporary_directory)) { Chris@0: // If no directory has been found default to 'files/tmp'. Chris@0: $temporary_directory = PublicStream::basePath() . '/tmp'; Chris@0: Chris@0: // Windows accepts paths with either slash (/) or backslash (\), but will Chris@0: // not accept a path which contains both a slash and a backslash. Since Chris@0: // the 'file_public_path' variable may have either format, we sanitize Chris@0: // everything to use slash which is supported on all platforms. Chris@0: $temporary_directory = str_replace('\\', '/', $temporary_directory); Chris@0: } Chris@0: // Save the path of the discovered directory. Do not check config schema on Chris@0: // save. Chris@0: $config->set('path.temporary', (string) $temporary_directory)->save(TRUE); Chris@0: } Chris@0: Chris@0: return $temporary_directory; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Discovers a writable system-appropriate temporary directory. Chris@0: * Chris@0: * @return mixed Chris@0: * A string containing the path to the temporary directory. Chris@0: * Chris@0: * @deprecated in Drupal 8.3.x-dev, will be removed before Drupal 9.0.0. Chris@0: * Use \Drupal\Component\FileSystem\FileSystem::getOsTemporaryDirectory(). Chris@0: * Chris@0: * @see https://www.drupal.org/node/2418133 Chris@0: */ Chris@0: function file_directory_os_temp() { Chris@0: return ComponentFileSystem::getOsTemporaryDirectory(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @} End of "defgroup file". Chris@0: */