<?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://miracle.rpz.name/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://miracle.rpz.name</link>
	<description>Sorry for my terrible english. My native language is PHP.</description>
	<lastBuildDate>Thu, 12 Jan 2012 20:42:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4-alpha-19719</generator>
		<item>
		<title>Асинхронные задачи в PHP</title>
		<link>http://miracle.rpz.name/2011/04/16/asynchronous-jobs-with-pure-php/</link>
		<comments>http://miracle.rpz.name/2011/04/16/asynchronous-jobs-with-pure-php/#comments</comments>
		<pubDate>Sat, 16 Apr 2011 19:59:54 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=450</guid>
		<description><![CDATA[Не открою Америки, если скажу что порой требуется выполнить некую времязатратную операцию, результат которой либо не нужен пользователю вовсе (запись в лог, удаление временных файлов и другое обслуживание сервера), либо его можно обмануть и сказать что операция выполнена успешно, а саму операцию выполнить &#8220;попозже&#8221;. Самым наверное близким всем примером такой операции можно назвать отправку почты [...]]]></description>
			<content:encoded><![CDATA[<p>Не открою Америки, если скажу что порой требуется выполнить некую времязатратную операцию, результат которой либо не нужен пользователю вовсе (запись в лог, удаление временных файлов и другое обслуживание сервера), либо его можно обмануть и сказать что операция выполнена успешно, а саму операцию выполнить &#8220;попозже&#8221;. Самым наверное близким всем примером такой операции можно назвать отправку почты &#8211; smtp-cессия может длится довольно долго, особенно если письмо огромное, сервер тормозной (ну да вы сами всё знаете, в реальном мире великое множество острых углов), но зачем пользователю ждать результата? Что ему делать если результат неуспешный? &#8220;Попробуйте повторить операцию позже&#8221; ? Не смешно! Рядовой пользователь на ваш рядовой ресурс не вернётся, дотошный &#8211; свяжется с вами другими способами, так что можно с чистой совестью соврать ему &#8211; мол всё путём, всё отправлено, всё доставлено, записано и всё так успешно и идеально, а в это время потихоньку начать на самом деле выполнять задачу.</p>
<p>Конечно если вокруг вас крутятся тысячи серверов, слово &#8220;ынтырпрайз&#8221; для вас звучит буднично, то для вас уже изобретено много-много buzz-word-ных решений с очередями сообщений, очередями задач и другими полезными решениями, но львиная доля разработчиков всё-таки создают сайты-визитки, поддерживают сайты на хостинг-планах &#8220;всё по 20 рублей&#8221;, да и вообще на мой взгляд глупо <a href="http://highload.com.ua/index.php/2010/07/09/gearman-и-php-асинхронные-задачи/">для отправки почты окружать простейший php-скрипт кучей софта вроде gearmand + расширения для работы с ним</a>. Я же хочу показать решение &#8220;для бедных&#8221;, <strong>простое, но удобное в разработке, поддержке и отладке решение</strong>.</p>
<p>Итак задача &#8211; отправить письмо, не заставляя ждать пользователя.<br />
Имеем:</p>
<pre class="php">
list($recipient,$subject,$body) = get_vars_from_request();
include 'superpupermailer.php';
$mailer = new SuperPuperMailer($recipient,$subject,$body);
if ($mailer->send()) {
echo "Аллилуя! Мы сделали это, храни нас Великий Байт.";
} else {
echo "О нет, это случилось!!! Быть того не может...но всё же случилось - приходи, милый друг, в другой раз, а сейчас ошибка!";
}
</pre>
<p>Тут всё понятно &#8211; либо отправилось, либо не отправилось &#8211; всем приходилось видеть это с разных сторон, те кто видел это со стороны браузера нередко наблюдали не только &#8220;ошибочка вышла&#8221;, но и другие подробности вроде конкретных строк в скриптах, warning-ов и Fatal error-ов. Но мы уже выяснили ранее &#8211; во-первых пользователю совершенно по барабану что у вас произошло с сервером, а во-вторых &#8220;пробовать ещё раз&#8221; он скорее всего не будет. Поэтому код можно изменить следующим образом:</p>
<pre class="php">
list($recipient,$subject,$body) = get_vars_from_request();
$async_job = '<?php include "superpupermailer.php"; $mailer = new SuperPuperMailer("'.$recipient.'","'.$subject.'","'.$body.'");
return $mailer->send();';
if (file_put_contents('/dir/for/jobs/email.php',$async_job)) {
echo "Ура! Мы сделали этот мир лучше!";
} else {
echo "Увы, мир жесток и безжалостен...";
}
</pre>
<p>Что это и зачем? Где отправка почты? Каким образом письмо отправится? Больше вопросов чем ответов. Опять-таки остался <em>else</em>, шило поменяли на мыло? В целом да &#8211; заменили тёплое мягким, но всё-таки нет &#8211; как часто у вас заканчивается неудачей запись на диск? Чаще чем таймаут при коннекте к почтовому серверу? </p>
<p>Теперь о главном &#8211; зачем файл? Где отправка почты?</p>
<p>Этим займётся другой скрипт:</p>
<pre class="php">
if (true === include('/dir/for/jobs/email.php')) {
  unlink('/dir/for/jobs/email.php');
}
</pre>
<p>Осталось вызвать этот скрипт. Например так:</p>
<pre class="php">
...
echo 'Ура! Мы сделали этот мир лучше!<img src="/job.php" height="1" width="1">';
...
</pre>
<p>Или же добавим в cron задание на вызов job.php каждый час/пять минут/каждую минуту.</p>
<p>Всё. Мы <strong>не заставили пользователя ждать</strong>, мы отправили сообщение, мы молодцы. А если не отправили? Отправим потом &#8211; файл-то остался!</p>
<p>Конечно возникает много закономерных возражений &#8211; что будет если send.php (или job.php) будет вызван одновременно двумя пользователями?<br />
Эти вопросы надо обстоятельно решать, задачи создавать с уникальными именами, блокировать одновременный запуск скрипта job.php, в общем работы аж на целых десять минут.</p>
<p>Самое интересное в конце:</p>
<pre class="php">
...
$job_name = uniqid('mail_');
if (file_put_contents('/dir/for/jobs/'.$job_name.'.php',$async_job)) {
   echo "Ура! Мы сделали этот мир лучше!";
              $job_url = '/job.php?job='.$job_name;
              if (false !== ($fh = @fsockopen($_SERVER['SERVER_ADDR'], $_SERVER['SERVER_PORT'],
    $errno, $errstr, 0.01))) {
                  fputs($fh,
                      "GET $job_url HTTP/1.0\r\n"
                          . "Host: {$_SERVER['HTTP_HOST']}\r\n\r\n"
                  );
                  fgets($fh,32);
                  fclose($fh);
              }

} else {
   echo "Увы, мир жесток и безжалостен...";
}
</pre>
<p>Что здесь происходит? Мы создали php-файл, при выполнении которого отправится письмо, затем подключились к веб-серверу и запросили скрипт job.php, передав ему параметром имя только что созданного файла. И тут же отключились &#8211; ведь нам не важен результат, мы уже солгали пользователю о том, что операция завершилась успешно. На всё-про всё потратили доли секунды.  Дальше уже дело техники &#8211; job.php захватит lock-файл, проверить наличие файла, имя которого ему передали, выполнит его, удалит в случае успеха, а затем отпустит lock-файл. Конечно надо не забывать, что скрипт может по каким-то причинам не выполнится (почтовый сервер недоступен, или ответит ошибкой, да и мало ли какие напасти происходят в реальности), поэтому следует вызывать job.php ещё и ещё, но пользователя это уже не должно волновать &#8211; у вас его письмо сохранилось и вы его доставите, он вам верит!</p>
<p>Разумеется решение годится не только для отправки почты, но и как я сказал в начале &#8211; <strong>для любых действий, результат которых не нужен немедленно</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2011/04/16/asynchronous-jobs-with-pure-php/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>PhpStorm</title>
		<link>http://miracle.rpz.name/2011/02/28/phpstorm/</link>
		<comments>http://miracle.rpz.name/2011/02/28/phpstorm/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 18:43:01 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[advertise]]></category>
		<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ide]]></category>
		<category><![CDATA[phpstorm]]></category>
		<category><![CDATA[xdebug]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=414</guid>
		<description><![CDATA[С недавних пор начал плотно использовать PhpStorm на работе &#8211; с появлением в системнике &#8220;лишней&#8221; памяти она (IDE) стала ну просто космически быстрой, дьявольски умной и невероятно удобной. Одно тяготило меня &#8211; не нашёл возможности увидеть вывод отлаживаемого скрипта. Особенно яростно это давит в момент отладки веб-сервисов. И вот сегодня утром IDE предложила написать о [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://miracle.rpz.name/shared/2011/phpstorm-linux.png" rel="tn"><img src="http://miracle.rpz.name/shared/2011/tn_phpstorm-linux.png" align="right" hspace="5"></a>С недавних пор начал плотно использовать <a href="http://www.jetbrains.com/phpstorm/">PhpStorm</a> на работе &#8211; с появлением в системнике &#8220;лишней&#8221; памяти она (IDE) стала ну просто космически быстрой, дьявольски умной и невероятно удобной. Одно тяготило меня &#8211; не нашёл возможности увидеть вывод отлаживаемого скрипта. Особенно яростно это давит в момент отладки веб-сервисов. И вот сегодня утром IDE предложила написать о себе отзыв. И я не отказал ей в тёплом слове и заодно спросил &#8211; где же, чёрт возьми, output?!</p>
<p>Был приятно удивлён скорой реакцией на запрос &#8211; приветливый support попытался мне помочь, а затем мы выяснили, что данный функционал ещё в пути и пока не готов. В связи с чем хочу выразить благодарность читателю за то, что он зайдёт на трекер к разработчикам и проголосует за эти фичи: <a href="http://youtrack.jetbrains.net/issues/WI?q=%23WI-4323+%23WI-4466">#WI-4323 и #WI-4466</a> и отдельные &#8220;спасибы&#8221; раздать Сергею Баранову и Николаю Матвееву за скорую и адекватную помощь и снисхождение к русскоязычной аудитории пользователей.</p>
<p>P.S.</p>
<p>Если вы понятия не имеете о чём идёт речь, но разрабатываете на PHP, вы просто обязаны попробовать PhpStorm в деле &#8211; <a href="http://confluence.jetbrains.net/display/WI/Web+IDE+EAP">скачать eap-релиз можно на сайте разработчиков</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2011/02/28/phpstorm/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>commit-jabber</title>
		<link>http://miracle.rpz.name/2009/02/24/commit-jabber-php/</link>
		<comments>http://miracle.rpz.name/2009/02/24/commit-jabber-php/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 14:38:04 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[jabber]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=213</guid>
		<description><![CDATA[После прочтения статьи о том, как в last.fm используют irc для логирования всего и вся тоже захотелось как-нибудь &#8220;выпендриться&#8221;. Мониторить сервера нам ни к чему, да и irc &#8211; поди объясни сейчас что это такое и чем оно лучше _______. Но недавно выдалась свободная минутка и я нашёл куда приложить усилия. Решил сделать post-commit хук [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://miracle.rpz.name/shared/2009/svnlog-psi.png" alt="" align="right" /><br />
После прочтения статьи о том, как в <a href="http://last.fm/">last.fm</a> <a href="http://www.metabrew.com/article/how-we-use-irc-at-lastfm/">используют irc для логирования</a> всего и вся тоже захотелось как-нибудь &#8220;выпендриться&#8221;.<br />
Мониторить сервера нам ни к чему, да и irc &#8211; поди объясни сейчас что это такое и чем оно лучше _______. Но недавно выдалась свободная минутка и я нашёл куда приложить усилия.<br />
Решил сделать post-commit хук в svn-репозитарии, который будет высылать детали о коммите, но не на почту, как это делается в <a href="http://subversion.tigris.org/tools_contrib.html#hook_scripts">традиционных скриптах</a>, а в <strong>jabber</strong> (cам jabber достался нам вместе с <a href="http://google.com/a/">почтой от гугла</a>) .<br />
По-моему получилось очень удобно и за несколько дней превратилось из игрушки в удобный инструмент для своевременного обновления и обнаружения &#8220;ну и зачем ты это сделал&#8221; <img src='http://miracle.rpz.name/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Собственно все внутренности состоят из <a href="http://code.google.com/p/xmpphp/">библиотеки XMPPHP</a> и маленького скриптика, который вешается на post-commit.<br />
Сам скриптик настолько маленький и бесхитростный, что комментировать его не вижу смысла &#8211; кладу <a href="http://miracle.rpz.name/shared/php/svnjabber.php.html">как есть</a>.<br />
Для функционирования нужно иметь xmpphp в <em>include_path</em>, бинарник svn в <em>PATH</em> и добавить <strong>post-commit hook</strong> в ваш репозитарий.</p>
<p>В сложнейшем, виндовом случае это будет <strong>post-commit.cmd</strong>, который лежит в директории <strong>hooks</strong> репозитария и имеет следующее содержание:</p>
<blockquote><p>/path/to/php.exe /path/to/svnjabber.php  %1 %2</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2009/02/24/commit-jabber-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ты не один</title>
		<link>http://miracle.rpz.name/2008/09/23/remember-you-are-not-alone/</link>
		<comments>http://miracle.rpz.name/2008/09/23/remember-you-are-not-alone/#comments</comments>
		<pubDate>Tue, 23 Sep 2008 19:35:43 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[DailyWTF]]></category>
		<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=115</guid>
		<description><![CDATA[Приключилась сегодня очень познавательная история, мораль которой должен понимать любой разработчик, детище которого обслуживает более одного пользователя. В рамках работ по выводу одного &#8220;неповоротливого асфальтоукладчика&#8221; на земную орбиту были проведены ряд его модернизаций. Испытания на тестовом полигоне показали что машина стала ездить на порядок быстрее и было решено доработки включить в работающий прототип(вроде и не [...]]]></description>
			<content:encoded><![CDATA[<p>Приключилась сегодня очень познавательная история, мораль которой должен понимать любой разработчик, детище которого обслуживает более одного пользователя.</p>
<p>В рамках работ по выводу одного &#8220;неповоротливого асфальтоукладчика&#8221; на земную орбиту были проведены ряд его модернизаций. Испытания на тестовом полигоне показали что машина стала ездить на порядок быстрее и было решено доработки включить в работающий прототип(вроде и не первая космическая, но уже есть чем гордиться!). Но на первом же серьёзном показе зверь-машина с чудо{вищным} грохотом рассыпалась у всех на глазах и я сел в лужу&#8230;</p>
<p>А теперь тоже самое, но по-русски, с выражением.<br />
Имеются ряд весьма тяжёлых для веба запросов к БД, результат которых условно не меняется в течении небольшого промежутка времени. Кеширование промежуточных результатов в самой БД нагрузку сняло на СУБД, но скрипты продолжали исправно тягать данные и это порой занимало внушительное время. Было решено результаты эти кешировать на стороне веб-сервера. Как хранилище был использован <a href="http://php.net/apc">apc</a>.</p>
<p>Первоначальный вариант выглядел примерно так:</p>
<pre class="php:nocontrols">
if (!$data = cache_get($key)) {
   $data = data_from_db();
   cache_set($key,$data,$expire_time)
}
</pre>
<p>Без излишеств, просто и со вкусом. Но позже выснилось что &#8220;всё не так просто&#8221; и в зависимости от некоторых космических характеристик и результатов выборки из базы будет меняется ещё одна переменная (меняется переменная&#8230; ого!).</p>
<pre class="php:nocontrols">
if (!$data = cache_get($key)) {
   $data = data_from_db();
   cache_set($key,$data,$expire_time);
   $other_data = some_function($data,$env);
   cache_set($other_key,$other_data,$expire_time);
} else {
   $other_data = cache_get($other_key);
}
</pre>
<p>Аляповато, но, чёрт возьми, работает&#8230;<br />
Работало&#8230;<br />
Должно было по идее работать&#8230;<br />
Но, почему-то оказавшись на боевом, изрядно нагруженном, сервере это не сработало. Вернее это работало&#8230;,  но не всё время&#8230; По истечении $expire_time периодически пропадали данные для $other_key. При отключении и/или очистке кеша работоспособность восстанавливалась&#8230; Кто виноват? Что делать? Кто за всё это ответит?!? Пришлось срочно пошевелить опилками.</p>
<p>Как мы все наверное догадываемся &#8211; реальный сервер обслуживает нереально много клиентов, причём не по очереди. И нет совершенно никаких гарантий на то, что между записью $key и $other_key не встрянет какой-либо маленький, но шустрый процесс (хотя нам это и не особо страшно), так же нет никаких оснований полагать что между выборкой $key и $other_key кто-то умный и большой не очистит кеш (целиком, или только $other_key &#8211; в данном эпизоде это не имеет значения).<br />
Оснований не было, но я был почему-то твёрдо уверен, что &#8220;это если и происходит, то с кем-то другим&#8221;. С пониманием проблемы конечно же пришло и простое решение, но ошибка, согласитесь, совсем не тривиальная.</p>
<p>Так что мораль сей басни: помни &#8211; ты не один!</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/09/23/remember-you-are-not-alone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>firebug для отладки серверного кода</title>
		<link>http://miracle.rpz.name/2008/05/06/firebug-console-for-server-side-messages/</link>
		<comments>http://miracle.rpz.name/2008/05/06/firebug-console-for-server-side-messages/#comments</comments>
		<pubDate>Tue, 06 May 2008 10:41:31 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[firebug]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=107</guid>
		<description><![CDATA[За последние пару лет firebug стал стандартным инструментом для отладки клиентской части веб-приложений у большинства разработчиков. Тем, у кого это не так &#8211; от души сочувствую ;o) Но многие не догадываются, что с помощью firebug можно отлаживать и серверный код. Не breakpoint-ами конечно. Но как замена унылым print-ам и var_dump-ам очень даже! Собственно делается всё [...]]]></description>
			<content:encoded><![CDATA[<p><a rel="tn" href="http://miracle.rpz.name/shared/fb/firebug.png"><img class="tn" src="http://miracle.rpz.name/shared/fb/tn_firebug.png" alt="" align="right" /></a><br />
За последние пару лет <a href="http://getfirebug.com">firebug</a> стал стандартным инструментом для отладки клиентской части веб-приложений у большинства разработчиков.<br />
Тем, у кого это не так &#8211; от души сочувствую ;o)<br />
Но многие не догадываются, что с помощью firebug можно отлаживать и серверный код. Не breakpoint-ами конечно. Но как замена унылым print-ам и var_dump-ам очень даже!</p>
<p>Собственно делается всё очень просто. Для того чтобы в консоли firebug-а появилось сообщение, необходимо написать js-код:</p>
<pre class="js:nocontrols">
console.log('сообщение');
console.group('разные типы сообщений');
console.info('к вашему сведению, мы тут логи пишем...');
console.warn('предупреждаем о разном');
console.error('и информируем об ошибках!!!');
console.groupEnd();
console.dir({сложная: {структура: [1,2,3]}});</pre>
<p>Подробнее о возможностях консоли firebug-а можно узнать в <a href="http://getfirebug.com/console.html">документации</a>.</p>
<p>Дело за малым &#8211; сформировать эти строки на вашей серверной платформе.<br />
Сложность представляет лишь последнее &#8211; <a href="http://json.org/">json</a>-упаковка сложных структур, но и она уже во многих платформах решена. Сам я пользуюсь функцией, описанной в коментариях к <a href="http://php.net/json_encode">json_encode</a>, т.к. родная слишком консервативна в вопросах кодировок(<a title="JSON text SHALL be encoded in Unicode.  The default encoding is UTF-8." href="http://www.ietf.org/rfc/rfc4627.txt?number=4627">по стандарту в json можно упаковать только уникод</a>, но браузеры более лояльны нежели писатели стандартов).</p>
<p>Собственно теперь чем это лучше всяких принтов и вар_дампов?<br />
Тем, что не меняют визуально документ, что существенно в современных сложных веб-приложениях.<br />
К тому же это в разы удобнее &#8211; все сообщения в одном месте, красиво представлены&#8230;</p>
<p>В заключение скажу о якобы готовых решениях для PHP:<br />
<a href="http://www.indelible.org/php/Log/guide.html#the-firebug-handler">Log::Firebug</a> из <a href="http://pear.php.net">PEAR</a> &#8211; драйвер для довольно распространнённого pear::log<br />
<a href="http://firephp.org/">FirePHP</a> &#8211; более комплексное решение, плагин к firebug-у и обёртка к серверному коду.</p>
<p>Я ни тем, ни другим не пользуюсь, т.к. первое сделано левой ногой, а второе заворачивает оригинальный документ в страшную multipart-кашу&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/05/06/firebug-console-for-server-side-messages/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>чуть ниже нуля</title>
		<link>http://miracle.rpz.name/2008/02/29/zero/</link>
		<comments>http://miracle.rpz.name/2008/02/29/zero/#comments</comments>
		<pubDate>Thu, 28 Feb 2008 21:12:09 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[DailyWTF]]></category>
		<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wtf]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/2008/02/29/zero/</guid>
		<description><![CDATA[Вот так вот: &#60;?php var_dump(round(-0.1)); ?&#62;]]></description>
			<content:encoded><![CDATA[<p>Вот так вот:</p>
<pre class="php:nocontrols">
&lt;?php
  var_dump(round(-0.1));
?&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/02/29/zero/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Y2K38</title>
		<link>http://miracle.rpz.name/2008/02/27/y2k38/</link>
		<comments>http://miracle.rpz.name/2008/02/27/y2k38/#comments</comments>
		<pubDate>Wed, 27 Feb 2008 20:53:55 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[DailyWTF]]></category>
		<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[date]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=100</guid>
		<description><![CDATA[Ожидаемый коллапс электронного пространства в y2k так и не состоялся, а следующий намечен на далёкий 2038-ой год. Но такой ли он далёкий? Буквально сегодня пришлось столкнуться лицом к лицу с нависшей над миром угрозой. В разрабатываемой системе все манипуляции с датами проводились через преобразование в unix timestamp и последующим его форматированием штатными средствами php (strtotime, [...]]]></description>
			<content:encoded><![CDATA[<div>
Ожидаемый <a href="http://bash.org.ru/quote/395081">коллапс</a> электронного пространства в y2k так и не состоялся, а следующий намечен на далёкий <a href="http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_2038_%D0%B3%D0%BE%D0%B4%D0%B0">2038</a>-ой год.<br />
Но такой ли он далёкий? Буквально сегодня пришлось столкнуться лицом к лицу с нависшей над миром угрозой.</div>
<div>
В разрабатываемой системе все манипуляции с датами проводились через преобразование в <a href="http://ru.wikipedia.org/wiki/Unix_timestamp">unix timestamp</a> и последующим его форматированием штатными средствами php (<a href="http://php.net/strtotime">strtotime</a>, <a href="http://php.net/mktime">mktime</a>, <a href="http://php.net/strftime">strftime</a>, <a href="http://php.net/date">date</a>) и вся эта хрупкая конструкция разлетелась, когда вдруг возникла дата 01.01.2059. Нет, это не сумашедшие бета-тестеры и не опечатка &#8211; это оказался срок <span style="text-decoration: line-through;">годности пива</span> действия паспорта. Казалось выхода нет и человеку надо будет менять паспорт, но решение всё же нашлось: <a href="http://phplens.com/phpeverywhere/adodb_date_library">ADOdb Date Time Library</a> &#8211; старенькая библиотечка на чистом php, которая позволит вам жить счастливо даже после официального окончания unix-эпохи.</div>
<div>
Какие ещё беды настрадал нам Предсказамус?</div>
<p><strong>Update:</strong> во какую <a href="http://code.google.com/p/y2038/">штуку</a> нашёл, надо бы донести это знание до тех, кому не безразлично&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/02/27/y2k38/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>phing.tasks.ext.SvnExportRevisionDiffTask</title>
		<link>http://miracle.rpz.name/2008/02/25/phing-ftp-deploy-from-subversion/</link>
		<comments>http://miracle.rpz.name/2008/02/25/phing-ftp-deploy-from-subversion/#comments</comments>
		<pubDate>Mon, 25 Feb 2008 17:38:25 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[phing]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/?p=99</guid>
		<description><![CDATA[В последнее время в посещаемых мною форумах и конференциях часто всплывает тема деплоя php-приложений на production-сервер. Я решил поделиться собственным рецептом. В распоряжении имеется: svn-репозитарий с проектом. ftp-доступ к рабочему серверу. установленный и готовый к тяжёлой рутине phing Сценарий работ следующий: Сделать экспорт кода из svn Подготовить его к загрузке (например убрать комментарии, &#8220;склеить&#8221; мелкие [...]]]></description>
			<content:encoded><![CDATA[<p>В последнее время в посещаемых мною форумах и конференциях часто всплывает тема деплоя php-приложений на production-сервер. Я решил поделиться собственным рецептом.</p>
<p>В распоряжении имеется:</p>
<ol>
<li>svn-репозитарий с проектом.</li>
<li>ftp-доступ к рабочему серверу.</li>
<li>установленный и готовый к тяжёлой рутине <a href="http://phing.info">phing</a>
</li>
</ol>
<p>Сценарий работ следующий:</p>
<ol>
<li>Сделать экспорт кода из svn</li>
<li>Подготовить его к загрузке (например убрать комментарии, &#8220;склеить&#8221; мелкие в один большой, удалить лишнее и т.п.)</li>
<li>Проверить на наличие ошибок (они могли попасть в репозитарий или образоваться на предыдущем шаге)</li>
<li>Закачать полученное на рабочий сервер.
</li>
</ol>
<p>Всё вроде бы просто, но смущает один момент &#8211; экспорт всего и вся. Со времени последнего обновления на сервере в репозитарии обновились 3 файла, а экспортировать нужно всё? Никак нет! Экспортировать будем только то, что изменилось. То есть первый шаг сценария будет выглядеть так:</p>
<ol>
<li>Получить последнюю версию проекта на сервере &#8211; <i>RevFrom</i></li>
<li>Получить последнюю версию проекта в репозитарии &#8211; <i>RevTo</i>
</li>
<li>Экспортировать файлы, которые изменились или добавились c <i>RevFrom</i> до <i>RevTo</i>
</li>
</ol>
<p>Версию рабочего проекта, не мудрствуя лукаво, предлагаю хранить в текстовом файле. Например revision.txt. Версию проекта в репозитарии поможет узнать SvnLastRevisionTask. Неясным остался лишь момент &#8211; каким образом выяснить какие файлы изменились. Те, кто пользовались TortoiseSVN наверняка знают о чудесной его возможности &#8211; сравнить две ревизии и экспортировать &#8220;разницу&#8221;. Но svn в чистом виде такой возможности не предоставляет. Так что пришлось немного поработать.<br />
<span id="more-99"></span><br />
Результатом работы стал класс &#8211; <a href="http://miracle.rpz.name/shared/phing/SvnExportRevisionDiffTask.html">SvnExportRevisionDiffTask</a> Принцип его работы таков: получаю список файлов для каждой ревизии в виде xml, потом эти списки сравниваются на предмет изменившихся или добавленных файлов. Список получается путём вызова svn, т.к. более удобного способа не нашлось.</p>
<p>Закачивать файлы будем посредством task-а, который я опубликовал ранее &#8211; <a href="http://miracle.rpz.name/2007/11/15/phing-ftpupload-task/">FtpUploadTask</a>.</p>
<p>Ну вот все вроде бы в сборе и можно приступать с сборке: раскладываем php-классы в соответствующие места, берём файл example.xml</p>
<pre class="xml:nocontrols">
&lt;?xml&nbsp;version=&#39;1.0&#39;?&gt;
&lt;project&nbsp;name=&#39;Deploy&#39;&nbsp;default=&#39;build&#39;&nbsp;basedir=&#39;./&#39;&nbsp;description=&#39;Demo&nbsp;phing-ftp-deploy&#39;&gt;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#39;propset&#39;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;projectUrl&#39;&nbsp;value=&#39;http://example.com/project_root/&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;revisionFile&#39;&nbsp;value=&#39;revision.txt&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;projectlastrev&nbsp;url=&#39;${projectUrl}&#39;&nbsp;revisionFile=&#39;${revisionFile}&#39;&nbsp;propertyName=&#39;fromrev&#39;&nbsp;/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;svnroot&#39;&nbsp;value=&#39;http://svn.example.com/project/branches/stable/&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;svnuser&#39;&nbsp;value=&#39;joe&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;svnpassword&#39;&nbsp;value=&#39;s3cre7&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;outputdir&#39;&nbsp;value=&#39;project-temp&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;svnlastrevision&nbsp;username=&#39;${svnuser}&#39;&nbsp;password=&#39;${svnpassword}&#39;&nbsp;repositoryurl=&#39;${svnroot}&#39;&nbsp;propertyName=&#39;torev&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;hostname&#39;&nbsp;value=&#39;ftp.example.com&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;user&#39;&nbsp;value=&#39;ftpuser@example.com&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;passwd&#39;&nbsp;value=&#39;s3cr3tk3y&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;dstdir&#39;&nbsp;value=&#39;project_root&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#39;overwrite&#39;&nbsp;value=&#39;true&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#39;build&#39;&nbsp;depends=&#39;propset,diff,lint&#39;&gt;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ftpupload&nbsp;host=&#39;${hostname}&#39;&nbsp;username=&#39;${user}&#39;&nbsp;password=&#39;${passwd}&#39;&nbsp;targetDir=&#39;${dstdir}&#39;&nbsp;mode=&#39;bin&#39;&nbsp;overwriteExisten=&#39;${overwrite}&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#39;${outputdir}&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#39;**&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exclude&nbsp;name=&#39;config.php.dist&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exclude&nbsp;name=&#39;examples/**&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ftpupload&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#39;diff&#39;&nbsp;depends=&#39;propset&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;delete&nbsp;includeemptydirs=&#39;true&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;сначала&nbsp;очистить&nbsp;директорию,&nbsp;в&nbsp;которую&nbsp;будут&nbsp;экспортироваться&nbsp;файлы&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#39;.&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#39;${outputdir}/**&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/delete&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;mkdir&nbsp;dir=&#39;${outputdir}&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;сохранить&nbsp;номер&nbsp;текущей&nbsp;ревизии&nbsp;в&nbsp;файл&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;echo&nbsp;file=&#39;${outputdir}/${revisionFile}&#39;&nbsp;message=&#39;${torev}&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;экспортировать&nbsp;нужные&nbsp;файлы&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;svndiff&nbsp;toDir=&#39;${outputdir}&#39;&nbsp;svnpath=&#39;/usr/local/subversion/bin/svn&#39;&nbsp;fromRevision=&#39;${fromrev}&#39;&nbsp;toRevision=&#39;${torev}&#39;&nbsp;force=&#39;true&#39;&nbsp;username=&#39;${svnuser}&#39;&nbsp;password=&#39;${svnpassword}&#39;&nbsp;repositoryurl=&#39;${svnroot}&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#39;lint&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;phplint&nbsp;haltOnFailure=&#39;true&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#39;${outputdir}&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#39;**/*.php&#39;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;файлы&nbsp;в&nbsp;pear::php_compat&nbsp;проверять&nbsp;в&nbsp;php5&nbsp;не&nbsp;надо&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exclude&nbsp;name=&#39;**/Php/Compat/**/*.php&#39;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/phplint&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;jslint&nbsp;haltOnFailure=&#39;true&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#39;${outputdir}&#39;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#39;**/*.js&#39;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/jslint&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;
&lt;/project&gt;
</pre>
<p>Открываем консоль, набираем <b>phing -f example.xml </b> и смотрим как вашу работу выполняет за вас бездушная машина&#8230; </p>
<blockquote><p>
Кстати говоря, эту задачу можно запускать не только вручную, но и например с помощью post-commit hook-а на репозитарии&#8230;
</p></blockquote>
<p>
Данный сценарий не затрагивает изменений в БД и позволяет синхронизировать только файлы, но и это, согласитесь, уже кое-что. А быть может у вас есть идеи, как обновить БД?</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/02/25/phing-ftp-deploy-from-subversion/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Sendmail &amp; shared hosting II</title>
		<link>http://miracle.rpz.name/2008/01/25/sendmail-shared-hosting-2/</link>
		<comments>http://miracle.rpz.name/2008/01/25/sendmail-shared-hosting-2/#comments</comments>
		<pubDate>Fri, 25 Jan 2008 13:54:19 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[sendmail]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/2008/01/25/antispam-via-php/</guid>
		<description><![CDATA[Когда-то давно я писал о том, как решил проблему обнаружения источников спама на виртуальном хостинге. По просьбе товарища Murz выкладываю описываемый в заметке скрипт &#8211; быть может пригодиться он не только ему. Ну и краткое руководство: Поместите скрипт куда-нибудь (пусть это будет /usr/bin/sendmail например, а реальный бинарник переименуйте в /usr/bin/sendmail.real) Отредактируете пути в скрипте (если [...]]]></description>
			<content:encoded><![CDATA[<p>Когда-то давно я писал о том, <a href="http://miracle.rpz.name/2006/03/13/sendmail-shared-hosting/">как решил проблему обнаружения источников спама на виртуальном хостинге</a>. По просьбе товарища <a href="http://shtrix.ru/" rel="nofollow">Murz</a> <a href="http://miracle.rpz.name/shared/php/sendmail.php.html">выкладываю описываемый в заметке скрипт</a> &#8211; быть может пригодиться он не только ему.</p>
<p>Ну и краткое руководство:</p>
<ol>
<li>Поместите скрипт куда-нибудь (пусть это будет /usr/bin/sendmail например, а реальный бинарник переименуйте в /usr/bin/sendmail.real)</li>
<li>Отредактируете пути в скрипте (если вы выбрали их другими)</li>
<li>Укажите путь к скрипту в директиве sendmail_path вашего php.ini (если отличается от указанных мною)</li>
<li>Ждите вестей&#8230;</li>
</ol>
<p><strong>P.S.</strong><br />
Вы без труда сможете добавить простейшие &#8220;фильтры&#8221; и не отправлять например письма содержащие некие сигнатуры&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/01/25/sendmail-shared-hosting-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>чтоб тебе пусто было!</title>
		<link>http://miracle.rpz.name/2008/01/19/php-mssql-empty-or-not-empty-this-is-a-question/</link>
		<comments>http://miracle.rpz.name/2008/01/19/php-mssql-empty-or-not-empty-this-is-a-question/#comments</comments>
		<pubDate>Sat, 19 Jan 2008 14:39:33 +0000</pubDate>
		<dc:creator>MiRacLe</dc:creator>
				<category><![CDATA[DailyWTF]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[mssql]]></category>

		<guid isPermaLink="false">http://miracle.rpz.name/2008/01/19/php-mssql-empty-or-not-empty-this-is-a-question/</guid>
		<description><![CDATA[Коллега(привет Денис) столкнулся с багом в php-mssql, который может съесть ваш мозг. Предупреждаю &#8211; пустые строки вовсе не пустые! Говорят это ошибка в либе, хотя и воспроизводиться и в win и в *nix (т.е. либы разные). Написал разработчику &#8211; а вдруг поможет. А пока имейте ввиду &#8211; если в resultset могут быть пустые строки &#8211; [...]]]></description>
			<content:encoded><![CDATA[<p>Коллега(привет Денис) столкнулся с багом в php-mssql, который может съесть ваш мозг.</p>
<p>Предупреждаю &#8211; <a href="http://bugs.php.net/bug.php?id=31641" title="php-bug #31641">пустые строки вовсе не пустые</a>! Говорят это ошибка в либе, хотя и воспроизводиться и в win и в *nix (т.е. либы разные). Написал разработчику &#8211; а вдруг поможет.</p>
<p>А пока имейте ввиду &#8211; если в resultset могут быть пустые строки &#8211;  надо их сделать таковыми самостоятельно (примерно так: $row[&quot;field&quot;] = ($row[&quot;field&quot;] != &quot; &quot;) ? $row[&quot;field&quot;] : &quot;&quot;;) &#8211; разумеется, если у вас за каким-то лесом в базе храняться одиночные пробелы, вам очень не повезло ;o)</p>
]]></content:encoded>
			<wfw:commentRss>http://miracle.rpz.name/2008/01/19/php-mssql-empty-or-not-empty-this-is-a-question/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- Served from: miracle.rpz.name @ 2012-02-06 18:18:08 by W3 Total Cache -->
