A PHP Error was encountered

Severity: 8192

Message: mysql_escape_string(): This function is deprecated; use mysql_real_escape_string() instead.

Filename: mysql/mysql_driver.php

Line Number: 303

PHP: Как уменьшить количество HTTP запросов с помощью схемы data: URI

PHP: Как уменьшить количество HTTP запросов с помощью схемы data: URI

Автор: Mowshon.
Опубликовано 25 июля 2011
в рубрике PHP, Рабочая среда

Просмотров: 6873.
Подписаться на комментарии по RSS.

Идея данной статьи заключается в следующем: можно уменьшить количество запросов HTTP, которые страница должна сделать для своих изображений, предварительно обработав исходный код и преобразовав их по схеме data:URI.

оптимизация страницы - загрузку страницы

Схема data:URI позволяет включать в веб-страницу данные в качестве внешнего ресурса. Схема может быть использована для любого вида данных, включая изображения, сценарии и таблицы стилей, и поддерживается во всех современных браузерах: Gecko браузерах, таких как Firefox и Camino, Webkit браузерах, как Safari, Konqueror и Chrome, конечно же, в Opera, и с ограничениями в IE8 (но не в IE7 или более ранней версии).

Как показывает Google, я не первый, кому пришла идея использовать схему для оптимизации страниц. Но все реализации, с которыми я встречался, вращались вокруг переписывания путей к изображениям вручную, чтобы указать на них в сценарии, как в следующем примере.

<?php
<img src="%3C?php%20echo%20data_uri%28%27images/darwinfish.png%27%29;%20?%3E" alt="Darwin Fish">

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

Код, лежащий в основе

Страница содержит пять элементов < img> и одно CSS фоновое изображение, но во всех поддерживаемых браузерах страница вообще не посылает дополнительных HTTP запросов:

<?php
if($datauri_supported = preg_match("/(Opera|Gecko|MSIE 8)/", $_SERVER['HTTP_USER_AGENT']))  
{  
   ob_start();  
}  
?>  
  
  
  
     
     
   <style type="text/css">  
      body  
      {  
         background:url(images/texture.jpeg) #e2e2dc repeat;  
         color:#554;  
      }  
   </style>  
  
     
      <img src="images/dropcap.jpg" alt="dropcap.jpg">  
      <img src="images/firefox.png" alt="firefox.png">  
      <img src="images/specificity.jpg" alt="specificity.jpg">  
      <img src="images/darwinfish.png" alt="darwinfish.png">  
      <img src="images/rolleyes.gif" alt="rolleyes.gif">  
     
if($datauri_supported)  
{  
   function create_data_uri($matches)  
   {  
      $filetype = explode('.', $matches[2]);  
      $filetype = strtolower($filetype[count($filetype) - 1]);  
      if(!preg_match('/^(gif|png|jp[e]?g|bmp)$/i', $filetype))  
      {  
         return $matches[0];  
      }  
      if(preg_match('/^//', $matches[2]))  
      {  
         $matches[2] = $_SERVER['DOCUMENT_ROOT'] . $matches[2];  
      }  
      @$data = base64_encode(file_get_contents($matches[2]));  
      return $matches[1] . "data:image/$filetype;base64,$data" . $matches[3];  
   }  
   $html = ob_get_contents();  
   ob_end_clean();  
   $html = preg_split("/
?
|
/", $html);  
   while(count($html) > 0)  
   {  
      $html[0] = preg_replace_callback("/(src=[\"'])([^\"']+)([\"'])/", 'create_data_uri', $html[0]);  
      $html[0] = preg_replace_callback("/(url(['\"]?)([^\"')]+)([\"']?))/", 'create_data_uri', $html[0]);  
      echo $html[0] "
";  
      array_shift($html);  
   }  
}  
?>

Как всё это работает

Основой кода является возможность создавать data URI с использованием base64-кодированных изображений.

Но кроме этого, необходимо применить несколько ключевых приемов, чтобы всё это заработало. Во-первых, это использование буфера вывода для предварительной компиляции исходного вывода, чтобы была возможность проанализировать его еще раз, прежде чем отправить в браузер. Если у вас не имеется свежая версия Mozila Firefox, то советую загрузить Мазилу сейчас.

Вы увидите, что в самом начале кода я установил условный оператор, который проверяет тип браузера и начинает буферизацию вывода. Это же условие используется снова, окружая основной код внизу сценария, поэтому для браузеров, которые не поддерживают эту технику, весь сценарий пропускается, и вывод страницы происходит в обычном режиме. Затем я разделил HTML с помощью разрыва строки, чтобы можно было выполнить обработку, вывести, а затем сразу удалить каждую строку, что позволяет избежать необходимости держать весь исходный код в памяти.

Во-вторых, для осуществления разбора страницы я использовал функцию обратного вызова preg_replace_callback, которая определяет HTML и CSS пути с помощью пары регулярных выражений, и выполняет обработку, для которой обычной замены было бы недостаточно. (Необходимо искать атрибуты SRC и URL свойства отдельно, так как их синтаксис слишком сильно отличается и одного регулярного выражения будет недостаточно)

В функции обратного вызова сначала нужно выяснить тип файла, который необходим для вывода данных и для определения разрешенных типов, поэтому можно отвергать все, что это не является изображением (например, SCRIPT SRC). Массив $matches, который передается в функцию, всегда содержит всю подстроку, соответствующую шаблону регулярного выражения в качестве первого элемента, поэтому если тип файла нам не подходит, можно просто вернуть в качестве результата этот первый элемент без изменений и всё.

Осталось проверить путь к корневому каталогу, перед которым нужно записать DOCUMENT_ROOT, чтобы создать правильный путь к файлу. Теперь можно кодировать изображение (с подавлением ошибок, в случае если исходный путь был нарушен), затем собрать всё вместе и вернуть data URI. Всё просто!

Когда оптимизация уже не является оптимизацией?

Когда затраты больше экономии! Есть несколько потенциальных затрат, которые мы должны рассмотреть.

Изображения в data:URI на треть больше оригинала. Такие изображения не кэшируются, по крайней мере, как изображения, но они кэшируются как часть исходного кода. Такое кэширование является слишком избыточным, но, по крайней мере, позволяет просмотр в автономном режиме.

Также первое место в потреблении вычислительной мощности занимает преобразование изображения, и к тому же файл становится больше. При загрузке не происходит значительной задержки, поскольку файл находится на том же сервере, но base64-кодировка является сравнительно дорогостоящим процессом.

Поэтому оптимальным способом применения данной методики было бы её использование не для всех изображений, а только для большого количества маленьких изображений, таких как иконки или фоновые рисунки. Дополнительный размер кода будет незначительным, а время обработки небольшим, при этом создается заметное преимущество от сокращения нескольких десятков запросов, и страница загружается быстро.

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

<?php
if(!preg_match('/^(gif)$/i', $filetype))  
{  
   return $matches[0];  
} 
?>

Также можно использовать функцию filesize, чтобы фильтровать изображения по размеру и обрабатывать только те, которые меньше определенного порога.

<?php
if(filesize($matches[2]) > 1024)  
{  
   return $matches[0];  
} 
?>

Некоторые браузеры устанавливают ограничения на размер data: URI, но на практике я их не встречал. Firefox, Opera, Safari и даже IE8 без проблем выводили данные изображений более 1 Мб.

Комментариев: 1

  1. балабол | 03.05.2012 в 14:55:59 | #1

    Я чета вообще не понял как применять эту методику и куда её впихивать в скрипте.

    Вот к примеру у меня есть страница со смайлами, как уменшить количество http запросов к каждому смайлу при загрузке страницы, если я все правильно понял

Оставьте комментарий!

Гость
Комментатор / хотите им стать

Чтобы стать комментатором введите email и пароль. Напишите комментарий. В дальшейшем ваша связка email-пароль, позволит вам комментировать и редактировать свои данные. Не забудьте про активацию (инструкция придет на ящик, указанный при регистрации).

grin LOL cheese smile wink smirk rolleyes confused surprised big surprise tongue laugh tongue rolleye tongue wink raspberry blank stare long face ohh grrr gulp oh oh downer red face sick shut eye hmmm mad angry zipper kiss shock cool smile cool smirk cool grin cool hmm cool mad cool cheese vampire snake excaim question

(обязательно)