Создаем простое меню в php. Многоуровневое меню на PHP и MySQL. Получаем массив вот такого вида, где ключ массива это ID категории

В этой статье я покажу, как можно создавать многоуровневое меню на PHP и MySQL . Безусловно, вариантов его создания можно придумать много, но, судя по количеству Ваших вопросов на эту тему, Вам нужен пример. И его я приведу в этой статье. Сразу отмечу, что данная статья имеет смысл только для тех, кто знает PHP и умеет работать с MySQL . Всем остальным сначала надо пройти этот , либо прочитать какие-нибудь книги по PHP и MySQL .

Для начала создадим таблицу в базе данных со следующими полями:

  • id - уникальный идентификатор.
  • title - анкор ссылки в меню.
  • link - адрес, на который будет вести пункт меню.
  • parent_id - родительский ID. Если родительского пункта нет, то здесь будет NULL (либо можно ещё 0 поставить).

С таблицей разобрались, теперь пришло время PHP-кода . Полный PHP-код приведён ниже:

$mysqli = new mysqli("localhost", "root", "", "db"); // Подключаемся к БД
$result_set = $mysqli->query("SELECT * FROM `menu`"); // Делаем выборку всех записей из таблицы с меню
$items = array(); // Массив для пунктов меню
while (($row = $result_set->fetch_assoc()) != false) $items[$row["id"]] = $row; // Заполняем массив выборкой из БД
$childrens = array(); // Массив для соответствий дочерних элементов их родительским
foreach ($items as $item) {
if ($item["parent_id"]) $childrens[$item["id"]] = $item["parent_id"]; // Заполняем массив
}
function printItem($item, $items, $childrens) {
/* Выводим пункт меню */
echo "

  • ";
    echo "".$item["title"]."";
    $ul = false; // Выводились ли дочерние элементы?
    while (true) {
    /* Бесконечный цикл, в котором мы ищем все дочерние элементы */
    $key = array_search($item["id"], $childrens); // Ищем дочерний элемент
    if (!$key) {
    /* Дочерних элементов не найдено */
    if ($ul) echo ""; // Если выводились дочерние элементы, то закрываем список
    break; // Выходим из цикла
    }
    unset($childrens[$key]); // Удаляем найденный элемент (чтобы он не выводился ещё раз)
    if (!$ul) {
    echo "
      "; // Начинаем внутренний список, если дочерних элементов ещё не было
      $ul = true; // Устанавливаем флаг
      }
      echo printItem($items[$key], $items, $childrens); // Рекурсивно выводим все дочерние элементы
      }
      echo "";
      }
      ?>

      Этот код полностью рабочий, однако, Вы должны понимать, что так никто не пишет (в частности, вывод через echo HTML-тегов ). И Ваша задача взять алгоритм из этого кода, но не сам код. А дальше этот алгоритм подключить к своему движку. Я постарался тщательно прокомментировать код вывода многоуровневого меню на PHP и MySQL , но, безусловно, он не самый прозрачный и требует уже неплохих начальных знаний. Если Вы ещё плохо знаете PHP и MySQL , то сначала настоятельно рекомендую пройти этот

      Ни один сайт не обходится без навигации или как еще называют "меню сайта". Так вот меню сайта бывает одноуровневым и многоуровневым в виде дерева. Если с одноуровневым меню особых сложностей в плане реализации не возникает, то при создании многоуровневого меню нужно хорошо подумать.

      Самое главное в этой задаче это спроектировать базу данных для нашего многоуровневого меню. Создадим таблицу Categories с тремя полями id , title , parent где:

      • ID - идентификатор
      • Title - Название меню
      • Parent - Родитель категории по умолчанию 0

      За ветвление меню отвечает поле Parent если Parent = 0 , то эта категория является родительской. Для того чтобы добавить потомков к родительской категории нужно в поле parent указать ID нужного родителя. Например:

      Таблицы с категориями

      Как видно из таблицы, у родительской категории Автомобили есть два потомка - это Мазда и Хонда связанных по полю Parent . А у категории Мотоциклы два потомка - это Кавасаки и Харлей . При этом у категории Лодки нет потомков. Надеюсь, что Вы поняли,как связать категории.

      Далее переходим от слов к практике. Создадим таблицу Categories.

      CREATE TABLE IF NOT EXISTS `categories` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `parent` int(10) unsigned NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=20 ; -- -- Дамп данных таблицы `categories` -- INSERT INTO `categories` (`id`, `title`, `parent`) VALUES (1, "Автомобили", 0), (2, "Мотоциклы", 0), (3, "Мазда", 1), (4, "Хонда", 1), (5, "Кавасаки", 2), (6, "Харлей", 2), (7, "Мазда 3", 3), (8, "Мазда 6", 3), (9, "Седан", 7), (10, "Хечбэк", 7), (11, "Лодки", 0), (12, "Лифтбэк", 8), (13, "Кроссовер", 8), (14, "Белый", 13), (15, "Красный", 13), (16, "Черный", 13), (17, "Зеленый", 13), (18, "Мазда CX", 3), (19, "Мазда MX", 3);

      Алгоритм работы состоит из следующего:

      Создаем соединение с базой данных

      query("SET NAMES "utf8""); /* * Это "официальный" объектно-ориентированный способ сделать это * однако $connect_error не работал вплоть до версий PHP 5.2.9 и 5.3.0. */ if ($mysqli->connect_error) { die("Ошибка подключения (" . $mysqli->connect_errno . ") " . $mysqli->connect_error); } /* * Если нужно быть уверенным в совместимости с версиями до 5.2.9, * лучше использовать такой код */ if (mysqli_connect_error()) { die("Ошибка подключения (" . mysqli_connect_errno() . ") " . mysqli_connect_error()); }

      Пишем функцию получения данных из таблицы Categories

      //Получаем массив нашего меню из БД в виде массива function getCat($mysqli){ $sql = "SELECT * FROM `categories`"; $res = $mysqli->query($sql); //Создаем масив где ключ массива является ID меню $cat = array(); while($row = $res->fetch_assoc()){ $cat[$row["id"]] = $row; } return $cat; }

      Получаем массив вот такого вида, где ключ массива это ID категории.

      Функция построения дерева из массива от Tommy Lacroix

      //Функция построения дерева из массива от Tommy Lacroix function getTree($dataset) { $tree = array(); foreach ($dataset as $id => &$node) { //Если нет вложений if (!$node["parent"]){ $tree[$id] = &$node; }else{ //Если есть потомки то перебераем массив $dataset[$node["parent"]]["childs"][$id] = &$node; } } return $tree; }

      Получаем массив в виде дерева

      Скрипт целиком

      query("SET NAMES "utf8""); /* * Это "официальный" объектно-ориентированный способ сделать это * однако $connect_error не работал вплоть до версий PHP 5.2.9 и 5.3.0. */ if ($mysqli->connect_error) { die("Ошибка подключения (" . $mysqli->connect_errno . ") " . $mysqli->connect_error); } /* * Если нужно быть уверенным в совместимости с версиями до 5.2.9, * лучше использовать такой код */ if (mysqli_connect_error()) { die("Ошибка подключения (" . mysqli_connect_errno() . ") " . mysqli_connect_error()); } //Получаем массив нашего меню из БД в виде массива function getCat($mysqli){ $sql = "SELECT * FROM `categories`"; $res = $mysqli->query($sql); //Создаем масив где ключ массива является ID меню $cat = array(); while($row = $res->fetch_assoc()){ $cat[$row["id"]] = $row; } return $cat; } //Функция построения дерева из массива от Tommy Lacroix function getTree($dataset) { $tree = array(); foreach ($dataset as $id => &$node) { //Если нет вложений if (!$node["parent"]){ $tree[$id] = &$node; }else{ //Если есть потомки то перебераем массив $dataset[$node["parent"]]["childs"][$id] = &$node; } } return $tree; } //Получаем подготовленный массив с данными $cat = getCat($mysqli); //Создаем древовидное меню $tree = getTree($cat); //Шаблон для вывода меню в виде дерева function tplMenu($category){ $menu = "
    • ". $category["title"].""; if(isset($category["childs"])){ $menu .= "
        ". showCat($category["childs"]) ."
      "; } $menu .= "
    • "; return $menu; } /** * Рекурсивно считываем наш шаблон **/ function showCat($data){ $string = ""; foreach($data as $item){ $string .= tplMenu($item); } return $string; } //Получаем HTML разметку $cat_menu = showCat($tree); //Выводим на экран echo "
        ". $cat_menu ."
      "; ?>

      Результат работы

      Многоуровневое меню на PHP + MySQL для админки

      Если Вы хотите использовать данное меню в админке своего сайта, то нужно переписать пару функций tplMenu() , showCat() .

      ".$category["title"].""; }else{ $menu = ""; } if(isset($category["childs"])){ $i = 1; for($j = 0; $j < $i; $j++){ $str .= "→"; } $i++; $menu .= showCat($category["childs"], $str); } return $menu; } /** * Рекурсивно считываем наш шаблон **/ function showCat($data, $str){ $string = ""; $str = $str; foreach($data as $item){ $string .= tplMenu($item, $str); } return $string; } //Получаем HTML разметку $cat_menu = showCat($tree, ""); //Выводим на экран echo ""; ?>

      Результат работы

      Выбери Автомобили → Мазда →→ Мазда 3 →→→ Седан →→→ Хечбэк →→ Мазда 6 →→→ Лифтбэк →→→ Кроссовер →→→→ Белый →→→→ Красный →→→→ Черный →→→→ Зеленый →→ Мазда CX →→ Мазда MX → Хонда Мотоциклы → Кавасаки → Харлей Лодки

      Именно это мы сейчас и разберем. И так, стоит задача, сделать вертикальное меню, в виде выпадающего списка.

      Как это можно реализовать на PHP? Очень просто! Например, у нас есть файл index.php, который в зависимости от выбранного раздела в выпадающем списке, должен отображать соответствующий контент на странице. Реализуется это следующим образом:

      1. Создаем файлы в формате.html, которые и будут содержать в себе необходимый для вывода контент.

      2. Создаем (пишем) в скрипте index.php необходимые условия, для вывода соответствующей информации.

      3. Рассматриваем созданный скрипт с позиции безопасности выполняемого сценария.

      Ну, вроде, как с теорией закончил, переходим к практике. Сначала создаем статические страницы в формате .html , которые и будут содержать необходимую информацию. Там можно написать все, что душе угодно:) В итоге у нас должно получиться, как минимум два файла first.html и second.html , соответственно потом их можно будет сделать сколько угодно, поняв основной алгоритм работы кода.

      Для вывода выпадающего списка в файле index.php создаем html форму, и ниже пишем PHP скрипт такого содержания:



      Menu PHP


      Выпадающее меню на PHP












      if (isset ($_GET ["where" ]))
      {
      if ($_GET ["where" ]==1 )
      $file = "first.html" ;
      if ($_GET ["where" ]==2 )
      $file = "second.html" ;
      include ($file );
      }
      ?>


      Вот и готов код выпадающего меню, и что самое интересное он будет нормально функционировать, но с точки зрения безопасности, он уязвим.

      Уязвимость данного скрипта заключается в том, что переменная $file остается не инициализирована, и в этом случае значение автоматически созданной переменной попадает сразу в функцию include , а она в свою очередь успешно ее (переменную) подключает и отображает на экране. И это может быть не только файл конфигурации .htaccess . Для того, что-бы взломать данный сценарий, достаточно параметру where передать не предусмотренное кодом значение, ну например 3. А так, как это значение не предусмотрено сценарием, то просто переменная $file не пройдет инициализацию. Поэтому, ей можно будет задать произвольное значение через строку URL.

      http://localhost/index.php?where=3&file=.htaccess

      Но это так, небольшое отступление от темы. 😀

      Вариант решения данной проблемы достаточно прост, переменную $file просто необходимо инициализировать до начала использования, т. е. присвоить ей значение по умолчанию.

      Здесь, если параметр where передан скрипту, то переменная будет инициализирована корректно, иначе просто окажется пустой. Вот такое получилось [безопасное] выпадающее меню на PHP.

      P.S. Создавая сценарии необходимо учитывать и соответственно исключать все возможные векторы атак. Только так можно создать проект, который будет отвечать правилам безопасности и востребован заказчиком. До новых встреч!

      Поскольку она раскрывает содержание модуля menu.php . Ниже будет представлена собственная разработка меню на PHP, которая была написана с нуля в блокноте.

      Этот код особенно будет полезен для динамичных сайтов, которые имеют самописные движки . Я предложу два варианта кода, которые имеют незначительные отличия (в чем различие будет пояснено после).

      Для начала приведу примерную структуру сайта, для которого подойдет это меню. Структура сайта должна иметь следующий вид (классический вид):

      /index.html /razdel_1/ /razdel_1/articles_1.html /razdel_1/articles_2.html ... /razdel_2/ /razdel_2/articles_1.html /razdel_2/articles_2.html ... ... ... /razdel_N/articles_2.html

      Сайт может содержать у разделов еще и подразделы:

      /razdel_1/podzaderl_1/ /razdel_1/podzaderl_1/articles_1.html /razdel_1/podzaderl_1/articles_2.html ... /razdel_1/podzaderl_2/articles_1.html /razdel_1/podzaderl_2/articles_2.html

      Такая структура также будет работать для нашего меню лишь с небольшими отличиями.

      Я предлагаю создать отдельный файл для меню на php. Например, menu.php было бы отличным названием для такого файлика. Для реализации меню также представлен стиль меню в CSS, чтобы сразу сделать его более менее красивым. Естественно этот стиль дается только для ознакомления, поскольку дизайны у сайтов очень разные.

      Код для стиля меню в CSS:

      .menu { height:42px; padding:0 0 0 16px; background:url(images/spacer.png) repeat; } .menu li { display:block; float:left; } .menu li.active { background: #000011; } .menu a { color:#FFF; display:block; line-height:42px; text-decoration:none; padding:0 14px; } .menu a:hover { background:url(images/spacer.png) repeat; }

      Теперь, давайте рассмотрим первый вариант реализации меню на PHP, который является немного упрощенным.

      Первый вариант кода меню на PHP

      \n"; for ($i=0;$i": "
    • "; echo "".$array_menu[$i]["name"]."
    • \n"; } echo "
    "; ?>

    Меню можно разделить на две части. Первая содержит информационный массив $array_menu , в который заносятся названия наших разделов с ссылками на разделы. Есть вариант забить эти данные в базу данных mySQL, но особо смысла в этом нет, поскольку выборка совсем небольшая, поэтому на скорость работы это никак не повлияет.

    Вторая часть содержит вывод меню через цикл for . В цикле происходит сравнение адреса сайта с адресом из массива $array_menu . Если есть совпадение, то выводим очередной раздел меню со специальным классом active:

  • , иначе просто
  • . Это позволяет нам выделить каким-то цветом ту часть меню, в котором находится пользователь. На мой взгляд, это необходимая вещь для любого сайта, чтобы пользователь мог понимать в каком разделе он находится.

    Порядок следования в массиве будет сохранятся и при выводе меню на сайте. То есть массив надо заполнять в порядке, в котором нужно выводить меню.

    Примечание:
    В случае, если URL (адреса) заголовком разделов имеют вид:
    /razdel_1
    или такой
    /razdel_1/nazvanie_razdela.html
    то в array_menu нужно записывать точное совпадение:
    $array_menu[$i]["url"]="/razdel_1"
    или для второго случая:
    $array_menu[$i]["url"]="/razdel_1/nazvanie_razdela.html" ;

    Как работает первый вариант меню?
    Он подсвечивает меню только, если Вы находитесь по адресу заголовка раздела. Например, если адрес страницы будет /razdel_1/articles_1.html , то меню никак не будет подсвечиваться.

    Второй вариант кода является модифицированным вариантом первого и предусматривает возможность подсвечивания меню даже в статьях, которые находятся в разделах.

    Второй вариант кода меню на PHP

    "; for ($i=0;$i": "
  • "; echo "".$array_menu[$i]["title"]."
  • "; } else { echo ($URL) == ($array_menu[$i]["url"]) ? "
  • ": "
  • "; echo "".$array_menu[$i]["title"]."
  • "; } } echo ""; ?>
    Апр 23 2017

    В предыдущих уроках мы разобрали на примерах, что такое массивы. В этом уроке мы используем массивы на практике для создания меню на сайте.

    Чем они удобнее обычных HTML-тегов?

    Ну, допустим, наш сайт имеет 100 страниц, на каждой из которых имеется одно и то же меню. И вдруг нам понадобилось изменить пункты меню. Используя только HTML, нам придётся делать правки на 100 страницах сайта, это очень много. Так вот на помощь в таких ситуациях к нам приходит PHP. Достаточно будет поменять пункты меню всего лишь один раз в одном файле.

    А теперь поехали.

    На локальном хостинге в папке “domains создаём папку под названием “array - menu . local ”.

    В этой папке создаём четыре файла: index . php , about . php , contact . php и menu . php .

    !!! Синтаксис файлов должен быть PHP .

    В файле index.php пишем простой HTML каркас.




    charset ="utf-8" >



    Главная


    include ("menu.php" );
    ?>

    Копируем этот код в файлы about.php и contact.php. Меняем только названия страниц в теге

    .

    Пишем код для меню.

    В файле menu.php пишем ассоциативный массив.

    $menu = array (
    "index"=> "index.php",
    "about"=> "about.php",
    "contacts"=> "contact.php"
    );
    ?>

    Ниже с помощью тегов HTML пишем меню.

    В браузере мы увидим обычное меню в виде списка.

    Кликая на любом пункте меню мы перейдём на соответствующую страницу, меню при этом будет на всех страницах.

    Теперь усложним задачу. Всё удаляем из файла menu.php и...

    Пишем многомерный массив.




    charset ="utf-8" >
    <span>Использование массива для вывода меню на сайте. </span>


    $menu = array (
    array ("link"=> "Главная", "href"=> "index.php" ),
    array ("link"=> "О нас", "href"=> "about.php" ),
    array ("link"=> "Контакты", "href"=> "contact.php" )
    );
    ?>



    И на последнем этапе...

    Отрисовываем меню с помощью цикла foreach .

    Удаляем из файла menu.php список