<?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; FastCGI</title>
	<atom:link href="http://blog.sjinks.pro/tag/fastcgi/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>Qt, libfcgi и многопоточность</title>
		<link>http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/</link>
		<comments>http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 17:31:00 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[потоки]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=956</guid>
		<description><![CDATA[Предотвращение блокирования событий при использовании libfcgi в многопоточном режиме Для создания приложений FastCGI на C/C++ есть библиотека libfcgi. Не буду вдаваться в дискуссию, зачем нужны приложения FastCGI на C/C++/подставить нужный язык, когда Python/PHP/Perl/подставить нужное гораздо удобнее. Отмечу лишь, что по работе понадобилось написать FastCGI-приложение на Qt (в основном из-за наличия нескольких высокопроизводительных библиотек, написанных на [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Предотвращение блокирования событий при использовании libfcgi в многопоточном режиме</em></h2>
<p>Для создания приложений <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a> на <a href="http://blog.sjinks.pro/tag/cpp/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  C/C++">C/C++</a> есть библиотека <a href="http://www.fastcgi.com/devkit/doc/overview.html">libfcgi</a>. Не буду вдаваться в дискуссию, зачем нужны приложения FastCGI на C/C++/подставить нужный язык, когда Python/<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>/Perl/подставить нужное гораздо удобнее. Отмечу лишь, что по работе понадобилось написать FastCGI-приложение на <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a> (в основном из-за наличия нескольких высокопроизводительных библиотек, написанных на <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a>, но не суть).</p>
<p>Строго говоря, libfcgi, хотя и является официальной библиотекой от создателей протокола, не лучший вариант для поддержки FastCGI — API, предоставляемое библиотекой, сильно ограничено (в плане функциональности) и недостаточно гибко.<span id="more-956"></span></p>
<p>Грубо говоря, приложение, использующее libfcgi, может работать в двух режимах:</p>
<ol>
<li>Последовательная обработка запросов: приложение получило запрос, обработало его, отправило результат, получило следующий запрос. Схема хороша, если обработка запроса тривиальна и/или не занимает много времени. Скорее всего, под большой нагрузкой масштабируется плохо, ибо чем длиннее очередь запросов, тем дольши придётся ждать клиенту.</li>
<li><a href="http://www.fastcgi.com/devkit/examples/threaded.c">Многопоточная</a> обработка запросов: приложение создаёт определённое количество потоков, каждый из которых будет обрабатывать свой запрос. При средних нагрузках эта схема работает лучше (если один поток занят, свободный поток займётся выполнением запроса). Но в предельном случае (когда все <a href="http://blog.sjinks.pro/tag/threads/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  потоки">потоки</a> заняты) имеем те же проблемы, что и в первом варианте. Схему можно немного изменить, создавая <a href="http://blog.sjinks.pro/tag/threads/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  потоки">потоки</a> по мере необходимости, но всё равно плодить <a href="http://blog.sjinks.pro/tag/threads/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  потоки">потоки</a> до бесконечности нельзя.</li>
</ol>
<p>Использование потоков не всегда уместно/хорошо: многопоточные программы, как правило, сложнее для разработки и отладки; кроме того, потоки потребляют системные ресурсы (например, память для стека) и при большом количестве потоков эти издержки могут быть существенными (например, для Linux/IA-32 размер стека для потока по умолчанию составляет 2 мегабайта).</p>
<p>К сожалению, при использовании libfcgi отказаться от потоков очень трудно — дело в том, что библиотека использует блокирующие операции при работе с сокетами.</p>
<p>В общем случае алгоритм работы с libfcgi следующий:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9565">
        <div class="code c" id="p956code5">
<span class="coMULTI">/* Инициализация */</span><br />
FCGX_Init<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw4">int</span> socket <span class="sy0">=</span> FCGX_OpenSocket<span class="br0">&#40;</span><span class="st0">&quot;:9001&quot;</span><span class="sy0">,</span> 256<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="coMULTI">/* ... */</span><br />
<br />
<span class="co1">// Собственно работа</span><br />
<span class="kw1">while</span> <span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; FCGX_Request<span class="sy0">*</span> req <span class="sy0">=</span> new FCGX_Request<span class="sy0">;</span><br />
&nbsp; &nbsp; FCGX_InitRequest<span class="br0">&#40;</span>req<span class="sy0">,</span> socket<span class="sy0">,</span> 0<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">int</span> rc <span class="sy0">=</span> FCGX_Accept_r<span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>rc <span class="sy0">&gt;=</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="coMULTI">/* Здесь создаём и запускаем поток, отвечающий за обработку запроса */</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>В случае с Qt и использованием рабочего цикла внутри основной программы имеется неприятный подводный камень: из-за того, что <code>FCGX_Accept_r()</code> использует блокирующие вызовы при работе с сокетом, основная программа может очень долго не увидеть сообщения, посылаемые, например, потоком.</p>
<p>Поэтому перед вызовом <code>FCGX_Accept_r()</code> имеет смысл проверять, имеются ли запросы на соединение.<br />
Решение в лоб:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9566">
        <div class="code cpp" id="p956code6">
<span class="co2">#include &lt;QtCore/QCoreApplication&gt;</span><br />
<span class="co2">#include &lt;sys/select.h&gt;</span><br />
<br />
<span class="coMULTI">/* ... */</span><br />
<br />
<span class="kw4">int</span> rc<span class="sy4">;</span><br />
<span class="kw1">do</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; QCoreApplication<span class="sy4">::</span><span class="me2">processEvents</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">struct</span> timeval tv <span class="sy1">=</span> <span class="br0">&#123;</span> 0, 500 <span class="br0">&#125;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; fd_set r<span class="sy4">;</span><br />
&nbsp; &nbsp; FD_ZERO<span class="br0">&#40;</span><span class="sy3">&amp;</span>r<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; FD_SET<span class="br0">&#40;</span>socket, <span class="sy3">&amp;</span>r<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; rc <span class="sy1">=</span> <span class="sy4">::</span><span class="me2">select</span><span class="br0">&#40;</span>socket<span class="sy2">+</span>1, <span class="sy3">&amp;</span>r, 0, 0, <span class="sy3">&amp;</span>tv<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span> <span class="kw1">while</span> <span class="br0">&#40;</span><span class="sy3">!</span>rc<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
FCGX_Request<span class="sy2">*</span> req <span class="sy1">=</span> <span class="kw3">new</span> FCGX_Request<span class="sy4">;</span><br />
FCGX_InitRequest<span class="br0">&#40;</span>req, socket, 0<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="kw4">int</span> sock <span class="sy1">=</span> FCGX_Accept_r<span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="coMULTI">/* ... */</span>
        </div>
    </div>
</div>

<p>Но более корректно будет использовать <code>QSocketNotifier</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9567">
        <div class="code cpp-qt" id="p956code7">
<span class="co1">// core.h</span><br />
<span class="co2">#include &lt;QtCore/QObject&gt;</span><br />
<br />
<span class="kw2">class</span> QSocketNotifier<span class="sy0">;</span><br />
<br />
<span class="kw2">class</span> Core <span class="sy0">:</span> <span class="kw2">public</span> <span class="kw5">QObject</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">Q_OBJECT</span><br />
<span class="kw2">public</span><span class="sy0">:</span><br />
&nbsp; &nbsp; <span class="kw2">explicit</span> Core<span class="br0">&#40;</span><span class="kw5">QObject</span> <span class="sy0">*</span>parent <span class="sy0">=</span> 0<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> run<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="kw2">private</span><span class="sy0">:</span><br />
&nbsp; &nbsp; <span class="kw5">QSocketNotifier</span><span class="sy0">*</span> m_notifier<span class="sy0">;</span><br />
<br />
<span class="kw2">private</span> <span class="kw2">slots</span><span class="sy0">:</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> connectionPending<span class="br0">&#40;</span><span class="kw4">int</span> socket<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
<br />
<span class="co1">// core.cpp</span><br />
<br />
Core<span class="sy0">::</span><span class="me2">Core</span><span class="br0">&#40;</span><span class="kw5">QObject</span> <span class="sy0">*</span>parent<span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw5">QObject</span><span class="br0">&#40;</span>parent<span class="br0">&#41;</span><span class="sy0">,</span> m_notifier<span class="br0">&#40;</span>0<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; FCGX_Init<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> sock <span class="sy0">=</span> FCGX_OpenSocket<span class="br0">&#40;</span><span class="st0">&quot;:9001&quot;</span><span class="sy0">,</span> 256<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; this<span class="sy0">-&gt;</span><span class="me3">m_notifier</span> <span class="sy0">=</span> <span class="kw1">new</span> <span class="kw5">QSocketNotifier</span><span class="br0">&#40;</span>sock<span class="sy0">,</span> <span class="kw5">QSocketNotifier</span><span class="sy0">::</span><span class="me2">Read</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QObject</span><span class="sy0">::</span><span class="kw2">connect</span><span class="br0">&#40;</span>this<span class="sy0">-&gt;</span><span class="me3">m_notifier</span><span class="sy0">,</span> SIGNAL<span class="br0">&#40;</span>activated<span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw1">this</span><span class="sy0">,</span> SLOT<span class="br0">&#40;</span>connectionPending<span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> Core<span class="sy0">::</span><span class="me2">connectionPending</span><span class="br0">&#40;</span><span class="kw4">int</span> socket<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw5">QSocketNotifier</span><span class="sy0">*</span> notifier <span class="sy0">=</span> qobject_cast<span class="sy0">&lt;</span><span class="kw5">QSocketNotifier</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>this<span class="sy0">-&gt;</span><span class="me3">sender</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; Q_CHECK_PTR<span class="br0">&#40;</span>notifier<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; notifier<span class="sy0">-&gt;</span><span class="me3">setEnabled</span><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; FCGX_Request<span class="sy0">*</span> req <span class="sy0">=</span> <span class="kw1">new</span> FCGX_Request<span class="sy0">;</span><br />
&nbsp; &nbsp; FCGX_InitRequest<span class="br0">&#40;</span>req<span class="sy0">,</span> socket<span class="sy0">,</span> 0<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> s <span class="sy0">=</span> FCGX_Accept_r<span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>s <span class="sy0">&gt;=</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="coMULTI">/* Здесь создаём и запускаем поток */</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; notifier<span class="sy0">-&gt;</span><span class="me3">setEnabled</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>В качестве альтернативы созданию потоков можно предложить использовать очередь запросов.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9568">
        <div class="code cpp" id="p956code8">
<span class="co2">#include &lt;QtCore/QMutex&gt;</span><br />
<span class="co2">#include &lt;QtCore/QMutexLocker&gt;</span><br />
<span class="co2">#include &lt;QtCore/QQueue&gt;</span><br />
<span class="co2">#include &lt;QtCore/QWaitCondition&gt;</span><br />
<br />
<span class="kw2">class</span> Queue <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy4">:</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> addToQueue<span class="br0">&#40;</span>FCGX_Request<span class="sy2">*</span> r, <span class="kw4">bool</span> broadcast <span class="sy1">=</span> <span class="kw2">false</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QMutexLocker locker<span class="br0">&#40;</span><span class="sy3">&amp;</span>this<span class="sy2">-</span><span class="sy1">&gt;</span>mx<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>queue.<span class="me1">enqueue</span><span class="br0">&#40;</span>r<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>broadcast<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>cv.<span class="me1">wakeAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</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; this<span class="sy2">-</span><span class="sy1">&gt;</span>cv.<span class="me1">wakeOne</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; FCGX_Request<span class="sy2">*</span> getFromQueue<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>mx.<span class="me1">lock</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>this<span class="sy2">-</span><span class="sy1">&gt;</span>queue.<span class="me1">isEmpty</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; this<span class="sy2">-</span><span class="sy1">&gt;</span>cv.<span class="me1">wait</span><span class="br0">&#40;</span><span class="sy3">&amp;</span>this<span class="sy2">-</span><span class="sy1">&gt;</span>mx<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; FCGX_Request<span class="sy2">*</span> result <span class="sy1">=</span> this<span class="sy2">-</span><span class="sy1">&gt;</span>queue.<span class="me1">dequeue</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>mx.<span class="me1">unlock</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> result<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="kw2">private</span><span class="sy4">:</span><br />
&nbsp; &nbsp; QMutex mx<span class="sy4">;</span><br />
&nbsp; &nbsp; QWaitCondition cv<span class="sy4">;</span><br />
&nbsp; &nbsp; QQueue<span class="sy1">&lt;</span>FCGX_Request<span class="sy2">*</span><span class="sy1">&gt;</span> queue<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>Но это уже совсем другая история.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/feed/</wfw:commentRss>
		<slash:comments>0</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>. Знакомые с принципом работы <a href="http://blog.sjinks.pro/tag/wp-super-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WP Super Cache">WP Super Cache</a> заметят, что 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="p87711">
        <div class="code nginx" id="p877code11">
<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="p87712">
        <div class="code text" id="p877code12">
$ 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>
		<item>
		<title>WordPress MultiSite, nginx и X-Accel-Redirect</title>
		<link>http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/</link>
		<comments>http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/#comments</comments>
		<pubDate>Sat, 04 Dec 2010 09:25:34 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[multisite]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=874</guid>
		<description><![CDATA[Ускорение загрузки файлов с дочерних блогов Одна из основных особенностей WordPress 3.0 — поддержка конфигурации MultiSite. При использовании FastCGI с WordPress MultiSite может выявиться одно слабое место: загруженные файлы (которые uploads) дочерних блогов отдаются PHP-скриптом (wp-includes/ms-files.php). Если количество процессов FastCGI небольшое, а загружаемые файлы большие и при этом имеется медленные клиенты, проблемы с производительностью гарантированы: дело в том, [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Ускорение загрузки файлов с дочерних блогов</em></h2>
<p>Одна из основных особенностей <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> 3.0 — поддержка конфигурации <a href="http://blog.sjinks.pro/tag/multisite/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  multisite">MultiSite</a>.</p>
<p>При использовании <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a> с WordPress MultiSite может выявиться одно слабое место: загруженные файлы (которые uploads) дочерних блогов отдаются <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>-скриптом (<code>wp-includes/ms-files.php</code>). Если количество процессов FastCGI небольшое, а загружаемые файлы большие и при этом имеется медленные клиенты, проблемы с производительностью гарантированы: дело в том, что один процесс FastCGI в один момент времени может обслуживать только одного клиента. Если запущено 5 процессов php-cgi, и имеется пять медленных клиентов, качающих файлы, все остальные клиенты будут ждать освобождения процессов PHP. Если клиенты медленные, а файлы большие, ждущие клиенты будут получать ошибку 504.</p>
<p>К счастью, при использовании <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a> проблема легко решается.<span id="more-874"></span></p>
<p>nginx поддерживает <a href="http://wiki.nginx.org/XSendfile">метод</a>, при котором приложение (в данном случае WordPress) может переложить ответственность за отдачу файла клиенту на nginx. Это достигается путём использования специального заголовка, <code>X-Accel-<a href="http://blog.sjinks.pro/tag/redirect/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  redirect">Redirect</a></code> (интересующимся подробностями рекомендую <a href="http://kovyrin.net/2006/11/01/nginx-x-accel-redirect-php-rails/">статью Алексея Ковырина</a>). <strong>WordPress полностью поддерживает данный метод.</strong> Но по умолчанию данный метод не используется, так как сначала нужно правильно настроить nginx.</p>
<p>Базовая настройка nginx для использования с WordPress приведена в <a href="http://blog.sjinks.pro/wordpress-plugins/nginx-compatibility/">соответствующей статье</a>, здесь же мы рассмотрим изменения, необходимые для поддержки multisite.</p>
<p>Загруженные файлы дочерних блогов располагаются в каталогах <span class="codebox"><code class="text">/wp-content/blog.dir/&lt;blog_id&gt;/</code></span>; WordPress же для отдачи файлов использует URL вида <span class="codebox"><code class="text">http://site.blog.com/files/&lt;filename&gt;</code></span>. Отдачей файла <span class="codebox"><code class="text">&lt;filename&gt;</code></span> клиенту занимается файл <code>/wp-includes/ms-files.php</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87416">
        <div class="code nginx" id="p874code16">
<span class="kw1">server</span> {<br />
<span class="co1">#...</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> ^~ /files/ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">rewrite</span> /files/(.+) /wp-includes/ms-files.php?file=$1 last;<br />
&nbsp; &nbsp; }<br />
<br />
<span class="co1">#...</span><br />
}
        </div>
    </div>
</div>

<p>В такой конфигурации отдавать файл клиенту будет сам WordPress (PHP), и при достаточной нагрузке мы столкнёмся с проблемами производительности. Поэтому настроим возможность отдачи файлов клиенту средствами nginx:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87417">
        <div class="code nginx" id="p874code17">
<span class="kw1">server</span> {<br />
<span class="co1">#...</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> ^~ /files/ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">rewrite</span> /files/(.+) /wp-includes/ms-files.php?file=$1 last;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> ^~ /blogs.dir/ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">internal</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">root</span> /path/to/blog/wp-content/;<br />
&nbsp; &nbsp; }<br />
<br />
<span class="co1">#...</span><br />
}
        </div>
    </div>
</div>

<p>Директива <code>internal</code> защищает файлы от прямых обращений, минуя <code>/wp-includes/ms-files.php</code>.</p>
<p>После внесения изменений в конфигурацию nginx, его необходимо перезапустить.</p>
<p>Затем добавляем следующую строку в <code>/wp-config.php</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87418">
        <div class="code php" id="p874code18">
<span class="kw1">define</span><span class="br0">&#40;</span><span class="st_h">'WPMU_ACCEL_REDIRECT'</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>После этого WordPress будет передавать заголовок X-Accel-Redirect с именем файла nginx, а nginx будет отдавать его клиенту. В результате скрипт PHP будет завершаться очень быстро и сможет обслуживать других клиентов.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Патч для php-cgi, позволяющий конфигурировать значение listen backlog</title>
		<link>http://blog.sjinks.pro/php/747-php-cgi-patch-to-configure-listen-backlog/</link>
		<comments>http://blog.sjinks.pro/php/747-php-cgi-patch-to-configure-listen-backlog/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 06:19:20 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[патч]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=747</guid>
		<description><![CDATA[Задание listen backlog через переменную окружения PHP_FCGI_LISTEN_BACKLOG По умолчанию значение listen backlog в php-cgi жёстко задано — 128. Это означает, что PHP не сможет обработать более 128 запросов одновременно (точнее, что очередь запросов не сможет превысить данного значения). Я столкнулся с тем, что 128 — это мало. Для тех, кто столкнулся с данной проблемой, но по каким-либо причинам не хочет/не может [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/747-php-cgi-patch-to-configure-listen-backlog/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Задание listen backlog через переменную окружения <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>_FCGI_LISTEN_BACKLOG</em></h2>
<p>По умолчанию значение listen backlog в php-cgi жёстко задано — 128. Это означает, что PHP не сможет обработать более 128 запросов одновременно (точнее, что очередь запросов не сможет превысить данного значения). Я столкнулся с тем, что 128 — это мало.</p>
<p>Для тех, кто столкнулся с данной проблемой, но по каким-либо причинам не хочет/не может поставить php-fpm (в котором backlog конфигурируется), я сделал небольшой <a href="http://blog.sjinks.pro/tag/patch/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  патч">патч</a>.<span id="more-747"></span></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p74723">
        <div class="code diff" id="p747code23">
--- php.orig/sapi/cgi/cgi_main.c.orig &nbsp; 2009-06-09 13:29:39.000000000 +0000<br />
<span class="re4">+++ php/sapi/cgi/cgi_main.c <span class="nu0">2010</span>-01-03 04:<span class="nu0">44</span>:<span class="nu0">34.000000000</span> +0000</span><br />
<span class="re6">@@ -<span class="nu0">1523</span>,<span class="nu0">7</span> +<span class="nu0">1523</span>,<span class="nu0">15</span> @@</span><br />
&nbsp;<br />
&nbsp;#if PHP_FASTCGI<br />
&nbsp; &nbsp; if <span class="br0">&#40;</span>bindpath<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="re7">- &nbsp; &nbsp; &nbsp; fcgi_fd = fcgi_listen<span class="br0">&#40;</span>bindpath, 128<span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; int backlog = <span class="nu0">128</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>getenv<span class="br0">&#40;</span>&quot;PHP_FCGI_LISTEN_BACKLOG&quot;<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; backlog = atoi<span class="br0">&#40;</span>getenv<span class="br0">&#40;</span>&quot;PHP_FCGI_LISTEN_BACKLOG&quot;<span class="br0">&#41;</span><span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>backlog &lt; <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; backlog = <span class="nu0">128</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></span><br />
<span class="re8">+</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; fcgi_fd = fcgi_listen<span class="br0">&#40;</span>bindpath, backlog<span class="br0">&#41;</span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>fcgi_fd &lt; 0<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fprintf<span class="br0">&#40;</span>stderr, &quot;Couldn't create FastCGI listen socket on port %s\n&quot;, bindpath<span class="br0">&#41;</span>;<br />
&nbsp;#ifdef ZTS
        </div>
    </div>
</div>

<p>Применять к файлу <code>sapi/cgi/cgi_main.c</code>.</p>
<p><strong>Что даёт:</strong> значение backlog можно задавать в переменной окружения <code>PHP_FCGI_LISTEN_BACKLOG</code>.</p>
<p>Проверялось на PHP 5.2.10-2ubuntu6.3 (Ubuntu 9.10).</p>
<p><strong>Установка в Debian/Ubuntu:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p74724">
        <div class="code bash" id="p747code24">
<span class="kw2">mkdir</span> php <span class="sy0">&amp;&amp;</span> <span class="kw3">cd</span> php<br />
<span class="kw2">apt-get</span> <span class="kw3">source</span> php5-cgi<br />
<span class="kw2">sudo</span> <span class="kw2">apt-get</span> <span class="kw2">install</span> devscripts build-essential <span class="kw2">wget</span><br />
<span class="kw2">sudo</span> <span class="kw2">apt-get</span> build-dep php5-cgi<br />
<span class="kw3">cd</span> php5-<span class="sy0">*</span><br />
<span class="re2">QUILT_PATCHES</span>=debian<span class="sy0">/</span>patches quilt <span class="re5">--quiltrc</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null push <span class="re5">-a</span><br />
<span class="kw2">wget</span> http:<span class="sy0">//</span>d.sjinks.pro<span class="sy0">/</span>listen-backlog-env-var.patch <span class="re5">-O</span> debian<span class="sy0">/</span>patches<span class="sy0">/</span>listen-backlog-env-var.patch<br />
<span class="re2">QUILT_PATCHES</span>=debian<span class="sy0">/</span>patches quilt <span class="re5">--quiltrc</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null import debian<span class="sy0">/</span>patches<span class="sy0">/</span>listen-backlog-env-var.patch<br />
<span class="re2">QUILT_PATCHES</span>=debian<span class="sy0">/</span>patches quilt <span class="re5">--quiltrc</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null push <span class="re5">-a</span><br />
<span class="re2">QUILT_PATCHES</span>=debian<span class="sy0">/</span>patches quilt <span class="re5">--quiltrc</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null pop <span class="re5">-a</span><br />
<span class="kw2">debuild</span> clean<br />
<span class="kw2">debuild</span> <span class="re5">-i</span> <span class="re5">-us</span> <span class="re5">-uc</span> <span class="re5">-b</span>
        </div>
    </div>
</div>

<p><strong>Практические результаты:</strong> при помощи <code>ab</code> генерировалась сильная нагрузка (DoS) на сервер (10,000 запросов в 200 параллельных потоков):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p74725">
        <div class="code bash" id="p747code25">
ab <span class="re5">-n</span> 10000 <span class="re5">-c</span> <span class="nu0">200</span> http:<span class="sy0">//</span>example.com<span class="sy0">/</span>
        </div>
    </div>
</div>

<p><strong>Стандартный PHP</strong> смог обработать <strong>2,275 запросов из 10,000</strong> — остальные запросы были отвергнуты (<strong>502 Bad Gateway</strong>).</p>
<p>После применения патча и</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p74726">
        <div class="code bash" id="p747code26">
<span class="kw3">echo</span> 2048 <span class="sy0">&gt;</span> <span class="sy0">/</span>proc<span class="sy0">/</span>sys<span class="sy0">/</span>net<span class="sy0">/</span>core<span class="sy0">/</span>somaxconn<br />
<span class="kw3">export</span> <span class="re2">PHP_FCGI_LISTEN_BACKLOG</span>=<span class="nu0">1024</span>
        </div>
    </div>
</div>

<p>и перезапуска, PHP смог обработать <strong>все запросы</strong>.</p>
<p>Изменилось всего-то 9 строк кода, а какой результат!</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/747-php-cgi-patch-to-configure-listen-backlog/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/747-php-cgi-patch-to-configure-listen-backlog/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>WP Super Cache vs MaxSite Cache: часть 2</title>
		<link>http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/</link>
		<comments>http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 08:23:41 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[MaxSite Cache]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[WP Super Cache]]></category>
		<category><![CDATA[кэш]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=725</guid>
		<description><![CDATA[Тест страничных кэшей на грамотно настроенном сервере Вторая часть статьи WP Super Cache vs MaxSite Cache. В предыдущей части я сравнивал поведение MaxSite Cache и WP Super Cache на тестовом VDS (512 MiB RAM, 10 GB HD, Intel Xeon X3320 (1 ядро), 2.5 GHz), на котором ни операционная система, ни программное обеспечение не были специально [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Тест страничных кэшей на грамотно настроенном сервере</em></h2>
<p><strong>Вторая часть статьи <a href="http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/">WP Super Cache vs MaxSite Cache</a></strong>.</p>
<p>В предыдущей части я сравнивал поведение <a href="http://blog.sjinks.pro/tag/maxsite-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MaxSite Cache">MaxSite Cache</a> и <a href="http://blog.sjinks.pro/tag/wp-super-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WP Super Cache">WP Super Cache</a> на тестовом VDS (512 MiB RAM, 10 GB HD, Intel Xeon X3320 (1 ядро), 2.5 GHz), на котором ни операционная система, ни программное обеспечение не были специально настроены — бралась конфигурация «из коробки» и тестировалась. Одним словом, «VDS абсолютного чайника».</p>
<p>В этой части изменилась только конфигурация программного обеспечения: сервер настраивался на максимальную <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a>.</p>
<p>В частности:</p>
<ul>
<li>отказ от Apache в пользу <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a> и от <code>mod_<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a>5</code> в пользу <code>php-fcgi</code> (количество <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a>-процессов выбиралось таким образом, чтобы избежать использования файла подкачки);</li>
<li>смена ядра с <code>linux-image-server</code> на <code>linux-image-virtual</code>;</li>
<li>настройка MySQL: отказ от InnoDB (экономит примерно 100 МБ памяти), увеличение буфера ключей и т.п.;</li>
<li>установка и настройка xCache (я исходил из того, что далеко не все чувствуют себя комфортно при сборке программ из исходников, поэтому брал только готовое ПО);</li>
<li>настройка <span class="codebox"><code class="bash">iptables</code></span> для фильтрации пакетов.</li>
</ul>
<p><span id="more-725"></span></p>
<p>Методика тестирования осталась прежней: <a href="http://blog.sjinks.pro/linux/722-transform-sitemap-to-siege-url-list/">карта сайта преобразовывалась в список адресов</a>, на этот список натравливался <code>siege</code>, а я присматривал за сервером и вносил коррективы в конфигурацию ПО (да, с первого раза трудно всё настроить идеально).</p>
<p>Чтобы убедиться, что новая конфигурация <strong>не хуже</strong> старой, я полностью отключил кэширование и имитировал 50 одновременных посетителей в течение 15 минут. На момент выполнения теста у сервера было свободно 348.5 МиБ памяти.</p>
<table class="bordered" cellspacing="0" cellpadding="0" rules="all">
<thead>
<tr>
<th>&nbsp;</th>
<th><strong>Голый <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a></strong></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество транзакций</th>
<td>4,825</td>
</tr>
<tr>
<th scope="row">Доступность сервера</th>
<td>99.98%</td>
</tr>
<tr>
<th scope="row">Объём данных, МБ</th>
<td>28.32</td>
</tr>
<tr>
<th scope="row">Среднее время ответа, с</th>
<td>9.23</td>
</tr>
<tr>
<th scope="row">Частота транзакций в секунду</th>
<td>5.36</td>
</tr>
<tr>
<th scope="row">Пропускная способность, МБ/с</th>
<td>0.03</td>
</tr>
<tr>
<th scope="row">Коэффициент параллельности</th>
<td>49.50</td>
</tr>
<tr>
<th scope="row">Максимальная длина транзакции, с</th>
<td>30.76</td>
</tr>
<tr>
<th scope="row">Минимальная длина транзакции, с</th>
<td>1.15</td>
</tr>
<tr>
<th scope="row">Максимальная загрузка процессора (system/user)</th>
<td>25.72%/68.39%</td>
</tr>
<tr>
<th scope="row">Load Average</th>
<td>40.81</td>
</tr>
<tr>
<th scope="row">Примерное потребление памяти, МиБ</th>
<td>414</td>
</tr>
</tbody>
</table>
<p>Данные загрузки/потребления памяти очень приблизительны. Хотя вряд ли пользователи станут ждать по 9 секунд загрузку страницы, радует, что сервер не ответил только на один запрос и не ушел в нокдаун. Простая экстраполяция показывает, что сервер выдержит примерно 463,000 обращения к PHP-страницам в сутки.</p>
<p>Мы убедились, что новая конфигурация вполне жизнеспособна (старой до неё, как до Китая в неудобной позе), переходим к тестированию плагинов.<br />
Тестирование проходило в 30 и 75 потоков. <strong>Я не разделял фазы построения и использования кэша</strong>.</p>
<table class="bordered" cellspacing="0" cellpadding="0" rules="all">
<thead>
<tr>
<th>&nbsp;</th>
<th><strong>MaxSite Cache</strong><br/>(30 потоков)</th>
<th><strong>MaxSite Cache</strong><br/>(75 потоков)</th>
<th><strong>WP Super Cache</strong><br/>(30 потоков, HALF ON)</th>
<th><strong>WP Super Cache</strong><br/>(30 потоков)</th>
<th><strong>WP Super Cache</strong><br/>(75 потоков)</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество транзакций</th>
<td>176,684</td>
<td>182,604</td>
<td>5,069</td>
<td>198,160</td>
<td>189,686</td>
</tr>
<tr>
<th scope="row">Объём данных, МБ</th>
<td>1,062.24</td>
<td>1,099.60</td>
<td>29.99</td>
<td>1,202.95</td>
<td>1,147.33</td>
</tr>
<tr>
<th scope="row">Среднее время ответа, с</th>
<td>0.13</td>
<td>0.34</td>
<td>5.30</td>
<td>0.10</td>
<td>0.29</td>
</tr>
<tr>
<th scope="row">Частота транзакций в секунду</th>
<td>196.36</td>
<td>203.00</td>
<td>5.64</td>
<td>220.20</td>
<td>210.95</td>
</tr>
<tr>
<th scope="row">Пропускная способность, МБ/с</th>
<td>1.18</td>
<td>1.32</td>
<td>0.03</td>
<td>1.34</td>
<td>1.28</td>
</tr>
<tr>
<th scope="row">Коэффициент параллельности</th>
<td>25.42</td>
<td>69.32</td>
<td>29.85</td>
<td>23.05</td>
<td>62.16</td>
</tr>
<tr>
<th scope="row">Максимальная длина транзакции, с</th>
<td>21.08</td>
<td>26.12</td>
<td>15.06</td>
<td>22.78</td>
<td>25.03</td>
</tr>
<tr>
<th scope="row">Минимальная длина транзакции, с</th>
<td>0.00</td>
<td>0.00</td>
<td>0.48</td>
<td>0.00</td>
<td>0.00</td>
</tr>
<tr>
<th scope="row">Load Average</th>
<td>1.8</td>
<td>2.2</td>
<td>30.1</td>
<td>1.3</td>
<td>1.65</td>
</tr>
</tbody>
</table>
<p><strong>Краткие выводы:</strong> на грамотно настроенном сервере лидирует WP Super Cache — и по скорости, и по создаваемой нагрузке. Это связано с тем, что задача по отдаче закэшированного контента переложена на web-сервер. Так как web-сервер справляется со статикой быстрее, чем с динамикой, в результате получаем рост производительности и снижение нагрузки.</p>
<p>Если по той или иной причине WP Super Cache не может работать в режиме Full On, то MaxSite Cache будет всё же предпочтительнее — ввиду своей простоты он обладает исключительным быстродействием.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>nginx Compatibility: делаем WordPress дружелюбнее к nginx</title>
		<link>http://blog.sjinks.pro/nginx/539-nginx-compatibility-making-wordpress-friendly-to-nginx/</link>
		<comments>http://blog.sjinks.pro/nginx/539-nginx-compatibility-making-wordpress-friendly-to-nginx/#comments</comments>
		<pubDate>Mon, 13 Apr 2009 22:22:25 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[Плагины WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[mod_rewrite]]></category>
		<category><![CDATA[redirect]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[плагин]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=539</guid>
		<description><![CDATA[Программное решение досадных мелочей с nginx Переведя несколько сайтов с Apache на nginx, уже который раз встречаю подводные камни. Один из них — нежелание WordPress понимать код редиректа, другая — постоянные попытки использовать PATHINFO-пермалинки вместо «нормальных» (pretty permalinks). Неудобно каждый раз лезть в код WordPress, чтобы поправить очередную несовместимость, поэтому я написал небольшой плагин. Будучи активированным, плагин устанавливает собственные [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/nginx/539-nginx-compatibility-making-wordpress-friendly-to-nginx/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Программное решение досадных мелочей с <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a></em></h2>
<p>Переведя несколько сайтов с Apache на nginx, уже который раз встречаю подводные камни. Один из них — нежелание <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/wordpress/510-wordpress-fastcgi-and-301-redirect/">понимать код редиректа</a>, другая — постоянные попытки использовать <a href="http://codex.wordpress.org/Using_Permalinks#PATHINFO:_.22Almost_Pretty.22">PATHINFO-пермалинки</a> вместо «нормальных» (pretty permalinks).</p>
<p>Неудобно каждый раз лезть в код WordPress, чтобы поправить очередную несовместимость, поэтому я написал небольшой <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a>.<span id="more-539"></span></p>
<p>Будучи активированным, плагин устанавливает собственные обработчики событий только в том случае, если сервер работает под управлением nginx, поэтому плагин без вреда (но и без всякой пользы) можно активировать на сервере с Apache — конфликтов не будет.</p>
<p>Текущая версия плагина решает следующие проблемы:</p>
<ul>
<li>Когда WordPress обнаруживает, что используется <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a> SAPI, он отказывается посылать коды перенаправления, <a href="http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/">отличные от 302</a>. Это приводит к тому, что при использовании неканонических ссылок PageRank от &laquo;неканонической&raquo; страницы не передаётся &laquo;канонической&raquo;. Я где-то читал, что использование кода 302 для склеивания страниц может караться поисковиками; так это или нет, утверждать не берусь. Плагин исправляет этот недочёт WordPress методом, аналогичным описанному <a href="http://blog.sjinks.pro/wordpress/patches/514-wordpress-fastcgi-and-301-redirect-part-2/">здесь</a>: только вместо физического исправления файла функция <span class="codebox"><code class="php">wp_redirect<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> просто переопределяется в другом файле.</li>
<li>Страница настроек постоянных ссылок полагается на наличие <code><a href="http://blog.sjinks.pro/tag/mod_rewrite/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  mod_rewrite">mod_rewrite</a></code>: если он загружен, используются красивые ссылки, если нет — используются &laquo;почти&raquo; красивые ссылки вида PATHINFO. Что же, разработчики пользуются Apache. Так как nginx не использует модули и API Apache, функция, проверяющая наличие <code>mod_rewrite</code>, скажет, что он не загружен. Тем не менее, nginx умеет переписывать адреса, и использование PATHINFO не оправдано. Поэтому плагин «заставляет» WordPress думать, что <code>mod_rewrite</code> всё-таки загружен и можно использовать нормальные постоянные ссылки.</li>
</ul>
<p><strong><a href="http://d.sjinks.pro/wordpress/nginx-compatibility-0.1.zip">Скачать nginx Compatibility 0.1</a>.</strong></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/nginx/539-nginx-compatibility-making-wordpress-friendly-to-nginx/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/nginx/539-nginx-compatibility-making-wordpress-friendly-to-nginx/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>WordPress, FastCGI и редирект 301: часть 2</title>
		<link>http://blog.sjinks.pro/nginx/514-wordpress-fastcgi-and-301-redirect-part-2/</link>
		<comments>http://blog.sjinks.pro/nginx/514-wordpress-fastcgi-and-301-redirect-part-2/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 18:16:57 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[Патчи]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[redirect]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[патч]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=514</guid>
		<description><![CDATA[Патч, исправляющий проблему редиректа с кодом 302 в FastCGI Более изящное решение, нежели представленное в первой части (WordPress, FastCGI и редирект 301). В первой части предлагалось при использовании web-сервера nginx закомментировать проверку на SAPI PHP (if ( php_sapi_name() != &#039;cgi-fcgi&#039; )). Однако есть лучшее решение. Сразу оговорюсь, что в официальном релизе оно вряд ли скоро [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/nginx/514-wordpress-fastcgi-and-301-redirect-part-2/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Патч, исправляющий проблему редиректа с кодом 302 в <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a></em></h2>
<p>Более изящное решение, нежели представленное в первой части (<strong><a href="http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/">WordPress, FastCGI и редирект 301</a></strong>).</p>
<p>В первой части предлагалось при использовании web-сервера <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a> закомментировать проверку на SAPI <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> (<span class="codebox"><code class="php"><span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw3">php_sapi_name</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="st_h">'cgi-fcgi'</span> <span class="br0">&#41;</span></code></span>). Однако есть лучшее решение.<span id="more-514"></span></p>
<p>Сразу оговорюсь, что в официальном релизе оно вряд ли скоро окажется (ибо работает с PHP 4.4+, а разработчики <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> хотят поддерживать такое старьё, как PHP 4.3), поэтому применять данное решение только на свой страх и риск.</p>
<p>Патч в формате unified diff (применять к <code>wp-includes/pluggable.php</code>):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p51428">
        <div class="code diff" id="p514code28">
--- trunk/public/wp-includes/pluggable.php &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>original<span class="br0">&#41;</span><br />
<span class="re4">+++ trunk/public/wp-includes/pluggable.php &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>modified<span class="br0">&#41;</span></span><br />
<span class="re6">@@ -<span class="nu0">845</span>,<span class="nu0">9</span> +<span class="nu0">845</span>,<span class="nu0">7</span> @@</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span> $is_IIS <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; header<span class="br0">&#40;</span>&quot;Refresh: <span class="nu0">0</span>;url=$location&quot;<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> else <span class="br0">&#123;</span><br />
<span class="re7">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span> php_sapi_name<span class="br0">&#40;</span><span class="br0">&#41;</span> != 'cgi-fcgi' <span class="br0">&#41;</span></span><br />
<span class="re7">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status_header<span class="br0">&#40;</span>$status<span class="br0">&#41;</span>; // This causes problems on IIS and some FastCGI setups</span><br />
<span class="re7">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; header<span class="br0">&#40;</span>&quot;Location: $location&quot;<span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; header<span class="br0">&#40;</span>&quot;Location: $location&quot;, null, $status<span class="br0">&#41;</span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp;<span class="br0">&#125;</span><br />
&nbsp;endif;
        </div>
    </div>
</div>

<p>Идея в том, чтобы переложить ответственность по отправлению кода перенаправления на PHP (который справляется с этим успешнее, чем WordPress). Решение является рабочим, жалоб пока нет <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><strong style="color: red">UPDATE:</strong> для nginx есть лучший способ: <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <strong><a href="http://blog.sjinks.pro/wordpress/plugins/539-nginx-compatibility-making-wordpress-friendly-to-nginx/">nginx Compatibility</a></strong>.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/nginx/514-wordpress-fastcgi-and-301-redirect-part-2/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/nginx/514-wordpress-fastcgi-and-301-redirect-part-2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WordPress, FastCGI и редирект 301</title>
		<link>http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/</link>
		<comments>http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 16:31:18 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[redirect]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=510</guid>
		<description><![CDATA[Как заставить WordPress посылать код 301 при использовании FastCGI Всё-таки удивительная штука WordPress… Сегодня чисто случайно обнаружил, что если PHP работает в режиме FastCGI (например, связка WordPress + nginx + PHP), то все редиректы с кодом 301 (Permanent Redirect) превращаются в редиректы с кодом 302 (Temporary Redirect). Чем это грозит? Если Вы занимаетесь спамомSEO, то Вы, вероятно, знаете, что переход с [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Как заставить <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> посылать код 301 при использовании <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a></em></h2>
<p>Всё-таки удивительная штука WordPress… Сегодня чисто случайно обнаружил, что если <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> работает в режиме FastCGI (например, связка WordPress + <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a> + <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>), то все редиректы с кодом 301 (Permanent <a href="http://blog.sjinks.pro/tag/redirect/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  redirect">Redirect</a>) превращаются в редиректы с кодом 302 (Temporary <a href="http://blog.sjinks.pro/tag/redirect/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  redirect">Redirect</a>).</p>
<p>Чем это грозит? Если Вы занимаетесь <del datetime="2009-03-05T16:07:27+00:00">спамом</del>SEO, то Вы, вероятно, знаете, что переход с кодом 302 <a href="http://www.searchmasters.co.nz/articles/97/do-302-redirects-pass-google-pr/">не передаёт PageRank</a>. Иными словами, если Вы изменили структуру пермалинков или по той или иной причине в Google "раскручена" страница с несколько другой постоянной ссылкой (например, &#x0068;ttp://example.com/?p=202), то «канонический редирект» (см. <span class="codebox"><code class="text">wp-includes/canonical.php</code></span>) не передаст PageRank целевой странице.<span id="more-510"></span></p>
<p>Еще раз повторюсь, это актуально только в случае использования PHP в режиме FastCGI (и для IIS, но это оффтопик).</p>
<p>Есть два способа решения проблемы:</p>
<ol>
<li>Написание плагина, реализующего свой вариант <span class="codebox"><code class="php">wp_redirect<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> (функция <span class="codebox"><code class="php">wp_redirect<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> определена в <code>wp-includes/pluggable.php</code>, что даёт возможность её переопределения);</li>
<li>Изменение кода <span class="codebox"><code class="php">wp_redirect<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> в <code>wp-includes/pluggable.php</code></li>
</ol>
<p>Я рассмотрю только второй вариант.</p>
<p>В оригинале функция <span class="codebox"><code class="php">wp_redirect<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> выглядит следующим образом:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p51031">
        <div class="code php" id="p510code31">
<span class="kw2">function</span> wp_redirect<span class="br0">&#40;</span><span class="re0">$location</span><span class="sy0">,</span> <span class="re0">$status</span> <span class="sy0">=</span> 302<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">global</span> <span class="re0">$is_IIS</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$location</span> <span class="sy0">=</span> apply_filters<span class="br0">&#40;</span><span class="st_h">'wp_redirect'</span><span class="sy0">,</span> <span class="re0">$location</span><span class="sy0">,</span> <span class="re0">$status</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$status</span> <span class="sy0">=</span> apply_filters<span class="br0">&#40;</span><span class="st_h">'wp_redirect_status'</span><span class="sy0">,</span> <span class="re0">$status</span><span class="sy0">,</span> <span class="re0">$location</span><span class="br0">&#41;</span><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">$location</span> <span class="br0">&#41;</span> <span class="co1">// allows the wp_redirect filter to cancel a redirect</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$location</span> <span class="sy0">=</span> wp_sanitize_redirect<span class="br0">&#40;</span><span class="re0">$location</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$is_IIS</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">header</span><span class="br0">&#40;</span><span class="st0">&quot;Refresh: 0;url=<span class="es4">$location</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw3">php_sapi_name</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="st_h">'cgi-fcgi'</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status_header<span class="br0">&#40;</span><span class="re0">$status</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// This causes problems on IIS and some FastCGI setups</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">header</span><span class="br0">&#40;</span><span class="st0">&quot;Location: <span class="es4">$location</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Всё, что требуется — закомментировать строку <span class="codebox"><code class="php"><span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw3">php_sapi_name</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="st_h">'cgi-fcgi'</span> <span class="br0">&#41;</span></code></span>. При этом не забываем прочитать комментарий разработчиков: <q>This causes problems on IIS and some FastCGI setups</q>.</p>
<p>Должно получиться что-то вида:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p51032">
        <div class="code php" id="p510code32">
<span class="kw2">function</span> wp_redirect<span class="br0">&#40;</span><span class="re0">$location</span><span class="sy0">,</span> <span class="re0">$status</span> <span class="sy0">=</span> 302<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">global</span> <span class="re0">$is_IIS</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$location</span> <span class="sy0">=</span> apply_filters<span class="br0">&#40;</span><span class="st_h">'wp_redirect'</span><span class="sy0">,</span> <span class="re0">$location</span><span class="sy0">,</span> <span class="re0">$status</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$status</span> <span class="sy0">=</span> apply_filters<span class="br0">&#40;</span><span class="st_h">'wp_redirect_status'</span><span class="sy0">,</span> <span class="re0">$status</span><span class="sy0">,</span> <span class="re0">$location</span><span class="br0">&#41;</span><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">$location</span> <span class="br0">&#41;</span> <span class="co1">// allows the wp_redirect filter to cancel a redirect</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$location</span> <span class="sy0">=</span> wp_sanitize_redirect<span class="br0">&#40;</span><span class="re0">$location</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$is_IIS</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">header</span><span class="br0">&#40;</span><span class="st0">&quot;Refresh: 0;url=<span class="es4">$location</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
<span class="co1">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ( php_sapi_name() != 'cgi-fcgi' )</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status_header<span class="br0">&#40;</span><span class="re0">$status</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// This causes problems on IIS and some FastCGI setups</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">header</span><span class="br0">&#40;</span><span class="st0">&quot;Location: <span class="es4">$location</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Не забываем сохранить файл, после чего редиректы с кодом 301 останутся редиректами с кодом 301 <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><strong style="color: red">UPDATE:</strong> для nginx есть лучший способ: <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <strong><a href="http://blog.sjinks.pro/wordpress/plugins/539-nginx-compatibility-making-wordpress-friendly-to-nginx/">nginx Compatibility</a></strong>.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/510-wordpress-fastcgi-and-301-redirect/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Конфигурация nginx для WordPress: критический взгляд со стороны</title>
		<link>http://blog.sjinks.pro/wordpress/458-nginx-config-for-wordpress-look-from-the-gallery/</link>
		<comments>http://blog.sjinks.pro/wordpress/458-nginx-config-for-wordpress-look-from-the-gallery/#comments</comments>
		<pubDate>Thu, 18 Dec 2008 11:25:21 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=458</guid>
		<description><![CDATA[Можно ли сделать лучше? Update: статья писалась давным-давно, правильная конфигурация nginx для работы с WordPress описана здесь. Три недели назад я рассказывал про одну из конфигураций nginx для WordPress. С тех пор я получил пару отзывов, что так делать неправильно с ссылкой на конфигурацию, одобренную Игорем Сысоевым (автором nginx). Лежит она здесь: This has the [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/458-nginx-config-for-wordpress-look-from-the-gallery/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Можно ли сделать лучше?</em></h2>
<p><strong style="color: red">Update:</strong> <strong>статья писалась давным-давно, правильная конфигурация <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</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/wordpress-plugins/nginx-compatibility/">здесь</a></strong>.</p>
<p>Три недели назад я рассказывал про одну из <strong><a href="http://blog.sjinks.pro/wordpress/398-wordpress-replacing-apache-with-nginx/">конфигураций nginx для WordPress</a></strong>. С тех пор я получил пару отзывов, что так делать неправильно с ссылкой на конфигурацию, одобренную Игорем Сысоевым (автором nginx). Лежит она <a href="http://michaelshadle.com/2008/08/17/nginx-wordpress-redux/">здесь</a>:</p>
<blockquote src="http://michaelshadle.com/2008/08/17/nginx-wordpress-redux/">This has the approval of Igor, the creator &#8211; you cannot get better than that.</blockquote>
<p><span id="more-458"></span></p>
<p>На серверах, которые мне пришлось переводить на nginx, стояла версия 0.6.34 (версию 0.7.сколько-то там пришлось снести из-за того, что она сегфолтилась при обработке некоторых запросов, а анализировать core dump нет желания).</p>
<p>Рассмотрим предлагаемую конфигурацию:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p45836">
        <div class="code nginx" id="p458code36">
<span class="kw1">server</span> {<br />
&nbsp; &nbsp;<span class="kw1">listen</span> <span class="nu0">80</span>;<br />
&nbsp; &nbsp;<span class="kw1">server_name</span> michaelshadle.com;<br />
&nbsp; &nbsp;<span class="kw1">index</span> <span class="kw1">index</span>.php;<br />
&nbsp; &nbsp;<span class="kw1">root</span> /home/mike/web/michaelshadle.com/;<br />
&nbsp; &nbsp;<span class="kw1">include</span> /etc/nginx/defaults.conf;<br />
&nbsp; &nbsp;<span class="kw1">include</span> /etc/nginx/<span class="kw1">expires</span>.conf;<br />
&nbsp; &nbsp;<span class="kw1">error_page</span> 404 = /wordpress/<span class="kw1">index</span>.php?q=$request_uri;<br />
&nbsp; &nbsp;<span class="kw1">location</span> ~ \.php$ {<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> 127.0.0.1:<span class="nu0">11000</span>;<br />
&nbsp; &nbsp;}<br />
}
        </div>
    </div>
</div>

<p>Начнём с того, что WordPress не требует параметр <code>q</code> в запросе: достаточно взглянуть на правила, которые он генерирует для Apache. Но это всё, по сути, мелочи.</p>
<p>Такая конфигурация тоже является рабочей, но есть одно «но»: если пользователь запрашивает несуществующий <strong><a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a></strong>-файл (например, опечатался), то ему прилетает экран с недружественным сообщением «No input file specified». К сожалению, для моего случая это было критично, ибо пользователь в такой ситуации должен был видеть немного другую страницу.</p>
<p>Есть еще одна <a href="http://www.lexa.ru/nginx-ru/msg20839.html">конфигурация</a> (правда, для Drupal), написанная Игорем Сысоевым. Если её перевести на WordPress, то получится предыдущий вариант, только хуже: помимо «No input file specified», на все 404 ошибки выдавался код 200 (!).</p>
<p>Конфигурация выглядела так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p45837">
        <div class="code nginx" id="p458code37">
<span class="kw1">server</span> {<br />
&nbsp; &nbsp; <span class="kw1">server_name</span> dev.example.com;<br />
&nbsp; &nbsp; <span class="kw1">index</span> <span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; <span class="kw1">root</span> /var/www/dev.example.com;<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> / {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">log_not_found</span> <span class="kw2">off</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">error_page</span> 404 = @wordpress;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> @wordpress {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> 127.0.0.1:<span class="nu0">9000</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME /var/www/dev.example.com/<span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> ~ \.php$ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> 127.0.0.1:<span class="nu0">9000</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME /var/www/dev.example.com$fastcgi_script_name;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;<br />
&nbsp; &nbsp; }<br />
}
        </div>
    </div>
</div>

<p>Вот что получалось при обращении к <code>dev.example.com/x/ph</code>:</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2008/12/redirect.png"><img src="http://static.sjinks.info/wp-content/uploads/2008/12/redirect.png" alt="200 instead of 404" class="alignnone size-full wp-image-459" /></a></p>
<p>Первый ответ 302 — это редирект с <code>dev.example.com/x/ph</code> на <code>dev.example.com/x/ph/</code><br />
А второй ответ 200 — это то, что не должно случаться. Это, кстати, объясняет <a href="http://blog.sjinks.pro/wordpress/patches/457-all-in-one-seo-pack-blank-screen-for-404/">баг, который я нашел в All in One SEO Pack</a>.</p>
<p>Взяв две рассмотренные конфигурации за основу, я создал третью, рабочую:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p45838">
        <div class="code nginx" id="p458code38">
<span class="kw1">server</span> {<br />
&nbsp; &nbsp; <span class="kw1">server_name</span> dev.example.com;<br />
<br />
&nbsp; &nbsp; <span class="kw1">index</span> <span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; <span class="kw1">root</span> /var/www/dev.example.com;<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> / {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">log_not_found</span> <span class="kw2">off</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">error_page</span> 404 = /<span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> = /<span class="kw1">index</span>.php {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> 127.0.0.1:<span class="nu0">9000</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME /var/www/dev.example.com/<span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; <span class="kw1">location</span> ~ \.php$ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> (!-e $request_filename) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">rewrite</span> ^(.+)$ /<span class="kw1">index</span>.php <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> 127.0.0.1:<span class="nu0">9000</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME /var/www/dev.example.com$fastcgi_script_name;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;<br />
&nbsp; &nbsp; }<br />
}
        </div>
    </div>
</div>

<p>Так как <cite>Игорь Сысоев</cite> говорит, что <q>обычно практикуемая прямая трансляция правил […] достойна всяческого порицания</q>, то такая конфигурация должна быть относительно хорошей. Хотя на мой взгляд, проверка существования файла делается что с rewrite, что без; видимо, в случае с nginx rewrite является довольно дорогой операцией (хотя, возможно, для <code>-e</code> выполняется лишний <code>stat</code>, не знаю).</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/458-nginx-config-for-wordpress-look-from-the-gallery/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/458-nginx-config-for-wordpress-look-from-the-gallery/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress: заменяем Apache mathopd&#8217;ом</title>
		<link>http://blog.sjinks.pro/wordpress/400-wordpress-replacing-apache-with-mathopd/</link>
		<comments>http://blog.sjinks.pro/wordpress/400-wordpress-replacing-apache-with-mathopd/#comments</comments>
		<pubDate>Tue, 25 Nov 2008 17:00:26 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Администрирование]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[mathopd]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=400</guid>
		<description><![CDATA[Дружим WordPress и mathopd Вторая статья из серии "WordPress: Заменяем Apache лёгким web-сервером". Первая статья была посвящена nginx, в данной статье разберём особенности конфигурирования mathopd и WordPress для совместной работы. В Ubuntu/Debian нам понадобится пакет libfcgi0ldbl, содержащий программу cgi-fcgi, которую mathopd использует в качестве обёртки для FastCGI: aptitude install libfcgi0ldbl Или можно попробовать собрать обёртку [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/400-wordpress-replacing-apache-with-mathopd/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Дружим <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/mathopd/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  mathopd">mathopd</a></em></h2>
<p>Вторая статья из серии "WordPress: Заменяем Apache лёгким web-сервером".</p>
<p><a href="http://blog.sjinks.pro/wordpress/398-wordpress-replacing-apache-with-nginx/">Первая статья</a> была посвящена <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a>, в данной статье разберём особенности конфигурирования mathopd и WordPress для совместной работы.<span id="more-400"></span></p>
<p>В Ubuntu/Debian нам понадобится пакет <code>libfcgi0ldbl</code>, содержащий программу <code>cgi-fcgi</code>, которую mathopd использует в качестве обёртки для <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p40042">
        <div class="code bash" id="p400code42">
<span class="kw2">aptitude</span> <span class="kw2">install</span> libfcgi0ldbl
        </div>
    </div>
</div>

<p>Или можно попробовать собрать обёртку с <a href="http://fastcgi.com/dist/fcgi-current.tar.gz" rel="nofollow">исходников</a>.</p>
<p>Как и в прошлом случае, мы предполагаем, что <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> в режиме FastCGI прослушивает 9000 порт на 127.0.0.1</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p40043">
        <div class="code math" id="p400code43">
Server {<br />
&nbsp; &nbsp; Port 80<br />
&nbsp; &nbsp; Address 0.0.0.0<br />
&nbsp; &nbsp; Virtual {<br />
&nbsp; &nbsp; &nbsp; &nbsp; Host example.com<br />
&nbsp; &nbsp; &nbsp; &nbsp; Control {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Alias /<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Location /var/www/example.com<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ScriptUser nobody<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; External {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;/usr/bin/cgi-fcgi -bind -connect 127.0.0.1:9000&quot; { .php }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
}
        </div>
    </div>
</div>

<p>Особенностью работы под mathopd является то, что он не предоставляет функциональности для переписывания адресов (как <a href="http://blog.sjinks.pro/tag/mod_rewrite/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  mod_rewrite">mod_rewrite</a> в Apache), поэтому пермалинки будут всего лишь "<a href="http://codex.wordpress.org/Using_Permalinks#PATHINFO:_.22Almost_Pretty.22" rel="nofollow">Almost Pretty</a>".</p>
<p>При тестировании данной конфигурации обнаружилась одна интересная особенность, которую, вероятно, стоит считать ошибкой mathopd: если демон web-сервера слушает нестандартный (не 80) порт, то WordPress уходит в вечный цикл редиректов.</p>
<p>Причина здесь в следующем: mathopd, в отличие от других серверов, <strong>не добавляет</strong> порт в переменную <span class="codebox"><code class="php"><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&quot;HTTP_HOST&quot;</span><span class="br0">&#93;</span></code></span>. Таким образом, для <code>example.com:8080</code> <span class="codebox"><code class="php"><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&quot;HTTP_HOST&quot;</span><span class="br0">&#93;</span></code></span> в mathopd будет <code>example.com</code> (nginx, например, укажет значение <code>example.com:8080</code>).</p>
<p>В WordPress есть интересная процедура&nbsp;&mdash;&nbsp;<code><a href="http://blog.sjinks.pro/tag/redirect/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  redirect">redirect</a>_canonical</code>, которая пытается привести URL к каноническому виду (типа, SEO friendly). В ней есть интересные строки:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p40044">
        <div class="code php" id="p400code44">
<ol class="php" style="font-family:monospace;" start="45"><li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span><span class="re0">$requested_url</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// build the URL in the address bar</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$requested_url</span> &nbsp;<span class="sy0">=</span> <span class="br0">&#40;</span> <span class="sy0">!</span><span class="kw1">empty</span><span class="br0">&#40;</span><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st_h">'HTTPS'</span><span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">strtolower</span><span class="br0">&#40;</span><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st_h">'HTTPS'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">==</span> <span class="st_h">'on'</span> <span class="br0">&#41;</span> ? <span class="st_h">'https://'</span> <span class="sy0">:</span> <span class="st_h">'http://'</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$requested_url</span> <span class="sy0">.=</span> <span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st_h">'HTTP_HOST'</span><span class="br0">&#93;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$requested_url</span> <span class="sy0">.=</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></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div></li>
</ol>
        </div>
    </div>
</div>

<p>В случае mathopd и <code>&#x0068;ttp://example.com:8080/</code>, <span class="codebox"><code class="php"><span class="re0">$requested_url</span></code></span> будет установлен в <code>&#x0068;ttp://example.com/</code>. Так как форма этого URL не будет совпадать (из-за того, что порт потерялся) с формой, хранимой в базе данных, WordPress сделает перенаправление на <code>&#x0068;ttp://example.com/</code>, и так будет продолжаться до бесконечности.</p>
<p>Для решения проблемы придётся закомментировать строку <span class="codebox"><code class="php">add_action<span class="br0">&#40;</span><span class="st_h">'template_redirect'</span><span class="sy0">,</span> <span class="st_h">'redirect_canonical'</span><span class="br0">&#41;</span><span class="sy0">;</span></code></span> в файле <code>/wp-includes/canonical.php</code>.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/400-wordpress-replacing-apache-with-mathopd/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/400-wordpress-replacing-apache-with-mathopd/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

