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

<channel>
	<title>Персональный блог Валерия Леонтьева &#187; PHP</title>
	<atom:link href="http://valera.ws/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://valera.ws</link>
	<description>Блог для публикации интересных личных заметок о работе, жизни, событиях... Digital lifestyle, веб-программирование, администрирование серверов и другое</description>
	<lastBuildDate>Sat, 31 Dec 2011 11:52:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Как стать хорошим программистом и хорошим php-программистом в частности?</title>
		<link>http://valera.ws/2011.12.31~how-to-be-a-good-programmer/</link>
		<comments>http://valera.ws/2011.12.31~how-to-be-a-good-programmer/#comments</comments>
		<pubDate>Sat, 31 Dec 2011 11:35:09 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PC]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[алгоритмы]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=628</guid>
		<description><![CDATA[Хочу поделиться ссылкой, по которой можно найти много полезной информации для развития себя как настоящего программиста. Ссылка на пост в белорусском сообществе программистов — dev.by. Написана человеком, который попросил дать ему совет, а потом свёл в статье резюме полученных советов. &#8230; <a href="http://valera.ws/2011.12.31~how-to-be-a-good-programmer/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-631" title="programmer at work" src="http://valera.ws/wp-content/uploads/2011/12/programmer.png" alt="" width="200" height="130" />Хочу поделиться ссылкой, по которой можно найти много полезной информации для развития себя как <strong>настоящего</strong> программиста. Ссылка на пост в белорусском сообществе программистов — dev.by. Написана человеком, который попросил дать ему совет, а потом свёл в статье резюме полученных советов. Ни автор, ни комментаторы не имеют ко мне никакого отношения. Но я готов подписаться под большинством полученный советов.</p>
<p><span id="more-628"></span></p>
<p>Ценность материала в том, что:</p>
<p>1) это хороший способ взглянуть на себя со стороны огромному числу программистов <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>, так как общая средняя квалификация этого класса программистов значительно ниже среднего по другим более серьезным языкам; взгляд со стороны поможет понять свои проблемы и найти способы их преодоления;</p>
<p>2) конкретные советы о том, что следует почитать/посмотреть.</p>
<p>Ссылка на материал: <a title="Как стать хорошим программистом и хорошим php-программистом в частности?" href="http://dev.by/blog/37028" target="_blank"><strong>Как стать хорошим программистом и хорошим php-программистом в частности?</strong></a></p>
<p><strong>А ниже позволю себе сделать частичный копипаст предложенных решений.</strong></p>
<h2>Мастерство программирования (или скорее можно назвать Основы)</h2>
<ul>
<li><a href="http://oz.by/books/more1015206.html" target="_blank">Совершенный код</a>,</li>
<li><a href="http://oz.by/books/more10109592.html" target="_blank">Чистый код</a>,</li>
<li><a href="http://oz.by/books/more105087.html" target="_blank">Рефакторинг</a>,</li>
<li><a href="http://oz.by/books/more1031721.html" target="_blank">Программист-прагматик</a>,</li>
<li><a href="http://oz.by/books/more1010353.html" target="_blank">Архитектура корпоративных программных приложений</a>,</li>
<li><a href="http://oz.by/books/more10182848.html" target="_blank">Кодеры за работой</a>.</li>
</ul>
<p>Нашел очень хорошую и исчерпывающую статью на английском: <a href="http://samizdat.mines.edu/howto/HowToBeAProgrammer.html" target="_blank">How to be a Programmer: A Short, Comprehensive, and Personal Summary</a></p>
<p>Курсы, выложенные по <a href="http://ru.wikipedia.org/wiki/MIT_OpenCourseWare" target="_blank">MIT OCW</a>:</p>
<ul>
<li><a href="http://ocw.mit.edu/courses/audio-video-courses/#electrical-engineering-and-computer-science" target="_blank">MIT Electrical Engineering and Computer Science</a></li>
</ul>
<p>Курсы Стэнфорда:</p>
<ul>
<li><a href="http://www.ml-class.org/" target="_blank">Mashine learning</a></li>
<li><a href="http://www.nlp-class.org/" target="_blank">Natural Language Processing class</a></li>
<li><a href="http://www.saas-class.org/" target="_blank">Software Engineering for Software as a Service class</a></li>
</ul>
<p>На каждом сайте внизу есть ссылки на другие курсы Стэнфорда.</p>
<h2>Алгоритмы.</h2>
<p>Как развивать:</p>
<p><a href="http://oz.by/books/more1034722.html" target="_blank">Искусство программирования</a> Кнутта — читать и выполнять задания.</p>
<p><a href="http://projecteuler.net/" target="_blank">Project Euer</a> — задания по алгоритмам, можно писать на PHP.</p>
<h2>ООП и Шаблоны проектирования</h2>
<p><a href="http://oz.by/books/more1074794.html" target="_blank">PHP: объекты, шаблоны и методики программирования</a> М. Зандстра сейчас, наверное, лучшая книга для введения в шаблоны проектирвания для PHP.</p>
<p><a href="http://shop.oreilly.com/product/9780596007126.do" target="_blank">Head First Design Patterns</a>, на русском <a href="http://oz.by/books/more10182766.html" target="_blank">Паттерны проектирования</a> — очень рекоммендуют, как очень хорошо разъясняющую книгу.</p>
<p>какие книги, методы обучения, задачи порекоммендуете?</p>
<h2>PHP основы</h2>
<p>Как развивать:</p>
<p>собственно работа по профессии и набор опыта,</p>
<p><a href="http://oz.by/books/more102159.html" target="_blank">Профессиональное PHP программирование</a> — вроде как лучшая книга по основам PHP (читать, чтобы заполнить пробелы по основам языка, начиная с типов и далее. Посмотреть, что есть из того, чего я не казался в работе, чтобы расширять кругозор.</p>
<p>Потом есть stackoverflow, там введи в поиск ~php~ и читай вопрос, давай свой ответ (про себя), потом смотри, что другие написали. Будешь по тегам смотреть заодно, что пхп-ники изучают.</p>
<h2>Javascript Основы</h2>
<p>Как развивать:</p>
<p>собственно работа по профессии и набор опыта,</p>
<p><a href="http://oz.by/books/more1011147.html" target="_blank">JavaScript. Подробное руководство. Д. Флэнаган</a> (читать и разбираться в пропущенных основах &#8211; типы, обьектная модель и др.)</p>
<p><a href="http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742" target="_blank">JavaScript: The Good Parts</a></p>
<p><a href="http://oz.by/books/more10193164.html" target="_blank">JavaScript. Шаблоны</a></p>
<p>Источник: <a title="Как стать хорошим программистом и хорошим php-программистом в частности?" href="http://dev.by/blog/37028" target="_blank">Как стать хорошим программистом и хорошим php-программистом в частности?</a> Ни автор, ни комментаторы не имеют ко мне никакого отношения.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2011.12.31~how-to-be-a-good-programmer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Передача имени сайта скрипту через cron (crontab)</title>
		<link>http://valera.ws/2011.01.13~sitename-php-from-cron/</link>
		<comments>http://valera.ws/2011.01.13~sitename-php-from-cron/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 20:32:58 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PC]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=530</guid>
		<description><![CDATA[Вчера на stackoverflow заметил вопрос о том, как передать скрипту через крон адрес сайта, если скрипт может выполняться «под разными сайтами». Это довольно интересный вопрос, и есть много вариантов решения. Сам решал его не так давно, а раз тема интерисует &#8230; <a href="http://valera.ws/2011.01.13~sitename-php-from-cron/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img style="width: 107px; height: 65px;" title="PHP-скрипт" src="http://valera.ws/images/php.png" border="0" alt="PHP-скрипт" hspace="3" vspace="3" width="107" height="65" align="left" />Вчера на stackoverflow заметил <a href="http://stackoverflow.com/questions/4673255/get-identifying-server-information-when-running-php-scripts-with-cron/4673387#4673387">вопрос</a> о том, как передать скрипту через крон адрес сайта, если скрипт может выполняться «под разными сайтами». Это довольно интересный вопрос, и есть много вариантов решения. Сам решал его не так давно, а раз тема интерисует и других, решил об этом написать.</p>
<p><span id="more-530"></span>Немного подробнее о самом вопросе. Зачастую встречаются сайты, работающие на одной кодовой базе на одном сервере, но, при этом, на разных доменах. При схожем внешнем виде на этих сайтах содержится разная информация в разном дизайне.</p>
<p>Самый простой пример таких сайтов — это локализованные версии одного сайта на разных языках. У меня в практике — это тематические форумы для разных групп.</p>
<p>Разделение этих сайтов обычно происходит через конфиги. Именно конфиг определяет все детали, уникальные для каждого сайта.</p>
<p>При запуске обработки пользовательского HTTP-запроса скриптам необходимо определить, какому именно домену предназначен запрос, и выбрать соответствующий конфиг. В <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> это довольно просто сделать: заглянуть в переменную <a href="http://php.net/manual/en/reserved.variables.server.php">$_SERVER</a>['SERVER_NAME']. В других языках программирования под веб, думаю, примерно так же просто.</p>
<p>По имени серевера определяется нужный конфиг и оттуда берутся все необходимые настройки. Все просто.</p>
<p>Но когда дело доходит до вызова скриптов из cron-а (или другого планировщика), то переменная $_SERVER['SERVER_NAME'] будет пуста. Оно-то и понятно: никакого сервера нет, скрипт запускается напрямую через <a href="http://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%BD%D0%BE%D0%B9_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8">CLI</a>. И узнать, для какого сайта вызывается скрипт, без явной передачи домена скрипту невозможно.</p>
<p>Самый простой способ указать домен — это прописать его аргументом командной строки. При вызове из cron-а после имени скрипта просто пишем домен, а в коде получаем его из переменной <a href="http://www.php.net/manual/en/features.commandline.usage.php">$argv</a> глобальной области видимости.</p>
<p>Но этот способ не отличается элегантностью, т.к. придется определять, как запускался сайт: через веб или CLI, и в зависимости от этого искать адрес сайта в разных местах.</p>
<p>Второй большой минус такого способа в том, что привязка происходит непосредственно по домену, т.е. нет гибкости. Если одинаковый сайт крутится на разных доменах, то придется мутить некую систему алиасов. А это еще уменьшает элегантность.</p>
<p>Таким образом ищем более удобный способ передать «указатель» на сайт. И находим: это <a href="http://ru.wikipedia.org/wiki/%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D1%81%D1%80%D0%B5%D0%B4%D1%8B">переменные окружения</a>. Среду окружения интерпретатор PHP получает оттуда, откуда он был запущен. Если скрипт запущен веб-сервером, то переменные будут получены от сервера. Если запускается скрипт через CLI, то среда будет получена от shell-а, в котором производился запуск. Повторю: запуск скриптов из cron-а — это обыкновенный запуск исполнимого файла в режиме CLI.</p>
<p>Теперь к конкретике. Чтобы переменная среды окружения попала из веб-сервера в PHP-скрипт (или скрипт/программу, написанную на других языках), ее надо установить (прописать). Для Апача установить переменную можно в файле .htaccess, либо в конфигах сервера (httpd.conf или конфиги виртуальных хостов). В идеале предпочтительно последнее. Но достаточно и минимального уровня доступа к .htaccess. Добивим в соответствующий конфиг строку:</p>
<p><code>SetEnv SITE_NAME site1</code></p>
<p>Чтобы определить переменную среды при запуске в режиме CLI (php /filename), нужно ее объявить и экпортировать:</p>
<p><code>export SITE_NAME=site1;</code></p>
<p>При запуске скрипта вручную следующей командой можно запускать сам PHP. Если запуск производится cron-ом, то стоит создать скрипт, на который ссылаться из crontab:</p>
<p><code>#!/bin/bash<br />
 export SITE_NAME=site1;<br />
 php /path</code></p>
<p>Для других сайтов вместо site1 подставляются другие имена.</p>
<p>Остается прочитать переменную в скрипте:</p>
<p><code>echo getenv('SITE_NAME');</code></p>
<p>Ну а дальше, в зависимости от значения переменной, подгружать нужный конфиг.</p>
<p>* Стоит отметить, что в случае разных «установок»<sup>1</sup> одного и того же сайта (development, testing, production) принято это значение передавать сайту в виде тоже же переменной окружения. Как правило, конфиг в этом случае содержит очень много информации, одинаковой для всех «установок», а отличаться, например, могут только параметры доступа к БД. Тогда имеет смысл все установки считать за один сайт (хоть домены и разные), а отличающиеся параметры вынести в отдельный конфиг, зависимый от «установки».</p>
<p><sup>1</sup> — Я намеряно в последнем абзаце заменил термин «окружение приложения» (application environment: тестовое, рабочее) на «установку», чтобы не было путаницы с тем окружением, где устанавливаюся переменные.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2011.01.13~sitename-php-from-cron/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Делегирование обслуживания почтового домена: часть 2. Отправка почты через localhost (настройка Exim4 в Debian)</title>
		<link>http://valera.ws/2010.11.28~exim-mail-localhost/</link>
		<comments>http://valera.ws/2010.11.28~exim-mail-localhost/#comments</comments>
		<pubDate>Sun, 28 Nov 2010 19:18:55 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PC]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Exim]]></category>
		<category><![CDATA[GMail]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[почта]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[сайты]]></category>
		<category><![CDATA[Яндекс]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=455</guid>
		<description><![CDATA[Настройка Exim и PHP mail() на примере Linux Debian Чтобы решить проблему отказа серверов Gmail от обслуживания  при отправке большого числа писем на несуществующие адреса, используем для отправки почты из скриптов сайта локальный почтовый SMTP-сервер (MTA). Локальный сервер будет выступать &#8230; <a href="http://valera.ws/2010.11.28~exim-mail-localhost/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>Настройка <a href="http://valera.ws/tag/exim/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Exim">Exim</a> и PHP mail() на примере Linux <a href="http://valera.ws/tag/debian/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Debian">Debian</a></h2>
<p>Чтобы решить проблему отказа серверов <a href="http://valera.ws/tag/gmail/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  GMail">Gmail</a> от обслуживания  при отправке большого числа писем на несуществующие адреса, используем для отправки почты из скриптов сайта локальный почтовый SMTP-сервер (<a href="http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%87%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80">MTA</a>). Локальный сервер будет выступать в качестве <a href="http://en.wikipedia.org/wiki/Open_mail_relay">mail relay</a>. В дополнение мы откажемся от подключения из скрипта к удаленному серверу, что может быть медленно. Локальные подключения всегда должны быть быстрее и стабильнее.<span id="more-455"></span></p>
<p>Локальный сервер мы будем использовать только для отправки писем. Причем, не важно, как будет происходить отправка: непосредственно через SMTP, или с помощью <a href="http://en.wikipedia.org/wiki/Mail_user_agent">MUA</a>. Получение почты по-прежнему будет происходить с серверов Gmail.</p>
<p>В дистрибутиве Debian 5 по умолчанию устанавливается MTA <a href="http://ru.wikipedia.org/wiki/Exim">Exim4</a>. Он отлично подойдет для наших задач. Причем его настройка производится с помощью мастера и невероятно проста. Настроить сервер требуется на прием соединений исключительно с локального соединения. При этом не нужно поручать ему обслуживание доменов, кроме дефолтного локального (localhost).</p>
<p>Итак, если Exim у вас не установлен, то установим его:</p>
<p class="console"># aptitude install exim4</p>
<p>Далее запускаем его конфигурацию:</p>
<p class="console"># dpkg-reconfigure exim4-config</p>
<p>1. На первом шаге необходимо выбрать конфигурацию сервера. В Exim есть несколько стандартных конфигураций, предназначенных для разных случаев. Подробнее о них в мануале. Нам нужна конфигурация “internet site; mail is sent and received directly using SMTP”.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-1.png"></a><a href="http://valera.ws/wp-content/uploads/2010/11/exim-1.png"><img class="alignnone size-full wp-image-461" title="exim-1" src="http://valera.ws/wp-content/uploads/2010/11/exim-1.png" alt="" width="721" height="393" /></a></p>
<p>2. Далее укажите имя сервера. Оно будет передаваться в SMTP-протоколе в команде HELLO, т.е. будет видно получателям вашей почты. Лучше всего, чтобы это имя совпадало с доменом, с которого шлется <a href="http://valera.ws/tag/%d0%bf%d0%be%d1%87%d1%82%d0%b0/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  почта">почта</a>. Например, valera.ws.</p>
<p>Если у вас на сервере несколько сайтов с разными доменами (см. ниже), то лучше это имя сделать нейтральным, чтобы «не палиться». Например, можно выбрать local-mail-agent.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-2.png"><img class="alignnone size-full wp-image-462" title="exim-2" src="http://valera.ws/wp-content/uploads/2010/11/exim-2.png" alt="" width="776" height="442" /></a></p>
<p>3. Далее требуется указать, какие интерфейсы должен слушать Exim. В нашем случае удаленные подключения мало того, что не нужны, так еще и опасны: кто угодно сможет рассылать почту через ваш сервер. Указываем только 127.0.0.1.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-3.png"><img class="alignnone size-full wp-image-463" title="exim-3" src="http://valera.ws/wp-content/uploads/2010/11/exim-3.png" alt="" width="776" height="442" /></a></p>
<p>4. Далее спрашивается, какие домены должен обслуживать сервер. Т.е. для каких доменов не нужно пересылать письма на удаленные SMTP-сервера, пользователь заберет их с этого сервера. Нам не нужно обслуживание наших доменов. Можно указать только localhost, т.к. его больше обслужить некому.</p>
<p>Не указывайте здесь адрес вашего сервера (подставляется по умолчанию), т.к. его обслуживание делегировано Gmail. Если его указать, то письма, отправленные на ящики вашего домена, в Gmail не попадут и останутся на сервере. Это не нужно.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-4.png"><img class="alignnone size-full wp-image-464" title="exim-4" src="http://valera.ws/wp-content/uploads/2010/11/exim-4.png" alt="" width="776" height="442" /></a></p>
<p>5. Далее можно указать, для каких доменов сервер должен служить релеем (список через точку с запятой). Здесь не указываем ничего, так как на следующем шаге мы разрешим себе релей для всех доменов. Можете указать список ваших доменов.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-5.png"><img class="alignnone size-full wp-image-465" title="exim-5" src="http://valera.ws/wp-content/uploads/2010/11/exim-5.png" alt="" width="776" height="442" /></a></p>
<p>6. Здесь укажем 127.0.0.1, чтобы раз-решить релей для всех запросов с локального IP.</p>
<p>При этой конфигурации есть один негативный момент. Если ваш сайт поломают, то злоумышленники смогут слать почту с любых доменов через ваш сервер. Если на сервере 1—2 сайта, то лучше на этом шаге оставить поле пустым, а на предыдущем шаге внести список этих доменов (для возврата на шаг назад нажмите кнопку “Cancel”). При появлении новых доменов не забывайте их заносить в конфиг. Если вы считаете свои <a href="http://valera.ws/tag/sajty/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  сайты">сайты</a> надежными, то проще всего указывать здесь 127.0.0.1.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-6.png"><img class="alignnone size-full wp-image-466" title="exim-6" src="http://valera.ws/wp-content/uploads/2010/11/exim-6.png" alt="" width="776" height="442" /></a></p>
<p>7. Дале уточняется, является ли для нас проблемой постоянные DNS-запросы при отправке каждого письма. В 99,9% это не проблема, так что выбираем ответ на вопрос “Keep number of DNS-queries minimal (Dial-on-Demand)?” “No”.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-7.png"><img class="alignnone size-full wp-image-467" title="exim-7" src="http://valera.ws/wp-content/uploads/2010/11/exim-7.png" alt="" width="776" height="442" /></a></p>
<p>8. Где хранить локальную почту (помните, мы указали серверу обслуживать домен localhost?) нам по сути не важно, так как этим как правило никто не пользуется. Можно выбрать вариант по умолчанию: складывать все в /var/mail.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-8.png"><img class="alignnone size-full wp-image-468" title="exim-8" src="http://valera.ws/wp-content/uploads/2010/11/exim-8.png" alt="" width="776" height="442" /></a></p>
<p>9. Предпоследний шаг — выбор конфигурации. Хранить все в одном файле, или раскидать по множеству мелких файлов. В большой файл проще вносить большие изменения, а с мелкими проще работать в случае мелких правок. Выберите вариант на свой вкус. Я выбрал “unsplit configuration” (ответ “No”).</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-9.png"><img class="alignnone size-full wp-image-469" title="exim-9" src="http://valera.ws/wp-content/uploads/2010/11/exim-9.png" alt="" width="776" height="442" /></a></p>
<p>10. На последнем шаге укажем на какой аккаунт реального пользователя системы пересылать сообщения, отправленные на служебные аккаунты postmaster, root и т.д. Здесь имеет смысл указать ваше имя пользователя в системе.</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/exim-10.png"><img class="alignnone size-full wp-image-470" title="exim-10" src="http://valera.ws/wp-content/uploads/2010/11/exim-10.png" alt="" width="776" height="442" /></a></p>
<p>Переконфигурировать Exim в любой момент можно тем же способом. Мастер подставит в значения по умолчанию текущие значения вашей конфигурации.</p>
<h2>Правильная настройка SPF</h2>
<p>Если кратко, то <a href="http://ru.wikipedia.org/wiki/Sender_Policy_Framework">SPF</a> — это способ борьбы со спамом.</p>
<p>Мы собираемся отправлять почту с сервера, <a href="http://en.wikipedia.org/wiki/PTR_record#PTR">PTR</a> IP которого не равен одной из MX-записей сервера, а так же в большинстве случаев <a href="http://en.wikipedia.org/wiki/PTR_record#PTR">PTR</a> IP не равен самому нашему домену (не всегда хостеры соглашаются менять PTR). В этом случае вероятность попадания писем в спам повышается. Но есть хороший способ ее понизить: указать правильно запись SPF нашего домена.</p>
<p>SPF-запись — это обыкновенная запись доменной зоны, имеющая тип TXT. Узнать текущее ее значение для домена можно с помощью команды host в Linux:</p>
<p class="console">$ host -t TXT valera.ws<br />
 valera.ws TXT record currently not present</p>
<p>В данном примере SPF-запись не задана. Зададим ее. С моего домена почта может отправляться с серверов Gmail и с моего сервера. Для начала узнаем, какой PTR моего сайта (valera.ws):</p>
<p class="console">$ nslookup valera.ws<br />
 Server:      194.224.52.4<br />
 Address:     194.224.52.4#53</p>
<p class="console">Non-authoritative answer:<br />
 Name:     valera.ws<br />
 Address:  93.174.6.118</p>
<p>IP-адрес моего сервера 93.174.6.118. Узнаем PTR:</p>
<p class="console">$ nslookup 93.174.6.118<br />
 Server:      194.224.52.4<br />
 Address:     194.224.52.4#53</p>
<p class="console">Non-authoritative answer:<br />
 118.6.174.93.in-addr.arpa	name = server.valera.ws.</p>
<p>Видно, что PTR IP, к которому привязан мой домен (IP моего сервера) — server.valera.ws.</p>
<p class="console">v=spf1 a mx ptr include:_spf.google.com ~all</p>
<p>По порядку:</p>
<ul>
<li>v=spf1 — версия SPF (первая);</li>
<li>a — разрешение отправлять почту с IP, указанного в A-записи домена (собственно с сервера, на который ваш домен ссылается);</li>
<li>mx — разрешение отправлять почту с IP, указанных в MX-записях домена (в нашем случае сервера Gmail);</li>
<li>ptr — разрешение отправлять почту с IP, PTR-запись которых содержит ваш домен (т.е. сам домен и поддомены);</li>
<li>include:_spf.google.com — подключение разрешений для серверов отправки почту Gmail (совсем не обязательно почта будет слаться с серверов, указанных в MX-записи);</li>
<li>~all — нейтральная реакция на всю остальную почту; здесь можно указать -all, что будет значить, что почта, не попадающая под эти правила, — спам.</li>
</ul>
<p>Если вы хотите отправлять почту с сервера, не попадающего под все эти правила, его можно указать по IP или домену PTR, например:</p>
<p class="console">v=spf1 a mx ptr ptr:example.com include:_spf.google.com ~all</p>
<p>Запись указывается для вашего домена соответствующим образом, который определяет владелец DNS-сервера. Обычно сервером заведует хостер и предоставляет возможность вносить изменения в DNS-зоны через панель хостинга. Либо сам по запросу в саппорт меняет запись. В зональном файле должна появиться запись вида:</p>
<p class="console">valera.ws.      TXT      v=spf1 a mx ptr include:_spf.google.com ~all</p>
<p>После обновления зоны host выдаст следующее:</p>
<p class="console">$ host -t TXT valera.ws<br />
 valera.ws      TXT      &raquo;v=spf1 a mx ptr include:_spf.google.com ~all&raquo;</p>
<h2>PHP mail()</h2>
<p>После всей этой настройки функция <a href="http://php.net/manual/en/function.mail.php">mail()</a> в PHP начнет слать почту через ваш локальный сервер на законных основаниях для антиспам-ботов. Но косяк будет в том, что в поле отправителя будет фигурировать адрес системного пользователя www-data@localdomain. Нас это не устраивает. Чтобы почта правильно слалась из mail(), необходимо использовать ее дополнительный параметр.</p>
<p class="console">bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )</p>
<p>Именно $additional_parameters нас и интерисует. В него надо передавать реального отправителя:</p>
<p class="console">mail($to, $subject, $message, $additional_headers, $additional_parameters.&raquo; -frealsender@valera.ws&raquo;);</p>
<p>Указывается отправитель слитно с параметром -f.</p>
<p>Теперь отправленные через mail() письма будут абсолютно адекватны (при условии, что вы указываете все нужные SMTP-заголовки, вроде “FROM:”, “TO:” и т.д.).</p>
<h2>А если несколько сайтов с разными IP (настройка Exim для отправки писем с разных IP)?</h2>
<p>Мы хотим использовать локальный SMTP-сервер для отправки почты со всех сайтов на сервере. Никаких проблем нет, если настроен Exim правильно (см. выше). Но проблема появляется, если разные сайты работают на разных IP. Мы не хотим в почте «палить» то, что все наши сайты живут на одном сервере. Но Exim по умолчанию шлет всю почту с основного (первого) IP сетевого интерфейса, а этот IP всем получателям в SMTP-заголовках “Received:” письма. Кроме того, там указывается и имя сервера, которые мы в случае с разными сайтами на сервере выбрали нейтральными.</p>
<p>Чтобы не «палить» IP сервера, нужно отсылать письмо на удаленный сервер с IP, равного A-записи домена сайта. Делается это несложно путем изменения конфига Exim. Внесем изменения в настройки транспорта SMTP Exim. Если вы выбрали монолитный конфиг, то нужно отредактировать файл:</p>
<p class="console"># nano /etc/exim4/exim4.conf.template</p>
<p>Находим в файле строку “remote_smtp:” (поиск в nano — F6). Добавляем в конец этого блока:</p>
<p class="console">interface = &laquo;${lookup{$sender_address_domain}lsearch{/usr/share/exim4/domain2ip}{$value}}&raquo;<br />
 helo_data = &laquo;$sender_address_domain&raquo;</p>
<p>Это значит, что при отправке письма нужно определить домен отправителя почты (для sender@valera.ws это valera.ws) и отправить почту с IP, к которому этот домен привязан. Само собой разумеется, что домен должен быть привязан к серверу, где установлен Exim.</p>
<p>Так же нужно создать файл в любом месте файл привязки доменов к IP (у домена может быть несколько IP, так что просто lookup-ить его не прокатит). Я выбрал для файла место: /usr/share/exim4/domain2ip</p>
<p class="console"># nano /usr/share/exim4/domain2ip</p>
<p>Туда вводим наши домены по шаблону:</p>
<p class="console">valera.ws: 123.123.123.123<br />
 vasya.ws: 123.123.123.124</p>
<p>Не забудьте дописать домен в файл в случае появления нового сайта.<br />
 Кстати, строку helo_data = &laquo;$sender_address_domain&raquo; можно добавить в файл даже если у вас один IP на все сайты. Тогда в команде HELLO SMTP-протокола (а, следовательно, и в заголовках писем) будет фигурировать ваш домен.</p>
<p>Идея с указанием интерфейса взята отсюда: <a href="http://www.directadmin.com/forum/showthread.php?t=36468">http://www.directadmin.com/forum/showthread.php?t=36468</a></p>
<h2>Проверка</h2>
<p>Остается проверить, чтобы все ваши настройки работали верно. Для этого просто отправим письмо с локального сервера через консоль.</p>
<p class="console">$ mail -a &laquo;From:feedbee@valera.ws&raquo; -s Test feedbee@gmail.com &#8212; -ffeedbee@valera.ws<br />
 Test &lt;Ctrl-D&gt;<br />
 Cc:</p>
<p>Проверяем отосланное письмо в ящике получателя:</p>
<p><a href="http://valera.ws/wp-content/uploads/2010/11/check.png"><img class="alignnone size-full wp-image-471" title="check" src="http://valera.ws/wp-content/uploads/2010/11/check.png" alt="" width="689" height="337" /></a></p>
<p>А вот текст SMTP-протокола:</p>
<p class="console">Delivered-To: feedbee@gmail.com<br />
 Received: by 10.236.109.139 with SMTP id s11cs13826yhg;<br />
 Wed, 24 Nov 2010 02:18:14 -0800 (PST)<br />
 Received: by 10.227.145.134 with SMTP id d6mr9025492wbv.195.1290593893066;<br />
 Wed, 24 Nov 2010 02:18:13 -0800 (PST)<br />
 Return-Path: feedbee@valera.ws<br />
 Received: from valera.ws (server.valera.ws [93.174.6.118])<br />
 by mx.google.com with ESMTP id b7si11085685wer.164.2010.11.24.02.18.12;<br />
 Wed, 24 Nov 2010 02:18:12 -0800 (PST)<br />
 Received-SPF: pass (google.com: domain of feedbee@valera.ws designates 93.174.6.118 as permitted sender) client-ip=93.174.6.118;<br />
 Authentication-Results: mx.google.com; spf=pass (google.com: domain of feedbee@valera.ws designates 93.174.6.118 as permitted sender) smtp.mail=feedbee@valera.ws<br />
 Received: from root by server.valera.ws with local (Exim 4.69)<br />
 (envelope-from &lt;feedbee@valera.ws&gt;)<br />
 id 1PLCQW-0006KD-Pc<br />
 for feedbee@gmail.com; Wed, 24 Nov 2010 10:18:12 +0000<br />
 To: feedbee@gmail.com<br />
 Subject: Test<br />
 From:feedbee@valera.ws<br />
 Message-Id: E1PLCQW-0006KD-Pc@server.valera.ws<br />
 Date: Wed, 24 Nov 2010 10:18:12 +0000</p>
<p class="console">Test</p>
<p>P.S. Чтобы отправленная почта не попадала в спам, отправляйте письма только от имени реально существующих на серверах Gmail адресов на ваших доменах. Туда же повалятся уведомления о недоставках.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2010.11.28~exim-mail-localhost/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Информер погоды от Яндекса с определение города по IP (обновление)</title>
		<link>http://valera.ws/2010.11.21~informer-pogody-ot-yandeksa-s-opredelenie-goroda-po-ip-obnovlenie/</link>
		<comments>http://valera.ws/2010.11.21~informer-pogody-ot-yandeksa-s-opredelenie-goroda-po-ip-obnovlenie/#comments</comments>
		<pubDate>Sun, 21 Nov 2010 20:59:59 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Жизнь]]></category>
		<category><![CDATA[GeoIP]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=432</guid>
		<description><![CDATA[Сегодня обновил свой старый сервис, который позволяет показывать пользователям сайта информер погоды в том городе, где они находятся. Все подробности в старой записи по этому поводу. Обновлено: исправлена ошибка, которая в последнее время неприятно сказывалась на работе сервиса; все переведено &#8230; <a href="http://valera.ws/2010.11.21~informer-pogody-ot-yandeksa-s-opredelenie-goroda-po-ip-obnovlenie/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Сегодня обновил свой старый сервис, который позволяет показывать пользователям сайта информер погоды в том городе, где они находятся. Все подробности в <a href="http://valera.ws/2008.04.05~weather-informer/comment-page-1/">старой записи</a> по этому поводу.<br />
 <span id="more-432"></span><br />
 Обновлено:</p>
<ul>
<li>исправлена ошибка, которая в последнее время неприятно сказывалась на работе сервиса;</li>
<li>все переведено на UTF-8</li>
<li>обновлены списки городов и стран Яндекс.Погоды</li>
</ul>
<p>Если вы используете старый файл настрое (полученный до 22 ноября), его <a href="http://valera.ws/2008.04.05~weather-informer/comment-page-1/">необходимо обновить</a>.</p>
<p>Сам сервис: <a href="http://ru.commontools.net/geoip/ya.weather.get.html">http://ru.commontools.net/geoip/ya.weather.get.html</a></p>
<p>UPD. Было проведено <a href="http://valera.ws/2010.12.26~weather-informer-3/">еще одно обновление</a> сервиса.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2010.11.21~informer-pogody-ot-yandeksa-s-opredelenie-goroda-po-ip-obnovlenie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Определение версии браузера</title>
		<link>http://valera.ws/2009.09.16~browser-version-detection/</link>
		<comments>http://valera.ws/2009.09.16~browser-version-detection/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 08:49:27 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>
		<category><![CDATA[браузеры]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=347</guid>
		<description><![CDATA[Вчера возникла задача определения версии браузера посетителя сайта, чтобы выводить сообщение об устаревшей версии браузера. Гуглинг не дал готового кода. PHP функция get_browser вообще нормально не работает. Пришлось написать PHP-код определения весии браузера самому. Итак, задача из HTTP-заголовка UserAgent получить &#8230; <a href="http://valera.ws/2009.09.16~browser-version-detection/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Вчера возникла задача определения версии браузера посетителя сайта, чтобы выводить сообщение об устаревшей версии браузера. Гуглинг не дал готового кода. <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> функция <a href="http://us2.php.net/manual/en/function.get-browser.php" target="_blank">get_browser</a> вообще нормально не работает. Пришлось написать PHP-код определения весии браузера самому.<span id="more-347"></span> Итак, задача из HTTP-заголовка UserAgent получить название и версию браузера пользователя, а затем сравнить версию с некими барьерными версиями (по каждому браузеру). Если браузер старше барьерных версий, будем выводить сообщение об ошибке.</p>
<p>Детектить версии нужно только популярных в СНГ немобильных версий браузеров, поэтому в моем коде определяется только Opera, Firefox, Safari, Internet Explorer и Google Chrome. Если вам потребуется определить версии большего числа браузеров, код можно легко дополнить.</p>
<p>Чтобы не раскидывать функции по проекту, весь код я оформляю в классы. Создадим статический класс, в котором будут два метода: определение версии браузера и сравнение версии с данными барьерными версиями по каждому из браузеров. Назовем его BrowserUtils.</p>
<p><script src="http://pastie.org/618513.js"></script> Класс состоит из двух методов: определение браузера и его версии и сравнении полученной версии с пороговыми версиями по разным браузерам. Использовать класс очень просто:  <script src="http://pastie.org/618518.js"></script></p>
<p>Единственный нюанс по коду есть у Safari. Все версии этого браузера всегда посылали в UserAgent тег Safari/build, где buld — версия их движка. Это большая первая цифра, например 528.16. Так версии Safari отображаются в Google Analytics. Но более поздние версии стали писать свою версию в теге Version. Выглядит это примерно так: Version/4.0.2.</p>
<p>Так как мне требовалось выводить версию пользователю, я использовал код считывания версии из тега Version, а для старых версий не детектит номер версии.</p>
<p><a href="http://valera.ws/files/browser_detection.zip">Скачать</a> PHP-код определения версии браузера.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2009.09.16~browser-version-detection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Установка eAccelerator в Debian etch</title>
		<link>http://valera.ws/2009.01.26~eaccelerator-debian-etch/</link>
		<comments>http://valera.ws/2009.01.26~eaccelerator-debian-etch/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 17:52:00 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=278</guid>
		<description><![CDATA[К сожалению, пакета eAccelerator в официальных репозиториях Debian Etch нет, по этому устанавливать этот модуль приходится из исходников. О том, как это сделать, и написано ниже. Перед установкой wAccelerator&#8217;а необходимо установить несколько требуемых для сборки пакетов: # apt-get install build-essential &#8230; <a href="http://valera.ws/2009.01.26~eaccelerator-debian-etch/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>К сожалению, пакета <a href="http://eaccelerator.net/" target="_blank">eAccelerator</a> в официальных репозиториях Debian Etch нет, по этому устанавливать этот модуль приходится из исходников. О том, как это сделать, и написано ниже.</p>
<p><span id="more-278"></span>Перед установкой wAccelerator&#8217;а необходимо установить несколько требуемых для сборки пакетов:</p>
<p><code># apt-get install build-essential <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a>5-dev</code></p>
<p>Теперь можно скачать и установить eAccelerator по следующей схеме (<a href="http://eaccelerator.net/wiki" target="_blank">убедитесь</a>, что скачиваете последниюю версию исходников):</p>
<p><code> # cd /tmp<br />
 # wget http://bart.eaccelerator.net/source/0.9.5.3/eaccelerator-0.9.5.3.tar.bz2<br />
 # tar xvfj eaccelerator-0.9.5.3.tar.bz2<br />
 # cd eaccelerator-0.9.5.3<br />
 # phpize<br />
 # ./configure<br />
 # make<br />
 # make install</code></p>
<p>eAccelerator установлен! Теперь необходимо настроить в конфиге PHP использование eAccelerator&#8217;а. В Debian Etchконфигурационные файлы для различных расширений PHP 5 хранятся в каталоге /etc/php5/conf.d, а ссылка на этот каталог присутствует в конфигурационном файле PHP5 /etc/php5/apache2/php.ini, что означает, что все файлы из /etc/php5/conf.d считываются при запуске или перезапуске Apache. Так что все, что нам надо сделать, это создать файл /etc/php5/conf.d/eaccelerator.ini следующего содержания:</p>
<p><code>vi /etc/php5/conf.d/eaccelerator.ini</code></p>
<p><code>extension="eaccelerator.so"<br />
 eaccelerator.shm_size="16"<br />
 eaccelerator.cache_dir="/var/cache/eaccelerator"<br />
 eaccelerator.enable="1"<br />
 eaccelerator.optimizer="1"<br />
 eaccelerator.check_mtime="1"<br />
 eaccelerator.debug="0"<br />
 eaccelerator.filter=""<br />
 eaccelerator.shm_max="0"<br />
 eaccelerator.shm_ttl="0"<br />
 eaccelerator.shm_prune_period="0"<br />
 eaccelerator.shm_only="0"<br />
 eaccelerator.compress="1"<br />
 eaccelerator.compress_level="9"</code></p>
<p>(Про разлиные настройки модуля можно почитать на странице: http://www.eaccelerator.net/wiki/Settings.)</p>
<p>Как видно из конфигурации, каталог /var/cache/eaccelerator используется для хранения кэша опкода PHP на диске. Его необходимо создать вручную и разрешить на запись:</p>
<p><code>mkdir -p /var/cache/eaccelerator<br />
 chmod 0777 /var/cache/eaccelerator</code></p>
<p>Теперь перезагружаем Apache и eAccelerator начинает работать:</p>
<p><code>/etc/init.d/apache2 restart</code></p>
<p>При помощи функции phpinfo() убедитесь, что модуль успешно подключен и функционирует.</p>
<p>Исходный материал на английском: <a href="http://www.howtoforge.com/eaccelerator_php5_debian_etch" target="_blank">http://www.howtoforge.com/eaccelerator_php5_debian_etch</a></p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2009.01.26~eaccelerator-debian-etch/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Хабро́метр — новый сервис логирования и отображения значений кармы и хабросилы</title>
		<link>http://valera.ws/2009.01.14~habrometr/</link>
		<comments>http://valera.ws/2009.01.14~habrometr/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 14:38:59 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>
		<category><![CDATA[habrahabr]]></category>
		<category><![CDATA[рейтинг]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=269</guid>
		<description><![CDATA[Хаброметр — сервис логирования значений кармы, хабрасилы и позиции в рейтинге хабрапользователя и отображения этой информации на информерах, которые можно вставить в профиль, блог, форум и т.д. Для этих целей уже давно был написан Кармаграф от Goodrone . Но развитие &#8230; <a href="http://valera.ws/2009.01.14~habrometr/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://habrometr.server.valera.ws/">Хаброметр</a> — сервис логирования значений кармы, хабрасилы и позиции в рейтинге хабрапользователя и отображения этой информации на информерах, которые можно вставить в профиль, блог, форум и т.д.</p>
<p><a href="http://habrometr.server.valera.ws/?action=user_page&amp;user=feedbee"><img title="Хаброметр feedbee" src="http://habrometr.server.valera.ws/habrometr_425x120.php" alt="Хаброметр feedbee" /></a> <img title="Хаброметр feedbee" src="http://habrometr.server.valera.ws/habrometr_88x120.php" alt="Хаброметр feedbee" /></p>
<p><img title="Хаброметр feedbee" src="http://habrometr.server.valera.ws/habrometr_88x15.php" alt="Хаброметр feedbee" /></p>
<p><span id="more-269"></span></p>
<p>Для этих целей уже давно был написан <a href="http://habrahabr.ru/blogs/ilhh/10994/">Кармаграф</a> от <a class="user_link" href="http://goodrone.habrahabr.ru/">Goodrone</a> . Но развитие его сейчас заморожено, а сам движок сломался и значения счетчиков не обновляется с прошлого года (на момент написания). Это и подтолкнуло написать свой кармаграф именно сейчас.</p>
<p>Считать ли само слово «кармаграф» названием конкретного сервиса от Goodrone, либо же наименованием класса сервисов (или самого графика) — не знаю. Чтобы не заморачиваться с этим вопросом, свой кармаграф решил назвать иначе — Хаброметр. Ведь не только карму он считает и показывает, но еще хабрасилу и позицию в рейтинге (все, что выдает на данный момент API Хабра). Хаброметр отличается от Кармаграфа не смотря на визуальную схожесть дизайна основного информера. Конечно, я постарался взять все лучшее у Кармаграфа. Основное отличие Хаброметра — информеров будет несколько разных видов. Уже сейчас доступны три вида — кармаграфик, табло и минитабло.</p>
<p>Итак, пару слов о том что получилось. Весь сервис состоит из подсистемы сбора информации и подсистемы ее визуализации. Каждые 2 часа бот собирает информацию о значениях кармы, хабрасилы и позиции в рейтинге (я называю эти данные Хабразначениями) через API Хабра по всем зарегистрированным на сервисе пользователям. Данные сохраняются в базу. В любое время любой желающий может зайти на страницу пользователя и посмотреть историю его Хабразначений. Сейчас показывается история из 500 последних запросов (12 запросов в сутки, получается чуть больше 40 дней). В перспективе отображение определенно изменится, появится календарь. Кроме того, существуют графические информеры, на которых отображаются текущие Хабразначения юзера, максимальные и минимальные значения за время мониторинга и график кармы (наличие определенных компонентов зависит от типа (размера) информера).</p>
<p>Все скрипты написаны на <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>, СУБД используется MySQL (пока во всяком случае). Для рисования используется ImageMagick. Для запуска по расписанию — Cron.</p>
<p>Работает сервис на моем сервере (server.valera.ws), который, к слову, не очень мощный и может не выдержать хабраэффекта. Кстати, с технической точки зрения есть одно существенное отличие работы Хаброметра от Кармаграфа — информеры рисуются не по расписанию после скачки свежих данных, а при первом запросе на отображение информера после обновления данных. Другими словами, после прорисовки информера он кэшируется. Сама прорисовка происходит очень быстро. А кэш чистится после скачки свежих данных. Это позволяет разнести пиковую нагрузку на прорисовку свежих информеров во времени. К тому же, не все зарегистрированные юзеры вообще где-то разместят информеры, а тем более не разместят информеры сразу всех типов. Так что разовая прорисовка всех информеров была бы излишней.</p>
<p>Естественно сервис предоставляется «как есть» и бесплатный для использования. Код Хаброметра я собираюсь открыть, но несколько позже. Сначала требуется отладить его работу, исправить ошибки (которые там наверняка найдутся). Код будет открыт под лицензией GPL 3.</p>
<p>Сейчас сервис работает в режиме beta-тестирования. Буду рад вашим отзывам, багрепортам на e-mail feedbee@gmail.com. В первую очередь хочется добиться стабильности работы и оптимизации ресурсозатрат сервиса. Ну а далее уже заботиться об удобстве пользования.</p>
<p>Первым делом постараюсь доделать запланированные виды информеров. Это 31х31, 88х31 и 350х20. Так же надо будет что-то придумать с расширением цветовых гамм. Когда будет время, поработаю над дизайном страниц сервиса.</p>
<p>P.S. Сайт сервиса (описание системы и бота): <a href="http://habrometr.server.valera.ws/">http://habrometr.server.valera.ws</a>.</p>
<p>P.S.S. Домен такой выбирал не специально, так случилось что server.valera.ws != valera.ws. Потому такой длинный.</p>
<p>P.S.S. Если из-за хабраэффекта накроется мой сервер, уже не кидайте много камней в огород. Пока не было возможности испытать его под нагрузкой.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2009.01.14~habrometr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Локальная офисная версия сайта</title>
		<link>http://valera.ws/2008.12.06~office-website/</link>
		<comments>http://valera.ws/2008.12.06~office-website/#comments</comments>
		<pubDate>Sat, 06 Dec 2008 14:05:24 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[сайты]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=213</guid>
		<description><![CDATA[Часто в компаниях есть штатные редакторы, которые работают с некими сайтами этой, принадлежащими ей — наполняют их контентом, модерируют и т.д. Обычно редакторы вместе с обычными пользователями пользуются одной версией сайта, которая располагается на хостинге в сети. Но это не &#8230; <a href="http://valera.ws/2008.12.06~office-website/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Часто в компаниях есть штатные редакторы, которые работают с некими сайтами этой, принадлежащими ей — наполняют их контентом, модерируют и т.д. Обычно редакторы вместе с обычными пользователями пользуются одной версией сайта, которая располагается на хостинге в сети. Но это не оптимально, так как лишний трафик (прежде всего HTML-код страниц, рисунки, css) гуляет с сервера на офис, занимая внешний канал компании и тратя трафик веб-сервера. При мдленном внешнем канале тратится так же и время редакторов.</p>
<p><span id="more-213"></span>В идеале, в данном случае передавать необходимо только добавляемые и получаемые данные, так как весь антураж может быть сохранен и доступен в пределах офиса локально.</p>
<p>Для решения этой задачи можно использовать общую базу данных, которая будет  располагаться на хостинге. На сервере в локальной сети поднять сайт, указать для  подключения к СУБД параметры доступа к база на удаленном сервере. Таким образом, у вас будут 2 одинаковых сайта, параллельно работающих с одним источником данных.</p>
<p>В принципе это обычная схема для балансировки нагрузки на фронтэнд (web-сервер). Практику много фронтэндов — один бэкэнд (база) применяют довольно часто, а следующий этап разделения нагрузки (когда уже СУБД не выдерживает напора) — кластеризация серверов баз данных. Но это лирическое отступление.</p>
<p>Следуюет учесть три нюанса. Во-первых, так как сервера у нас теперь два, время на них может быть разное. Следовательно при записи в базу временные показатели будут для серверов расходиться и может возникнуть путаница. Чтобы этого избежать, проще всего брать время из СУБД. Делать это надо естественно 1 раз за запрос (кэшировать), а не при каждой необходимости (при условии, что запрос выполняется не более 1 секунды; если больше, значит ваша система нуждается в оптимизации). Таким образом время на всех серверах будет синхронизировано по времени на сервере с СУБД.</p>
<p>Второй нюанс заключается в том, что по сети информация между сервером на офисе и базой у провайдера будет ходить в открытом виде, что потенциально опасно. Так же опасно создавать пользователя, которому будет разрешено удаленно подключаться к сети с любого хоста, так как получив ваш пароль злоумышленник легко завладеет базой и сайтом (если <a href="http://valera.ws/tag/ip/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  IP">IP</a> статичский, второй аспект не актуален).</p>
<p>Решить эту проблему можно через подключение к СУБД по защищенному SSL-протоколу. Популярные СУБД поддерживают SSL (MySQL, PgSQL). Подключение клиента к серверу через SSL поддерживают родные C API этих СУБД, и PHP MySQL/PgSQL API тоже. Но SSL не поддерживается PDO (во всяком случае я не нашел информацию о поддержке), который в настоящее время очень популярен и который следует использовать. По этому вариант подключения к базе через SSL отпадает.</p>
<p>Остается другой, довольно простой для использования и сложный для настройки вариант — перегон трафика между офисом и хостингом через VPN. Сам <a href="http://valera.ws/2008.11.21~traffic-security/">VPN я уже описывал</a> в своем блоге. После поднятия VPN-тоннеля необходимо прописать роут на IP вашего сервера (того сервера, где находится СУБД) через виртуальный интерфейс VPN-соединения. Таким образом весь трафик между PHP и СУБД будет ходить по безопасному зашифрованному каналу.</p>
<p>Третий нюанс заключается в кэшировании. Часто кэш некоторых элементов заводят пожизненно (или на долгое время), а сбрасывается он только при изменении данных редактором. В этом случае, при внесении изменений на одном из серверов, кэш не сбросится на втором и на неопределенный срок там останется неактуальная информация. Эта проблема решается через изменение стратегии кэширования, либо использование общего сервера кэширования и выходит за рамки данной статьи. Если именно этот вопрос для вас остается актуальным, ищите информацию в гугле, т.к. та же самая проблема существует при  балансировке нагрузки путем &laquo;размножения&raquo; фронэндов.</p>
<p>Когда все проблемы решены, все что остается делать — это следить за тем, чтобы версии скриптов на серверах в сети и на офисе были одинаковыми, чтобы не повредить базу.</p>
<p>Теперь редакторы сайта смогут пользоваться более быстрой локальной версией сайта, но все изменения будут отображаться в том числе и на сайте в сети.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.12.06~office-website/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Статистика Google Analytics на вашем сайте</title>
		<link>http://valera.ws/2008.11.30~googleanalytics/</link>
		<comments>http://valera.ws/2008.11.30~googleanalytics/#comments</comments>
		<pubDate>Sun, 30 Nov 2008 14:16:45 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>
		<category><![CDATA[статистика]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=207</guid>
		<description><![CDATA[Один добрый хабрапользователь Andex написал на Хабре статью о том, как на свой сайт экспортировать статистику с Google.Analytics. Подробности читайте в соответствующем блоге. Все замечательно работает (на момент 30 ноября 2008 года), и хорошо выглядит даже дефолтовый набор отчетов, который &#8230; <a href="http://valera.ws/2008.11.30~googleanalytics/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Один добрый хабрапользователь <a href="http://andex.habrahabr.ru/" target="_blank">Andex</a> <a href="http://habrahabr.ru/blogs/webdev/42080/" target="_blank">написал</a> на <a href="http://habrahabr.ru" target="_blank">Хабре</a> статью о том, как на свой сайт экспортировать статистику с <a href="http://www.google.com/analytics/" target="_blank">Google.Analytics</a>. Подробности читайте в <a href="http://habrahabr.ru/blogs/webdev/42080/" target="_blank">соответствующем блоге</a>. Все замечательно работает (на момент 30 ноября 2008 года), и хорошо выглядит даже дефолтовый набор отчетов, который автор делал для себя. Но есть один недостаток для меня, который я исправил.</p>
<p><span id="more-207"></span>Но обо всем по порядку. Для начала <a href="http://habrahabr.ru/blogs/webdev/42080/" target="_blank">прочитайте статью</a> Andex&#8217;а и &laquo;заведите&raquo; статистику на web-сервере.</p>
<p>Если во время установки что-то не заработало, читайте комментарии.</p>
<p>У меня возникла такая проблема: если сходу ошибиться с паролем, то система обратиться к гуглу с неправильным паролем столько раз, сколько отчетов экспортируется. В дефалтном варианте это 8 раз. После этого гугл естественно будет требовать от вас ввода каптчи, чтобы убедиться, что вы не подбираете пароли. А возвращать в этом случае он будет временный редирект (Temporary redirect). Его вы в логе и увидите, при этом stat.php будет вывалить нутисы про Undefined index&#8217;ы. В этом случае, надо подождать минут 20, а потом повторно запросить статистику, и все будет хорошо :)</p>
<p>Что меня не устроило в дефалтовых отчетах? Только то, что графики по посетителям и по посещениям были разделены. Вместо того, чтобы на одном графике сделать 3 кривых, было сделано 2 графика по 2 кривых (посетители + просмотры, посещения + просмотры).</p>
<p>Я решил это исправить. Но исправить так, чтобы ковырять готовый код по минимуму для простоты и быстроты решения, и для совместимости с потенциальными будущими апдейтами.</p>
<p>Итак, что нужно сделать? Нужно составить новый сводный отчет (*.csv), в котором будут храниться объединенные данные по посетителям, посещениям и просмотрам. И нужно сделать *settings.xml-файл, в котором будут настройки визуализации нового графика.</p>
<p>Генерацию сводного отчета я вынес в функцию. Она берет два отдельных отчета и составляет из них общий:</p>
<pre>function makeFull($postfix = '')
{
	$fvisits = fopen($GLOBALS["path"] . "visits$postfix.csv", 'r');
	$fvisitors = fopen($GLOBALS["path"] . "visitors$postfix.csv", 'r');
	$ffull = fopen($GLOBALS["path"] . "full$postfix.csv", 'w');
	while (!feof($fvisits))
	{
		$visits_line = explode(';', fgets($fvisits));
		$visitors_line = explode(';', fgets($fvisitors));
		if (count($visits_line) == 3 &amp;&amp; count($visitors_line) == 3)
		{
			// новая строка =     дата       ;        посетители       ;       посещения       ;       показы &amp; \n
			$new_line = $visitors_line[0] . ';' . $visitors_line[1] . ';' . $visits_line[1] . ';' . $visitors_line[2];
			fputs($ffull, $new_line);
		}
	}
	fclose($fvisits);
	fclose($fvisitors);
	fclose($ffull);
}</pre>
<p>Эту функцию надо поместить в stat.php (например в конец). Вызвать ее нужно 2 раза (отчет за все время и отчет за последние 3 месяца):</p>
<pre>makeFull();
makeFull('_3');</pre>
<p>Это нужно делать после генерации соответствующих отчетов, т.е. проще всего дописать в конце файла stat.php.</p>
<p>Далее из файлов visitors_3_settings.xml и visitors_settings.xml я сделал копии (full_3_settings.xml и full_settings.xml) и добавил в настройках графиков новый график-кривую (новую секцию &lt;graph gid=&raquo;3&#8243;&gt;&lt;/graph&gt;).</p>
<p>Осталось подредактировать index.php, чтобы новые графики отображались вместо старых. В index.php вместо кода первых четырех графиков появился следующий код:</p>
<pre>	&lt;div id="visitors" align="center" style="padding-bottom:80px"&gt;
&lt;strong&gt;Для просмотра сожержимого, установите последнюю версию Adobe Flash Player&lt;/strong&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
	// &lt;![CDATA[
	var so = new SWFObject("amline.swf", "amline_chart", "600", "350", "8", "#FFFFFF");
	so.addVariable("path", "./amline/");
	so.addVariable("settings_file", escape("full_settings.xml?&lt;?php echo mktime();?&gt;"));
	so.addVariable("data_file", escape("full.csv?&lt;?php echo mktime();?&gt;"));
	so.addVariable("preloader_color", "#BBBBBB");
	so.write("visitors");
	// ]]&gt;
&lt;/script&gt;
&lt;div id="visitors_3" align="center" style="padding-bottom:80px"&gt;
&lt;strong&gt;Для просмотра сожержимого, установите последнюю версию Adobe Flash Player&lt;/strong&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
	// &lt;![CDATA[
	var so = new SWFObject("amline.swf", "amline_chart", "600", "400", "8", "#FFFFFF");
	so.addVariable("path", "./amline/");
	so.addVariable("settings_file", escape("full_3_settings.xml?&lt;?php echo mktime();?&gt;"));
	so.addVariable("data_file", escape("full_3.csv?&lt;?php echo mktime();?&gt;"));
	so.addVariable("preloader_color", "#BBBBBB");
	so.write("visitors_3");
	// ]]&gt;
&lt;/script&gt;</pre>
<p>Вот и все. Теперь страница статистики (index.php) выглядит примерно так:</p>
<div id="attachment_208" class="wp-caption alignnone" style="width: 219px"><a href="http://valera.ws/wp-content/uploads/2008/11/charts.png"><img class="size-medium wp-image-208" title="charts" src="http://valera.ws/wp-content/uploads/2008/11/charts-209x300.png" alt="Вид сводных диаграм из Google.Analytics" width="209" height="300" /></a><p class="wp-caption-text">Вид сводных диаграм из Google.Analytics</p></div>
<p><strong>Скачка готовых файлов</strong>.</p>
<p>Мой мод вывода статистики затронул файлы из <a href="http://code.google.com/p/statga/downloads/list" target="_blank">пакета statga от Andex&#8217;а</a>. Изменения производились в версии statga 2.0.1. Не каснулись пакета только 2 новых файла: full_3_settings.xml и full_settings.xml. Их вы можете смело брать из моего пакета в любом случае. Как модернизировать файлы пакета <a href="http://code.google.com/p/statga/downloads/list" target="_blank">statga</a> для изменения визуализации написано выше. Так что, если Andex обновит версию, вы сможете внести правки вручную. Если нет, можно использовать готовые файлы версии 2.0.1:</p>
<p><a href="http://valera.ws/files/statga_2.0.1_plus_feedbee_mod.zip" target="_blank">Скачать модефицированную версию statga 2.0.1 feedbee mod</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.11.30~googleanalytics/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>О жизни современного программиста</title>
		<link>http://valera.ws/2008.10.25~o-zhizni-sovremennogo-programmista/</link>
		<comments>http://valera.ws/2008.10.25~o-zhizni-sovremennogo-programmista/#comments</comments>
		<pubDate>Sat, 25 Oct 2008 10:52:00 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Жизнь]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=158</guid>
		<description><![CDATA[Реакция на комментарии на Хабре. Да, питонисты — тихие спокойные ребята, а пхп-шники — агрессивные дурачки, потому что: 1) Питонисты и Рубироиды при каждом удобном случае лезут в топики про php и кричат, что php — гавно, а руби/питон — &#8230; <a href="http://valera.ws/2008.10.25~o-zhizni-sovremennogo-programmista/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Реакция на <a href="http://habrahabr.ru/blogs/webdev/43080/#comment_1066520" target="_blank">комментарии на Хабре</a>.</p>
<p>Да, питонисты — тихие спокойные ребята, а пхп-шники — агрессивные дурачки, потому что:</p>
<p>1) Питонисты и Рубироиды при каждом удобном случае лезут в топики про <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a> и кричат, что <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a> — гавно, а руби/питон — круто!</p>
<p>2) На форумах и в IRC-чатах, когда кто-то задает вопрос `как это сделать в php/java/с++/c#` тут же находятся рубироиды и питонщики, которые кричат, что это не надо делать на данном языке, а надо делать на руби или питоне! А автор вопроса — мудак!</p>
<p>3) Когда дается ответ на вопрос `как это сделать в php/java/с++/c#` в несколько строк кода, тут же находится довольный рубироид и пишет все в одну только ему понятную строчку и кричит `вот как все просто на руби, а вы мудаки все еще пишете на ХХХ`!</p>
<p>Как же это уже раздражает…</p>
<p>Ребята, если сидит компания из нескольких человек с пивом и обсуждает, как они хорошо съездили в Крым, не надо влазить в их беседу, объясняя, что Крым гавно, а Египет жжот. Есть большая вероятность, что вы получите в морду.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.10.25~o-zhizni-sovremennogo-programmista/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Профилирование PHP под Windows</title>
		<link>http://valera.ws/2008.10.22~php-profiling-under-windows/</link>
		<comments>http://valera.ws/2008.10.22~php-profiling-under-windows/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 15:02:15 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=151</guid>
		<description><![CDATA[Рано или поздно все программисты PHP сталкиваются с необходимостью профилирования собственного кода. Она возникает на этапе оптимизации работы веб-приложения. Вообще, профилирование — это подсчет затрат времени на выполнение каждой отдельной функции (в том числе методов классов) в контексте времени генерации &#8230; <a href="http://valera.ws/2008.10.22~php-profiling-under-windows/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://valera.ws/wp-content/uploads/2008/10/xdebug.png"><img class="alignleft size-full wp-image-156" title="xdebug" src="http://valera.ws/wp-content/uploads/2008/10/xdebug.png" alt="" width="119" height="70" /></a>Рано или поздно все программисты <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> сталкиваются с необходимостью профилирования собственного кода. Она возникает на этапе оптимизации работы веб-приложения. Вообще, профилирование — это подсчет затрат времени на выполнение каждой отдельной функции (в том числе методов классов) в контексте времени генерации страницы-ответа целиком. О профилировании написано в Интернете достаточно много, поэтому на теории заострять внимание смысла нет. &laquo;Под катом&raquo; описана установка и настройка софта для профилирования <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>-скриптов в ОС Windows.</p>
<p><span id="more-151"></span>Для профилирования нам понадобится компонент подсчета времени выполнения функций PHP и формирования отчета и компонент визуального представления этого отчета для анализа.</p>
<p>Существуют как минимум 3 профайлера PHP-кода: <a href="http://www.xdebug.org/" target="_blank">Xdebug</a>, <a href="http://pecl.php.net/apd" target="_blank">Advanced PHP Debuger</a> и <a href="http://dd.cron.ru/" target="_blank">DBG</a>. Скажу честно, два последних я даже не рассматривал по двум причинам: Xdebug — самый популярный, Xdebug встроен в сборку <a href="http://www.apachefriends.org/en/xampp.html" target="_blank">xampp</a>, которая стоит на моей локальной машине.</p>
<p><strong>Установка Xdebug</strong></p>
<p>Интеграция Xdebug&#8217;а в PHP очень проста. С сайта <a href="http://www.xdebug.org/" target="_blank">www.xdebug.org</a> необходимо скачать DLL-extension для вашей версии PHP. <a href="http://www.xdebug.org/link.php?url=xdebug203-52-win" target="_blank">Вот файл</a> для PHP 5.2.1-5.2.6 под Windows. Скачанный файл необходимо положить в каталог расширений PHP (extension_dir). А в php.ini добавить следующие строки:</p>
<p>extension=php_xdebug.dll</p>
<p>[XDebug]<br />
;; Only Zend OR (!) XDebug<br />
zend_extension_ts=&raquo;<em>c:\php\ext\php_xdebug.dll</em>&raquo;<br />
xdebug.remote_enable=true<br />
xdebug.remote_host=127.0.0.1<br />
xdebug.remote_port=9000<br />
xdebug.remote_handler=dbgp<br />
xdebug.profiler_enable=1<br />
xdebug.profiler_output_dir=&raquo;<em>c:\temp</em>&raquo;</p>
<p>При этом строки секции [Zend] требуется закомментировать (поставить ; в начале каждой строки):</p>
<p>[Zend]<br />
;zend_extension_ts = &laquo;c:\php\zendOptimizer\lib\ZendExtensionManager.dll&raquo;<br />
;zend_extension_manager.optimizer_ts = &laquo;c:\php\zendOptimizer\lib\Optimizer&raquo;<br />
;zend_optimizer.enable_loader = 0<br />
;zend_optimizer.optimization_level=15</p>
<p>Установите правильные пути в параметры zend_extension_ts и xdebug.profiler_output_dir секции XDebug. Путь xdebug.profiler_output_dir — это каталог, в который будет записан файл отчета.</p>
<p>На этом установка Xdebug закончена. Подробности по тонкой настройке этого расширения ищите при необходимости в гугле. Ознакомиться со всеми его возможностями можно на <a href="http://www.xdebug.org/" target="_blank">официальном сайте</a>.</p>
<p><strong>Установка KCachegrind под Windows</strong></p>
<p>Открываем любую страницу вашего сайта и в каталоге xdebug.profiler_output_dir появляется файл отчета. Открывать его в Блокноте или другом средстве просмотра текстовых файлов нет никакого смысла. Его формат невозможно воспринять в текстовом виде. Для просмотра файла отчета понадобится средство <a href="http://kcachegrind.sourceforge.net/cgi-bin/show.cgi" target="_blank">KCachegrind</a>, которое требует наличия KDE для запуска.</p>
<p>Есть, правда, еще <a href="http://sourceforge.net/projects/wincachegrind" target="_blank">WinCachegrind</a>, но эта программулина глючная, слабенькая и с 2005 года не обновляется. Мой файл отчета она прочитать не смогла (parse error).</p>
<p>Итак, приступаем к установке KCachegrind под Windows. Благо, она абсолютно простая.</p>
<ol>
<li>Зайдите на <a href="http://www.winkde.org/pub/kde/ports/win32/installer/" target="_blank">www.winkde.org/pub/kde/ports/win32/installer/</a> и скачайте самую последнюю версию установщика.</li>
<li>Запустите установщик (есть <a href="http://www.winkde.org/pub/kde/ports/win32/installer/manual/" target="_blank">картинки</a> процесса установки), выберите каталог установки (например в C:\KDE), скачайте то, что вам нужно (я выбрал все пакеты — это около 230 Мб).</li>
<li>Добавьте переменную окружения KDEDIRS (<em>Пуск &gt; Панель управления &gt; Система &gt; Дополнительно &gt; Переменные среды</em>, нажмите &laquo;Создать&raquo; в разделе Пользовательские переменные и создайте переменную с именем KDEDIRS и значением равным папке, в которую Вы установили KDE4, напр. C:\KDE).</li>
<li>Добавьте папку библиотек, %KDEDIRS%\lib, и папку исполняемых файлов, %KDEDIRS%\bin, к переменной %PATH% Windows. (<em>Пуск &gt; Панель управления &gt; Система &gt; Дополнительно &gt; Переменные среды</em>, дважды щелкните на системной переменной Path и добавьте эти строки, разделяя их точкой с запятой.)</li>
<li>Если у Вас не установлена Visual Studio 2005 (или 2008), то скачайте и установите &laquo;<a href="http://www.microsoft.com/downloads/details.aspx?familyid=200B2FD9-AE1A-4A14-984D-389C36F85647&amp;displaylang=en" target="_blank">Microsoft Visual C++ 2005 SP1 Redistributable Package (x86)</a>&laquo;.</li>
<li>Попробуйте запустить какое-нибудь Qt приложение в папке bin, например linguist.exe.</li>
<li>Если получилось, попробуйте запустить любое приложение KDE, такое как kwrite.exe.</li>
</ol>
<p><a href="http://techbase.kde.org/Projects/KDE_on_Windows/Installation_(ru)#.D0.9D.D0.B5.D0.BE.D0.B1.D1.85.D0.BE.D0.B4.D0.B8.D0.BC.D1.8B.D0.B5_.D0.BF.D0.B0.D0.BA.D0.B5.D1.82.D1.8B" target="_blank">Дополнительная информация</a> по установке.</p>
<p>На этом установка закончена. Вы можете запустить  KCachegrind (c:\KDE\bin\kcachegrind.exe) и скормить ей файл вашего отчета профайлера.</p>
<p>Дополнительную информацию по профилированию PHP-кода можете почитать на <a href="http://devzone.zend.com/article/2899-Profiling-PHP-Applications-With-xdebug" target="_blank">сайте Zend&#8217;а</a>, а я планирую написать еще статейку на эту тему, может даже завтра.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.10.22~php-profiling-under-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Любые символы в именах переменных в PHP</title>
		<link>http://valera.ws/2008.10.21~lyubye-simvoly-v-imenax-peremennyx-v-php/</link>
		<comments>http://valera.ws/2008.10.21~lyubye-simvoly-v-imenax-peremennyx-v-php/#comments</comments>
		<pubDate>Tue, 21 Oct 2008 10:33:38 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=148</guid>
		<description><![CDATA[Хотите использовать в именах переменных PHP любые символы? Следующий пример абсолютно работоспособен: &#60;?php $name = &#8216;что угодно &#8211; 1 + 44.4&#8242;; $$name  = &#8216;ДА!&#8217;; echo $$name;]]></description>
			<content:encoded><![CDATA[<p>Хотите использовать в именах переменных <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> любые символы?</p>
<p><span id="more-148"></span>Следующий пример абсолютно работоспособен:</p>
<p>&lt;?php</p>
<p>$name = &#8216;что угодно &#8211; 1 + 44.4&#8242;;</p>
<p>$$name  = &#8216;ДА!&#8217;;</p>
<p>echo $$name;</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.10.21~lyubye-simvoly-v-imenax-peremennyx-v-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Smarty 3</title>
		<link>http://valera.ws/2008.10.21~smarty-3/</link>
		<comments>http://valera.ws/2008.10.21~smarty-3/#comments</comments>
		<pubDate>Tue, 21 Oct 2008 07:17:58 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=144</guid>
		<description><![CDATA[Оказывается, шаблонизатор для PHP-сайтов Smarty еще жив! 17 октября на сайте появилась новость о том, что доступен альфа-релиз 3-й версии со значительными изменениями, который не совместим с версией 2. Так как самомуписать обзор изменений лень, приведу выжимку из обсуждения темы &#8230; <a href="http://valera.ws/2008.10.21~smarty-3/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="mceTemp">
<dl class="wp-caption alignleft" style="width: 260px;">
<dt class="wp-caption-dt"><img style="margin-top: 5px; margin-bottom: 5px;" title="Smarty 3" src="http://smarty.net/gifs/smarty-logo-orange.gif" alt="" width="250" height="64" /></dt>
</dl>
</div>
<p>Оказывается, шаблонизатор для PHP-сайтов <a href="http://smarty.net/" target="_blank">Smarty</a> еще жив! 17 октября на сайте появилась новость о том, что доступен альфа-релиз 3-й версии со значительными изменениями, который не совместим с версией 2.</p>
<p><span id="more-144"></span>Так как самомуписать обзор изменений лень, приведу выжимку из обсуждения темы на <a href="http://habrahabr.ru/blogs/php/42810/" target="_blank">habrahabr&#8217;e</a>.</p>
<p>Интерфейс шаблонизатора особо не изменился. Это всё те же display(), fetch() и assign(), которые покрывают процентов 99 всех потребностей. Исчез метод assign_by_ref().</p>
<p>Внутренности же претерпели более существенные изменения:</p>
<ul>
<li>Отказ от поддержки PHP4 и полное использование объектно-ориентированных возможностей PHP5. То есть в шаблонах можно использовать разыменования объектов без костылей;</li>
<li>Объектно-ориентированный подход затронул и плагины: теперь каждый плагин является классом, отнаследованным от Smarty_Internal_PluginBase</li>
<li>Файл основного класса — Smarty.class.php — стал подозрительно маленьким: всего 11 кб, включая здоровенные спойлеры лицензии LGPL ;)</li>
<li>Все требуемые элементы, исключённые из ядра, подгружаются лишь по мере необходимости (lazy loading)</li>
<li>Маленькая приятность — встроенная реализация паттерна singleton.</li>
<li>Поддержка нативных PHP-шаблонов.</li>
</ul>
<p>Надо сказать, что по сравению с веткой 2.x, дистрибутив значительно потолстел: папка libs, экспортированная из SVN, заняла немногим менее 800 кб, в то время как в версии 2.6.20 её вес был был порядка 320 кб.</p>
<p>Подробности о релизе — в официальном <a href="http://smarty-php.googlecode.com/svn/branches/Smarty3Alpha/README" target="_blank">README</a>.</p>
<p>Желающие могут вытащить версию из SVN:<br />
svn checkout <a href="http://smarty-php.googlecode.com/svn/branches/Smarty3Alpha/" target="_blank">smarty-php.googlecode.com/svn/branches/Smarty3Alpha/</a></p>
<p>Вот тут <a href="http://groups.google.com/group/smarty-developers/browse_thread/thread/c29ae569842882cd" target="_blank">groups.google.com/group/smarty-developers/browse_thread/thread/c29ae569842882cd</a> немного про синтаксис:</p>
<p>PHP: &lt;?= $foo ?&gt;<br />
Smarty: {$foo} // same as Smarty 2</p>
<p>PHP: &lt;?= $foo['bar'] ?&gt;<br />
Smarty: {$foo['bar']} // no more {$foo.bar}</p>
<p>PHP: &lt;?= $foo[$bar][$foo['bar']] ?&gt;<br />
Smarty: {$foo[$bar][$foo['bar']] ?&gt; // identical to PHP</p>
<p>PHP: &lt;?php foreach($foo as $bar) {… } ?&gt;<br />
Smarty: {foreach $foo as $bar}… {/foreach} // just a delimiter<br />
adjustment</p>
<p>PHP: &lt;?php for($x = 0; $x&lt;$y; $x++) {… } ?&gt;<br />
Smarty: {for $x=0; $x&lt;$y; $x++}… {/for} // get rid of {section}</p>
<p>PHP: &lt;?php if($foo == $bar &amp;&amp; $blah !== &#8216;ziggy&#8217;) {… } ?&gt;<br />
Smarty: {if $foo == $bar &amp;&amp; $blah !== &#8216;ziggy&#8217;}… {/if}</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.10.21~smarty-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend Framework — это круто!</title>
		<link>http://valera.ws/2008.10.16~zend-framework-eto-kruto/</link>
		<comments>http://valera.ws/2008.10.16~zend-framework-eto-kruto/#comments</comments>
		<pubDate>Thu, 16 Oct 2008 11:12:55 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=134</guid>
		<description><![CDATA[Zend Framework — это круто. Круто, потому что удобно и логично. Потому что в нем нет ничего лишнего: можно использовать как весь фреймворк целиком, так и отдельные его компоненты. Все компоненты можно заменить своими, не нарушая целостности фреймворка. Зенд не &#8230; <a href="http://valera.ws/2008.10.16~zend-framework-eto-kruto/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="mceTemp">
<dl class="wp-caption alignleft" style="width: 133px;">
<dt class="wp-caption-dt"><img style="margin-bottom: 5px; margin-left: 5px;" title="Zend Framework" src="http://framework.zend.com/images/logo_small.gif" alt="" width="123" height="23" align="left" /></dt>
<dd class="wp-caption-dd"></dd>
</dl>
</div>
<p><a href="http://valera.ws/tag/zend-framework/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  zend framework">Zend Framework</a> — это круто. Круто, потому что удобно и логично. Потому что в нем нет ничего лишнего: можно использовать как весь фреймворк целиком, так и отдельные его компоненты. Все компоненты можно заменить своими, не нарушая целостности фреймворка. Зенд не представляет готовые части сайта, и тем более — сайты. <a href="http://valera.ws/tag/zend-framework/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  zend framework">Zend Framework</a> — это помощник в создании сайта, не более того. Очень гибкий, масштабируемый.</p>
<p><span id="more-134"></span>Именно поэтому я и начал его изучать. До сих пор я использовал свой самописанный фреймворк, так как считал, что нет пока достойных альтернатив, с которыми я смогу быстро подружиться, которые не будут вызывать дискомфорт и отвращение при использовании.</p>
<p>В то же время я понимал, что функционал моего фреймворка в разы уступает функционалу и качеству фреймворков, которые написаны профессиональными командами или большим сообществом программистов. Глупо считать, что они человек может написать достойного конкурента таким монстрам, как ZF, CakePHP, symfony. Понимая это, я просто ждал момента, когда сделают достойный перехода на него фреймворк. И вот, похоже, дождался.</p>
<p>Изучать ZF начал с версии 1.6. Почитал Quick Start, затем начал читать мануал. Обратил внимание, что большинство идей ZF сходятся с теми идеями, на которых я строил свой движок, причем автономно, не изучая особенности других фреймворков. Только вот реализация этих идей, естественно, у ZF гораздо лучше, полнее. Факт схожести идей заложил в моем сознании доверие к этому фреймворку. Кроме того, слышал хорошие отзывы о нем от других программистов, которые использовали раньше и используют сейчас разные фреймворки и имеют достойный опыт сравнения.</p>
<p>Может быть эта запись в блоге подвигла вас на изучение ZF? Тогда расскажу вам вот что. Прежде всего, сходите на сайт <a href="http://framework.zend.com/" target="_self">Zend Framework</a>&#8216;а и оглядитесь вокруг :) Изучение начинайте с <a href="http://framework.zend.com/docs/quickstart" target="_blank">Quick Start</a>&#8216;а. Там все довольно хорошо описано, но с большего. Т.е. вы сможете подготовиться к восприятию тонкостей и деталей подробного мануала. Соберите на вашем сервере сайт, который предлагает Quick Start, поэкспериментируйте с ним. Только после этого переходите к полному <a href="http://framework.zend.com/manual/ru/" target="_blank">руководству программиста</a>.</p>
<p>Так как руководство состоит из описания отдельных компонентов фреймворка (52 главы-компонента на данный момент), нужно определиться, с чего начать. Поможет опредлитсья вам как раз Quick Start. Я приведу свой порядок изучения: <a href="http://framework.zend.com/manual/ru/introduction.html" target="_self">Introduction</a>, <a href="http://framework.zend.com/manual/ru/zend.controller.html" target="_self">Zend_Controller</a>, <a href="http://framework.zend.com/manual/ru/zend.cache.html" target="_self">Zend_Cache</a>, <a href="http://framework.zend.com/manual/ru/zend.loader.html" target="_self">Zend_Loader</a>, <a href="http://framework.zend.com/manual/ru/zend.view.html" target="_self">Zend_View</a>, <a href="http://framework.zend.com/manual/ru/zend.layout.html" target="_self">Zend_Layout</a>, <a href="http://framework.zend.com/manual/ru/zend.config.html" target="_self">Zend_Config</a>, <a href="http://framework.zend.com/manual/ru/zend.db.html" target="_self">Zend_Db</a>. Дальнейший порядок, в принципе, значения не имеет.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.10.16~zend-framework-eto-kruto/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Немного о кешировании: memcache</title>
		<link>http://valera.ws/2008.08.09~memcached/</link>
		<comments>http://valera.ws/2008.08.09~memcached/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 17:58:59 +0000</pubDate>
		<dc:creator>Валера Леонтьев</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Все рубрики]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">http://valera.ws/?p=96</guid>
		<description><![CDATA[Установка memcached под Windows Статья с пошаговой инструкцией по установке memcached под ОС Windows. Скачать дистрибутив для Win32 можно отсюда: http://jehiah.cz/projects/memcached-win32/ Мануал по пользованию memcached из PHP: http://www.php.net/memcache. Что кэшируем? 1. Самое важное: кэширование тяжелых запросов к БД, которые при нагрузке &#8230; <a href="http://valera.ws/2008.08.09~memcached/">Читать далее <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>Установка <a href="http://valera.ws/tag/memcached/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  memcached">memcached</a> под Windows</strong></p>
<p>Статья с пошаговой инструкцией <a href="http://www.aberdnikov.ru/info/php/memcache-php5-win32/" target="_self">по установке memcached под ОС Windows</a>. Скачать дистрибутив для Win32 можно отсюда: <a href="http://jehiah.cz/projects/memcached-win32/" target="_blank">http://jehiah.cz/projects/memcached-win32/</a></p>
<p><strong>Мануал</strong> по пользованию memcached из <a href="http://valera.ws/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>: <a href="http://www.php.net/memcache" target="_blank">http://www.php.net/memcache</a>.</p>
<p><span id="more-96"></span></p>
<p><strong>Что кэшируем?</strong></p>
<p>1. Самое важное: кэширование тяжелых запросов к БД, которые при нагрузке тормозят выполнение и грузят сервер. Обычно проблема кэширования запросов заключается в том, что надо знать, когда кэш уже не актуален. Для этого есть два пути: &laquo;срок хранения&raquo; кэша по времени и сброс кэша во время добавления/изменения записей, влиящих на него. Первый способ имеет смысл только тогда, когда не обязательно отображать данные самой последней свежести. В большинстве же случаев, нужно использовать второй способ.</p>
<p>2. Кэширование результатов запросов, которые очень редко меняются. Например, если вы храните настройки сайта в базе, то при каждой загрузке страницы эти настройки надо получить из базы. Такой запрос отработает моментально быстро, и очевидной необходимости его кешировать нет. Но если выделить с десяток таких запросов, то их суммарное время уже можно считать значительным. При этом нагрузка ложится на часто самое узкое место в производительности сайта — демона базы данных. По-этому, может иметь смысл хранить результаты таких запросов на сервере кэширования. Для такого кэширования подойдет только способ 2 из пункта 1. Кстати, сюда же можно отнести кэширование &laquo;статических страниц&raquo;, которые динамически генерирует CMS.</p>
<p>3. Кэширование вместо генерации. Это касается ,больших объектов, которые используются при каждом запросе страницы сайта, и время инициализации которых довольно значительное, а так же кэширование данных, на получение которых уходит длительное время (например получение информации от других серверов из сети).</p>
<p><strong>Юзерозависимость</strong></p>
<p><strong></strong>Все закэшированные данные можно разделить на два класса: юзерозависимые и юзеронезависимые. Это деление имеет значение для создания логики работы подсистемы кэширования. Юзерозависимые данные — это информация, актуальная только для одного данного пользователя (например, количество новых сообщений на форуме). Юзеронезависимые данные — информация, актуальная для всех пользователей (например, количество товаров в каталоге интернет-магазина).</p>
<p>В случае юзерозависимой сущности кэширования надо хранить не один элемент данных (например, число), а массив этих элементов, в котором ключ — id пользователя. И операции с такой сущностью должны быть следующие: а) получение/установка/удаление данных сущности для данного пользователя, б) получение/удаление данных сущности для всех пользователей. Для обеспечения автоматизации работы такого функционала удобно написать класс-оболочку для memcached, заточенную под конкретный фреймворк/cms (так как подсистема пользователей у всех реализована по-разному).</p>
<p><strong>Чего не хватает в memcache?</strong></p>
<p>Вобщем-то всего там хватает, потому что сама библиотека (представленная как extionsion в php) представляет собой лишь инструмент для хранения кэшированных данных. Чтобы обеспечить удобную работу с кэшем, необходимо надстроить над механизмом хранения контроллер взаимодействия (интерфейс). В первую очередь он должен обеспечить функционал &laquo;<em>пространств имен</em>&raquo; для создания условий модульной разработки, что очень важно в MVC. Так же он должен обеспечить работу с <em>юзерозависимыми данными</em> через пару &laquo;ключ—id пользователя&raquo; и соответствующие связанные операции, упомянутые выше. Нужна и возможность <em>пометки данных по принадлежности к некоему классу</em>, чтобы потом очистить сразу весь кэш, относящийся к данному классу (например, при обновлении таблицы, от которой зависит вся хранимая в кэше информация данного класса).</p>
<p>Думаю, что завтра реализую оболочку для API memcached в PHP, которая реализует эти три дополнения, и открою ее для всех желающих.</p>
]]></content:encoded>
			<wfw:commentRss>http://valera.ws/2008.08.09~memcached/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

