<?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/tag/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>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>
	</channel>
</rss>

<!-- Served from: miracle.rpz.name @ 2012-02-06 17:57:40 by W3 Total Cache -->
