<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Работа для  программистов &#187; PHP</title>
	<atom:link href="http://job-interview.ru/articles/post/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://job-interview.ru/articles</link>
	<description>вакансии, вопросы, статьи</description>
	<lastBuildDate>Thu, 29 Mar 2012 20:53:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Разработка в среде WEB: Java или PHP?</title>
		<link>http://job-interview.ru/articles/post/356</link>
		<comments>http://job-interview.ru/articles/post/356#comments</comments>
		<pubDate>Tue, 28 Feb 2012 18:31:26 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[ООП]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">/articles/?p=356</guid>
		<description><![CDATA[Вместо предисловия.
Я постараюсь максимально объективно сравнить два языка. В конечном итоге, выбор платформы, стиля и языка &#8211; не определяющий фактор успеха. Главное, чтобы руки разработчика не повторяли форму интеграла. Ведь язык лишь инструмент, а инструмент, как известно, продолжение рук. 

Начнем.


WEB развивается уже второй десяток лет. Время статичных HTML-страниц кануло в истории, на смену которому пришел [...]]]></description>
			<content:encoded><![CDATA[<h2>Вместо предисловия.</h2>
<p>Я постараюсь максимально объективно сравнить два языка. В конечном итоге, выбор платформы, стиля и языка &#8211; не определяющий фактор успеха. Главное, чтобы руки разработчика не повторяли форму <em>интеграла</em>. Ведь язык лишь инструмент, а инструмент, как известно, продолжение рук. </p>
<p><span id="more-356"></span></p>
<h2>Начнем.</h2>
<p><img border="0" align="left" style="padding: 0px 10px 10px;" src="/img/javaphp/javaphp.jpg"></p>
<p style="height: 110px;">
<strong>WEB</strong> развивается уже второй десяток лет. Время статичных <strong>HTML-страниц</strong> кануло в истории, на смену которому пришел абстрактный стандарт <em>WEB2</em>, главное требование которого &#8211; взаимодействие с пользователем. Спорить, правильно ли это, конечно, можно, только в таком случае появляется вполне резонный вопрос: зачем читать эту статью, если она о средствах создания подобных сервисов? </p>
<h2>Порог вхождения.</h2>
<p>Традиционно для сравнительного анализа языков в первую очередь используют удобство синтаксиса, скорость работы и возможности.</p>
<p>Такой подход логичен для выбора собственного. А вот с точки зрения работодателя, качества самого программиста значительно важнее.</p>
<p><strong>PHP</strong> считается простым языком. Это не удивительно: от открытия учебника до первого &#8220;HelloWorld-a&#8221; проходит не больше 5 минут. С одной стороны это хорошо. Но подводных камней не мало.</p>
<p><img border="0" align="left" src="/img/javaphp/helloworld.jpg" style="padding: 10px;"></p>
<p>Потратив неделю на изучение PHP, можно научиться базовым приемам ввода-вывода, примитивной <em>выборке из БД</em> и парочке других алгоритмов обработки информации. С усложнением задач появляется соблазн <em>изобретать &#8220;велосипеды&#8221;</em> и &#8220;костыли&#8221; на основе старых знаний, делая код нечитабельным, уничтожая возможность дальнейшей поддержки на корню.</p>
<p>Работа с таким &#8220;<em>кодером</em>&#8221; в команде, или еще хуже, поддержка проекта, написанного им, превращается в будни школьного учителя. Естественно, это утверждение относится не ко всем, но такая проблема существует.</p>
<p>Что касается <strong>Java</strong>, порог вхождения очень высокий. Вместо &#8220;<em>Установка LAMP под Ubuntu</em>&#8221; и &#8220;<em>Скачать самоучитель PHP</em>&#8220;, необходимо вникнуть в <strong>сервлеты</strong>, взаимодействие между ними, <strong>jsp</strong>, научиться работе с каким-нибудь <em>фреймворком</em>.</p>
<p>Плюс <strong>ООП</strong>, который в Java обязателен. Если проводить аналогию, начало работы сравнимо с <em>высшей математикой</em> в ВУЗ-е: всех неспособных отправить на службу родине.</p>
<p>Подобный подход к оценке языка не панацея. Достаточно много серьезных проектов, написанных на <strong>PHP</strong>. Более того, на данный момент в сфере <strong>WEB-разработок</strong> он доминирует.</p>
<h2>Синтаксис и код.</h2>
<p><img border="0" align="left" src="/img/javaphp/sourcecode.jpg" style="padding: 10px;"></p>
<p>Одна из обсуждаемых проблем <strong>Java</strong> &#8211; длиннейшие названия классов и стандартных методов. Чего только стоит &#8220;<em>System.out.println()</em>&#8221; оного вместо &#8220;<em>echo</em>&#8221; на PHP. Конечно, это легко решается &#8220;<em>import</em>-ом&#8221; в начале документа или выбором современной <em>IDE</em>, в которой достаточно написать первую букву метода или поля, как появится возможность выбора нужного из списка. Тем не менее, отрицать впечатляющий объем кода на Java &#8211;  предвзято.</p>
<p><strong>PHP</strong> тоже не идеален. Взять к примеру обязательный знак доллара перед переменной. Конечно, рациональное зерно различия между обозначениями переменных и методами(функциями) присутствует. Лично у меня это вызывает жуткую головную боль. В первую очередь от созерцания самого знака. Плюс, я так и не сумел привить у себя<br />
привычки ставить доллар перед каждой переменной. Слишком меркантильно, что-ли&#8230;</p>
<p>Что касается кода, я думаю мало кто станет спорить, что серьезный проект == серьезная <em>работа в команде</em>. А работа в команде требует годного, понятного кода, качественную <em>документацию</em>, и возможность эффективно распределить работу.</p>
<p>Здесь принудительное ООП Java и <strong>Javadoc</strong> для документации дают ощутимый прирост в копилке аргументов &#8220;За Java&#8221;.</p>
<p>В PHP эти возможности так же есть. Сравнительно недавно я узнал о аналогах Javadoc в PHP- <strong>phpdoc</strong>/<strong>PhpDocumentor</strong>.</p>
<p>С известных версий PHP поддерживает объектный подход(ООП). Правда он смешанный, и соблазн написать простую функцию без обертки очень большой.</p>
<h2>Техническая площадка.</h2>
<p><img border="0" align="left" src="/img/javaphp/servers.jpg" style="padding: 10px;"></p>
<p>С кодом мы разобрались. А вот что касается хостинга, Java в проигрыше. <strong>PHP-хостинг</strong> распространен и он дешевле.</p>
<p>Правда под вопросом, стоит ли экономить на хостинге, если проект серьезный? Тем не менее, то, что заменить техническую основу проекта на PHP проще &#8211; факт.</p>
<p>Другой вопрос, если проект используется в интрасети. Стоимость <strong>хостинга</strong> отпадает. И программирование на стороне клиента дает плюс в сторону Java. Интеграция <em>апплетов</em> на нем в сети интернет потерпела крах, так как для запуска они требуют имплементатор на локалхосте. Но когда клиенты доступны физически, проблем нет.</p>
<p>Единая платформа, без связки разных языков &#8211; очевидный плюс. </p>
<h2>Вместо заключения.</h2>
<p>Я постарался не затрагивать сравнения технических характеристик языков. Такой информации в интернете полно. Так же считаю, что качество разработки значительно важнее. Язык создан для человека, а не для процессора. Для второго есть ассемблер.</p>
<p>Претензий на объективность у меня нет. Я попытался, насколько успешно- не знаю. Буду рад аргументированной критике.</p>
<p>Под конец повторюсь: все в руках разработчика, язык лишь инструмент. Профессионал и пальцем болт закрутит.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/356/feed</wfw:commentRss>
		<slash:comments>513</slash:comments>
		</item>
		<item>
		<title>Ускоряем проект на Symfony через nginx+memcached</title>
		<link>http://job-interview.ru/articles/post/300</link>
		<comments>http://job-interview.ru/articles/post/300#comments</comments>
		<pubDate>Wed, 23 Feb 2011 15:11:09 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[фреймворки]]></category>

		<guid isPermaLink="false">/articles/?p=300</guid>
		<description><![CDATA[

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


Однако, плату за универсальность никто не отменял. И, хотя Symfony предоставляет обширные возможности для кэширования, оно не всегда спасает, особенно на нагруженных проектах и особенно на [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/img/symfony_speed_up.jpg" border="0"></p>
<p>
<strong>Symfony</strong> — популярный фреймворк, использующий <strong>язык PHP</strong>, для ускорения процесса разработки web-приложений. Благодаря гибкой и продуманной структуре классов Symfony, программировать под этот <strong>фреймворк</strong> становится одним удовольствием, это действительно очень удобно.
</p>
<p>
Однако, плату за универсальность никто не отменял. И, хотя Symfony предоставляет обширные возможности для <strong>кэширования</strong>, оно не всегда спасает, особенно на нагруженных проектах и особенно на страницах, которые состоят из часто меняющихся блоков.
</p>
<p>
В этой статье я постараюсь описать <strong>минусы кэширования</strong> в Symfony и приемы их обхода.
</p>
<p><span id="more-300"></span></p>
<p>
Представьте ситуацию, когда есть страница, на которой данные могут меняться только раз в 1-2 суток, тогда мы смело можем ее закэшировать на 24 часа. В Symfony это делается очень просто установкой параметров в файле cache.yml для модулей:</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">enabled: true
with_layout: true
lifetime: <span style="">86400</span></pre></div></div>

</p>
<p>
Это означает, что раз в 24 часа при заходе одного пользователя страница будет перестраиваться, т. е. выполнять запросы к базе данных, исполнять <strong>код PHP</strong>, еще какие-то действия, после этого результат будет записан в кэш и отдан клиенту. После этого все последующие 24 часа каждый пользователь будет получать эту страницу из кэша — никаких запросов к базе, минимальное исполнение только самого необходимого кода. Красота!
</p>
<p>
И вот в один прекрасный момент руководство решает добавить на эту страницу блок с последними <em>комментариями пользователей</em>. Все, счастливая жизнь закончилась, пришло время пораскинуть мозгами. Думаю, очень многие <em>веб-разработчики</em> сталкивались с подобной историей.
</p>
<p>
Проблема в том, что блок с последними комментариями может обновиться как через минуту, так и через 2-3 часа, поэтому кэшировать всю страницу мы не можем, т. к. не понятно какое время жизни выставлять для кэша. Вообще это типичный случай, когда следует применять <strong>блочное кэширование</strong>, т. е. делим страницу на блоки (или компоненты в Symfony), каждому блоку задаем свои параметры кэширования.
</p>
<p>
Но такой тип кэширования далек от идеала, т. к. в этом случае Symfony придется выполнить большую часть своего кода. Код исполняется, как обычно, просто перед выполнением каждого блока будет проверка на наличие блока в кэше и, если он там есть и время жизни не истекло, то вместо выполнения этого блока будет просто вставлен html-код из кэша.<br />
При таком блочном кэшировании будет исполняться код Symfony при каждом <em>http-запросе</em>, кроме того, будет как минимум один <em>запрос к базе данных</em>, если пользователь авторизован &#8211;  Symfony получает данные о пользователе из базы еще до подключения блоков.
</p>
<p>
Однако, есть другой способ применения кэширования для случая, описанного выше. Для этого нам понадобится (я также привожу описание установки нужного ПО, для тех, кому оно понадобится, все примеры я проверял у себя на <em>Linux SUSE 11.3</em>):
</p>
<ul>
<li>
<strong>Nginx</strong> в качестве web-сервера</p>
<p><a href="#" onclick="jQuery('blockquote#nginx_install').toggle(); return false;" >Как установить и настроить Nginx</a></p>
<blockquote style="display: none;" id="nginx_install">
<p>
Скачиваем дистрибутив:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># wget http://sysoev.ru/nginx/nginx-0.8.54.tar.gz</span></pre></div></div>

<p>
Распаковываем его:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># tar zxf nginx-0.8.54.tar.gz</span></pre></div></div>

<p>
Переходим в созданную папку:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd nginx-0.8.54</span></pre></div></div>

<p>
Собираем и устанавливаем nginx:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># ./configure &amp;&amp; make &amp;&amp; make install</span></pre></div></div>

<p>
Для удобства работы с nginx создадим файл:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># touch /etc/init.d/nginx</span></pre></div></div>

<p>
И положим в него следующее содержимое:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#! /bin/bash</span>
&nbsp;
<span style="color: #666666; font-style: italic;">### BEGIN INIT INFO</span>
<span style="color: #666666; font-style: italic;"># Provides:          nginx</span>
<span style="color: #666666; font-style: italic;"># Required-Start:    $remote_fs $syslog $named $network $time</span>
<span style="color: #666666; font-style: italic;"># Required-Stop:     $remote_fs $syslog $named $network</span>
<span style="color: #666666; font-style: italic;"># Default-Start:     3 5</span>
<span style="color: #666666; font-style: italic;"># Default-Stop:      0 1 2 4 6</span>
<span style="color: #666666; font-style: italic;"># Short-Description: Start nginx at boot time</span>
<span style="color: #666666; font-style: italic;"># Description:       Enable service provided by nginx.</span>
<span style="color: #666666; font-style: italic;">### END INIT INFO</span>
&nbsp;
<span style="color: #007800;">PATH</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>sbin:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin:<span style="color: #000000; font-weight: bold;">/</span>sbin:<span style="color: #000000; font-weight: bold;">/</span>bin:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>sbin:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>bin
<span style="color: #007800;">NAME</span>=nginx
<span style="color: #007800;">DESC</span>=nginx
<span style="color: #007800;">PIDFILE</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>logs<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$NAME</span>.pid
<span style="color: #007800;">DAEMON</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>sbin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$NAME</span>
<span style="color: #007800;">DAEMON_CONFIG</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf
&nbsp;
<span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #660033;">-x</span> <span style="color: #007800;">$DAEMON</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">0</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #660033;">-e</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">case</span> <span style="color: #ff0000;">&quot;$1&quot;</span> <span style="color: #000000; font-weight: bold;">in</span>
  start<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Starting <span style="color: #007800;">$DESC</span>: &quot;</span>
        <span style="color: #007800;">$DAEMON</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; started&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  stop<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Stopping <span style="color: #007800;">$DESC</span>: &quot;</span>
 <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
                <span style="color: #c20cb9; font-weight: bold;">kill</span> <span style="color: #660033;">-15</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #000000; font-weight: bold;">`</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; stopped&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  restart<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Restarting <span style="color: #007800;">$DESC</span>: &quot;</span>
 <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
                <span style="color: #c20cb9; font-weight: bold;">kill</span> <span style="color: #660033;">-15</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #000000; font-weight: bold;">`</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
        <span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: #000000;">1</span>
        <span style="color: #007800;">$DAEMON</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; restarted&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  reload<span style="color: #7a0874; font-weight: bold;">&#41;</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Reloading <span style="color: #007800;">$DESC</span>: &quot;</span>
 <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #c20cb9; font-weight: bold;">kill</span> <span style="color: #660033;">-HUP</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #000000; font-weight: bold;">`</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; reloaded&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  configtest<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #007800;">$DAEMON</span> <span style="color: #660033;">-t</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  <span style="color: #000000; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #007800;">N</span>=<span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$NAME</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: <span style="color: #007800;">$N</span> {start|stop|status|restart|reload|configtest}&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span>
        <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
<span style="color: #000000; font-weight: bold;">esac</span> 
&nbsp;
<span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">0</span></pre></div></div>

<p>
Стартуем nginx:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx start</span></pre></div></div>

<p>
Заходим на страницу http://localhost и видим:
</p>
<p>
«Welcome to nginx!»
</p>
<p><a href="#" onclick="jQuery('blockquote#nginx_install').toggle(); return false;" >свернуть</a></p>
</blockquote>
</li>
<li>
Фреймворк Symfony</p>
<p><a href="#" onclick="jQuery('blockquote#symfony_install').toggle(); return false;" >Как установить Symfony и настроить связку Nginx+Symfony</a></p>
<blockquote style="display: none;" id="symfony_install">
<p>
Заходим в папку, в которой будет находиться ваш проект Symfony. Далее выполняем команды:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># mkdir -p lib/vendor</span>
<span style="color: #666666; font-style: italic;"># cd lib/vendor/</span>
<span style="color: #666666; font-style: italic;"># wget http://www.symfony-project.org/get/symfony-1.4.8.tgz</span>
<span style="color: #666666; font-style: italic;"># tar zxpf symfony-1.4.8.tgz</span>
<span style="color: #666666; font-style: italic;"># mv symfony-1.4.8 symfony</span>
<span style="color: #666666; font-style: italic;"># cd ../../</span>
<span style="color: #666666; font-style: italic;"># php lib/vendor/symfony/data/bin/symfony generate:project PROJECT_NAME</span>
<span style="color: #666666; font-style: italic;"># php symfony generate:app frontend</span></pre></div></div>

<p>
Мы создали наш проект Symfony, теперь нужно настроить связку Nginx+Symfony. Находим файл conf/nginx.conf и заполняем его следующим:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">worker_processes  <span style="color: #000000;">1</span>;
&nbsp;
events <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    worker_connections  <span style="color: #000000;">1024</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
http <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    include       mime.types;
    default_type  application<span style="color: #000000; font-weight: bold;">/</span>octet-stream;
&nbsp;
    log_format  main  <span style="color: #ff0000;">'$remote_addr - $remote_user [$time_local] &quot;$request&quot; '</span>
                      <span style="color: #ff0000;">'$status $body_bytes_sent &quot;$http_referer&quot; '</span>
                      <span style="color: #ff0000;">'&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;'</span>;
&nbsp;
    access_log  logs<span style="color: #000000; font-weight: bold;">/</span>access.log  main;
    error_log  logs<span style="color: #000000; font-weight: bold;">/</span>error.log info;
&nbsp;
    sendfile        on;
    keepalive_timeout  <span style="color: #000000;">65</span>;
&nbsp;
    upstream fcgi_www <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	server 127.0.0.1:<span style="color: #000000;">9000</span>;
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
    server <span style="color: #7a0874; font-weight: bold;">&#123;</span>
        listen       <span style="color: #000000;">80</span>;
        server_name  localhost;
&nbsp;
        error_page   <span style="color: #000000;">500</span> <span style="color: #000000;">502</span> <span style="color: #000000;">503</span> <span style="color: #000000;">504</span>  <span style="color: #000000; font-weight: bold;">/</span>50x.html;
        location = <span style="color: #000000; font-weight: bold;">/</span>50x.html <span style="color: #7a0874; font-weight: bold;">&#123;</span>
            root   html;
        <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web</span>
&nbsp;
	location ~ <span style="color: #ff0000;">&quot;^(/css/|/images/|/js/|/uploads/)&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    expires 3d;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span>sf<span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>vendor<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>data<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/lib/vendor/symfony/data/web</span>
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    fastcgi_param REQUEST_URI            <span style="color: #007800;">$request_uri</span>;
	    fastcgi_param DOCUMENT_URI           <span style="color: #007800;">$document_uri</span>;
	    fastcgi_param DOCUMENT_ROOT          <span style="color: #007800;">$document_root</span>;
	    fastcgi_param GATEWAY_INTERFACE      CGI<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span>;
	    fastcgi_param SERVER_SOFTWARE        nginx<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$nginx_version</span>;
	    fastcgi_param REMOTE_ADDR            <span style="color: #007800;">$remote_addr</span>;
	    fastcgi_param REMOTE_PORT            <span style="color: #007800;">$remote_port</span>;
	    fastcgi_param SERVER_ADDR            <span style="color: #007800;">$server_addr</span>;
	    fastcgi_param SERVER_PORT            <span style="color: #007800;">$server_port</span>;
	    fastcgi_param SERVER_NAME            <span style="color: #007800;">$server_name</span>;
	    fastcgi_param SERVER_PROTOCOL        <span style="color: #007800;">$server_protocol</span>;
	    fastcgi_param CONTENT_TYPE           <span style="color: #007800;">$content_type</span>;
	    fastcgi_param CONTENT_LENGTH         <span style="color: #007800;">$content_length</span>;
	    fastcgi_param HTTP_ACCEPT_ENCODING   <span style="color: #c20cb9; font-weight: bold;">gzip</span>,deflate;
	    fastcgi_param QUERY_STRING           <span style="color: #007800;">$query_string</span>;
	    fastcgi_param REDIRECT_STATUS        <span style="color: #000000;">200</span>;
	    fastcgi_param REQUEST_METHOD         <span style="color: #007800;">$request_method</span>;
	    fastcgi_param SCRIPT_FILENAME        <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>index.php; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web/index.php</span>
	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;
&nbsp;
	    fastcgi_pass  fcgi_www;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>
Теперь осталось запустить <strong>PHP в режиме FastCGI</strong>:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php-cgi -a -b 127.0.0.1:9000 -c /etc/php5/fastcgi/php.ini</span></pre></div></div>

<p>
Если все правильно сделали, то по адресу http://localhost/ должна отобразиться страница примерно следующего содержания:
</p>
<p>
Symfony Project Created </p>
<p>Congratulations! You have successfully created your symfony project.
</p>
<p><a href="#" onclick="jQuery('blockquote#symfony_install').toggle(); return false;" >свернуть</a></p>
</blockquote>
</li>
<li>
<strong>Memcached</strong> и расширение для PHP</p>
<p><a href="#" onclick="jQuery('blockquote#memcached_install').toggle(); return false;" >Как установить memcached и расширение PHP к нему.</a></p>
<blockquote style="display: none;" id="memcached_install">
<p>
Устанавливаем memcached.
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz</span>
<span style="color: #666666; font-style: italic;"># tar zxf memcached-1.4.5.tar.gz</span>
<span style="color: #666666; font-style: italic;"># cd memcached-1.4.5/</span>
<span style="color: #666666; font-style: italic;"># ./configure</span></pre></div></div>

<p>
Если выскочит ошибка: <em>error: libevent is required.</em><br />
то устанавливаем libevent
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd ../</span>
<span style="color: #666666; font-style: italic;"># wget http://www.monkey.org/~provos/libevent-2.0.9-rc.tar.gz</span>
<span style="color: #666666; font-style: italic;"># tar zxf libevent-2.0.9-rc.tar.gz</span>
<span style="color: #666666; font-style: italic;"># cd libevent-2.0.9-rc/</span>
<span style="color: #666666; font-style: italic;"># ./configure</span>
<span style="color: #666666; font-style: italic;"># make &amp;&amp; make install</span></pre></div></div>

<p>
После этого продолжаем установку memcached:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd ../memcached-1.4.5/</span>
<span style="color: #666666; font-style: italic;"># ./configure</span>
<span style="color: #666666; font-style: italic;"># make &amp;&amp; make install</span></pre></div></div>

<p>
Устанавливаем расширение для PHP:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># pecl install memcache</span></pre></div></div>

<p>
После этого включаем расширение memcache.so в php.ini:
</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;"><span style="color: #000099;">extension</span><span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">memcache.so</span></pre></div></div>

<p>
Запускаем memcached:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/memcached start</span></pre></div></div>

<p><a href="#" onclick="jQuery('blockquote#memcached_install').toggle(); return false;" >свернуть</a></p>
</blockquote >
</li>
</ul>
<p>
Сейчас после открытия в браузере http://localhost мы видим страницу нашего проекта на Symfony.
</p>
<p>
Итак, у нас все есть для работы, начнем ускорять наш проект. За основу берется то, что Nginx умеет обращаться к memcached по ключу и отдавать значение, которое содержится по этому ключу, в качестве ответа web-сервера.
</p>
<p>
<strong>Memcached</strong> — это демон, который хранит данные в оперативной памяти, обращаться к этим данным мы можем по определенному ключу.
</p>
<p>
Воспользуемся всеми вышеописанными возможностями memcached и nginx. В качестве ключа в memcached мы будем использовать URL-адрес страниц нашего сайта, а в качестве содержимого HTML страницы. Теперь нам нужно настроить nginx так, чтобы он при наличии в memcached значения (html) по ключу (url страницы) отдавал его сразу же в ответе клиенту, в противном случае запрос должен передаваться к Symfony, который его обрабатывает, сохраняет в memcached и отдает ответ для клиента. Таким образом, если в данный момент страница не в кэше, то его добавит в кэш Symfony, и при следующем запросе к этой странице ответ будет получен еще на стороне nginx, не доходя даже до Symfony.
</p>
<p>
<img src="/img/nginx_memcached.png" border="0">
</p>
<p>
Итак, добавим в наш проект возможность записи ответа сервера в memcached. Для этого воспользуемся механизмом фильтров в Symfony. Создадим в директории lib нашего проекта поддиректорию cache, а в ней создадим файл sfHtmlCacheFilter.class.php. Содержимое этого файла будет следующее:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> sfHtmlCacheFilter <span style="color: #000000; font-weight: bold;">extends</span> sfFilter
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$multi_replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Метод вызывается после того, как страница полностью сформирована,
     * здесь содержимое страницы записывается в memcached, если она указана в конфиге html_cache.yml.
     *
     * @param &lt;Object&gt; $filterChain
     * @return &lt;NULL&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> execute <span style="color: #009900;">&#40;</span><span style="color: #000088;">$filterChain</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$filterChain</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResponse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// Если в наших конфигах прописано не использовать кэширование или мы находимся в debug-режиме, то прекращем выполнение.</span>
	<span style="color: #666666; font-style: italic;">// Здесь также проверяется код ответа - если он не равен 200, то прекращем выполнение.</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>
          <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_cache'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getGetParameters</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPostParameters</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">||</span>
          <span style="color: #009900;">&#40;</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_debug'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #339933;">!</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_no_script_name'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStatusCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
          <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000088;">$uri</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRouting</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCurrentInternalUri</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getHost</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// Получаем запрошенный URI - будущий ключ для memcached</span>
        <span style="color: #000088;">$webUri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getUri</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$uriCacheParams</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// Получаем из конфига страницы, которые подлежат кэшированию</span>
        <span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getConfig</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$uriParams</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$routing_uri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^(.*)\?.*$/i'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'$1'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #666666; font-style: italic;">// Сравниваем запрошенный URI с записями в конфиге</span>
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'#^'</span><span style="color: #339933;">.</span><span style="color: #000088;">$key</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'$#'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$webUri</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$uriCacheParams</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$uriParams</span><span style="color: #339933;">;</span>
                    <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
	    <span style="color: #666666; font-style: italic;">// Если запрошенная страница есть в конфиге, то прекращаем цикл</span>
            <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uriCacheParams</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000088;">$webUri</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span>_decodeUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$webUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$uriCacheParams</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStatusCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'200'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
	    <span style="color: #666666; font-style: italic;">// Записываем содержимое ответа в кэш</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">setUri</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">.</span><span style="color: #000088;">$webUri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uriCacheParams</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'lifetime'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Получить конфиг тэгов
     *
     * @return &lt;Array&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> getConfig<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$conf</span> <span style="color: #339933;">=</span> sfYaml<span style="color: #339933;">::</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_config_dir'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/html_cache.yml'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$conf</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Вызывается из методов save() моделей,
     * удаляет из кэша все страницы, зависящие от заданной модели
     *
     * @param &lt;Object&gt; $model - объект, для которого вызывается метод save в модели
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> deleteCache<span style="color: #009900;">&#40;</span><span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> sfContext<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$model_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getConfig</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$arUri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Получаем страницы из конфига по этой модели</span>
        <span style="color: #000088;">$arCacheParam</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$config</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$model_name</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getHost</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Обходим в цикле страницы, строим из них ключи для memcache</span>
        <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arCacheParam</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$uri</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$attr</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'attributes'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'attributes'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #990000;">settype</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'array'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$prop</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'get'</span><span style="color: #339933;">.</span><span style="color: #000088;">$prop</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
                <span style="color: #009933; font-style: italic;">/**
                 * method_exists не работает для Doctrine,
                 * но работает для Propel, is_callable всегда будет
                 * возвращать true для Doctrine, поэтому существование
                 * метода проверяется таким образом.
                 */</span>
                try <span style="color: #009900;">&#123;</span>
                        <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$model</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                catch <span style="color: #009900;">&#40;</span>Exception <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>
&nbsp;
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">is_string</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">strpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">' '</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span>_decodeUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    <span style="color: #009900;">&#125;</span>
                    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^pageLimit:(\d+)$/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$prop</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'pageLimit'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">range</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$pageLimit</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
            <span style="color: #000088;">$isCachable</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$beforeDeleteCache</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'beforeDeleteCache'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'beforeDeleteCache'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #990000;">settype</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$beforeDeleteCache</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'array'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$beforeDeleteCache</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$callback</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$isCachable</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$model</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
            <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$isCachable</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$uri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace_callback</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/\(.*\)/U'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'self'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'replace_attr_callback'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">replace_multi_attr</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #b1b100;">else</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$arUri</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">.</span><span style="color: #000088;">$uri</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Удаляем массив страниц из memcached</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">deleteUri</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Используется для парсинга конфига при удалении страницы из memcached
     *
     * @param &lt;Array&gt; $matches
     * @return &lt;String&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> replace_attr_callback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$expr</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$arKeys</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_keys</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$key</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$arKeys</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">!==</span> <span style="color: #0000ff;">'pageLimit'</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$expr</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$expr</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">else</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$expr</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'%MULTI_REPLACEMENT_'</span><span style="color: #339933;">.</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'%'</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$expr</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Используется для парсинга конфига при удалении страницы из memcached
     *
     * @param &lt;Array&gt; $attr
     * @param &lt;String&gt; $uri
     * @param &lt;Array&gt; $arUri
     * @param &lt;Integer&gt; $key
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> replace_multi_attr<span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span><span style="color: #000088;">$arUri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$ind</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">replace_multi_attr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #339933;">,</span>
                                <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'%MULTI_REPLACEMENT_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$key</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'%'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$i</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
                                <span style="color: #000088;">$arUri</span><span style="color: #339933;">,</span>
                                <span style="color: #000088;">$key</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$key</span> <span style="color: #339933;">==</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$arUri</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">.</span><span style="color: #000088;">$uri</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Возвращает объект для работы с memcached.
     *
     * @return &lt;Object&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> getMemcache<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$memcache</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Memcache<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$con</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$memcache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'127.0.0.1'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">11211</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$memcache</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Записываем содержимое страницы в memcached
     *
     * @param &lt;String&gt; $uri - ключ в memcached
     * @param &lt;String&gt; $data - значение в memcached
     * @param &lt;Integer&gt; $lifetime - время жизни кэша
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static  <span style="color: #000000; font-weight: bold;">function</span> setUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #339933;">,</span> <span style="color: #000088;">$lifetime</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$memcache</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getMemcache</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$memcache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$lifetime</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Удаляет страницу из memcached
     *
     * @param &lt;Array&gt; $arUri - массив ключей memcached,
     * которые следует удалить
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> deleteUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">settype</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'array'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$memcache</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getMemcache</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$memcache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Метод декодирует URI через rawurldecode,
     * но символ пробела оставляет в прежнем виде,
     * т.к. nginx его не декодирует в своей переменной $uri
     *
     * @param &lt;string&gt; $uri
     * @param &lt;boolean&gt; $decode
     * @return &lt;string&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> _decodeUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$decode</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$decode</span> ? <span style="color: #990000;">rawurldecode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #000088;">$encodedUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">' '</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'%20'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>
Пока нас будет интересовать только первый метод класса execute. Он вызывается после того, как закончено формирование страницы, в этом методе у нас есть возможность обратиться к содержимому страницы, еще до того, как она отправлена клиенту.
</p>
<p>
Все, что делается в методе execute — это получение текущего адреса страницы, проверка его в конфиге html_cache.yml и, если он там есть, записываем содержимое в memcached.
</p>
<p>
Теперь создадим сам конфиг html_cache.yml и положим его в папку config нашего проекта:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">Index:
  /: <span style="">&#123;</span> lifetime: <span style="">86400</span> <span style="">&#125;</span></pre></div></div>

</p>
<p>
Здесь мы задаем адрес запрошенной страницы («/» &#8211; запрос главной страницы сайта), в фигурных скобках перечислены параметры кэширования, мы указали время жизни кэша 86400 секунд, т. е. сутки. Параметр Index сейчас используется только лишь в качестве группировки адресов страниц, но здесь можно также указывать названия <strong>моделей Symfony</strong>, об этом будет рассказано ниже.
</p>
<p>
По части Symfony у нас почти все готово, осталось включить использование кэширования и активировать наш фильтр.
</p>
<p>
Чтобы включить кэширование для секции prod прописываем в файле apps/frontend/config/settings.yml (изменения выделены жирным шрифтом):
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
</pre>
</td>
<td class="code">
<pre class="ini" style="font-family:monospace;">prod:
  .settings:
    no_script_name:         true
    <b>cache:               true</b>
    logging_enabled:        true</pre>
</td>
</tr>
</table>
</div>
<p>А теперь активируем фильтр, добавляем в файл apps/frontend/config/filters.yml пару строчек:</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
</pre>
</td>
<td class="code">
<pre class="ini" style="font-family:monospace;">rendering: ~
security:  ~
&nbsp;
# insert your own filters here
&nbsp;
<b>htmlcache:
    class: sfHtmlCacheFilter</b>
&nbsp;
cache:     ~
execution: ~</pre>
</td>
</tr>
</table>
</div>
<p>
Тем самым мы активировали наш класс-фильтр.
</p>
<p>
Теперь сбрасываем <strong>кэш Symfony</strong>:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony cache:clear</span></pre></div></div>

</p>
<p>
И заходим на страницу http://localhost/ . Если все правильно сделали главная страница нашего сайта должна оказаться в memcached, проверяем:
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre>
</td>
<td class="code">
<pre class="html" style="font-family:monospace;"><b># telnet localhost 11211</b>
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
<b>get http://localhost/</b>
VALUE http://localhost/ 0 2026
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
&lt;head&gt;
&nbsp;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;

&lt;title&gt;&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;/css/main.css&quot; /&gt;

&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;/sf/sf_default/css/screen.css&quot; /&gt;
&nbsp;
&lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot; /&gt;

&nbsp;
&lt;!--[if lt IE 7.]&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;/sf/sf_default/css/ie.css&quot; /&gt;

&lt;![endif]--&gt;
&nbsp;
&lt;/head&gt;
&lt;body&gt;
&lt;div class=&quot;sfTContainer&quot;&gt;
  &lt;a href=&quot;http://www.symfony-project.org/&quot;&gt;&lt;img alt=&quot;symfony PHP Framework&quot; class=&quot;sfTLogo&quot; src=&quot;/sf/sf_default/images/sfTLogo.png&quot; height=&quot;39&quot; width=&quot;186&quot; /&gt;&lt;/a&gt;

&lt;div class=&quot;sfTMessageContainer sfTMessage&quot;&gt;
  &lt;img alt=&quot;ok&quot; class=&quot;sfTMessageIcon&quot; src=&quot;/sf/sf_default/images/icons/ok48.png&quot; height=&quot;48&quot; width=&quot;48&quot; /&gt;  &lt;div class=&quot;sfTMessageWrap&quot;&gt;

    &lt;h1&gt;Symfony Project Created&lt;/h1&gt;
    &lt;h5&gt;Congratulations! You have successfully created your symfony project.&lt;/h5&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;dl class=&quot;sfTMessageInfo&quot;&gt;

  &lt;dt&gt;Project setup successful&lt;/dt&gt;
  &lt;dd&gt;This project uses the symfony libraries. If you see no image in this page, you may need to configure your web server so that it gains access to the &lt;code&gt;symfony_data/web/sf/&lt;/code&gt; directory.&lt;/dd&gt;
&nbsp;
  &lt;dt&gt;This is a temporary page&lt;/dt&gt;

  &lt;dd&gt;This page is part of the symfony &lt;code&gt;default&lt;/code&gt; module. It will disappear as soon as you define a &lt;code&gt;homepage&lt;/code&gt; route in your &lt;code&gt;routing.yml&lt;/code&gt;.&lt;/dd&gt;

&nbsp;
  &lt;dt&gt;What's next&lt;/dt&gt;
  &lt;dd&gt;
    &lt;ul class=&quot;sfTIconList&quot;&gt;
      &lt;li class=&quot;sfTDatabaseMessage&quot;&gt;Create your data model&lt;/li&gt;

      &lt;li class=&quot;sfTColorMessage&quot;&gt;Customize the layout of the generated templates&lt;/li&gt;
      &lt;li class=&quot;sfTLinkMessage&quot;&gt;&lt;a href=&quot;http://www.symfony-project.org/doc&quot;&gt;Learn more from the online documentation&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

  &lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
&nbsp;
END
<b>quit</b>
Connection closed by foreign host.</pre>
</td>
</tr>
</table>
</div>
<p>
Отлично! Теперь наш проект может перед отдачей ответа клиенту записывать в memcached HTML страниц.
</p>
<p>
Ну а теперь осталось настроить nginx, чтобы он мог сам отвечать клиенту, если запрошенная страница присутствует в memcached.
</p>
<p>
Для этого нам надо добавить еще один <strong>upstream для memcached</strong> в конфиг nginx и задать правила для проксирования в него запросов. Вот каким должен получиться конфиг для Nginx (изменения выделены жирным шрифтом):
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
</pre>
</td>
<td class="code">
<pre class="bash" style="font-family:monospace;">worker_processes  <span style="color: #000000;">1</span>;
&nbsp;
&nbsp;
events <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    worker_connections  <span style="color: #000000;">1024</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
&nbsp;
http <span style="color: #7a0874; font-weight: bold;">&#123;</span>

    include       mime.types;
    default_type  application<span style="color: #000000; font-weight: bold;">/</span>octet-stream;
&nbsp;
    log_format  main  <span style="color: #ff0000;">'$remote_addr - $remote_user [$time_local] &quot;$request&quot; '</span>
                      <span style="color: #ff0000;">'$status $body_bytes_sent &quot;$http_referer&quot; '</span>

                      <span style="color: #ff0000;">'&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;'</span>;
&nbsp;
    access_log  logs<span style="color: #000000; font-weight: bold;">/</span>access.log  main;
    error_log  logs<span style="color: #000000; font-weight: bold;">/</span>error.log info;
&nbsp;
    sendfile        on;
    keepalive_timeout  <span style="color: #000000;">65</span>;

&nbsp;
    <b>upstream memcached_backend <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	server 127.0.0.1:<span style="color: #000000;">11211</span>;
    <span style="color: #7a0874; font-weight: bold;">&#125;</span></b>
&nbsp;
    upstream fcgi_www <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	server 127.0.0.1:<span style="color: #000000;">9000</span>;
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>

&nbsp;
    server <span style="color: #7a0874; font-weight: bold;">&#123;</span>
        listen       <span style="color: #000000;">80</span>;
        server_name  localhost;
&nbsp;
        error_page   <span style="color: #000000;">500</span> <span style="color: #000000;">502</span> <span style="color: #000000;">503</span> <span style="color: #000000;">504</span>  <span style="color: #000000; font-weight: bold;">/</span>50x.html;
        location = <span style="color: #000000; font-weight: bold;">/</span>50x.html <span style="color: #7a0874; font-weight: bold;">&#123;</span>

            root   html;
        <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web</span>
&nbsp;

	location ~ <span style="color: #ff0000;">&quot;^(/css/|/images/|/js/|/uploads/)&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    expires 3d;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span>sf<span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>vendor<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>data<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/lib/vendor/symfony/data/web</span>

	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    fastcgi_param REQUEST_URI            <span style="color: #007800;">$request_uri</span>;
	    fastcgi_param DOCUMENT_URI           <span style="color: #007800;">$document_uri</span>;
	    fastcgi_param DOCUMENT_ROOT          <span style="color: #007800;">$document_root</span>;
	    fastcgi_param GATEWAY_INTERFACE      CGI<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span>;
	    fastcgi_param SERVER_SOFTWARE        nginx<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$nginx_version</span>;
	    fastcgi_param REMOTE_ADDR            <span style="color: #007800;">$remote_addr</span>;
	    fastcgi_param REMOTE_PORT            <span style="color: #007800;">$remote_port</span>;
	    fastcgi_param SERVER_ADDR            <span style="color: #007800;">$server_addr</span>;
	    fastcgi_param SERVER_PORT            <span style="color: #007800;">$server_port</span>;
	    fastcgi_param SERVER_NAME            <span style="color: #007800;">$server_name</span>;
	    fastcgi_param SERVER_PROTOCOL        <span style="color: #007800;">$server_protocol</span>;
	    fastcgi_param CONTENT_TYPE           <span style="color: #007800;">$content_type</span>;
	    fastcgi_param CONTENT_LENGTH         <span style="color: #007800;">$content_length</span>;
	    fastcgi_param HTTP_ACCEPT_ENCODING   <span style="color: #c20cb9; font-weight: bold;">gzip</span>,deflate;
	    fastcgi_param QUERY_STRING           <span style="color: #007800;">$query_string</span>;
	    fastcgi_param REDIRECT_STATUS        <span style="color: #000000;">200</span>;
	    fastcgi_param REQUEST_METHOD         <span style="color: #007800;">$request_method</span>;
	    fastcgi_param SCRIPT_FILENAME        <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>index.php; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web/index.php</span>

	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;
&nbsp;
            <b><span style="color: #666666; font-style: italic;"># Если это POST-запрос, то передаем обработку сразу в Symfony</span>
	    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">$request_method</span> = POST<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>

		fastcgi_pass  fcgi_www;
		<span style="color: #7a0874; font-weight: bold;">break</span>;
	    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
           <span style="color: #666666; font-style: italic;"># Если на предыдущем шаге мы не вышли из location'а, то это GET-запрос.</span>
           <span style="color: #666666; font-style: italic;"># Устанавливаем ключ для memcached, по которому будем искать значение</span>
	    <span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">$memcached_key</span> <span style="color: #ff0000;">&quot;http://<span style="color: #007800;">$host</span><span style="color: #007800;">$uri</span>&quot;</span>;
           <span style="color: #666666; font-style: italic;"># Задаем upstream для memcached</span>

	    memcached_pass  memcached_backend;
&nbsp;
           <span style="color: #666666; font-style: italic;"># Устанавливаем тип содержимого, полученного от memcached, у нас хранится HTML</span>
	    default_type text<span style="color: #000000; font-weight: bold;">/</span>html;
           <span style="color: #666666; font-style: italic;"># Указываем nginx'у переходить в именованный location @symfony в случае отсутствия ключа </span>
           <span style="color: #666666; font-style: italic;"># в memcached или в случае возникновении ошибки при запросе к memcached</span>
	    proxy_intercept_errors  on;
	    error_page <span style="color: #000000;">404</span> <span style="color: #000000;">502</span> = <span style="color: #000000; font-weight: bold;">@</span>symfony;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>

&nbsp;
       <span style="color: #666666; font-style: italic;"># Здесь описан именованный location, куда nginx переходит в случае отсутствия ключа или                                          </span>
       <span style="color: #666666; font-style: italic;"># возникновении ошибки при обращении к memcached. Здесь просто перечислены параметры </span>
       <span style="color: #666666; font-style: italic;"># fastcgi так же, как было сделано выше.</span>
	location <span style="color: #000000; font-weight: bold;">@</span>symfony <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    fastcgi_param REQUEST_URI            <span style="color: #007800;">$request_uri</span>;
	    fastcgi_param DOCUMENT_URI           <span style="color: #007800;">$document_uri</span>;
	    fastcgi_param DOCUMENT_ROOT          <span style="color: #007800;">$document_root</span>;
	    fastcgi_param GATEWAY_INTERFACE      CGI<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span>;
	    fastcgi_param SERVER_SOFTWARE        nginx<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$nginx_version</span>;
	    fastcgi_param REMOTE_ADDR            <span style="color: #007800;">$remote_addr</span>;
	    fastcgi_param REMOTE_PORT            <span style="color: #007800;">$remote_port</span>;
	    fastcgi_param SERVER_ADDR            <span style="color: #007800;">$server_addr</span>;
	    fastcgi_param SERVER_PORT            <span style="color: #007800;">$server_port</span>;
	    fastcgi_param SERVER_NAME            <span style="color: #007800;">$server_name</span>;
	    fastcgi_param SERVER_PROTOCOL        <span style="color: #007800;">$server_protocol</span>;
	    fastcgi_param CONTENT_TYPE           <span style="color: #007800;">$content_type</span>;
	    fastcgi_param CONTENT_LENGTH         <span style="color: #007800;">$content_length</span>;
	    fastcgi_param HTTP_ACCEPT_ENCODING   <span style="color: #c20cb9; font-weight: bold;">gzip</span>,deflate;
	    fastcgi_param QUERY_STRING           <span style="color: #007800;">$query_string</span>;
	    fastcgi_param REDIRECT_STATUS        <span style="color: #000000;">200</span>;
	    fastcgi_param REQUEST_METHOD         <span style="color: #007800;">$request_method</span>;
	    fastcgi_param SCRIPT_FILENAME        <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>index.php; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web/index.php</span>

	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;
	    fastcgi_pass  fcgi_www;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span></b>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
</td>
</tr>
</table>
</div>
<p>
Теперь проверяем нет ли ошибок в конфигах Nginx после внесения изменений:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx configtest</span>
the configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf syntax is ok
configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf <span style="color: #7a0874; font-weight: bold;">test</span> is successful</pre></div></div>

</p>
<p>
И говорим Nginx, чтобы он перечитал конфиг:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx reload</span>
Reloading nginx:  reloaded</pre></div></div>

</p>
<p>
Проверяем! Заходим на страницу http://localhost/ , она у нас уже должна лежать в memcached. Лично я в своем браузере Mozilla Firefox даже на примере такой простой странички вижу, что она стала загружаться гораздо быстрее!
</p>
<p>
Но не будем доверять всему тому, что видим. Проведем небольшой бенчмарк, в этом нам поможет утилита <strong>ab2</strong> — инструмент от разработчиков <strong>web-сервера Apache</strong>.
</p>
<p>
Сначала закомментируем наши <strong>настройки в Nginx</strong>, чтобы он перенаправлял все на Symfony.
</p>
<p>
Вносим следующие изменения в наш конфиг для Nginx, начиная с 71-й строки:
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
</pre>
</td>
<td class="code">
<pre class="bash" style="font-family:monospace;">	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;<b>
	    fastcgi_pass  fcgi_www;
&nbsp;
<span style="color: #666666; font-style: italic;">#	    if ($request_method = POST) {</span>

<span style="color: #666666; font-style: italic;">#		fastcgi_pass  fcgi_www;</span>
<span style="color: #666666; font-style: italic;">#		break;</span>
<span style="color: #666666; font-style: italic;">#	    }</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#	    set $memcached_key &quot;http://$host$uri&quot;;</span>
<span style="color: #666666; font-style: italic;">#	    memcached_pass  memcached_backend;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#	    default_type text/html;</span>
<span style="color: #666666; font-style: italic;">#	    proxy_intercept_errors  on;</span>

<span style="color: #666666; font-style: italic;">#	    error_page 404 502 = @symfony;</span></b>
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">@</span>symfony <span style="color: #7a0874; font-weight: bold;">&#123;</span></pre>
</td>
</tr>
</table>
</div>
</pre>
<p>
Затем стандартные команды:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx configtest</span>
the configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf syntax is ok
configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf <span style="color: #7a0874; font-weight: bold;">test</span> is successful
<span style="color: #666666; font-style: italic;"># /etc/init.d/nginx reload</span>
Reloading nginx:  reloaded</pre></div></div>

</p>
<p>
И запускаем утилиту от Apache,  отправим на наш сайт 1000 запросов, причем 10 будем выполнять параллельно:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># ab2 -n 1000 -c 10 http://127.0.0.1:80/</span>
This is ApacheBench, Version <span style="color: #000000;">2.3</span> <span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #007800;">$Revision</span>: <span style="color: #000000;">655654</span> $<span style="color: #000000; font-weight: bold;">&gt;</span>
Copyright <span style="color: #000000;">1996</span> Adam Twiss, Zeus Technology Ltd, http:<span style="color: #000000; font-weight: bold;">//</span>www.zeustech.net<span style="color: #000000; font-weight: bold;">/</span>
Licensed to The Apache Software Foundation, http:<span style="color: #000000; font-weight: bold;">//</span>www.apache.org<span style="color: #000000; font-weight: bold;">/</span>
&nbsp;
Benchmarking 127.0.0.1 <span style="color: #7a0874; font-weight: bold;">&#40;</span>be patient<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Completed <span style="color: #000000;">100</span> requests
Completed <span style="color: #000000;">200</span> requests
Completed <span style="color: #000000;">300</span> requests
Completed <span style="color: #000000;">400</span> requests
Completed <span style="color: #000000;">500</span> requests
Completed <span style="color: #000000;">600</span> requests
Completed <span style="color: #000000;">700</span> requests
Completed <span style="color: #000000;">800</span> requests
Completed <span style="color: #000000;">900</span> requests
Completed <span style="color: #000000;">1000</span> requests
Finished <span style="color: #000000;">1000</span> requests
&nbsp;
Server Software:        nginx<span style="color: #000000; font-weight: bold;">/</span>0.8.54
Server Hostname:        127.0.0.1
Server Port:            <span style="color: #000000;">80</span>
&nbsp;
Document Path:          <span style="color: #000000; font-weight: bold;">/</span>
Document Length:        <span style="color: #000000;">2026</span> bytes
&nbsp;
Concurrency Level:      <span style="color: #000000;">10</span>
Time taken <span style="color: #000000; font-weight: bold;">for</span> tests:   <span style="color: #000000;">26.412</span> seconds
Complete requests:      <span style="color: #000000;">1000</span>
Failed requests:        <span style="color: #000000;">646</span>
   <span style="color: #7a0874; font-weight: bold;">&#40;</span>Connect: <span style="color: #000000;">0</span>, Receive: <span style="color: #000000;">0</span>, Length: <span style="color: #000000;">646</span>, Exceptions: <span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
Write errors:           <span style="color: #000000;">0</span>
Non-2xx responses:      <span style="color: #000000;">646</span>
Total transferred:      <span style="color: #000000;">1142110</span> bytes
HTML transferred:       <span style="color: #000000;">964622</span> bytes
Requests per second:    <span style="color: #000000;">37.86</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #666666; font-style: italic;">#/sec] (mean)</span>
Time per request:       <span style="color: #000000;">264.116</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Time per request:       <span style="color: #000000;">26.412</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean, across all concurrent requests<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Transfer rate:          <span style="color: #000000;">42.23</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>Kbytes<span style="color: #000000; font-weight: bold;">/</span>sec<span style="color: #7a0874; font-weight: bold;">&#93;</span> received
&nbsp;
Connection Times <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
              min  mean<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #000000; font-weight: bold;">/</span>-sd<span style="color: #7a0874; font-weight: bold;">&#93;</span> median   max
Connect:        <span style="color: #000000;">0</span>    <span style="color: #000000;">0</span>   <span style="color: #000000;">0.1</span>      <span style="color: #000000;">0</span>       <span style="color: #000000;">1</span>
Processing:     <span style="color: #000000;">0</span>  <span style="color: #000000;">264</span> <span style="color: #000000;">349.9</span>      <span style="color: #000000;">3</span>     <span style="color: #000000;">827</span>
Waiting:        <span style="color: #000000;">0</span>  <span style="color: #000000;">264</span> <span style="color: #000000;">349.9</span>      <span style="color: #000000;">3</span>     <span style="color: #000000;">810</span>
Total:          <span style="color: #000000;">1</span>  <span style="color: #000000;">264</span> <span style="color: #000000;">349.9</span>      <span style="color: #000000;">3</span>     <span style="color: #000000;">827</span>
&nbsp;
Percentage of the requests served within a certain <span style="color: #000000; font-weight: bold;">time</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
  <span style="color: #000000;">50</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">3</span>
  <span style="color: #000000;">66</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">703</span>
  <span style="color: #000000;">75</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">713</span>
  <span style="color: #000000;">80</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">716</span>
  <span style="color: #000000;">90</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">748</span>
  <span style="color: #000000;">95</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">788</span>
  <span style="color: #000000;">98</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">790</span>
  <span style="color: #000000;">99</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">796</span>
 <span style="color: #000000;">100</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">827</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>longest request<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

</p>
<p>
У меня после таких тестов отваливался через некоторое время <strong>fastcgi</strong>. Во время выполнения ab2 попробуйте проверить загрузку страницы в браузере — можно наблюдать постепенное нарастание тормозов при загрузке страницы.
</p>
<p>
Итак, если вас настигла беда с fastcgi, как и у меня, то запускаем его снова:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">php-cgi <span style="color: #660033;">-a</span> <span style="color: #660033;">-b</span> 127.0.0.1:<span style="color: #000000;">9000</span> <span style="color: #660033;">-c</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>php5<span style="color: #000000; font-weight: bold;">/</span>fastcgi<span style="color: #000000; font-weight: bold;">/</span>php.ini</pre></div></div>

</p>
<p>
Далее убираем наши комментарии, сделанные перед запуском теста, релоадим nginx и запускаем ab2 с теми же параметрами:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx configtest</span>
the configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf syntax is ok
configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf <span style="color: #7a0874; font-weight: bold;">test</span> is successful
<span style="color: #666666; font-style: italic;"># /etc/init.d/nginx reload</span>
Reloading nginx:  reloaded
<span style="color: #666666; font-style: italic;"># ab2 -n 1000 -c 10 http://127.0.0.1:80/</span>
This is ApacheBench, Version <span style="color: #000000;">2.3</span> <span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #007800;">$Revision</span>: <span style="color: #000000;">655654</span> $<span style="color: #000000; font-weight: bold;">&gt;</span>
Copyright <span style="color: #000000;">1996</span> Adam Twiss, Zeus Technology Ltd, http:<span style="color: #000000; font-weight: bold;">//</span>www.zeustech.net<span style="color: #000000; font-weight: bold;">/</span>
Licensed to The Apache Software Foundation, http:<span style="color: #000000; font-weight: bold;">//</span>www.apache.org<span style="color: #000000; font-weight: bold;">/</span>
&nbsp;
Benchmarking 127.0.0.1 <span style="color: #7a0874; font-weight: bold;">&#40;</span>be patient<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Completed <span style="color: #000000;">100</span> requests
Completed <span style="color: #000000;">200</span> requests
Completed <span style="color: #000000;">300</span> requests
Completed <span style="color: #000000;">400</span> requests
Completed <span style="color: #000000;">500</span> requests
Completed <span style="color: #000000;">600</span> requests
Completed <span style="color: #000000;">700</span> requests
Completed <span style="color: #000000;">800</span> requests
Completed <span style="color: #000000;">900</span> requests
Completed <span style="color: #000000;">1000</span> requests
Finished <span style="color: #000000;">1000</span> requests
&nbsp;
Server Software:        nginx<span style="color: #000000; font-weight: bold;">/</span>0.8.54
Server Hostname:        127.0.0.1
Server Port:            <span style="color: #000000;">80</span>
&nbsp;
Document Path:          <span style="color: #000000; font-weight: bold;">/</span>
Document Length:        <span style="color: #000000;">2026</span> bytes
&nbsp;
Concurrency Level:      <span style="color: #000000;">10</span>
Time taken <span style="color: #000000; font-weight: bold;">for</span> tests:   <span style="color: #000000;">0.337</span> seconds
Complete requests:      <span style="color: #000000;">1000</span>
Failed requests:        <span style="color: #000000;">0</span>
Write errors:           <span style="color: #000000;">0</span>
Total transferred:      <span style="color: #000000;">2170000</span> bytes
HTML transferred:       <span style="color: #000000;">2026000</span> bytes
Requests per second:    <span style="color: #000000;">2971.65</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #666666; font-style: italic;">#/sec] (mean)</span>
Time per request:       <span style="color: #000000;">3.365</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Time per request:       <span style="color: #000000;">0.337</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean, across all concurrent requests<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Transfer rate:          <span style="color: #000000;">6297.35</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>Kbytes<span style="color: #000000; font-weight: bold;">/</span>sec<span style="color: #7a0874; font-weight: bold;">&#93;</span> received
&nbsp;
Connection Times <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
              min  mean<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #000000; font-weight: bold;">/</span>-sd<span style="color: #7a0874; font-weight: bold;">&#93;</span> median   max
Connect:        <span style="color: #000000;">0</span>    <span style="color: #000000;">0</span>   <span style="color: #000000;">0.4</span>      <span style="color: #000000;">0</span>       <span style="color: #000000;">3</span>
Processing:     <span style="color: #000000;">1</span>    <span style="color: #000000;">3</span>   <span style="color: #000000;">0.6</span>      <span style="color: #000000;">3</span>       <span style="color: #000000;">5</span>
Waiting:        <span style="color: #000000;">0</span>    <span style="color: #000000;">3</span>   <span style="color: #000000;">0.6</span>      <span style="color: #000000;">3</span>       <span style="color: #000000;">4</span>
Total:          <span style="color: #000000;">1</span>    <span style="color: #000000;">3</span>   <span style="color: #000000;">0.5</span>      <span style="color: #000000;">3</span>       <span style="color: #000000;">6</span>
&nbsp;
Percentage of the requests served within a certain <span style="color: #000000; font-weight: bold;">time</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
  <span style="color: #000000;">50</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">3</span>
  <span style="color: #000000;">66</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">3</span>
  <span style="color: #000000;">75</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">80</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">90</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">95</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">98</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">99</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
 <span style="color: #000000;">100</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">6</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>longest request<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

</p>
<p>
Тут даже говорить нечего, все сказано в первом и втором выводах ab2. Достаточно взглянуть хотя бы на параметр «Time taken for tests», который показывает общее время проведения тестов. В первом случае он равен  26.412 секунд, во втором - 0.337 секунд. Прирост производительности почти в 80 раз!
</p>
<p>
Конечно, тестирование на локальном компьютере — это не есть тестирование в условиях, приближенных к реальным, однако какое-то представление оно все же дает.
</p>
<p>
А теперь вернемся к примеру, который был описан в самом начале статьи. Есть страница с постоянным контентом и есть блок с последними комментариями.
</p>
<p>
Как кэширование, которое мы только что внедрили в Symfony, поможет нам с кэшированием такой страницы? Пока никак. Наш кэш живет только какое-то определенное время, указанное в параметре lifetime, поэтому блок с комментариями будет обновляться только, когда истечет время жизни кэша. Но нас это не устраивает, нужно, чтобы страница обновлялась каждый раз после того, как добавился комментарий. Хорошо бы после добавления комментария удалять из кэша страницу.
</p>
<p>
Зададимся вопросом: «В какой момент у нас обычно должен обновляться кэш?». Обычно в момент, когда что-то меняется в базе данных. При чем, если изменения производятся в таблице, где хранятся комментарии, то обновляться должны страницы, где выводятся блоки, связанные с комментариями.
</p>
<p>
Для начала подключим к нашему проекту на Symfony <strong>базу данных</strong>. Не имеет значения какую базу данных использовать. Если вы знакомы с Symfony, то без труда сможете подключить свою базу данных. В своих же примерах я использую <em>MySQL</em>, <em>пользователь root</em> с паролем secretpass, имя базы данных — symfony.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># mysqladmin -uroot -psecretpass create symfony</span>
<span style="color: #666666; font-style: italic;"># php symfony configure:database &quot;mysql:host=localhost;dbname=symfony&quot; root secretpass</span></pre></div></div>

</p>
<p>
Теперь опишем нашу будущую базу данных в Symfony, для этого отредактируем файл config/doctrine/schema.yml:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">Comment:
  columns:
    text: <span style="">&#123;</span> type: string<span style="">&#40;</span><span style="">255</span><span style="">&#41;</span>, notnull: true <span style="">&#125;</span></pre></div></div>

</p>
<p>
Далее воспользуемся готовыми инструментами Symfony и сгенерируем код для моделей, SQL для базы данных.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony doctrine:build --model</span>
<span style="color: #666666; font-style: italic;"># php symfony doctrine:build --sql</span>
<span style="color: #666666; font-style: italic;"># php symfony doctrine:insert-sql</span></pre></div></div>

</p>
<p>
Последняя команда выполняет SQL, чтобы создать необходимые <em>таблицы в базе данных</em>. Вместо этих трех команд можно было бы выполнить php symfony doctrine:build —all, которая выполняет те же 3 действия, но за один раз.
</p>
<p>
Теперь сгенерируем стандартную функциональность для добавления, удаления, редактирования и просмотра списка объектов модели:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony doctrine:generate-module --with-show --non-verbose-templates frontend comment Comment</span></pre></div></div>

</p>
<p>
Здесь мы говорим сгенерировать код для нового модуля comment, код генерируется для существующей модели Comment.
</p>
<p>
Далее необходимо переопределить метод save() для моделей, участвующих в кэшировании. У нас это одна модель Comment, поэтому открываем файл lib/model/doctrine/Comment.class.php и добавляем в класс Comment метод save():
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Comment <span style="color: #000000; font-weight: bold;">extends</span> BaseComment
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #009900;">&#40;</span>Doctrine_Connection <span style="color: #000088;">$conn</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        parent<span style="color: #339933;">::</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$conn</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        sfHtmlCacheFilter<span style="color: #339933;">::</span><span style="color: #004000;">deleteCache</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>
Мы добавили метод save(), который переопределяет метод save() класса <strong>Doctrine_Record</strong>. В нашем методе мы вызываем метод save() родительского класса, которым и окажется Doctrine_Record::save().
</p>
<p>
Далее вызывается метод нашего класса-фильтра sfHtmlCacheFilter::deleteCache($this), которому в качестве параметра передается сохраняемый объект. Таким образом, этот новый метод не делает ничего нового, кроме как добавляется метод для очистки кэша при каждом сохранении объекта.
</p>
<p>
Удаляем кэш Symfony, чтобы наши изменения вступили в силу.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony cache:clear</span></pre></div></div>

</p>
<p>
Все, теперь зайдем по адресу http://localhost/comment и увидим сгенерированную Symfony страницу. Нажимаем на ссылку «New», добавляем первую запись, возвращаемся назад к списку и видим только что добавленный комментарий.
</p>
<p>
Выше уже упоминалось, что в конфиге html_cache.yml можно прописывать зависимости страниц от моделей. Пришло время рассказать об этом подробнее.<br />
Настройки в файле html_cache.yml используется следующим образом.
</p>
<p>
Перед отдачей любой страницы клиенту проверяется наличие адреса этой страницы в конфиге. Если он есть, то происходит запись содержимого страницы в кэш.<br />
При сохранении модели вызывается метод класса-фильтра для удаления из кэша страниц, зависящих от текущей модели. Модели перечислены, как элементы первого уровня, на втором уровне перечислены зависящие от этих моделей адреса страниц.
</p>
<p>
Сейчас у нас в файле html_cache.yml на первом уровне прописана несуществующая модель Index, на втором уровне прописана главная страница. Т. к. модели Index у нас нет, то эта настройка просто говорит о том, что неоходимо записывать в кэш содержимое главной страницы, но никакого удаления ее из кэша не происходит.
</p>
<p>
Для такой главной страницы это и не нужно, т. к. там выводится всегда одна и та же информация. А вот со страницей списка комментариев ситуация иная — если для нее мы применяем кэширование, то необходимо удалять кэш этой страницы при каждом добавлении комментария.
</p>
<p>
Добавим такую настройку. Страница со списком комментариев располагается по адресу http://localhost/comment. Добавляем в файл config/html_cache.yml следующую запись:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">Comment:
  /comment: <span style="">&#123;</span> lifetime: <span style="">86400</span> <span style="">&#125;</span></pre></div></div>

</p>
<p>
Теперь наша страница  http://localhost/comment будет отдаваться клиенту еще на стороне nginx при наличии ее в кэше. В противном случае nginx передаст управление Symfony, который сформирует и запишет содержимое страницы в кэш.
</p>
<p>
Таким образом, мы организовали зависимость страниц от изменяющихся моделей — при изменении определенных моделей очищается кэш зависящих от этих моделей страниц.
</p>
<p>
В файле html_cache.yml можно использовать <strong>регулярные выражения</strong>, а также подставлять в адреса страниц результаты выполнения методов объектов. Применим кэширование к детальным страницам комментариев, которые располагаются по адресам вида - http://localhost/comment/show/id/1 .
</p>
<p>
Добавим к модели Comment следующую зависимость:
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
</pre>
</td>
<td class="code">
<pre class="ini" style="font-family:monospace;">Comment:
  /comment: <span style="">&#123;</span> lifetime: <span style="">86400</span> <span style="">&#125;</span><b>
  /comment/show/id/<span style="">&#40;</span>\d+<span style="">&#41;</span>: <span style="">&#123;</span> lifetime: <span style="">86400</span>, attributes: <span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>Id<span style="">&#93;</span></span> <span style="">&#125;</span></pre>
<p></b></p>
</td>
</tr>
</table>
</div>
<p>
Здесь мы указали в адресе регулярное выражение, которое пропускает только числовые значения ID комментариев. Мы также указали новый параметр attributes, который является массивом. В этом массиве объявляются методы модели, возвращаемые значения которых будут подставлены по порядку вместо регулярных выражений, заключенных в скобки. Причем методы могут возвращать не только обычные значения, но и массивы, в этом случае для удаления из кэша будет сформирован массив адресов страниц.
</p>
<p>
В данном примере вместо регулярного выражения (\d+) будет подставлен результат вызова метода getId() для объекта модели Comment. Это справедливо только при сохранении объекта и <strong>удалении кэша</strong> для него. При добавлении страницы в кэш будет произведено лишь сравнение текущего адреса страницы с регулярным выражением /comment/show/id/(\d+) и, если адрес пройдет проверку, то страница добавится в кэш.
</p>
<p>
После произведенных изменений в файле html_cache.yml страницы вида  http://localhost/comment/show/id/1 постигнет участь предыдущих рассматриваемых страниц — они будут писаться в кэш.
</p>
<p>
Помимо параметров lifetime и attributes можно использовать параметр beforeDeleteCache, в который передается название метода модели (полное название). Этот метод должен возвращать true или false. При получении false кэш для записи с этим параметром удаляться не будет.
</p>
<p>
На этом все. Теперь наш проект на Symfony стал не просто быстрым, а мегабыстрым. Ответы клиент получает не от php-скриптов на сервере и даже не с диска, а из памяти сервера.
</p>
<p>
Спасибо за внимание! Чтобы ваши сайты всегда летали!
</p>
<p></p>
<p><b>UPD:</b> Спасибо Sergei за <a href="#350">найденную ошибку</a>. Все описанное работало только с латинскими буквами в url'е, но не работало с русскими. Внесены нужные изменения в класс-фильтр для Symfony, а также в конфиге nginx в качестве ключа для memcached теперь используется переменная $uri, а не $request_uri</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/300/feed</wfw:commentRss>
		<slash:comments>561</slash:comments>
		</item>
		<item>
		<title>CMS Битрикс. За и против.</title>
		<link>http://job-interview.ru/articles/post/234</link>
		<comments>http://job-interview.ru/articles/post/234#comments</comments>
		<pubDate>Thu, 04 Feb 2010 21:45:56 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[bitrix]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[битрикс]]></category>

		<guid isPermaLink="false">/articles/?p=234</guid>
		<description><![CDATA[Проработав 2 года с CMS Битрикс, у меня сформировалось свое отношение к этому движку. Есть как плюсы, так и минусы, но все же негатива накопилось гораздо больше.
В этой статье я поделюсь своим мнением с читателями и постараюсь описать и хорошие, и плохие стороны этой CMS.
Во-первых, хочется сказать пару слов о тормозах этой системы. В этом [...]]]></description>
			<content:encoded><![CDATA[<p>Проработав 2 года с <strong>CMS Битрикс</strong>, у меня сформировалось свое отношение к этому <em>движку.</em> Есть как плюсы, так и минусы, но все же негатива накопилось гораздо больше.</p>
<p>В этой статье я поделюсь своим мнением с читателями и постараюсь описать и хорошие, и плохие стороны этой <strong>CMS</strong>.</p>
<p>Во-первых, хочется сказать пару слов о <em>тормозах</em> этой системы. В этом ее любят обвинять очень многие.</p>
<p>Для простых сайтов движок вполне подходит и тормозов в этом случае наблюдаться не будет, если, конечно, <em>проектировщик</em> не допустил откровенных ляпов при создании структуры <strong>инфоблоков</strong> (о том что это за зверь сейчас узнаем).</p>
<p><span id="more-234"></span></p>
<p>Тормоза начинаются, когда от сайта требуется что-то большее, нежели обычный текстовый контент. В этом случае проектировщик сталкивается с неуклюжестью движка.<br />
В битриксе все основывается на понятии инфоблока. Давайте рассмотрим что же на самом деле из себя представляет <strong>инфоблок.</strong></p>
<p><img title="Диаграмма инфоблоков Битрикс" src="/uploads/tiger/bitrix.png" alt="Диаграмма инфоблоков Битрикс" /></p>
<p><strong>Инфоблок</strong> — это такая <em>сущность</em>, которая объединяет элементы с определенным набором свойств. Часть свойств, такие как название элемента, раздел, даты активности и т.п., присутствует у элементов всех инфоблоков. К этим свойствам проектировщик может добавить еще и свои свойства, но они уже будут рассматриваться в контексте каждого конкретного инфоблока.</p>
<p>Существует также понятие <strong>типа инфоблока</strong>, который объединяет в себе инфоблоки.<br />
Поясню на примере. Допустим, мы создаем сайт, на котором будут размещены <em>вакансии.</em>. В этом случае нам будут необходимы 3 инфоблока: «Вакансии», «Отрасли», «Компании».</p>
<p>После создания инфоблока «Вакансии» мы можем создать в нем элементы со стандартным набором свойств:</p>
<ul>
<li>Название</li>
<li>Активность (да/нет)</li>
<li>Период активности (активен в указанный период времени)</li>
<li>Краткое описание</li>
<li>Подробное описание</li>
<li>Изображение-превью</li>
<li>Увеличенное изображение</li>
<li>Раздел</li>
</ul>
<p>Этих свойств будет достаточно для обычного текстового контента (статьи, новости и т.д.), но нам для вакансий этого не хватит. Мы создадим еще свойства:</p>
<ul>
<li>Компания (свойство, ссылающееся на инфоблок «Компании»)</li>
<li>Отрасль (свойство, ссылающееся на инфоблок «Отрасли»)</li>
<li>Опыт работы (свойство типа список с значениями «до 2-х лет», «от 2-х до 4-х лет», «более 4 лет» и т.д.)</li>
</ul>
<p>В инфоблоке «Отрасли» и «Компании» ограничимся стандартным набором свойств, которые предоставляет нам битрикс.</p>
<p>Вот, что у нас получилось:</p>
<p><img title="Структура инфоблоков Битрикс для размещения вакансий" src="/uploads/tiger/vacancy_bitrix.png" alt="Структура инфоблоков Битрикс для размещения вакансий" /></p>
<p>Вроде бы с точки зрения <em>теории баз данных</em> у нас все верно. Все сущности разделены, избыточности нет и т.д. Но давайте взглянем на <strong>структуру базы</strong>.</p>
<p>Рассмотрим как работает <strong>выборка из инфоблоков</strong> на простом примере. В <strong>битриксе</strong> существует часть таблиц в базе данных, которые хранят данные, связанные с инфоблоками — сами инфоблоки (b_iblock), их элементы(b_iblock_element), свойства(b_iblock_property), значения свойств (b_iblock_element_property).</p>
<p>Это не все таблицы, связанные с инфоблоками, но для простоты понимания нас будут интересовать именно они.</p>
<p><img title="ER-диаграмма некоторых таблиц Битрикса, хранящих данные об инфоблоках" src="/uploads/tiger/bd_bitrix.png" alt="ER-диаграмма некоторых таблиц Битрикса, хранящих данные об инфоблоках" /></p>
<p>Как видим, элементы всех инфоблоков хранятся в одной таблице, все свойства этих элементов так же хранятся в одной таблице.</p>
<p>Как же так! Зачем <em>СУБД</em> копаться в вакансиях, отраслях, если нам нужно будет выбрать всего лишь список всех компаний, вакансии которых храняться в базе ?!</p>
<p>А что будет, если нашему сайту необходим более сложный функционал? Вот тогда то и начнутся тормоза.</p>
<p>Теперь воспользуемся <strong>АПИ битрикса</strong> и выберем список вакансий конкретной компании, но те вакансии, которые не относятся к определенной отрасли.</p>
<p>В примере происходит выборка из инфоблока «Вакансии», ID которого 23, а также происходит фильтрация по компании, ID которой 373, и по отрасли, ID которой 317. В последнем параметре метода GetList передается список выбираемых полей — ID, компания, опыт работы, начало периода активности вакансии.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$arFilter</span> <span style="color: #339933;">=</span> <span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span>
<span style="color: #0000ff;">&quot;IBLOCK_ID&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">23</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// выбираем элементы из инфоблока, ID которого 23</span>
<span style="color: #0000ff;">&quot;ACTIVE&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">&quot;Y&quot;</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// выбираем только активные элементы</span>
<span style="color: #0000ff;">&quot;PROPERTY_COMPANY&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">373</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// вакансии будут принадлежать компании с ID=373</span>
<span style="color: #0000ff;">&quot;!PROPERTY_BRANCH&quot;</span> <span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">317</span> <span style="color: #666666; font-style: italic;">// вакансии, принадлежащие отрасли с ID=317, нас не интересуют</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$res</span> <span style="color: #339933;">=</span> CIBlockElement<span style="color: #339933;">::</span><span style="color: #004000;">GetList</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DATE_ACTIVE_FROM&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">&quot;ASC&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arFilter</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ID&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;PROPERTY_COMPANY&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;PROPERTY_EXPERIENCE&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;DATE_ACTIVE_FROM&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Выглядит красиво, прямо как-будто один безобидный <strong>SQL запрос</strong>, но заглянем внутрь:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> BP<span style="color: #66cc66;">.*</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock_property BP<span style="color: #66cc66;">,</span> b_iblock B
<span style="color: #993333; font-weight: bold;">WHERE</span>
BP<span style="color: #66cc66;">.</span>IBLOCK_ID<span style="color: #66cc66;">=</span>B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">23</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> UPPER<span style="color: #66cc66;">&#40;</span>BP<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">=</span>UPPER<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'COMPANY'</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> BP<span style="color: #66cc66;">.*</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock_property BP<span style="color: #66cc66;">,</span> b_iblock B
<span style="color: #993333; font-weight: bold;">WHERE</span>
BP<span style="color: #66cc66;">.</span>IBLOCK_ID<span style="color: #66cc66;">=</span>B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">23</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> UPPER<span style="color: #66cc66;">&#40;</span>BP<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">=</span>UPPER<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'EXPERIENCE'</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> BP<span style="color: #66cc66;">.*</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock_property BP<span style="color: #66cc66;">,</span> b_iblock B
<span style="color: #993333; font-weight: bold;">WHERE</span>
BP<span style="color: #66cc66;">.</span>IBLOCK_ID<span style="color: #66cc66;">=</span>B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">23</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> UPPER<span style="color: #66cc66;">&#40;</span>BP<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">=</span>UPPER<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'BRANCH'</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> BE<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> ID<span style="color: #66cc66;">,</span> FPV0<span style="color: #66cc66;">.</span>VALUE <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_COMPANY_VALUE<span style="color: #66cc66;">,</span> FPV0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_COMPANY_VALUE_ID<span style="color: #66cc66;">,</span> FPEN0<span style="color: #66cc66;">.</span>VALUE <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_EXPERIENCE_VALUE<span style="color: #66cc66;">,</span> FPEN0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_EXPERIENCE_ENUM_ID<span style="color: #66cc66;">,</span> FPV1<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_EXPERIENCE_VALUE_ID<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">IF</span><span style="color: #66cc66;">&#40;</span>EXTRACT<span style="color: #66cc66;">&#40;</span>HOUR_SECOND
<span style="color: #993333; font-weight: bold;">FROM</span>
BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&gt;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y %H:%i:%s'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> DATE_ACTIVE_FROM<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">IF</span><span style="color: #66cc66;">&#40;</span>EXTRACT<span style="color: #66cc66;">&#40;</span>HOUR_SECOND
<span style="color: #993333; font-weight: bold;">FROM</span>
BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&gt;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y %H:%i:%s'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> ACTIVE_FROM
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock B
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_lang L <span style="color: #993333; font-weight: bold;">ON</span> B<span style="color: #66cc66;">.</span>LID<span style="color: #66cc66;">=</span>L<span style="color: #66cc66;">.</span>LID
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element BE <span style="color: #993333; font-weight: bold;">ON</span> BE<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property FP0 <span style="color: #993333; font-weight: bold;">ON</span> FP0<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FP0<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'COMPANY'</span>
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property FP1 <span style="color: #993333; font-weight: bold;">ON</span> FP1<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FP1<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'EXPERIENCE'</span>
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property FP2 <span style="color: #993333; font-weight: bold;">ON</span> FP2<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FP2<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'BRANCH'</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element_property FPV0 <span style="color: #993333; font-weight: bold;">ON</span> FPV0<span style="color: #66cc66;">.</span>IBLOCK_PROPERTY_ID <span style="color: #66cc66;">=</span> FP0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV0<span style="color: #66cc66;">.</span>IBLOCK_ELEMENT_ID <span style="color: #66cc66;">=</span> BE<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element_property FPV1 <span style="color: #993333; font-weight: bold;">ON</span> FPV1<span style="color: #66cc66;">.</span>IBLOCK_PROPERTY_ID <span style="color: #66cc66;">=</span> FP1<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV1<span style="color: #66cc66;">.</span>IBLOCK_ELEMENT_ID <span style="color: #66cc66;">=</span> BE<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element_property FPV2 <span style="color: #993333; font-weight: bold;">ON</span> FPV2<span style="color: #66cc66;">.</span>IBLOCK_PROPERTY_ID <span style="color: #66cc66;">=</span> FP2<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV2<span style="color: #66cc66;">.</span>IBLOCK_ELEMENT_ID <span style="color: #66cc66;">=</span> BE<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property_enum FPEN0 <span style="color: #993333; font-weight: bold;">ON</span> FPEN0<span style="color: #66cc66;">.</span>PROPERTY_ID <span style="color: #66cc66;">=</span> FP0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV1<span style="color: #66cc66;">.</span>VALUE_ENUM <span style="color: #66cc66;">=</span> FPEN0<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">WHERE</span>
<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'23'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'Y'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>FPV0<span style="color: #66cc66;">.</span>VALUE_NUM <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'373'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span> FPV2<span style="color: #66cc66;">.</span>VALUE_NUM <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">OR</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #66cc66;">&#40;</span>FPV2<span style="color: #66cc66;">.</span>VALUE_NUM <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'317'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>WF_STATUS_ID<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">AND</span> BE<span style="color: #66cc66;">.</span>WF_PARENT_ELEMENT_ID <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span>
BE<span style="color: #66cc66;">.</span>ACTIVE_FROM <span style="color: #993333; font-weight: bold;">ASC</span></pre></div></div>

<p>Ужас! А что же тогда творится с <em>СУБД</em> на реальных сайтах.</p>
<p>Мы при написании метода <strong>GetList</strong> использовали 3 свойства (ключи значений массивов, начинающиеся с «PROPERTY_») и в <strong>SQL-запросах</strong>, которые сгенерил битрикс, видим 3 запроса для каждого из 3-х свойств. А что будет, если создать десятки свойств? А будет ровно столько запросов сколько участвует в методе GetList.</p>
<p>Ну и в конце мы видим громадный запрос, напичканный join&#8217;ами. Если приглядеться к этому запросу, то можно догадаться, что количество join&#8217;ов зависит от количества свойств, участвующих в методе GetList.</p>
<p>Понятно, что все это плата за универсальность. Все те, кто используют <strong>битрикс</strong> любят повторять, что это далеко не идеальная система, но это лучшая CMS из всех существующих. А чем она лучше? Да только, пожалуй, тем, что у нее присутствует больше всевозможных модулей по сравнению с другими <strong>CMS</strong>. Еще есть удобная админка, в которой быстро разберутся модераторы. Так же битрикс постоянно обновляется и пополняется новыми модулями, в этом тоже его плюс.</p>
<p>Как я уже сказал, мое мнение, что битрикс сгодится только для простых сайтов. Если требуется какой-то более менее сложный функционал, то приходится ломать голову как обойти эти издержки универсальности.</p>
<p>Возникает вопрос. Зачем простому сайту, на котором в основном <em>статьи</em> и новости, дополнительные модули в виде магазина, форума, блогов, тормозной статистики (которую к тому же предлагают многие бесплатные сервисы). А ведь такой сайт <em>программист</em> может без проблем создать, например, на бесплатном <em>фреймворке symfony</em>, в котором админка генерится одной командой. Так зачем платить больше?</p>
<p>Ну а сайт со сложным функционалом, как я уже сказал, по моему мнению начинать делать на битриксе лучше не стоит. Эта затея перерастет в поиски путей обхода битриксовых фич.<br />
И все-таки смысл создавать сайты на битриксе, как мне видится, есть. Но прежде, чем описать свою точку зрения на этот счет, нужно сказать несколько слов о многочисленной армии кодеров-битриксоидов.</p>
<p>Это такие люди, в основном студенты, которые еще не слышали ни о теории баз данных, ни о паттернах проектирования, не работали с существующими фреймворками. Для них битрикс — это все, что стоит за сайтом. Они даже о новых <em>технологиях</em> узнают только тогда, когда она будет включена в очередную версию <em>CMS</em>.</p>
<p>Как-то раз ко мне подошел один из сотрудников за помощью. Он парсил <em>файл CSV</em>, но этот процесс у него отрабатывал не верно. Стали смотреть скрипт и тут программист высказывает свое предположение: «Может быть <strong>битрикс</strong> где-то закрался?». Может быть всемогущий битрикс каким-то  магическим образом и мог бы закрасться в его скрипт, но дело в том, что он его запускал без подключения движка. На самом деле потом нашли обычную ошибку в логике самого скрипта.</p>
<p>Еще был случай. Отмечали чей-то день рождения и двое программистов начали обсуждать все достоинства битрикса. Один из них кинул фразу: «Ну битрикс — это очень мощная система, он внутри себя и <em>язык Си</em> использует, и <em>ассемблер</em>». Второй округлил глаза и не поверил. А тот ему: «Ну ты залезь в код битрикса, посмотри». Тут вообще без комментариев.</p>
<p>Так вот, мое мнение, что создавать сайты на битриксе имеет смысл, но только для <em>менеджеров</em>. Они не знают всех тонкостей работы движка, его подводных камней.<br />
Им выгодно иметь в своем штате <strong>битриксоидов</strong>, которым не нужно платить нормальные деньги, ведь это еще новичек, который дальше битрикса ничего не видел. Да и работать он будет с системой, в которой уже большинство вещей сделано за него.</p>
<p>Таким образом, на свет появляются <em>web-студии</em>, которые штампуют на битриксе сайт за сайтом. Их основной задачей в итоге становиться увеличение штата сотрудников, способных делать сайты на битриксе. <em>Дешевая рабочая сила</em>. Чем больше штат, тем больше сайтов они смогут клепать.</p>
<p>И напоследок хотелось бы дать совет <strong>начинающим программистам</strong>. Не устраивайтесь на работу в <em>web-студии</em>, которые в своих описаниях вакансий упоминают слово «<strong>Битрикс</strong>». Если вы начнете свой карьерный путь с этого движка, то потом соскочить с него будет не просто. Пройдет года 2 и ваши друзья уже неплохо продвинуться в программировании, кто-то перерастет в <em>проектировщика</em>, а вы будете жить одними <strong>инфоблоками</strong> и не понимать что происходит внутри.<br />
Я сейчас не говорю о всех, но именно таких программистов я встречал часто. Конечно, все люди разные, кто-то может на работе использовать битрикс, но дома в целях <em>самообразования</em> тренироваться в других <em>областях программирования</em>. Но все же лучше набираться знаний на работе, где человек проводит большую часть своего времени.</p>
<p>На этом все. Спасибо за внимание. В комментариях жду ваших мыслей по поводу использования битрикса.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/234/feed</wfw:commentRss>
		<slash:comments>875</slash:comments>
		</item>
		<item>
		<title>“Многопоточность” в PHP (socket)</title>
		<link>http://job-interview.ru/articles/post/194</link>
		<comments>http://job-interview.ru/articles/post/194#comments</comments>
		<pubDate>Sun, 27 Dec 2009 13:21:34 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[асинхронные сокеты]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[неблокирующие сокеты]]></category>

		<guid isPermaLink="false">/articles/?p=194</guid>
		<description><![CDATA[Использование асинхронных сокетов.
Предлагаю вашему вниманию третью статью из цикла &#8220;Многопоточность&#8221; в  PHP. В данной статье мы рассмотрим асинхронные или неблокирующие сокеты.
Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование асинхронных сокетов.</h3>
<p>Предлагаю вашему вниманию третью статью из цикла <a href="/articles/post/62" target="_blank">&#8220;Многопоточность&#8221; в  PHP</a>. В данной статье мы рассмотрим <strong>асинхронные</strong> или <strong>неблокирующие сокеты</strong>.</p>
<p>Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у нас много и с ними производятся одинаковые действия. Хорошо, если бы можно было не дожидаться завершения соединения, а сразу же открывать следущее. И такая возможность существует.</p>
<p>Но сначала давайте разберем само <strong>понятие &#8220;сокет&#8221;</strong>. Что такое сокет?<br />
<span id="more-194"></span></p>
<blockquote><p><strong>Сокеты</strong>  — это название программного интерфейса для обеспечения информационного обмена между <em>процессами</em>. Процессы при таком обмене могут исполняться как на одном компьютере, так и на различных, связанных между собой сетью. <strong>Сокет</strong> — абстрактный объект, представляющий конечную точку соединения.</p></blockquote>
<p>В нашем случае сокет будет представлять собой соединение между нашей программой и компьютером, с которого требуется получить необходимую информацию.</p>
<p><em>Работа с сокетами</em> достаточно проста:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// создаем сокет</span>
<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// открываем сокет</span>
<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'80'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// записываем данные в сокет</span>
<span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #339933;">,</span> <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// читаем данные из сокета</span>
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Сначала <em>функцией socket_create</em> инициализируем сокет и задаем его характеристики – флаг AF_INET, переданный в качестве первого параметра, указывает, что создается  сокет для интернета, второй параметр – тип сокета (самые распространенные – TCP и UDP)  нам нужен TCP-сокет &#8211; SOCK_STREAM, и третий параметр задает протокол (TCP).<br />
Затем с помощью <em>функции socket_connect</em> происходит соединение к указанному адресу и порту. Надо заметить, что эта функция принимает в качестве параметра не сам адрес хоста, а его ip адрес, поэтому сначала мы должны его определить <em>функцией gethostbyname</em>.<br />
Теперь нам надо <strong>сформировать запрос</strong>, который мы отправим на сервер (подробнее о <strong>http-заголовках</strong> можно почитать в <a href="/articles/post/86" target="_blank">статье PHP и HTTP</a>). Собственно отправку производит <em>функция socket_write</em>, второй параметр которой – это то, что мы отправляем и третий – длина отправляемой строки (т.е. всех сформированных заголовков).<br />
Запись произведена, теперь <em>функцией socket_read</em> читаем данные, переданные для нас сервером.<br />
В результате в переменной $result хранится хтмл, который нам необходим.</p>
<p>Задача у нас стоит та же, что и в предыдущих примерах: <em>получить содержимое нескольких html-страниц</em>. Вот код, реализующий это:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'www.yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$rtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи чтения</span>
<span style="color: #000088;">$wtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи записи</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// результаты</span>
&nbsp;
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// открываем отдельный сокет</span>
	<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// таймаут для чтения</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_RCVTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут для записи</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_SNDTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// задаем неблокирующий режим сокетов</span>
	<span style="color: #990000;">socket_set_nonblock</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
	<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// соединяемся</span>
	<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">80</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// добавляем в задачи для записи</span>
	<span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// продолжаем, пока есть задачи для записи или чтения</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью чтения</span>
	<span style="color: #000088;">$rtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$rtasks</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью записи</span>
	<span style="color: #000088;">$wtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$wtasks</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// ждем результатов из сокетов</span>
	<span style="color: #000088;">$n</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$e</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$n</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для записи</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач записи</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач записи</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// добавляем в задачи чтения</span>
			<span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
			<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #666666; font-style: italic;">// записываем в сокет</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для чтения</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач чтения</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// считываем результат из сокета</span>
			<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// закрываем сокет</span>
			<span style="color: #990000;">socket_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач чтения</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// заносим html в массив результатов</span>
			<span style="color: #000088;">$results</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Можно заметить, что код несильно отличается от <a href="/articles/post/92#stream_code" target="_blank">кода для stream-функций</a>.</p>
<p>В общих словах здесь происходит следующее. Каждый сокет <em>инициализируется</em> и переводится в <em>неблокирующий режим</em>. Затем в цикле производится проверка готовых к чтению или записи сокетов, и если такие существуют, производится соответствующая операция. Все действия протекают в <em>асинхронном порядке</em>, т.е не ждут окончания предыдущей операции. Например, если данные с мэйл.ру поступили раньше, чем от яндекса, то будут обрабатываться именно они, хотя коннект к яндексу мог произойти до коннекта к мэйлу. Можно сказать, что все происходит в несколько &#8220;потоков&#8221;, когда параллельно ожидается готовность каждого сокета к какому-либо действию.</p>
<p>Теперь разберем код более подробно.<br />
Итак, у нас есть массив с адресами страниц. В строке 9 запускается цикл для инициализации соединения с каждым хостом. В 11 строке создается сокет, затем в 15 и 17 строках мы задаем таймауты для чтения и записи соответственно. В 19 строчке <em>функцией socket_set_nonblock</em> задаем <strong>неблокирующий режим,</strong> превращающий каждый наш сокет в <strong>асинхронный</strong>. Это необходимо для того, чтобы после очередной операции над сокетом не происходило ожидание ее окончания, а продолжал работу остальной код программы. В 26 строке заносим инициализированный сокет в массив сокетов для записи.</p>
<p>Основной цикл начинается в 30 строчке. Он будет продолжаться до тех пор, пока у нас остаются сокеты, в которые нужно записать или из которых надо прочитать.<br />
В 32 строке массиву $rtasks_ присваиваем массив сокетов, из которых должна быть прочитана информация. В 34-ой в $wtasks_ заносится массив с сокетами, в которые необходимо произвести запись.<br />
Главная функция в этом цикле &#8211; <em>socket_select</em>. Она принимает на вход массивы сокетов, ожидающих чтения, ожидающих запись и массив для исключительных ситуаций, четвертый параметр, передаваемый в данную функцию – таймаут. Параметры-массивы передаются по ссылке, т.е когда произойдет ожидаемое событие (<em>socket_select</em> в этом случае вернет число больше 0), в них появятся соответствующие дескрипторы.<br />
Если нашлись сокеты, доступные для записи, ищем урл, соответствующий каждому из готовых сокетов, и <em>функцией socket_write</em> записываем в него заголовки для получения хтмл страницы в ответе. Так же в 44-ой строке удаляем дескриптор из массива для записи, так как она будет произведена, и заносим его в строке 46 в массив для чтения, чтобы потом получить интересующий нас ответ.<br />
Если же имеются сокеты, готовые нам ответить, считываем из них информацию <em>функцией socket_read</em>.<br />
Profit! В массиве $results содержится вожделенный хтмл-код!</p>
<p><b>Замечание:</b><br />
<i>При вызове функции socket_connect, когда сокет переведен в неблокирующий режим функцией socket_set_nonblock, выдается предупреждение <b style="color: red;">&#8220;Operation now in progress&#8221; (&#8221;Операция на незаблокированном сокете не может быть завершена немедленно&#8221;)</b>, а socket_connect возвращает false. Несмотря на это, код нормально отрабатывает.</i></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/194/feed</wfw:commentRss>
		<slash:comments>12683</slash:comments>
		</item>
		<item>
		<title>Вопросы на собеседовании для PHP-программиста (часть 3)</title>
		<link>http://job-interview.ru/articles/post/104</link>
		<comments>http://job-interview.ru/articles/post/104#comments</comments>
		<pubDate>Sat, 01 Aug 2009 17:49:23 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[регулярные выражения]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/?p=104</guid>
		<description><![CDATA[Это заключительная статья, о вопросах на собеседованиях для PHP-программиста, на которые мне приходилось отвечать.
В первых двух статьях я уже выкладывал список вопросов.
В первой статье были вопросы по темам:

PHP
Задачи по составлению различных запросов SQL

В второй статье были вопросы по темам:

Администрирование MySQL
Основные принципы ООП

В этой статье я выкладываю вопросы с собеседований для PHP — программиста по следующим [...]]]></description>
			<content:encoded><![CDATA[<p>Это заключительная статья, о <strong>вопросах на собеседованиях</strong> для PHP-программиста, на которые мне приходилось отвечать.</p>
<p>В первых двух статьях я уже выкладывал список вопросов.</p>
<p>В первой <a title="Вопросы на собеседовании для PHP-программиста (часть 1)" href="/articles/post/12">статье</a> были вопросы по темам:</p>
<ul>
<li><em>PHP</em></li>
<li><em>Задачи по составлению различных запросов SQL</em></li>
</ul>
<p>В второй <a title="Вопросы на собеседовании для PHP-программиста (часть 2)" href="/articles/post/57">статье</a> были вопросы по темам:</p>
<ul>
<li><em>Администрирование MySQL</em></li>
<li><em>Основные принципы ООП</em></li>
</ul>
<p>В этой статье я выкладываю вопросы с собеседований для <strong>PHP — программиста</strong> по следующим темам:</p>
<ul>
<li><em>Регулярные выражения</em></li>
<li><em>Основные протоколы интернета</em></li>
<li><em>Работа в командной строке Linux</em></li>
</ul>
<p>Итак, представляю список вопросов.</p>
<h3>Регулярные выражения</h3>
<blockquote>
<ol>
<li>Напишите регулярное выражение для проверки E-mail.</li>
<li>С использованием регулярных выражений напишите скрипт, который в заданном тексте ищет все слова, начинающиеся на «Str», и переворачивает эти слова. На выходе скрипта должен быть текст с перевернутыми словами.</li>
<li>Напишите регулярное выражение, которое ищет все ссылки в документе HTML.</li>
</ol>
</blockquote>
<h3>Основные протоколы интернета</h3>
<blockquote>
<ol>
<li>По какому протоколу передаются данные в интернете?</li>
<li>Назовите <em>уровни модели OSI</em>.</li>
<li>В чем основные отличия протокола HTTP/1.1 от HTTP 1.0 ?</li>
<li>Что такое заголовки <em>HTTP</em>?</li>
<li>В чем состоит преимущество постоянных соединений?</li>
<li>Какие методы запроса протокола HTTP вы знаете?</li>
</ol>
</blockquote>
<h3>Работа в командной строке Linux</h3>
<blockquote>
<ol>
<li>Напишите команду, которая убьет все процессы, начинающиеся на «proc».</li>
<li>Напишите команду, которая поставит папке и всем папкам и файлам, которые в ней хранятся права: чтение, запись, выполнение для владельца, чтение, запись для группы, выполнение для всех остальных.</li>
<li>Какими средствами будете пользоваться, если нужно отслеживать запросы к web-серверу в реальном времени?</li>
</ol>
</blockquote>
<p>
На этом все. Надеюсь мой список вопросов поможет кому-то подготовиться к прохождению собеседования на должность PHP-программиста.
</p>
<p><a title="Вопросы на собеседовании для PHP-программиста (часть 1)" href="/articles/post/12">Вопросы на собеседовании для PHP-программиста (часть 1)</a></p>
<p><a title="Вопросы на собеседовании для PHP-программиста (часть 2)" href="/articles/post/57">Вопросы на собеседовании для php-программиста (часть 2)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/104/feed</wfw:commentRss>
		<slash:comments>452</slash:comments>
		</item>
		<item>
		<title>&#8220;Многопоточность&#8221; в PHP (stream)</title>
		<link>http://job-interview.ru/articles/post/92</link>
		<comments>http://job-interview.ru/articles/post/92#comments</comments>
		<pubDate>Tue, 28 Jul 2009 07:24:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[stream]]></category>
		<category><![CDATA[stream_socket]]></category>
		<category><![CDATA[многопоточность]]></category>

		<guid isPermaLink="false">/articles/?p=92</guid>
		<description><![CDATA[Использование stream-функций.
Это вторая статья из серии “Многопоточность” в PHP.
В прошлый раз мы рассмотрели curl, теперь давайте поговорим о stream-функциях.

Вольный перевод документации:
Streams (потоки) были введены в PHP 4.3.0 как способ обобщить работу с файлами, сетью, сжатием данных и другими процессами, которые совместно используют единый набор функций. В простейшем определении, поток – объект ресурса, имеющий &#8220;потокообразное&#8221; поведение, [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование stream-функций.</h3>
<p>Это вторая статья из серии <a href="/articles/post/62" target="_blank">“Многопоточность” в PHP</a>.</p>
<p>В <a href="/articles/post/67" target="_blank">прошлый раз</a> мы рассмотрели <em>curl</em>, теперь давайте поговорим о <strong>stream-функциях</strong>.</p>
<p>
Вольный перевод документации:</p>
<blockquote><p><strong>Streams</strong> (потоки) были введены в PHP 4.3.0 как способ обобщить работу с файлами, сетью, сжатием данных и другими процессами, которые совместно используют единый набор функций. В простейшем определении, поток – объект ресурса, имеющий &#8220;потокообразное&#8221; поведение, т.е. из которого можно читать, в который можно писать и внутри которого можно перемещаться.</p></blockquote>
<p><strong>stream_socket-функции</strong> являются частью streams, при помощи них мы можем коннектиться или писать/читать данные, <em>не дожидаясь завершения предыдущей операции</em>.</p>
<p><span id="more-92"></span></p>
<p>Итак, <em>дано</em>: массив с урлами. <em>Задача</em>: непоследовательно получить их содержимое.</p>
<p>Давайте рассмотрим код, который решает поставленную нами задачу:</p>
<p><a name="stream_code"></a></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'www.yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$rtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи чтения</span>
<span style="color: #000088;">$wtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи записи</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// результаты</span>
&nbsp;
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// открываем отдельный сокет</span>
    <span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">stream_socket_client</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">':80'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errno</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errstr</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span>
        STREAM_CLIENT_ASYNC_CONNECT<span style="color: #339933;">|</span>STREAM_CLIENT_CONNECT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// добавляем в задачи для записи</span>
    <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью чтения</span>
    <span style="color: #000088;">$rtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$rtasks</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью записи</span>
    <span style="color: #000088;">$wtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$wtasks</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// ждем результатов из сокетов</span>
    <span style="color: #000088;">$n</span> <span style="color: #339933;">=</span> <span style="color: #990000;">stream_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$e</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$n</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// сокеты, доступные для записи</span>
        <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач записи</span>
            <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// удаляем из задач записи</span>
            <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// добавляем в задачи чтения</span>
            <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
            <span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Encoding: gzip,deflate<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// записываем в сокет</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">fwrite</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// сокеты, доступные для чтения</span>
        <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач чтения</span>
            <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// считываем результат из сокета</span>
            <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fread</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">8192</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// закрываем сокет</span>
            <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// удаляем из задач чтения</span>
            <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// заносим html в массиы результатов</span>
            <span style="color: #000088;">$results</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>
 Сначала инициализируются три массива: $rtasks – в него будут заноситься сокеты, из которых можно читать данные, $wtasks – для сокетов, готовых к записи, и $results – массив для сохранения содержимого заданных страниц.</p>
<p>
Затем в цикле <em>функцией stream_socket_client</em> открываются сокеты для каждого из урлов, при этом ставится флаг STREAM_CLIENT_ASYNC_CONNECT, который указывает, что каждое следующее соединение надо открывать <strong>не дожидаясь завершения открытия предыдущего</strong>. Флаг STREAM_CLIENT_CONNECT указывает, что мы создаем именно клиентское подключение.<br />
Дескрипторы сокетов заносятся в массив $wtasks.</p>
<p>В 18-ой строке начинается главный цикл, и сразу массивам $rtasks_ и $wtasks_, передаваемым в функцию stream_select, присваиваются массивы, в которых хранятся сокеты для чтения и записи соответственно. <em>Функция stream_select</em> отслеживает наличие данных в потоках и принимает на вход несколько параметров: первый – это массив дескрипторов, в которых ожидается завершение операции чтения, второй – массив с дескрипторами, ожидающими завершение записи, третий – для особых случаев (поступление &#8220;out-of-band data&#8221; &#8211; внеполосных данных) и четвертый параметр &#8211; это таймаут.  Массивы передаются в функцию по указателям, и как только функция возвращает число больше 0, в них будут находится сокеты, готовые к действиям.</p>
<p>В 28-ой строке мы смотрим, в какие сокеты можно записать данные (надо что-то отправить, прежде чем нам придет ответ-результат), и если такие сокеты есть, то удаляем из массива для записи текущий дескриптор, помещаем его в массив для чтения, и отправляем заголовки, необходимые для получения контента.<br />
Далее, в 49-ой строчке, просматриваем сокеты, готовые для считывания из них данных, забираем содержимое, удаляем дескриптор из масива для чтения и закрываем сокет. Результат заносим в массив $results. Повторяем эти операции до тех пор, пока у нас остаются какие-либо открытые сокеты.</p>
<p>После работы скрипта нужный нам контент находится в массиве $results.</p>
<p>В статье рассмотрен пример работы с <strong>функциями stream_socket_*</strong>, на очереди <a href="/articles/post/194" target="_blank">асинхронные сокеты</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/92/feed</wfw:commentRss>
		<slash:comments>108</slash:comments>
		</item>
		<item>
		<title>PHP и HTTP</title>
		<link>http://job-interview.ru/articles/post/86</link>
		<comments>http://job-interview.ru/articles/post/86#comments</comments>
		<pubDate>Mon, 27 Jul 2009 19:00:02 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">/articles/?p=86</guid>
		<description><![CDATA[
В этой статье я постараюсь описать работу с HTTP-запросами в языке программирования PHP.


Очень часто на собеседованиях приходится слышать вопрос:

  Что происходит, когда пользователь в адресной строке браузера, вводит адрес сайта и нажимает enter?
  

Ответ должен звучать примерно так:


Отправляется HTTP-запрос по протоколу TCP/IP на сервер, на котором расположен сайт. Далее программа web-сервер (обычно Apache, [...]]]></description>
			<content:encoded><![CDATA[<p>
В этой статье я постараюсь описать работу с <strong>HTTP-запросами</strong> в языке программирования <strong>PHP</strong>.
</p>
<p>
Очень часто на <em>собеседованиях</em> приходится слышать вопрос:</p>
<blockquote><p>
  Что происходит, когда пользователь в адресной строке браузера, вводит адрес сайта и нажимает enter?
  </p></blockquote>
<p>
Ответ должен звучать примерно так:
</p>
<p>
Отправляется HTTP-запрос по протоколу <em>TCP/IP</em> на сервер, на котором расположен сайт. Далее программа web-сервер (обычно <em>Apache</em>, <em>nginx</em> или <em>lighttpd</em>) принимает этот запрос и в случае, если вызываемый файл — это обычный HTML, то посылает в ответ браузеру свой <strong>HTTP-ответ</strong>, в котором содержится этот <strong>HTML</strong>.
</p>
<p>
Если вызываемый файл — это скрипт, например PHP, то сначала передается управление этому скрипту, который после всех своих операций на выход подает HTML, который web-сервер отсылает HTTP-ответом обратно браузеру.
</p>
<p>
Получив от сервера HTML, браузер его преобразовывает в удобочитаемый вид согласно <a href="http://www.w3.org/" title="стандарт W3C">стандарту W3C</a>, отправляет дополнительные запросы для отображения изображений или flash и пользователь видит содержимое сайта — текст, картинки, flash и т.д.
</p>
<p>
В этой статье я дам подробное описание HTTP-запросов и параметров, которые могут в нем содержаться. Потом представлю реализацию обмена HTTP-запросами посредством языка PHP — мы напишем простой <strong>прокси-сервер</strong>, при обращении к которому он возвращает браузеру страницу сайта, адрес которого был указан в GET-параметре.
</p>
<p><span id="more-86"></span></p>
<p>
Для тех, кто не знает, браузеры обмениваются с серверами HTTP-запросами. Именно за счет этого мы можем переходить по ссылкам, отправлять данные формы и получать на эти действия ответы от сервера.
</p>
<p>
Кстати, очень полезными бывают утилиты, отображающие HTTP-запросы, которые отправляет и получает браузер. Я пользуюсь для этого браузером Mozilla Firefox и утилитой <a title="HttpFox" href="https://addons.mozilla.org/en-US/firefox/addon/6647">HttpFox</a>.
</p>
<p>
Итак, давайте рассмотрим пример.
</p>
<p>
Введем в адресную строку браузера <a href="http://example.com">http://example.com</a> и нажмем enter.
</p>
<p>
В результате браузер отправит HTTP-запрос вида:
</p>
<blockquote>
<pre>
GET / HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.1.1 Firefox/3.0.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
</pre>
</blockquote>
<p>
В приведенном примере браузер хочет получить индексную страницу сайта example.com.
</p>
<p>
Получив запрос от браузера, web-сервер проверяет в своих настройках что является индексным файлом для сайта example.com.
</p>
<p>
Если это обычный HTML, например файл index.html, то просто возвращается его содержимое.
</p>
<p>При запросе индексной страницы сайта <a href="http://example.com">http://example.com</a> браузер получает от сервера следующий ответ:</p>
<blockquote>
<pre>
HTTP/1.x 200 OK
Date: Tue, 21 Jul 2009 17:09:54 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT
Etag: "b80f4-1b6-80bfd280"
Accept-Ranges: bytes
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8 

&lt;HTML&gt;
&lt;HEAD&gt;
  &lt;TITLE&gt;Example Web Page&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;body&gt;
&lt;p&gt;You have reached this web page by typing &quot;example.com&quot;,
&quot;example.net&quot;,
  or &quot;example.org&quot; into your web browser.&lt;/p&gt;
&lt;p&gt;These domain names are reserved for use in documentation and are not available
  for registration. See &lt;a href="http://www.rfc-editor.org/rfc/rfc2606.txt"&gt;RFC
  2606&lt;/a&gt;, Section 3.&lt;/p&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</pre>
</blockquote>
<p>
Обратите внимание на <strong>2 перевода строки</strong> в ответе сервера. Они являются разделением между параметрами ответа и телом сообщения, содержащего html, который и отображается в окне браузера.
</p>
<p>
В случае какого-либо скрипта, сначала происходит выполнение этого скрипта, который возвращает web-серверу HTML. Web-сервер в свою очередь отправляет этот HTML браузеру.
</p>
<p>
Представим себе, что индексной страницей сайта example.com является файл index.php. Web-сервер в этом случае, получив запрос от браузера, сначала передает управление интерпретатору PHP, который выполняет код, содержащийся в этом файле.
</p>
<p>Например, в файле index.php содержался бы следующий код:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'category'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;p&gt;This is a category of example.com&lt;/p&gt;&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">else</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;p&gt;This is a main page of example.com&lt;/p&gt;&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>
Если ввести в адресной строке браузера http://example.com?category=1 и нажать enter, то браузер отправит примерно следующий запрос:</p>
<blockquote>
<pre>
GET /index.php?category=1 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.1.1 Firefox/3.0.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
</pre>
</blockquote>
<p>
От сервера придет в этом случае следующий ответ:</p>
<blockquote>
<pre>
HTTP/1.x 200 OK
Date: Tue, 21 Jul 2009 17:09:54 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT
Etag: "b80f4-1b6-80bfd280"
Accept-Ranges: bytes
Content-Length: 39
Connection: close
Content-Type: text/html; charset=UTF-8 

&lt;p&gt;This is a category of example.com&lt;p&gt;</pre>
</blockquote>
<p>
Однако, если в адресной строке браузера ввести http://example.com/index.php, то ответ сервера будет таким: </p>
<blockquote><pre>
HTTP/1.x 200 OK
Date: Tue, 21 Jul 2009 17:09:54 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT
Etag: "b80f4-1b6-80bfd280"
Accept-Ranges: bytes
Content-Length: 40
Connection: close
Content-Type: text/html; charset=UTF-8 

&lt;p&gt;This is a main page of example.com&lt;/p&gt;
</pre>
</blockquote>
<p>
С телом запроса думаю все понятно — в нем содержится html, который и отражается в окне браузера. Давайте теперь разберем что же хранится в параметрах запроса браузера и ответа сервера.
</p>
<p>
Начнем с HTTP-запроса, который отправляет браузер.
</p>
<p>
Первая строка &#8211;  это строка запроса. Она содержит следующие поля, разделенные через пробел:</p>
<ul>
<li><strong>Метод запроса</strong>. Может принимать значения: OPTIONS, GET, HEAD, POST, DELETE, TRACE. Целью настоящей статьи не является рассмотрение всех методов. Нам будет достаточно метода GET. Если вы хотите получить описание каждого из методов, то советую обратится к документу <a href="http://www.faqs.org/rfcs/rfc2068.html" title="документ RFC 2068">RFC 2068</a></li>
<li><strong>Запрашиваемый URI</strong> — путь до запрашиваемого ресурса на сервере. Если запрашивается главная страница сайта, то указывается путь до корневого каталога сервера &#8211; «/».</li>
<li>Версия <strong>HTTP-протокола</strong>. В этом поле содержится строка вида: «HTTP/1.1». О различных версиях протокола HTTP также можно прочитать в документе <a href="http://www.faqs.org/rfcs/rfc2068.html" title="документ RFC 2086">RFC 2086</a>.</li>
</ul>
<p>
Далее после строки запроса следуют <strong>HTTP-заголовки</strong>. Описание каждого заголовка начинается с новой строки и представлено в виде:<br />
ЗАГОЛОВОК: ЗНАЧЕНИЕ.
</p>
<p>
Рассмотрим заголовки, которые отсылает браузер в нашем примере.</p>
<ul>
<li><strong>Host</strong>. Значением для этого заголовка должно быть доменное имя и порт запрашиваемого ресурса. Значение представляется в виде:
<p>ДОМЕННОЕ_ИМЯ:ПОРТ</p>
<p>Порт можно не указывать. В этом случае предполагается, что используется порт по умолчанию — в нашем случае это порт 80.</p>
<p>В нашем последнем примере для этого заголовка устанавливается значение example.com, т.е. браузер отправляет запрос на сервер example.com и хочет обратиться к файлу /index.php с переданным GET-параметром category=1.</p>
</li>
<li><strong>User-Agent</strong>. Содержит информацию о клиенте, который инициировал запрос к серверу, а также его программное обеспечение. Значение этого поля описывает ряд компонентов клиента. Оно может быть множественным, где все значения отделены друг от друга через пробел.
<p>В нашем последнем примере значением этого заголовка является:</p>
<p>Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.1.1 Firefox/3.0.8 </p>
<p>Здесь описываются параметры браузера и операционной системы — браузер Mozilla Firefox 3.0.8, основанный на движке Gecko, операционная система Linux Suse 11.1 оконной системой X11, процессор с архитектурой i686.</p>
<p>Этот заголовок используется для статистических целей.</p>
</li>
<li><strong>Accept</strong>. В этом заголовке клиент передает список форматов, которые допустимы для ответа. Значение этого поля хранит список допустимых форматов, разделенных через запятую. Кроме того, для каждого формата можно указать уровень предпочтения от 0 до 1. Если уровень предпочтения не указан, то он считается равным 1. Значение в этом поле должно соответствовать виду:
<p>ФОРМАТ1[;q=УРОВЕНЬ_ПРЕДПОЧТЕНИЯ1],ФОРМАТ2[;q=УРОВЕНЬ_ПРЕДПОЧТЕНИЯ2]&#8230;</p>
<p>В нашем примере браузер в этом заголовке посылает значение:</p>
<p>text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 </p>
<p>Его можно прочитать следующим образом: браузер предпочитает ответы в форматах text/html, application/xhtml+xml. Если сервер не может послать ответ в этих форматах, то браузер будет ожидать ответ в формате application/xml. Если же и в этом формате сервер не может послать ответ, то браузер примет ответ в любом формате.</p>
</li>
<li><strong>Accept-Language</strong>. Этот заголовок аналогичен заголовку ACCEPT, только здесь браузер сообщает серверу о своих предпочтениях о естественных языках, в которых должен приходить ответ.
<p>В нашем примере значением заголовка является:</p>
<p>ru,en-us;q=0.7,en;q=0.3 </p>
<p>Браузер сообщает серверу, что ждет ответ на русском языке, но также примет ответ на «американском английском» и английском языках.</p>
</li>
<li>
<strong>Accept-Encoding</strong>. Подобен ACCEPT. В этом заголовке браузер указывает какое кодирование к содержимому допустимо в ответе. Кодирование содержимого необходимо для сжатия или других его преобразований.
<p>В нашем примере в ответе для браузера допустимо сжатие программой gzip и механизмом deflate:</p>
<p>gzip,deflate</p>
</li>
<li><strong>Accept-Charset</strong>. Этот заголовок браузер посылает, чтобы сообщить серверу о своих предпочтениях кодировки ответа.
<p>В нашем примере этот заголовок принимает значение:</p>
<p>windows-1251,utf-8;q=0.7,*;q=0.7 </p>
<p>Браузер ждет ответ от сервера в первую очередь в кодировке windows-1251, но также примет ответ в любой кодировке.</p>
</li>
<li><strong>Keep-Alive</strong>. Заголовок Keep-Alive содержит значение, которое означает в течение какого времени в секундах будет удерживаться  соединение. Этот заголовок следует отправлять только в том случае, если заголовок Connection содержит значение keep-alive.
<p>Поддерживается только для протокола  HTTP версии 1.1.</p>
<p>В нашем примере этот заголовок содержит значение 300, т.е. браузер сообщает серверу, что намерен удерживать постоянное соединение с сервером в течение 300 секунд.</p>
</li>
<li>
<strong>Connection</strong>. Информация о проводимом соединении. В нашем примере этот заголовок принимает значение keep-alive, которое говорит серверу о том, что браузер хочет установить постоянное TCP соединение.
<p>До появления постоянных соединений для запроса каждой страницы сайта устанавливалось отдельное соединение. Открытие каждый раз отдельного соединения требует дополнительной нагрузки на сервер.</p>
<p>Например, браузер может запрашивать какую-то страницу с изображениями. После получения HTML страницы ему нужно будет запросить с сервера каждое изображение. При каждом запросе изображения будет открываться отдельное TCP соединение, что приведет к дополнительной нагрузке.</p>
<p>Использование постоянных соединений решает эту проблему. Если обе стороны (клиент и сервер) их поддерживают, то, в случае приведенного примера, HTML страницы и каждое изображение могут быть получены за одно TCP соединение.</p>
<p>Заголовок Connection поддерживается только для протокола  HTTP версии 1.1.</p>
<p>Этот заголовок также может принимать значение close. В этом случае клиент сообщит серверу, что после принятия HTTP-запроса соединение должно быть разорвано.</p>
</li>
</ul>
<p>
А теперь давайте рассмотрим параметры <strong>HTTP-ответа</strong>, который отправляет сервер браузеру.
</p>
<p>
Первая строка — это <strong>строка состояния</strong>, которая состоит из следующих полей, разделенных пробелом:
</p>
<ul>
<li><strong>Версия протокола HTTP</strong>. В нашем ответе от сервера в этом поле содержится HTTP/1.x. Сервер поддерживает протоколы HTTP 1.0 и 1.1.</li>
<li>Код состояния ответа. С возможными кодами состояния можно ознакомиться в документе <a href="http://www.faqs.org/rfcs/rfc2068.html" title="документ RFC 2068">RFC 2068</a>. В нашем случае от сервера нам необходим код состояния ответа, равный 200, который означат, что запрос браузера был выполнен удачно.</li>
<li><strong>Комментарий</strong>. Комментарий для кода состояния. Если код состояния 200, то комментарий будет «OK».</li>
</ul>
<p>
За строкой состояния следуют HTTP-заголовки, каждый начинается с новой строки. В нашем примере сервер отсылает следующие HTTP-заголовки:
</p>
<ul>
<li>
<p>
<strong>Date</strong>. В этом заголовке хранится дата в формате <a href="http://www.faqs.org/rfcs/rfc822.html" title="документ RFC 822">RFC 822</a>, описывающее когда отправляемый ответ был сгенерирован. Но это теория, на практике значением этого заголовка может быть любое время.
</p>
<p>В нашем примере в этом заголовке содержится:</p>
<p>Tue, 21 Jul 2009 17:09:54 GMT.</p>
</li>
<li>
<p>
<strong>Server</strong>. В этом заголовке содержится информация о программном обеспечении, которое используется на сервере, а также его компонентах. Если ответ от сервера направляется через proxy, то используется заголовок «Via».
</p>
<p>В ответе от сервере на наш запрос содержится следующее:</p>
<p>Apache/2.2.3 (CentOS)</p>
<p>Это означает, что на сервере используется web-сервер Apache версии 2.2.3. В качестве операционной системы используется дистрибутив Linux CentOS.</p>
</li>
<li>
<p>
<strong>Last-Modified</strong>. В этом заголовке сервер сообщает дату последнего изменения какой-либо сущности — файла, базы данных и т.п. В нашем случае сервер отправляет дату последнего изменения файла index.php.</p>
<p>Этот заголовок важен для браузера при использовании механизма кеширования. При обращении к какой-либо странице браузер кеширует ее. При повторном обращении к этой странице браузер, основываясь на заголовке Last-Modified проверит не устарела ли страница, сохраненная в кеше. Если нет, то браузер не будет еще раз считывать данные, а выведет страницу из кеша.</p>
<p>В ответе сервера из нашего примера в этом заголовке хранится:</p>
<p>Tue, 15 Nov 2005 13:24:10 GMT</p>
</li>
<li>
<p>
<strong>Etag</strong>. В этом заголовке содержится метка объекта ресурса. В нашем случае в качестве объекта выступает файл index.php.
</p>
<p>Наряду с заголовком Last-Modified значение этого заголовка используется при кешировании браузером. При первом запросе страницы браузер сохраняет значение Etag для страницы. При повторном запросе страницы значение Etag, которое пришло от сервера, сравнивается с тем, которое хранится в кеше браузера. Если они равны, то браузеру нет смысла считывать еще раз данные страницы, он просто возьмет их из кеша.</p>
<p>В нашем примере в ответе сервера Etag имеет следующее значение:</p>
<p>&#8220;b80f4-1b6-80bfd280&#8243;</p>
</li>
<li>
<p>
<strong>Accept-Ranges</strong>. Этот заголовок сообщает клиенту о том, что он может запрашивать данные с сервера фрагментами, указывая их смещение в байтах.
</p>
<p>Используется для реализации скачивания файлов с докачкой.</p>
<p>В нашем примере сервер поддерживает эту возможность, о чем он и сообщает, передав в заголовке Accept-Ranges значение bytes.</p>
<p>Зная эту возможность, браузер может передать серверу смещение в байтах, с которого необходимо начать передачу файла. Для этого браузер посылает заголовок Range с параметром bytes, значение которого и является смещением в байтах. Например:</p>
<p>Range: bytes=2048</p>
<p>Этот заголовок означает, что браузер запросил у сервера содержимое файла, начиная с 2-го мегабайта.</p>
</li>
<li>
<p>
Content-Length. Этот заголовок содержит размер тела HTTP-ответа сервера.<br />
В нашем примере размер тела сообщения 40.
</p>
</li>
<li>
<p>
<strong>Connection</strong>. Как и в случае для клиента, этот заголовок предоставляет информацию о проводимом соединении. В нашем примере этот заголовок принимает значение close, которое говорит клиенту о том, что сервер либо не поддерживает постоянное TCP соединение, либо он просто отказывает браузеру в постоянном соединении.
</p>
</li>
<li>
<p>
<strong>Content-Type</strong>. В этом заголовке содержится формат тела HTTP-ответа сервера.
</p>
<p>В нашем примере в этом заголовке содержится:</p>
<p>text/html; charset=UTF-8</p>
<p>Это означает, что сервер отвечает браузеру данными в формате text/html и кодировке UTF-8.</p>
<p>В этом заголовке сервера также может храниться, например, «text/css; charset=utf-8» при ответе браузеру на запрос файла CSS. Или, например, может храниться «image/gif» при ответе браузеру на запрос GIF-изображения.</p>
<p>О других форматах тела сообщения в ответах сервера читайте в <a href="http://www.faqs.org/rfcs/rfc822.html" title="документ RFC 822">RFC 822</a>.</p>
</li>
</ul>
<p>
После HTTP—заголовков в ответе сервера содержится 2 перевода строки, за которыми следует само тело сообщения. 2 перевода строки служат разделением между параметрами ответа сервера и телом сообщения, в котором содержится html, отображаемый браузером.
</p>
<p>
В нашем примере в теле сообщения ответа от сервера содержится:</p>
<blockquote><p>
  &lt;p&gt;This is a main page of example.com&lt;/p&gt;
  </p></blockquote>
<p>
Ну а теперь напишем простой <strong>прокси-сервер на PHP</strong>, который покажет практическое использование упомянутых HTTP-заголовков.
</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$body</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// доменное имя передаем в GET-параметре $_GET['host']</span>
<span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'host'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// открываем сокет на стандартном для HTTP порту 80</span>
<span style="color: #000088;">$hSocket</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fsockopen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">80</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errno</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errstr</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">30</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$hSocket</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// первой строкой идет строка запроса</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.1<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// указываем доменное имя</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: <span style="color: #006699; font-weight: bold;">$host</span><span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> 
     <span style="color: #666666; font-style: italic;">// пусть мы будем для сервера браузером Mozilla Firefox</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.1.1 Firefox/3.0.<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// указываем форматы, в которых будем ожидать ответ от сервера</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> 
    <span style="color: #666666; font-style: italic;">// языки, на которых ожидаем ответ</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> 
    <span style="color: #666666; font-style: italic;">// указываем какое кодирование к содержимому допустимо в ответе. </span>
    <span style="color: #666666; font-style: italic;">//Только в этом случае нужно будет раскодировать содержимое.</span>
    <span style="color: #666666; font-style: italic;">//$request .= &quot;Accept-Encoding: gzip,deflate\r\n&quot;; </span>
    <span style="color: #666666; font-style: italic;">// выставляем предпочтения для кодировок ответа</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> 
    <span style="color: #666666; font-style: italic;">// будем удерживать постоянное соединение в течение 300 секунд</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Keep-Alive: 300<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// открываем постоянное соединение</span>
    <span style="color: #666666; font-style: italic;">// здесь мы завершаем передачу HTTP-заголовков, </span>
    <span style="color: #666666; font-style: italic;">// поэтому в конце обязательно указываем 2 перевода строки</span>
    <span style="color: #000088;">$request</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Connection: keep-alive<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> 
    <span style="color: #666666; font-style: italic;">// посылаем HTTP-заголовки через открытый сокет</span>
    <span style="color: #990000;">fwrite</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$hSocket</span><span style="color: #339933;">,</span> <span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
    <span style="color: #666666; font-style: italic;">// флаг, указывающий на то, что считывается тело запроса</span>
    <span style="color: #000088;">$bIsData</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span> 
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">feof</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$hSocket</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// считываем ответ от сервера</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$str</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fgets</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$hSocket</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">128</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// построчно</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$bIsData</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$body</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$str</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// тело запроса записываем в переменную $body</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #666666; font-style: italic;">// встретилась строка, содержащая только перевод строки, это означает, </span>
        <span style="color: #666666; font-style: italic;">//что дальше пойдет тело запроса</span>
        <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$str</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span> 
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$bIsData</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$hSocket</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// закрываем сокет</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// указываем на то, чтобы web-сервер отправил браузеру заголовки </span>
    <span style="color: #666666; font-style: italic;">// Last-Modified, Connection и Keep-alive</span>
    <span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Last-Modified: Tue, 21 Jul 2009 17:09:54 GMT&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Connection: Keep-Alive&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//</span>
    <span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Keep-Alive: timeout=30, max=100&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// передаем тело запроса</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$body</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// работа php-скрипта закончена, теперь web-сервер отправляет ответ браузеру</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Чтобы отправить заголовки серверу, необходимо сначала открыть сокет. <strong>Сокет</strong> — это программный интерфейс, который позволяет обмениваться данными между процессами. При этом процессы могут выполняться на разных компьютерах, связанных сетью.
</p>
<p>
В нашем случае один процесс — это процесс браузера, второй — это процесс web-сервера, запущенный на удаленном компьютере.
</p>
<p>
В PHP сокет открывается функцией <a href="http://ru.php.net/fsockopen" title="функция PHP fsockopen">fsockopen</a>. Далее в переменную $request мы записываем все нужные нам заголовки и отправляем их серверу функцией <a href="http://ru.php.net/fwrite" title="функция PHP fwrite">fwrite</a>. После этого мы построчно считываем ответ сервера пока не будет достигнут конец данных (<a href="http://ru.php.net/feof" title="функция PHP feof">feof</a>). После получения ответа мы отправляем этот ответ браузеру вместе с заголовками, которые в PHP выставляются функцией <a href="http://ru.php.net/header" title="функция PHP header">header</a>.
</p>
<p>
Этот скрипт принимает через GET-параметр доменное имя сайта и отправляет к нему HTTP-запрос, считывает ответ и отдает этот ответ web-серверу, который отправляет его браузеру.
</p>
<p>
При помощи подобного скрипта вы можете сами поиграться с отправляемыми HTTP-запросами.
</p>
<p>
Нам этом все. Спасибо за внимание.
</p>
<p>
Для тех, кто заинтересовался и хочет подробнее изучить <strong>HTTP</strong> могу посоветовать следующие ссылки:
</p>
<p>
<a href="http://ru.wikipedia.org/wiki/HTTP" title="статья, подробно описывающая HTTP">http://ru.wikipedia.org/wiki/HTTP</a> &#8211; статья, подробно описывающая HTTP.
</p>
<p>
<a href="http://www.faqs.org/rfcs/rfc2068.html" title="документ RFC 2068">http://www.faqs.org/rfcs/rfc2068.html</a> &#8211; документ RFC 2068.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/86/feed</wfw:commentRss>
		<slash:comments>5545</slash:comments>
		</item>
		<item>
		<title>&#8220;Многопоточность&#8221; в PHP (curl)</title>
		<link>http://job-interview.ru/articles/post/67</link>
		<comments>http://job-interview.ru/articles/post/67#comments</comments>
		<pubDate>Thu, 09 Jul 2009 07:09:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[мультизапросы]]></category>

		<guid isPermaLink="false">/articles/?p=67</guid>
		<description><![CDATA[Использование библиотеки curl.
Эта статья является первой из серии &#8220;Многопоточность&#8221; в PHP

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

Используем [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование библиотеки curl.</h3>
<p>Эта статья является первой из серии <a href="/articles/post/62" target="_blank">&#8220;Многопоточность&#8221; в PHP</a></p>
<p>
<strong>Curl</strong> – это библиотека, позволяющая подсоединяться к разным серверам по разным протоколам. Обладает удобством в работе и способностью гибко настраиваться.<br />
Curl реализует механизм <em>множественных запросов</em>, или <em>мультизапросов</em>. Его принцип заключается в том, что посылается несколько запросов, при этом перед отправкой следующего не ожидается ответ на предыдущий.
</p>
<p>Используем это в нашем примере <strong>скачивания нескольких страниц</strong>.
</p>
<p>Рассмотрим сначала процесс <em>скачивания содержимого с одного url</em>. </p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'mail.ru'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// инициализация сеанса curl</span>
<span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// curl_exec будет возвращать результат</span>
<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// не будет возвращаться http-заголовок</span>
<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// загрузка страницы и выдача её браузеру</span>
<span style="color: #000088;">$content</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// завершение сеанса и освобождение ресурсов</span>
<span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>
Здесь <em>функцией curl_init</em> мы инициализируем сеанс curl и в качестве параметра передаем урл страницы, которую хотим скачать. Далее первым вызовом <em>функции curl_setopt</em> говорим, что результат надо вернуть, а не вывести в браузер, и вторым запрещаем передачу нам http-ответа сервера. curl_setopt принимаюет в качестве параметров дескриптор соединения $ch, название опции и ее значение соответственно. С помощью curl_setopt можно задать много параметров для более тонкого управления соединением, подробнее читайте в <a href="http://php.net/curl" target="_blank">мануале</a> к этой библиотеке. Затем <em>функцией curl_exec</em> производим собственно скачивание и в завершении закрываем соединение &#8211; <em>curl_close</em>. В переменной $content у нас теперь находится код страницы, указанной в $url.
</p>
<p>А сейчас давайте попробуем <strong>скачать сразу несколько страниц</strong> (основа примера взята из документации на php.net):
</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// инициализируем &quot;контейнер&quot; для отдельных соединений (мультикурл)</span>
<span style="color: #000088;">$cmh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_init</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// массив заданий для мультикурла</span>
<span style="color: #000088;">$tasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// перебираем наши урлы</span>
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// инициализируем отдельное соединение (поток)</span>
	<span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// если будет редирект - перейти по нему</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_FOLLOWLOCATION<span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// возвращать результат</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// не возвращать http-заголовок</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут соединения</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_CONNECTTIMEOUT<span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут ожидания</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_TIMEOUT<span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// добавляем дескриптор потока в массив заданий</span>
	<span style="color: #000088;">$tasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ch</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// добавляем дескриптор потока в мультикурл</span>
	<span style="color: #990000;">curl_multi_add_handle</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// количество активных потоков</span>
<span style="color: #000088;">$active</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// запускаем выполнение потоков</span>
<span style="color: #b1b100;">do</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$mrc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$active</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> 
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$mrc</span> <span style="color: #339933;">==</span> CURLM_CALL_MULTI_PERFORM<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// выполняем, пока есть активные потоки</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$active</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$mrc</span> <span style="color: #339933;">==</span> CURLM_OK<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// если какой-либо поток готов к действиям</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">curl_multi_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// ждем, пока что-нибудь изменится</span>
		<span style="color: #b1b100;">do</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000088;">$mrc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$active</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// получаем информацию о потоке</span>
			<span style="color: #000088;">$info</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_info_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// если поток завершился</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'msg'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> CURLMSG_DONE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'handle'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору потока в массиве заданий</span>
				<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// забираем содержимое</span>
				<span style="color: #000088;">$tasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_getcontent</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// удаляем поток из мультикурла</span>
				<span style="color: #990000;">curl_multi_remove_handle</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// закрываем отдельное соединение (поток)</span>
				<span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$mrc</span> <span style="color: #339933;">==</span> CURLM_CALL_MULTI_PERFORM<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// закрываем мультикурл</span>
<span style="color: #990000;">curl_multi_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Код подробно откомментирован, но давайте разберем все по порядку.<br />
В 7 строчке мы инициализируем контейнер для отдельных соединений curl (далее я буду называть его <em>мультикурл</em>), именно он позволит нам проводить операции с ними <em>параллельно</em>.<br />
Далее в цикле инициализируем соединение (назовем его <em>поток</em>) для каждого урла из нашего массива, попутно добавляя его в мультикурл и в массив заданий $tasks. $tasks – массив, в котором ключами являются адреса наших страниц, а значениями – соответствующие дескрипторы curl. <em>Функция curl_multi_add_handle</em> добавляет к дескриптору нашего мультизапросного соединения отдельное созданное соединение.</p>
<p>
В 34 строке запускается цикл для начала работы нашего мультикурла. <em>Функция curl_multi_exec</em> <strong>одновременно отправляет на выполнение все объявленные потоки</strong>, при этом в переменную $active заносится количество выполняемых потоков.
</p>
<p>
В основном цикле, начинающемся на 40 строчке, происходят главные действия. Он выполняется до тех пор, пока есть незавершенные потоки или пока не произошла ошибка. В 42 строке вызывается <em>функция curl_multi_select</em>, которая проверяет готовность какого-либо из потоков к дальнейшим действиям с ним. Затем, в 47 строке, <em>функцией curl_multi_info_read</em> получаем информацию о потоке. Но так как curl_multi_info_read обновляет возвращаемую информацию только после вызова curl_multi_exec, сделаем это в строке 45.
</p>
<p>Функция curl_multi_info_read возвращает массив, в котором нас интересуют ключи &#8216;msg&#8217; и &#8216;handle&#8217;. По &#8216;msg&#8217; мы проверяем, выполнился ли поток, а по &#8216;handle&#8217; узнаем его дескриптор. Получив дескриптор, ищем по массиву заданий, к какому урлу он относится и записываем вместо него вожделенное содержимое страницы, получаемое <em>функцией curl_multi_getcontent</em>.<br />
Теперь, когда данный поток выполнил свою задачу, удаляем его из мультикурла, а потом закрываем самого.</p>
<p>После завершения всех потоков <em>функцией curl_multi_close</em> закрываем мультикурл.</p>
<p>Сейчас в массиве заданий $tasks находятся html-коды заданных страниц.</p>
<p>Надеюсь, после прочтения статьи стало немного понятнее, как можно реализовать выполнение &#8220;многопоточных&#8221; запросов на PHP.</p>
<p>В <a href="/articles/post/92" target="_blank">следующей статье</a> рассмотрим использование stream-функций для подобных целей.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/67/feed</wfw:commentRss>
		<slash:comments>17579</slash:comments>
		</item>
		<item>
		<title>&#8220;Многопоточность&#8221; в PHP (вступление)</title>
		<link>http://job-interview.ru/articles/post/62</link>
		<comments>http://job-interview.ru/articles/post/62#comments</comments>
		<pubDate>Thu, 09 Jul 2009 07:05:07 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[многозадачность]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[многопроцессность]]></category>

		<guid isPermaLink="false">/articles/?p=62</guid>
		<description><![CDATA[Intro
Эта небольшая серия статей является обобщением материала, найденного в интернете и не претендует на оригинальность. Идея ее написать возникла у меня после поиска информации по каждому из пунктов данного материала, чтобы облегчить задачу тем, кому придется столкнуться с данной темой.

Сразу хочу сказать, что многопоточности в PHP нет. Не зря слово многопоточность в заголовке взято в [...]]]></description>
			<content:encoded><![CDATA[<h3>Intro</h3>
<p>Эта небольшая серия статей является обобщением материала, найденного в интернете и не претендует на оригинальность. Идея ее написать возникла у меня после поиска информации по каждому из пунктов данного материала, чтобы облегчить задачу тем, кому придется столкнуться с данной темой.
</p>
<p>Сразу хочу сказать, что <b>многопоточности в PHP нет</b>. Не зря слово многопоточность в заголовке взято в кавычки. Да, существует <em>многопроцессность</em>, реализующаяся средствами операционной системы (этот случай будет разобран), <em>многозадачность</em>, но <em>многопоточности</em> не существует. Однако некоторые задачи все-таки можно выполнять <em>параллельно</em>.
</p>
<p>Возьмем пример, встречающийся достаточно часто: <strong>скачать программно содержимое нескольких страниц</strong>. Если страниц немного, то их можно без проблем и больших затрат времени загрузить последовательно. Но если их тысячи? И вот здесь можно применить подходы, позволяющие <strong>выполнить скачивание одновременно</strong>. Некоторые из них и будут подробно описаны в данном материале. Сначала мы рассмотрим <a href="/articles/post/67" target="_blank">использование библиотеки curl</a>, которая может производить загрузку одновременно нескольких страниц. Затем попробуем применить к нашей задаче <a href="/articles/post/92" target="_blank">stream-функции</a>. После этого сделаем то же самое с помощью <a href="/articles/post/194" target="_blank">асинхронных сокетов</a>. И наконец распараллелим наш процесс функцией fork.</p>
<p>Все способы проверены на личном опыте. Для примеров взят максимум простой код, без оптимизации, его цель – показать принципы работы каждого метода.
</p>
<p>Для вступления рассмотрим такой способ, как</p>
<h3>Вызов одновременно нескольких копий скрипта</h3>
<p>Суть состоит в том, что <strong>один скрипт вызывается с разными параметрами</strong>, разбивающими задачу на несколько одинаковых подзадач.</p>
<p>Пример. Пусть у нас есть скрипт getcontent.php</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'rambler.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'bing.com'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'mail.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$k</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'k'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$urls</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$k</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$content</span> <span style="color: #339933;">=</span> <span style="color: #990000;">file_get_contents</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$f</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fopen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$k</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'.cont'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'w'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">fwrite</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$f</span><span style="color: #339933;">,</span> <span style="color: #000088;">$content</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$f</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Здесь $urls – массив урлов, содержимое с которых нам надо получить.<br />
Вызывая этот скрипт как getcontent.php?k=n , где n равен какому-либо ключу массива $urls, мы получим на жестком диске файл с именем n.cont, в котором и сохранен html интересующей нас страницы.
</p>
<p>Теперь откроем в браузере пять вкладок, напишем в адресной строке первой http://путь/getcontent.php?k=0, адресной строке второй http://путь/getcontent.php?k=1 и т.д. до http://путь/getcontent.php?k=4 и в каждой быстро нажмем Enter. Если теперь зайти в папку с нашим скриптом, то мы увидим там 5 файлов с html сайтов из масива, причем их получение произошло практически (зависит от того, как быстро жать enter) одновременно. Вот на таком нехитром примере мы показали простейший способ <em>выполнения одного задания в несколько &#8220;потоков&#8221;</em> <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
</p>
<p>Недостаток этого способа в том, что на каждый запущенный скрипт выделяется определенное количество памяти, общее количество которой в данном случае пропорционально количеству запущенных копий скрипта. Другой минус – неудобство управлением данными.</p>
<p>В <a href="/articles/post/67" target="_blank">следующей статье</a> мы попробуем для достижения нашей цели воспользоваться более гуманным способом – использовать библиотеку curl.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/62/feed</wfw:commentRss>
		<slash:comments>66</slash:comments>
		</item>
		<item>
		<title>Вопросы на собеседовании для PHP-программиста (часть 2)</title>
		<link>http://job-interview.ru/articles/post/57</link>
		<comments>http://job-interview.ru/articles/post/57#comments</comments>
		<pubDate>Wed, 08 Jul 2009 21:18:15 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[вопросы]]></category>
		<category><![CDATA[ООП]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/?p=57</guid>
		<description><![CDATA[Итак, в продолжение моей предыдущей статьи, выкладываю следующий список вопросов, на которые мне приходилось отвечать на собеседованиях. В первой статье я разделил их на 7 тем и выложил вопросы из первых двух.
Теперь я затрону 2 темы — это «Администрирование СУБД» и «Основные принципы ООП».
Как уже было упомянуто, я являюсь PHP-программистом и, основываясь на своем опыте [...]]]></description>
			<content:encoded><![CDATA[<p>Итак, в продолжение моей предыдущей <a href="/articles/post/12">статьи</a>, выкладываю следующий список вопросов, на которые мне приходилось отвечать на <strong>собеседованиях</strong>. В первой статье я разделил их на 7 тем и выложил вопросы из первых двух.</p>
<p>Теперь я затрону 2 темы — это <strong>«Администрирование СУБД»</strong> и <strong>«Основные принципы ООП»</strong>.</p>
<p>Как уже было упомянуто, я являюсь <em>PHP-программистом</em> и, основываясь на своем опыте прохождения собеседований, могу сказать, что в основном при упоминании СУБД имеется ввиду <strong>MySQL</strong>, реже PostgreSQL. В настоящей статье я перечислю вопросы, касающиеся администрирования именно MySQL.</p>
<h3>Администрирование MySQL</h3>
<blockquote>
<p>1.&nbsp;&nbsp;Что работает быстрее? <em>MyISAM</em> или <em>InnoDB</em>? Почему в основном используют MyISAM?</p>
<p>2.&nbsp;&nbsp;Есть ли для MySQL универсальная защита от <em>SQL-инъекций</em>?</p>
<p>3.&nbsp;&nbsp;Какими средствами вы будете пользоваться при поиске источника замедления запросов к MySQL? Дайте описание полей, выводимых командой <em>EXPLAIN</em>.</p>
<p>4.&nbsp;&nbsp;Расскажите о способах хранения деревьев в таблице? Например, когда нужно реализовать древовидные комментарии к статье.</p>
<p>5.&nbsp;&nbsp;На что вы в первую очередь обратите внимание при при наличии ощутимых «тормозов» MySQL при условии, что все направленные запросы составлены корректно? Расставьте приоритеты:</p>
<ul>
<li>Настройки MySQL</li>
<li>Файловая система</li>
<li>Язык программирования</li>
<li>Память</li>
</ul>
<p>6.&nbsp;&nbsp;Перечислите случаи, когда использование индексов может только навредить.</p>
</blockquote>
<h3>Основные принципы ООП</h3>
<blockquote>
<p>1.&nbsp;&nbsp;Чем <em>интерфейс</em> отличается от <em>абстрактного класса</em>?</p>
<p>2.&nbsp;&nbsp;Как реализовать <em>множественное наследование</em> в PHP?</p>
<p>3.&nbsp;&nbsp;Напишите класс, реализующий <em>синглтон</em>, подсчитывающий количество попыток создания объектов этого класса.</p>
<p>4.&nbsp;&nbsp;Каким будет вывод? Объясните.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?</span>
<span style="color: #000000; font-weight: bold;">class</span> foo <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">function</span> bar<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$a</span><span style="color: #009900;">&#41;</span> 
  <span style="color: #009900;">&#123;</span> 
    <span style="color: #000088;">$a</span><span style="color: #339933;">++;</span> 
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">function</span> bar2<span style="color: #009900;">&#40;</span><span style="color: #000088;">$a</span><span style="color: #009900;">&#41;</span> 
  <span style="color: #009900;">&#123;</span> 
    <span style="color: #339933;">++</span><span style="color: #000088;">$a</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$f</span> <span style="color: #339933;">=&amp;</span> <span style="color: #000000; font-weight: bold;">new</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$a</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> 
<span style="color: #000088;">$b</span> <span style="color: #339933;">=&amp;</span> <span style="color: #000088;">$a</span><span style="color: #339933;">;</span> 
<span style="color: #000088;">$c</span> <span style="color: #339933;">=&amp;</span> <span style="color: #000088;">$b</span><span style="color: #339933;">;</span> 
<span style="color: #000088;">$d</span> <span style="color: #339933;">=&amp;</span> <span style="color: #000088;">$c</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$f</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bar</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$a</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$f</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bar2</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$a</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$d</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>5.&nbsp;&nbsp;Для чего нужен <em>паттерн</em> «Наблюдатель». В каких случаях его применение может быть полезно?</p>
</blockquote>
<p>
На этом все. В следующей статье я выложу вопросы по оставшимся темам:</p>
<ul>
<li><em>Регулярные выражения</em></li>
<li><em>Основные протоколы интернета</em></li>
<li><em>Работа в командной строке Linux</em></li>
</ul>
<p><a href="/articles/post/12">Вопросы на собеседовании для PHP-программиста (часть 1)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/57/feed</wfw:commentRss>
		<slash:comments>45</slash:comments>
		</item>
	</channel>
</rss>
