normalizeSegments($rest); } return $this->normalizeSegments($path); } private function normalizeSegments(string $path): string { if ($path === '' || $path === '/') { return $path === '' ? '' : '/'; } $segments = explode('/', $path); $normalized = []; foreach ($segments as $index => $segment) { if ($segment === '') { $normalized[] = ''; continue; } $normalized[] = $this->normalizeSegment($segment, $index, $segments); } $result = implode('/', $normalized); return $result === '' ? '/' : $result; } /** * @param array $segments */ private function normalizeSegment(string $segment, int $index, array $segments): string { if (ctype_digit($segment)) { return '{id}'; } if (preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $segment) === 1) { return '{uuid}'; } if (preg_match('/^[0-9a-f]{32,64}$/i', $segment) === 1) { return '{hash}'; } if ($this->isArtworkPublicSlug($segment, $index, $segments)) { return '{slug}'; } return $segment; } /** * /art/{id}/{slug} stays distinct from /art/{id}/similar and other actions. * * @param array $segments */ private function isArtworkPublicSlug(string $segment, int $index, array $segments): bool { if ($index !== 3 || ($segments[1] ?? '') !== 'art') { return false; } if (! ctype_digit((string) ($segments[2] ?? ''))) { return false; } $actions = ['similar', 'view', 'download', 'edit', 'comments', 'favourite', 'favorite']; return ! in_array(strtolower($segment), $actions, true); } }