alter('file_url', $uri); $scheme = StreamWrapperManager::getScheme($uri); if (!$scheme) { // Allow for: // - root-relative URIs (e.g. /foo.jpg in http://example.com/foo.jpg) // - protocol-relative URIs (e.g. //bar.jpg, which is expanded to // http://example.com/bar.jpg by the browser when viewing a page over // HTTP and to https://example.com/bar.jpg when viewing a HTTPS page) // Both types of relative URIs are characterized by a leading slash, hence // we can use a single check. if (mb_substr($uri, 0, 1) == '/') { return $uri; } else { // If this is not a properly formatted stream, then it is a shipped file. // Therefore, return the urlencoded URI with the base URL prepended. $options = UrlHelper::parse($uri); $path = $GLOBALS['base_url'] . '/' . UrlHelper::encodePath($options['path']); // Append the query. if ($options['query']) { $path .= '?' . UrlHelper::buildQuery($options['query']); } // Append fragment. if ($options['fragment']) { $path .= '#' . $options['fragment']; } return $path; } } elseif ($scheme == 'http' || $scheme == 'https' || $scheme == 'data') { // Check for HTTP and data URI-encoded URLs so that we don't have to // implement getExternalUrl() for the HTTP and data schemes. return $uri; } else { // Attempt to return an external URL using the appropriate wrapper. if ($wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($uri)) { return $wrapper->getExternalUrl(); } else { return FALSE; } } } /** * Transforms an absolute URL of a local file to a relative URL. * * May be useful to prevent problems on multisite set-ups and prevent mixed * content errors when using HTTPS + HTTP. * * @param string $file_url * A file URL of a local file as generated by file_create_url(). * * @return string * If the file URL indeed pointed to a local file and was indeed absolute, * then the transformed, relative URL to the local file. Otherwise: the * original value of $file_url. * * @see file_create_url() */ function file_url_transform_relative($file_url) { // Unfortunately, we pretty much have to duplicate Symfony's // Request::getHttpHost() method because Request::getPort() may return NULL // instead of a port number. $request = \Drupal::request(); $host = $request->getHost(); $scheme = $request->getScheme(); $port = $request->getPort() ?: 80; // Files may be accessible on a different port than the web request. $file_url_port = parse_url($file_url, PHP_URL_PORT) ?? $port; if ($file_url_port != $port) { return $file_url; } if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) { $http_host = $host; } else { $http_host = $host . ':' . $port; } return preg_replace('|^https?://' . preg_quote($http_host, '|') . '|', '', $file_url); } /** * Constructs a URI to Drupal's default files location given a relative path. */ function file_build_uri($path) { $uri = \Drupal::config('system.file')->get('default_scheme') . '://' . $path; /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */ $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager'); return $stream_wrapper_manager->normalizeUri($uri); } /** * Modifies a filename as needed for security purposes. * * Munging a file name prevents unknown file extensions from masking exploit * files. When web servers such as Apache decide how to process a URL request, * they use the file extension. If the extension is not recognized, Apache * skips that extension and uses the previous file extension. For example, if * the file being requested is exploit.php.pps, and Apache does not recognize * the '.pps' extension, it treats the file as PHP and executes it. To make * this file name safe for Apache and prevent it from executing as PHP, the * .php extension is "munged" into .php_, making the safe file name * exploit.php_.pps. * * Specifically, this function adds an underscore to all extensions that are * between 2 and 5 characters in length, internal to the file name, and either * included in the list of unsafe extensions, or not included in $extensions. * * Function behavior is also controlled by the configuration * 'system.file:allow_insecure_uploads'. If it evaluates to TRUE, no alterations * will be made, if it evaluates to FALSE, the filename is 'munged'. * * @param $filename * File name to modify. * @param $extensions * A space-separated list of extensions that should not be altered. Note that * extensions that are unsafe will be altered regardless of this parameter. * @param $alerts * If TRUE, \Drupal::messenger()->addStatus() will be called to display * a message if the file name was changed. * * @return string * The potentially modified $filename. * * @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Dispatch a * \Drupal\Core\File\Event\FileUploadSanitizeNameEvent event instead. * * @see https://www.drupal.org/node/3032541 */ function file_munge_filename($filename, $extensions, $alerts = TRUE) { @trigger_error('file_munge_filename() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Dispatch a \Drupal\Core\File\Event\FileUploadSanitizeNameEvent event instead. See https://www.drupal.org/node/3032541', E_USER_DEPRECATED); $original = $filename; // Allow potentially insecure uploads for very savvy users and admin if (!\Drupal::config('system.file')->get('allow_insecure_uploads')) { // Remove any null bytes. See // http://php.net/manual/security.filesystem.nullbytes.php $filename = str_replace(chr(0), '', $filename); $allowed_extensions = array_unique(explode(' ', strtolower(trim($extensions)))); // Remove unsafe extensions from the allowed list of extensions. $allowed_extensions = array_diff($allowed_extensions, FileSystemInterface::INSECURE_EXTENSIONS); // Split the filename up by periods. The first part becomes the basename // the last part the final extension. $filename_parts = explode('.', $filename); // Remove file basename. $new_filename = array_shift($filename_parts); // Remove final extension. $final_extension = array_pop($filename_parts); // Loop through the middle parts of the name and add an underscore to the // end of each section that could be a file extension but isn't in the list // of allowed extensions. foreach ($filename_parts as $filename_part) { $new_filename .= '.' . $filename_part; if (!in_array(strtolower($filename_part), $allowed_extensions) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) { $new_filename .= '_'; } } $filename = $new_filename . '.' . $final_extension; if ($alerts && $original != $filename) { \Drupal::messenger()->addStatus(t('For security reasons, your upload has been renamed to %filename.', ['%filename' => $filename])); } } return $filename; } /** * Undoes the effect of file_munge_filename(). * * @param $filename * String with the filename to be unmunged. * * @return * An unmunged filename string. * * @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use * str_replace() instead. * * @see https://www.drupal.org/node/3032541 */ function file_unmunge_filename($filename) { @trigger_error('file_unmunge_filename() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use str_replace() instead. See https://www.drupal.org/node/3032541', E_USER_DEPRECATED); return str_replace('_.', '.', $filename); } /** * @} End of "defgroup file". */