Блог веб разработки статьи | видеообзоры | исходный код

Блог веб разработки статьи | видеообзоры | исходный код

webfanat вконтакте webfanat youtube

Управление буфером вывода в php

Управление буфером вывода в php

Всех приветствую! Тема статьи - управление(контроль) выводом в php. Данного вопроса мы уже частично касались в статье PHP буфер но сегодня я хочу показать вам как это можно использовать в работе. Поехали!

Допустим у нас есть файл index.php со следующим содержимым.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
    <title>Заголовок</title>
  </head>
  <body>
    <h1>Заголовок</h1>
    <p>Какой то текст</p>
  </body>
</html>

И мы хотим перехватить содержимое вывода и изменить заголовок. Для этого нужно написать следующее:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
    <title>Заголовок</title>
  </head>
  <body>
    <h1>Заголовок</h1>
    <p>Какой то текст</p>
  </body>
</html>
<?php
  $data = ob_get_clean();
  $data = str_replace('Заголовок', 'Новый заголовок', $data);
  echo $data;
?>

Функция ob_get_clean() возвращает содержимое вывода и очищает сам вывод. Содержимое вывода мы помещаем в переменную $data, затем через функцию str_replace() меняем заголовок на новый и делаем вывод обновленного содержимого. В результате вместо 'Заголовок' будет выводится 'Новый заголовок'. Заметьте что весь вывод должен происходить до вызова функции ob_get_clean().

Вот так можно менять содержимое вывода не влезая в основной функционал который формирует контент страницы. Конечно же так делать не следует но иногда такой прием может оказаться крайне полезным и эффективным в решении задачи!

Идем дальше! Бывает необходимо преждевременно что то выводить на страницу при выполнении php скрипта.

Пример:

<?php
for($i = 1; $i <= 5; $i++){
   sleep(1); // Отправка запроса
   echo 'Данные с сайта '.$i.' получены<br />';
 }

В данном примере идет имитация парсинга с пяти сайтов. Функция sleep() делает задержку в одну секунду имитируя время обработки одного запроса. Мы рассчитываем последовательно выводить информацию после каждого запроса. Однако если запустить данный код, всю информацию мы увидим только после завершения работы скрипта. Нас это не устраивает поэтому здесь нужно записать так:

ob_implicit_flush(true);
ob_end_flush();

for($i = 1; $i <= 5; $i++){
   sleep(1); // Отправка запроса
   echo 'Данные с сайта '.$i.' получены<br />';
 }

В результате работы данного скрипта будет происходить предварительный вывод записей. Функция ob_implicit_flush() со значением true включает возможность неявного сброса, а ob_end_flush() сбрасывает(отправляет) вывод тем самым отключая буферизацию вывода. Однако на некоторых серверах такой механизм может и не работать. Это связано с настройками конфигурации, к примеру в файле php.ini следующие директивы должны иметь подобные значения:

implicit_flush = Off
output_buffering = 4096
zlib.output_compression = Off

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

На основе всего этого давайте разработаем скрипт который будет проверять список доменов на доступность и существование.

Серверная часть будет содержаться в файле valid.php

<?php

function valid($domain){
  if(!filter_var($domain, FILTER_VALIDATE_URL)){
        return false;
    }
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $domain);
  curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,10);
  curl_setopt($curl,CURLOPT_HEADER,true);
  curl_setopt($curl,CURLOPT_NOBODY,true);
  curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
  $response = curl_exec($curl);
   curl_close($curl);
   if ($response) return true;
   return false;
}

ob_implicit_flush(true);
ob_end_flush();

if(isset($_POST['domains']) && trim($_POST['domains']) !== ''){
  $domains = rtrim(trim($_POST['domains']), ',');
  $domains = explode(',', $domains);
  echo json_encode(array('info'=> 'Количество сайтов '.count($domains)), true);
  $i = 1;
    foreach($domains as $domain){
       sleep(1); // Отправка запроса
       $status = valid(trim($domain));

       if($status){
         $status = 'Существует';
       }else{
            $status = 'Не существует';
       }
      echo json_encode(array(
        'domain'=> 'Сайт '.$domain.' проверен',
        'number'=>$i,
         'count'=>count($domains),
         'status' => $status
       ), true);
      $i++;
     }


}else{
  echo 'Данные не переданы';
  die();
}

Здесь функция valid() делает запрос и проверяет сайт на доступность. Клиентская часть кода будет содержаться в index.html

<form>
      <div>
        <textarea style="width:50%; height:100px;" name="domains" placeholder="Введите список доменов через запятую в формате https://domain.com"></textarea>
      </div>
      <button >Проверить</button>
      <div id="message"></div>
  </form>
  <script>

function uintToString(uintArray) {
    var encodedString = String.fromCharCode.apply(null, uintArray),
        decodedString = decodeURIComponent(escape(encodedString));
    return decodedString;
}

function addMessage(info){
  var p = document.createElement('p');
  if('info' in info){
    document.querySelector('#message').innerHTML = '';
    p.innerHTML = `${info['info']}`;
      document.querySelector('#message').appendChild(p);
    return false;
  }

  p.innerHTML = `${info['number']}/${info['count']} ${info['domain']} - ${info['status']}`;
  document.querySelector('#message').appendChild(p);
}

    document.querySelector('form').addEventListener('submit', async function(e){
      e.preventDefault();
var data = new FormData(this);
  fetch('/valid.php',{method: "post", body: data}).then((response) => {
    const reader = response.body.getReader();

    const stream =  new ReadableStream({
      start(controller) {
        function push() {
          reader.read().then(({ done, value }) => {

            if (done) {
              controller.close();
              return;
            }
            var info = JSON.parse(uintToString(value));
              addMessage(info);
              controller.enqueue(value);
            push();
          });
        };
        push();
      }
    });
    return new Response(stream, { headers: { "Content-Type": "plain/text" } });
  }).then(function(res){
    return   res.text();
  }).then(function(res){
    alert('Работа скрипта завершена');
  });
});
  </script>

Здесь представлено поле textarea и кнопка 'Проверить'. В само поле необходимо через запятую перечислить список доменов в таком формате(https://webfanat.com). После этого нажать кнопку 'Проверить' и все данные через ajax запрос отправятся на нашу серверную часть valid.php. Обратите внимание что ответ с сервера мы считываем в режиме реального времени построчно, то есть в процессе работы php скрипта через интерфейс ReadableStream. Данный интерфейс относится к инструментарию API Streams с которым мы в скором времени обязательно познакомимся! Функция uintToString() преобразует массив типа Uint8Array в строку, addMessage() добавляет сообщение в блок с id message. Если в целом разобраться то ничего сложного здесь нет! Результатом будет последовательный вывод сообщений о текущем статусе определенного домена, примерно раз в 1 секунду.

В принципе вот и все что я хотел вам рассказать по поводу использования управления контролем вывода в php. Конечно тема намного обширнее но моем задачей было показать вам как это можно использовать в практике на реальных примерах. Надеюсь вы почерпнули что то новое! Дополнительную информацию можно найти на официальном мануале php.

На этом у меня все! Не забывайте подписываться в группу Вконтакте для получения новостей о выходе новых статей и переходите на канал Youtube.

Всем добра и процветания!

Оцените статью:

Статьи

Разработки

Комментарии

В данном разделе пока нет комментариев!

Реклама

Запись экрана

Данное расширение позволяет записывать экран и выводит видео в формате webm