Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Экзамен / web / example1 / Введение в PHP.doc
Скачиваний:
101
Добавлен:
18.05.2015
Размер:
3 Mб
Скачать

Сжатие данных в протоколе http

Благодаря автоматической генерации, сложной разметке и внедрению Unicode, современные web-страницы могут иметь довольно большой размер. В протоколе HTTP предусмотрена возможность сжатия передаваемых данных. Для этого могут применяться способы сжатия, сходные с программами zip, gzip, bzip2, rar. Но сжатые сервером данные (например, передаваемая HTML-стрница) не записываются в файл на диске, а сразу передаются клиенту в сжатом виде. При этом может быть достигнута существенная экономия трафика и времени передачи.

Клиент, способный принимать информацию в сжатом виде, сообщает об этом серверу при помощи заголовка Accept-Encoding:

GET /~dimss/ HTTP/1.1

Host: localhost

Accept-Encoding: gzip,deflate

........

Сервер, видя такой заголовок, имеет право сжать содержимое своего ответа одним из предложенных методов. О том, что данные передаются в сжатом виде, сервер извещает клиента заголовком Content-Encoding:

HTTP/1.x 200 OK

Content-Encoding: gzip

........

Content-Type: text/html; charset=utf-8

[сжатые данные, на вид -- полная абракадабра]

Использование сжатия оговаривается в спецификации протокола HTTP/1.1 Спецификацией предусмотрено три способа сжатия: deflate (RFC 1951), compress (аналогичен Unix-программе compress) и gzip (RFC 1952, аналогичен Unix-программе gzip). Наиболее практичным является метод gzip. Его поддерживают большинство современных Web-клиентов. Использование сжатия для динамических HTML-документов целесообразно, несмотря на дополнительную процедуру сжатия. Статические HTML-документы можно хранить в сжатом виде, и разжимать перед передачей, если клиент не понимает gzip. Эти функции можно возложить на Web-сервер, см. далее.

Естественно, внедрение сжатия в прикладном коде - это не лучший вариант. О сжатии должна заботиться среда программирования или сам Web-сервер.

Так, язык PHP позволяет автоматически сжимать передаваемые страницы, для этого в php.ini есть опция zlib.output_compression.

Модули поддержки сжатия существуют для большинства Web-серверов. Для сервера Apache существуют модули mod_deflate и mod_gzip. Сжатие gzip поддерживается набирающим популярность сервером nginx. Сжатие deflate и gzip поддерживает также сервер Microsoft IIS.

Приложение 2. Сериализация объектов

Сериализация - это процесс, посредством которого массив или объект класса преобразуется в символьную строку для дальнейшей передачи или хранения. Сериализация выполняется следующим образом: serialize($obj); где Sobj — объект для сериализации. Рассмотрим пример:

<?php //pr30

$a= array("key" =>"testing", 1 => 10, 2 => "mystring");

echo $b=serialize($a) ,"<br>";

print_r (unserialize($b));

?>

Вывод :

a:3:{s:3:"key";s:7:"testing";i:1;i:10;i:2;s:8:"mystring";}

Array ( [key] => testing [1] => 10 [2] => mystring )

Строка сериализации не может непосредственно использоваться для передачи с помощью HTTP-протокола или для сохранения в базе данных, так как она содержит недопустимые символы. Если данные нужно сохранить в базе данных, то подойдет простое использование функции addslashes(). При работе с HTTP-протоколом нужно использовать функцию urlencode(). После сериализации и кодирования строка может быть передана в базу данных как скрытый элемент HTML-формы или записана в файл для дальнейшего использования.

Для восстановления переменной из ее сериализованного представления в РНР предусмотрена функция unserialize ():

unserialize($obj_string [, $callback_function])

где $obj_string представляет строку сериализации для восстановления переменной, $callback_function — имя необязательной функции обратного вызова для использования, если unserialize () реконструирует объект, который не был определен. При успешном завершении функция unserialize() возвращает реконструированный объект, или же false, если РНР не может реконструировать сериализованные данные.

Сериализация объектов в сессиях

Функция serialize() возвращает строку, содержащую представление объекта в виде потока байтов. При сериализации объекта PHP сохраняет в строке имя класса и значения свойств объекта. Методы объекта и данные о родительских классах или имплементируемых интерфейсах не сохраняются. Чтобы иметь возможность дессериализации объекта, должен быть определён класс этого объекта. То есть, если у вас имеется объект $a класса A в файле page1.php и вы его сериализуете, вы получите строку, которая ссылается на класс A и содержит все значения переменных, содержащихся в $a. Если вы хотите выполнить десериализацию в файле page2.php, воссоздав объект $a класса A, определение класса A обязано иметься в page2.php. Это можно сделать, например, сохранив определение класса A в include-файле и подключив этот файл и в page1.php, и в page2.php.

//classa.php:

<?php

class A

{

private $one = 1;

public function show_one()

{

echo $this->one;

}

}

?>

<?php

//pr31.php:

include 'classa.php';

$a = new A;

$s = serialize($a);

echo 's=',$s;

// сохраняем $s там, где pr32.php может его найти.

$fp = fopen("store", "w");

fputs($fp, $s);

fclose($fp);

?>

Вывод:

s=O:1:"A":1:{s:6:"Aone";i:1;}

<?php

//pr32.php:

// это необходимо для правильной работы десериализации.

include ("classa.php");

$s = implode("", @file("store"));

$a = unserialize($s);

// теперь используем функцию show_one() объекта $a.

$a->show_one();

?>

Вывод:

1

Если вы используете сессии и session_register() для регистрации объектов, эти объекты сериализуются автоматически в конце каждой PHP-страницы и десериализуются автоматически на каждой последующей странице. Это означает, что эти объекты могут появиться на любой странице, после того как стали частью вашей сессии. Рекомендуется включать определение классов всех таких зарегистрированных объектов во все страницы, даже если вы и не используете эти классы во всех. Если объект десериализуется в отсутствие определения класса, он потеряет ассоциацию с этим классом и станет практически бесполезен.

Итак, если в вышеприведённом примере $a стало частью сессии через запуск session_register("a"), вы должны включить/include файл classa.inc во все ваши страницы, а не только в page1.php и page2.php.

Подготовка данных к сохранению.

Данные сессии, хранятся в массиве $_SESSION.

Данные хранятся на стороне сервера и об их наличии и составе пользователь может только догадываться. В программе эти данные могут состоять из любых типов данных, доступных программисту: строки, числа, массивы и объекты, но не ресурсы (об этом ниже). При записи данные подвергаются процедуре сериализации (serialization) - преобразования структур любой сложности (не содержащих ресурсов) в строку, из которой в последствии можно восстановить структуру назад. Для сериализации используется функция serialize(). Для обратного процесса - десериализации - unserialize(). При старте сессии эти PHP, получив от обработчика сессии строку, посредством функции unserialize() восстанавливает данные и помещает их в массив $_SESSION. При завершении программы происходит обратный процесс: массив $_SESSION автоматически сериализуется и строка передается обработчику сессии для записи. Т.е. обработчик сессии работает только со строкой и не зависит от сложности структуры хранимых данных.

Рассмотрим особенности работы сериализации:

1. Ссылки.

Массив $_SESSION, как и любой другой массив, может содержать ссылки на другие переменные, а так же может содержать объекты и массивы, которые тоже содержат ссылки. Возможна да же рекурсивная связь.

Код:

<?php

$array['b'] = array();

$array['a'] = array('bRef' => &$array['b']);

$array['b']['aRef'] = &$array['a'];

echo "<pre>" . htmlspecialchars(print_r($array, true)) . "</pre>";

?>

Можно сериализовать массив целиком и потом восстановить его. Но если попытаться сериализовать отдельно $array['a'] и $array['b'], а потом их восстановить, то связи будут нарушены. Вот пример такого разрушения связей.

<?php

$array['b'] = array();

$array['a'] = array('bRef' => &$array['b']);

$array['b']['aRef'] = &$array['a'];

$array['a']['val'] = 1;

echo "<pre>" . htmlspecialchars(print_r($array, true)) . "</pre>";

$str_a = serialize($array['a']);

$str_b = serialize($array['b']);

echo "<pre>" . htmlspecialchars($str_a) . "</pre>";

echo "<pre>" . htmlspecialchars($str_b) . "</pre>";

$array2['a'] = unserialize($str_a);

$array2['b'] = unserialize($str_b);

$array2['a']['val'] = 2;

echo "<pre>" . htmlspecialchars(print_r($array2, true)) . "</pre>";

?>

2. Объекты и их классы.

Особенность сериализации объекта в том, что сохраняется только состояние объекта - его данные, а для "оживления" обязательно заранее должен быть объявлен класс.

Выходов из этого положения два: заранее загружать объявления необходимых классов, либо воспользоваться специальным обработчиком, который сможет попытаться подгрузить требуемый класс. Назначается обработчик в ini.php (unserialize_callback_func'), но может быть изменен во время работы программы.

Выглядит этот обработчик так:

Код:

<?php

ini_set("unserialize_callback_func", "my_unserialize_callback_func");

function my_unserialize_callback_func($classname)

{

// Предпологаем, что файлы, содержащие классы,

// находятся в поддиректории classes и имеют имя

// соответствующее имени класса.

$filename = "classes/$classname.php";

if (!is_file($filename))

die("Не удалось подгрузить класс '$classname'");

include_once($filename);

}

?>

Для того чтобы можно было управлять процессом сериализации/десериализации в классах PHP предусмотрены специальные "волшебные" методы: __sleep() и __wakeup(). Метод __sleep() должен возвращать массив с именами своих свойств, которые будут сохранены. __sleep вызывается перед сериализацией чтоб можно было убрать ненужные связи.

Метод __wakeup() нужен для выполнения процедур инициализации объекта после десериализации. __wakeup вызывается после unserialize, чтоб можно было необходимые связи вернуть.

Метод __sleep обязательно должен вернуть массив со списком свойств, которые нужно сериализовать; Если объект сериализуется, а потом продолжает использоваться, он может быть испорчен, так как при сериализации был вызван метод __sleep.

Пример использования:

<?php

class Connection {

protected $link;

private $server, $username, $password, $db;

public function __construct($server, $username, $password, $db)

{

$this->server = $server;

$this->username = $username;

$this->password = $password;

$this->db = $db;

$this->connect();

}

private function connect()

{

$this->link = mysql_connect($this->server, $this->username, $this-> password);

mysql_select_db($this->db, $this->link);

}

public function __sleep()

{

return array('server', 'username', 'password', 'db');

}

public function __wakeup()

{

$this->connect();

}

}

?>

Пример сериализации

class A implements Serializable {

private $x='y';

function __construct()

{

echo __METHOD__ . " called\n";

}

function __destruct()

{

echo __METHOD__ . " called\n";

}

function serialize()

{

return $this->x;

}

function unserialize($s)

{

$this->x=$s;

}

}

class B {

private $x='y';

function __construct()

{

echo __METHOD__ . " called\n";

}

function __destruct()

{

echo __METHOD__ . " called\n";

}

function __sleep()

{

return array('x');

}

}

echo "Serializable (the new way)\n";

$x1=new A;

$s=serialize($x1);

var_dump($s);

$y1=unserialize($s);

var_dump($y1);

echo "__sleep/__wakeup (the old way)\n";

$x2=new B;

$s=serialize($x2);

var_dump($s);

$y2=unserialize($s);

var_dump($y2);

Сериализация объектов и автозагрузка.

При сериализации объекта PHP сохраняет в итоговой строке имя класса и значения свойств объекта. Методы объекта и данные о родительских классах или имплементируемых интерфейсах не сохраняются. Следовательно, необходимый класс должен быть определён до того, как объект будет обратно десериализован из строки. В большинстве случаев все классы системы не имеет смысла подключать при каждом запросе. А если класс с нужным именем не был определён, PHP инстанцирует объект класса __PHP_Incomplete_Class_Name и определяет в нём свойства, сохранённые при сериализации объекта. Само собой, нормальная работа с таким объектом невозможна.

Положение исправляет автозагрузка классов, но одного наличия определённой функции __autoload() недостаточно, чтобы интерпретатор попытался автоматически подключить нужный класс. Для этого должна быть установлена директива конфигурации unserialize_callback_func, в которой указывается имя метода автозагрузки. Устанавливать значение этой директивы можно в любом месте, поэтому самое простое и правильное — на этапе инициализации приложения присвоить этой директиве значение __autoload. При этом нужно помнить, что если функция автозагрузки указана, но не определена, при вызове функции unserialize() возникнет warning.

Проблема становится ещё актуальнее, если вспомнить, что сессии для хранения данных используют именно сериализацию. Десериализация производится при вызове функции session_start(), которая часто вызывается в самом начале работы приложения. Ещё хуже, если сессия стартует автоматически (с использованием директивы session.auto_start). В этом случае не помогает и использование директивы auto_prepend_file, то есть нет возможности стандартными средствами определить функцию автозагрузки до старта сессии.

В конечном итоге получается, что для нормального сохранения объектов в сессии нужно обязательное выполнение следующих условий:

1. Автоматический запуск сессий отключён.

2. Функция __autoload() определяется до момента старта сессии.

3. До момента старта сессии выполняется команда ini_set('unserialize_callback_func', '__autoload').

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

Приложение3. Взаимодействие PHP и JavaScript

Скрипты JavaScript выполняются на машине клиента, в то время как PHP-приложения выполняются на сервере. Существует две простые возможности взаимодействия PHP и JavaScript: передача переменных из JavaScript в PHP и динамическое формирование скриптов JavaScript средствами PHP.

Передача переменных из JavaScript в PHP может осуществлятся по методу GET или POST. Рассмотрим пример определения разрешения экрана и глубину цвета монитора посетителя страницы средствами JavaScript и передачи этих данные в PHP-скрипт.

<script language="JavaScript">

//javasphp.htm

var height=0;

var width=0;

var colorDepth = screen.colorDepth;

if (self.screen)

{

width = screen.width

height = screen.height

}

if (width > 0 && height > 0)

{

/*перенаправление на скрипт javasphp.php */

window.location.href=

"http://localhost/mypr/javasphp.php?wid="+width+"&hei="+height+"&col="+colorDepth;

}

else exit();

</script>

После выполнения этого кода происходит автоматический переход на страницу javasphp.php, на которой происходит вывод разрешения экрана и глубины цветопередачи в окно браузера.

Файл javasphp.php

?php

echo "Ширина : ".$_GET['wid'],"<br>";

echo "Высота : ".$_GET['hei'],"<br>";

echo "Цветовое разрешение:".$_GET['col'];

?>

Вывод:

Ширина : 1024 Высота : 768 Цветовое разрешение:32

Передача данных из JavaScript, происходит по методу GET.

JavaScript и AJAX

Название AJAX - это аббревиатура от "Asynchronous JavaScript And XML”. Технология AJAX позволяет создавать интерактивные веб-приложения, для которых измененные страницы могут полностью не перегружаться, а перегружаются лишь изменившиеся в результате работы приложения данные. Отметим, что новые сервисы Google, в том числе GMail, Orkut, Google Groups, Google Maps, Google Suggest, Google Finance , являются AJAX-приложениями.

Рассмотрим отличия классической модели веб-приложения и модели AJAX.

Классическая модель веб-приложения. Последовательность выполнения приложения:

- Пользователь загружает в браузер веб-страницу и генерирует событие.

- Браузер отправляет HTTP запрос серверу.

- Cервер генерирует новую веб-страницу и возвращает ее в ответ браузеру.

- Браузер отображает новую страницу.

Соседние файлы в папке example1