За последние 24 часа нас посетили 33437 программистов и 1754 робота. Сейчас ищут 1262 программиста ...

include VS file_get_contents

Тема в разделе "PHP для новичков", создана пользователем anempadest, 25 июн 2016.

  1. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    Делаю движок сайта. Работает он по следующему принципу.
    1. Ссылка обрабатывается через ЧПУ и имеет вид
    http://site.ru/sauna/page
    2. Страница 'page' находится по адресу
    /include/page.php
    3. Выводящую страницу я собираю так:
    PHP:
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <?
    5. $html = file_get_contents($path, TRUE);
    6. echo preg_replace('#.+<head>(.+)</head>.+#s', '$1', $html);
    7. ?>
    8. </head>
    9. <body>
    10. <?
    11. echo preg_replace('#.+<body>(.+)</body>.+#s', '$1', $html);
    12. ?>
    13. </body>
    14. </html>
    До сего момента всё было хорошо, пока я не захотел в page.php вставить кое-что через include(). Результат выводится как обычный текст:
    PHP:
    1. <!--?
    2. include('z/herb-menu.php');
    3. ?-->
    После получаса размышлений, я понял, что я вставляю содержимое блока BODY, как текст, а мне нужно его вставлять, как код PHP.

    Вопрос.
    Как, получив содержимое другого файла в виде текста, обработать его так, будто это ещё код PHP?
    Надеюсь, понятно объяснил.
     
    #1 anempadest, 25 июн 2016
    Последнее редактирование модератором: 25 июн 2016
  2. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    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.
     
  3. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    Об этом и речь!
    Я бы легко импортировал содержимое другого файла в результирующую страницу через include(), но у меня есть такие задачи:
    1) Религия мне не позволяет использовать SQL .
    2) Мне нравится настраивать страницу в одном файле (я и программист. и копирайтер, и сеошник, и сам делаю свой сайт). Поэтому я, открывая один файл, хочу и <title> с дискрипшеном для каждой страницы прописать, и <body> сформировать.

    В том, что предлагает индустрия, мне не нравится, что содержимое страницы хранится в одном месте, а описание (заголовок) страницы хранится в другом месте. Если я не буду использовать БД, то у меня будут отдельные файлы с содержимым страниц и отдельный файлы (или файл, например, в формате JSON) с описанием заголовка, дискрипшена и кивордз) для каждой страницы.

    Неужели нет какого-то красивого решения моей задачи?
     
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.598
    Симпатии:
    1.764
    Как сия религия называется?

    Вообще, страница разделяется, заголовок выносится в head.php (он же почти у всех одинаковый), футер - в footer.php, и потом перед подключением head.php можно будет в глобальной переменной задать title
    PHP:
    1. <!-- head.php -- >
    2. <!-- Куча разного кода -->
    3. <title><?= $title; ?>;</title>
    4.  
    5. <!--- mainContent.php -->
    6. <?php
    7. $title = "Очень хороший сайт без грязного SQL";
    8. include "head.php";
    9. ?>
    Надеюсь, мысль ясна
    --- Добавлено ---
    И да, со временем, с разрастанием сайта тебе придётся либо использовать SQL в каком-либо варианте, либо таки имитировать его функции через json, xml или свой формат файлов. Лучше использовать SQL в любом варианте :) Поскольку там очень умные люди на сверхбыстром C писали все функции, а тут ты будешь всё делать сам и на медленном php
     
  5. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    Пример с фруктами понятен? Это и есть довольно хорошее решение
     
    anempadest нравится это.
  6. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    О! Это ужасная религия. Это гремучая смесь лени, страха и невежества!
    Но можно сказать и проще: зачем умножать сущности без нужды? Я все данные храню в файлах на домашнем компьютере. Я не боюсь атак, не заморачиваюсь с архивацией БД или с её переносом. Пока получается :) Правда, всё сложнее и сложнее оставаться адептом.
     
  7. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.598
    Симпатии:
    1.764
    Ну это пока сайт небольшой. А чтоб не бояться атак на SQL, надо соблюдать всего два нехитрых правила, которые здесь много раз описаны.
     
  8. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    Не совсем.

    Мой .httaccess:
    Код (Text):
    1. DirectoryIndex index.php
    2. Options -Indexes
    3. ErrorDocument 404 /
    4.  
    5. RewriteEngine On
    6. RewriteCond %{REQUEST_FILENAME} !-d
    7. RewriteCond %{REQUEST_FILENAME} !-f
    8. RewriteRule ^([^/]+)/([^/]+)/?$ index.php?one=$1&two=$2 [QSA]
    9. RewriteRule ^([^/]+)/?$ index.php?one=$1 [QSA]
    Я сижу на странице /index.php и с неё собираю очередную страницу сайта по запросу пользователя.
    Код (Text):
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <?php
    5. //path
    6. $one = $_GET['one'];
    7. $two = $_GET['two'];
    8. if (isset($two)) {
    9.     $path = $one . '/' . $two;
    10. } else if ($one == 'index.php') {
    11.     $path = 'shop';
    12. } else {
    13.     $path = $one;
    14. };
    15. $path .= ".php";
    16. //html
    17. set_include_path( dirname(__FILE__) . '/include');
    18. if (is_readable( get_include_path() . '/' . $path) == FALSE) {
    19.     $path = '404.php';
    20. };
    21. $html = file_get_contents($path, TRUE);
    22. //head
    23. echo preg_replace('#.+<head>(.+)</head>.+#s', '$1', $html);
    24. include('z/head.php');
    25. ?>
    26. </head>
    27. <body>
    28. <?php
    29. //body
    30. echo preg_replace('#.+<body>(.+)</body>.+#s', '$1', $html);
    31. //footer
    32. include('z/aside.php');
    33. include('z/footer.php');
    34. ?>
    35. </body>
    36. </html>
    Так мой сайт работает сейчас. Допустим, я его переделываю:
    Код (Text):
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <?php
    5. echo "<title>$title</title>\n";
    6. echo "<meta content=\"$description\" name=\"description\">\n";
    7. echo "<meta content=\"$keywords\" name=\"keywords\">\n";
    8. include('z/head.php');
    9. ?>
    10. </head>
    11. <body>
    12. <?php
    13. //path
    14. $one = $_GET['one'];
    15. $two = $_GET['two'];
    16. if (isset($two)) {
    17.     $path = $one . '/' . $two;
    18. } else if ($one == 'index.php') {
    19.     $path = 'shop';
    20. } else {
    21.     $path = $one;
    22. };
    23. $path .= ".php";
    24. //html
    25. set_include_path( dirname(__FILE__) . '/include');
    26. if (is_readable( get_include_path() . '/' . $path) == FALSE) {
    27.     $path = '404.php';
    28. };
    29. include($path);
    30. //footer
    31. include('z/aside.php');
    32. include('z/footer.php');
    33. '</div>';
    34. ?>
    35. </body>
    36. </html>
    Страница, которая импортируется, имеет такой код:
    Код (Text):
    1. <?php
    2. $title = 'Блог';
    3. $discription = 'Это блог';
    4. $keywords = 'блог';
    5. ?>
    6. <article>
    7.     <h1>Статьи</h1>
    8.     <p>На этой странице размещены статьи.</p>
    9. </article>
    И в результате TITLE, DESCRIPTION и KEYWORDS пустые. Оно и понятно, ведь этим переменным присваиваются значения после заполнения HEAD.

    Как быть?
     
    #8 anempadest, 25 июн 2016
    Последнее редактирование: 25 июн 2016
  9. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    Можно и красивей оформить,
    PHP:
    1. <?php
    2.  
    3. $title = 'Мой сайт';
    4.  
    5. function render($buffer)
    6. {
    7.   global $title;
    8.   // заменяем текст {&title} на содержимое $title, в тексте между ob_start("render"); и ob_end_flush(); который был напечатан
    9.   return (str_replace("{&title}", $title, $buffer));
    10. }
    11.  
    12. ob_start("render");
    13.  
    14. ?>
    15. <html>
    16. <head>
    17.     <title>{&title}</title>
    18. </head>
    19. <body>
    20. <p>Hello Word!</p>
    21. <?php
    22. // Изменяет $title
    23. $title .= ' :: Главная страница';
    24. ?>
    25. </body>
    26. </html>
    27. <?php
    28.  
    29. ob_end_flush(); // тут запускаем render() уже после изменения $title
     
    anempadest нравится это.
  10. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    Тысяча чертей! Оно работает!
    Вы меня спасли! :)
     
  11. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    Узнал ещё про стек буферов... Пробовал играться с этим, но желаемое не получилось.
    Допустим, задача - та же:
    - есть index.php
    - в него вытаскиваем head.php
    - в него вытаскиваем contetn.php
    - Как в <head> поменять TITLE.

    Товарищи выше помогли эту задачу решить через буфер. То есть при сбрасывании буфера запускается функция callback, в которой методом replace меняю строку {title} на $title.

    А теперь вернёмся к стеку буферов.
    Например, хочу вывести:

    HTML:
    1. Один
    2. Два
    Пишу:
    PHP:
    1. echo 'Два<br>';
    2. echo 'Один<br>';
    Надеюсь, что оно сначала выведет вложенный буфер второго уровня, а после этого - буфер первого уровня. Но не работает! Почему?
     
  12. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
  13. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    @denis01
    Огромное спасибо!
    Сделал так:
    PHP:
    1. //статья
    2. $article = ob_get_contents();
    3. //шапка
    4. <head>...</head>
    5. <body>
    6. echo $article;
    7. </body>
    Работает! И очень красиво работает!

    Но пока искал информацию, наткнулся на упоминание о проблеме переполнения буфера. Это про что?
     
  14. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    где такое пишут? чтобы контекст понять
     
  15. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @anempadest а ещё можно использовать заместо кучи икнлудов и ob_start не по существу, и тд, можно использовать банальное пространство имён... Написать примитивный роутер, и от него плясать.
     
  16. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    @askanim так давай пример, чтобы title поменять в layout из вложенного шаблона. Чтобы шаблоны были обычные PHP файлы с разными способами вывода.
     
  17. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @denis01 любой framework, и в придачу на моём это уже реализовано хочешь передать передавай.
     
  18. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
  19. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @denis01 ну его всмысле самому придумывать не надо :D Он уже везде реализован, в готовом решении я к тому что зачем его самому придумывать :), а вообще у себя я юзал раньше без шаблонизатора, require_once при подключении шаблона html.

    Я не смотрел в эту сторону но можно в принципе и на пространстве имён что нибудь замутить :)
     
  20. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    Значит кода не будет. Ясно, понятно.
     
  21. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    ну я подумаю про psr-4 и сделаю, у меня же весь двиг на нём работает правда внутри автозагрузчик один фиг require подрубает .... Так что не знаю, просто что много таких функций как ob_start(); использовать не надо я к тому, что их нужно юзать в одном месте, сделать раз и потом к ним не возвращаться.
     
  22. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    Есть правило "Лучше быстро, чем самостоятельно". Следуя ему, лучше скопировать готовое, чем писать самому. Но мне это правило не нравится. Я могу 100 раз скопировать, но так и не понять, почему и как оно работает. А если я пишу код своими ручками, то ко мне приходит знание. Может быть, в краткосрочной перспективе, я работаю медленнее, но стратегически растёт мой профессионализм и я не становлюсь копи-пастером.

    Буду благодарен за пример использования пространства имён.
     
  23. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    @askanim вот уже два человека ждут
     
  24. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @denis01 вот надо было тебе я просто сказал что так можно..... Завтра выложу код, на работе буду когда. Ща уже спать иду время позднее, я во Владивостоке живу.
     
  25. anempadest

    anempadest Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    42
    Симпатии:
    0
    @askanim
    Спокойной ночи! И интересует код, которым можно выводить HEAD с заменённым TITLE после инклуда ARTICLE при условии, что TITLE прописан в ARTICLE.
    --- Добавлено ---
    Неужели можно сделать ещё красивее и короче?

    PHP:
    1. <?php
    2. //url
    3. $url = $_GET['url'];
    4. $url = rtrim($url, '/');
    5. //path
    6. $path = empty($url) ? 'show' : $url;
    7. $path = dirname(__FILE__) . '/include/' . $path . '.php';
    8. //page
    9. if (is_readable($path)) {
    10.     include($path);
    11. } else {
    12.     include('error/404.php');
    13. };
    14. //буфер
    15. $article = ob_get_contents();
    16. //язык
    17. if (!$language) $language = 'ru';
    18. ?>
    19. <!DOCTYPE html>
    20. <html>
    21.  
    22. <head>
    23. <title><?=$title?></title>
    24. <meta content="<?=$description?>" name="description">
    25. <meta content="<?=$keywords?>" name="keywords">
    26. <meta content="<?=$language?>" http-equiv="Content-Language">
    27. <?php include('z/head.php'); ?>
    28. </head>
    29.  
    30. <body>
    31.  
    32. <?php
    33. //article
    34. echo $article;
    35. //footer
    36. include('z/aside.php');
    37. include('z/footer.php');
    38. ?>
    39.  
    40. </body>
    41. </html>