<?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>Работа для  программистов</title>
	<atom:link href="http://job-interview.ru/articles/feed" rel="self" type="application/rss+xml" />
	<link>http://job-interview.ru/articles</link>
	<description>вакансии, вопросы, статьи</description>
	<lastBuildDate>Sun, 27 Nov 2011 16:31:28 +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>Программист на фрилансе</title>
		<link>http://job-interview.ru/articles/post/332</link>
		<comments>http://job-interview.ru/articles/post/332#comments</comments>
		<pubDate>Tue, 31 May 2011 19:51:38 +0000</pubDate>
		<dc:creator>Pablo Monteagudo</dc:creator>
				<category><![CDATA[Фриланс]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[фриланс-биржи]]></category>

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

В этой статье я хочу описать свой опыт работы на фрилансе.

Что за фриланс?

Может быть есть люди, которые не знают, что такое фриланс? &#8220;Freelance&#8221; буквально переводится как &#8220;внештатно&#8221;, соответственно &#8220;freelancer&#8221; — &#8220;внештатный сотрудник&#8221;. Обычно это подразумевает поиск заказов через интернет, выполнение их дома за компьютером (хотя некоторые ловко трудятся во время основной работы   ) [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/img/fl_sait_1000_rub.jpg" style="float:left;margin-right:5px;width:260px;" title="Сделаю сайт за 1000 рублей" /></p>
<p>
В этой статье я хочу описать свой опыт работы на фрилансе.
</p>
<h3>Что за фриланс?</h3>
<p>
Может быть есть люди, которые не знают, что такое <b>фриланс</b>? <i>&#8220;Freelance&#8221;</i> буквально переводится как &#8220;внештатно&#8221;, соответственно <i>&#8220;freelancer&#8221;</i> — &#8220;внештатный сотрудник&#8221;. Обычно это подразумевает поиск заказов через интернет, выполнение их дома за компьютером (хотя некоторые ловко трудятся во время основной работы <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ) и оплату выполненной работы через интернет. Существуют специальные сайты — фриланс-биржы — на которых происходит общение заказчиков, имеющих какие-либо задания, и исполнителей, готовых эти задания выполнить.
</p>
<p><span id="more-332"></span></p>
<h3>А зачем это нужно?</h3>
<p>
Наверное каждый программист замечал, что работая постоянно, у него не хватает времени заниматься какими-то своими проектами. А различные идеи периодически приходят, и думаешь: &#8220;Вот было бы время, обязательно бы это реализовал&#8221;. Да и на работе бывают времена, что приходится заниматься неинтересными делами. Тем более в мои планы не входило всю жизнь работать &#8220;на дядю&#8221;, рано или поздно пришлось бы уходить на вольные хлеба, и во время особо скучного периода на тогдашней постоянной работе я и решил это сделать.
</p>
<p>
Для начала я решил закрепиться на <b>фриланс-биржах</b>, чтобы в случае чего всегда можно было бы заработать денег, невзирая на текущую жизненную ситуацию, был бы под рукой ноутбук и интернет. К тому же всегда есть из чего выбрать: захотел делать сайт — вперед, захотел написать скрипт — флаг в руки, надоел язык программирования — меняй, никто не запрещает.
</p>
<h3>Биржи? Биржи. Биржи&#8230;</h3>
<p>
Фриланс-бирж существует множество, как российских, так и зарубежных, в итоге я зарегистрировался на трех — <i>freelancer.com</i>, <i>free-lance.ru</i> и <i>weblancer.net</i>.
</p>
<p><img src="/img/fl_ows_f.png" style="float:left;width:200px;margin-right:3px;" /></p>
<p>
freelancer.com я выбрал, так как прочитал довольно интересную статью, описывающую прелесть работы на ней. Здесь я решил представиться веб-студией, по идее такой подход вызывает больше доверия у заказчиков, придумал &#8220;конторе&#8221; название, сделал простенький логотип, зарегистрировался и начал осматриваться.<br />
Если описать в общем, сайт представляет собой типичную фриланс-биржу &#8211; страницы разделов по возможным IT-работам, например создание сайтов &#8220;под ключ&#8221;, создание дизайнов, работа с различными CMS, написание скриптов, системное администрирование и т.д. Заказчик выбирает нужный ему раздел, создает проект, на который откликаются заинтересовавшиеся фрилансеры.
</p>
<p>
На freelancer.com ищут заказы очень много фрилансеров, среди которых немало выходцев из Азии. Качество работы большинства этих товарищей, как и знание английского языка, оставляет желать лучшего (кто не слышал про программистов-индусов <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ), но они берут ценами, иногда демпинг с их стороны вызывает даже не недоумение, а смех. Вполне реально найти &#8220;исполнителя&#8221; на сложный специфичный портал за сумму например 100$ и сроком исполнения 3 дня. И это предложение еще могут перебить!<br />
Естественно, есть и мастера своего дела, с высочайшим профессионализмом, большим опытом и умением подойти к клиенту.
</p>
<p>
К сожалению, на этом сайте мне так и не удалось получить ни одного заказа, наверное из-за окончательной переориентации на отечественный рынок. Свою роль сыграли и не очень удовлетворительный английский, и разница во времени с многими заказчиками.
</p>
<p>
Российские биржи, на которых я зарегистрировался — free-lance.ru и weblancer.net. free-lance.ru &#8211; самая известная из отечественных, держит первенство по количеству проектов и активных фрилансеров. Содержит много платных услуг, жизнь без которых затруднена, например не имея pro-аккаунта можно подавать только три заявки на понравившиеся проекты в сутки. Но таким ограничением страдают все биржи, которые я встречал. Впрочем это мне не очень мешало, с первых дней мне хотелось насладится преимуществом выбора интересных заданий. К сожалению, появлялись они не так часто, как хотелось бы, а при подаче заявки меня всегда обходили более опытные исполнители, с отзывами и более долгим временем нахождения на сайте.
</p>
<p><a href="/img/fl_dem_cust.jpg" target="_blank"><img src="/img/fl_dem_cust_sm.jpg" style="float:left;margin-right:5px;" /></a></p>
<p>
Про это стоит упомянуть подробнее. Практически все заказчики смотрят на количество отзывов, имеющихся у фрилансера, которые оставили прошлые работодатели. Хорошо выполнил работу — написали положительный, плохо, не выполнил или исчез — отритцательный. Наверное уже с 3-мя отритцательными отзывами лучше завести новый аккаунт, так же как и если первый отзыв — негативный. То же самое и с временем, прошедшим после регистрации, некоторые не доверяют людям, у которых оно меньше месяца. Сначала порой приходилось работать и <del>за еду</del> просто за отзыв.
</p>
<p>
Когда подходящий проект найден, встает задача, чтобы заказчик выбрал именно вас. Тут у каждого свой подход, кто-то просто называет цену и оставляет сообщение &#8220;пишите в личку&#8221;, кто-то строчит простыни текста, в подробностях расписывая все свои предыдущие достижения, кто-то выбирает нечто среднее. По-моему стоит писать, какие подобные задания уже приходилось выполнять и по-возможности дать понять, что понимаешь задание и чуть ли не начал его делать.
</p>
<p>
Но вот первый проект получен, наконец-то меня выбрали исполнителем! Обсудив все детали задания, пора начинать работать! Но, что все не так просто, стало понятно через пару проектов. ТЗ и детали нужно обговаривать ОЧЕНЬ подробно, выясняя все до последних мелочей, иначе дорабатывать и изменять казалось бы незначительные и неважные детали и наводить красоту по вкусу заказчика можно вечно, либо, неправильно поняв суть задания, вообще выбрать неверный путь решения задачи. Был случай, когда недели две работы потратились впустую из-за непонимания и несогласованности между мной и заказчиком, в итоге я потерял деньги, а клиент время, хорошо, что в результате разошлись мирно, без написания отритцательных отзывов друг другу.
</p>
<p>
И наконец, самый приятный момент — оплата. На всех биржах есть сервисы безопасных сделок, которые сделаны для того, чтобы ни работодатель, ни исполнитель не обманывали друг друга. Я ими не пользовался ни разу, предпочитая или доверять заказчику, получая деньги после выполнения задания, или беря предоплату. В подавляющем большинстве случаев оплата происходит с помощью вебмани или яндекс-денег.
</p>
<h3>Не биржей единой</h3>
<p>
Поиск заказов не ограничивается только биржами.<br />
У многих заказчиков постоянно появляются новые задания, и если ты хорошо выполнил одно, наверняка следующее также достанется тебе, плюс этот заказчик будет рекомендовать тебя своим знакомым, у которых возникла необходимость в привлечении стороннего сотрудника.<br />
Постепенно знакомые и бывшие коллеги узнают о твоей работе на фрилансе и заказы начинают приходить через них.<br />
Через некоторое время я перестал заходить на биржи и выполнял только подобные задания, потому что они скорее всего будут интересные, с заказчиком уже сложились более-менее неплохие отношения, почти нет недоверия и настороженности, как у тебя, что прокатят с деньгами, так и у него, что работа не будет выполнена.
</p>
<p>
Также не стоит забывать про свои задумки, отводить какое-то время на них, даже если пока ни одна из них еще не приносит какой-либо ощутимой отдачи, ведь это только пока <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Главное, что для них находится время.
</p>
<h3>Ожидания и реальность</h3>
<p><img src="/img/fl_good_bad.jpg" /></p>
<p>
Для кого-то работать дома в кайф, но я знал, что постоянно находиться в четырех стенах мне будет затруднительно, однако утешал себя мыслью, что можно будет выйти, например, в парк и работать там. Но на практике зарядки ноутбука хватает не намного времени, у нетбука маленький экран, а на лавке в парке с этими девайсами неудобно сидеть. Если еще вспомнить, каким жарким было лето 2010, то можно понять, как я завидовал людям, сидящим в прохладных офисах с кондиционерами, тогда как дома был только плохо спасающий от этого ада вентилятор.
</p>
<p>
Когда я начинал свой путь по дороге фриланса, то не строил иллюзий, что в первый же день клиенты выстроятся в очередь, но все же было неожиданно, что уцепиться за первый проект удалось только недели через две. Эта ситуация получилась и из-за того, что, как упоминалось ранее, я не откликался на неинтересные заявки, а ждал чего-то более привлекательного. Зато проект оказался интересным, довольно денежным и с хорошим заказчиком, которому впоследствии я выполнил еще несколько заданий.
</p>
<p>
По поводу рабочего времени происходило примерно так, как я и думал: то работы нет, то работать приходится по ночам, не говоря уже про выходные. Если на постоянной работе знаешь, что в субботу-воскресенье отдыхаешь, на фрилансе все смешивается и иногда удивляешься радости друзей о том, что завтра выходной.<br />
Можно безболезненно с утра покататься на велосипеде, посреди рабочего дня прерваться, например, на гантели или прогулку (это если нет срочной работы, конечно <img src='/articles/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  ).
</p>
<p>
Волнующий денежный вопрос. Честно говоря, когда я уходил на фриланс, то ожидал, что буду зарабатывать больше. Очень сложно назвать среднюю сумму заработка, в первые месяцы у меня выходило не более 10-15 тысяч ежемесячно.
</p>
<h3>Итого</h3>
<p>
Что же в итоге? Не жалею ли я о том, что ушел с постоянной работы на фриланс? Нет.<br />
Сейчас я частично (5 часов в день) работаю в офисе на постоянной работе, которая нашла меня через фриланс, остальное время практически полностью посвящаю своим делам, лишь иногда откликаясь на работу от постоянных заказчиков, приобретенных на фрилансе.
</p>
<p></p>
<p>
В заключение хочу выразить огромную благодарность своей девушке Саше, которая была со мной и  поддерживала меня все это время.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/332/feed</wfw:commentRss>
		<slash:comments>0</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>tiger</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>0</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>tiger</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>0</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>tiger</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>4</slash:comments>
		</item>
		<item>
		<title>CMS Битрикс. За и против.</title>
		<link>http://job-interview.ru/articles/post/234</link>
		<comments>http://job-interview.ru/articles/post/234#comments</comments>
		<pubDate>Thu, 04 Feb 2010 21:45:56 +0000</pubDate>
		<dc:creator>sasha84</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[bitrix]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[битрикс]]></category>

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

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

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

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

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

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

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

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

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

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

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


Все это из области фантастики. Каждый из нас допускает ошибки, поэтому [...]]]></description>
			<content:encoded><![CDATA[<p>
Как известно, все <em>программисты</em> при написании программ допускают ошибки. Не думаю, что найдется хоть один разработчик, который,как-то решив разработать более-менее сложное приложение, сел за свой компьютер, открыл любимый редактор, набрал нужный код, скомпоновал его и после запуска программа сделала все то, что от нее требовалось.
</p>
<p><a target="_blank" href="http://6.joinru.programmerinfo.e-autopay.com/"><img src="/img/courses/C++bannergif.gif"></a></p>
<p>Все это из области фантастики. Каждый из нас допускает ошибки, поэтому нам нужно их как-то отлавливать. </p>
<p>Если <em>ошибка синтаксическая</em>, то  в большинстве случаев на это укажет компилятор. Но, если  <strong>ошибка логическая</strong>, то часто <em>программист</em> сам не в состоянии определить ее.</p>
<p>Конечно, если <em>программа</em> не сложная, то можно самостоятельно, не прибегая ни к каким дополнительным средствам, выявить ошибку.</p>
<p>Однако, в больших программах самостоятельно отследить тот момент, когда программа начинает вести себя неправильно в большинстве случаев просто невозможно. В таких ситуациях на помощь приходят <strong>отладчики</strong>, которые позволяют программисту пройти по пути работы программы, отслеживая при этом ее состояние в определенные моменты времени выполнения.</p>
<p>В этой статье рассказывается об <strong>отладке программ</strong>, написанных на языке C, в <em>командной строке Linux</em> с использованием утилиты <strong>GDB</strong>.</p>
<p><span id="more-160"></span></p>
<p>Многие программисты, которые с успехом разрабатывали свои приложения на <strong>языках C/C++</strong> для <em>Windows</em>, после перехода к разработке программ на том же языке, но под ОС семейства <em>Linux</em> с удивлением обнаруживают, что отсутствует возможность той отладки, которой они пользовались в редакторах при написании программ для <em>Windows</em>.</p>
<p>Однако, такая возможность есть и это <strong>отладчик GDB</strong>.</p>
<p>Как следует из документации к этой утилите «<em>цель отладчика GDB</em>  &#8211; это позволить вам увидеть, что происходит внутри программы пока она выполняется, или что программа делает в момент ее краха.».</p>
<p>На момент написания этой статьи <strong>отладчик GDB</strong> работает с программами, написанными на <em>языках C, C++, Modula-2</em>. Мы будем отлаживать приложение, написанное на <strong>языке C</strong>.</p>
<p>Давайте начнем с приведения кода программы, которая в качестве аргумента принимает число и высчитывает <em>факториал</em> этого числа при помощи <em>рекурсии</em>. Ее мы и будем отлаживать.</p>
<p><div class="wp_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre>
</td>
<td class="code">
<pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339933;">#include &lt;unistd.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> fact<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> num<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>num <span style="color: #339933;">&lt;=</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> num <span style="color: #339933;">*</span> fact<span style="color: #009900;">&#40;</span>num <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> atoi<span style="color: #009900;">&#40;</span>argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d! = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #339933;">,</span> fact<span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre>
</td>
</tr>
</table>
</div>
<p>Теперь скомпилируем ее с включением отладочной информации. Для этого в командной строке заходим в директорию, в которой лежит наш файл с расширением .c и выполняем команду:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">g++</span> <span style="color: #660033;">-g</span> fact.c <span style="color: #660033;">-o</span> fact</pre>
</div>
</div>
<p>Опция <em>-g</em> сообщает <em>компилятору</em> о том, что в программу нужно включить отладочную информацию, которой и воспользуется <strong>отладчик GDB</strong>. </p>
<p>Опция <em>-o</em> сообщает <strong>компилятору g++</strong> путь до исполняемого файла. Если ее не указать, то, по умолчанию, компилятор создаст исполняемый файл в той же директории, где находится наша программа, и назовет его a.out.</p>
<p>Теперь запустим нашу программу в режиме отладки:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">gdb</span> <span style="color: #660033;">-q</span> fact</pre>
</div>
</div>
<p>Опцию <em>-q</em> можно не указывать, она используется лишь для того, чтобы при первом заходе в отладчик не выводилась информация о версии, лицензионное соглашение и т.д.</p>
<p>Итак, мы запустили отладчик. Теперь мы можем выполнять его команды.</p>
<p>Для просмотра исходного кода программы используется команда <em>list</em>, в которую можно передать номер строки для того, чтобы вывести код, окружающий переданную строку. </p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> list <span style="color: #000000;">10</span>
<span style="color: #000000;">5</span>       int fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>int num<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">6</span>       <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">8</span>           <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">9</span>             <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">1</span>;
<span style="color: #000000;">10</span>          <span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #000000;">11</span>
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">13</span>      <span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
</div>
</div>
<p>Также можно передать название функции, после чего будет выведен код, окружающий эту функцию.</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> list fact
<span style="color: #000000;">1</span>       <span style="color: #666666; font-style: italic;">#include &lt;stdio.h&gt;</span>
<span style="color: #000000;">2</span>       <span style="color: #666666; font-style: italic;">#include &lt;stdlib.h&gt;</span>
<span style="color: #000000;">3</span>       <span style="color: #666666; font-style: italic;">#include &lt;unistd.h&gt;</span>
<span style="color: #000000;">4</span>
<span style="color: #000000;">5</span>       int fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>int num<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">6</span>       <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">8</span>           <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">9</span>             <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">1</span>;
<span style="color: #000000;">10</span>          <span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
</div>
</div>
<p>Давайте запустим теперь <strong>выполнение программы под отладчиком</strong>. Это можно сделать одной из двух команд: <em>run</em> или <em>start</em>.</p>
<p>Отличие между этими двумя командами в том, что, вызвав команду <em>start</em>, отладчик останавливается на входе в функцию main, а команда <em>run</em> выполняется до тех пор, пока не наткнется на <strong>точку останова</strong> (о них чуть позднее).</p>
<p>Обе эти команды принимают в качестве параметра аргументы программы так же, как если бы программа запускалась из командной строки.</p>
<p>Итак, запустим программу на выполнение в режиме отладки:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> start <span style="color: #000000;">4</span>
Temporary breakpoint <span style="color: #000000;">2</span> at 0x8048556: <span style="color: #c20cb9; font-weight: bold;">file</span> fact.c, line 17.
Temporary breakpoint <span style="color: #000000;">2</span>, main <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">argc</span>=<span style="color: #000000;">2</span>, <span style="color: #007800;">argv</span>=0xbffffa24<span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">17</span>
<span style="color: #000000;">17</span>        int a = atoi<span style="color: #7a0874; font-weight: bold;">&#40;</span>argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;</pre>
</div>
</div>
<p>Как видим, отладчик остановился сразу же на входе в функцию main, а также вывел код и номер строки, перед которой остановился.</p>
<p>Используя команду <em>print</em>, мы можем вывести значения переменных и выражений. Посмотрим какие входные аргументы приняла наша программа:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> print argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
$<span style="color: #000000;">1</span> = 0xbffffb41 <span style="color: #ff0000;">&quot;/home/user/cpp/fact&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> print argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
$<span style="color: #000000;">2</span> = 0xbffffb5f <span style="color: #ff0000;">&quot;4&quot;</span></pre>
</div>
</div>
<p>В нулевом элементе массива argv содержится путь до выполняемой программы, а в первом элементе наш переданный аргумент — 4.</p>
<p>Для того, чтобы перейти на следующую строку, необходимо выполнить команду <em>step</em> или <em>next</em>.</p>
<p>Используя эти команды, можно передвигаться по программе. Отличие этих команд состоит в том, что <em>step</em> будет заходить внутрь функции каждый раз, когда ее встретит, а <em>next</em> пойдет дальше.</p>
<p>Перейдем к следующей строке:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">18</span>        <span style="color: #7a0874; font-weight: bold;">printf</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%d! = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, a, fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>a<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;</pre>
</div>
</div>
<p>Мы сделали один шаг и остановились перед 18-ой строкой.</p>
<p>Пойдем дальше:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
fact <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">num</span>=<span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">7</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre>
</div>
</div>
<p>Мы вошли в функцию fact с входным параметром 4 и оказались перед 7-ой строкой.</p>
<p>Т.к. мы имеем дело с рекурсией, то, вероятно, нам будет интересно значение переменной num, которое будет изменяться при каждом рекурсивном входе в функцию fact.</p>
<p>Добавим в процесс отладки слежение за переменной num. Для этого существует команда <em>display</em>, которой необходимо передать название переменной. В нашем случае это будет переменная num.</p>
<p>Выполним команду <em>display</em> и перейдем на один шаг вперед:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> display num
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">4</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">4</span></pre>
</div>
</div>
<p>Как видим, теперь при каждой остановке программы <strong>отладчик GDB</strong> сообщает нам значение переменной num.</p>
<p>Сейчас мы находимся перед рекурсивным входом в функцию fact. Заходим в нее и делаем еще один шаг вперед:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
fact <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">num</span>=<span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">7</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">3</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">3</span></pre>
</div>
</div>
<p>Отладчик сообщает нам значение переменной num, которое уже равно 3. Сейчас мы снова находимся перед заходом в функцию fact. </p>
<p>Скорее всего, не имеет смысла каждый раз проделывать эти шаги в функции fact. Нам достаточно было бы отслеживать какие значения принимает переменная num в 12-ой строке, т.к. в этой строке происходит рекурсивный вызов функции, а также возвращается результат ее выполнения.</p>
<p>Для того, чтобы добиться поставленных целей, мы можем поставить <strong>точки останова</strong>. Наша рассматриваемая программа достаточно не велика, поэтому мы могли бы пройти по каждой строке, используя отладчик, вплоть до завершения программы.</p>
<p>Однако, в реальных программах <em>программисты</em> отлаживают код, который содержит в себе тысячи строк. Если бы для отладки такого кода пришлось бы обойти каждую строку, то это превратилось бы в долгую и муторную работу.</p>
<p>Расставив <strong>точки останова</strong>, отладчик может «перепрыгивать» к строкам, на которых они поставлены, минуя весь остальной код. Для этого можно использовать команду <em>continue</em>, которая продолжает выполнение программы до тех пор, пока не встретится <strong>точка останова</strong>. Если их нет, то программа выполнится до конца.</p>
<p>Итак, давайте поставим точку останова в строке 12 и выполним команду <em>continue</em>, чтобы продолжить программу до тех пор, пока не наткнемся на строку 12:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">break</span> <span style="color: #000000;">12</span>
Breakpoint <span style="color: #000000;">2</span> at 0x8048529: <span style="color: #c20cb9; font-weight: bold;">file</span> fact.c, line 12.
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">continue</span>
Continuing.
&nbsp;
Breakpoint <span style="color: #000000;">2</span>, fact <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">num</span>=<span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">12</span>
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">2</span></pre>
</div>
</div>
<p>Мы прошли все шаги, которые до этого проделывали командой <em>step</em>. Теперь, каждый раз выполняя команду <em>continue</em> мы будем оказываться на 12-ой строке, а, благодаря выполненной ранее команде <em>display</em>, мы сможем наблюдать как изменяется значение переменной num на каждом шаге.</p>
<p>Есть и другой способ следить за изменением переменной в ходе работы программы с использованием команды <em>watch</em>. В отличие от команды <em>display</em>, эта команда при каждом изменении переменной, переданной в качестве параметра, будет останавливать выполнение программы и выводить старое и новое значение переменной.</p>
<p>Обе команды <em>display</em> и <em>watch</em> могут в качестве параметра принимать не только переменные, но и выражения.</p>
<p>Продолжим выполнение программы:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">continue</span>
Continuing.
<span style="color: #000000;">4</span><span style="color: #000000; font-weight: bold;">!</span> = <span style="color: #000000;">24</span>
&nbsp;
Program exited normally.</pre>
</div>
</div>
<p>Отладчик показал вывод нашей программы, а именно подсчитанный факториал от 4. Последняя строка в выводе отладчика сообщает, что программа завершилась. Отладчик также вывел бы код возврата программы в восьмеричной форме, если бы программа возвращала число, отличное от нуля.</p>
<p>Очень полезной может оказаться команда <em>set variable</em>, которая позволяет изменять значение переменной по ходу выполнения программы:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;">user<span style="color: #000000; font-weight: bold;">@</span>linux-hn2z:~<span style="color: #000000; font-weight: bold;">/</span>cpp<span style="color: #000000; font-weight: bold;">/&gt;</span> <span style="color: #c20cb9; font-weight: bold;">gdb</span> <span style="color: #660033;">-q</span> fact
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> start <span style="color: #000000;">4</span>
Temporary breakpoint <span style="color: #000000;">1</span> at 0x8048556: <span style="color: #c20cb9; font-weight: bold;">file</span> fact.c, line 17.
Starting program: <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>user<span style="color: #000000; font-weight: bold;">/</span>cpp<span style="color: #000000; font-weight: bold;">/</span>fact <span style="color: #000000;">4</span>
&nbsp;
Temporary breakpoint <span style="color: #000000;">1</span>, main <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">argc</span>=<span style="color: #000000;">2</span>, <span style="color: #007800;">argv</span>=0xbfffef84<span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">17</span>
<span style="color: #000000;">17</span>        int a = atoi<span style="color: #7a0874; font-weight: bold;">&#40;</span>argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">18</span>        <span style="color: #7a0874; font-weight: bold;">printf</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%d! = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, a, fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>a<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">set</span> variable <span style="color: #007800;">a</span>=<span style="color: #000000;">10</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> c
Continuing.
<span style="color: #000000;">10</span><span style="color: #000000; font-weight: bold;">!</span> = <span style="color: #000000;">3628800</span></pre>
</div>
</div>
<p>В этом примере мы запустили программу с входным параметром — 4, но по ходу выполнения программы мы заменили этот параметр на 10, и программа подсчитала факториал от 10.</p>
<p>Команду <em>set variable</em> можно применять, например, когда вы на каком-то шаге обнаружили, что программа ведет себя не верно, но путем изменения значения переменной можно исправить ситуацию и посмотреть как программа будет вести себя дальше.</p>
<p>В настоящей статье описаны далеко не все <strong>возможности отладчика GDB</strong>. За более подробными руководствами обращайтесь к документации по утилите, кроме того, находясь в отладчике, можно вывести список всех команд и описаний к ним, воспользовавшись командой <em>help</em>.</p>
<p>На этом все. Удачной отладки.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/160/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Вопросы на собеседовании для PHP-программиста (часть 3)</title>
		<link>http://job-interview.ru/articles/post/104</link>
		<comments>http://job-interview.ru/articles/post/104#comments</comments>
		<pubDate>Sat, 01 Aug 2009 17:49:23 +0000</pubDate>
		<dc:creator>tiger</dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[регулярные выражения]]></category>
		<category><![CDATA[собеседование]]></category>

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

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

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

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

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

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

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

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

<p>
 Сначала инициализируются три массива: $rtasks – в него будут заноситься сокеты, из которых можно читать данные, $wtasks – для сокетов, готовых к записи, и $results – массив для сохранения содержимого заданных страниц.</p>
<p>
Затем в цикле <em>функцией stream_socket_client</em> открываются сокеты для каждого из урлов, при этом ставится флаг STREAM_CLIENT_ASYNC_CONNECT, который указывает, что каждое следующее соединение надо открывать <strong>не дожидаясь завершения открытия предыдущего</strong>. Флаг STREAM_CLIENT_CONNECT указывает, что мы создаем именно клиентское подключение.<br />
Дескрипторы сокетов заносятся в массив $wtasks.</p>
<p>В 18-ой строке начинается главный цикл, и сразу массивам $rtasks_ и $wtasks_, передаваемым в функцию stream_select, присваиваются массивы, в которых хранятся сокеты для чтения и записи соответственно. <em>Функция stream_select</em> отслеживает наличие данных в потоках и принимает на вход несколько параметров: первый – это массив дескрипторов, в которых ожидается завершение операции чтения, второй – массив с дескрипторами, ожидающими завершение записи, третий – для особых случаев (поступление &#8220;out-of-band data&#8221; &#8211; внеполосных данных) и четвертый параметр &#8211; это таймаут.  Массивы передаются в функцию по указателям, и как только функция возвращает число больше 0, в них будут находится сокеты, готовые к действиям.</p>
<p>В 28-ой строке мы смотрим, в какие сокеты можно записать данные (надо что-то отправить, прежде чем нам придет ответ-результат), и если такие сокеты есть, то удаляем из массива для записи текущий дескриптор, помещаем его в массив для чтения, и отправляем заголовки, необходимые для получения контента.<br />
Далее, в 49-ой строчке, просматриваем сокеты, готовые для считывания из них данных, забираем содержимое, удаляем дескриптор из масива для чтения и закрываем сокет. Результат заносим в массив $results. Повторяем эти операции до тех пор, пока у нас остаются какие-либо открытые сокеты.</p>
<p>После работы скрипта нужный нам контент находится в массиве $results.</p>
<p>В статье рассмотрен пример работы с <strong>функциями stream_socket_*</strong>, на очереди <a href="/articles/post/194" target="_blank">асинхронные сокеты</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/92/feed</wfw:commentRss>
		<slash:comments>9</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>tiger</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>4</slash:comments>
		</item>
	</channel>
</rss>

