Рекурсивно формируйте ul/li, экранируя подписи и атрибуты. Пункты без url выводите как текст, а для ссылок разрешайте только явно допустимые протоколы.
Генерация HTML‑меню из вложенного массива
Рекурсивно формируйте ul/li, экранируя подписи и атрибуты. Пункты без url выводите как текст, а для ссылок разрешайте только явно допустимые протоколы.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо преобразовать вложенный массив в разметку HTML‑меню. В качестве входных данных дан многомерный массив, где каждый элемент может содержать ключи label, url и опционально items — массив дочерних пунктов. Требуется пройтись по структуре и вывести соответствующий список <ul>/<li> с ссылками.
<?php
$navItems = [
[
'label' => 'Yil framework',
'url' => 'https://yilframework.ru',
],
[
'label' => 'More Frameworks',
'items' => [
['label' => 'Laravel', 'url' => 'http://laravel.com/'],
['label' => 'Slim', 'url' => 'http://www.slimframework.com/'],
],
],
[
'label' => 'Symfony',
'url' => 'https://symfony.com/',
],
];
?>
Ответ
Рекурсивно формируйте ul/li, экранируя подписи и атрибуты. Пункты без url выводите как текст, а для ссылок разрешайте только явно допустимые протоколы.
function menu(array $items): string {
$escape = fn(string $s) => htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$html = '<ul>';
foreach ($items as $item) {
$label = $escape((string) $item['label']);
$url = $item['url'] ?? null;
$scheme = is_string($url) ? strtolower((string) parse_url($url, PHP_URL_SCHEME)) : '';
$link = in_array($scheme, ['http', 'https'], true)
? '<a href="' . $escape($url) . '">' . $label . '</a>' : $label;
$html .= '<li>' . $link;
if (!empty($item['items'])) $html .= menu($item['items']);
$html .= '</li>';
}
return $html . '</ul>';
}
Вариант рассчитан на абсолютные HTTP(S)-ссылки из условия. Для внешней структуры также ограничьте глубину вложения.