Делаю движок сайта. Работает он по следующему принципу. 1. Ссылка обрабатывается через ЧПУ и имеет вид http://site.ru/sauna/page 2. Страница 'page' находится по адресу /include/page.php 3. Выводящую страницу я собираю так: PHP: <!DOCTYPE html> <html> <head> <? $html = file_get_contents($path, TRUE); echo preg_replace('#.+<head>(.+)</head>.+#s', '$1', $html); ?> </head> <body> <? echo preg_replace('#.+<body>(.+)</body>.+#s', '$1', $html); ?> </body> </html> До сего момента всё было хорошо, пока я не захотел в page.php вставить кое-что через include(). Результат выводится как обычный текст: PHP: <!--? include('z/herb-menu.php'); ?--> После получаса размышлений, я понял, что я вставляю содержимое блока BODY, как текст, а мне нужно его вставлять, как код PHP. Вопрос. Как, получив содержимое другого файла в виде текста, обработать его так, будто это ещё код PHP? Надеюсь, понятно объяснил.
file_get_contents просто текст из файла получает, include выполняет PHP код, по этому замени file_get_contents на include. Будь осторожен с $path, чтобы в неё не подставили через ЧПУ путь файла с помощью которого смогут выполнить, то что нарушит безопасность. Ещё ты захочешь тег <title> дополнять из страниц, для этого посмотри https://secure.php.net/manual/ru/function.ob-start.php пример с фруктами. Не использую короткие теги <? ?> лучше полные <?php ?>. Сейчас актуальная версия PHP 5.6 и 7.
Об этом и речь! Я бы легко импортировал содержимое другого файла в результирующую страницу через include(), но у меня есть такие задачи: 1) Религия мне не позволяет использовать SQL . 2) Мне нравится настраивать страницу в одном файле (я и программист. и копирайтер, и сеошник, и сам делаю свой сайт). Поэтому я, открывая один файл, хочу и <title> с дискрипшеном для каждой страницы прописать, и <body> сформировать. В том, что предлагает индустрия, мне не нравится, что содержимое страницы хранится в одном месте, а описание (заголовок) страницы хранится в другом месте. Если я не буду использовать БД, то у меня будут отдельные файлы с содержимым страниц и отдельный файлы (или файл, например, в формате JSON) с описанием заголовка, дискрипшена и кивордз) для каждой страницы. Неужели нет какого-то красивого решения моей задачи?
Как сия религия называется? Вообще, страница разделяется, заголовок выносится в head.php (он же почти у всех одинаковый), футер - в footer.php, и потом перед подключением head.php можно будет в глобальной переменной задать title PHP: <!-- head.php -- > <!-- Куча разного кода --> <title><?= $title; ?>;</title> <!--- mainContent.php --> <?php $title = "Очень хороший сайт без грязного SQL"; include "head.php"; ?> Надеюсь, мысль ясна --- Добавлено --- И да, со временем, с разрастанием сайта тебе придётся либо использовать SQL в каком-либо варианте, либо таки имитировать его функции через json, xml или свой формат файлов. Лучше использовать SQL в любом варианте Поскольку там очень умные люди на сверхбыстром C писали все функции, а тут ты будешь всё делать сам и на медленном php
О! Это ужасная религия. Это гремучая смесь лени, страха и невежества! Но можно сказать и проще: зачем умножать сущности без нужды? Я все данные храню в файлах на домашнем компьютере. Я не боюсь атак, не заморачиваюсь с архивацией БД или с её переносом. Пока получается Правда, всё сложнее и сложнее оставаться адептом.
Ну это пока сайт небольшой. А чтоб не бояться атак на SQL, надо соблюдать всего два нехитрых правила, которые здесь много раз описаны.
Не совсем. Мой .httaccess: Код (Text): DirectoryIndex index.php Options -Indexes ErrorDocument 404 / RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^([^/]+)/([^/]+)/?$ index.php?one=$1&two=$2 [QSA] RewriteRule ^([^/]+)/?$ index.php?one=$1 [QSA] Я сижу на странице /index.php и с неё собираю очередную страницу сайта по запросу пользователя. Спойлер: Старый код Код (Text): <!DOCTYPE html> <html> <head> <?php //path $one = $_GET['one']; $two = $_GET['two']; if (isset($two)) { $path = $one . '/' . $two; } else if ($one == 'index.php') { $path = 'shop'; } else { $path = $one; }; $path .= ".php"; //html set_include_path( dirname(__FILE__) . '/include'); if (is_readable( get_include_path() . '/' . $path) == FALSE) { $path = '404.php'; }; $html = file_get_contents($path, TRUE); //head echo preg_replace('#.+<head>(.+)</head>.+#s', '$1', $html); include('z/head.php'); ?> </head> <body> <?php //body echo preg_replace('#.+<body>(.+)</body>.+#s', '$1', $html); //footer include('z/aside.php'); include('z/footer.php'); ?> </body> </html> Так мой сайт работает сейчас. Допустим, я его переделываю: Спойлер: Новый код Код (Text): <!DOCTYPE html> <html> <head> <?php echo "<title>$title</title>\n"; echo "<meta content=\"$description\" name=\"description\">\n"; echo "<meta content=\"$keywords\" name=\"keywords\">\n"; include('z/head.php'); ?> </head> <body> <?php //path $one = $_GET['one']; $two = $_GET['two']; if (isset($two)) { $path = $one . '/' . $two; } else if ($one == 'index.php') { $path = 'shop'; } else { $path = $one; }; $path .= ".php"; //html set_include_path( dirname(__FILE__) . '/include'); if (is_readable( get_include_path() . '/' . $path) == FALSE) { $path = '404.php'; }; include($path); //footer include('z/aside.php'); include('z/footer.php'); '</div>'; ?> </body> </html> Страница, которая импортируется, имеет такой код: Код (Text): <?php $title = 'Блог'; $discription = 'Это блог'; $keywords = 'блог'; ?> <article> <h1>Статьи</h1> <p>На этой странице размещены статьи.</p> </article> И в результате TITLE, DESCRIPTION и KEYWORDS пустые. Оно и понятно, ведь этим переменным присваиваются значения после заполнения HEAD. Как быть?
Можно и красивей оформить, PHP: <?php $title = 'Мой сайт'; function render($buffer) { global $title; // заменяем текст {&title} на содержимое $title, в тексте между ob_start("render"); и ob_end_flush(); который был напечатан return (str_replace("{&title}", $title, $buffer)); } ob_start("render"); ?> <html> <head> <title>{&title}</title> </head> <body> <p>Hello Word!</p> <?php // Изменяет $title $title .= ' :: Главная страница'; ?> </body> </html> <?php ob_end_flush(); // тут запускаем render() уже после изменения $title
Узнал ещё про стек буферов... Пробовал играться с этим, но желаемое не получилось. Допустим, задача - та же: - есть index.php - в него вытаскиваем head.php - в него вытаскиваем contetn.php - Как в <head> поменять TITLE. Товарищи выше помогли эту задачу решить через буфер. То есть при сбрасывании буфера запускается функция callback, в которой методом replace меняю строку {title} на $title. А теперь вернёмся к стеку буферов. Например, хочу вывести: HTML: Один Два Пишу: PHP: ob_start(); echo 'Два<br>'; ob_start(); echo 'Один<br>'; ob_end_flush(); ob_end_flush(); Надеюсь, что оно сначала выведет вложенный буфер второго уровня, а после этого - буфер первого уровня. Но не работает! Почему?
Потрать день, чтобы изучить всё https://secure.php.net/manual/ru/book.outcontrol.php Ответ https://secure.php.net/manual/ru/function.ob-get-contents.php
@denis01 Огромное спасибо! Сделал так: PHP: ob_start(); //статья $article = ob_get_contents(); ob_end_clean(); //шапка <head>...</head> <body> echo $article; </body> Работает! И очень красиво работает! Но пока искал информацию, наткнулся на упоминание о проблеме переполнения буфера. Это про что?
@anempadest а ещё можно использовать заместо кучи икнлудов и ob_start не по существу, и тд, можно использовать банальное пространство имён... Написать примитивный роутер, и от него плясать.
@askanim так давай пример, чтобы title поменять в layout из вложенного шаблона. Чтобы шаблоны были обычные PHP файлы с разными способами вывода.
@askanim где код который можно будет запустить и посмотреть пример с title без ob_start? Условия писал выше. https://github.com/yiisoft/yii2/blob/master/framework/base/View.php#L320 --- Добавлено --- https://github.com/twigphp/Twig/blob/v1.24.1/lib/Twig/Template.php#L203
@denis01 ну его всмысле самому придумывать не надо Он уже везде реализован, в готовом решении я к тому что зачем его самому придумывать , а вообще у себя я юзал раньше без шаблонизатора, require_once при подключении шаблона html. Я не смотрел в эту сторону но можно в принципе и на пространстве имён что нибудь замутить
ну я подумаю про psr-4 и сделаю, у меня же весь двиг на нём работает правда внутри автозагрузчик один фиг require подрубает .... Так что не знаю, просто что много таких функций как ob_start(); использовать не надо я к тому, что их нужно юзать в одном месте, сделать раз и потом к ним не возвращаться.
Есть правило "Лучше быстро, чем самостоятельно". Следуя ему, лучше скопировать готовое, чем писать самому. Но мне это правило не нравится. Я могу 100 раз скопировать, но так и не понять, почему и как оно работает. А если я пишу код своими ручками, то ко мне приходит знание. Может быть, в краткосрочной перспективе, я работаю медленнее, но стратегически растёт мой профессионализм и я не становлюсь копи-пастером. Буду благодарен за пример использования пространства имён.
@denis01 вот надо было тебе я просто сказал что так можно..... Завтра выложу код, на работе буду когда. Ща уже спать иду время позднее, я во Владивостоке живу.
@askanim Спокойной ночи! И интересует код, которым можно выводить HEAD с заменённым TITLE после инклуда ARTICLE при условии, что TITLE прописан в ARTICLE. --- Добавлено --- Неужели можно сделать ещё красивее и короче? PHP: <?php ob_start(); //url $url = $_GET['url']; $url = rtrim($url, '/'); //path $path = empty($url) ? 'show' : $url; $path = dirname(__FILE__) . '/include/' . $path . '.php'; //page if (is_readable($path)) { include($path); } else { include('error/404.php'); }; //буфер $article = ob_get_contents(); ob_end_clean(); //язык if (!$language) $language = 'ru'; ?> <!DOCTYPE html> <html> <head> <title><?=$title?></title> <meta content="<?=$description?>" name="description"> <meta content="<?=$keywords?>" name="keywords"> <meta content="<?=$language?>" http-equiv="Content-Language"> <?php include('z/head.php'); ?> </head> <body> <?php //article echo $article; //footer include('z/aside.php'); include('z/footer.php'); ?> </body> </html>