Парсинг php-файла для создания опций
В последнюю версию Albireo CMS добавил возможность работать с php-файлом конфигурации через обычную форму. Это сильно упрощает администрирование сайта.
В системе для хранения опций используются разные конфигурационные php-файлы. Это совершенно стандартный подход, когда файл возвращает массив по return. Что-то вроде такого:
return [
'siteTitle' => 'Создание своего сайта - MAXSITE.ORG',
'siteDescription' => 'Создание своего сайта',
'siteYearCreation' => '2006',
'homeOutputModule' => 'home/home1.php',
'homeTPLfile' => 'one-column-3.php',
'homeLimitPagination1' => 10,
'homeLimitPagination2' => 12,
];
В админ-панели есть специальная страница Config, где собраны все конфиг-файлы сайта. По клику открывается стандартный текстовый редактор, где и можно редактировать файл.
Но мне было интересно решить другую задачу.
Часть config-файлов достаточно простая — в них, как в приведенном примере, нет сложного форматирования: просто 'key' => value. Фактически это сразу годится для парсинга в форму, где будет ключ массива и input-поле для ввода значения. Таким образом можно взять произвольный конфиг-файл, распарсить его в форму, потом, при сохранении, всё собирается обратно в тот же php-файл.
В чём «фишка»? Мы работаем с нативным php-файлом. Обычно для таких задач используется более удобные форматы данных, тот же JSON или серилизация. То есть данные в файле хранятся особым образом. Но поскольку я принципиально использую только PHP, то всё это не годится. Потому что файл можно править ручками как текст, а можно через админ-панель через парсинг. И важно, чтобы в каждом случае сохранить исходное форматирование, например комментарии.
Провозился я с этим несколько недель, за которые перепробовал самые разные подходы и варианты и в итоге остановился на самом простом, когда поле принимает значение в чистом php-формате.
В админке это выглядит так:

Но в реальности это такой файл (привожу весь код для полноты понимания):
<?php if (!defined('BASE_DIR')) exit('No direct script access allowed');
/**
* (c) Albireo CMS, https://maxsite.org/albireo, 2020-2025
*/
// default page data
return [
// Сжатие html-кода
'compress' => 1,
// Включить сбор статистики посещений страницы
'stat' => 1,
// Навигация под текстом по страницам type: blog по дате публикации date: дата
'nav' => 1,
// Навигация перед текстом по страницам type: blog по дате публикации date: дата
'nav-top' => 1,
// Файлы шапки шаблон/modules/*
'headers' => 'headers/header12.php',
// Файлы подвала
'footers' => 'footers/footer1.php',
// Файл в виде <style> ... </style> в HEAD
'css.layout' => 'fields.css',
'headers.title' => 'Albireo CMS',
'headers.subtitle' => 'The best site',
'headers.subtitle2' => '',
'headers.logo' => UPLOADS_URL . 'images/logo.webp',
'headers.namesite' => 'Albireo CMS',
// Разметка Open Graph protocol
'ogp[og:site_name]' => 'Website on Albireo CMS',
];
# end of file
Строчка с // над значением считается комментарием и выводится в описании поля. При этом можно использовать любые другие комментарии — они просто игнорируются для формы. Алгоритм парсинга достаточно «хитрый» для того, чтобы сохранить все строки файла нетронутыми. Но при этом, если нужно добавить новую опцию, они автоматом будут размещены в конце массива.
Я довольно много времени потратил на то, что пытался «играть» с типами данных. Изначально мне хотелось сделать так, чтобы строки автоматом сами оборачивались кавычками, массивы скобками, числа и bool как есть. В теории это позволило бы исключать кавычки, как это принято в PHP. Я столкнулся с проблемой когда пробовал ввести php-выражение, например 'my' => 1 + 2. Здесь невозможно привести фрагмент 1 + 2 к числу, который и есть итоговый, но для парсера (любого) это будет строчка '1 + 2', что очевидно является ошибкой.
Другой пример: 'debug' => LOCALHOST. Здесь любой парсер поймёт, что «LOCALHOST» — это строка, и никогда не будет знать, что это константа.
Ещё вариант: 'userLang' => detectUserLang('ru', ['en', 'ru', 'uk']). То есть для парсера это всё очень сложные варианты.
В итоге я понял, что проще и надёжней выводить всё как есть в формате PHP: если это строка, то должны быть кавычки, если массив, то скобки и т.п. Конечно, если пользователь ошибётся в редактировании, например не закроет или не укажет кавычку, то это будет php-ошибкой. Но это тоже самое, что и при редактировании всего файла как текст, то есть нет принципиальной разницы.
В Albireo CMS есть два файла, которые можно использовать как опции: config.php, где хранится основная информация и настройки сайта, и page-data.php, где хранятся дефолтные настройки (поля) записей. Остальные конфигурации в общем-то редко используются, поэтому их нет смысла править через форму. Но, если пользователю это нужно, то можно добавить любые config-файлы в настройках админ-панели.
Я думаю, что такая возможность достаточно крутая штука. С её помощью можно организовать любые опции сайта в виде нативного php-кода. В других системах ничего подобного нет.