<?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>Ars Longa, Vita Brevis &#187; PHP</title>
	<atom:link href="http://blog.sjinks.pro/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.sjinks.pro</link>
	<description>Quod scripsi, scripsi</description>
	<lastBuildDate>Mon, 06 Feb 2012 17:56:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Обход плагина WP Hashcash</title>
		<link>http://blog.sjinks.pro/security/955-bypass-wp-hashcash/</link>
		<comments>http://blog.sjinks.pro/security/955-bypass-wp-hashcash/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 05:43:11 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Безопасность]]></category>
		<category><![CDATA[Плагины WordPress]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[плагин]]></category>
		<category><![CDATA[спам]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=955</guid>
		<description><![CDATA[Не так страшен JavaScript, как его малюют… WP Hashcash — очередной плагин WordPress для борьбы со спамом. Принцип работы основывается на том, что спам-боты не умеют исполнять JavaScript. Идея в том, что если пользователь открыл сайт из браузера, браузер выполнит некоторый хитрый код JavaScript, и реузльтат работы этого скрипта будет передан назад на сервер в качестве доказательства [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/security/955-bypass-wp-hashcash/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Не так страшен <a href="http://blog.sjinks.pro/tag/javascript/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  JavaScript">JavaScript</a>, как его малюют…</em></h2>
<p><a href="http://wordpress-plugins.feifei.us/hashcash/">WP Hashcash</a> — очередной <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> для борьбы со спамом. Принцип работы основывается на том, что <a href="http://blog.sjinks.pro/tag/spam/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  спам">спам</a>-боты не умеют исполнять JavaScript. Идея в том, что если пользователь открыл сайт из браузера, браузер выполнит некоторый хитрый код JavaScript, и реузльтат работы этого скрипта будет передан назад на сервер в качестве доказательства «человечности» комментатора.<span id="more-955"></span></p>
<p>Недостаток этого подхода заключается в том, что используемый JavaScript является довольно-таки простым; как следствие, его можно «понять» даже из <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>-скрипта.</p>
<p>Пример кода JavaScript, генерируемого плагином:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9557">
        <div class="code javascript" id="p955code7">
<span class="kw2">function</span> wphc<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> wphc_data <span class="sy0">=</span> <span class="br0">&#91;</span>1850500665<span class="sy0">,</span>1666021931<span class="sy0">,</span>1699898495<span class="sy0">,</span>1648446524<span class="sy0">,</span>2035770162<span class="sy0">,</span>1980447546<span class="sy0">,</span>2018932269<span class="sy0">,</span>956464429<span class="sy0">,</span>890644332<span class="sy0">,</span>956447103<span class="sy0">,</span>890644332<span class="sy0">,</span>973224063<span class="sy0">,</span>890579818<span class="sy0">,</span>761213796<span class="sy0">,</span>1850368808<span class="sy0">,</span>1615687680<span class="sy0">,</span>1750492719<span class="sy0">,</span>756628087<span class="br0">&#93;</span><span class="sy0">;</span> <br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw2">var</span> i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>wphc_data.<span class="me1">length</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span><span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wphc_data<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">=</span>wphc_data<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">^</span><span class="nu0">220336991</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> a <span class="sy0">=</span> <span class="kw2">new</span> Array<span class="br0">&#40;</span>wphc_data.<span class="me1">length</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw2">var</span> i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>wphc_data.<span class="me1">length</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy0">=</span> String.<span class="me1">fromCharCode</span><span class="br0">&#40;</span>wphc_data<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy0">&amp;</span> 0xFF<span class="sy0">,</span> wphc_data<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">&gt;&gt;&gt;</span>8 <span class="sy0">&amp;</span> 0xFF<span class="sy0">,</span> wphc_data<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">&gt;&gt;&gt;</span>16 <span class="sy0">&amp;</span> 0xFF<span class="sy0">,</span> wphc_data<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">&gt;&gt;&gt;</span>24 <span class="sy0">&amp;</span> 0xFF<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">eval</span><span class="br0">&#40;</span>a.<span class="me1">join</span><span class="br0">&#40;</span><span class="st0">''</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Такой JavaScript весьма похож на PHP <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Как следствие, идея обхода плагина заключается в том, чтобы преобразовать JavaScript в PHP и выполнить получившийся PHP-код.</p>
<p>Итак:</p>
<ol>
<li>В PHP нет ключевого слова <code>var</code> (строго говоря, оно там есть, только имеет другое назначение).</li>
<li>В PHP несколько другой синтаксис объявления массива</li>
<li>Идентификаторы в PHP начинаются с доллара</li>
<li>Операция сдвига выглядит как <code>&gt;&gt;</code>, а не <code>&gt;&gt;&gt;</code>.</li>
<li>В PHP нет классов Array, String, но никто не мешает их написать <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ol>
<p>Наша задача состоит в преобразовании кода, приведённого выше, в нечто подобное:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9558">
        <div class="code php" id="p955code8">
<span class="kw2">function</span> wphc<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$wphc_data</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span>1850500665<span class="sy0">,</span>1666021931<span class="sy0">,</span>1699898495<span class="sy0">,</span>1648446524<span class="sy0">,</span>2035770162<span class="sy0">,</span>1980447546<span class="sy0">,</span>2018932269<span class="sy0">,</span>956464429<span class="sy0">,</span>890644332<span class="sy0">,</span>956447103<span class="sy0">,</span>890644332<span class="sy0">,</span>973224063<span class="sy0">,</span>890579818<span class="sy0">,</span>761213796<span class="sy0">,</span>1850368808<span class="sy0">,</span>1615687680<span class="sy0">,</span>1750492719<span class="sy0">,</span>756628087<span class="br0">&#41;</span><span class="sy0">;</span> <br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="re0">$i</span><span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">&lt;</span>count<span class="br0">&#40;</span><span class="re0">$wphc_data</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">++</span><span class="br0">&#41;</span><span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$wphc_data</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">=</span><span class="re0">$wphc_data</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span>^<span class="nu0">220336991</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="re0">$i</span><span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">&lt;</span>count<span class="br0">&#40;</span><span class="re0">$wphc_data</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$a</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span> <span class="sy0">=</span> fromCharCode<span class="br0">&#40;</span><span class="re0">$wphc_data</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span> <span class="sy0">&amp;</span> 0xFF<span class="sy0">,</span> <span class="re0">$wphc_data</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">&gt;&gt;</span>8 <span class="sy0">&amp;</span> 0xFF<span class="sy0">,</span> <span class="re0">$wphc_data</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">&gt;&gt;</span>16 <span class="sy0">&amp;</span> 0xFF<span class="sy0">,</span> <span class="re0">$wphc_data</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">&gt;&gt;</span>24 <span class="sy0">&amp;</span> 0xFF<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span><span class="kw3">join</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="sy0">,</span> <span class="re0">$a</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Это достигается таким набором правил <code>str_replace()</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9559">
        <div class="code php" id="p955code9">
<span class="re0">$x</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'wphc_data'</span> &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'$wphc_data'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'var $'</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'$'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'var '</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'$'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'];'</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">');'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'= ['</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'= array('</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'new Array($wphc_data.length)'</span> <span class="sy0">=&gt;</span> <span class="st_h">'array()'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'$wphc_data.length'</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'count($wphc_data)'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">' i&lt;'</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">' $i&lt;'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'[i]'</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'[$i]'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'i++'</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'$i++'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'&gt;&gt;&gt;'</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'&gt;&gt;'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'a[$i] ='</span> &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'$a[$i] ='</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'String.'</span> &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st_h">'eval'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">&quot;a.join('')&quot;</span> <span class="sy0">=&gt;</span> <span class="st_h">'join(&quot;&quot;, $a)'</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="kw3">array_keys</span><span class="br0">&#40;</span><span class="re0">$x</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="kw3">array_values</span><span class="br0">&#40;</span><span class="re0">$x</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="re0">$s</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>При желании правила можно попытаться оптимизировать, но мне было лень — скрипт ломался на коленке за 10 минут.</p>
<p>Реализация функции <code>fromCharCode</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95510">
        <div class="code php" id="p955code10">
<span class="kw2">function</span> fromCharCode<span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">,</span> <span class="re0">$b</span><span class="sy0">,</span> <span class="re0">$c</span><span class="sy0">,</span> <span class="re0">$d</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">chr</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="kw3">chr</span><span class="br0">&#40;</span><span class="re0">$b</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="kw3">chr</span><span class="br0">&#40;</span><span class="re0">$c</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="kw3">chr</span><span class="br0">&#40;</span><span class="re0">$d</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>После замены результат нужно вычислить при помощи <code>eval()</code>. После чего получим такой результат:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95511">
        <div class="code javascript" id="p955code11">
<span class="kw2">function</span> wphc_compute<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span><span class="kw1">return</span> 43448 <span class="sy0">*</span> 43448 <span class="sy0">+</span> <span class="nu0">75878</span><span class="sy0">;</span> <span class="br0">&#125;</span> wphc_compute<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Как можно заметить, этот код является одновременно и PHP-кодом, и JavaScript-кодом.</p>
<p>Следующий шаг —</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95512">
        <div class="code php" id="p955code12">
<span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="st_h">'wphc_compute();'</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw1">eval</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw1">echo</span> wphc_compute<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Результатом выполнения будет число 1887804582.</p>
<p>Как видим, для обхода такой простой защиты не нужен даже интерпретатор JavaScript <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/security/955-bypass-wp-hashcash/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/security/955-bypass-wp-hashcash/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SQLMon для Yii</title>
		<link>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/</link>
		<comments>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 15:02:18 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[лог]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=947</guid>
		<description><![CDATA[Расширение для анализа производительности SQL-запросов для Yii Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа. Ситуацию частично исправило расширение под названием Yii DB profiler. Но остались некоторые неудобства: Отображение запросов в порядке убывания времени выполнения — в принципе, это [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Расширение для анализа производительности SQL-запросов для <a href="http://blog.sjinks.pro/tag/yii/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Yii">Yii</a></em></h2>
<p>Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа.</p>
<p>Ситуацию частично исправило расширение под названием <a href="http://rmcreative.ru/blog/post/yii-db-profiler">Yii DB profiler</a>. Но остались некоторые неудобства:</p>
<ul>
<li>Отображение запросов в порядке убывания времени выполнения — в принципе, это дело вкуса: при таком порядке сразу видны проблемные запросы. С другой стороны, лично мне более привычен хронологический порядок — так чётче прослеживается логика работы;</li>
<li>Prepared statements. Это просто здорово, но если повторять запрос в phpMyAdmin (например, если интересует план выполнения запроса), бывает очень муторно заменять все связанные значения. Например, для запросов вида
          
<div class="codebox">
    <div class="the_code" style="" id="p94717">
        <div class="code mysql" id="p947code17">
<span class="kw1">SELECT</span> <span class="st0">'t'</span>.<span class="st0">&quot;object<span class="es1">_</span>id&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c0&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;ymd&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c1&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;black&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c2&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;brown&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c3&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;yellow&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c4&quot;</span><span class="sy2">,</span> <br />
<span class="st0">'t'</span>.<span class="st0">&quot;neutral&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c5&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;white&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c6&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;unknown&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c7&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;error&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c8&quot;</span><span class="sy2">,</span> <span class="st0">'object'</span>.<span class="st0">&quot;object&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t1<span class="es1">_</span>c2&quot;</span><span class="sy2">,</span><br />
<span class="st0">'object'</span>.<span class="st0">&quot;id&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t1<span class="es1">_</span>c0&quot;</span><br />
<span class="kw1">FROM</span> <span class="st0">'dnsbl<span class="es1">_</span>summary'</span> <span class="st0">'t'</span> <br />
<span class="kw13">LEFT</span> <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> <span class="st0">'objects'</span> <span class="st0">'object'</span> <span class="kw1">ON</span> <span class="br0">&#40;</span><span class="st0">'t'</span>.<span class="st0">&quot;object<span class="es1">_</span>id&quot;</span><span class="sy1">=</span><span class="st0">'object'</span>.<span class="st0">&quot;id&quot;</span><span class="br0">&#41;</span> <br />
<span class="kw1">WHERE</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span>black <span class="sy1">&gt;</span> 0<span class="br0">&#41;</span> <span class="kw10">OR</span> <span class="br0">&#40;</span>brown <span class="sy1">&gt;</span> 0<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span>ymd<span class="sy1">=</span>:ycp0<span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>black<span class="sy1">&gt;</span>:ycp1<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>brown<span class="sy1">=</span>:ycp2<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>yellow<span class="sy1">=</span>:ycp3<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span>neutral<span class="sy1">&gt;</span>:ycp4<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>white<span class="sy1">&gt;</span>:ycp5<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>unknown<span class="sy1">=</span>:ycp6<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>black<span class="sy1">&gt;</span>:ycp7<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span>error<span class="sy1">=</span>:ycp8<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>object.enabled <span class="sy1">=</span> 1<span class="br0">&#41;</span><br />
<span class="kw1">LIMIT</span> <span class="nu0">50</span>
        </div>
    </div>
</div>

заменять все <code>:ycpXXX</code> на их значения немного муторно. В общем случае здесь вряд ли можно что-то сделать — заполнители параметров могут быть любыми (и даже позиционными), поэтому тупое использование <code>str_replace</code> может наделать делов.
</li>
</ul>
<p>Лично мне список запросов нужен обычно только для двух вещей:</p>
<ol>
<li>Оценка работы механизмов кэширования;</li>
<li>Оценка плана выполнения запроса, составленная оптимизатором.</li>
</ol>
<p>Первое обычно не критично (зачастую достаточно посмотреть на количество запросов), а вот второе позволяет выявить многие будущие проблемы с производительностью заранее.</p>
<p>В результате, взяв за основу <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <a href="http://rmcreative.ru/">Александра</a>, я портировал <a href="http://blog.sjinks.pro/tag/sqlmon/">SQLMon</a> на Yii.<br />
<span id="more-947"></span></p>
<p>В результате получилось расширение, позволяющее получать планы выполнения запросов в реальном времени.</p>
<p>Поддерживаются <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a> и SQLite, в планах поддержка PgSQL (там не всё просто, ибо Postgres <em>выполняет</em> запрос, что может привести к интересным последствиям при использовании <code>INSERT</code>/<code>UPDATE</code>/<code>DELETE</code>; как следствие, придётся использовать <a href="http://blog.sjinks.pro/php/932-pdo-nested-transactions/">вложенные транзакции</a>).</p>
<p>Вывод результатов осуществляется либо при помощи виджета:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p94718">
        <div class="code php" id="p947code18">
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widget</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'ext.sqlmon.components.SQLMon'</span><br />
&nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'explain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения запроса</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'backtrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'dsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения (может быть полезно при использовании нескольких БД)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'cssFile'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="co1">// Эстеты могут задать свой файл стилей </span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Либо при помощи Log Route:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p94719">
        <div class="code php" id="p947code19">
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'components'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'log'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'routes'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'class'</span> <span class="sy0">=&gt;</span> <span class="st_h">'ext.sqlmon.components.SQLMonLogRoute'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showExplain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showDsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showBacktrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'class'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'ext.sqlmon.components.SQLMonFileLogRoute'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'logFile'</span> <span class="sy0">=&gt;</span> <span class="st_h">'sqlmon.log'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showExplain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showDsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showBacktrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p><code>SQLMonLogRoute</code> наследуется от <code>CWebLogRoute</code>, но, как и <code>CProfileLogRoute</code>, отказывается выдавать данные для AJAX-запросов.</p>
<p><code>SQLMonFileLogRoute</code> наследуется от <code>CFileLogRoute</code> и, как следствие, воспринимает все параметры конфигурации последнего.</p>
<p>Для того, чтобы протоколирование нормально работало, сообщения от SQLMon попадают в общий протокол и, как следствие, видны при использовании <code>CWebLogRoute</code> (в этом случае выдаётся минимум информации).</p>
<p>Результаты работы выглядят примерно так (пример приведён для SQLite):</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-yii.png"><img src="http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-yii-300x283.png" alt="Пример выдачи SQLMon" title="SQLMon в Yii" width="300" height="283" class="alignnone size-medium wp-image-948" /></a></p>
<p>Реализовано всё через собственный класс <a href="http://blog.sjinks.pro/tag/pdo/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PDO">PDO</a>, поэтому для использования SQLMon нужно в файл конфигурации добавить такие строки:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p94720">
        <div class="code php" id="p947code20">
<br />
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'import'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'ext.sqlmon.components.*'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<br />
&nbsp; &nbsp; <span class="st_h">'components'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'db'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
<span class="co1">// ...</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'pdoClass'</span> <span class="sy0">=&gt;</span> <span class="st_h">'SQLMonPDO'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Реализация просмотра выполнения плана выполнения запроса осуществляется при помощи класса-наследника от <code>PDOStatement</code> и переопределения метода <code>PDO::prepare()</code>.</p>
<p>Планы на будущее:</p>
<ul>
<li>поддержка <a href="http://blog.sjinks.pro/tag/postgresql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PostgreSQL">PostgreSQL</a>;</li>
<li>возможность расширения классов <code>SQLMonPDO</code> и <code>SQLMonPDOStatement</code> (возможно, придётся позаимствовать некоторые идеи из <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a>);</li>
<li>наследование <code>SQLMon_Explainer_Base</code> от <code>CComponent</code>, что даст дополнительные плюшки для расширяемости;</li>
<li>более красивая реализация функции SQLMon::arr2pre(), что позволит рисовать красивые ASCII-таблички;</li>
<li>возможная поддержка FireBug;</li>
<li>протоколирование в <a href="http://blog.sjinks.pro/tag/html/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HTML">HTML</a>-файл;</li>
<li>информация профайлера MySQL (нужность пока под большим вопросом);</li>
<li>рефакторинг, написание документации</li>
</ul>
<p><strong><a href='http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-0.1.zip'>SQLMon 0.1 for Yii</a></strong> — скачать бесплатно без регистрации без смс <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Преобразование ошибок в PHP в исключения</title>
		<link>http://blog.sjinks.pro/php/937-convert-php-errors-into-exceptions/</link>
		<comments>http://blog.sjinks.pro/php/937-convert-php-errors-into-exceptions/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 21:13:06 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=937</guid>
		<description><![CDATA[Механизм трансляции ошибок в исключения с целью последующей обработки Навеяно этим сообщением на форуме. Дано: фреймворк перехватывает все возникающие ошибки (которые разрешены текущим значением error_reporting()) и аварийно завершает работу скрипта (в целях отладки/безопасности/нужное подчеркнуть); имеется код, вызывающий PHP-функцию, которая может сгенерировать предупреждение (в оригинальном сообщении это mkdir() — кидает E_WARNING, если не удаётся создать каталог) местные стандарты [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/937-convert-php-errors-into-exceptions/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Механизм трансляции ошибок в исключения с целью последующей обработки</em></h2>
<p>Навеяно <a href="http://www.yiiframework.com/forum/index.php?/topic/8310-%D0%BE%D1%82%D0%BB%D0%BE%D0%B2-php-%D0%BE%D1%88%D0%B8%D0%B1%D0%BE%D0%BA">этим сообщением</a> на форуме.</p>
<p>Дано:</p>
<ul>
<li>фреймворк перехватывает все возникающие ошибки (которые разрешены текущим значением <code>error_reporting()</code>) и аварийно завершает работу скрипта (в целях отладки/безопасности/нужное подчеркнуть);</li>
<li>имеется код, вызывающий <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>-функцию, которая может сгенерировать предупреждение (в оригинальном сообщении это <code>mkdir()</code> — кидает <code>E_WARNING</code>, если не удаётся создать каталог)</li>
<li>местные стандарты кодирования запрещают использование оператора <code>@</code> (довольно распространённая практика).</li>
</ul>
<p>Требуется обработать возникшую ошибку без <acronym title="аварийный останов">авоста</acronym> скрипта.<span id="more-937"></span></p>
<p>Сначала рассмотрим предложенные варианты решений и наведём критику (как же без этого).</p>
<p><strong>Способ 1</strong>:</p>
<blockquote>В PHP существуют специальные функции (is_dir, is_writable, …), в зависимости от возвращаемого значения которых вы можете генерировать соответствующее сообщение.</blockquote>
<p>Идея в том, чтобы проверять все возможные ошибочные ситуации до вызова проблемной функции. С одной стороны по-хорошему так и надо поступать. С другой стороны, всего не предусмотришь — а если создавать обёртку для каждой проблемной функции, код может очень сильно раздуться. К тому же следует помнить, что проверка на возможные ошибки с последующим вызовом функции — операция неатомарная. Иными словами, требуемый каталог может быть создан другим скриптом в следующее мгновение после того, как проверка на существование создаваемого каталога вернула отрицательный результат. Для каталогов это, возможно, не очень актуально, но для операция с сокетами — самое то.</p>
<p><strong>Способ 2</strong>: изменение <code>error_reporting</code>.</p>
<p>Что-то типа:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93728">
        <div class="code php" id="p937code28">
<span class="re0">$level</span><span class="sy0">=</span><span class="kw3">error_reporting</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw3">error_reporting</span><span class="br0">&#40;</span><span class="re0">$level</span> <span class="sy0">|</span> ~<span class="kw4">E_WARNING</span> <span class="sy0">|</span> ~<span class="kw4">E_ERROR</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span><span class="kw3">is_dir</span><span class="br0">&#40;</span><span class="re0">$path</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="kw4">false</span><span class="sy0">===</span><span class="kw3">mkdir</span><span class="br0">&#40;</span><span class="re0">$path</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;throw <span class="kw2">new</span> CException<span class="br0">&#40;</span>Yii<span class="sy0">::</span><span class="me2">t</span><span class="br0">&#40;</span><span class="st_h">'myapp'</span><span class="sy0">,</span><span class="st_h">'Can not create path &quot;{path}&quot;'</span><span class="sy0">,</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'{path}'</span><span class="sy0">=&gt;</span><span class="re0">$path</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
error_reporing<span class="br0">&#40;</span><span class="re0">$level</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Убирать <code>E_ERROR</code> всё же не стоит.<br />
Опять же, создание обёртки для каждой проблемной функции раздует код. К тому же вызов <code>error_reporting()</code> — не самая быстрая операция (по крайней мере раньше было именно так).</p>
<p><strong>Способ 3</strong>:</p>
<blockquote>
Мы в текущем проекте столкнулись с приблизительно такой же проблемой: Memcache генерит PHP-ошибки, а не исключения, которые хотя бы через try/catch можно было отловить.
<p>Пришлось изобретать свой хэндлер и &laquo;оборачивать&raquo; все обращения к мемкешу предвалительно нашим &laquo;молчаливым&raquo; хэндлером:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93729">
        <div class="code php" id="p937code29">
<span class="kw2">function</span> mcSilenceErrorHandler<span class="br0">&#40;</span><span class="re0">$errno</span><span class="sy0">,</span> <span class="re0">$errstr</span><span class="sy0">,</span> <span class="re0">$errfile</span><span class="sy0">,</span> <span class="re0">$errline</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QLogger<span class="sy0">::</span><span class="kw3">log</span><span class="br0">&#40;</span><span class="st_h">'memcache_errors'</span><span class="sy0">,</span> <span class="re0">$errstr</span> <span class="sy0">.</span> <span class="st_h">' at ('</span> <span class="sy0">.</span> <span class="re0">$errfile</span> <span class="sy0">.</span> <span class="st_h">':'</span> <span class="sy0">.</span> <span class="re0">$errline</span> <span class="sy0">.</span> <span class="st_h">')'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>В самом коде используется так, что перед потенциально &laquo;опасными&raquo; обращениями к мемкешу, мы выставляем свой &laquo;молчаливый&raquo; хэндлер, а потом возвращаем старый &#8211; <a href="http://blog.sjinks.pro/tag/yii/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Yii">Yii</a>&#8217;шный &#8211; хэндлер.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93730">
        <div class="code php" id="p937code30">
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> <span class="kw3">flush</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$result</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$old_handler</span> <span class="sy0">=</span> <span class="kw3">set_error_handler</span><span class="br0">&#40;</span><span class="st_h">'mcSilenceErrorHandler'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$result</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_cache<span class="sy0">-&gt;</span><span class="me1">flush</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set_error_handler</span><span class="br0">&#40;</span><span class="re0">$old_handler</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$result</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
        </div>
    </div>
</div>

</blockquote>
<p>Решение à la Способ №2, обладающее практически теми же недостатками.</p>
<p>Ну а теперь собственно предлагаемое решение.</p>
<p><a href="http://blog.sjinks.pro/php/yii/934-catch-fatal-errors/">Как известно</a>, PHP позволяет пользователю установить собственные обработчики для обработки ошибок и необработанных исключительных ситуаций. Решение же состоит в том, чтобы из обработчика ошибок кинуть исключение. Исключение либо будет перехвачено в блоке <code>try</code>/<code>catch</code> где-то в коде, либо не будет обработано пользовательским кодом и будет перехвачено в обработчике необработанных исключений (что приведёт к аварийному завершению скрипта).</p>
<p>Код будет выглядеть примерно так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93731">
        <div class="code php" id="p937code31">
<span class="kw2">function</span> my_error_handler<span class="br0">&#40;</span><span class="re0">$code</span><span class="sy0">,</span> <span class="re0">$error</span><span class="sy0">,</span> <span class="re0">$file</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="re0">$line</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">error_reporting</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="re0">$code</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; throw <span class="kw2">new</span> ErrorException<span class="br0">&#40;</span><span class="re0">$error</span><span class="sy0">,</span> <span class="re0">$code</span><span class="sy0">,</span> 0<span class="sy0">,</span> <span class="re0">$file</span><span class="sy0">,</span> <span class="re0">$line</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw2">function</span> my_shutdown_handler<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="re0">$error</span> <span class="sy0">=</span> <span class="kw3">error_get_last</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">in_array</span><span class="br0">&#40;</span><span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'type'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="kw4">E_PARSE</span><span class="sy0">,</span> <span class="kw4">E_ERROR</span><span class="sy0">,</span> <span class="kw4">E_USER_ERROR</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; my_display_error<span class="br0">&#40;</span><span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'type'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'message'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'file'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'line'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">die</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw2">function</span> my_display_error<span class="br0">&#40;</span><span class="re0">$code</span><span class="sy0">,</span> <span class="re0">$error</span><span class="sy0">,</span> <span class="re0">$file</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="re0">$line</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="co1">// Возникла фатальная ошибка, которую обработать штатными средствами нельзя.</span><br />
<span class="co1">// Вывод информации об ошибке и завершение работы скрипта</span><br />
<span class="br0">&#125;</span><br />
<br />
<br />
<span class="co1">// Выполняется где-то во время инициализации приложения</span><br />
<span class="kw3">set_error_handler</span><span class="br0">&#40;</span><span class="st_h">'my_error_handler'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw3">register_shutdown_function</span><span class="br0">&#40;</span><span class="st_h">'my_shutdown_handler'</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>После такого можно писать:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93732">
        <div class="code php" id="p937code32">
try <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw3">mkdir</span><span class="br0">&#40;</span><span class="re0">$dir</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
catch <span class="br0">&#40;</span>ErrorException <span class="re0">$e</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="st_h">'Всё плохо при создании каталога: '</span><span class="sy0">,</span> <span class="re0">$e</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Так как тема взята с форума Yii, рассмотрим, как интегрировать всё это безобразие с Yii:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93733">
        <div class="code php" id="p937code33">
<span class="kw2">&lt;?php</span><br />
<span class="kw2">class</span> MyWebApplication <span class="kw2">extends</span> CWebApplication<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$config</span><span class="sy0">=</span><span class="kw4">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">parent</span><span class="sy0">::</span>__construct<span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">register_shutdown_function</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">,</span> <span class="st_h">'shutdown'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>YII_ENABLE_EXCEPTION_HANDLER <span class="sy0">&amp;&amp;</span> <span class="sy0">!</span>YII_ENABLE_ERROR_HANDLER<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set_error_handler</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">,</span> <span class="st_h">'myErrorHandler'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> shutdown<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>YII_ENABLE_EXCEPTION_HANDLER <span class="sy0">&amp;&amp;</span> <span class="br0">&#40;</span><span class="re0">$error</span> <span class="sy0">=</span> <span class="kw3">error_get_last</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">in_array</span><span class="br0">&#40;</span><span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'type'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="kw4">E_PARSE</span><span class="sy0">,</span> <span class="kw4">E_ERROR</span><span class="sy0">,</span> <span class="kw4">E_USER_ERROR</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">handleException</span><span class="br0">&#40;</span><span class="kw2">new</span> ErrorException<span class="br0">&#40;</span><span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'message'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'type'</span><span class="br0">&#93;</span><span class="sy0">,</span> 0<span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'file'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'line'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">die</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> myErrorHandler<span class="br0">&#40;</span><span class="re0">$code</span><span class="sy0">,</span> <span class="re0">$error</span><span class="sy0">,</span> <span class="re0">$file</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="re0">$line</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">error_reporting</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="re0">$code</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw <span class="kw2">new</span> ErrorException<span class="br0">&#40;</span><span class="re0">$error</span><span class="sy0">,</span> <span class="re0">$code</span><span class="sy0">,</span> 0<span class="sy0">,</span> <span class="re0">$file</span><span class="sy0">,</span> <span class="re0">$line</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Использование:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93734">
        <div class="code php" id="p937code34">
<span class="kw1">define</span><span class="br0">&#40;</span><span class="st_h">'YII_ENABLE_ERROR_HANDLER'</span><span class="sy0">,</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw1">define</span><span class="br0">&#40;</span><span class="st_h">'YII_ENABLE_EXCEPTION_HANDLER'</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="kw1">require_once</span> <span class="st_h">'protected/components/MyWebApplication.php'</span><span class="sy0">;</span><br />
Yii<span class="sy0">::</span><span class="me2">createApplication</span><span class="br0">&#40;</span><span class="st_h">'MyWebApplication'</span><span class="sy0">,</span> <span class="re0">$config</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">run</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/937-convert-php-errors-into-exceptions/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/937-convert-php-errors-into-exceptions/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Перехват фатальных ошибок в Yii</title>
		<link>http://blog.sjinks.pro/php/yii/934-catch-fatal-errors/</link>
		<comments>http://blog.sjinks.pro/php/yii/934-catch-fatal-errors/#comments</comments>
		<pubDate>Sun, 07 Aug 2011 08:06:17 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[Kohana]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=934</guid>
		<description><![CDATA[Облегчаем жизнь разработчику Как и Kohana, Yii помогает разработчику, отлавливая неперехваченные исключения и ошибки в коде. Как и в Kohana, реализуется это одинаково — через функции PHP set_exception_handler() и set_error_handler(). Но, в отличие от Kohana, Yii не умеет перехватывать фатальные ошибки (E_ERROR в терминах PHP). Как следствие, если приложение сгенерирует фатальную ошибку (например, вызов несуществующей функции), у [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/934-catch-fatal-errors/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Облегчаем жизнь разработчику</em></h2>
<p>Как и <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a>, <a href="http://blog.sjinks.pro/tag/yii/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Yii">Yii</a> помогает разработчику, отлавливая неперехваченные исключения и ошибки в коде. Как и в <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a>, реализуется это одинаково — через функции <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> <code><a href="http://www.php.net/manual/en/function.set-exception-handler.php">set_exception_handler()</a></code> и <code><a href="http://www.php.net/manual/en/function.set-error-handler.php">set_error_handler()</a></code>. Но, в отличие от Kohana, Yii не умеет перехватывать фатальные ошибки (<code>E_ERROR</code> в терминах PHP).</p>
<p>Как следствие, если приложение сгенерирует фатальную ошибку (например, вызов несуществующей функции), у разработчика все шансы об этом не узнать (например, на production-сервере с <code>display_errors</code> установленным <code>Off</code>). Конечно, если приложение хорошо протестировано шансы возникновения такой ситуации близки к нулю, но если приложение позволяет пользователю устанавливать какие-либо свои дополнения, то лучше узнавать о проблемах прежде, чем начальник получит кучу гневных писем <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> <span id="more-934"></span></p>
<p>Причина, по которой Yii не может обработать фатальные ошибки заключается в том, что PHP принципиально не вызывает функции, установленные <code>set_error_handler()</code>, при возникновении ошибок типа <code>E_ERROR</code>, <code>E_PARSE</code>, <code>E_CORE_ERROR</code>, <code>E_CORE_WARNING</code>, <code>E_COMPILE_ERROR</code>, <code>E_COMPILE_WARNING</code>.</p>
<p>Тем не менее, Kohana умеет перехватывать <code>E_ERROR</code>, поэтому было бы неплохо добавить такую поддержку и в Yii.</p>
<p>Вся магия заключается в том, что функции, зарегистрированные при помощи <code>register_shutdown_function()</code> вызываются даже в случае <code>E_ERROR</code>. А определить наличие ошибки можно при помощи функции <code><a href="http://www.php.net/manual/en/function.error-get-last.php">error_get_last()</a></code>.</p>
<p>У меня получился такой код:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93437">
        <div class="code php" id="p934code37">
<span class="kw2">&lt;?php</span><br />
<br />
<span class="kw2">class</span> MyWebApplication <span class="kw2">extends</span> CWebApplication<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$config</span><span class="sy0">=</span><span class="kw4">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">parent</span><span class="sy0">::</span>__construct<span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">register_shutdown_function</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">,</span> <span class="st_h">'shutdown'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> shutdown<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>YII_ENABLE_ERROR_HANDLER <span class="sy0">&amp;&amp;</span> <span class="br0">&#40;</span><span class="re0">$error</span> <span class="sy0">=</span> <span class="kw3">error_get_last</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">handleError</span><span class="br0">&#40;</span><span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'type'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'message'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'file'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#91;</span><span class="st_h">'line'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">die</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Пользоваться так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93438">
        <div class="code php" id="p934code38">
<span class="kw1">require_once</span> <span class="st_h">'protected/components/MyWebApplication.php'</span><span class="sy0">;</span><br />
Yii<span class="sy0">::</span><span class="me2">createApplication</span><span class="br0">&#40;</span><span class="st_h">'MyWebApplication'</span><span class="sy0">,</span> <span class="re0">$config</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">run</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/934-catch-fatal-errors/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/yii/934-catch-fatal-errors/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Вложенные транзакции в PDO</title>
		<link>http://blog.sjinks.pro/php/932-pdo-nested-transactions/</link>
		<comments>http://blog.sjinks.pro/php/932-pdo-nested-transactions/#comments</comments>
		<pubDate>Sat, 06 Aug 2011 07:21:34 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PDO]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=932</guid>
		<description><![CDATA[Использование вложенных транзакций в MySQL и PostgreSQL с PDO В PDO есть такая особенность: отсутствие поддержки вложенных транзакций. Вложенные транзакции бывают весьма полезны: например, у нас есть два сервиса, которые могут взаимодействовать между собой. Сервис А начинает транзакцию, что-то делает, затем вызывает сервис Б, затем подтверждает транзакцию. Может так случиться, что сервисы А и Б разрабатываются разными людьми и разработчик [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/932-pdo-nested-transactions/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Использование вложенных транзакций в <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a> и <a href="http://blog.sjinks.pro/tag/postgresql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PostgreSQL">PostgreSQL</a> с <a href="http://blog.sjinks.pro/tag/pdo/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PDO">PDO</a></em></h2>
<p>В PDO есть такая особенность: отсутствие поддержки вложенных транзакций.</p>
<p>Вложенные транзакции бывают весьма полезны: например, у нас есть два сервиса, которые могут взаимодействовать между собой. Сервис А начинает транзакцию, что-то делает, затем вызывает сервис Б, затем подтверждает транзакцию.</p>
<p>Может так случиться, что сервисы А и Б разрабатываются разными людьми и разработчик сервиса Б может не знать, что сервис А уже начал выполнение транзакции. Как следствие, при использовании PDO как только сервис Б попытается начать транзакцию, PDO выбросит исключение, предупреждающее о наличии активной транзакции.</p>
<p>Тем не менее, такие СУБД как MySQL и PostgreSQL поддерживают вложенные транзакции (о чём PDO не знает). Поэтому было бы неплохо добавить поддержку вложенных транзакций для данных СУБД в PDO.<span id="more-932"></span></p>
<p>Ниже приведена очень простая реализация поддержки вложенных транзакций в PDO:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93240">
        <div class="code php" id="p932code40">
<span class="kw2">class</span> MyPDO <span class="kw2">extends</span> PDO<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">static</span> <span class="re0">$_supported_drivers</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'mysql'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'pgsql'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">protected</span> <span class="re0">$_nest_level</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> nestedTransactionsSupported<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="sy0">!</span><span class="kw1">empty</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="sy0">::</span><span class="re0">$_supported_drivers</span><span class="br0">&#91;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getAttribute</span><span class="br0">&#40;</span>PDO<span class="sy0">::</span><span class="me2">ATTR_DRIVER_NAME</span><span class="br0">&#41;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> beginTransaction<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_nest_level <span class="sy0">||</span> <span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">nestedTransactionsSupported</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">parent</span><span class="sy0">::</span><span class="me2">beginTransaction</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">exec</span><span class="br0">&#40;</span><span class="st0">&quot;SAVEPOINT LEVEL<span class="es4">{$this-&gt;_nest_level}</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">++</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_nest_level<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> commit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">--</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_nest_level<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_nest_level <span class="sy0">||</span> <span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">nestedTransactionsSupported</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">parent</span><span class="sy0">::</span><span class="me2">commit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">exec</span><span class="br0">&#40;</span><span class="st0">&quot;RELEASE SAVEPOINT LEVEL<span class="es4">{$this-&gt;_nest_level}</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> rollBack<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">--</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_nest_level<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_nest_level <span class="sy0">||</span> <span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">nestedTransactionsSupported</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">parent</span><span class="sy0">::</span><span class="me2">rollBack</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">exec</span><span class="br0">&#40;</span><span class="st0">&quot;ROLLBACK TO SAVEPOINT LEVEL<span class="es4">{$this-&gt;_nest_level}</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p><strong>Подводные камни:</strong> в MySQL есть такое понятие как <dfn>неявное подтверждение транзакции</dfn> (<a href="http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html">implicit commit</a>). На практике это ломает уровень вложенности транзакций, поддерживаемый данной реализацией. С другой стороны, в web-приложениях редко возникает необходимость использования транзакций (тем более вложенных) там, где присутствуют операторы, вызывающие неявное подтверждение транзакции.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/932-pdo-nested-transactions/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/932-pdo-nested-transactions/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Ставим спам в комментариях на службу людям</title>
		<link>http://blog.sjinks.pro/wordpress/931-comment-spam-to-serve-humanity/</link>
		<comments>http://blog.sjinks.pro/wordpress/931-comment-spam-to-serve-humanity/#comments</comments>
		<pubDate>Sat, 06 Aug 2011 04:48:20 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Spamhaus]]></category>
		<category><![CDATA[Stop Forum Spam]]></category>
		<category><![CDATA[спам]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=931</guid>
		<description><![CDATA[Автоматическое отправление автоматического спама на Stop Forum Spam Я давно получаю по несколько тысяч спам-комментариев в день (не то, что мне он мешает — система его отсеивает полностью автоматически) и, как следствие, давно думаю о том, как заставить этот спам служить людям. Начиналось всё созданием чёрных списков типа DNSBL (сюда попадали IP-адреса спамеров) и URIBL (а сюда — рекламируемые [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/931-comment-spam-to-serve-humanity/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Автоматическое отправление автоматического спама на <a href="http://blog.sjinks.pro/tag/stop-forum-spam/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Stop Forum Spam">Stop Forum Spam</a></em></h2>
<p>Я давно получаю по несколько тысяч <a href="http://blog.sjinks.pro/tag/spam/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  спам">спам</a>-комментариев в день (не то, что мне он мешает — система его отсеивает полностью автоматически) и, как следствие, давно думаю о том, как заставить этот <a href="http://blog.sjinks.pro/tag/spam/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  спам">спам</a> служить людям.</p>
<p>Начиналось всё созданием чёрных списков типа DNSBL (сюда попадали <a href="http://blog.sjinks.pro/tag/ip/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  IP">IP</a>-адреса спамеров) и URIBL (а сюда — рекламируемые домены), но на раскрутку очередного чёрного списка (а также на его поддержание) банально не было ни сил, ни времени.</p>
<p>Закончилось всё тем, что я прекратил заниматься велосипедостроительством, зарегистрировался на <a href="http://www.stopforumspam.com/">Stop Forum Spam</a> и теперь отсылаю весь полученный спам туда. Хотя я не во всём согласен с SFS, положительным моментом является то, что списки спамеров мониторятся <a href="http://blog.sjinks.pro/tag/spamhaus/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Spamhaus">Spamhaus</a> (<a href="http://www.spamhaus.org/sbl/sbl.lasso?query=SBL115165">пример 1</a>, <a href="http://www.spamhaus.org/sbl/sbl.lasso?query=SBL115164">пример 2</a>). Хотя Spamhaus о себе тоже много думает (блокировать почту на основании того, что с данного IP-адреса идёт форумный спам — <a href="http://blogspambl.com/faq.html#idiot">бред</a>), тем не менее, у Spamhaus больше шансов прикрыть спамера, чем у простого блоггера.</p>
<p>На этом лирическое отступление закончено, далее идёт рассказ о том, как автоматически сообщать об автоматическом спаме в Stop Forum Spam, ибо чем больше отчетов они получат, тем быстрее спамер будет остановлен.<span id="more-931"></span></p>
<p>Идея, на которой строится реализация метода, абсолютно <a href="http://iskariot.ru/development/vs-auto-spam/">не нова</a>, но эффективна.</p>
<p><strong>Шаг первый.</strong> Регистрация на SFS и получение <a href="http://www.stopforumspam.com/signup">API-ключа</a>.</p>
<p><strong>Шаг второй.</strong> Создаём в каталоге с файлами <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> такой простенький файл (например, <code>wp-comments-post2.<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a></code>):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93145">
        <div class="code php" id="p931code45">
<span class="kw1">require_once</span> <span class="kw3">dirname</span><span class="br0">&#40;</span><span class="kw4">__FILE__</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st_h">'wp-comments-post2.php'</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p><strong>Шаг третий.</strong> Добавляем в <code>comments.php</code> используемой темы липовую форму комментариев. Например, такую:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93146">
        <div class="code xhtml" id="p931code46">
<span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;display: none; left: -10000px; top: -10000px;&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span>&gt;&lt;<span class="kw2">strong</span>&gt;</span>Пожалуйста, не используйте данную форму комментирования — она исключительно для спамеров.<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">strong</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">form</span> <span class="kw3">method</span><span class="sy0">=</span><span class="st0">&quot;post&quot;</span> <span class="kw3">action</span><span class="sy0">=</span><span class="st0">&quot;/wp-comments-post.php&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;comment-form-author&quot;</span>&gt;&lt;<span class="kw2">label</span>&gt;</span>Имя<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">label</span>&gt;</span> <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text&quot;</span> <span class="kw3">size</span><span class="sy0">=</span><span class="st0">&quot;30&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;author&quot;</span><span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;comment-form-email&quot;</span>&gt;&lt;<span class="kw2">label</span>&gt;</span>E-mail<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">label</span>&gt;</span> <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text&quot;</span> <span class="kw3">size</span><span class="sy0">=</span><span class="st0">&quot;30&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;email&quot;</span><span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;comment-form-url&quot;</span>&gt;&lt;<span class="kw2">label</span>&gt;</span>Сайт<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">label</span>&gt;&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text&quot;</span> <span class="kw3">size</span><span class="sy0">=</span><span class="st0">&quot;30&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;url&quot;</span><span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;comment-form-comment&quot;</span>&gt;&lt;<span class="kw2">label</span>&gt;</span>Комментарий<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">label</span>&gt;&lt;<span class="kw2">textarea</span> <span class="kw3">rows</span><span class="sy0">=</span><span class="st0">&quot;8&quot;</span> <span class="kw3">cols</span><span class="sy0">=</span><span class="st0">&quot;45&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;comment&quot;</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">textarea</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;form-submit&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;submit&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;Отправить комментарий&quot;</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;submit&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;submit&quot;</span><span class="sy0">/</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;hidden&quot;</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;comment_post_ID&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;&lt;?php echo get_the_ID(); ?&gt;</span></span>&quot; name=&quot;comment_post_ID&quot;/&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;hidden&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;0&quot;</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;comment_parent&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;comment_parent&quot;</span><span class="sy0">/</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span><br />
&nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">form</span>&gt;</span><br />
<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
        </div>
    </div>
</div>

<p><strong>Шаг четвёртый.</strong> Меняем нормальную форму комментирования. Всё, что требуется — изменить action формы комментирования с <code>/wp-comments-post.php</code> на <code>/wp-comments-post2.php</code>.</p>
<p>Если для создания формы комментирования используется новомодная функция <code>comment_form()</code> изменить <code>action</code> можно так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93147">
        <div class="code php" id="p931code47">
<span class="kw2">&lt;?php</span> <br />
&nbsp; &nbsp; <span class="kw3">ob_start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; comment_form<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">ob_get_clean</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="st_h">'/wp-comments-post.php'</span><span class="sy0">,</span> <span class="st_h">'/wp-comments-post2.php'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="re0">$s</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p><strong>Шаг пятый.</strong> Добавляем кусок кода в файл <code>functions.php</code> используемой темы:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p93148">
        <div class="code php" id="p931code48">
&nbsp; &nbsp; <span class="kw2">function</span> killallspam_pre_comment_approved<span class="br0">&#40;</span><span class="re0">$status</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">false</span> <span class="sy0">!==</span> <span class="kw3">strpos</span><span class="br0">&#40;</span><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st_h">'REQUEST_URI'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="st_h">'/wp-comments-post.php'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'comment'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'email'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'author'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st_h">'REMOTE_ADDR'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$apikey</span> &nbsp;<span class="sy0">=</span> <span class="st_h">'API-ключ Stop Forum Spam'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$comment</span> <span class="sy0">=</span> <span class="kw3">stripslashes</span><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'comment'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$ip</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st_h">'REMOTE_ADDR'</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$email</span> &nbsp; <span class="sy0">=</span> <span class="kw3">stripslashes</span><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'email'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$user</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw3">stripslashes</span><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'author'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$options</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_RETURNTRANSFER <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_AUTOREFERER &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_URL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'http://www.stopforumspam.com/add.php'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_MAXREDIRS &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> 10<span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_FOLLOWLOCATION <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_POST &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CURLOPT_POSTFIELDS &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'username='</span> <span class="sy0">.</span> <span class="kw3">urlencode</span><span class="br0">&#40;</span><span class="re0">$user</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st_h">'&amp;ip_addr='</span> <span class="sy0">.</span> <span class="kw3">urlencode</span><span class="br0">&#40;</span><span class="re0">$ip</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st_h">'&amp;email='</span> <span class="sy0">.</span> <span class="kw3">urlencode</span><span class="br0">&#40;</span><span class="re0">$email</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st_h">'&amp;api_key='</span> <span class="sy0">.</span> <span class="re0">$apikey</span> <span class="sy0">.</span> <span class="st_h">'&amp;evidence='</span> <span class="sy0">.</span> <span class="kw3">urlencode</span><span class="br0">&#40;</span><span class="re0">$comment</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$ch</span> <span class="sy0">=</span> <span class="kw3">curl_init</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">curl_setopt_array</span><span class="br0">&#40;</span><span class="re0">$ch</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">curl_exec</span><span class="br0">&#40;</span><span class="re0">$ch</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">curl_close</span><span class="br0">&#40;</span><span class="re0">$ch</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="st_h">'spam'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$status</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">function_exists</span><span class="br0">&#40;</span><span class="st_h">'add_filter'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; add_filter<span class="br0">&#40;</span><span class="st_h">'pre_comment_approved'</span><span class="sy0">,</span> <span class="st_h">'killallspam_pre_comment_approved'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Вместо <code>API-ключ Stop Forum Spam</code> подставляем свой API-ключ.</p>
<p>Вместо возни с cURL можно использовать API-функцию WordPress <code>wp_remote_post()</code>.</p>
<p><strong>Шаг шестой.</strong> Радуемся жизни <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/931-comment-spam-to-serve-humanity/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/931-comment-spam-to-serve-humanity/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>php: symbol zlibVersion, version libmysqlclient_16 not defined in in file libmysqlclient.so.16 with link time reference</title>
		<link>http://blog.sjinks.pro/linux/918-zlibversion-version-libmysqlclient_16-not-defined-in-file-libmysqlclientso16/</link>
		<comments>http://blog.sjinks.pro/linux/918-zlibversion-version-libmysqlclient_16-not-defined-in-file-libmysqlclientso16/#comments</comments>
		<pubDate>Mon, 30 May 2011 16:13:54 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ошибка]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=918</guid>
		<description><![CDATA[Быстрое исправление &#039;relocation error&#039; Не везёт мне с PHP на CentOS… Ситуация: имеется сервер на CentOS с установленной CPanel. PHP в случайные моменты времени завершается с ошибкой вида php: relocation error: php: symbol zlibVersion, version libmysqlclient_16 not defined in in file libmysqlclient.so.16 with link time reference Вместо zlibVersion может быть другое имя, например crc32. Из-за [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/linux/918-zlibversion-version-libmysqlclient_16-not-defined-in-file-libmysqlclientso16/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Быстрое исправление &#039;relocation error&#039;</em></h2>
<p><a href="http://blog.sjinks.pro/administering/460-upgrading-php-in-centos-5/">Не везёт</a> мне с <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> на <a href="http://blog.sjinks.pro/tag/centos/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  CentOS">CentOS</a>…</p>
<p>Ситуация: имеется сервер на CentOS с установленной CPanel. PHP в случайные моменты времени завершается с ошибкой вида</p>
<p><strong>php: relocation error: php: symbol zlibVersion, version libmysqlclient_16 not defined in in file libmysqlclient.so.16 with link time reference</strong></p>
<p>Вместо <code>zlibVersion</code> может быть другое имя, например <code>crc32</code>.</p>
<p>Из-за CPanel/WHM возможности ограничены опциями, предоставляемыми EasyApache — обновить <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a>/PHP штатными средствами (например, через <code>yum</code>) не представляется возможным из-за риска сломать CPanel.<span id="more-918"></span></p>
<p>Текст ошибки явно указывает на проблему с версией библиотеки, поэтому в первую очередь нужно выянить, где на сервере находится <code>libmysqlclient</code>. В моём случае это <code>/usr/lib64</code> и <code>/usr/lib64/mysql</code>.</p>
<p>Затем смотрим, какую из библиотек использует <code>php</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91852">
        <div class="code bash" id="p918code52">
$ <span class="kw2">ldd</span> <span class="sy0">`</span><span class="kw2">which</span> php<span class="sy0">`</span> <span class="sy0">|</span> <span class="kw2">grep</span> libmysqlclient<br />
&nbsp; &nbsp; &nbsp; &nbsp; libmysqlclient.so.16 =<span class="sy0">&gt;</span> <span class="sy0">/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<span class="sy0">/</span>libmysqlclient.so.16 <span class="br0">&#40;</span>0x00000034c6000000<span class="br0">&#41;</span><br />
$ <span class="kw2">ls</span> <span class="re5">-la</span> <span class="sy0">`/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<span class="sy0">/</span>libmysqlclient.so.16<span class="sy0">`</span><br />
lrwxrwxrwx <span class="nu0">1</span> root root <span class="nu0">27</span> May <span class="nu0">29</span> 00:08 <span class="sy0">/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<span class="sy0">/</span>libmysqlclient.so.16 -<span class="sy0">&gt;</span> libmysqlclient.so.16.0.0<span class="sy0">*</span>
        </div>
    </div>
</div>

<p>Но <code>libmysqlclient.so.16.0.0</code> существует и в <code>/usr/lib64</code>, и в <code>/usr/lib64/mysql</code>, поэтому посмотрим, где нужный символ есть:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91853">
        <div class="code bash" id="p918code53">
$ <span class="kw2">nm</span> <span class="sy0">/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<span class="sy0">/</span>mysql<span class="sy0">/</span>libmysqlclient.so.16.0.0 <span class="sy0">|</span> <span class="kw2">grep</span> zlibVersion<br />
<span class="kw2">nm</span>: libmysqlclient.so.16.0.0: no symbols<br />
$ <span class="kw2">nm</span> <span class="sy0">/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<span class="sy0">/</span>libmysqlclient.so.16.0.0 <span class="sy0">|</span> <span class="kw2">grep</span> zlibVersion<br />
00000034c60d64b0 T zlibVersion
        </div>
    </div>
</div>

<p>Меняем символьную ссылку на нужный файл:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91854">
        <div class="code bash" id="p918code54">
<span class="kw2">rm</span> <span class="re5">-f</span> <span class="sy0">/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<span class="sy0">/</span>libmysqlclient.so.16<br />
<span class="kw3">cd</span> <span class="sy0">/</span>usr<span class="sy0">/</span>lib64<span class="sy0">/</span>mysql<br />
<span class="kw2">ln</span> <span class="re5">-s</span> ..<span class="sy0">/</span>libmysqlclient.so.16.0.0 libmysqlclient.so.16
        </div>
    </div>
</div>

<p>После чего <a href="http://blog.sjinks.pro/tag/bug/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  ошибка">ошибка</a> исчезает.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/linux/918-zlibversion-version-libmysqlclient_16-not-defined-in-file-libmysqlclientso16/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/linux/918-zlibversion-version-libmysqlclient_16-not-defined-in-file-libmysqlclientso16/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>KSES в WordPress: можно ли проще?</title>
		<link>http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/</link>
		<comments>http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/#comments</comments>
		<pubDate>Thu, 10 Feb 2011 06:07:09 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[KSES]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=894</guid>
		<description><![CDATA[Регулярные выражения против DOM XML Вчера мне довелось разбираться с тем, как работает KSES в WordPress. KSES (рекурсивный акроним от KSES Strips Evil Scripts) — подсистема в WordPress (изначально написанная Ulf Harnhammar), предназначенная для проверки и очистки текста, введённого пользователем: она позволяет задать список допустимых тэгов, стилей и протоколов и на основе этих параметров убрать из текста [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Регулярные выражения против DOM XML</em></h2>
<p>Вчера мне довелось разбираться с тем, как работает <a href="http://blog.sjinks.pro/tag/kses/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  KSES">KSES</a> в <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a>.</p>
<p>KSES (рекурсивный акроним от KSES Strips Evil Scripts) — подсистема в WordPress (изначально написанная Ulf Harnhammar), предназначенная для проверки и очистки текста, введённого пользователем: она позволяет задать список допустимых тэгов, стилей и протоколов и на основе этих параметров убрать из текста пользователя всё, что им не соответствует.</p>
<p>KSES является довольно стабильной подсистемой; что немаловажно, KSES <em>работает</em>. Работает —  не трогай, а то сломаешь…<span id="more-894"></span></p>
<p>Лично мне в KSES не нравится использование регулярных выражений. Одна из причин — теория разработки компиляторов. Известно, что <a href="http://blog.sjinks.pro/tag/html/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HTML">HTML</a> — это грамматика второго типа в иерархии Хомского (контекстно-свободная грамматика), а регулярные выражения — грамматика третьего типа (регулярная грамматика). Грамматика второго типа является более сложной, нежели грамматика третьего типа. Как следствие, описать более простой грамматикой то, что соответствует более сложной, очень трудно (вряд ли возможно на 100%, но это моё мнение).</p>
<p>Что плохо, среди <a href="http://codex.wordpress.org/Automated_Testing">тестов WordPress</a> я не нашёл тестов для KSES. Что может означать, что, вероятно, никто из разработчиков не строил и не проверял граф путей в KSES; как следствие, не гарантии, что при граничных условиях всё будет работать нормально.</p>
<p>Другая причина, по которой я не люблю регулярные выражения — это скорость: особой производительностью они не отличаются. Хотя с другой стороны, объёмы проверяемого текста не так велики, чтобы KSES оказывал существенное влияние на <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a>.</p>
<p>Каковы альтернативы? <a href="http://htmlpurifier.org/comparison">Обзор</a>.</p>
<p>На <em>мой</em> взгляд, самая удобная альтернатива — использование DOM XML и работа с полученным деревом. Тем более, что в <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> есть соответствующая поддержка. А парсер на C в любом случае быстрее парсера на <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>.</p>
<p>Парсер DOM XML в PHP позволяет работать даже с некорректным HTML. Что означает, что он берёт на себя решение проблемы с неправильно закрытыми или незакрытыми тэгами. Парсер понимает HTML entities и преобразует их в нормальный текст. Что означает, что не нужно возиться с разными форматами записи entities и переводить их к одному виду (чему в KSES уделено не мало кода). И так далее.</p>
<p>Для проверки некоторых идей я написал небольшой класс, который делает <em>почти</em> то же самое, что и KSES, только иначе <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Я ни в коем случае не рассматриваю его как замену KSES.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p89456">
        <div class="code php" id="p894code56">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw2">class</span> Xex<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$protocols</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$tags</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$css</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$strip_comments</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$strip_script_text</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$strip_style_text</span> &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$script_text</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$style_text</span> &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$trim_text</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="kw1">array</span> <span class="re0">$tags</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="kw1">array</span> <span class="re0">$protocols</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="kw1">array</span> <span class="re0">$css</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">null</span> <span class="sy0">!==</span> <span class="re0">$tags</span><span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">tags</span> <span class="sy0">=</span> <span class="re0">$tags</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">null</span> <span class="sy0">!==</span> <span class="re0">$protocols</span><span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">protocols</span> <span class="sy0">=</span> <span class="kw3">array_combine</span><span class="br0">&#40;</span><span class="re0">$protocols</span><span class="sy0">,</span> <span class="re0">$protocols</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">null</span> <span class="sy0">!==</span> <span class="re0">$css</span><span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">css</span> <span class="sy0">=</span> <span class="kw3">array_combine</span><span class="br0">&#40;</span><span class="re0">$css</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> checkProtocols<span class="br0">&#40;</span><span class="re0">$str</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\r</span>&quot;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\t</span>&quot;</span><span class="sy0">,</span> <span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$str</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">':'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="sy0">,</span> 2<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// See http://tools.ietf.org/html/rfc3986#section-3.1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">preg_match</span><span class="br0">&#40;</span><span class="st_h">'/^[a-z][a-z0-9+.-]*$/'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="sy0">!</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">protocols</span><span class="br0">&#91;</span><span class="re0">$s</span><span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$str</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> sanitizeCss<span class="br0">&#40;</span><span class="re0">$css</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">,</span><span class="st0">&quot;<span class="es1">\r</span>&quot;</span><span class="sy0">,</span><span class="st0">&quot;<span class="es1">\t</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">preg_match</span><span class="br0">&#40;</span><span class="st_h">'![\\(&amp;=}]|/\\*!'</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$arr</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">';'</span><span class="sy0">,</span> <span class="kw3">trim</span><span class="br0">&#40;</span><span class="re0">$css</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$arr</span> <span class="kw1">as</span> <span class="re0">$x</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$x</span> <span class="sy0">=</span> <span class="kw3">trim</span><span class="br0">&#40;</span><span class="re0">$x</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$x</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$found</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">false</span> <span class="sy0">===</span> <span class="kw3">strpos</span><span class="br0">&#40;</span><span class="re0">$x</span><span class="sy0">,</span> <span class="st_h">':'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$found</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parts</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">':'</span><span class="sy0">,</span> <span class="re0">$x</span><span class="sy0">,</span> 2<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">css</span><span class="br0">&#91;</span><span class="kw3">rtrim</span><span class="br0">&#40;</span><span class="re0">$parts</span><span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$found</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$found</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">.=</span> <span class="re0">$x</span> <span class="sy0">.</span> <span class="st_h">';'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$css</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> parseDOM<span class="br0">&#40;</span>DOMNode <span class="re0">$el</span><span class="sy0">,</span> DOMNode <span class="re0">$new</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">nodeType</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_ELEMENT_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$prefix</span> <span class="sy0">=</span> <span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> ? <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> <span class="sy0">.</span> <span class="st_h">':'</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$tag</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="re0">$prefix</span> <span class="sy0">.</span> <span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">tagName</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">tags</span><span class="br0">&#91;</span><span class="re0">$tag</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span> <span class="sy0">=</span> <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">hasAttributes</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$attrs</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">tags</span><span class="br0">&#91;</span><span class="re0">$tag</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">attributes</span> <span class="kw1">as</span> <span class="re0">$a</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$attrs</span><span class="br0">&#91;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span><span class="sy0">-&gt;</span><span class="me1">removeAttribute</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="st_h">'style'</span> <span class="sy0">==</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">sanitizeCss</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$css</span> <span class="sy0">!=</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span><span class="sy0">-&gt;</span><span class="me1">setAttribute</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="kw3">in_array</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">,</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'xmlns'</span><span class="sy0">,</span> <span class="st_h">'profile'</span><span class="sy0">,</span> <span class="st_h">'href'</span><span class="sy0">,</span> <span class="st_h">'src'</span><span class="sy0">,</span> <span class="st_h">'cite'</span><span class="sy0">,</span> <span class="st_h">'classid'</span><span class="sy0">,</span> <span class="st_h">'codebase'</span><span class="sy0">,</span> <span class="st_h">'data'</span><span class="sy0">,</span> <span class="st_h">'usemap'</span><span class="sy0">,</span> <span class="st_h">'longdesc'</span><span class="sy0">,</span> <span class="st_h">'action'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">checkProtocols</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$s</span> <span class="sy0">!=</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span><span class="sy0">-&gt;</span><span class="me1">setAttribute</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$tag</span> <span class="sy0">==</span> <span class="st_h">'script'</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">strip_script_text</span> <span class="sy0">||</span> <span class="re0">$tag</span> <span class="sy0">==</span> <span class="st_h">'style'</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">strip_style_text</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span> <span class="sy0">=</span> <span class="re0">$new</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">hasChildNodes</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">childNodes</span> <span class="kw1">as</span> <span class="re0">$e</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">parseDOM</span><span class="br0">&#40;</span><span class="re0">$e</span><span class="sy0">,</span> <span class="re0">$n</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_TEXT_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">trim_text</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="kw2">new</span> DOMText<span class="br0">&#40;</span><span class="kw3">trim</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">wholeText</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_CDATA_SECTION_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_COMMENT_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parent</span> <span class="sy0">=</span> <span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">parentNode</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$parent</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">tagName</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$prefix</span> <span class="sy0">=</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> ? <span class="br0">&#40;</span><span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> <span class="sy0">.</span> <span class="st_h">':'</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$tag</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="re0">$prefix</span> <span class="sy0">.</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">tagName</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="st_h">'style'</span> <span class="sy0">==</span> <span class="re0">$tag</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">style_text</span> <span class="sy0">||</span> <span class="st_h">'script'</span> <span class="sy0">==</span> <span class="re0">$tag</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">script_text</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="kw2">new</span> DOMText<span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">data</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">strip_comments</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> sanitize<span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span> <span class="sy0">=</span> <span class="kw2">new</span> DOMDocument<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">recover</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">strictErrorChecking</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">substituteEntities</span> &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">resolveExternals</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">formatOutput</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$old</span> <span class="sy0">=</span> <span class="kw3">libxml_use_internal_errors</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="kw3">chr</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">preg_replace</span><span class="br0">&#40;</span><span class="st_h">'!&lt;([^a-z\\?\\!/])!i'</span><span class="sy0">,</span> <span class="st_h">'&amp;lt;$1'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">preg_replace</span><span class="br0">&#40;</span><span class="st_h">'!&lt;((?:[\\?\\!/]\\s*)?[a-z][^&gt;]*)(?=&lt;)!i'</span><span class="sy0">,</span> <span class="st_h">'&amp;lt;$1'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">@</span><span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">loadHTML</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">libxml_use_internal_errors</span><span class="br0">&#40;</span><span class="re0">$old</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span> <span class="sy0">=</span> <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">createDocumentFragment</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="kw2">new</span> DOMElement<span class="br0">&#40;</span><span class="st_h">'wrap'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">parseDOM</span><span class="br0">&#40;</span><span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">documentElement</span><span class="sy0">,</span> <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">firstChild</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">replaceChild</span><span class="br0">&#40;</span><span class="re0">$new</span><span class="sy0">,</span> <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">documentElement</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">saveXML</span><span class="br0">&#40;</span><span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">documentElement</span><span class="sy0">,</span> LIBXML_NOEMPTYTAG<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">substr</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="sy0">,</span> <span class="kw3">strpos</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="sy0">,</span> <span class="st_h">'&lt;wrap&gt;'</span><span class="br0">&#41;</span> <span class="sy0">+</span> 6<span class="sy0">,</span> <span class="sy0">-</span>7<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>Менее 200 строк против почти полутора тысяч.</p>
<p>На 45-килобайтном документе DOM быстрее KSES от 5 до 9 раз.<br />
На 90-килобайтном документе DOM быстрее KSES от 6 до 9 раз.<br />
На 180-килобайтном документе DOM быстрее KSES от 9 до 10 раз.</p>
<p>Производительность зависит от количества тэгов и стилей (разбор стилей реализован практически одинаково). Например, на домашней странице Google XEX может опережать KSES в 25 раз; если же соединить домашнюю страницу Google саму с собой 4 раза, разница во времени сокращается.</p>
<p>На домашней странице WordPress разница в 7 раз.</p>
<p>На <a href="http://blog.sjinks.pro/test/accordion/accordion1.html">этой странице</a> разница в 4 раза.</p>
<p>Всё-таки KSES очень медленный…</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Автоматическая проверка репутации IP-адреса</title>
		<link>http://blog.sjinks.pro/php/886-automatic-ip-reputation-check/</link>
		<comments>http://blog.sjinks.pro/php/886-automatic-ip-reputation-check/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 02:51:44 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[IP Reputation]]></category>
		<category><![CDATA[XPath]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=886</guid>
		<description><![CDATA[На примере SendMail, Reputation Authority, SenderBase и SenderScore Репутация IP-адреса — одна из очень важных составляющих, используемых для борьбы с почтовым спамом. Письма приходят с IP-адресов, а репутация этих адресов может сказать, является ли данный адрес ответственным за рассылку спама или нет. По некоторым данным проверка репутации IP-адресов позволяет остановить порядка 80% спама. Как следствие, компании, занимающиеся [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/886-automatic-ip-reputation-check/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>На примере SendMail, Reputation Authority, SenderBase и SenderScore</em></h2>
<p>Репутация <a href="http://blog.sjinks.pro/tag/ip/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  IP">IP</a>-адреса — одна из очень важных составляющих, используемых для борьбы с почтовым спамом.</p>
<p>Письма приходят с IP-адресов, а репутация этих адресов может сказать, является ли данный адрес ответственным за рассылку спама или нет. По некоторым данным проверка репутации IP-адресов позволяет остановить порядка 80% спама.</p>
<p>Как следствие, компании, занимающиеся массовой рассылкой электронных писем, должны заботиться о поддержании хорошей репутации адресов своих почтовых серверов.<span id="more-886"></span></p>
<p>Очень часто для отправки писем используется множество адресов — в частности из-за того, что крупные почтовые сервисы (GMail, Yahoo!, Hotmail, AOL, ….) имеют различные ограничения на количество сообщений, принимаемых с одного адреса, а также на скорость отправки почтовых сообщений. Например, компания, которую мы консультируем, рассылает более 100,000,000 писем в месяц, для чего используется не один десяток IP-адресов.</p>
<p>Естественно, что ручная проверка сотен адресов в десятке различных сервисов — занятие неблагодарное и утомительное. Но, к счастью, всё автоматизируется, что будет рассмотрено на примере <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>.</p>
<p>Очень часто для извлечения данных из web-страницы (data scraping) используются регулярные выражения. Но это вчерашний день <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  К тому же не всегда просто составить эффективное регулярное выражение, которое сразу выберет все необходимые данные — с большой вероятностью могут потребоваться несколько выражений и доводка результата напильником.</p>
<p>Простая и достойная альтернатива регулярным выражениям — <a href="http://blog.sjinks.pro/tag/xpath/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  XPath">XPath</a>. Тем более, что построить нужный <a href="http://blog.sjinks.pro/tag/xpath/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  XPath">XPath</a> можно при помощи FireBug (он позволяет скопировать адрес выделенного элемента как <a href="http://blog.sjinks.pro/tag/xpath/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  XPath">XPath</a>).</p>
<p>Рассмотрим на примере SenderScore. Репутация проверяется по ссылке вида <span class="codebox"><code class="text">https://senderscore.org/lookup.php?lookup=1.1.1.1</code></span>, где вместо 1.1.1.1 задаётся IP-адрес.</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2011/02/senderscore.png"><img src="http://static.sjinks.info/wp-content/uploads/2011/02/senderscore.png" alt="Проверка репутации IP-адреса при помощи SenderScore" title="Проверка репутации IP-адреса при помощи SenderScore" width="473" height="320" class="alignnone size-full wp-image-887" /></a></p>
<p>Как видно на скриншоте, FireBug показывает XPath требуемого элемента. Но при знании XPath можно использовать и более простое выражение.</p>
<p>Как это выглядит на PHP:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p88658">
        <div class="code php" id="p886code58">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$oldSetting</span> <span class="sy0">=</span> <span class="kw3">libxml_use_internal_errors</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw3">libxml_clear_errors</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$html</span> <span class="sy0">=</span> <span class="kw2">new</span> DOMDocument<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$html</span><span class="sy0">-&gt;</span><span class="me1">loadHtmlFile</span><span class="br0">&#40;</span><span class="st_h">'https://senderscore.org/lookup.php?lookup=1.1.1.1'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="re0">$xpath</span> <span class="sy0">=</span> <span class="kw2">new</span> DOMXPath<span class="br0">&#40;</span><span class="re0">$html</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="st_h">'Sender Score: '</span><span class="sy0">,</span> <span class="re0">$xpath</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="br0">&#40;</span><span class="st_h">'//div[@id=&quot;senderscore_number&quot;]'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">item</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">nodeValue</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw3">libxml_clear_errors</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw3">libxml_use_internal_errors</span><span class="br0">&#40;</span><span class="re0">$oldSetting</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<h2>XPath для других сервисов</h2>
<h3>Reputation Authority</h3>
<p><span class="codebox"><code class="text">http://reputationauthority.org/lookup.php?ip=1.1.1.1</code></span></p>
<p>Поиск ведётся относительно вершины <code>//div[@class="LookupIP-content"]/table[2]/tr[4]/td</code></p>
<ul>
<li><strong>Reputation Score:</strong> <code>.//table/tr[2]/td[2]</code></li>
<li><strong>Clean emails:</strong> <code>.//table[2]/tr[2]/td[2]</code></li>
<li><strong>Viruses:</strong> <code>.//table[2]/tr[3]/td[2]</code></li>
<li><strong>Spam:</strong> <code>.//table[2]/tr[4]/td[2]</code></li>
<li><strong>Malformed Emails:</strong> <code>.//table[2]/tr[5]/td[2]</code></li>
<li><strong>Suspicious Emails:</strong> <code>.//table[2]/tr[6]/td[2]</code></li>
<li><strong>Good Users:</strong> <code>.//table[2]/tr[8]/td[2]</code></li>
<li><strong>Bad Users:</strong> <code>.//table[2]/tr[9]/td[2]</code></li>
</ul>
<h3>SenderBase</h3>
<p><span class="codebox"><code class="text">http://www.senderbase.org/senderbase_queries/rep_lookup?search_name=1.1.1.1&amp;action%3ASearch=Search</code></span></p>
<p>При запросе страницы User-Agent должен быть похожим на нормальный браузер.</p>
<ul>
<li><strong>Email Reputation</strong> <code>//div[@id="tab1body"]//span[1]/text()</code></li>
<li><strong>Web Reptation</strong> <code>//div[@id="tab2body"]//span[1]/text()</code></li>
</ul>
<h3>SendMail</h3>
<p><span class="codebox"><code class="text">http://sendmail.com/sm/resources/tools/ip_reputation/ip_reputation_results/index.shtml?IP=1.1.1.1&amp;search.x=1&amp;search.y=1&amp;search=Submit</code></span></p>
<p>При запросе страницы Referer должен указывать на <span class="codebox"><code class="text">http://sendmail.com/sm/resources/tools/ip_reputation/</code></span>.</p>
<p>Поиск ведётся относительно вершины <code>//dev[@id="content"]/table[@class="ip_reputation"]</code></p>
<ul>
<li><strong><a href="http://blog.sjinks.pro/tag/ip-reputation/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  IP Reputation">IP Reputation</a> Class:</strong> <code>.//tr[4]/td[2]/text()</code></li>
<li><strong>Volume</strong> (может отсутствовать) <code>.//tr[5]/td[2]</code></li>
<li><strong>Weighted Risk</strong> <code>.//tr[6]/td[2]</code> (если Volume отсутствует, то <code>.//tr[5]/td[2]</code>)</li>
<li><strong>Spam Ratio</strong> (может отсутствовать) <code>.//tr[7]/td[2]</code></li>
<li><strong>Valid Bulk Ratio</strong> (может отсутствовать) <code>.//tr[8]/td[2]</code></li>
</ul>
<p>Либо можно использовать проверку текста:</p>
<ul>
<li><strong>Volume</strong> <code>.//tr/td[1][normalize-space()="Volume"]/following-sibling::td[1]</code></li>
<li><strong>Weighted Risk</strong> <code>.//tr/td[1][normalize-space()="Weighted Risk"]/following-sibling::td[1]</code></li>
<li><strong>Spam Ratio</strong> <code>.//tr/td[1][normalize-space()="Spam Ratio"]/following-sibling::td[1]</code></li>
<li><strong>Valid Bulk Ratio</strong> <code>.//tr/td[1][normalize-space()="Valid Bulk Ratio"]/following-sibling::td[1]</code></li>
</ul>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/886-automatic-ip-reputation-check/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/886-automatic-ip-reputation-check/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WordPress: кэширование средствами nginx</title>
		<link>http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/</link>
		<comments>http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/#comments</comments>
		<pubDate>Fri, 10 Dec 2010 12:08:15 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[кэш]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=877</guid>
		<description><![CDATA[Уменьшение потребления ресурсов во много раз Много было сказано про кэширование в WordPress… Сегодня я хочу рассказать о действительно эффективном методе, позволяющем сильно снизить нагрузку. Метод основан на использовании кэша FastCGI web-сервера nginx. Идея состоит в генерации статических страниц и отдачи их пользователям, не имеющим cookie комментатора. Зарегистрированным пользователям, а также комментаторам всегда отдаётся свежая [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Уменьшение потребления ресурсов во много раз</em></h2>
<p>Много было сказано про <a href="http://blog.sjinks.pro/?s=WordPress%20cache">кэширование в WordPress</a>… Сегодня я хочу рассказать о действительно эффективном методе, позволяющем сильно снизить нагрузку.</p>
<p>Метод основан на использовании кэша <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a> web-сервера <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a>.</p>
<p>Идея состоит в генерации статических страниц и отдачи их пользователям, не имеющим cookie комментатора. Зарегистрированным пользователям, а также комментаторам всегда отдаётся свежая страница. Так как читателей, ни разу не оставлявших комментарий, как правило, гораздо больше, чем комментаторов, то подобный использование кэша позволяет значительно снизить нагрузку на <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a>/<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>. Знакомые с принципом работы WP Super Cache заметят, что WPSC использует тот же принцип работы.<span id="more-877"></span></p>
<p>В чем же преимущество перекладывания работы на Web-сервер (nginx)?</p>
<ol>
<li>PHP — интерпретируемый язык. Как следствие, аналогичный код на компилируемом языке будет во много раз быстрее.</li>
<li>WordPress во многом bloatware <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  От момента начала загрузки страницы до окончания выполнения стадии <code>init</code> выполняется очень много «лишнего» кода.</li>
<li>В зависимости от нагрузки на сервер от запроса страницы до выполнения PHP-кода может пройти некоторое время: всё зависит от загруженности PHP (если все дочерние процессы PHP заняты обработкой запроса, новому запросу придётся ждать освобождения одного из процессов. Если за приемлемое время ни один процесс не освободился, пользователь видит сообщение о печально знаменитой ошибке 504).</li>
<li>Когда обслуживанием кэша занимается web-сервер, шансы на возникновение <a href="http://blog.sjinks.pro/wordpress/521-wp-super-cache-under-high-load/">подобной ситуации</a></li>
 (когда даже автор не может понять, в чём дело) значительно снижаются: реализация синхронизации/блокировок средствами PHP — неблагодарное дело.
</ol>
<p>Теперь переходим от теории к практике.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87761">
        <div class="code nginx" id="p877code61">
<ol class="nginx" style="font-family:monospace;"><li class="li1"><div class="de1"><span class="kw1">fastcgi_cache_path</span> /var/lib/nginx/myblog levels=2 keys_zone=myblog:10m max_size=512m inactive=20m;</div></li>
<li class="li1"><div class="de1"><span class="kw1">server</span> {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">server_name</span> example.com;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">root</span> /path/to/blog;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> ($http_cookie ~* <span class="st0">&quot;comment_author_|wordpress_(?!test_cookie)|wp-postpass_&quot;</span> ) {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">set</span> $do_not_cache <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; fastcgi_cache_bypass $do_not_cache;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; fastcgi_no_cache $do_not_cache;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_pass_header</span> Cookie;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache</span> myblog;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_key</span> $request_method|$host|$request_uri;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_valid</span> 301 8h;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_valid</span> 404 1h;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_valid</span> 200 15m;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> ($http_user_agent !~ FeedBurner) {</div></li>
<li class="li1"><div class="de1"><span class="co1"># Здесь идут перенаправления для FeedBurner</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">error_page</span> 404 = @wordpress;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">log_not_found</span> <span class="kw2">off</span>;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ^~ /files/ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">rewrite</span> /files/(.+) /wp-includes/ms-files.php?file=$1 last;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ~ ^/(wp-admin/.*\.php|wp-login\.php|wp-register\.php|(feed|comment/feed)(/.*)?)$ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try_files</span> $uri @wordpress;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">set</span> $do_not_cache <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; fastcgi_cache_bypass <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; fastcgi_no_cache <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> unix:/dev/shm/php-fcgi.sock;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME $document_root$fastcgi_script_name;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> @wordpress {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_NAME /<span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME $document_root/<span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> unix:/dev/shm/php-fcgi.sock;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> ($do_not_cache != <span class="st0">&quot;1&quot;</span>) {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">add_header</span> Vary Cookie;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ~ \.php$ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME $document_root$fastcgi_script_name;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try_files</span> $uri @wordpress;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> unix:/dev/shm/php-fcgi.sock;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> ($do_not_cache != <span class="st0">&quot;1&quot;</span>) {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">add_header</span> Vary Cookie;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ^~ /blogs.dir/ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">internal</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">root</span> /path/to/blog/wp-content/;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">}</div></li>
</ol>
        </div>
    </div>
</div>

<p>Документация по использованию FastCGI в nginx приведена <a href="http://sysoev.ru/nginx/docs/http/ngx_http_fastcgi_module.html">здесь</a>, поэтому я не буду подробно останавливаться на том, что конкретно каждая директива делает.</p>
<p>Основная магия происходит в строка 8—10: здесь определяются условия, при которых отдаётся свежая страница. В данном случае проверяется наличие авторизационных cookie и cookie комментатора. Важно, чтобы в случае отказа от кэширования переменная $<code>do_not_cache</code> устанавливалась в 1.</p>
<p>Строка 16 задаёт ключ, по которому страница доступна в кэше. В ключе присутствует <code>$request_method</code>, чтобы различать запросы GET и HEAD (для HEAD данные не возвращаются, только заголовки).</p>
<p>Строки 17—19 задают время жизни кэша в зависимости от кода ответа. Чем больше время жизни, тем реже будет обновляться информация для незарегистрированных пользователей.</p>
<p>В строке 32 задаётся маска для страниц, которые не должны кэшироваться (например, админка, страницы логина и регистрации, фиды).</p>
<p>Так как содержимое страницы <em>может</em> отличаться в зависимости от cookie пользователя, в строках 49 и 59 для закэшированных страниц принудительно выставляется заголовок <code>Vary: Cache</code>. Если используются другие правила (например, фильтрация по User-Agent), нужно добавлять соответствующее правило.</p>
<p>Строки 21—23: подробнее описано в статье <strong>«<a href="http://blog.sjinks.pro/wordpress/691-redirect-rss-feeds-to-feedburner-with-nginx/">Перенаправление RSS в WordPress на FeedBurner для nginx</a>»</strong></p>
<p>Строки 28—30, 63—66 подробнее описаны в статье <strong>«<a href="http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/">WordPress MultiSite, nginx и X-Accel-Redirect</a>»</strong></p>
<p>Вроде бы ничего не забыл. Теперь о том, какую <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a> мы получаем:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87762">
        <div class="code text" id="p877code62">
$ ab -n 10000 -c 100 http://blog.sjinks.pro/<br />
Server Software: &nbsp; &nbsp; &nbsp; &nbsp;nginx<br />
Server Hostname: &nbsp; &nbsp; &nbsp; &nbsp;blog.sjinks.pro<br />
Server Port: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;80<br />
<br />
Document Path: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/<br />
Document Length: &nbsp; &nbsp; &nbsp; &nbsp;50294 bytes<br />
<br />
Concurrency Level: &nbsp; &nbsp; &nbsp;100<br />
Time taken for tests: &nbsp; 46.925 seconds<br />
Complete requests: &nbsp; &nbsp; &nbsp;10000<br />
Failed requests: &nbsp; &nbsp; &nbsp; &nbsp;0<br />
Write errors: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br />
Total transferred: &nbsp; &nbsp; &nbsp;504940000 bytes<br />
HTML transferred: &nbsp; &nbsp; &nbsp; 502940000 bytes<br />
Requests per second: &nbsp; &nbsp;213.10 [#/sec] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 469.254 [ms] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 4.693 [ms] (mean, across all concurrent requests)<br />
Transfer rate: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;10508.28 [Kbytes/sec] received<br />
<br />
Connection Times (ms)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max<br />
Connect: &nbsp; &nbsp; &nbsp; 16 &nbsp; 94 &nbsp;76.9 &nbsp; &nbsp; 94 &nbsp; &nbsp;3125<br />
Processing: &nbsp; 118 &nbsp;373 &nbsp;81.7 &nbsp; &nbsp;360 &nbsp; &nbsp;1334<br />
Waiting: &nbsp; &nbsp; &nbsp; 17 &nbsp; 69 &nbsp;38.5 &nbsp; &nbsp; 57 &nbsp; &nbsp; 422<br />
Total: &nbsp; &nbsp; &nbsp; &nbsp;156 &nbsp;467 105.0 &nbsp; &nbsp;445 &nbsp; &nbsp;3535<br />
<br />
Percentage of the requests served within a certain time (ms)<br />
&nbsp; 50% &nbsp; &nbsp;445<br />
&nbsp; 66% &nbsp; &nbsp;454<br />
&nbsp; 75% &nbsp; &nbsp;471<br />
&nbsp; 80% &nbsp; &nbsp;494<br />
&nbsp; 90% &nbsp; &nbsp;541<br />
&nbsp; 95% &nbsp; &nbsp;589<br />
&nbsp; 98% &nbsp; &nbsp;655<br />
&nbsp; 99% &nbsp; &nbsp;768<br />
&nbsp;100% &nbsp; 3535 (longest request)
        </div>
    </div>
</div>

<p>Сервер зафлудили 10,000 запросами в 100 <strong>параллельных</strong> потоков. Сервер выдал практически полгигабайта за 47 секунд; в среднем сервер обрабатывал <strong>213 запросов в секунду</strong>, при этом <strong>99% запросов были обработаны за 768 мс</strong> (при том, что на сервере несколько сайтов в Alexa Top 100,000)! Нагрузка на сервер была минимальной (изменений Load Average замечено не было).</p>
<p><strong style="color: red">UPDATE:</strong> есть один небольшой нюанс: CAPTCHA. Если вы их используете, убедитесь, что они работают. Дело в том, что страница со статьёй будет отдаваться непосредственно из кэша nginx, PHP загружаться не будет. Поэтому если CAPTCHA полагается на использование сессии, она может работать неправильно. Здесь всё зависит от используемого плагина.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/feed/</wfw:commentRss>
		<slash:comments>61</slash:comments>
		</item>
	</channel>
</rss>

