Парсинг php-файла для создания опций

09-04-2025Время чтения ~ 4 мин.Albireo CMS / Framework 86

В последнюю версию 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-формате.

В админке это выглядит так:

Опции в админке Albireo CMS

Но в реальности это такой файл (привожу весь код для полноты понимания):

<?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-кода. В других системах ничего подобного нет.

Похожие записи
Оставьте комментарий!