diff --git a/CHANGELOG.md b/CHANGELOG.md index d63cb2d2a..11c8b497e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,10 @@ 1. [](#new) * Added support for registering assets from `HtmlBlock` + * Added unicode-safe `Utils::basename()` and `Utils::pathinfo()` methods 2. [](#improved) - * Improved `Filesystem::basename()` and `Filesystem::pathinfo()` to be UTF-8 safe + * Improved `Filesystem::basename()` and `Filesystem::pathinfo()` to be unicode-safe + * Made path handling unicode-safe, use new `Utils::basename()` and `Utils::pathinfo()` everywhere # v1.7.28 ## 01/24/2022 diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index 953bbc88e..134c62fba 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -198,7 +198,7 @@ class Assets extends PropertyObject call_user_func_array([$this, 'add'], $args); } else { // Get extension - $extension = pathinfo(parse_url($asset, PHP_URL_PATH), PATHINFO_EXTENSION); + $extension = Utils::pathinfo(parse_url($asset, PHP_URL_PATH), PATHINFO_EXTENSION); // JavaScript or CSS if ($extension !== '') { diff --git a/system/src/Grav/Common/Backup/Backups.php b/system/src/Grav/Common/Backup/Backups.php index 0465fe705..9c23908c4 100644 --- a/system/src/Grav/Common/Backup/Backups.php +++ b/system/src/Grav/Common/Backup/Backups.php @@ -105,7 +105,7 @@ class Backups public function getBackupDownloadUrl($backup, $base_url) { $param_sep = $param_sep = Grav::instance()['config']->get('system.param_sep', ':'); - $download = urlencode(base64_encode(basename($backup))); + $download = urlencode(base64_encode(Utils::basename($backup))); $url = rtrim(Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim( $base_url, '/' diff --git a/system/src/Grav/Common/Cache.php b/system/src/Grav/Common/Cache.php index c7b550cb9..ed40a085f 100644 --- a/system/src/Grav/Common/Cache.php +++ b/system/src/Grav/Common/Cache.php @@ -177,7 +177,7 @@ class Cache extends Getters public function purgeOldCache() { $cache_dir = dirname($this->cache_dir); - $current = basename($this->cache_dir); + $current = Utils::basename($this->cache_dir); $count = 0; foreach (new DirectoryIterator($cache_dir) as $file) { diff --git a/system/src/Grav/Common/Config/Setup.php b/system/src/Grav/Common/Config/Setup.php index 8ffd63762..f8ce94394 100644 --- a/system/src/Grav/Common/Config/Setup.php +++ b/system/src/Grav/Common/Config/Setup.php @@ -401,7 +401,7 @@ class Setup extends Data } // Create security.yaml salt if it doesn't exist into existing configuration environment if possible. - $securityFile = basename(static::$securityFile); + $securityFile = Utils::basename(static::$securityFile); $securityFolder = substr(static::$securityFile, 0, -\strlen($securityFile)); $securityFolder = $locator->findResource($securityFolder, true) ?: $locator->findResource($securityFolder, true, true); $filename = "{$securityFolder}/{$securityFile}"; diff --git a/system/src/Grav/Common/File/CompiledFile.php b/system/src/Grav/Common/File/CompiledFile.php index e55a4a5d8..222842278 100644 --- a/system/src/Grav/Common/File/CompiledFile.php +++ b/system/src/Grav/Common/File/CompiledFile.php @@ -10,6 +10,7 @@ namespace Grav\Common\File; use Exception; +use Grav\Common\Utils; use RocketTheme\Toolbox\File\PhpFile; use RuntimeException; use Throwable; @@ -88,7 +89,7 @@ trait CompiledFile $this->content = $cache['data']; } } catch (Exception $e) { - throw new RuntimeException(sprintf('Failed to read %s: %s', basename($this->filename), $e->getMessage()), 500, $e); + throw new RuntimeException(sprintf('Failed to read %s: %s', Utils::basename($this->filename), $e->getMessage()), 500, $e); } return parent::content($var); diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php b/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php index c23a6e954..b6c5230d8 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php @@ -335,7 +335,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa $list[$key] = $child->slug(); break; case 'basename': - $list[$key] = basename($key); + $list[$key] = Utils::basename($key); break; case 'folder': $list[$key] = $child->folder(); diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php b/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php index 25440a96a..c0ca5c405 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php @@ -637,7 +637,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface $payload = [ 'name' => $child->menu(), 'value' => $child->rawRoute(), - 'item-key' => basename($child->rawRoute() ?? ''), + 'item-key' => Utils::basename($child->rawRoute() ?? ''), 'filename' => $child->folder(), 'extension' => $child->extension(), 'type' => 'dir', @@ -692,7 +692,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface $route = $child->getRoute(); $route = $route ? ($route->toString(false) ?: '/') : ''; $payload = [ - 'item-key' => htmlspecialchars(basename($child->rawRoute() ?? $child->getKey())), + 'item-key' => htmlspecialchars(Utils::basename($child->rawRoute() ?? $child->getKey())), 'icon' => $icon, 'title' => htmlspecialchars($child->menu()), 'route' => [ diff --git a/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php b/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php index 613b1ec73..f590e3661 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php +++ b/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php @@ -16,13 +16,13 @@ use Grav\Common\Debugger; use Grav\Common\Flex\Types\Pages\PageIndex; use Grav\Common\Grav; use Grav\Common\Language\Language; +use Grav\Common\Utils; use Grav\Framework\Filesystem\Filesystem; use Grav\Framework\Flex\Storage\FolderStorage; use RocketTheme\Toolbox\File\MarkdownFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; use SplFileInfo; -use function assert; use function in_array; use function is_string; @@ -277,7 +277,7 @@ class PageStorage extends FolderStorage } else { $params = $template = $language = ''; } - $objectKey = basename($key); + $objectKey = Utils::basename($key); if (preg_match('|^(\d+)\.(.+)$|', $objectKey, $matches)) { [, $order, $folder] = $matches; } else { @@ -584,7 +584,7 @@ class PageStorage extends FolderStorage $mark = $matches[2] ?? ''; $ext = $matches[1] ?? ''; $ext .= $this->dataExt; - $markdown[$mark][basename($k, $ext)] = $timestamp; + $markdown[$mark][Utils::basename($k, $ext)] = $timestamp; } $modified = max($modified, $timestamp); @@ -675,7 +675,7 @@ class PageStorage extends FolderStorage /** @phpstan-var array{'storage_key': string, 'storage_timestamp': int, 'children': array} $parent */ $parent = &$list[$parentKey]; - $basename = basename($storage_key); + $basename = Utils::basename($storage_key); if (isset($parent['children'][$basename])) { $timestamp = $meta['storage_timestamp']; diff --git a/system/src/Grav/Common/Flex/Types/Users/UserObject.php b/system/src/Grav/Common/Flex/Types/Users/UserObject.php index d78687137..d9217917d 100644 --- a/system/src/Grav/Common/Flex/Types/Users/UserObject.php +++ b/system/src/Grav/Common/Flex/Types/Users/UserObject.php @@ -30,6 +30,7 @@ use Grav\Common\Flex\Types\UserGroups\UserGroupCollection; use Grav\Common\Flex\Types\UserGroups\UserGroupIndex; use Grav\Common\User\Interfaces\UserInterface; use Grav\Common\User\Traits\UserTrait; +use Grav\Common\Utils; use Grav\Framework\File\Formatter\JsonFormatter; use Grav\Framework\File\Formatter\YamlFormatter; use Grav\Framework\Filesystem\Filesystem; @@ -645,7 +646,7 @@ class UserObject extends FlexObject implements UserInterface, Countable $medium = MediumFactory::fromFile($path); if ($medium) { $media->add($path, $medium); - $name = basename($path); + $name = Utils::basename($path); if ($name !== $path) { $media->add($name, $medium); } @@ -814,7 +815,7 @@ class UserObject extends FlexObject implements UserInterface, Countable } // Calculate path without the retina scaling factor. - $realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', basename($filepath)); + $realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', Utils::basename($filepath)); $list[$filename] = [$file, $settings]; diff --git a/system/src/Grav/Common/Form/FormFlash.php b/system/src/Grav/Common/Form/FormFlash.php index b2c619e1c..7acaf7fdc 100644 --- a/system/src/Grav/Common/Form/FormFlash.php +++ b/system/src/Grav/Common/Form/FormFlash.php @@ -10,6 +10,7 @@ namespace Grav\Common\Form; use Grav\Common\Filesystem\Folder; +use Grav\Common\Utils; use Grav\Framework\Form\FormFlash as FrameworkFormFlash; use function is_array; @@ -58,7 +59,7 @@ class FormFlash extends FrameworkFormFlash Folder::create($tmp_dir); $tmp_file = $upload['file']['tmp_name']; - $basename = basename($tmp_file); + $basename = Utils::basename($tmp_file); if (!move_uploaded_file($tmp_file, $tmp_dir . '/' . $basename)) { return false; @@ -90,7 +91,7 @@ class FormFlash extends FrameworkFormFlash Folder::create($tmp_dir); $tmp_file = $upload['file']['tmp_name']; - $basename = basename($tmp_file); + $basename = Utils::basename($tmp_file); if (!move_uploaded_file($tmp_file, $tmp_dir . '/' . $basename)) { return false; diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php index 2b18255fa..7031945b2 100644 --- a/system/src/Grav/Common/GPM/GPM.php +++ b/system/src/Grav/Common/GPM/GPM.php @@ -631,7 +631,7 @@ class GPM extends Iterator throw new \RuntimeException("Malformed GPM URL: {$package_file}"); } - $filename = basename($package['path'] ?? ''); + $filename = Utils::basename($package['path'] ?? ''); if (Grav::instance()['config']->get('system.gpm.official_gpm_only') && ($package['host'] ?? null) !== 'getgrav.org') { throw new RuntimeException('Only official GPM URLs are allowed. You can modify this behavior in the System configuration.'); @@ -660,7 +660,7 @@ class GPM extends Iterator $package_file = realpath($package_file); if ($package_file && file_exists($package_file)) { - $filename = basename($package_file); + $filename = Utils::basename($package_file); Folder::create($tmp); copy($package_file, $tmp . DS . $filename); return $tmp . DS . $filename; @@ -692,7 +692,7 @@ class GPM extends Iterator } // either theme or plugin - $name = basename($source); + $name = Utils::basename($source); if (Utils::contains($name, 'theme')) { return 'theme'; } @@ -730,7 +730,7 @@ class GPM extends Iterator $glob = glob($source . '*.yaml') ?: []; foreach ($glob as $filename) { - $name = strtolower(basename($filename, '.yaml')); + $name = strtolower(Utils::basename($filename, '.yaml')); if (in_array($name, $ignore_yaml_files)) { continue; } diff --git a/system/src/Grav/Common/GPM/Installer.php b/system/src/Grav/Common/GPM/Installer.php index 1eed5b4de..8a1a5303e 100644 --- a/system/src/Grav/Common/GPM/Installer.php +++ b/system/src/Grav/Common/GPM/Installer.php @@ -12,6 +12,7 @@ namespace Grav\Common\GPM; use DirectoryIterator; use Grav\Common\Filesystem\Folder; use Grav\Common\Grav; +use Grav\Common\Utils; use RuntimeException; use ZipArchive; use function count; @@ -192,7 +193,7 @@ class Installer $package_folder_name = $zip->getNameIndex(0); if ($package_folder_name === false) { - throw new \RuntimeException('Bad package file: ' . basename($zip_file)); + throw new \RuntimeException('Bad package file: ' . Utils::basename($zip_file)); } $package_folder_name = preg_replace('#\./$#', '', $package_folder_name); $zip->close(); diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index 5519175e2..18d490295 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -735,7 +735,7 @@ class Grav extends Container /** @var Config $config */ $config = $this['config']; - $path_parts = pathinfo($path); + $path_parts = Utils::pathinfo($path); /** @var Pages $pages */ $pages = $this['pages']; diff --git a/system/src/Grav/Common/Helpers/YamlLinter.php b/system/src/Grav/Common/Helpers/YamlLinter.php index 71f0e873c..b31180f0e 100644 --- a/system/src/Grav/Common/Helpers/YamlLinter.php +++ b/system/src/Grav/Common/Helpers/YamlLinter.php @@ -11,6 +11,7 @@ namespace Grav\Common\Helpers; use Exception; use Grav\Common\Grav; +use Grav\Common\Utils; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use RegexIterator; @@ -108,7 +109,7 @@ class YamlLinter */ protected static function extractYaml($path) { - $extension = pathinfo($path, PATHINFO_EXTENSION); + $extension = Utils::pathinfo($path, PATHINFO_EXTENSION); if ($extension === 'md') { $file = MarkdownFile::instance($path); $contents = $file->frontmatter(); diff --git a/system/src/Grav/Common/Media/Traits/MediaObjectTrait.php b/system/src/Grav/Common/Media/Traits/MediaObjectTrait.php index 0949f1d50..edabbdeb6 100644 --- a/system/src/Grav/Common/Media/Traits/MediaObjectTrait.php +++ b/system/src/Grav/Common/Media/Traits/MediaObjectTrait.php @@ -141,7 +141,7 @@ trait MediaObjectTrait { $alternatives = []; foreach ($this->alternatives + [$this->get('width', 0) => $this] as $size => $alternative) { - if ($withDerived || $alternative->filename === basename($alternative->filepath)) { + if ($withDerived || $alternative->filename === Utils::basename($alternative->filepath)) { $alternatives[$size] = $alternative; } } diff --git a/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php b/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php index 98885e06c..2bddf9752 100644 --- a/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php +++ b/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php @@ -132,9 +132,9 @@ trait MediaUploadTrait if ($folder === '.') { $folder = ''; } - $filename = basename($filename); + $filename = Utils::basename($filename); } - $extension = pathinfo($filename, PATHINFO_EXTENSION); + $extension = Utils::pathinfo($filename, PATHINFO_EXTENSION); // Decide which filename to use. if ($settings['random_name']) { diff --git a/system/src/Grav/Common/Page/Markdown/Excerpts.php b/system/src/Grav/Common/Page/Markdown/Excerpts.php index f500f4abe..17f9cbff5 100644 --- a/system/src/Grav/Common/Page/Markdown/Excerpts.php +++ b/system/src/Grav/Common/Page/Markdown/Excerpts.php @@ -206,7 +206,7 @@ class Excerpts && (empty($url_parts['host']) || $url_parts['host'] === $grav['uri']->host()); if ($local_file) { - $filename = basename($url_parts['path']); + $filename = Utils::basename($url_parts['path']); $folder = dirname($url_parts['path']); // Get the local path to page media if possible. diff --git a/system/src/Grav/Common/Page/Medium/GlobalMedia.php b/system/src/Grav/Common/Page/Medium/GlobalMedia.php index af8ee841e..20f63ad56 100644 --- a/system/src/Grav/Common/Page/Medium/GlobalMedia.php +++ b/system/src/Grav/Common/Page/Medium/GlobalMedia.php @@ -11,6 +11,7 @@ namespace Grav\Common\Page\Medium; use Grav\Common\Grav; use Grav\Common\Media\Interfaces\MediaObjectInterface; +use Grav\Common\Utils; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use function dirname; @@ -89,7 +90,7 @@ class GlobalMedia extends AbstractMedia } $path = dirname($filename); - [$basename, $ext,, $extra] = $this->getFileParts(basename($filename)); + [$basename, $ext,, $extra] = $this->getFileParts(Utils::basename($filename)); $medium = MediumFactory::fromFile($filename); if (null === $medium) { diff --git a/system/src/Grav/Common/Page/Medium/MediumFactory.php b/system/src/Grav/Common/Page/Medium/MediumFactory.php index 6e9f820eb..620446b70 100644 --- a/system/src/Grav/Common/Page/Medium/MediumFactory.php +++ b/system/src/Grav/Common/Page/Medium/MediumFactory.php @@ -13,6 +13,7 @@ use Grav\Common\Grav; use Grav\Common\Data\Blueprint; use Grav\Common\Media\Interfaces\ImageMediaInterface; use Grav\Common\Media\Interfaces\MediaObjectInterface; +use Grav\Common\Utils; use Grav\Framework\Form\FormFlashFile; use Psr\Http\Message\UploadedFileInterface; use function dirname; @@ -37,7 +38,7 @@ class MediumFactory return null; } - $parts = pathinfo($file); + $parts = Utils::pathinfo($file); $path = $parts['dirname']; $filename = $parts['basename']; $ext = $parts['extension'] ?? ''; @@ -101,7 +102,7 @@ class MediumFactory return null; } - $parts = pathinfo($clientName); + $parts = Utils::pathinfo($clientName); $filename = $parts['basename']; $ext = $parts['extension'] ?? ''; $basename = $parts['filename']; diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index abda49bfe..25f8ff6b6 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -196,7 +196,7 @@ class Page implements PageInterface } // extract page language from page extension - $language = trim(basename($this->extension(), 'md'), '.') ?: null; + $language = trim(Utils::basename($this->extension(), 'md'), '.') ?: null; $this->language($language); $this->hide_home_route = $config->get('system.home.hide_in_urls', false); @@ -1465,7 +1465,7 @@ class Page implements PageInterface $this->extension = $var; } if (empty($this->extension)) { - $this->extension = '.' . pathinfo($this->name(), PATHINFO_EXTENSION); + $this->extension = '.' . Utils::pathinfo($this->name(), PATHINFO_EXTENSION); } return $this->extension; @@ -2109,9 +2109,9 @@ class Page implements PageInterface { if ($var !== null) { // Filename of the page. - $this->name = basename($var); + $this->name = Utils::basename($var); // Folder of the page. - $this->folder = basename(dirname($var)); + $this->folder = Utils::basename(dirname($var)); // Path to the page. $this->path = dirname($var, 2); } @@ -2150,7 +2150,7 @@ class Page implements PageInterface { if ($var !== null) { // Folder of the page. - $this->folder = basename($var); + $this->folder = Utils::basename($var); // Path to the page. $this->path = dirname($var); } diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index c4029fe9f..8ad2ccd8f 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -2065,7 +2065,7 @@ class Pages $list[$key] = $child->slug(); break; case 'basename': - $list[$key] = basename($key); + $list[$key] = Utils::basename($key); break; case 'folder': $list[$key] = $child->folder(); diff --git a/system/src/Grav/Common/Page/Types.php b/system/src/Grav/Common/Page/Types.php index 43fe0fb64..420c58860 100644 --- a/system/src/Grav/Common/Page/Types.php +++ b/system/src/Grav/Common/Page/Types.php @@ -12,6 +12,7 @@ namespace Grav\Common\Page; use Grav\Common\Data\Blueprint; use Grav\Common\Filesystem\Folder; use Grav\Common\Grav; +use Grav\Common\Utils; use InvalidArgumentException; use RocketTheme\Toolbox\ArrayTraits\ArrayAccess; use RocketTheme\Toolbox\ArrayTraits\Constructor; @@ -144,7 +145,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable if (strpos($name, 'modular/') !== 0) { continue; } - $list[$name] = ucfirst(trim(str_replace('_', ' ', basename($name)))); + $list[$name] = ucfirst(trim(str_replace('_', ' ', Utils::basename($name)))); } ksort($list); diff --git a/system/src/Grav/Common/Processors/RequestProcessor.php b/system/src/Grav/Common/Processors/RequestProcessor.php index 358e81b42..bad410c11 100644 --- a/system/src/Grav/Common/Processors/RequestProcessor.php +++ b/system/src/Grav/Common/Processors/RequestProcessor.php @@ -11,6 +11,7 @@ namespace Grav\Common\Processors; use Grav\Common\Processors\Events\RequestHandlerEvent; use Grav\Common\Uri; +use Grav\Common\Utils; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -42,7 +43,7 @@ class RequestProcessor extends ProcessorBase } $uri = $request->getUri(); - $ext = mb_strtolower(pathinfo($uri->getPath(), PATHINFO_EXTENSION)); + $ext = mb_strtolower(Utils::pathinfo($uri->getPath(), PATHINFO_EXTENSION)); $request = $request ->withAttribute('grav', $this->container) diff --git a/system/src/Grav/Common/Security.php b/system/src/Grav/Common/Security.php index 2d67bda5a..017720ca8 100644 --- a/system/src/Grav/Common/Security.php +++ b/system/src/Grav/Common/Security.php @@ -61,7 +61,7 @@ class Security if ($clean_svg !== false ) { file_put_contents($file, $clean_svg); } else { - $quarantine_file = basename($file); + $quarantine_file = Utils::basename($file); $quarantine_dir = 'log://quarantine'; Folder::mkdir($quarantine_dir); file_put_contents("$quarantine_dir/$quarantine_file", $original_svg); diff --git a/system/src/Grav/Common/Twig/Extension/FilesystemExtension.php b/system/src/Grav/Common/Twig/Extension/FilesystemExtension.php index f60fa12c2..9b9085558 100644 --- a/system/src/Grav/Common/Twig/Extension/FilesystemExtension.php +++ b/system/src/Grav/Common/Twig/Extension/FilesystemExtension.php @@ -373,11 +373,7 @@ class FilesystemExtension extends AbstractExtension */ public function pathinfo($path, $flags = null) { - if (null !== $flags) { - return pathinfo($path, (int)$flags); - } - - return pathinfo($path); + return Utils::pathinfo($path, $flags); } /** diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index cd339d3d6..76d9a9926 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -217,7 +217,7 @@ class Uri $path = $bits['path'] ?? '/'; // remove the extension if there is one set - $parts = pathinfo($path); + $parts = Utils::pathinfo($path); // set the original basename $this->basename = $parts['basename']; @@ -854,7 +854,7 @@ class Uri } if ($full_path) { - $path_info = pathinfo($full_path); + $path_info = Utils::pathinfo($full_path); $page_path = $path_info['dirname']; $filename = ''; @@ -899,7 +899,7 @@ class Uri $routes = $pages->routes(); // if this is an image, get the proper path - $url_bits = pathinfo($url_path); + $url_bits = Utils::pathinfo($url_path); if (isset($url_bits['extension'])) { $target_path = $url_bits['dirname']; } else { @@ -1046,7 +1046,7 @@ class Uri $base_url = rtrim($base . $grav['pages']->base(), '/') . $language_append; // if absolute and starts with a base_url move on - if (pathinfo($markdown_url, PATHINFO_DIRNAME) === '.' && $page->url() === '/') { + if (Utils::pathinfo($markdown_url, PATHINFO_DIRNAME) === '.' && $page->url() === '/') { return '/' . $markdown_url; } // no path to convert @@ -1085,7 +1085,7 @@ class Uri return $normalized_url; } - $path_info = pathinfo($full_path); + $path_info = Utils::pathinfo($full_path); $page_path = $path_info['dirname']; $filename = ''; diff --git a/system/src/Grav/Common/User/DataUser/User.php b/system/src/Grav/Common/User/DataUser/User.php index b442cc3e5..71e7f9b35 100644 --- a/system/src/Grav/Common/User/DataUser/User.php +++ b/system/src/Grav/Common/User/DataUser/User.php @@ -21,6 +21,7 @@ use Grav\Common\Page\Medium\MediumFactory; use Grav\Common\User\Authentication; use Grav\Common\User\Interfaces\UserInterface; use Grav\Common\User\Traits\UserTrait; +use Grav\Common\Utils; use Grav\Framework\Flex\Flex; use function is_array; @@ -177,7 +178,7 @@ class User extends Data implements UserInterface if ($path && is_file($path)) { $medium = MediumFactory::fromFile($path); if ($medium) { - $media->add(basename($path), $medium); + $media->add(Utils::basename($path), $medium); } } diff --git a/system/src/Grav/Common/User/DataUser/UserCollection.php b/system/src/Grav/Common/User/DataUser/UserCollection.php index 9f35e37e6..d0ada09c9 100644 --- a/system/src/Grav/Common/User/DataUser/UserCollection.php +++ b/system/src/Grav/Common/User/DataUser/UserCollection.php @@ -114,7 +114,7 @@ class UserCollection implements UserCollectionInterface if (!$user->exists()) { foreach ($files as $file) { if (Utils::endsWith($file, YAML_EXT)) { - $find_user = $this->load(trim(pathinfo($file, PATHINFO_FILENAME))); + $find_user = $this->load(trim(Utils::pathinfo($file, PATHINFO_FILENAME))); foreach ($fields as $field) { if (isset($find_user[$field]) && $find_user[$field] === $query) { return $find_user; diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index 9d76e1dd6..64c81a927 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -662,7 +662,7 @@ abstract class Utils // fire download event Grav::instance()->fireEvent('onBeforeDownload', new Event(['file' => $file, 'options' => &$options])); - $file_parts = pathinfo($file); + $file_parts = static::pathinfo($file); $mimetype = $options['mime'] ?? static::getMimeByExtension($file_parts['extension']); $size = filesize($file); // File size @@ -926,7 +926,7 @@ abstract class Utils */ public static function getMimeByFilename($filename, $default = 'application/octet-stream') { - return static::getMimeByExtension(pathinfo($filename, PATHINFO_EXTENSION), $default); + return static::getMimeByExtension(static::pathinfo($filename, PATHINFO_EXTENSION), $default); } /** @@ -971,7 +971,7 @@ abstract class Utils public static function checkFilename($filename) { $dangerous_extensions = Grav::instance()['config']->get('security.uploads_dangerous_extensions', []); - $extension = pathinfo($filename, PATHINFO_EXTENSION); + $extension = static::pathinfo($filename, PATHINFO_EXTENSION); return !( // Empty filenames are not allowed. @@ -985,6 +985,46 @@ abstract class Utils ); } + /** + * Unicode-safe version of PHP’s pathinfo() function. + * + * @link https://www.php.net/manual/en/function.pathinfo.php + * + * @param string $path + * @param int|null $flags + * @return array|string + */ + public static function pathinfo(string $path, int $flags = null) + { + $path = str_replace(['%2F', '%5C'], ['/', '\\'], rawurlencode($path)); + + if (null === $flags) { + $info = pathinfo($path); + } else { + $info = pathinfo($path, $flags); + } + + if (is_array($info)) { + return array_map('rawurldecode', $info); + } + + return rawurldecode($info); + } + + /** + * Unicode-safe version of the PHP basename() function. + * + * @link https://www.php.net/manual/en/function.basename.php + * + * @param string $path + * @param string $suffix + * @return string + */ + public static function basename(string $path, string $suffix = ''): string + { + return rawurldecode(basename(str_replace(['%2F', '%5C'], '/', rawurlencode($path)), $suffix)); + } + /** * Normalize path by processing relative `.` and `..` syntax and merging path * @@ -1620,8 +1660,8 @@ abstract class Utils $route = '/' . $matches[2]; // Exclude filename from the page lookup. - if (pathinfo($route, PATHINFO_EXTENSION)) { - $basename = '/' . basename($route); + if (static::pathinfo($route, PATHINFO_EXTENSION)) { + $basename = '/' . static::basename($route); $route = \dirname($route); } else { $basename = ''; diff --git a/system/src/Grav/Console/Cli/SandboxCommand.php b/system/src/Grav/Console/Cli/SandboxCommand.php index 2ba562542..0ba2850de 100644 --- a/system/src/Grav/Console/Cli/SandboxCommand.php +++ b/system/src/Grav/Console/Cli/SandboxCommand.php @@ -10,6 +10,7 @@ namespace Grav\Console\Cli; use Grav\Common\Filesystem\Folder; +use Grav\Common\Utils; use Grav\Console\GravCommand; use RuntimeException; use Symfony\Component\Console\Input\InputArgument; @@ -301,7 +302,7 @@ class SandboxCommand extends GravCommand foreach ($binaries as $bin) { chmod($bin, $dir_perms); - $io->writeln(' bin/' . basename($bin) . ' permissions reset to ' . decoct($dir_perms)); + $io->writeln(' bin/' . Utils::basename($bin) . ' permissions reset to ' . decoct($dir_perms)); } $io->newLine(); diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 1df7803f6..d25ebe3c5 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -579,7 +579,7 @@ class InstallCommand extends GpmCommand $tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true); $this->tmp = $tmp_dir . '/Grav-' . uniqid(); - $filename = $package->slug . basename($package->zipball_url); + $filename = $package->slug . Utils::basename($package->zipball_url); $filename = preg_replace('/[\\\\\/:"*?&<>|]+/m', '-', $filename); $query = ''; diff --git a/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php b/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php index efd9c7dbd..24e1fc2b3 100644 --- a/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php +++ b/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php @@ -97,7 +97,7 @@ trait ControllerResponseTrait $headers = $headers ?? []; $options = $options ?? ['force_download' => true]; - $file_parts = pathinfo($filename); + $file_parts = Utils::pathinfo($filename); if (!isset($headers['Content-Type'])) { $mimetype = Utils::getMimeByExtension($file_parts['extension']); @@ -140,7 +140,7 @@ trait ControllerResponseTrait $code = (int)$this->getConfig()->get('system.pages.redirect_default_code', 302); } - $ext = pathinfo($url, PATHINFO_EXTENSION); + $ext = Utils::pathinfo($url, PATHINFO_EXTENSION); $accept = $this->getAccept(['application/json', 'text/html']); if ($ext === 'json' || $accept === 'application/json') { return $this->createJsonResponse(['code' => $code, 'status' => 'redirect', 'redirect' => $url]); diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php index 539b84c99..d75380373 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php @@ -324,7 +324,7 @@ trait PageLegacyTrait $key = preg_replace(static::PAGE_ORDER_PREFIX_REGEX, '', $key); \assert(is_string($key)); } else { - $key = trim($parentKey . '/' . basename($this->getKey()), '/'); + $key = trim($parentKey . '/' . Utils::basename($this->getKey()), '/'); } if ($index->containsKey($key)) { @@ -336,7 +336,7 @@ trait PageLegacyTrait } while ($index->containsKey($test)); $key = $test; } - $folder = basename($key); + $folder = Utils::basename($key); // Get the folder name. $order = $this->getProperty('order'); @@ -539,7 +539,7 @@ trait PageLegacyTrait if ($language) { $language = '.' . $language; } - $format = '.' . ($this->getProperty('format') ?? pathinfo($this->name(), PATHINFO_EXTENSION)); + $format = '.' . ($this->getProperty('format') ?? Utils::pathinfo($this->name(), PATHINFO_EXTENSION)); return $language . $format; } diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php index 421cbec8c..c4c8cd7fb 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php @@ -15,10 +15,10 @@ use Grav\Common\Page\Interfaces\PageCollectionInterface; use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Page\Pages; use Grav\Common\Uri; +use Grav\Common\Utils; use Grav\Framework\Filesystem\Filesystem; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; -use function dirname; use function is_string; /** @@ -375,7 +375,7 @@ trait PageRoutableTrait $value = $this->getMasterKey() ?: $this->getKey(); } - return basename($value) ?: null; + return Utils::basename($value) ?: null; } ); } diff --git a/system/src/Grav/Framework/Flex/Storage/FileStorage.php b/system/src/Grav/Framework/Flex/Storage/FileStorage.php index 7a1764692..1864439cb 100644 --- a/system/src/Grav/Framework/Flex/Storage/FileStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/FileStorage.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Grav\Framework\Flex\Storage; use FilesystemIterator; +use Grav\Common\Utils; use Grav\Framework\Flex\Interfaces\FlexStorageInterface; use RuntimeException; use SplFileInfo; @@ -125,7 +126,7 @@ class FileStorage extends FolderStorage */ protected function getKeyFromPath(string $path): string { - return basename($path, $this->dataFormatter->getDefaultFileExtension()); + return Utils::basename($path, $this->dataFormatter->getDefaultFileExtension()); } /** diff --git a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php index 4da59d73c..600e98947 100644 --- a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php @@ -352,7 +352,7 @@ class FolderStorage extends AbstractFilesystemStorage */ protected function getKeyFromPath(string $path): string { - return basename($path); + return Utils::basename($path); } /** @@ -688,7 +688,7 @@ class FolderStorage extends AbstractFilesystemStorage $pattern .= '/{FILE}{EXT}'; } else { $filesystem = Filesystem::getInstance(true); - $this->dataFile = basename($pattern, $extension); + $this->dataFile = Utils::basename($pattern, $extension); $pattern = $filesystem->dirname($pattern) . '/{FILE}{EXT}'; } } diff --git a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php index 30da11e19..73e2b065d 100644 --- a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php @@ -13,6 +13,7 @@ namespace Grav\Framework\Flex\Storage; use Grav\Common\Data\Data; use Grav\Common\Filesystem\Folder; +use Grav\Common\Utils; use Grav\Framework\Filesystem\Filesystem; use InvalidArgumentException; use LogicException; @@ -53,9 +54,9 @@ class SimpleStorage extends AbstractFilesystemStorage $filesystem = Filesystem::getInstance(true); $extension = $this->dataFormatter->getDefaultFileExtension(); - $pattern = basename($options['folder']); + $pattern = Utils::basename($options['folder']); - $this->dataPattern = basename($pattern, $extension) . $extension; + $this->dataPattern = Utils::basename($pattern, $extension) . $extension; $this->dataFolder = $filesystem->dirname($options['folder']); $this->keyField = $options['key'] ?? 'storage_key'; $this->keyLen = (int)($options['key_len'] ?? 32); @@ -432,7 +433,7 @@ class SimpleStorage extends AbstractFilesystemStorage */ protected function getKeyFromPath(string $path): string { - return basename($path); + return Utils::basename($path); } /** diff --git a/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php b/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php index 05e3a4433..ad437ebe4 100644 --- a/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php +++ b/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php @@ -346,7 +346,7 @@ trait FlexMediaTrait } // Calculate path without the retina scaling factor. - $realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', basename($filepath)); + $realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', Utils::basename($filepath)); $list[$filename] = [$file, $settings]; @@ -508,7 +508,7 @@ trait FlexMediaTrait user_error(__METHOD__ . '() is deprecated since Grav 1.7, use Media class that implements MediaUploadInterface instead', E_USER_DEPRECATED); // Check the file extension. - $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + $extension = strtolower(Utils::pathinfo($filename, PATHINFO_EXTENSION)); $grav = Grav::instance(); diff --git a/system/src/Grav/Framework/Form/FormFlash.php b/system/src/Grav/Framework/Form/FormFlash.php index 06cc2eeea..863eb4af6 100644 --- a/system/src/Grav/Framework/Form/FormFlash.php +++ b/system/src/Grav/Framework/Form/FormFlash.php @@ -343,7 +343,7 @@ class FormFlash implements FormFlashInterface // Prepare upload data for later save $data = [ - 'name' => basename($filename), + 'name' => Utils::basename($filename), 'type' => Utils::getMimeByLocalFile($filename), 'size' => filesize($filename), ]; diff --git a/system/src/Grav/Installer/VersionUpdate.php b/system/src/Grav/Installer/VersionUpdate.php index 3efca1f31..c0658acc8 100644 --- a/system/src/Grav/Installer/VersionUpdate.php +++ b/system/src/Grav/Installer/VersionUpdate.php @@ -3,6 +3,7 @@ namespace Grav\Installer; use Closure; +use Grav\Common\Utils; /** * Class VersionUpdate @@ -25,7 +26,7 @@ final class VersionUpdate public function __construct(string $file, VersionUpdater $updater) { - $name = basename($file, '.php'); + $name = Utils::basename($file, '.php'); $this->revision = $name; [$this->version, $this->date, $this->patch] = explode('_', $name); diff --git a/system/src/Grav/Installer/YamlUpdater.php b/system/src/Grav/Installer/YamlUpdater.php index ac562495f..e842a6902 100644 --- a/system/src/Grav/Installer/YamlUpdater.php +++ b/system/src/Grav/Installer/YamlUpdater.php @@ -9,6 +9,7 @@ namespace Grav\Installer; +use Grav\Common\Utils; use Symfony\Component\Yaml\Yaml; use function assert; use function count; @@ -69,7 +70,7 @@ final class YamlUpdater file_put_contents($this->filename, $yaml); } catch (\Exception $e) { - throw new \RuntimeException('Failed to update ' . basename($this->filename) . ': ' . $e->getMessage()); + throw new \RuntimeException('Failed to update ' . Utils::basename($this->filename) . ': ' . $e->getMessage()); } return true;