<?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; web</title>
	<atom:link href="http://job-interview.ru/articles/post/tag/web/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>Как я проводил собеседование</title>
		<link>http://job-interview.ru/articles/post/290</link>
		<comments>http://job-interview.ru/articles/post/290#comments</comments>
		<pubDate>Sun, 23 Jan 2011 17:44:01 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[вопросы]]></category>
		<category><![CDATA[задачи]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/post/290</guid>
		<description><![CDATA[Вот уже прошло почти полтора года, как я в поисках работы посещал собеседования в разных компаниях, после чего мною была написана статья Нужны ли логические задачи на собеседованиях?. И вот совсем недавно мне самому пришлось набирать команду программистов и проводить с ними собеседования. Как вы могли бы догадаться, собеседования без задач на логику.  
Так [...]]]></description>
			<content:encoded><![CDATA[<p>Вот уже прошло почти полтора года, как я в поисках работы посещал собеседования в разных компаниях, после чего мною была написана статья <a title="Нужны ли логические задачи на собеседованиях?" href="/articles/post/7">Нужны ли логические задачи на собеседованиях?</a>. И вот совсем недавно мне самому пришлось набирать команду программистов и проводить с ними собеседования. Как вы могли бы догадаться, собеседования без <strong>задач на логику</strong>. <img src='/articles/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Так получилось, что через некоторое время в компании на проекте остался всего один программист — и это был я. Необходимо было в кратчайшие сроки воссоздать команду. <strong>Проведение собеседования</strong> доверили мне. </p>
<p>Цель: <em>найти 2-х программистов, один должен быть опытным, другой начинающим</em>.<br />
<span id="more-290"></span><br />
Хочу сразу сказать, эта статья не содержит никаких советов о том, как проводить «<strong>правильное собеседование</strong>». Здесь я рассказываю о своем опыте проведения собеседований и, как показало время, в моем случае эти собеседования оказались правильными, т.к. я подобрал тех людей, которых и хотел. Но обо всем по порядку.</p>
<p>Началось все с того, что в один прекрасный день ко мне утром подошел мой начальник и сказал, что через 20 минут должен придти соискатель и надо бы подготовить вопросы для него. 20 минут на подготовку вопросов!</p>
<p>Пришлось быстро вспомнить какие вопросы задавали мне на собеседованиях, поискать по интернету и т.д. В общем кое-как я подготовил 7 вопросов. 3 вопроса, на мой взгляд, были вообще элементарными, 2 — довольно простыми при наличии опыта, еще 2 — SQL-запросы, не из самых легких.</p>
<p>Итак, начали собеседование, я дал 15 минут на подготовку ответов на вопросы. По истечении этого времени кандидат дал 3 правильных ответа из 7 — 1 из категории элементарных, 2 из категории «простые при наличии опыта».</p>
<p>Такие ответы не давали полного понимания о знаниях человека. Вроде бы ответил на вопросы, которые должны были показать его опыт, но не ответил на 2 из 3-х элементарных вопросов. А что с SQL? Ответы были неправильными, но и вопросы не из легких.</p>
<p>Очевидно, что мною были неправильно подготовлены вопросы, они не позволяли понять знания кандидата. К слову сказать, в этот же день приходил еще один соискатель, с ним была примерно та же история — правильно ответил на 2 простых вопроса и 1 на проверку опыта.</p>
<p>Теперь мне нужно было подготовить правильные вопросы для проведения собеседования.  На следующий день должны были придти еще программисты, времени на подготовку вопросов было уже предостаточно.</p>
<p>Я решил, что все вопросы нужно разделить на несколько частей:</p>
<ol>
<li> <strong>Пара простейших вопросов, с которыми справится любой программист.</strong></li>
<p>Чтобы сразу же выявить тех, кто по своим знаниям нам точно не подходит. Должен сказать, что из всех собеседуемых таких оказалось 3 человека. С ними я сразу прощался, не переходя к более сложным вопросам.</p>
<li> <strong>Вопросы, на которые ответит любой программист с опытом.</strong></li>
<p>В общем-то это также несложные вопросы, но они показывают на сколько опытен программист. Например, человек, недавно окончивший университет и не работавший еще над более менее серьезными проектами, вряд ли будет знаком с различными <em>методами кэширования</em>, <em>системами контроля версий</em>, вряд ли он работал с <em>высоконагруженными проектами</em>.</p>
<li> <strong>Немного теории и вопросы по проектированию.</strong></li>
<p>Эта часть вопросов должна была показать на сколько человек способен работать самостоятельно, сможет ли он без тотального контроля решить задачу наиболее оптимальным способом. Сюда относятся составление правильной структуры БД еще до начала реализации, написание кода, который хорошо впишется в существующий. И не забываем про нагрузки — задача может быть реализована, прекрасно работать на девелоперских серверах, но после выката на продакшн может положить весь сайт.</p>
<li><strong>Несложные SQL-запросы.</strong></li>
<p>Ну и немного поломать мозг. Но только совсем слегка. Эта часть вопросов на составление <strong>SQL-запросов</strong>, все запросы довольно простые и при знании операторов SQL решаются быстро. Также здесь можно понять на сколько правильно человек выбирает методы решения — при незнании каких-то возможностей SQL, некоторые начинали составлять мегазапросы с огромным количеством подзапросов, join&#8217;ов и т.д.</p>
<li><strong>Вопросы не для всех.</strong></li>
<p>Эти вопросы я задавал только тем, кто с легкостью ответил на все предыдущие вопросы. Если они для соискателя очень простые, то хочется копнуть глубже и понять на сколько хороши его знания. Как правило, положительное решение по кандидатам, дошедших до этой части вопросов, у меня формировалось еще в середине собеседования.</ol>
<p>Первую версию вопросов я подготовил уже на следующий день. Вопросы готовил с той мыслью, что по окончании собеседования у меня должно быть четкое понимание готов ли я работать с этим человеком или нет, никаких сомнений быть не должно.</p>
<p>По началу после 1-2 собеседований я корректировал часть вопросов — некоторые вопросы были не понятны соискателям (криво составлены мной), некоторые я просто заменял, считая, что новые лучше подойдут для собеседования. В результате у меня сформировался список вопросов, с которым я ходил на каждое собеседование.</p>
<p>Для начала человек должен был ответить на 2 простых вопроса из 1-й части:</p>
<ol>
<li> <strong>jQuery</strong>
<ul>
<li>выбрать элементы с атрибутом id=&#8221;myID&#8221;</li>
<li>выбрать элементы с атрибутом class=&#8221;myClass&#8221;</li>
<li>выбрать все input&#8217;ы с атрибутом id=&#8221;myID&#8221;, которые находятся внутри &lt;div class=&#8221;myClass&#8221;&gt;</li>
</ul>
</li>
<li><strong>Javascript</strong>
<p>Необходимо выполнить команду alert(’!’) перед отправкой данных формы нажатием кнопки &#8220;ОК&#8221;.</p>
<p>Какой из перечисленных фрагментов кода позволит решить поставленную задачу?</p>
<ul>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;"> &lt;FORM ACTION=&quot;test.pl&quot; onSubmit=&quot;alert(’!’)&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;submit&quot; VALUE=&quot;OK&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;FORM ACTION=&quot;test.pl&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;button&quot; VALUE=&quot;OK&quot; onClick=&quot;alert(’!’);this.submit()&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;FORM ACTION=&quot;test.pl&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;submit&quot; VALUE=&quot;OK&quot; onSubmit=&quot;alert(’!’)&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;FORM ACTION=&quot;test.pl&quot; onBeforeSubmit=&quot;alert(’!’)&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;submit&quot; VALUE=&quot;OK&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
</ul>
</li>
<p>На эти вопросы, думаю, ответит каждый web-программист. Далее я переходил к следующей части вопросов, которые должны были показать на сколько человек опытен:</p>
<li> <strong>Memcached</strong>. Что это такое? В каких случаях применяется?</li>
<p>Здесь я также просил рассказать соискателя вообще о кэшировании: как устроена система кэширования? Что обычно кэшируют? Когда кэширование не применимо?</p>
<p>Подавляющее большинство было знакомо с кэшированием, но никогда не слышали про memcached, и рассказывали о хранении кэша в файлах. В основном соискатели использовали кэширование только результатов SQL-запросов.</p>
<li> Что такое <strong>паттерн проектирования singleton</strong> и как он реализуется?</li>
<p>Стандартный ответ на этот вопрос был такой: «Я слышал про singleton, применяется в ООП, но как реализуется и для чего нужен не помню». Примерно каждый 4-й полностью отвечал на этот вопрос.</p>
<li> Командная строка *nix. Напишите команду, которая убьет все процессы, начинающиеся на «proc».</li>
<p>Из всех кандидатов на этот вопрос правильно ответили 2 человека. В основном все сразу говорили, что с командной строкой не особо знакомы, знают несколько команд, но не более.</p>
<li> Зачем нужен <em>HAVING в SQL</em>?</li>
<p>Для меня это было удивительно, но на этот вопрос правильно ответили лишь человека 2-3. Когда я включал этот вопрос в свой список, у меня были сомнения нужен ли он вообще, но, как оказалось, очень даже нужен и показывает опыт работы с SQL.</p>
<p>После этого один вопрос на теорию, здесь же я пытался выяснить, как человек будет справляться с задачами проектирования.</p>
<li> Что такое <em>нормализация БД</em>? Что такое <em>денормализация БД</em>? Для чего она нужна?</li>
<p>Здесь пополам, кто-то отвечал, кто-то нет. Почти каждого, особенно тех, кто не помнил или не слышал этих слов, после этого вопроса я просил набросать структуру БД для хранения товаров интернет-магазина, у каждого товара может быть от одного и более разделов.</p>
<li> Расскажите о способах хранения <strong>деревьев в таблице</strong>? Например, когда нужно реализовать <strong>древовидные комментарии</strong> к статье.</li>
<p>Большинство отвечали стандартно — у каждого комментария есть поле parent_id и т.д. Некоторые были знакомы с различными методами хранения деревьев, а были люди, которые прямо на собеседовании придумывали эти методы.</p>
<p>Далее следовали вопросы по составлению запросов SQL. Я не задавал ни одного сложного запроса, все они были простые, для правильного ответа требовалось только знание SQL.</p>
<li>Имеется таблица пользователей следующей структуры:

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> users <span style="color: #66cc66;">&#40;</span> 
id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">,</span>
username CHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
city_id INT<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> 
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<ul>
<li>id &#8211; целочисленный первичный ключ последовательной нумерации</li>
<li>username &#8211; логин пользователя</li>
<li>city_id &#8211; город проживания пользователя</li>
</ul>
<p>Необходимо выбрать города, в которых проживает не менее n пользователей</li>
<li>Имеется таблица для хранения информации о посещениях страниц пользователями:

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`page_visit`</span> <span style="color: #66cc66;">&#40;</span>
<span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`user_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`page`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`date`</span> datetime <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span></pre></td></tr></table></div>

<p>Необходимо вывести:</p>
<ol type="a">
<li> последних 10 пользователей, посетивших страницу «/about/»</li>
<li> всех пользователей, посетивших страницу «/about/», с указанием следующих данных:
<ul type="square">
<li>ID пользователя</li>
<li>Количество посещений страницы</li>
<li>Время первого посещения страницы</li>
<li>Время последнего посещения страницы</li>
</ul>
</li>
</ol>
</li>
<li>Есть 2 таблицы:

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> users <span style="color: #66cc66;">&#40;</span>
id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span>
username CHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> user_email <span style="color: #66cc66;">&#40;</span>
id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">,</span>
user_id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
email CHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p>Необходимо вывести все email&#8217;ы пользователей, а также их логины.</li>
<p>Далее был вопрос для тех, кто без особых проблем справился со всеми предыдущими:</p>
<li> Пользовались telnet? Напишите, как при при помощи telnet обратиться к главной странице example.com.</li>
<p>На этот вопрос ответил только один человек из всех соискателей. Кстати, он был сисадмином и решил переквалифицироваться в web-программиста.</ol>
<p>Для последней части, возможно, следовало бы придумать вопросов побольше, но у меня так и не дошли руки до этого, да и задавать их пришлось всего раза 2-3.</p>
<p>Помимо этих вопросов, некоторых соискателей по ходу собеседования я спрашивал о том, с какими <em>фреймворками</em> они работали, работали ли с <em>системами контроля версий</em> (<em>svn</em>, <em>cvs</em>, <em>git</em>), смогут ли настроить web-сервер (<em>nginx</em>, <em>apache</em>).</p>
<p>В итоге мне пришлось провести около 20-ти собеседований, после которых в нашу компанию были взяты на работу 2 программиста. Мне удалось выполнить поставленную цель: один программист — начинающий, сейчас он учится и растет каждый день  нереальными темпами, второй программист — уже поработавший в нашей профессии достаточно времени и в данный момент решает наши повседневные задачи самостоятельно и без чьей-либо помощи, он в ней и не нуждается.</p>
<p>На мой взгляд, все вопросы, которые я задавал, были довольно простыми. Я считаю, что не покажет человек в полной мере своих знаний, если его бомбить <strong>сложными вопросами на собеседовании</strong>.</p>
<p>Мне даже известны случаи, когда сложные вопросы только мешали правильному пониманию возможностей человека. Рассказывал один знакомый, который любит выносить мозг соискателю на собеседовании: к ним приходил человек, ответивший на очень сложный вопрос, вся их команда была удивлена этому факту. В итоге его взяли, а потом пришлось уволить, т.к. этот новый сотрудник начал просто разрушать их проекты своим качеством кода, неправильным подходом в самом начале задачи. Проще говоря, за ним нужен был глаз да глаз, что не входило в планы команды.</p>
<p>Простые вопросы сразу дают ответ, знает человек тот или иной вопрос или нет. Для ответа на сложные вопросы, как правило, необходимо обладать знаниями из разных областей, да еще надо пораскинуть мозгами и правильно применить эти знания — нет четкого понимания о знании или незнании конкретного вопроса, а это мешает правильно оценить человека.</p>
<p>Сложные вопросы требуют много времени на ответ, кроме того такими вопросами можно довести кандидата до того состояния, когда он уже не в готов ответить даже на то, что знает. Этим можно пропустить, возможно, неплохого программиста в будущем.</p>
<p>Итак, мой вывод: на <strong>собеседовании</strong> нужно задавать только <strong>простые вопросы</strong>, <strong>сложным вопросам</strong> тут не место. Этим я и руководствовался, общаясь с программистами, теперь по истечении времени я понимаю, что такое собеседование в моем случае оказалось правильным, т.к. своих целей я добился.</p>
<p>А что вы думаете о простых и сложных <strong>собеседованиях для программистов</strong>? Каким оно должно быть?</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/290/feed</wfw:commentRss>
		<slash:comments>194</slash:comments>
		</item>
		<item>
		<title>Хочу открыть интернет-магазин</title>
		<link>http://job-interview.ru/articles/post/271</link>
		<comments>http://job-interview.ru/articles/post/271#comments</comments>
		<pubDate>Sun, 30 May 2010 13:31:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Интернет-коммерция]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[интернет-магазин]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">/articles/?p=271</guid>
		<description><![CDATA[
Наверное, многие, проработав определенное время в какой-то отрасли, приходят к мыслям о том, что нужно попробовать что-то свое. С некоторых пор такие мысли стали посещать и меня.


Я web-программист, проработал уже достаточное время на этой должности и, честно говоря, порядком подустал. К тому же я не вижу каких-то особых перспектив, к которым мне хотелось бы стремиться.


Нет, [...]]]></description>
			<content:encoded><![CDATA[<p>
Наверное, многие, проработав определенное время в какой-то отрасли, приходят к мыслям о том, что нужно попробовать что-то свое. С некоторых пор такие мысли стали посещать и меня.
</p>
<p>
Я <strong>web-программист</strong>, проработал уже достаточное время на этой должности и, честно говоря, порядком подустал. К тому же я не вижу каких-то особых перспектив, к которым мне хотелось бы стремиться.
</p>
<p>
Нет, они, конечно, есть. Программист перерастает в руководителя группы, потом в руководителя отдела, возможно, потом еще в кого-то, потом «потолок». Кого-то может такая ситуация устраивает, но она не для меня.
</p>
<p>
И я решил, что нужно открывать свое дело, где ты работаешь только на себя, получаешь столько денег, сколько заработал сам. Вот здесь открываются огромные перспективы. Они мне интересны, хочется стремиться к поставленным для себя целям.
</p>
<p>
Для начала я посоветовался со своими друзьями, перечитал не мало статей про различные  <a href="http://moyevro.ru/category/vidy-zarabotka/" title="виды заработка в интернете">виды заработка</a> для программиста. И вот какие выводы я для себя сделал:
</p>
<blockquote><p>
Где web-программист может проявить себя самостоятельно? </p>
<ul>
<li>
Фриланс.
</li>
<p>
Возможно, стоило бы попробовать, но все-таки по рассказам знакомых фрилансеров больших денег там не заработаешь. Особенно первое время придется усиленно экономить. Да и все же это не совсем работа на себя, а работа на заказчика.
</p>
<li>
Web-студия.
</li>
<p>
Для ее открытия нужен какой-то стартовый капитал, которого у меня нет. Кроме того, большие риски, что вложенные на начальном этапе средства так и не окупятся. Опять же в этом варианте присутствуют заказчики, на которых тебе придется вкалывать.
</p>
<li>
Интернет-магазин.
</li>
<p>На данный момент самый подходящий для меня вариант. Его я и выбрал.</p>
</ul>
</blockquote>
<p><span id="more-271"></span></p>
<h2>Почему я хочу открыть интернет-магазин?</h2>
<p>
<img style="padding: 10px" src="/img/shop_1.jpg" align="left" alt="Почему я хочу открыть интернет-магазин?" title="Почему я хочу открыть интернет-магазин?"><br />
Устал от работы на дядю, надоели начальники, которые вечно самоутверждаются за счет своих подчиненных.
</p>
<p>Ситуацию можно описать известной фразой: «Я начальник, ты дурак, ты начальник, я дурак». Причем как-то получается так, что «дураком» ты становишься автоматически, независимо от объема твоих знаний, опыта и т.д. Начальник все равно знает больше, чем ты, только он может принять единственно верные решения.</p>
<p>
Кто-то может сказать: «Все правильно, он прошел свой путь, начиная простым программистом, набрался опыта, поднялся по карьерной лестнице и, конечно же, он будет обладать большими знаниями».
</p>
<p>
Если он бывший программист, то да, я согласен. Однако, очень часто в роли начальников выступают совсем не программисты, а менеджеры, которые считают, что разбираются в твоей области гораздо лучше, чем ты, а все программисты — это обычные кодеры, которые реализовывают их гениальные идеи.
</p>
<p>
Найдется ли такой программист, который никогда не попадал на такой диалог?<br />
<em> &#8211; Сколько займет времени, чтобы это сделать?</em> <br />
<em> &#8211; Думаю, что где-то полдня нужно будет.</em> <br />
<em> &#8211; Почему так долго? Здесь же просто кнопку поставить.</em> 
</p>
<p>
Дальше ты начинаешь пытаться как-то объяснить, почему это занимает столько времени, но понимаешь, что то, что ты говоришь, человеку все равно не понятно. Да и занятие это бесполезное, но какой может быть другой выход, если тебе задают подобный вопрос.
</p>
<p>
В ответ на твои объяснения ты получаешь примерно следующую фразу: «<em>Ну не знаю, мне кажется, что все равно это очень долго</em>».
</p>
<p>
Кроме того, много денег при работе на кого-то не заработаешь. Все равно есть потолок.
</p>
<p>
Доход от интернет-магазина будет зависеть только от тебя и от его развития. Теоретически предела доходам здесь нет.
</p>
<p>
Еще одна причина, по которой я хочу начать свое дело — устал от работы в коллективе. Возможно, эта причина относится только ко мне, а может и нет.
</p>
<p>
На мой взгляд, каждому коллективу присуща определенная доля лживости. Вроде как все говорят: «Мы вместе, мы одна команда». Все друг другу улыбаются, все друзья, все классно. Однако, это только на поверхности.
</p>
<p>
Как люди могут быть друзьями, когда они всеми силами стараются показать себя выше других, чтобы начальство их заметило? А этим приходится заниматься, все ведь хотят продвинуться вверх по службе.
</p>
<p>
Коллективу часто приходится объяснять начальству, почему не выдерживаются сроки в том или ином проекте. А начальству важно знать, кто конкретно тормозит проект. В таких ситуациях приходится закладывать кого-то из своих «друзей».
</p>
<p>
Когда в коллективе решают, кому конкретно доверить очередной проект, тут то и выясняется, чьи знания и опыт ценят, а чьи нет.
</p>
<p>
Но ведь на поверхности то все равны, все сотрудники одинаково ценятся.
</p>
<p>
В общем эта как-бы «дружба» не для меня. Чисто с психологической точки зрения я бы себя чувствовал спокойнее, занимаясь своим делом и не отвлекаясь на всякие закулисные склоки.
</p>
<h2>А что продавать?</h2>
<p>
<img style="padding: 10px" src="/img/shop_2.jpg" align="right" alt="А что продавать?" title="А что продавать?"><br />
Вот это очень трудный и самый важный вопрос на начальном этапе. На данный момент в интернете можно купить почти все. Конкуренты есть везде. Но выбирать что-то нужно.
</p>
<p>Я для себя определил следующие критерии моего будущего товара:</p>
<ul>
<li>
Он должен быть легким, чтобы не было проблем при доставке.
</li>
<li>
Его стоимость не должна быть очень низкой. Большого объема заказов в первое время не предвидится, поэтому даже один заказ должен приносить более менее приличную сумму (не 1 рубль, а, скажем, 200).
</li>
<li>
Он должен быть приспособлен для интернета. Например, продавать продукты питания через интернет, на мой взгляд, не самая лучшая идея. Все-таки некоторые товары люди хотят «пощупать», когда его выбирают.
</li>
<li>
В идеале этот товар должен быть интересен мне, чтобы я мог иметь какое-то мнение по нему. Тогда я бы мог составлять описания к товарам, а это поможет продвижению в поисковиках.
</li>
</ul>
<p>
Осталось теперь найти товар, удовлетворяющий этим моим критериям. Пока я нахожусь в поиске.
</p>
<p>
Под эти пункты очень подходят книги, но здесь очень высока конкуренция, поэтому их я не рассматриваю.
</p>
<p>
<strong>Определиться с товаром</strong> — это одна проблема. Решив ее, придется еще <strong>найти поставщиков</strong>, которые готовы этот товар поставлять. Кроме того, т.к. у меня нет никакого <em>начального капитала</em>, то закупать товар оптом я не смогу. Поэтому нужно найти поставщика, который будет готов поставлять товар по факту заказа. Т.е. мне представляется следующая схема: мне пришел заказ, я еду к поставщику, забираю у него товар, доставляю товар клиенту.
</p>
<p>
Найти такого поставщика будет нелегкой задачей, но все же она должна быть решаема. Делаю такой вывод, основываясь на различные статьи в блогах, где люди на начальных стадиях сталкивались с такой проблемой и находили выход.
</p>
<p>
Итак, товар выбран, поставщик найден. Чем мой магазин будет отличаться от других? Нужно придумать <strong>уникальное торговое предложение</strong> (УТП). Возможно, в моем магазине цены будут ниже, чем у конкурентов, возможно, что-то еще, но клиента нужно будет чем-то зацепить, чтобы, совершив один раз покупку у меня, он вернулся ко мне же за следующей.
</p>
<p>
На эту тему я пока даже не думаю, сначала надо определиться с товаром.
</p>
<h2>Планы</h2>
<p>
<img style="padding: 10px" src="/img/shop_3.jpg" align="left" alt="Планы" title="Планы"><br />
Перед открытием магазина я <strong>зарегистрирую ИП</strong>. Скорее всего воспользуюсь услугами какого-нибудь агентства, но, похоже, что даже в этом случае придется помотаться по всяким гос. учреждениям. Ну а что делать, без этого в нашей стране никуда.
</p>
<p>
Еще думаю, что может сначала не писать навороченный магазин, а сделать просто <strong>список товаров</strong> и рядом номер телефона. Посмотрю, как пойдут заказы. Если будет все хорошо, то доработаю до приличного магазина.
</p>
<p>
С другой стороны, все говорят о <em>дружелюбном интерфейсе</em> для покупателей, что чуть ли это не самое главное. Ну в общем это я еще решу, просто не хотелось бы тратить время, если в итоге магазин не оправдает моих надежд.
</p>
<p>
Да, еще планирую обзавестись прямым номером на свой мобильный. Оставлять 10-значный номер телефона на сайте, как мне кажется, будет выглядеть не серьезно.
</p>
<p>
Доставкой буду заниматься первое время сам. Придется как-то совмещать с текущей работой, но это, надеюсь, продлится не долго, т.к. за первые 1-2 месяца станет более менее понятно, что получится из магазина в итоге.
</p>
<p>
Если заказов будет не мало, то возьму отпуск, может даже за свой счет.
</p>
<p>
Моя первоначальная цель — достичь дохода от магазина, равного половине моей текущей зарплаты. Если добьюсь этого, то планирую уволиться, а часть денег зарабатывать на <em>фрилансе</em>. В итоге мой месячный доход будет равен текущему доходу на постоянной работе.
</p>
<p>
Давно хочу изучить <em>язык программирования python</em> и <em>фреймворк django</em>. Как раз мой магазин поможет мне в этом. Даже, если ничего путного не выйдет, то, как минимум, будет опыт программирования на python.
</p>
<p>
Ну вот вроде и все. Я хотел в этой статье поделиться своими мыслями и планами по поводу открытия своего <strong>интернет-магазина</strong>. Как только приступлю к реализации этих планов, поделюсь полученным опытом в следующей статье.
</p>
<p>
Жду любых ваших мнений в комментариях.
</p>
<p>
Также интересно было бы узнать мнение программистов, которые уже прошли путь <strong>открытия своего бизнеса</strong> (не обязательно интернет-магазин).</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/271/feed</wfw:commentRss>
		<slash:comments>346</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>5538</slash:comments>
		</item>
		<item>
		<title>Вопросы на собеседовании для PHP-программиста (часть 1)</title>
		<link>http://job-interview.ru/articles/post/12</link>
		<comments>http://job-interview.ru/articles/post/12#comments</comments>
		<pubDate>Tue, 30 Jun 2009 19:49:54 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[вопросы]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/?p=12</guid>
		<description><![CDATA[С некоторых пор я решил записывать все задаваемые мне вопросы на собеседованиях.
В этой статье хотел бы поделиться ими с аудиторией job-interview. За весь мой опыт прохождения собеседований вопросов набралось немало. Во всяком случае на одну статью не хватит, поэтому здесь я выложу часть из них. Остальные вопросы буду выкладывать в последующих статьях.


Я являюсь PHP-программистом, поэтому [...]]]></description>
			<content:encoded><![CDATA[<p>С некоторых пор я решил записывать все задаваемые мне <strong>вопросы на собеседованиях</strong>.<br />
В этой статье хотел бы поделиться ими с аудиторией <em>job-interview</em>. За весь мой опыт <em>прохождения собеседований</em> вопросов набралось немало. Во всяком случае на одну статью не хватит, поэтому здесь я выложу часть из них. Остальные вопросы буду выкладывать в последующих статьях.
</p>
<p>
Я являюсь <em>PHP-программистом</em>, поэтому все вопросы будут из этой области.<br />
На собеседовании работодатели обычно разделяют их по следующим темам:</p>
<ul>
<li><strong>PHP</strong></li>
<li><strong>Задачи по составлению различных запросов SQL</strong></li>
<li><strong>Администрирование СУБД</strong> (обычно это <em>MySQL</em>)</li>
<li><strong>Основные принципы ООП</strong></li>
<li><strong>Регулярные выражения</strong></li>
<li><strong>Основные протоколы интернета</strong></li>
<li><strong>Работа в командной строке Linux</strong></li>
</ul>
<p>Итак, начнем.</p>
<h3>PHP</h3>
<blockquote>
<div style="padding-left: 23px">
<p>1.&nbsp;&nbsp;Имеется <em>массив</em> целых чисел, все числа кроме одного встречаются в массиве дважды. Необходимо реализовать функцию поиска числа, встречающегося в массиве один раз.</p>
<p>2.&nbsp;&nbsp;</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</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;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$i</span> <span style="color: #339933;">+=</span> <span style="color: #339933;">++</span><span style="color: #000088;">$i</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++;</span>
<span style="color: #b1b100;">print</span> <span style="color: #000088;">$i</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Сколько выведет? Почему?</p>
<p >3.&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
</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: #000000; font-weight: bold;">class</span> ListItem <span style="color: #009900;">&#123;</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$next</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$a</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ListItem<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$b</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ListItem<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$c</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ListItem<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$a</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$b</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$b</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$c</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$c</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Необходимо написать функцию, которая на вход получает объект $а, а возвращает перевернутый список.</p>
<p>4.&nbsp;&nbsp;Как реализовать <em>множественное наследование в PHP</em>?</p>
<p>5.&nbsp;&nbsp;Чем отличается <em>наследование в javascript</em> от наследования в PHP?</p>
</div>
</blockquote>
<h3>Запросы SQL</h3>
<blockquote>
<ol>
<li>Есть таблица currency_course, в которой перечислены курсы валют за конкретную дату.<br />
	Поля таблицы currency_course: <br />currency (тип валюты — USD, EUR и т.д.), <br />date (дата установленного курса), <br />course (курс валюты)<br />
	<br />Требуется выбрать последние курсы по каждой валюте.</li>
<li>В таблице 1 000 000 записей. Необходимо предложить варианты выбора 10 случайных записей. Запрос вида select * from table order by rand() limit 10 не подойдет, т.к. очень «тяжелый».</li>
<li>В таблице 1 000 000 записей. Есть поле, которое принимает только одно из двух значений. Стоит ли индексировать по этому полю?</li>
<li>Необходимо предложить структуру базы данных для хранения <em>древовидных комментариев</em>.</li>
<li>Имеется таблица покупателей с полями: id, name<br />
А также таблица продаж: id, cust_id, date, summ_pay<br />
Необходимо:<br />
а) Вывести лучшего покупателя.<br />
б) Вывести лучших покупателей за каждый месяц.</li>
</ol>
</blockquote>
<p>Пока все. Продолжение следует&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/12/feed</wfw:commentRss>
		<slash:comments>181</slash:comments>
		</item>
		<item>
		<title>Нужны ли логические задачи на собеседовании?</title>
		<link>http://job-interview.ru/articles/post/7</link>
		<comments>http://job-interview.ru/articles/post/7#comments</comments>
		<pubDate>Sun, 28 Jun 2009 11:51:16 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[вопросы]]></category>
		<category><![CDATA[задачи]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/?p=7</guid>
		<description><![CDATA[Не так давно я занялся поисками работы на должность web-программиста. Скажу сразу, что мой опыт работы в этой области составляет 2 года. Я просмотрел все имеющиеся вакансии в интернете, разослал свое резюме.
Ответ не заставил себя долго ждать, уже через 2 дня меня пригласили на собеседование.
В вакансии от соискателя требовался стандартный набор навыков:

PHP
MySQL
JavaScript
ООП

Думаю каждый web-разработчик обладает [...]]]></description>
			<content:encoded><![CDATA[<p>Не так давно я занялся <em>поисками работы</em> на должность <strong>web-программиста</strong>. Скажу сразу, что мой опыт работы в этой области составляет 2 года. Я просмотрел все имеющиеся <em>вакансии в интернете</em>, разослал свое резюме.</p>
<p>Ответ не заставил себя долго ждать, уже через 2 дня меня пригласили на <strong>собеседование</strong>.<br />
В вакансии от соискателя требовался стандартный набор навыков:</p>
<ul>
<li><em>PHP</em></li>
<li><em>MySQL</em></li>
<li><em>JavaScript</em></li>
<li><em>ООП</em></li>
</ul>
<p>Думаю каждый <strong>web-разработчик</strong> обладает этими навыками. Однако времени на подготовку и повторение всего того, что я знаю, у меня совсем не было, да и на первое собеседование я шел скорее с целью &#8220;разведать обстановку&#8221; — какие <strong>вопросы на собеседованиях</strong> сейчас задают я совершенно не знал.</p>
<p>Интерес к этой вакансии у меня был огромный &#8211; в описании к ней было указано, что компания работает в игровой индустрии и производит различные MMORPG и <a href="http://igruli.com.ua/">flash игры</a>, а к играм я с детства неравнодушен.</p>
<p>Добираясь до офиса я прокручивал у себя в голове все возможные вопросы, которые мне могут задать. Мысленно я для себя готовил ответы на различные вопросы, связанные с тем, что было перечислено в вакансии.</p>
<p>Придя в офис, меня сразу же направили к старшему программисту, который должен был проводить со мной собеседование. Усадили меня прямо за его столом и сказали немного подождать. Когда он пришел, то к моему удивлению предложил мне 2 <strong>задачи на логику</strong> и дал 10 минут на их решение.</p>
<p>Привожу эти <strong>задачи с собеседования</strong>.</p>
<blockquote>
<ol>
<li>В стакан положили бактерии. Каждую секунду бактерии увеличиваются в 2 раза. Известно, что стакан заполняется полностью за минуту. За какое время стакан наполнится наполовину?</li>
<li>Представьте себе, что земной шар обмотали веревкой по экватору. Потом веревку увеличили на 1 метр и расположили так, что любая точка экватора равноудалена от веревки. Сможет ли между веревками пролезть мышь?</li>
</ol>
</blockquote>
<p>Вообще в школе и в университете у меня с математикой проблем не было, поэтому не думал, что задачи вызовут какие-то проблемы. Однако, за отведенное время я их не решил.</p>
<p>По моему 10 минут — это слишком мало для таких задач, тем более на собеседовании, где человек в любом случае волнуется.</p>
<p>Понятно, что это <strong>задачи с подвохом</strong> на проверку сообразительности и работодатель тем самым хочет отсеить простых кодировщиков, которые программируют не думая ни о каких алгоритмах. К кодировщикам я себя не отношу.</p>
<p>Придя домой, я решил их и потратил на поиски решения примерно час.</p>
<p>Первая задача очень понравилась, к ней как бы надо подойти с особой стороны.<br />
Вторая — это просто обычная математика, решается применением всем известных формул.<br />
Понятно, что собеседование я не прошел, хотя на вопросы, связанные с <em>программированием</em> отвечал довольно неплохо.</p>
<p>После этого собеседования у меня возникли следующие <em>вопросы</em>:</p>
<ul>
<li>Достаточное ли время 10 минут, чтобы решить такие задачи?</li>
<li>Кому бы этого времени хватило?</li>
<li>Вообще нужны ли <strong>каверзные вопросы</strong> на проверку логики на собеседовании, ведь никто не даст соискателю достаточное время на поиски решения?</li>
</ul>
<p>Также жду <strong>варианты решений задач</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/7/feed</wfw:commentRss>
		<slash:comments>1024</slash:comments>
		</item>
		<item>
		<title>Добро пожаловать на сайт, посвященный поиску работы для программистов.</title>
		<link>http://job-interview.ru/articles/post/1</link>
		<comments>http://job-interview.ru/articles/post/1#comments</comments>
		<pubDate>Mon, 15 Jun 2009 14:12:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Проект Job-Interview.ru]]></category>
		<category><![CDATA[job-interview.ru]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[проект]]></category>

		<guid isPermaLink="false">http://jo-in.ru/blog/?p=1</guid>
		<description><![CDATA[Предполагаемая аудитория &#8211; это люди, занимающиеся web-разработками, системным программированием и всем тем, что связано с IT.
Нашей целью является объединить людей этой профессии для оказания помощи друг другу в прохождении собеседования, составлении резюме, накоплении знаний. 
В разделе &#8220;Вопросы на собеседовании&#8221; мы будем выкладывать самые распространенные вопросы, которые задает работодатель соискателю, откликнувшемуся на его вакансию программиста. Раздел [...]]]></description>
			<content:encoded><![CDATA[<p>Предполагаемая аудитория &#8211; это люди, занимающиеся <em>web-разработками</em>, <em>системным программированием</em> и всем тем, что связано с <em>IT</em>.</p>
<p>Нашей целью является объединить людей этой профессии для оказания помощи друг другу в <strong>прохождении собеседования</strong>, составлении резюме, накоплении знаний. </p>
<p>В разделе <a href="/questions/" title="Вопросы на собеседовании для программистов">&#8220;Вопросы на собеседовании&#8221;</a> мы будем выкладывать самые распространенные вопросы, которые задает работодатель соискателю, откликнувшемуся на его вакансию программиста. Раздел будет постоянно пополняться, сейчас в нем можно найти вопросы по <a href="/questions/php" title="Вопросы на собеседовании по PHP">PHP</a>, <a href="/questions/cpp" title="Вопросы на собеседовании по C++">C++</a>, <a href="/questions/dotnet" title="Вопросы на собеседовании по .NET">.NET</a> и <a href="/questions/database" title="Вопросы на собеседовании по базам данных">базам данных</a>.</p>
<p>В разделе <a href="/vacancy/" title="Вакансии для программистов">&#8220;Вакансии&#8221;</a> вы сможете найти самые свежие объявления от работодателей для программистов. Раздел обновляется несколько раз в день.</p>
<p>Мы также предлагаем вам проверить свои знания, посетив раздел <a href="/test/" title="Тесты для программистов">&#8220;Тесты&#8221;</a>. Зарегистрированные пользователи при желании могут <strong>разместить свой тест</strong>, который им предлагали пройти на собеседовании, а затем в личном кабинете следить за статистикой прохождения теста другими пользователями сайта.</p>
<p>В разделе <a href="/books/">&#8220;Книги&#8221;</a> собраны <strong>книги для программистов</strong>. Здесь можно найти литературу по самым разным IT-тематикам: <em>устройство компьютера</em> и <em>работа с &#8220;железом&#8221;</em>, <em>языки программирования</em> и <em>алгоритмы</em>, <em>компьютерные сети</em>, а также многое другое. </p>
<p>Если вы опытный <strong>программист</strong>:</p>
<div style="padding-left: 10px">На нашем сайте вы можете рассказывать о своем опыте прохождения собеседований, выкладывать различные <em>вопросы</em>, на которые вам приходилось отвечать, а также делиться знаниями с пока менее продвинутыми коллегами. Для этого в разделе <a href="/articles">&#8220;Статьи&#8221;</a> мы предлагаем вам выкладывать свои соображения по всем вышеперечисленным вопросам.</div>
<p>Если вы начинающий <strong>программист</strong>:</p>
<div style="padding-left: 10px">Вы получаете возможность общаться и набираться знаний. Задавайте свои вопросы и советуйтесь с теми, кто уже сталкивался с вашими проблемами.</div>
<p>
Итак, </p>
<ul>
<li>если вы готовитесь к собеседованию или вам просто интересно узнать о самых распространенных <strong>вопросах на собеседовании</strong>, то вам <a href="/questions/">сюда</a>.</li>
<li>если вы в поисках работы, то посетите раздел <a href="/vacancy/" title="Вакансии для программистов">Вакансии для программистов</a>, в котором всегда самые свежие предложения от работодателей.</li>
<li>если вам есть, что рассказать, или вы хотели бы получить ответ на какой-либо вопрос от более опытных коллег, вам <a href="/articles">сюда</a>.  Вы также можете <strong>разместить свою статью</strong>, для этого необходимо будет пройти простую процедуру <a href="/articles/login?action=register">регистрации</a>.</li>
<li>если вы хотите проверить свои знания, то вам в раздел <a href="/test/" title="Тесты для программистов">Тесты для программистов</a>.</li>
</ul>
<p>
Присоединяйтесь к нашей <a target="_blank" href="http://vkontakte.ru/club17930164" rel="external nofollow">группе Вконтакте</a>.<br />
<a target="_blank" href="http://vkontakte.ru/club17930164" rel="external nofollow"><br />
<img border="0" src="/img/vkontakte.jpg"><br />
</a>
</p>
<p>Следите за нашими вакансиями в <a title="Следите за нашими вакансиями в Twitter" rel="external nofollow" href="http://twitter.com/jobinterview_ru" target="_blank">Twitter</a> <a title="Следите за нашими вакансиями в Twitter" rel="external nofollow" href="http://twitter.com/jobinterview_ru" target="_blank" style="text-decoration: none;">&nbsp;<img border="0" src="/img/Twitter_32x32.png"></a></p>
<p>Желаем удачи,<br />
 Команда Job-Interview.ru</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/1/feed</wfw:commentRss>
		<slash:comments>8328</slash:comments>
		</item>
	</channel>
</rss>
