Raiju/includes/page-path.php
2026-10-25 06:05:42 +03:00

98 lines
3.4 KiB
PHP

<?php
/**
* Helpers for public page paths and their flat-file content identifiers.
*
* Public paths may contain multiple SEO-friendly segments, for example
* `products/vitamin-d`. JSON files remain flat and use a reserved double
* underscore between segments: `en_products__vitamin-d.json`.
*/
function raijuPagePathSegmentPattern(): string {
return '[a-z0-9]+(?:-[a-z0-9]+)*';
}
function raijuPagePathPattern(): string {
$segment = raijuPagePathSegmentPattern();
return $segment . '(?:/' . $segment . ')*';
}
function raijuPageContentKeyPattern(): string {
$segment = raijuPagePathSegmentPattern();
return '[a-z]{2}_' . $segment . '(?:__' . $segment . ')*';
}
function raijuPageNormalizePath(string $path): string {
$path = trim(strtolower($path));
$path = trim($path, '/');
if ($path === '' || !preg_match('#^' . raijuPagePathPattern() . '$#', $path)) {
return '';
}
return $path;
}
function raijuPageIsValidPath(string $path): bool {
$path = trim($path);
return $path !== ''
&& $path === trim($path, '/')
&& $path === strtolower($path)
&& (bool)preg_match('#^' . raijuPagePathPattern() . '$#', $path);
}
function raijuPageContentKey(string $lang, string $path): string {
$path = raijuPageNormalizePath($path);
if (!preg_match('/^[a-z]{2}$/', $lang) || $path === '') {
return '';
}
return $lang . '_' . str_replace('/', '__', $path);
}
/** @return array{lang:string,path:string}|null */
function raijuPageParseContentKey(string $contentPage): ?array {
if (!preg_match('#^([a-z]{2})_(' . raijuPagePathSegmentPattern() . '(?:__' . raijuPagePathSegmentPattern() . ')*)$#', $contentPage, $matches)) {
return null;
}
return [
'lang' => $matches[1],
'path' => str_replace('__', '/', $matches[2]),
];
}
function raijuPageIsValidContentKey(string $contentPage): bool {
return raijuPageParseContentKey($contentPage) !== null;
}
function raijuPageJsonPath(string $root, string $lang, string $path): string {
$key = raijuPageContentKey($lang, $path);
return $key === '' ? '' : rtrim($root, '/\\') . '/content/pages/' . $key . '.json';
}
function raijuPageTemplatePath(string $root, string $lang, string $path): string {
$path = raijuPageNormalizePath($path);
if (!preg_match('/^[a-z]{2}$/', $lang) || $path === '') {
return '';
}
return rtrim($root, '/\\') . '/' . $lang . '/' . $path . '.php';
}
/**
* Relative browser path from a clean page URL back to the site root.
*/
function raijuPageBasePath(string $path, bool $languagePrefixed): string {
$path = raijuPageNormalizePath($path);
if ($path === '') return '';
$urlSegments = substr_count($path, '/') + 1 + ($languagePrefixed ? 1 : 0);
$requestPath = (string)parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
$directoryUrl = str_ends_with($requestPath, '/');
return str_repeat('../', max(0, $urlSegments - ($directoryUrl ? 0 : 1)));
}
function raijuPageUrlPath(string $lang, string $path, ?string $defaultLang = null): string {
$path = raijuPageNormalizePath($path);
if ($path === '') return '';
$defaultLang = $defaultLang ?: (defined('SITE_LANG_DEFAULT') ? SITE_LANG_DEFAULT : 'en');
if ($path === 'home') {
return $lang === $defaultLang ? '/' : '/' . $lang . '/';
}
return $lang === $defaultLang ? '/' . $path : '/' . $lang . '/' . $path;
}