Хостинг-Центр РБК и WordPress (depricated)

Вот уже приблизительно два года я пользуюсь услугами хостинг-провайдера Хостинг-Центр РБК. В лист предоставляемых услуг входит возможность создания самостоятельных подсайтов внутри имеющегося домена, на которые накладываются странные ограничения. Те, кто пытался установить WordPress, TYPO3, Joomla и прочие гибко настраиваемые CMS наверняка знают о чём идёт речь.

Проблема заключается в установленных ограничениях на оперативную память для исполняемых скриптов. Поэтому при попытке запустить «громоздкий» скрипт сервер возвращает ошибку.

Fatal error: Out of memory (allocated 9699328)

Разговоры на эту тему с техподдержкой ХЦ бесполезны.

В данной статье речь пойдёт о простом (не идеальном) способе обхода описанной проблемы используя .htaccess и php.

Очевидно то, что для корректной установки и дальнейшей работы CMS необходимо будет запустить её на основном либо другом удалённом хостинге. Затем .htaccess на нашем подсайте будет отлавливать HTTP-запросы и отдавать их нашему php-cкрипту, который будет делать реальные запросы к удалённому сайту, забирать и изменять ссылки в содержимом, а затем его выводить.

Определимся с деталями. Положим что уже есть установленный и работающий WordPress на сайте http://www.site.ru/blog/. На основном хостинге создан подсайт blog.site.ru, где мы хотим видеть наш блог. В настройках веб-сервера нашего подсайта (в контрольной панели Хостинг-Центра РБК) выбрана версия PHP5. Версия движка WordPress2.7.1.

.htaccess

Первым действием в публичной папке подсайта («~/www/htdocs/«) создаём (либо изменяем содержимое уже имеющегося файла) «.htaccess» на следующие строки

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule . /index.php [L]
</IfModule>

Это стандартный .htaccess-файл движка блогов WordPress, являющийся идеально подходящим как для нашего случая, так и для тех, когда на удалённом сайте установлена любая другая CMS. Данная конфигурация возвращает пользователю, запрашивающему адрес вида http://blog.site.ru/<что угодно> результат работы скрипта index.php. В самом index.php мы уже работаем с запрошенным URL.

В PHP включена поддержка libcurl — библиотеки функций, написанной Daniel Stenberg, которая позволяет взаимодействовать с различными серверами по различным протоколам.

Возможности этой библиотеки мы и будем в основном использовать в нашем скрипте.

Первый подводный камень — невозможность обработки нашим скриптом POST-запросов, а это значит что для наименьших «потерь» (да, они всё-таки предстоят в нашем случае) админкой WordPress‘а придётся пользоваться по реальному адресу. Скорее всего проблема в том, что POST-запросы хранятся в заголовке документа, и при попытке внешнего скрипта (нашего index.php) для нашего реального сайта «подсунуть» ему переменные в POST-запросе останавливают выполнение нашего скрипта из соображений безопасности. Формы на сайте использующие метод GET (например тот же поиск) работать будут нормально.

index.php

Метод работы cURL в PHP делится на 2 части: случаи, когда мы работаем с заголовком запрашиваемого документа, и случаи, когда мы работаем с его телом. В нашем случае мы действуем сразу в обоих направлениях.

Итак, второе наше действие — создаём index.php.

Прежде всего определимся с переменными GET-форм. Передавать их в запросе следует используя специальный параметр сеанса cURLCURLOPT_POSTFIELDS. Значение этого параметра — собственно сами данные POST-запроса известного вида «?key=value&key2=value2«. Наш скрипт получает переменные эти в виде массива $_POST.

foreach ($_POST as $key => $value) {
	$postapx .= "&" . $key . '=' . $value;
}

Этот фрагмент собирает все полученные скриптом переменные в строку ($postapx), которую мы будем присоединять к нашим запросам реальной страницы.

Как говорилось выше, работа сURL разделена на две части: возврат заголовка и возврат содержимого запрашиваемого документа. Прежде чем выводить содержимое, необходимо скопировать заголовок удалённой страницы.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.site.ru/blog" . $_SERVER["REQUEST_URI"]);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
if ($postapx) {
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postapx);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$resp = curl_exec($ch);
curl_close($ch);

Инициализируем сеанс cURL и задаём ему параметры. CURLOPT_URL — указание запрашиваемой страницы. CURLOPT_HEADER — переключатель установленный в значение «включен» (по умолчанию «выключен»), отвечающий за возврат в результат заголовка. CURLOPT_NOBODY — переключатель, отключающий включение в результат запроса содержимого документа, потому как мы заняты пока исключительно заголовками. Затем мы проверяем наличие переменных GET-запроса нашему скрипту и при положительном результате включаем их в запрос удалённого документа.  Положительное значение переключателя CURL_RETURNTRANSFER запрещает прямой вывод результата запроса, вместо чего возвращает его в виде значения. Полезно, когда мы хотим записать его в переменную ($resp) для дальнейших операций над результатом. Все необходимые действия выполнены. Закрываем сеанс.

$headLines = explode("\n", $resp);
$i = 0;
foreach ($headLines as &$value) {
	$i++;
	if ($i > 2) {
		$skip = false;
		if (
			strstr($value, "Connection: keep-alive") ||
			strstr($value, "Keep-Alive:") ||
			strstr($value, "Transfer-Encoding:")
		)
			$skip = true;
		if (!$skip)
			header($value);
	}
}

Данные заголовка запрошенного документа сейчас хранятся в исходном виде — каждый новый параметр заголовка разделяется символом переноса строки \n. Существует необходимость работать с каждым параметром отдельно. Первая строка разбивает каждую новую строку принятой информации в отдельные элементы массива оператором explode. Далее наш скрипт перебирает каждый параметр на предмет необходимости включения его в наш документ.

HTTP/1.1 200 OK
Server: nginx/0.5.35

Первые две строки наш скрипт вернёт и без их наследования, поэтому организованный перед циклом счётчик $i пропускает обработку первых двух строк результата. Есть ещё несколько параметров (Connection, Keep-Alive и Transfer-Encoding) которые мы не наследуем из-за неуместности их при работе со статичными веб-документами.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.site.ru/blog" . $_SERVER["REQUEST_URI"] . $postapx);
if ($postapx) {
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postapx);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);

Снова инициализируем cURL-сессию, теперь уже для записи содержимого запрашиваемого документа в переменную $content.

$content = str_replace('http://www.site.ru/blog', 'http://blog.site.ru', $content);
print $content;

Затем производим в результате запроса замену всех присутствующих в нём ссылок на удалённые ресурсы и выводим его.

На этом этапе можно проверить работоспособность нашего скрипта. Но помните о рассказанных ранее проблемах с POST-запросами. Далее речь пойдёт лишь о частном случае с WordPress.

А теперь о жертвах

Сразу нужно упомянуть о том, что единственную жертву мы имеем лишь в случае, когда мы не используем других попыток создать POST-запрос нашему скрипту. В ином случае жертвами становятся все файлы, делающие эти попытки. Таким образом логично выключить из шаблона ссылки для входа и регистрации в административной зоне WordPress (вход и регистрация), т.к. всё-равно функционировать они не будут.

Как следствие: Вы публикуете новый материал и вообще пользуетесь админкой по реальному её адресу вида http://www.site.ru/blog/wp-login.php.

Публично POST-запрос в блоге также используется, когда пользователь пытается оставить комментарий к записи. Следовательно наша жертва — файл wp-comments-post.php. Он начинается со следующего блока:

if ( 'POST' != $_SERVER['REQUEST_METHOD'] ) {
	header('Allow: POST');
	header('HTTP/1.1 405 Method Not Allowed');
	header('Content-Type: text/plain');
	exit;
}

Он полностью комментируется. Затем методом поиска и замены ищем все фрагменты «$_POST» заменяя их на «$_GET«.

Нужно помнить об этих изменениях при обновлениях движка WordPress эти изменения аннулируются.

Последний этап — изменение метода формы обращённой к только что изменённому файлу. В случае с использованием стандартной темы Kubrick она находится в файле comments.php в каталоге темы.

В нём ищем:

<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="POST" id="commentform">

… и заменяем method="POST" на method="GET".

Вот и всё!

Архив содержащий скрипт и изменённый wp-comment-post.php (2,459 b)

UPD от 15.07.2009:
Яндекс снял с индекса… Пожалуй есть причины переселить блог на другой хостинг.

Метки: , , , , ,

Поделись ссылкой!

Комментарии (10)


Anagh
02.08.2009 в 10:59

Спасибо тебе большое. Без этой статьи, у меня никогда бы не получилось поставить wordpress на хостинг РБК.


Anagh
02.08.2009 в 11:04

По глупости, изменил в админке «параметры->общие» Адрес WordPress (URL) с поддомена на домен, после чего никак не мог попасть в админку. Поменял обратно напрямую через бд в таблице wp_options


uoziod
02.08.2009 в 13:21

да-да-да… обратно менять уже только средствами в базе. дык и скрипт рассчитан по идее на то, что он сам поменяет что нужно в нужный момент, а настройки уже самой инсталляции WP должны быть как для основного хоста.


SAN
07.08.2009 в 20:28

РБК гавно! Очень жаль потраченных сил, но даже wordpress с минимальным количеством проверенных плагинов и кешем, умудряется тормозить и висеть! мне даже не могут включить вывод используемой памяти, не говоря уже о лимите, который предусмотрен тарифным планом! О какой оптимизации в таком случае идет речь… Короче, я валю оттуда, чего и всем желаю!
Удачи!


Малах
08.10.2009 в 09:01

Что то мне с .htaccess не сильно понятно


uoziod
27.10.2009 в 08:28

А что там? Любой запрос перенаправляется к index.php, где мы про referer’у уже вычисляем, что запрашивалось.


uoziod
13.11.2009 в 11:49

теперь вроде бы можно установить и WordPress и TYPO3 на поддомен! только я всё-равно съехал от Хостинг-Центра!)


cellworld
17.11.2009 в 22:43

Вот спасибки, а то я уже думал съезжать с РБК…


Андрей
08.04.2010 в 00:31

Господа, может лучше смотреть в сторону буржуйских хостингов ?


uoziod
08.04.2010 в 00:42

Абсолютно солидарен!!! Особенно после вчерашней истории с МцХостом…

Оставить комментарий

XHTML: Вы можете использовать эту разметку: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>