#15, Октябрь'2005 :: Тонкая настройка PHP

Page 1

Октябрь '05 № 15

Тонкая настройка PHP Интервью: авторы dbtree и phpMyAdmin Новый взгляд на Smarty

издается с февраля 2004 года, www.phpinside.ru


Люди Наши. Кузьма Феськов и dbtree...................................................................................................................4 Интервью с одним из ведущих разработчиков phpMyAdmin Марком Делислом..................................7 Идеи Smarty — не просто шаблоны....................................................................................................................11 Принципы создания proxy-сервера на PHP в интрасети. Вопросы безопасности................................17 Тема с обложки HOWTO по оптимизации PHP...................................................................................................................19 Логирование ошибок стандартными средствами PHP............................................................................41 Один PHP хорошо, а два лучше.................................................................................................................45

Анонс Мы рады сообщить вам, что следующая PHP-конференция пройдет в мае 2006 г. в Москве.

Тематика конференции •Применение

PHP Inside #15

PHP в веб-разработке: приёмы, методы и парадигмы программирования в PHP, полезные модули и библиотеки.

СОДЕРЖАНИЕ / АНОНСЫ

Содержание

•Эффективное

создание приложений: фреймворки, гибкие методологии, экстремальное программирование, ТDD-методики.

•PHP

и корпоративные информационные системы: разработка систем масштаба предприятия, интеграция корпоративных ИС.

•Будущее

PHP: основные направления развития, PHP6, мультиязычные приложения,

Unicode.

Совместно с конференцией пройдет серия мастер-классов (практических занятий). •Test

driven development (TDD) — 2.5 дня: приемы, паттерны, тестирование операций с БД, рефакторинг, функциональное тестирование, использование SimpleTest и Selenium.

•Разработка

расширений PHP — 0.5 дня: Объектно-ориентированные модули изнутри, портирование PHP классов на C, Zend API.

Порядок оформления заявок на участие в конференции Авторам, желающим принять участие в конференции с устным докладом (30-60 мин.), необходимо до 1 февраля 2006 отправить тезисы доклада (в виде стандартного файла .doc или .txt произвольной формы) объемом в одну-две страницы, отражающие cодержание представляемого доклада. На основе тезисов будет проведен отбор докладов для включения в программу конференции.

2


АНОНСЫ

Авторы докладов, прошедших рецензирование, будут уведомлены после 15 февраля и получат второе информационное сообщение, в котором будут изложены правила оформления электронных версий докладов. Тезисы докладов 2006@phpconf.ru.

принимаются

оргкомитетом

по

электронному

адресу:

PHP Inside #15

Все сведения о подготовке и работе конференции, включая требования к представляемым материалам, данные об участниках конференции, программа, контрольные сроки и текущие объявления, будут приведены на официальном интернет-сайте конференции: http://www.phpconf.ru/ Если вы планируете участвовать в мастер-классах, просим вас учесть, что число мест на каждый мастер-класс ограничено (~24 чел.), поскольку мастер-классы ориентированы на большое количество практики. Участие в мастер-классах оплачивается отдельно от конференции и требует наличия ноутбука c определенным ПО (Apache+MySQL+PHP5+клиент cvs).

Основные даты До 1 февраля — прием тезисов, докладов. 20 февраля — рассылка второго информационного сообщения с предварительным порядком работы конференции, списком принятых докладов и перечнем требований по оформлению электронных версий. 1 марта — рассылка третьего информационного сообщения с программой работы конференции. 1 апреля — прием докладов и оплата участия по программе предварительной регистрации (действуют скидки корпоративным участникам, от 3-х и более человек). Середина мая - мастер-классы (3дня), рабочие дни конференции (2дня)

Наши координаты Адрес электронной почты оргкомитета: 2006@phpconf.ru. По вопросам спонсорского участия обращайтесь по адресу: sp2006@phpconf.ru. Официальный сайт PHP-конференции http://www.phpconf.ru/

3


ЛЮДИ

Наши. Кузьма Феськов и dbtree

Наши. Кузьма Феськов и dbtree

PHP Inside #15

Интервьюировал: Андрей Олищук [nw] Мы продолжаем серию статей и интервью с отечественными PHP-разработчиками Кузьма Феськов — автор современной версии библиотеки для работы с иерархическими структурами dbtree, автор и переводчик документации (к ADODB, официальный перевод к phpGacl) и статей о PHP и связанных технологиях, любезно согласился дать нашему журналу интервью. nw: Ты являешься автором библиотеки dbtree. Откуда пришла мысль развивать эту библиотеку? Кузьма Феськов (КФ): Когда-то наткнулся на phpDBTree Максима Полторака. С математикой у меня к сожалению туго, и далась мне эта теория не сразу, помнится даже забрасывал пару раз в дальний угол все это дело. А потом настало «просветление» и как-то все встало на свои места. Организация класса Максимом мне не подходила: слишком много своих разработок к тому времени накопилось. Это подтолкнуло к глобальной переделке библиотеки. Работа над разными проектами шла, стали выявляться постоянно нужные однотипные операции, которые имели отношение к выводу дерева, но не к его обработке. Подумалось, раз эти действия так часто повторяются, почему они не могут стать частью библиотеки? Вот они и стали ее частью, значительно расширив ее функционал. Количество интересующихся этой темой росло, а информации не очень-то и прибавлялось.

Очень хочется поблагодарить зарубежных программистов – нельзя не отметить их дисциплину и эффективность их писем

В один прекрасный день, очередное обсуждение на форуме PHPClub сподвигло меня выложить библиотеку на всеобщее обозрение. Я не могу делать что-то на половину, так уж устроен, поэтому в кратчайшие сроки я написал подробнейшую документацию на библиотеку, где документация, там и интересные примеры, где примеры, там и учебник по использованию... Таким образом, на сегодняшний день библиотека превратилась из простого класса в мощное пособие по работе с деревьями. Как вы понимаете, где публичный доступ, там и вопросы, и претензии, и просьбы – пришлось развивать. Текущая версия (2.1) на редкость получилась удачной, поток замечаний резко иссяк, хотя по количеству обращений вижу, что интерес наоборот возрос. Сей факт позволил мне сделать передышку и на время остановиться и подумать над дальнейшими планами – а планы, поверьте, есть! nw: Что умеет твоя библиотека? КФ: Ну, разумеется, она умеет ловко управляться с деревьями, причем предлагает несколько простых и, отчасти, уникальных функций. В прочем, давайте по порядку: •

добавление, редактирование и удаление узлов – стандартные функции;

4


ЛЮДИ

перемещение узлов – здесь есть несколько интересных находок, которые позволяют решить давнюю проблему деревьев Nested Sets, а именно – сортировку узлов в пределах одного родителя, что значительно облегчило жизнь программисту и менеджеру;

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

безусловно, нельзя не отметить поддержку транзакций и множества (думаю, что не ограниченного количества) баз данных – все это базируется на библиотеке ADODB. На сегодняшний день я предлагаю программистам удобный и простой интерфейс, благодаря которому они могут использовать PEAR::DB и любой другой класс для работы с базой данных.

PHP Inside #15

Наши. Кузьма Феськов и dbtree

Думаю, что этого списка «умений» достаточно, чтобы начать ей пользоваться! nw: Каким образом происходит работа над новым функционалом библиотеки? Кто-то пишет тебе feauture requests или ты реализуешь то, что необходимо прежде всего тебе? Здесь задействованы разные пути, например, в текущей версии есть пара «заказных» функций, написанных по просьбе Мануэля Лемоса, который живо откликнулся на появление данной библиотеки на phpclasses.org. Разумеется, очень много мне диктуют внутренние потребности моих проектов. Очень хочется поблагодарить зарубежных программистов – нельзя не отметить их дисциплину и эффективность их писем. Я конечно же получаю письма и от русскоговорящих пользователей, однако они в подавляющем большинстве просительные или констатационые. Например, среднестатистический западный программист всегда четко опишет ошибку, подробно задокументирует обстоятельства, при которых она возникла, и, иногда, предложит пути исправления. Это очень помогает развитию библиотеки и в значительной степени впрощает жизнь мне и другим пользователям. Очень надеюсь видеть такие же содержательные письма и от российских пользователей. nw: Ты перевел документацию к некоторым известным библиотекам, таким к примеру, как ADODB. Зачем тебе это? Почему ты просто не читаешь документацию и не забываешь о ней по прочтении? Наверное сказываются два моих педагогических диплома – не могу я пройти мимо, не могу не поделиться своими знаниями. Если я Cтановление пов чем-то досконально разобрался – я обязательно напишу об этом настоящему статью или переведу документацию. Во-первых, это определенная профессионального дань уважения создателям этих библиотек – они помогли мне, а я, в программистского свою очередь, помогаю им; во-вторых, я считаю, что становление по- сообщества в России настоящему профессионального программистского сообщества в невозможно без России невозможно без такого альтруизма, ибо книги выходят уста- альтруизма ревшими, многие просто не умеют (не значит не хотят) делиться своими знаниями, остаюсь я (пусть и не скромно) и другие достойные люди, которые отдают свои знания другим. nw: С решением каких задач тебе приходится сталкиваться как веб-разработчику чаще всего? В каких областях разработки ты считаешь себя наиболее компетентным? По работе я очень часто сталкивался с многоязычными приложениями, поэтому очень хорошо разбираюсь в вопросах многоязычности и всем, что с этими вопросами связано. Всегда с удовольствием выступаю в роли проектировщика. Достаточно хорошо чуствую себя управленцем – руководство командой разработчиков. 5


ЛЮДИ

Наши. Кузьма Феськов и dbtree

PHP Inside #15

Также меня интересуют вопросы дистанционного образования и систем тестирования. В остальном же – всегда интересно изучить и использовать новую технологию, докопаться до сути вопроса. Что будет в результате? Следите за моим сайтом, как правило, мои изыскани заканчиваются статьей или переводом. nw: Какими технологиями ты пользуешься? (СУБД, веб-серверы, шаблонизаторы, библиотеки, модули к PHP etc) Даже не знаю, что тут и упомянуть – много средств: какие-то лучше знаю, какие-то хуже. CVS, XML, MySQL,PostgreSQL, Smarty, Curl, GetText, Iconv и так далее. nw: Компания в которой ты трудишься, работает на зарубежных заказчиков. Есть ли разница между зарубежными заказчиками и отечественными клиентами? Отличаются ли условия работы, организационные процессы, требования, оплата труда? Гм – не думаю, что я смогу написать в ответ что-то дельное. Компания как компания – те же проблемы, что и у всех, продвижения и зарплаты также нужно добиваться. nw: Мы узнали о твоих профессиональных интересах. А какой ты в обычной жизни? Как проводишь свободное время? Где и как проводишь отпуска? Что любишь и какую музыку слушаешь обычно? Очень много читаю, поэтому меня часто называют занудой и заумным чудиком. Мне думается, что я просто человек своего мира – мне никогда не бывает скучно с сами собой. Между тем я очень отзывчивый, бодрый и веселый! В свое время объездил всю Россию, сейчас осваиваю заграницу. Мое последнее приключение – Прага. Дивный город, постоянно его вспоминаю, хочу обратно! Мой музыкальный формат – 104 FM – Наше радио – Русский рок. Также Стинг, Мадонна и разнообразная инструментальная музыка. Очень люблю радио постановки, поэтому постоянно что-то скачиваю из Интернета и слушаю – очень помогает в развитии воображения, образного мышления – крайне рекомендую! Мне кажется, что я умею быть отличным другом – поэтому у меня много друзей и знакомых. Ну, вот на этом, пожалуй, я закончу саморекламную паузу! Хочется пожелать читателям журнала удачи, успеха и профессионализма!

6


ЛЮДИ

Интервью с одним из ведущих разработчиков phpMyAdmin Марком Делислом

PHP Inside #15

Интервью с одним из ведущих разработчиков phpMyAdmin Марком Делислом Интервьюировал: Arjen Lentz Перевод: Андрей Олищук Arjen Lentz - менеджер по связям с сообществом разработчиков в MySQL AB Марк Делисл (Marc Delisle) - один из ведущих разработчиков популрного проекта phpMyAdmin, веб-ориентированного инструмента для администрирования MySQL. Я расспросил Марка о MySQL, phpMyAdmin (конечно же!) и о процессах разработки в целом. Arjen: Пожалуйста, расскажите о себе, немного фактов из жизни, для тех кто не знает Марка как человека. Marc: я разработчик программного обеспечения и системный администратор Cegep de Sherbrook, колледжа расположенного в Квебеке, Канада. В этой сфере работаю с 1980 года, а это означает, что мне пришлось пережить много волн развития компьютерных технологий, включая разработку приложений на Cobol для Oracle, пользовательских интерфейсов на бейсике для терминалов и т.д. С 1998 года я, по большей части, работаю для веба на PHP. Что касается личной жизни, то я горжусь тем, что являюсь отцом четырех детей. Arjen: Почему вы выбрали MySQL и когда произошло знакомство с этой СУБД? Marc: Я начал с mSQL (Mini SQL Дэвида Хьюза) для преподавания курса по базам данных (я так же подрабатываю преподаванием) и тогда мне не хватило некоторых возможностей. Тогда, в 1998 я и познакомился с MySQL. Arjen: Что вам больше всего нравится в MySQL? Marc: Скорость и стабильность. Arjen: ха-ха, вы наслушались наш маркетинг? Marc: Совсем нет! Скорость и стабильность это два основных фактора для меня. Arjen: Относительно phpMyAdmin... как начался этот проект? Marc: Прежде всего я обратил свое внимание на MySQLWebadmin, но вскоре обнаружил phpMyAdmin, которому на тот момент было всего три месяца. Но так как я преподавал франкоговорящим студентам в Квебеке, мне понадобилась французская версия. Тогда я обратился к Тобиасу Ратшиллеру (Tobias Ratschiller), основателю проекта, с просьбой поправить код для более легкой локализации phpMyAdmin.

Сейчас мы знаем, что необходимо реализовывать новые возможности MySQL 4.1 и 5.0, но четкого плана у нас нет

7


ЛЮДИ

Интервью с одним из ведущих разработчиков phpMyAdmin Марком Делислом

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

PHP Inside #15

С 1998 до 2000 года phpMyAdmin был в первой фазе разработки (в 1998 появилась первая мультиязычная версия). Однако в августе 2000 Тобиас перестал уделять проекту время и в марте 2001 года была сформирована новая команда и phpMyAdmin был переведен на портал sourceforge.net. Я присоеднинился к этой команде в 2001 году и начал интенсивную работу над версией 2.2.0 в августе 2001. Arjen: Кто сейчас вовлечен в разработку phpMyAdmin? Кто "возглавляет" проект сейчас? Marc: Наша команда состоит из восьми человек, двое из которых являются "администраторами проекта". Все мы волонтеры. В команду входят следующие разработчики: Александр Турек (Германия), Гарвин Хайкинг (Германия), Робин Джонсон (Канада), Михаль Цихарь (Чехия), Михаель Кек (Германия), Марсель Чопп (Швейцария). Проект администрируют Оливер Мюллер (Швейцария) и я.

В 2002 году я удивлялся показателю 10 скачиваний phpMyAdmin в минуту, но теперь воспринимаю это как обычное дело

Arjen: Я полагаю, что у вас налажен процесс разработки (пусть и неформальный) согласно которому вы определяете пути развития проекта. Каким образом вы определяете какой функционал и когда должен быть реализован? Marc: В последние несколько лет у нас был некоторый определенный заранее план, к примеру, редизайн интерфейса к версии 2.6.0 или MIME-based трансформации. Но в 2005 году этот процесс стал более неформальным. Сейчас мы знаем, что необходимо реализовывать новые возможности MySQL 4.1 и 5.0, но четкого плана у нас нет. Arjen: По вашему мнению, почему phpMyAdmin завоевал такую популярность? Получается, что phpMyAdmin становится стандартом для веб-ориентированного администрирования MySQL и включается во все большее количество дистрибутивов Linux, Novell NetWare и других. Marc: Просто система делает свою работу и содержит некоторые дополнения в виде визуализации полей blob при просмотре таблиц или некоторые возможности PDF. Но я не могу сказать точно, за что phpMyAdmin любят люди - за его специальные возможности или за способность выполнять повседневные задачи. Конечно, немаловажным фактом для пользователей MySQL остается возможность администрировать СУБД через веб-интерфейс.

Я был первым человеком, который начал перевод системы на другие языки

Я рад этому успеху, но он не вызывает у меня удивления, потому что мы прислушивались к сообществу и старались быстро исправлять важные ошибки. В 2002 году я удивлялся показателю: 10 скачиваний phpMyAdmin в минуту, но теперь воспринимаю это как обычное дело. И еще один важный момент: я был первым человеком, который начал перевод системы на другие языки и вот сейчас мы имеем 50 переводов и еще один находится в работе. Arjen: Это здорово! А какой коэффициент скачивания программы сейчас? Я правильно понимаю, что этот показатель все равно не отражает полной картины, так как phpMyAdmin установлен на серверах многих хостинг-провайдеров? Marc: Да, вы правы, это действительно так. Хостинг-провайдер или школа могут установить систему один раз и с ней будут работать сотни пользователей и это только часть от всех инсталляций. В любом случае, в 2005 году мы достигли показателя 220 320 тысяч скачиваний за месяц.

8


ЛЮДИ

Интервью с одним из ведущих разработчиков phpMyAdmin Марком Делислом

Arjen: Ого! Впечатляющие цифры. Есть ли у вас какие либо особенные планы по поводу будущего phpMyAdmin?

Кто-то советует нам создать графический механизм конфигурирования, но на это у нас просто нет человеческих ресурсов.

в 2005 году мы достигли показателя 220 - 320 тысяч скачиваний за месяц

PHP Inside #15

Marc: Чтож, мы будем придерживаться традиций и оставим интерфейс более менее таким как он есть сейчас, но несомненно, хотелось бы реализовать интерфейс для управления представлением.

Arjen: Может быть кто-то из читателей данного интервью сможет взяться за эту работу! Возможно это ужасный вопрос, но сколько времени вы тратите на разработку phpMyAdmin в среднем за неделю? Marc: Это ужасно только для моей жены :) Я трачу 7-10 часов в неделю. Правда последнее время стало исключением, так как я был занят написанием книги о phpMyAdmin на английском, а потом на французском языках, что конечно же делал за деньги. Книга была опубликована на четырех языках и вскоре выйдет на пятом. Она доступна на http://phpmyadmin.net. Я полагаю, что эта книга добавит доверия к проекту в плане документации, так как волонтеры не очень-то любят писать 250-ти страничные руководства. Arjen: Вы участвуете еще в каких либо Open Source проектах? Marc: Нет, phpMyAdmin мое единственное детище :) Arjen: Конечно за исключением четырех детей из реальной жизни ;-) Что бы вы могли посоветовать пользователям, которые хотят писать код для phpMyAdmin или других открытых проектов? Как им принять участие? Marc: Мой совет... нашей команде нужны хорошие баг-репорты (отчеты об ошибках) и это самый лучший способ принять участие. Еще нам нужны программисты, которые самостоятельно смогут разбираться в исходном коде и присылать нам большие или маленькие патчи. Но тут не бывает волшебства и контрибъюторы проявляют большую щедрость, даря свое время проекту. Arjen: Какие нововведения вы хотели бы видеть в MySQL? Marc: Это будет сюрпризом для вас, но я как разработчик phpMyAdmin очень хотел бы поменьше всяких нововведений в MySQL, потому как нам придется их реализовывать в phpMyAdmin :) Arjen: Могу себе представить. Но есть ли что-то такое, чего вам действительно не хватает? Marc: Кое что конечно кажется нелогичным, к примеру вывод запросов SHOW CREATE TABLE и SHOW FULL FIELDS, но мы пытаемся с этим справляться. Arjen: Я полагаю, что INFORMATION_SCHEMA в MySQL 5.0 решит эти проблемы? Marc: Да, но здесь необходимо учитывать, что мы должны поддерживать и старые версии, которые остануться повсюду! Arjen: Правильно. Может ли MySQL AB что-то сделать для вас? Marc: Как разработчик phpMyAdmin я бы сказал, что мне очень приятно входить в его команду и отвечать на вопросы официального представителя MySQL AB. Для многих пользователей phpMyAdmin остается единственным доступным административным инструментом для работы с MySQL. Однако на таких мероприятиях как Конференция пользователей MySQL у меня сложилось ощущение, что phpMyAdmin не имеет никакого отношения к MySQL AB. То же самое и в обучающих курсах от MySQL AB. 9


ЛЮДИ

Интервью с одним из ведущих разработчиков phpMyAdmin Марком Делислом

PHP Inside #15

Я мечтаю о том, чтобы на сайте MySQL были упоминания о том, что существует вот такой веб-ориентированный продукт. Даже если это не продукт от MySQL AB. Дело в том, что существует большой объем консалтинговой работы для многих веб-ориентированных проектов и я догадываюсь, что большинство этих проектов работает с MySQL. Arjen: Это очень полезная обратная связь. Мы готовим обширное решение на эту тему. Marc: И продолжайте приглашать нас на мероприятия, посвященные LAMP :) Arjen: Насчет этого не беспокойтесь - мы будем продолжать делать это. А сейчас - спасибо за интервью.

10


ИДЕИ

Smarty — не просто шаблоны

PHP Inside #15

Smarty — не просто шаблоны Автор: Кузьма Феськов Smarty может быть не просто шаблонизатором, а еще, своего рода фреймворком для разработки веб-приложений Скажем сразу, этот материал не будет вас учить пользоваться базовыми возможностями данной библиотеки. Напротив, я копну гораздо глубже. Цель этого материала взглянуть на шаблонизатор Smarty с другой стороны, и увидеть в нем не просто очень удобный и мощный шаблонный движок, а некий фреймворк для разработки ваших приложений. Часто, говоря о Smarty, незаслуженно обвиняют его в низкой производительности и «тормознутости», что ж – автор данного материала с указанными товарищами не согласен. Напротив, раз уж мы приняли решение использовать в своем приложении эту библиотеку, я предлагаю вам на полную катушку задействовать ее возможности, отдав на откуп шаблонизатору как вывод информации пользователю, так и управление этой информацией.

Компонентная модель Одна из сильных сторон Smarty – это возможность создавать свои плагины и расширения. Воспользуемся этой его возможностью в полной мере и попробуем реализовать на ее основе компонентную модель сайта. Что такое в нашем понимании компонент? Под компонентом я буду подразумевать обособленный блок сайта, который умеет выполнять строго определенный набор действий и, в результате своей работы, либо выводить что-либо на экран, либо готовить какие-то данные для других компонентов. Компонент – это элемент сайта, который, во-первых, точно знает какие действия он может совершать, во-вторых, какие библиотеки для совершения этих действий ему нужны. В результате сайт будет состоять из ядра - набора библиотек (классов), которые содержат в себе какие-то низкоуровневые действия, например работают с базой, – и компоненты, которые подключают эти библиотеки и, в нужном порядке, вызывают те или иные их методы. В чем положительная сторона такого подхода? 1. вы пишите специальные классы (объекты) ядра своего сайта, они никак не зависят от вывода на экран, а просто подготавливают и обрабатывают данные, тем самым обеспечивается высокая переносимость кода и возможность его повторного использования; 2. в случае командной работы, вам не надо заботиться о том, что делает соседний программист, который пишет свой компонент; 3. стандартизация кода – вы можете создать интерфейс компонента и строго следовать его требованиям, что позволит одному программисту легко разобраться в компоненте другого программиста. Это основные преимущества данного подхода. 11


ИДЕИ

Smarty — не просто шаблоны

Общие классы

PHP Inside #15

Безусловно, в каждом приложении есть набор классов, которые нужны всем, или большинству компонентов, например, класс для работы с базой. Как поступить в таком случае? И для этой проблемы в Smarty есть удачное решение. Впрочем, давайте по порядку. Сначала инициализируем класс Smarty: <?php /** Путь до Smarty */ define('SMARTY_DIR', '/smarty/'); /** Путь до Smarty шаблонов */ define('TEMPLATES', '/templates/'); /** Путь до Smarty компилированных шаблонов */ define('TEMPLATES_C', '/templates_c/'); require_once(SMARTY_DIR . 'Smarty.class.php'); $smarty = new Smarty; $smarty->compile_check = TRUE; $smarty->force_compile = TRUE; $smarty->template_dir = TEMPLATES; $smarty->compile_dir = TEMPLATES_C; $smarty->plugins_dir[] = LIBS_PATH; $smarty->caching = FALSE; ?>

Итак, Smarty готов к работе. Что необходимо сделать с общими классами, чтобы обеспечить доступ к ним внутри любого компонента? Скажем, у нас есть несколько общих компонентов: 1. adodb – класс для работы с базой; 2. session – класс для работы с сессиями; 3. errors – класс для обработки ошибок; 4. variables – класс для хранения и обработки состояния массивов $_GET и $_POST. Первым делом, нам необходимо создать объекты данных классов (параметры конструкторов зависят от вашей конкретной реализации). В целом, это делается стандартным образом: <?php require_once(CLASSES_DIR . '/variables.class.php'); $vars = new Variables(); require_once(CLASSES_DIR . '/errors.class.php'); $errors = new Errors($smarty); require_once(CLASSES_DIR . '/security.class.php'); $security = new Security($adodb); // и так далее... ?>

Объекты созданы и теперь необходимо обеспечить доступ к ним в любом компоненте нашего приложения.

12


ИДЕИ

Smarty — не просто шаблоны

Для этого необходимо зарегистрировать данные объекты в Smarty:

PHP Inside #15

<?php $smarty->register_object('adodb', $adodb); $smarty->register_object('vars', $vars); $smarty->register_object('errors', $errors); $smarty->register_object('security', $security); ?>

Для регистрации объектов мы используем метод Smarty register_object(). После чего ваш объект станет доступным везде, где он может понадобиться. Как «достать» нужный вам зарегистрированный объект мы рассмотрим в следующей части.

Функция «Компонент» К текущему моменту Smarty ничего не знает о каких-либо компонентах, и нам нам надо научить его работать с ними. Для этого мы добавляем к синтаксису шаблонов новый тег – {component}. Чтобы Smarty научился обрабатывать этот тег – пишем простую функцию: <?php // Smarty function Component // // @author Feskov Kuzma function smarty_function_component($params, &$smarty) { $adodb = &$smarty->get_registered_object('adodb'); $vars = &$smarty->get_registered_object('vars'); $errors = &$smarty->get_registered_object('errors'); $security = &$smarty->get_registered_object('security');

} ?>

if (empty($params['name'])) { $params['name'] = 'site_view'; } if (is_file(ADMIN_LIBS_PATH . '/' . $params['name'] . '.component.php')) { require(ADMIN_LIBS_PATH . '/' . $params['name'] . '.component.php'); } else { echo 'Component <strong>' . $params['name'] . '</strong> not found'; } unset($adodb, $errors, $security, $vars);

Давайте разберемся, что делает данная функция. Во-первых, она создает обработчик для нового тега – {component}, во-вторых, достает (get_registered_object()) и делает доступными вызванному компоненту зарегистрированные ранее общие объекты. Немножко теории. Чтобы вызвать данную функцию к жизни, необходимо в любом шаблоне написать тэг {component}. Поскольку функция не выполняет никаких продуктивных действий, и служит исключительно диспетчером компонентов, просто написать {component} недостаточно, поскольку эта команда неинформативна. Конечно, функция не даст сбоя, и запустит принятый по умолчанию компонент 'site_view'.

13


ИДЕИ

Smarty — не просто шаблоны

PHP Inside #15

Каким образом уточнить, какой именно компонент вам требуется и как передать ему дополнительные параметры? Все очень просто, мы несколько измени вызов компонента в шаблоне: {component name='имя требуемого компонента' var1='значение параметра' var2='значение другого параметра'}

И так далее, как вы понимаете, name, var1, var2 – это дополнительные параметры для нашего компонента. Name, например, указывает имя компонента, который мы хотим вызвать, а остальные параметры – это дополнительные данные для вызываемого компонента, их количество может быть любым, ровно как и их имена. После того, как в шаблоне встретится указанный выше тег, произойдет вызов нашей функции, которая, в свою очередь, вызовет нужный вам компонент. Все дополнительные параметры будут доступны как в нашей функции так и в вызываемом компоненте, они будут содержаться в массиве $params, где ключ – это название параметра, а значение – соответственно – его значение. Мы приняли, что файлы наших компонентов именуются следующим образом: name.component.php

где name – это наш параметр name. Функция ищет в указанной папке файл с именем, сформированным указанным образом и исполняет его. В случае отсутствия параметра name запускает компонент, назначенный по умолчанию, в противном случае – выдает ошибку. Помимо зарегистрированных ранее общих объектов, нашим компонентам полностью доступна вся мощь шаблонизатора Smarty – у вас есть объект $smarty. Обращаю также внимание, что все что вы ассигните (assign) в объект $smarty, будет также доступно не только вашему компоненту, но и общему (вызывающему) шаблону, а это значит, что компоненты вовсе не обязаны всегда выводить что-либо на экран, они вполне могут передавать подготовленные данные в общий шаблон, а он, в свою очередь, может передать их другому компоненту, который на основе их может что-либо вывести на экран. Дополнительным преимуществом такого подхода оказывается возможность моделирования сайта путем нехитрого изменения его шаблонов – то есть получается интересная взаимосвязь дизайна и логики. Мы привыкли, что логика управляет выводом, а здесь, отчасти, вывод управляет логикой. Также отмечу, что вложенность компонентов может быть бесконечной. То есть компонент в своей работе может запустить какой-то свой шаблон, который, в свою очередь, может вызвать другой компонент.

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

14


ИДЕИ

Smarty — не просто шаблоны

В шаблоне напишем так:

PHP Inside #15

{component name='news' action='view' count=5 tpl='news_mainpage.tpl'}

Параметр name указывает на нужный нам компонент, action обозначает действие, которое требуется совершить, count – это фильтр количества новостей, и tpl – название шаблона, который будет использован для формирования вывода новостей на экран. Теперь давайте посмотрим, как мог бы выглядеть наш компонент: <?php // News component // // @author Feskov Kuzma // Подключаем необходимый нам класс // и создаем объект require_once(CLASSES_DIR . '/news.class.php'); $news = new News($adodb); // Обрабатываем возможные действия switch ($params['action']) { // --- View news --case 'view': // Получаем 5 последних новостей $data = $news->NewsList($params['count']); if (false === $data) { // Выводим ошибку $errors->ComponentErrPrint('Компонент news, действие ' . $params ['action'], $news->ERROR); } // Проверяем - есть ли такой шаблон if(is_file(TEMPLATES . '/' . $params['tpl'])) { // Выводим новости на экран $smarty->assign('data', $data); $smarty->display($params['tpl']); } else { // Выводим ошибку $errors->ComponentErrPrint('Компонент news, действие ' . $params ['action'], 'Шаблон не найден'); } break; // --- Default action --default: // Если никакого действия не задали, выводим ошибку $errors->ComponentErrPrint('news_view', 'Неизвестное действие'); break; } ?>

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

15


ИДЕИ

Smarty — не просто шаблоны

Обмен данными между компонентами

PHP Inside #15

Немного остановлюсь на разделении компонентов на типы: prepare – эти компоненты ничего не выводят на экран, они только подготавливают данные для других компонентов или общего (главного) шаблона, и view – эти компоненты обязательно в результате своей работы что-то выводят на экран. Давайте посмотрим, каким образом компонент prepare может подготовить данные для компонента view. <?php // --- Фрагмент компонента prepare --$smarty->assign('prepare_data', $prepare_data); ?>

Из данного фрагмента видно, что компонент prepare создал какой-то набор данных и ассигнул (assign) его в главный шаблон, присвоив этим данным имя 'prepare_data'. Теперь давайте взглянем на главный шаблон: <!-- Фрагмент главного шаблона --> <!-- Вызываем компонент prepare --> {component name='prepare'} <!-- Вызываем компонент view --> {component name='view' prepare_data=$prepare_data}

Как видно из этого фрагмента, сначала мы вызвали компонент prepare, а затем компонент view. В качестве параметра передали в view продукт деятельности компонента prepare. <?php // --- Фрагмент компонента view --print_r($params['prepare_data']); ?>

В свою очередь, компоненту view эти данные стали доступны посредствам массива $params, в котором появился новый индекс – prepare_data.

Итоги Итак, здесь мы с вами рассмотрели несколько необычную роль шаблонизатора Smarty в разработке приложений: поручили Smarty быть не только удобным шаблонизатором, но и диспетчером нашего приложения, отдали ему на откуп формирование сайта. Таким образом, используя эту технологию, вы легко можете менять логику и вид своего приложения изменяя только его шаблоны для вывода на экран, что позволяет довольно часто экономить время при разработке как простых, так и сложных приложений. Также, такой подход позволяет максимально абстрагировать ядро вашего сайта (классы) от вывода информации на экран, что дает дополнительные преимущества для создания переносимого кода и позволяет развертывать новые приложения на базе старых. Компонентная модель разработки позволяет добиться существенного разграничения труда программистов, работающих в команде. На этом все, надеюсь этот материал даст вам повод для новых изысканий и идей.

16


ИДЕИ

Принципы создания proxy-сервера на PHP в интрасети. Вопросы безопасности Автор: Роман Толкачев Организовывая Интрасеть, Интернет-провайдер подвергает себя определённому риску, в случае, если сервер со страницами клиентов виден из Интернета и на страничках можно использовать PHP Это, прежде всего, не риск расставания с паролями доступа (хотя и такое возможно), а риск быть взломанным собственными пользователями. Хочется отметить, что всё сказанное ниже чистый вымысел, герои рассказа давно умерли и т.д., и т.п.

fopen(), include()… Уже много раз, в разговоре о безопасности PHP, упоминалась деректива allow_url_fopen. При значении On (по-умолчанию), функции include(), fopen() и смежные получают возможность получать содержимое по протоколам HTTP, FTP и т.д. Что же это даёт? Многие думают, что главной дырой, в этом случае, является исполнение удалённого кода, но они окажутся неправы. Рассмотрим пример:

В данном случае клиент (т.е. мы/наш браузер) имеет доступ к ресурсам ИнтраНет сервера, но не к http://www.somehost.com/, потому как не хотим платить много денег, и сидим в Интрасети. В то же время, любой другой пользователь Интернет может просматривать ИнтраНет ресурсы. Фактически сервер имеет доступ в Интернет. PHP скрипты исполняются на сервере, а это значит, что на них не действует ограничение зоны просмотра страниц, в отличии от клиента. Вот это, как раз, и позволяет абонентам сети использовать PHP в корыстных целях. Теперь к конкретному примеру: <? $html = implode('', file('http://' . $_GET["site"])); echo $html; ?>

17

PHP Inside #15

Принципы создания proxy-сервера на PHP в интрасети. Вопросы безопасности


ИДЕИ

Принципы создания proxy-сервера на PHP в интрасети. Вопросы безопасности

PHP Inside #15

Если запустить http://www.mysite.prov.ru/test.php?site=somehost.com/, то мы получим всё содержимое главной страницы http://somehost.com/, даже если находимся в пределах ИнтраСети. Разумеется, наш скрипт должен быть на ИнтраНет HTTP сервере. Такой же механизм может быть приспособлен и для получения файлов (т.е. нетарифицированного скачивания из интернета). Решение данной проблемы состоит в отключении allow_url_fopen в файле php.ini (установка значения в off).

сURL Рассмотрим второй вариант. Если провайдер достаточно умён, чтобы отключить данную дериктиву, но в то же время не так умен для проверки всех устанавливаемых расширений. Итак, он всё же устанавливает cURL. Объясняю что это такое. Это расширение позволяет совершать запросы к HTTP серверам. Много интересных особенностей у данного расширения, с которыми вы можете познакомиться в официальном мануале. И опять существует возможность связываться с удалённым сервером через ИнтраНет HTTP сервер, причём это работать будет быстрее. Аналогичный пример: <?php $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $_GET["site"]); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec($ch); curl_close($ch); ?>

Использовать так же. Устранить данную уязвимость можно лишь удалением расширения cURL. Самые «трудолюбивые» могут пойти дальше и сделать прокси-сервер, который будет перенаправлять запросы браузера на скрипты. Но это, как говорится, уже совсем другая история.

18


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

HOWTO по оптимизации PHP Автор: Джон Лим (John Lim) Перевод: Кузьма Феськов PHP очень быстрый язык программирования, но есть еще множество способов оптимизации, помимо оптимизации кода

PHP Inside #15

В этом материале мы объясним, почему оптимизация PHP захватывает собой гораздо больше факторов, нежели простая оптимизация кода, и почему настройка PHP требует понимания, каким образом работает PHP относительно других компонентов вашего сервера. Также мы займемся выявлением узких мест, связанных с этими компонентами и устранением их. Также мы затронем вопросы оптимизации ваших PHP скриптов, чтобы они работали еще быстрее. Оригинал статьи здесь: http://phplens.com/lens/php-book/optimizing-debugging-php.php

Достижение высокой производительности Когда мы говорим о хорошей производительности, мы не говорим о том, насколько быстро ваши скрипты будут запускаться. Производительность – это набор компромисов между масштабируемостью и скоростью. Скрипты, настроенные, чтобы использовать минимум ресурсов, могут быть медленнее, чем скрипты, использующие кэширование, потомучто больше копий одного и того же скрипта может быть запущено одновременно на одном сервере. В примере ниже, A.php – спринтер – настроен для быстрого запуска, а B.php – бегун марафона – может бегать трусцой, почти с той же самой скоростью. При низкой загрузке, A.php существенно быстрее, но как только трафик начинает увеличиваться, работа B.php снижается лишь немного, тогда как A.php выдыхается.

19


ТЕМА С ОБЛОЖКИ

Давайте возьмем более реалистичный пример для дальнейших рассуждений. Предположим, нам необходимо написать скрипт, который должен прочитать файл размером 250 кб и сгенерировать HTML, резюмирующий информацию из файла. Мы пишем два сценария, которые делают одно и тоже: hare.php, который читает файл в память целиком и обрабатывает его за один проход, и tortoise.php, который читает файл построчно не сохраняя в памяти информации, больше чем одна строка. Tortoise.php будет медленнее, потому что использует многократное чтение, требует большего количества системных вызовов. Hare.php требует 0.04 секунды центрального процессора, а также 10 мб памяти. Tortoise.php требует 0.06 секунд процессорного времени и 5 мб памяти. Сервер располагает 100 мб свободной памяти и процессор на 99% свободен. Предположим, что никакой фрагментации памяти не происходит (для упрощения). При 10 одновременных запусках скрипта, hare.php исчерпает память (10 х от 10 до 100). В этой точке, tortoise.php все еще будет иметь в своем распоряжении 50 мб свободной памяти. 11 запуск hare.php приведет к уменьшению производительности, поскольку система начнет использовать виртуальную память. При этом, его первоначальная скорость может упасть более чем в половину. Каждый запуск hare.php на данный момент занимает 0.08 секунд процессорного времени. Тем временем tortoise.php все также будет занимать свое процессорное время – 0.06 секунд. В таблице ниже, самый быстрый сценарий выделен полужирным: Соединения

CPU-секунды при запуске одного скрипта

CPU-секунды при запуске десяти скриптов

CPU-секунды при запуске одиннадцати скриптов

Hare.php

0.04

0.40

0.88 (Свободная закончилась)

Tortoise.php

0.06

0.60

0.66

память

Вышеприведенные примеры говорят нам о том, что тот, кто хочет получить высокую производительность – не пишет просто быстрые скрипты. Для достижения высокой производительности PHP требуется хорошее понимание работы основных аппаратных средств, операционной системы и другого программного обеспечения, типа сервера и базы данных.

Узкие места Пример hare и tortoise (зайца и черепахи) показал нам причины узких мест. С бесконечной оперативной памятью hare будет быстрее всегда, чем tortoise. К сожалению, вышеупомянутая модель слишком упрощена, и есть еще много других узких мест, препятствующих работе, помимо оперативной памяти:

Сеть Ваша сеть, вероятно, самое узкое место. Например, вы говорите, что у вас 10 Мбит связь с интернетом, по которой вы можете скачать 1 мб данных в секунду. Если каждая страница у вас занимает 33 кб, то обычные 33 страницы в секунду будут занимать весь ваш канал. Более тонкие узкие места в сети – это скорость отклика, например, сервера имен (DNS), или адресация нужного количества памяти для программного обеспечения сети.

20

PHP Inside #15

HOWTO по оптимизации PHP


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Центральный процессор Если вы контролируете загрузку центрального процессора, то увидите, что пересылка обычных HTML страниц вообще не будет обременять процессор, и, в данном случае, самым узким местом будет сеть. Однако, для сложных динамических web-страниц, производимых PHP, скорость вашего процессора будет ограничивающим фактором. Наличие нескольких процессоров или фермы серверов может значительно снизить подобное ограничение.

Shared Memory (общедоступная память) Общедоступная память используется для связи между процессами, и хранит ресурсы, которые делятся между несколькими процессами, типа кэшированных данных и кода. Если общей памяти недостаточно, то любая попытка обратиться к ресурсам, использующим общую память, например, соединение с базой данных, или запуск кода, вызовет ошибку.

PHP Inside #15

Файловая система Доступ к жесткому диску может быть в 50-100 раз медленнее, чем доступ к данным в оперативной памяти. Кэширование файлов с использованием оперативной памяти могут снизить данное ограничение. Однако, в условиях небольшого количества памяти для системного кэша, работа будет замедляться. Системные файлы так же могут быть сильно фрагментированными, замедляя дисковый доступ. Частое использование симлинков на UNIX системах также приводят к замедлению. Также печально известны установки поумолчанию для доступа к диску в Linux системах, которые настроены для совместимости, а не для скорости. Используйте команду hdperm, чтобы перенастроить параметры диска вашей Linux системы.

Управление процессами В некоторых операционных системах, например, в Windows, создание нового процесса – это медленная операция. Это означает, что CGI процесс, вызываемый для каждой операции, будет работать значительно медленнее. Запуск PHP в multi-threaded (в виде модуля) режиме должно увеличить скорость ответа (примечание: старые версии PHP неустойчивы в данном режиме). Избегайте переполнения вашего сервера множеством ненужных процессов. Например, если ваш сервер предназначен только для обслуживания сети, избегайте запуска (или даже вообще установки) X-Windows. На Windows-системах избегайте запуска Microsoft Find Fast (компонент офиса), а также всякого рода screensaver'ов. Потомучто все это заканчивается 100% использованием процессора. Некоторые программы вы можете рассмотреть к удалению, включая неиспользуемые сетевые протоколы, серверы почты, сканеры антивирусов, аппаратные драйверы для мыши, инфракрасного порта и так далее. На Unix: я подразумеваю, что вы общаетесь со своим сервером посредствам SSH. В этом случае, вы можете рассмотреть к удалению следующее: •

демоны, например, telnetd, inetd, atd, ftpd, lpd, sambad

sendmail для поступающей почты

portmap для NFS

xfs, fvwm, xinit, X

Также вы можете отключить запуск некоторых программ при загрузке, изменяя файлы запуска, которые обычно хранятся в /etc/init* или /etc/rc*/init* директории.

21


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Также рассмотрите задачи, которые запускаются по крону. Посмотрите, можно ли их удалить или перенести на непиковые периоды.

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

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

PHP Inside #15

Мой совет – преже чем начинать проектирование приложения, сделайте некоторые основные эталонные тесты аппаратных средств и программного обеспечения, чтобы получить чувство максимальной работоспособности, которую вы могли бы достигнуть. Тогда, когда вы проектируете и кодируете приложение, держите желательные рабочие параметры в памяти, потому что на каждом этапе пути вам придется идти на компромиссы между производительностью, функциональностью, защитой и гибкостью. Также выберите хорошие испытательные данные. Если ваша база данных, как ожидается, будет хранить только 100 000 записей, избегайте тестирования ее только со 100 записями, вы будете потом об этом сожалеть. Это когда-то случилось с одним из программистов в моей компании: мы обнаружили медленный код значительно позже, потратив много времени впустую, поскольку пришлось переписать большую часть кода, который работал, но не масштабировался.

Настройка вашего сервера для PHP Далее, мы рассмотрим с вами, как оптимизировать работу с PHP двух самых распространенных web-серверов, Apache 1.3 и IIS. Разработчики PHP заявляют, что нет никакой разницы в скорости и преимуществах масштабирования при использовании Apache 2.0 над Apache 1.3, особенно, если PHP установлен в виде модуля.

Apache 1.3/2.0 Этот сервер доступен на Unix и Windows платформах, это самый популярный сервер в мире. Apache 1.3 использует pre-forking (предразветвления) модель для обслуживания сети. После старта, сервер создает дочерние процессы для обслуживания каждого HTTP запроса. Родительский процесс действует как ангел-хранитель, проверяя, что все дочерние процессы работают правильно и координирует их действия. Чем больше HTTP запросов, тем больше дочерних процессов будет порождено, чтобы их обработать. Поскольку HTTP запросы начнут замедляться, родительский процесс уничтожает неактивные дочерние процессы, освобождая ресурсы для новых процессов. Красота данного подхода в том, что это делает Apache чрезвычайно устойчивым. Даже если дочерний процесс рушится, родительский и другие дочерние процессы будут изолированы от сбойного дочернего процесса.

22


ТЕМА С ОБЛОЖКИ

Модель предразветвления не настолько быстра, как другие решения. Но, что касается меня, то это является «суматохой ни о чем», на сервере, обслуживающем PHP сценарии, потомучто другие узкие места дадут сбой раньше, чем проблемы Apache станут существенными для сервера. Ошибкоустойчивость и надежность Apache более важный фактор. Apache 2.0 может работать в модульном режиме (multi-threaded). Мои эталонные тесты показали, что преимуществ этого режима не так уж много. Также будте готовы к тому, PHP расширения несовместимы, например GD и IMAP. Проверено на Apache 2.0.47 (23 октября 2003). Apcahe сконфигурирован при помощи файла httpd.conf. Следующие параметры особенно важны при настройке дочерних процессов: Параметр

По умолчанию

Описание

MaxClients

256 Максимальное число дочерних процессов, которые может создать сервер. Значение поумолчанию 256 означает, что одновременно может быть обработано 256 HTTP запросов. Любые дальнейшие запросы будут поставлены в очередь.

StartServers

5 Количество дочерних процессов, которые будут созданы сразу после старта сервера.

MinSpareServers

5 Число неактивных дочерних процессов, которые должны быть созданы. Если число неактивных процессов падает ниже этого числа, то 1 ребенок создается первоначально, 2 на следующую секунду, 4 еще через секунду, и так далее, пока не будет создано 32 дочерних процесса с интервалом в секунду.

MaxSpareServers

10 Если создано больше, чем данное число дочерних процессов, то эти дополнительные процессы будут остановлены.

MaxRequestsPerChild

0 Устанавливает какое число HTTP запросов ребенок должен обработать перед завершением. Если вы устанавливаете ее в 0, то дочерний процесс никогда не умирает. Установите его в пределах от 100 до 10000, если вы подозреваете утечки памяти или неправильно использование ресурсов.

Для больших сайтов наилучшими значениями будут близкие к этим: •

MinSpareServers 32

MaxSpareServers 64

Apache под Windows ведет себя иначе. Вместо того, чтобы использовать дочерние процессы, Apache использует треды. Вышеупомянутые параметры не используются. Вместо этого мы имеем один параметр: ThreadsPerChild который имеет значение поумолчанию – 50. эта переменная указывает число тредов, которые могут быть порождены Apache. Поскольку в Winodws есть только один дочерний процесс, то количество HTTP запросов, которые он может обработать, равняется 50. Для серверов сети, которые испытывают более серьезные нагрузки, увеличьте этот параметр от 256 до 1024.

23

PHP Inside #15

HOWTO по оптимизации PHP


Параметр

По умолчанию

Описание

SendBufferSize

Определяется операционной системой

Определяет объем буфера вывода (в байтах), используемого в TCP/IP соединениях. Этот параметр прежде всего полезен для переполненных или медленных сетей, когда пакеты необходимо буферизировать. В этом случае, установите этот параметр близким к размеру самого большого пересылаемого файла. Один TCP/IP буфер будет создан при соединении.

KeepAlive (on/off)

on

В оригинале HTTP спецификации, каждый HTTP запрос должен создавать новое соединение с сервером. Keep-alive заголовок был создан, чтобы уменьшить нагрузку на сервер. Параметр keep-alive говорит серверу, чтобы он использовал тоже самое соединение через socket (сокет) для нескольких HTTP запросов. Если у вас есть отдельные сервер, который обслуживает все изображения (images), то вы можете выключить этот параметр. Подобная техника поможет значительно сэкономить ресурсы сервера.

KeepAliveTimeOut

15 Количество секунд для удержания сокет-соединения. Это время включает в себя генерацию контента и ответ клиента. Если клиент не реагирует в течение этого времени – будет создано новое соединение. Это значение не должно быть большим, иначе сокет будет простаивать в этот период.

MaxKeepAliveRequests

100 Сокет-соединения будут закончены, как только их количество достигнет этой цифры. Установите большое значение, но меньше MaxClients или ThreadsPerChild.

TimeOut

300 Отсоединиться, если время простоя превышает это число. Вы можете установить меньшее значение, если ваши клиенты имеют небольшую задержку.

LimitRequestBody

0 Максимальный размер PUT или POST. 0 – нет лимита.

Если вы не требуете DNS поиска и не используете htaccess для настройки отдельных директорий в Apache, вы можете задать: # выключить DNS поиск: PHP скрипты получают только IP адрес HostnameLookups off # отключить проверку htaccess <Directory /> AllowOverride none </Directory>

24

ТЕМА С ОБЛОЖКИ

Другие полезные параметры, которые вы можете изменить приведены ниже:

PHP Inside #15

HOWTO по оптимизации PHP


Options FollowSymLinks #Options SymLinksIfOwnerMatch

Настройка IIS Настройка производительности исходя из обращений к серверу в день.

Определяет, какое количество памяти отвести для IIS. (Performance Tab).

Управление полосой пропуска

Управляет полосой пропуска в секунду, разделенную по серверам. (Performance Tab).

Управление процессом

Управляет процентом процессорного времени, доступного для процесса по серверам. (Performance Tab).

Таймаут

По умолчанию – 900 секунд. Установите более низкое значение, если у вас локальная сеть. (Web Site Tab)

HTTP компрессия

В IIS 5 вы можете сжимать динамические страницы, HTML и картинки. Вы можете настроить эти параметры. Значение по умолчанию – выключено. HTTP сжатие нужно включать для всего сервера. Чтобы включить этот параметр – нажмите правую кнопку мыши на консоли сервера (не на одном из подсайтов), выберите Свойства (Properties). Нажмите на Вкладке Service, затем выберите Compress application files для компрессии динамических данных, и Compress static files — для компрессии статического контента.

Также вы можете изменить, настроенный поумолчанию, уровень изоляции webсервера. Во вкладке Home Directory в Application Protection вы можете определить уровень изоляции. На высшем уровне изоляции ваш сайт будет работать медленнее, потомучто это будет отдельный процесс от IIS, вто время как запуск сайта в IIS процессе – самая высока скорость, но сервер может «лечь», если в вашем скрипте есть серьезные ошибки. На данный момент я рекомендую запускать PHP сайты как CGI или с использованием ISAPI совместно с Application Protection установленной в hight (высокая). Вы также можете использовать regedit.exe для изменения параметров IIS 5, сохраненных в ветке HKEY_LOCAL_MACHINESYSTEM CurrentControlSetServicesInetinfoParameters. MemCacheSize

Устанавливает количество памяти, которую IIS будет использовать для кэширования своих файлов. Поумолчанию, ISS может использовать 50% установленной в компьютере памяти. Вы можете увеличить этот параметр, если на машине работает только IIS. Значение задается в мегабайтах. 25

ТЕМА С ОБЛОЖКИ

Если вас не волнует безопасность папок при вызове симлинков, включите FollowSymLinks и выключите SymLinksIfOwnerMatch, чтобы предотвратить дополнительный системный вызов lstat():

PHP Inside #15

HOWTO по оптимизации PHP


Определяет максимальный размер файла, который может быть кэширован. Размер указывается в байтах. Значение поумолчанию – 262,144 (256 кб).

ObjectCacheTTL

Устанавливает время (в миллисекундах), в течение которого кэшированный объект сохраняется в памяти. Значение поумолчанию – 30,000 миллисекунд (30 секунд).

MaxPoolThreads

Устанавливает число нитей на процессор. Определяет, сколько CGI приложений может быть запущено одновременно. Значение поумолчанию – 4. увеличьте это значение, если вы используете PHP как CGI.

ListenBackLog

Максимальное количество активных живых соединений (Keep alive), которые ISS поддерживает в очереди соединений. Значение поумолчанию – 15, должно быть увеличено к числу одновременных соединений, поддерживаемых вашим сервером. Максимально – 255.

Если эти параметры отсутствуют в данной ветке реестра – будут использоваться параметры поумолчанию.

Высокая производительность в Windows: IIS и FastCGI После большого тестирования, я считаю, что самая высокая производительность PHP в Windows достигается использованием IIS с FastCGI. CGI – это протокол для вызова внешней программы из сервера. Это дает не самую высокую скорость, потому что CGI программа удаляется каждый раз после создания страницы. FastCGI изменяет этот протокол для достижения более высокой производительности, заставляя CGI программу оставаться запущенной после обработки запроса, и многократно использоваться для обработки последующих запросов. Поскольку установка FastCGI на IIS достаточно сложна, вы должны использовать EasyWindows PHP Installer (http://phplens.com/phpeverywhere/easywindows). Он установит PHP, FastCGI и Turck MMCache для достижения лучшей производительности. Этот инсталлер также может установить PHP для Apache 1.3/2.0.

PHP 4 и Zend Engine Zend Engine – это внутренний компилятор и движок, использованный для создания PHP 4. Созданный Zeev Suranski и Andi Gutmn, Zend Engine – это сокращение от их имен. На начальном этапе – PHP работал следующим образом:

26

ТЕМА С ОБЛОЖКИ

MemCachedFileSize

PHP Inside #15

HOWTO по оптимизации PHP


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

PHP скрипт загружается в Zend Engine и компилируется в opcode. Opcode – это набор низкоуровневых бинарных инструкций. После запуска opcode происходит генерация HTML и передача его клиенту. Opcode удаляется из памяти после выполнения.

PHP Inside #15

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

PHP скрипт загружается в Zend Engine и компилируется в opcode. Opcode может быть оптимизирован с использованием необязательного оптимизатора, названного Zend Optimizer. В зависимости от скрипта, он может увеличить скорость выполнения PHP скрипта до 50%. Раньше, после выполнения, opcode уничтожался. Теперь вы можете организовать его кэширование, используя несколько альтернативных вариантов: продукты с открытым кодом и Zend Accelerator (раньше известен как Zend Cache), который является закрытым коммерческим продуктом. Только кэшированный opcode совместим с Zend Optimizer и Zend Accelerator. Opcode кэш ускоряет выполнение, удаляя из цепочки загрузку исходного скрипта и его компиляцию. Время выполнения, с использованием кэширования, может улучшиться от 10 до 200%. Где искать инструменты для кэширования opcode? Zend Accelerator. Это коммерческий продукт, развитый командой Zend Engine. Очень надежный. Искать здесь: http://zend.com. Вы обязательно должны протестировать программы с открытыми кодами, прежде чем начинать их использовать, поскольку их работа и надежность очень зависит от запускаемых PHP скриптов. Turck MMCache – (http://turck-mmcache.sourceforge.net/) больше не поддерживается. Смотрите eAccelerator, который является развитием mmcache и активно развивается.

27


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Alternative PHP Cache – http://apc.communityconnect.com/. PHP Accelerator – http://www.php-accelerator.co.uk/. AfterBurner Cache – http://www.bwcache.bware.it/. Один из секретов высокой производительности состоит не в том, чтобы написать быстрый PHP код, а в том, чтобы кэшировать результаты выполнения скрипта в файл или общую память. Скрипт запускается однажды, генерируемый HTML захватывается и все последующие обращения к скрипту приводят к показу уже готового HTML. Если требуется регулярное обновление данных, то необходимо указать срок жизни для кэшированных HTML. Кэширование HTML – это не часть PHP языка или Zend Engine – но осуществляется при помощи PHP кода. Существует много классов и библиотек для организации подобного. Одна из них – PEAR Cache, о которой мы поговорим в следующей части. Другой распространенный способ – библиотека Smarty.

PHP Inside #15

И, наконец, HTML, отдаваемый браузеру клиента, может быть сжат. Это включается добавлением следующего кода вначале вашего скрипта: <?php ob_start("ob_gzhandler"); ::: ::: ?>

Если ваш HTML очень сжимаем, то это может уменьшить размер на 50-80%, сокращая тем самым требования пропускного канала. Другая сторона – это необходимость в более мощном процессоре, чтобы эффективно и быстро сжимать страницы.

HTML кэширование с использованием PEAR Cache PEAR Cache – это набор классов для кэширования разнообразных типов данных, включая HTML и картинки. Самое распространенное использование PEAR Cache – это кэширование HTML текста. Чтобы использовать кэширование – задействуем Output buffering class, с кэшированием всего выдаваемого текста между функциями start() и end(): <?php require_once("Cache/Output.php"); $cache = new Cache_Output("file", array("cache_dir" => "cache/") ); if ($contents = $cache->start(md5("это уникальный ключ!"))) { # # Возвращаем кэшированные данные # print $contents; print "<p>Кэшированные данные</p>"; } else { # # Кэшированных данных нет, либо срок их жизни истек # print "<p>Не покидайте дом без этого:</p>"; # помещаем в кэш print "<p>Stand and deliver</p>"; # помещаем в кэш print $cache->end(10); } ?>

28


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

С тех пор, как я написал эти строки, была создана более продвинутая система кэширования PEAR: Cache Lite (http://pear.php.net/package/Cache_Lite); чтобы узнать об этом подробнее, смотрите memcached (http://www.danga.com/memcached/). Cache конструктор принимает первым параметром тип драйвера для сохранения кэша. Доступны следующие драйверы: файл, база данных, общая память (смотрите папку: pear/Cache/Container). Тесты Ulf Wendel показывают, что драйвер «файл» дает наилучшую производительность. Второй параметр – это параметры для используемого драйвера. Варианты: cache_dir – это папка для сохранения кэшированных данных, filename_prefix – уникальная приставка к названию файлов для сохранения кэшированных данных. Что странно, время жизни кэша не является параметром для конструктора. Для кэширования каких-то данных, вам необходимо сгенерировать уникальный ключ (id) для этих данных. В примере выше, мы использовали md5("это уникальный ключ!").

PHP Inside #15

Функция start() использует ключ для поиска кэшированной копии данных. Если контент не был кэширован, функция вернет пустую строку. И все последующие echo и print будут буферизироваться в кэш, до тех пор, пока не встретится функция end(). Функция end() возвращает содержимое буфера и заканчивает буферизацию вывода. Функция end() принимает в качестве первого параметра время жизни кэша. Этим параметром могут быть секунды или Unix таймштамп, указывающий точное время окончания жизни кэша, или 0 – установит интервал по умолчанию – 24 часа. Другой способ использования PEAR Cache – это сохранение значения переменных или других данных. Для реализации этого – используйте основной Cache класс: <?php require_once("Cache.php"); $cache = new Cache("file", array("cache_dir" => "cache/") ); $id = $cache->generateID("'это уникальный ключ"); if ($data = $cache->get($id)) { print "Кэшированные данные.<br>Дата: $data"; } else { $data = "Количество памяти достаточное..."; $cache->save($id, $data, $expires = 60); print "Кэш потерян.<br>"; } ?>

Для сохранения используемых данных применяйте функцию save(). Если выбранный вами уникальный ключ уже существует, вы можете использовать функцию generateID(). Объекты и массивы могут быть сохранены благодаря использованию функции serialize() внутри функции save(). Последний параметр – это время жизни кэша. Этим параметром могут быть секунды или Unix таймштамп, указывающий точное время окончания жизни кэша, или 0 – установит интервал по умолчанию – 24 часа. Для получения кэшированных данных используйте функцию get().

29


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Использование тестов производительности Выше мы свами затронули много проблем и моментов касающихся производительности. Теперь мы прибавляем мяса и костей, и смотрим на то, как проверять и тестировать производительность вашего кода, и как получить информацию относительно того, что и как работает и настраивается. Если вы хотите получить наиболее реалистичные тесты производительности вебсервера, вам необходим инструмент, умеющий посылать разнообразные HTTP запросы. На Unix обычные инструментальные средства тестирования включают ab (сокращение от apachebench), который являются частью пакета Apache. И более нового flood (http://httpd.apache.org/test/flood). На Windows NT/2000 вы можете использовать Microsoft's free Web Application Stress Tool (http://webtool.rte.microsoft.com). Эти утилиты могут делать параллельные множественные HTTP запросы моделируя тем самым множество клиентов сети, и выдавать вам детальную статистику по завершению теста.

PHP Inside #15

Вы можете контролировать, каким образом ведет себя ваш сервер, поскольку тесты проводятся на основе Unix с использованием "vmstat1". Он печатает информацию о статусе вашего диска, виртуальной памяти, и загрузки процессора каждую секунду. Альтернативно вы можете использовать "top d 1" который дает вам полноэкранную индикацию всех процессов запущенных и сортированных по степени загрузки процессора каждую секунду. На Windows 2000 вы можете использовать Performance Monitor или Task Manager для просмотра статистики своей системы. Если вы хотите проверить специфический аспект вашего кода без необходимости использования HTTP запросов, вы можете написать тест с использованием функции microtime(), которая возвращает текущее время в микросекундах в виде строки. Следующая функции конвертирует это значение в число, подходящее для статистики: <?php function getmicrotime() { list($usec, $sec) = explode(" ",microtime()); return ((float)$usec + (float)$sec); } $time = getmicrotime(); # # Здесь тестируемый код # echo " Время прошло: " . getmicrotime() - $time . " секунд"; ?>

Альтернативно, вы можете использовать специальные инструменты для профелирования: APD (http://www.linuxjournal.com/article.php?sid=7213) или Xdebug (http://xdebug.derickrethans.nl/). Еще вы можете прочитать специальную статью на эту тему: http://phplens.com/phpeverywhere/node/view/52.

30


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Этапы тестирования производительности Далее, я привожу детали реального теста производительности, созданного для одного из клиентов. В данном случае, клиент хотел гарантированное время отклика 5 секунд для любой PHP страницы, которая не делала сложных SQL запросов. Конфигурация сервера: Apache 1.3.20, PHP 4.0.6 на Red Hat 7.2 Linux. Аппаратное обеспечение: два Pentium III 933 Mhz, 1Gb RAM. HTTP запросы будут обращаться к скрипту testmysql.php. Этот скрипт читает и обрабатывает примерно 20 записей из MySql базы данных, расположенной на другом сервере. Для простоты мы предполагаем, что вся графика грузится с другого сервера. Как инструмент для тестирования производительности мы использовали ab. Мы задали ab делать 1000 запросов (-n1000), используя 10 одновременных соединений (-c10). Вот результаты:

Server Software: Server Hostname: Server Port:

Apache/1.3.20 192.168.0.99 80

Document Path: Document Length:

/php/testmysql.php 25970 bytes

Concurrency Level: Time taken for tests: Complete requests: Failed requests: Total transferred: HTML transferred: Requests per second: Transfer rate:

10 128.672 seconds 1000 0 26382000 bytes 25970000 bytes 7.77 205.03 kb/s received

Connnection Times (ms) min avg Connect: 0 9 Processing: 698 1274 Total: 698 1283

PHP Inside #15

# ab -n1000 -c10 http://192.168.0.99/php/testmysql.php This is ApacheBench, Version 1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/

max 114 2071 2185

После запуска теста производительности, он начал контролировать на стороне сервера использование ресурсов с использованием команды "top d 1". Параметр "d 1" указывает, что необходимо делать задержку в 1 секунду перед обновлением данных. Вывод показан ниже. 10:58pm up 3:36, 2 users, load average: 9.07, 3.29, 1.79 74 processes: 63 sleeping, 11 running, 0 zombie, 0 stopped CPU0 states: 92.0% user, 7.0% system, 0.0% nice, 0.0% idle CPU1 states: 95.0% user, 4.0% system, 0.0% nice, 0.0% idle Mem: 1028484K av, 230324K used, 798160K free, 64K shrd, Swap: 2040244K av, 0K used, 2040244K free PID 1142 1154 1155 1141 1174 1178 1157

USER apache apache apache apache apache apache apache

PRI 20 17 20 15 14 13 15

NI 0 0 0 0 0 0 0

SIZE 7280 8044 8052 6764 6848 6864 7536

RSS SHARE STAT 7280 3780 R 8044 3788 S 8052 3796 R 6764 3780 S 6848 3788 S 6864 3804 S 7536 3788 R

%CPU %MEM 21.2 0.7 19.3 0.7 19.3 0.7 14.7 0.6 12.9 0.6 12.9 0.6 11.0 0.7

TIME 0:20 0:20 0:20 0:20 0:20 0:19 0:19

27196K buff 30360K cached

COMMAND httpd httpd httpd httpd httpd httpd httpd

31


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP 1159 1148 1158 1163 1169 1176 1171 1170 1168 1377 1152 1167 1 2

apache apache apache apache apache apache apache apache apache natsoft apache apache root root

15 11 14 20 12 16 15 16 10 11 9 9 8 9

0 0 0 0 0 0 0 0 0 0 0 0 0 0

7540 6672 7400 7540 6856 8052 7984 7204 6856 1104 6752 6848 520 0

7540 6672 7400 7540 6856 8052 7984 7204 6856 1104 6752 6848 520 0

3788 3784 3788 3788 3796 3796 3780 3796 3796 856 3788 3788 452 0

R S R R S R S R S R S S S SW

11.0 10.1 10.1 10.1 10.1 10.1 9.2 6.4 4.6 2.7 1.8 0.9 0.0 0.0

0.7 0.6 0.7 0.7 0.6 0.7 0.7 0.7 0.6 0.1 0.6 0.6 0.0 0.0

0:19 0:20 0:19 0:19 0:20 0:19 0:18 0:20 0:20 0:02 0:20 0:19 0:04 0:00

httpd httpd httpd httpd httpd httpd httpd httpd httpd top httpd httpd init keventd

PHP Inside #15

Посмотрите на «шапку» вывода. Результаты показывают, что Apache, на машине с двумя процессорами, отработал с 0% простоя. Это очень плохо. Средняя загрузка составила 9.07 за последнюю минуту (3.29 за последние 5 минут, 1.79 за последние 15 минут). Средняя загрузка – это среднее число процессов, готовых быть запущенными. Для двухпроцессорного сервера любая загрузка больше 2, означает, что система будет перегружена процессами. Здесь вы можете видеть тесную связь между загруженностью 9.07 и количеством запущенных процессов (10), которые были определены в тесте ab. К счастью, мы располагаем большим объемом свободной оперативной памяти, приблизительно 798 160 Мб, никакой виртуальной памяти не используется. Далее, внизу, мы можем видет процессы, упорядоченные по количеству использования центрального процессора. Самые активные – это процессы Apache (httpd). Первая задача httpd использует 7280 Кб памяти и отнимет в среднем 21.2% процессора, и 0.7% оперативной памяти. Колонка STAT показывает статус: R – работает, S – бездействует, W – означает, что процесс выгружен из памяти. Вышеприведенные цифры показывают нам типичную пиковую нагрузку, мы можем сделать некоторое планирование. Если среднее число загрузки для сервера с двумя процессорами 9.0, и задача отнимает для исполнения примерно одно и тоже время, то слегка загруженный сервер должен быть 9.0/2 процессора = в 4.5 раз более быстрым. Так что HTTP запрос, который обыкновенно занимал 1.283 секунды, при пиковой нагрузке займет примерно 1.283/4.5 = 0.285 секунд. Для проверки этого, мы делаем тест производительности с 2 одновременными процессами (вместо 10 выше). Получаем 0.281 секунды, что очень близко к предсказанному значению 0.285! # ab

-n100 -c2 http://192.168.0.99/php/testmysql.php

[ some lines omitted for brevity ] Requests per second: Transfer rate: Connnection Times (ms) min avg Connect: 0 2 Processing: 255 279 Total: 255 281

7.10 187.37 kb/s received max 40 292 332

Наоборот, удваивая количество подключений, мы можем предсказать, что среднее время выполнения должно удвоиться с 1.283 до 2.566 секунд. В тестах производительности мы, фактически, получили 2.570 секунд.

32


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Перегрузка при 40 подключениях После того, как мы запустили тест производительности с 40 запросами, сервер был перегружен с 35% неудачных запросов. При дальнейшем расследовании было обнаружено, что MySql сервер отказывал в запросах с ошибкой «Слишком много подключений». Тест производительности также указал на поведение дочерних процессов Apache. Каждый скрипт PHP использовал 2 постоянных соединения, так, на 40 запросах мы имели 80 постоянных подключений, что значительно ниже значения по умолчанию MySql (max_connections 100). Однако, дочерние процессы Apache, которым не переданы немедленно новые запросы, всеравно удерживают постоянное соединение. Эти неактивные дочерние процессы породили еще более 20 постоянных соединений, которые оказались «соломкой, которая сломала спину верблюду».

Исправляем ситуацию

PHP Inside #15

Переведя скрипты на непостоянные соединения, мы устранили эту проблему и получили результат 5.340 секунд. Альтернативное решение состояло в том, чтобы увеличить MySql max_connections выше, чем значение по умолчанию.

Заключение Вышеупомянутое исследование в очередной раз показывает нам, что оптимизация вашей работы является чрезвычайно сложной. Это требует понимания множества программных систем, включая маршрутизацию сети, стек TCP/IP, количество физической и виртуальной памяти, количество процессоров, поведение дочерних процессов Apache, ваших скриптов PHP и конфигурации базы данных. В данном случае, код PHP был очень хорошо отлажен и самым узким местом оказался центральный процессор, который вызывал замедление в момент ответа. Поскольку нагрузка возросла, система значительно замедлилась, но находилась у требуемого порога (что является хорошим показателем), пока мы не столкнулись с более серьезным узки местом – недостаточным количеством возможных подключений к MySql. Это вызвало многократные ошибки наших скриптов, пока мы не устранили их переходом на непостоянные соединения. Из вышеприведенных значений, мы можем вычислить какое количество соединений мы можем обработать не выходя за пределы желаемого времени ответа. Предполагая наличе двусторонней сети с временем доступа 0.5 секунд на Internet (0.25 секунд одна сторона), мы можем предсказать. Поскольку наш клиент хотел время ответа 5 секунд, сервер сможет обрабатывать до 34 одновременных подключений в секунду. Это дает на пиковой нагрузке 34/5 = 6.8 страниц в секунду.

33


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Для получения максимального количества страниц для просмотра в день, мы должны умножить пиковую способность в секунду на 50.000 (эта методика предложена вебмастерами pair.com, большой хостинговой компанией), что даст нам 340 000 страниц в день.

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

PHP Inside #15

Большинство PHP сценариев просты. Они получают небольшое количество информации о сессии, загружают некоторое количество информации из системы управления контентом или базы данных, форматируют соответствующий HTML и отдают результат своей работы HTTP клиенту. Предположим, что типичный PHP сценарий исполняется 0.1 секунду, время ожидания Internet – 0.2 секунды, только 33% времени из этих 0.3 секунд будут использоваться для генерации PHP сценарием ответа. Так, если вы улучшите скорость своего скрипта на 20%, клиент будет видеть, что время ответа сократилось до 0.28 секунд, что является незначительным усовершенствованием. Конечно сервер сможет обработать на 20% больше запросов к одной и той же странице, что увеличивает масштабируемость. Вышеприведенный пример вовсе не означает, что мы должны опустить руки и все бросить. Это означает, что мы не должны чувствовать гордость после отвоевания очередного 1% скорости в своих скриптах. Мы должны тратить свое время на оптимизацию заслуживающих внимание областей нашего кода, чтобы получить более высокую отдачу.

Высокие степени оптимизации Места, где высокая степень оптимизации достижима, находятся внутри циклов while и for, где каждое замедление кода увеличивается в несколько раз из-за их повторения. Лучший способ для понимания этого, это рассмотреть несколько примеров: Пример 1 Вот вам один из простых примеров, печатающих массив: for ($j = 0;$j < sizeof($arr);$j++) echo $arr[$j] . '<br>'; Этот код может быть существенно ускорен, если переписать его следующим образом: for ($j=0, $max = sizeof($arr), $s = '';$j < $max;$j++) $s .= $arr[$j] . '<br>'; echo $s;

Для начала необходимо понять, что выражение $j < sizeof($arr) будет вычисляться каждый раз, пока цикл будет выполнятся. Поскольку результат этого выражения всегда постоянен, мы переносим его в $max. Если говорить техническим языком, то это называется оптимизацией инварианта цикла. Вторая проблема заключается в том, что в PHP 4 многократный вывод на экран командой echo работает гораздо медленнее, нежели сохранения всех данных в строке и однократный вывод результата на экран. Это связано с тем, что echo дорогая операция, которая может повлечь за собой посылку пакетов TCP/IP HTTP клиенту. Конечно, накопление данных в строке $s имеет некоторые проблемы масштабируемости, поскольку расходует больше памяти. 34


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Дополнительный способ ускорить вышеприведенный код – это использование буферизации вывода. Это позволит накапливать информацию внутренне и потом вывести ее целиком на экран в конце выполнения скрипта. Это существенно уменьшит нагрузку на сеть за счет использования большего количества памяти и увеличения времени ожидания. В части моего кода, состоящего полностью из команд echo, улучшение работы достигло 15%. ob_start(); for ($j=0, $max = sizeof($arr), $s = '';$j < $max;$j++) echo $arr[$j] . '<br>';

PHP Inside #15

Обратите внимание, на то, что буферизация при помощи функции ob_start() может использоваться как глобальная оптимизация для всех ваших скриптов. В долго выполняющихся сценариях вы, возможно, захотите периодически выводить содержимое буфера, чтобы иметь определенную обратную связь с HTTP клиентом. Это может быть сделано при помощи функции ob_end_flush(). Эта функция также выключает буферизацию вывода, так что вам необходимо будет вызвать функцию ob_start() для ее возобновления. Резюме: этот пример показал нам, как оптимизировать варианты циклов и как использовать буферизацию вывода для ускорения вашего кода. Пример 2 В следующем примере мы циклом проходим по PEAR DB recordset'у, используя специальную форматирующую функцию для форматирования результата, а затем выводим его командой echo. На сей раз я протестировал производительность, время выполнения составило 10.2 микросекунды (я не учитывал время подключения к базе и исполнение SQL запроса): function FormatRow(&$recordSet) { $arr = $recordSet->fetchRow(); return '<storng>' . $arr[0] . '</storng><em>' . $arr[1] . '</em>'; } for ($j = 0;$j < $rs->numRows();$j++) { print FormatRow($rs); }

Из первого примера мы с вами узнали, каким образом можно оптимизировать цикл. Изменим код следующим образом (получим 8.7 микросекунд): function FormatRow(&$recordSet) { $arr = $recordSet->fetchRow(); return '<strong>' . $arr[0] . '</strong><em>' . $arr[1] . '</em>'; } ob_start(); for ($j = 0, $max = $rs->numRows();$j < $max;$j++) { print FormatRow($rs); }

Мои тесты производительности показали, что использование переменной $max сэкономило 0.5 микросекунды, а ob_start() - 1.0 микросекунду. В общей сложности – 1.5 микросекунды.

35


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Однако, изменяя алгоритм цикла мы можем упростить и ускорить код. В нашем случае, мы увеличили скорость выполнения до 8.5 микросекунд: function FormatRow($arr) { return '<strong>' . $arr[0] . '</strong><em>' . $arr[1] . '</em>'; } ob_start(); while ($arr = $rs->fetchRow()) { print FormatRow($arr); }

Однако, в данном случае возможна еще одна оптимизация. Мы можем убрать функцию форматирования (потенциально жертвуя удобством эксплуатации ради скорости), чтобы сэкономить еще 0.1 микросекунду (в результате получим 8.4 микросекунды):

PHP Inside #15

ob_start(); while ($arr = $rs->fetchRow()) { print '<strong>' . $arr[0] . '</strong><em>' . $arr[1] . '</em>'; }

Переключаясь на использование PEAR Cache, время выполнения повысилось до 3.5 микросекунд для кэшированных данных: require_once("Cache/Output.php"); ob_start(); $cache = new Cache_Output("file", array("cache_dir" => "cache/")); $t = getmicrotime(); if ($contents = $cache->start(md5("this is a unique kexy!"))) { print "<p>Cache Hit</p>"; print $contents; } else { print "<p>Cache Miss</p>"; ## ## Code to connect and query database omitted ## while ($arr = $rs->fetchRow()) { print '<strong>' . $arr[0] . '</strong><em>' . $arr[1] . '</em>'; } }

print $cache->end(100);

print (getmicrotime()-$t);

Ниже я суммирую методы оптимизации: Время выполнения (микросекунды)

Описание

9,9 Первоначальный вариант без оптимизации, не учитываем время соединения с базой и выполнение SQL запроса.

36


9,2 Используем ob_start() 8,7 Оптимизируем цикл при помощи $max и ob_start() 8,5 Меняем тип цикла с for на while, парсим как массив в FormatRow() с использованием ob_start() 8,4 Удаляем FormatRow() и используем ob_start() 3,5 Используем PEAR Cache совместно с ob_start() Из вышеприведенных данных вы видите, что самая существенная оптимизация была достигнута не простым «щипанием» кода, а глобальной оптимизацией при помощи функции ob_start(), а также радикально отличающимся алгоритмом - кэшированием HTML.

ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Оптимизации объектно-ориентированной программы

Инициализируйте все переменные перед их использованием.

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

Пробуйте помещать все часто используемые функции в производные классы.

PHP Inside #15

В марте 2001 года я провел некоторые неофициальные тесты производительности классов на PHP 4.0.4 pl1. Дам несколько советов, исходящих из этих результатов. Три главных пункта:

Внимание: поскольку PHP постоянно совершенствуется, могли произойти усовершенствования в лучшую сторону.

Дополнительные детали •

Также я пришел к выводу, что вызов метода объекта (функция определена в классе) примерно в два раза медленнее, нежели обычный вызов функции. Что касается меня, то я считаю эту ситуацию приемлемой если сопоставлять с другими ООП языками.

Внутри метода (следующие отношения весьма приблизительны):

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

Увеличение значения глобальной переменной почти в два раза медленнее, чем увеличение локальной переменной.

Увеличение свойства объекта (например, $this->prop++) примерно в три раза медленнее чем локальная переменная.

Увеличение неопределенной локальной переменной примерно в 9-10 раз медленнее, чем предопределенной.

Только определение глобальной переменной без ее использования в функции также замедляет работу (примерно на тоже самое время, как и увеличение локальной переменной). PHP, вероятно, делает проверку на существование глобальной переменной.

Скорость обращения к методу не зависит от количества методов в классе, потому что я добавил еще более 10 методов в тестовый класс, что не привело к изменениям в скорости.

Методы в производных классах работаю быстрее, нежели определенные в базовом классе. 37


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP •

Функции с одним параметром вызова, а также с пустым телом занимают по времени столько же, сколько занимают 7-8 операций $localvar++. Вызов подобного метода занимает 15 $localvar++.

Дополнение от 11 июля 2004: эти испытания были проведены почти 3 года назад. Я проверил эти данные вновь на версии 4.3.3. Вызов функции теперь занимает 20 $localvar++, а вызов метода 30 $localvar++. Это может быть потому, что $localvar++ стало выполняться быстрее или вызов функция стал медленнее.

Резюме Чем больше вы разбираетесь в программном обеспечении, которое вы используете (Apache, PHP, IIS, база данных), и чем глубже ваши знания операционной системы, организации сети, аппаратного обеспечения сервера, тем лучше вы сможете выполнить глобальную оптимизацию вашего кода и вашей системы.

PHP Inside #15

Для PHP скриптов самое узкое место обычно – это центральный процессор. Два процессора, вероятно, будут лучше, чем два гигабайта оперативной памяти. Сборка PHP с параметром configure –enable-inline-optimization позволяет сделать максимально быстрый исполняемый файл. Оптимизируйте вашу базу данных и индексы, которые чаще всего используются в параметре WHERE ваших SQL запросов. ADODB – очень популярная библиотека абстрактного доступа – позволяет работать в режими оптимизации SQL запросов, где вы можете всесторонне изучить ваши неудачные SQL запросы, а также определить, в каком скрипте они выполняются. Используйте кэширование HTML, если ваши данные редко меняются. Даже если ваши данные меняются каждую минуту – кэширование может помочь, если данные синхронизировать с кэшем. В зависимости от сложности кода, кэширование позволяет улучшить скорость до 10 раз. Тестируйте производительность вашего сложного кода на ранних этапах (или по крайней мере его опытные образцы), таким образом вы получите чувство ожидаемых параметров работы, прежде чем будет слишком поздно. Попробуйте использовать реалистические количества испытательных данных, чтобы гарантировать должную масштабируемость. Рассмотрите возможности использования кэширования опкода. Это дает прирост производительности на 10-200% в зависимости от сложности вашего кода. Обязательно сделайте стресс тестирование вашего кода, прежде чем устанавливать оптимизаторы на реально работающий сервер, поскольку некоторые из них более надежны чем другие. Используйте ob_start() в начале вашего кода. Это даст вам повышение производительности на 5-15%. Вы также можете использовать gzip сжатие для организации быстрых загрузок (это требует дополнительных ресурсов центрального процессора). Рассмотрите возможность установки Zend Optimizer'а. Это бесплатное программное обеспечение делает некоторую оптимизацию, но будте внимательны – некоторые скрипты фактически замедляются, когда установлен Zend Optimizer. В основном, Zend Optimizer очень полезен, когда ваш код содержит множество циклов. Оптимизируйте код циклов. Переместите определения, по которым работает цикл перед циклом. Используйте массивы и строковые функции везде, где это возможно. Они работают значительно быстрее, чем написание аналогичного кода.

38


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Самый быстрый способ связать многократные небольшие строки в одну – это использовать буфер вывода (ob_start()) и печатать echo в буфер. В конце получить данные функцией ob_get_contents. Это работает, потомучто для буферизации выделяется первоначальный буфер в 40 кб, который растет кусками по 10 кб. Работая с массивами и объектами используйте ссылки где это возможно. Если это короткий скрипт, и обслуживание кода – это не проблема, вы можете использовать глобальные переменные для сохранения объектов и массивов. Если у вас много скриптов, использующих переменные сессии, рассмотрите возможность скомпилировать PHP для использования общедоступной памяти для сессий, или используйте RAM диск для их хранения. Включите эти возможности configure –withmm, затем перекомпилируйте PHP, а также установите session.save handler = mm в php.ini. Для поиска подстроки, используйте самую быструю команду strpos(), preg_match() и уж затем ereg(). Точно также str_replace() быстрее чем preg_replace(), которая, в свою очередь, быстрее, чем ereg_replace().

PHP Inside #15

Располагайте наиболее часто встречающиеся утверждения switch в самом верху. Если большинство случаев попадает под значение по умолчанию, определите его также в самом начале. Обработка XML данных регулярными выражениями работает значительно быстрее, чем использование SAX и DOM. Делайте unset() неиспользуемых более переменных, чтобы освободить память. Это главным образом полезно для ресурсов и больших массивов. Для классов с глубокой иерархией расширенные функции работают быстрее, чем определенные в основном классе (родительском). Рассмотрите возможность копирования часто используемых функций из основного класса в наследующий. Рассмотрите возможность написание вашего кода как расширение PHP или Java класс или COM объект, если вы нуждаетесь в сверхскорости. Будте осторожны при обмене данными между COM и Java.

Бесполезная оптимизация Некоторые виды оптимизации полезны. Другие – напрасная трата времени. Часто полезность усовершенствования пренебрежимо мала. Часто, внутренние изменения в PHP делают щипковые изменения кода устаревшими. Вот некоторые общие легенды: Echo быстрее чем print. Считается, что echo быстрее, так как не возвращает никакого значения, тогда как print возвращает. Из моих тестов производительности PHP 4.3 видно, что различие в них пренебрежительно малы. И в некоторых ситуациях print быстрее echo (когда ob_start включен). Удаление из кода комментариев ускоряет его выполнение. Если вы используете кэширование опкода, комментарии уже проигнорированы. Это миф, тянущийся со времен PHP 3, когда каждая строка скрипта интерпретировалась в момент ее выполнения. 'var=' . $var быстрее чем "var=$var". Это было справедливо для PHP 4.2 и более ранних версий. В PHP 4.3 это было устранено. Добавление от 22 июня 2004: очевидно, что в PHP 4.3 скорость была значительно увеличена, но различия устранены не полностью. Однако, я нахожу, что различия стали незначительными.

39


ТЕМА С ОБЛОЖКИ

HOWTO по оптимизации PHP

Ускоряют ли ссылки ваш код? Ссылки не обеспечивают никакого преимущества для работы со строками, целыми числами и другими базовыми типами данных. Например, рассмотрим следующий код: function TestRef(&$a) { $b = $a; $c = $a; } $one = 1; ProcessArrayRef($one);

И тот же самый код без ссылок:

PHP Inside #15

function TestNoRef($a) { $b = $a; $c = $a; } $one = 1; ProcessArrayNoRef($one);

PHP фактически не создает копии переменных, когда «обрабатывает значение», но использует вместо этого очень быструю ссылку, рассчитывая все внутри себя. Так в TestRef(), $b и $c будут устанавливаться дольше, так как ссылки должны отслеживаться, в то время как TestNoRef() $b и $c только указывают на первоначальное значение $a и PHP всего лишь увеличивает число ссылок. Поэтому TestNoRef() будет выполнена быстрее, чем TestRef(). Напротив, функции, которые принимают массивы и объекты в качестве параметров, имеют преимущества в работе, если использовать ссылки. Это происходит потому, что массивы и объекты не используют счетчик ссылок. Поэтому при использовании массивов и объектов без ссылок будет создано множество копий, когда они будут обрабатываться. Так следующий код: function ObjRef(&$o) { $a =$o->name; } быстрее, чем этот: $function ObjRef($o) { $a = $o->name; }

Замечание: в PHP 5 все объекты передаются по ссылке автоматически, без требования явного указания &. Объектная модель PHP 5 должна быть значительно быстрее.

40


ТЕМА С ОБЛОЖКИ

Логирование ошибок стандартными средствами PHP

Логирование ошибок стандартными средствами PHP Автор: Андрей Олищук

PHP Inside #15

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

Зачем это нужно? Логирование ошибок - очень важный метод их обработки, который позволяет сохранять информацию об ошибках для целей отладки, но при этом скрывать их от сторонних глаз. К примеру, если допустить ошибку в простейшем коде (пропущена открывающая кавычка): <?php echo hello"; ?>

то по умолчанию настроенный PHP выдаст на экран что-то вроде этого: Parse error: parse error, unexpected '"', expecting ',' or ';' in d:\programms\apache\Apache\htdocs\pro.php on line 2

Из информации об этой ошибке можно нехитро "выудить" абсолютный путь к корневой директории сайта: d:\programms\apache\Apache\htdocs\. Конечно, это не бог весть какой секрет, однако и сообщения об ошибках бывают куда более информативными. Очень опасен вывод ошибок, к примеру, при SQL-инъекциях в СУБД через вебсайт. В таких случаях злоумышленник сможет получать такую информацию как структура таблицы (имя таблицы и количество полей), имя пользователя и много другое, что поможет ему взломать плохо защищенную базу данных. Конечно, от этого следует защищаться прежде всего средствами самого языка, но при этом, отключение вывода ошибок на экран для публично работающего сайта является одним из средств защиты. Однако, простое отключение сообщений об ошибках не исправит сами ошибки. Они все равно будут возникать и их придется искать и править. Для эффективного поиска и правки конечно же будет необходим максиммум информации о произошедшем сбое и тут на помощь должны прийти сообщения об ошибках. Логирование как раз и позволяет скрывать всю информацию от посторонних глаз и при этом сохранять отладочную информацию. У логирования есть и другие полезные стороны. В большинстве случаев, в логфайл записывается не только описание ошибки и место ее возникновения, но и дата и время ее возникновения. Таким образом, лог-файл можно использовать еще и как журнал ошибок и вести по нему всю необходимую статистику.

41


ТЕМА С ОБЛОЖКИ

Логирование ошибок стандартными средствами PHP

PHP предоставляет такие возможности логирования как: настройка ведения логов в php.ini и использование функции error_log().

Настройка в php.ini В файле php.ini есть несколько директив, отвечающих за управление выводом сообщений об ошибках. Прежде всего, это директива error_reporting, в которой можно установить типы стандартных ошибок, при возникновении которых PHP будет «сигнализировать» на экран или в лог-файл. Подробнее о типах ошибок и соответсвующих им константах можно узнать из официальной документации по адресу: http://ru.php.net/manual/en/ref.errorfunc.php#errorfunc.constants. При отладке на рабочей машине рекомендуется включать все виды ошибок. Это делается установкой значения директивы error_reporting в E_ALL для PHP 4 и E_ALL & E_STRICT для PHP 5 (тип ошибок E_STRICT был введен в PHP 5, представляет собой больше рекомендации нежели ошибки и не входит в состав E_ALL).

PHP Inside #15

Далее, по необходимости, можно оставить включенным или отключить вывод сообщений на экран. За это отвечает директива display_errors, которая принимает значение 1, если вывод включен и 0, если отключен. Рекомендации по включению те же: для рабочей тестовой машины лучше оставить 1 (чтобы оперативно видеть все ошибки, возникающие при отладке), а для публичного сервера установить значение в 0, так как пользователям нет необходимости видеть лишнюю внутреннюю информацию. Логирование файлов никак не зависит от этой директивы и может использоваться как вместо вывода сообщений об ошибках на экран, так и вместе с ними. Теперь мы подошли непосредственно к управлению логированием. Чтобы PHP записывал ошибки в лог-файл нужно сделать две вещи: включить логирование и указать путь к лог-файлу на сервере. Все это делается выставлением значений для двух директив в php.ini: log_errors и error_log. log_errors Эта диретива указывает, должен ли PHP записывать информацию об ошибках в лог-файл. Соответственно, значение может быть либо on либо off. Как несложно догадаться, при значении on, запись логов ведется, а при off – нет. error_log Если директива log_errors «включена» (т.е. имеет значение on), то именно в директиве error_log PHP будет искать путь к лог-файлу. Данная директива принимает в качестве значения строку, определяющую путь к лог-файлу в файловой системе сервера. К примеру, в Linux это можно записать так: error_log = /home/logs/error_log

А для Windows следующим образом: error_log = "D:\Temp\phplog.txt"

При этом, лог-файл будет выглядеть примерно так: [01-Jan-2006 03:48:46] PHP Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in d:\programms\apache\Apache\htdocs\sud\sud\classes\class.mysql.php on line 29 [01-Jan-2006 03:48:48] PHP Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in d:\programms\apache\Apache\htdocs\sud\sud\classes\class.mysql.php on line 29 [01-Jan-2006 15:50:05] PHP Parse error: parse error, unexpected '"', expecting ',' or ';' in d:\programms\apache\Apache\htdocs\pro.php on line 2

42


ТЕМА С ОБЛОЖКИ

Логирование ошибок стандартными средствами PHP

Этот формат является стандартным и может быть отпарсен для ведения статистики в автоматическом режиме.

Использование функции error_log() Настройки в php.ini хороши и одновременно плохи тем, что влияют на все PHPскрипты, работающие на машине. Это значит, что если вам понадобится что-то изменить отдельно для конкретного скрипта, то придется использовать функцию ini_set(), которая не всегда бывает разрешена хостером.

PHP Inside #15

К тому же, в лог-файл иногда нужно записывать не только стандартные ошибки, такие как E_WARNING или E_ERROR, но и ошибки, присущие отдельным веб-приложениям. Допустим, в лог-файл необходимо записать сообщение об ошибке, говорящей, что товары на складе кончились - к примеру, если значение некоторого поля в SQL-выборке SELECT равно нулю. Если такая выборка пройдет, то для PHP-приложения не будет никакой ошибки – подключились к базе, передали запрос, получили результат выборки и все без ошибок. Для записи пользовательского лога используем пример: error_log("Произошла ошибка", 3, "D:/Temp/app_log.txt");

Первым параметром функции идет сообщение об ошибке, далее указывается способ отправки сообщения (3 - означает запись в конец лог-файла) и третим параметром идет путь к лог-файлу. Более подробную информацию по функции можно найти в официальной документации. Стоит отметить, что функцию error_log() не следует путать с директивой error_log из php.ini. Однако, функция error_log() автоматически не вставляет время возникновения ошибки и символы переноса строки, если второй параметр принимает значение 3. Поэтому, эти данные будет необходимо организовывать самостоятельно и указывать их в тексте сообщения об ошибке. В случае, когда необходимо вести не отдельный лог-файл PHP-приложения, а писать ошибки в стандартный лог (установленный в директиве error_log файла php.ini), то можно заменить способ отправки сообщения (второй параметр функции error_log()), указав вместо значения 3, значение 0. Следующий код напишет сообщение об ошибке в стандартный лог, при этом автоматически подставив время и перевод строки в конце. error_log("Произошла ошибка",0);

Так как error_log() является функцией, ее можно вызывать в любом месте кода. Это может быть полезно для установки режимов «режим отладки» и «режим работы» для ваших PHP-приложений прямо в PHP-коде приложения. К примеру, Илья Альшанетский (Ilia Alshanetsky) приводит такой способ логирования ошибок в двух режимах (перевод текста и комментарии мои): <?php function sql_failure_handler($query, $error) { //Формируется строка ошибки которая состоит //из исходного SQL-запроса и //текста ошибки, возвращаемого MySQL $msg = htmlspecialchars(«Ошибка выполнения запроса: {$query}<br>Текст ошибки: {$error}»); //В любом случае пишется в лог error_log($msg,3,«/home/site/logs/sql_error_log»);

43


ТЕМА С ОБЛОЖКИ

Логирование ошибок стандартными средствами PHP //Если определена константа debug //к примеру, в конфигурационном файле приложения //то функция возвращает полную строку ошибки, к примеру, для вывода на экран if (defined('debug')) { return $msg; } //В любом случае возвращается нейтральная фраза //для «чужих» посетителей return «Запрашиваемая страница временно недоступна»; } //Попытка выполнить запрос к базе, в случае неудачи //которого, будет вызвана наша функция mysql_query($query) or die(sql_query_handler($query,mysql_error())); ?>

Данный пример демонстрирует, как можно управлять логированием динамически.

PHP Inside #15

Итог Как уже было сказано, тонкая настройка конфигурационного файла php.ini и использование функции error_log() позволяют укрепить систему безопасности и при этом фиксировать все происходящие ошибки. Однако не стоит забывать, что логирование ошибок это всего лишь средство получения и хранения отладочной информации и оно никоим образом не заменяет обработку ошибок в самих PHP-приложениях. Кроме того, в данном материале обработка ошибок была затронута частично – только по части логирования, но в PHP есть большее количество директив и функций по управлению выводом ошибок. Если вы хотите подробнее изучить эти возможности, то обратитесь к официальной документации и к файлу php.ini – в нем зачастую даются пояснения тех или иных директив.

44


ТЕМА С ОБЛОЖКИ

Один PHP хорошо, а два лучше

Один PHP хорошо, а два лучше Автор: Денис Баженов Как совмещать четвертую и пятую версию PHP на одной машине. Узнайте об одном из вариантов прямо сейас Зачем спорить? Можно все удачно совмещать! (Рекламный лозунг компании Zannussi)

PHP Inside #15

В последнее время идут жаркие дебаты о необходимости внедрения в массы PHP5. Некоторые поддерживают эту идею. Некоторым хватает тех возможностей, которые предоставляет «четверка». В этой статье я не собираюсь рассуждать о плюсах и минусах «братьев по разуму». Я попытаюсь предложить выход для людей, которые обладают собственными серверными площадками и которые хотят опробовать PHP5 «в бою», но при этом не могут отказаться от «четверки» в силу необходимости сопровождения и разработки приложений на ее платформе. Я опишу процесс установки PHP4 и PHP5 одновременно на один веб-сервер. Таким образом, вы сможете работать одновременно с двумя типами скриптов. Идея состоит в регистрации SAPI библиотек интерпретатора на разные расширения файлов.

Реализация Итак, начнем. Для реализации будут необходимы: • дистрибутивы PHP4 и PHP5; • рабочий веб-сервер; • любой бинарный редактор. Описание будет проводиться применительно к платформе Windows + Apache/2.0. Процесс интеграции мало, чем отличается для разных операционных систем или разных версий Apache. Разница лишь в разных именах библиотек SAPI, с которыми вам придется работать, а также еще в некоторых моментах, о которых я скажу позже. Данный подход будет работать лишь в тех случаях, когда PHP работает как модуль Apache или, как еще говорят, SAPI библиотека. Просьба не путать SAPI с ISAPI. SAPI (Server API) – это термин принятый для обозначения API любого сервера (Apache, iPlanet и т.д.). ISAPI (Internet Server API) – это стандарт корпорации Microsoft на API их веб-сервера IIS. PHP работает на веб-сервере c помощью соответствующего SAPI расширения (php4apache.dll – PHP4 для Apache/1.3 php5apache2.dll – PHP5 для Apache/2.0). Регистрация SAPI библиотеки в веб-сервере осуществляется следующим образом. # Для PHP4 LoadModule php4_module F:/php4/sapi/php4apache2.dll # Эта строка только для линейки 1.3 AddModule mod_php4.c AddType application/x-httpd-php .php

45


Библиотеки php4apache2.dll и php5apache2.dll используют один и тот же строковый идентификатор (application/x-httpd-php) для определения зависимости между расширением обрабатываемого файла и SAPI библиотекой обработчика. Именно это следует исправить для возможности совместной работы двух интерпретаторов. Все копии интерпретатора, установленные на веб-сервере (в нашем случае их две) должны обладать уникальной идентифицирующей строкой типа. Я в качестве примера для второй копии PHP возьму идентификатор «application/x-httpd-ze2». Вы можете взять любой другой идентификатор. Длины исходной и замещаемой строк типа в бинарных файлах должны быть равны, для сохранения общей длины файла! Идентификатор типа зашит в библиотеках SAPI для конкретных веб-серверов. Править необходимо только библиотеку для вашего конкретного сервера. Полный список SAPI библиотек и веб-серверов, для которых они предназначены, вы можете найти в руководстве по установке интерпретатора, которое поставляется вместе с дистрибутивом продукта, а также на сайте разработчика http://www.php.net/. Предположим, что «четверка» будет основной используемой версией интерпретатора. Значит, ее SAPI модуль можно загружать в веб-сервер. # Загружаем SAPI библиотеку # Для Apache/2.0 LoadModule php4_module F:/php4/sapi/php4apache2.dll # Для Apache/1.3 LoadModule php4_module F:/php4/sapi/php4apache.dll # Регистрируем SAPI библиотеку на обработку файлов *.php AddType application/x-httpd-php .php

Теперь надо загрузить «пятерку» так, что бы веб-сервер мог отличать ее от «четверки». Для этого надо изменить, используемый библиотекой, идентификатор типа. Для этого необходимо открыть библиотеку php5apache2.dll (php5apache.dll если вы используете Apache/1.3) в двоичном редакторе и заменить все вхождения строки «application/xhttpd-php» на строку «application/x-httpd-ze2». Для библиотеки php5apache2.dll (PHP/5.1b1) таких вхождений два, со смещениями 0x000048EC и 0x0000490C. Для той же библиотеки из дистрибутива PHP/5.0.4 смещения равны 0x000048E8 и 0x00004908 соответственно. После этого можно загружать SAPI модуль «пятерки» в Apache, используя подставной идентификатор «application/x-httpd-ze2». # Для Apache/2.0 LoadModule php5_module F:/php5/sapi/php5apache2.dll # Для Apache/1.3 LoadModule php5_module F:/php5/sapi/php5apache.dll AddType application/x-httpd-ze2 .php5

После перезапуска веб-сервера все файлы с расширением «*.php» будут обрабатываться «четверкой», а файлы «*.php5» «пятеркой».

ТЕМА С ОБЛОЖКИ

# Для PHP5 LoadModule php5_module F:/php5/php5apache2.dll # Эта строка только для линейки 1.3 AddModule mod_php5.c AddType application/x-httpd-php .php

PHP Inside #15

Один PHP хорошо, а два лучше


Конфигурации интерпретаторов должны различаться. Потому как они имеют разные интерфейсы и разные модули расширений. Поэтому в конфигурационный файл веб-сервера нужно добавить такую строчку. # Эта директива определяет путь, где находится # конфигурационный ini-файл PHP5 PHPIniDir F:/php5

Теперь php.ini от «четверки» должен лежать там, где всегда, а конфигурационный файл «пятерки» необходимо поместить в папку F:/php5. Теперь, конфигурации интерпретаторов можно менять независимо. К сожалению, директиву PHPIniDir нельзя использовать вместе с Apache/1.3 (Еще один повод перейти на серию 2.0). Если у вас Apache/1.3, то проблему можно решить с помощью бинарного редактора. Необходимо открыть библиотеку php5ts.dll и заменить все вхождения строк php.ini и php-%s.ini на что-нибудь отличное от имени конфигурационного файла PHP4. Я для примера возьму строки ze2.ini и ze2-%s.ini соответственно. php-%s.ini - это строка – аргумент, которая передается функции sprintf() для генерации альтернативного имени конфигурационного файла. В данном случае %s это имя используемого SAPI. Например, php-cgi.ini или php-apache.ini. Более подробно о назначении альтернативных файлов конфигурации вы можете узнать из руководства по установке интерпретатора. При замене строки php-%s.ini вы должны убедиться, что замещаемая строка, как и оригинал, содержит подстроку %s. Теперь конфигурационный файл «пятерки» должен лежать там же где и аналогичный файл его младшего брата, но он должен иметь имя ze2.ini, а не php.ini.

Настройка веб-сервера Совсем не обязательно переименовывать все скрипты PHP5 в «*.php5». Если в директории F:/htdocs/php5app находятся скрипты «пятерки», то достаточно в конфигурационный файл сервера добавить следующие строки. <Directory F:/htdocs/php5app> <Files "*.php"> ForceType application/x-httpd-ze2 </Files> </Directory>

Теперь все файлы в этой дирректории с расширением «*.php» сервер будет рассматривать как приложения PHP5, а не PHP4. В Apache/2.0 директива ForceType является частью модуля core (ядра веб-сервера), в то время как в линейке 1.3 эта директива находится в модуле mod_mime. Поэтому, если вы используете Apache/1.3, то необходимо что бы этот модуль загружен на сервере.

ТЕМА С ОБЛОЖКИ

Конфигурирование интерпретаторов

PHP Inside #15

Один PHP хорошо, а два лучше


Стабильность Относительно стабильности подобного решения я не могу сказать ничего определенного. На системах WinNT сервер Apache, обрабатывает все запросы разными потоками в пределах одного процесса. А это значит, что в одно адресное пространство этого процесса, оказываются загруженными библиотеки сразу нескольких интерпретаторов, что теоретически может приводить к самым непредсказуемым результатам. На системах *nix существует несколько моделей поведения веб-сервера, но ни одна из них не решает проблемы разделения адресного пространства. Гарантию стабильности, в подобных условиях, могут дать только программисты Zend/PHPTeam. Отмечу лишь, что моя тестовая платформа (Apache/2.0.52 + PHP/4.3.11 + PHP/5.1b1) вела себя не очень стабильно, хотя критических ошибок все же не было. Я склонен списывать это на «сырость» PHP/5.1b1.

ТЕМА С ОБЛОЖКИ

Один PHP хорошо, а два лучше

Возможно, стоит поставить «пятерку» без модификации. А «четверку» править бинарным редактором. Это будет правильнее, так как, скорее всего, «пятерку» вам придется обновлять чаще. Смысл процедуры, при этом, остается тот же. В какой-то мере, для меня, спор о пользе PHP5 и вреде PHP4 (или наоборот? :) отпал. Приложения, разбросанные по разным папкам, работают на разных интерпретаторах. Все определяет конфигурация веб-сервера. Это удобно для тестирования и разработки до тех пор, пока будут длиться «переходные процессы».

PHP Inside #15

Выводы


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.