Мультисайтинг в Друпале - как использовать

Мне показалось странным, что на хабре эта тема практически не освещена и я постараюсь немного исправить эту ситуацию. 

Я не сторонник англицизма, но в нашем языке нет даже похожего термина. Вкратце мультисайтинг можно определить как возможность использовать файлы движка для разных сайтов. Не стану разбираться в этимологии этого слова, но осмелюсь предположить, что его появление было связано с Drupal. Одним из наиболее распространённых примеров мультисайтинга может быть использование общей базы данных пользователей на нескольких сайтах. В друпале мультисайтинг реализован привлекательно, с точки зрения простоты и удобства, о чём я и решил написать.

Вместо вступления

На мой взгляд, Drupal – это пластилин, из которого при желании можно слепить очень симпатичные вещицы. Хоть мой опыт общения с друпалом не так уж и велик, но мне пока не случалось встретить задачу, которую не удалось бы решить с его помощью. Должен признать, что если уровень знаний/мотивации/опыта разработчика малы, то из этого пластилина скорее всего получится кучка известной нетонущей массы, но речь совсем не об этом.

Как это делается?

Нужно отметить логическую грамотность построения структуры папок Drupal. Ядро отделено от собственного кода, весь код отделён от разметки. Мультисайтинг предусмотрен друпалом «из коробки», для чего существует папка sites в корневой директории. В этой папке должны располагаться файлы настроек сайтов, находящихся в связке с основным сайтом. Люди, хоть раз устанавливавшие Drupal, знают, что друпал требует создания файла settings.php в папке 

sites/default

В данном случае название папки 'default' определяет его принадлежность к «основному» сайту. 
В случае, когда нужно организовать мультисайтинг создаются папки с именами доменов рядом с 'default’ и туда копируется файлы settings.php из sites/all/default/default.settings.php

sites/first.example.ru/settings.php
sites/second.example.ru/settings.php
.
.
.
sites/n.example.ru/settings.php

в которых указываются специфичные настройки для данного сайта. Темы и модули, которые необходимо сделать доступными только для указанного сайта помещаются в соответствующие папки 

sites/first.example.ru/themes/
sites/first.example.ru/modules/

Темы и модули, размещённые в папке 

sites/all

будут доступны всем сайтам в мультисайтинговой связке. Таким образом можно существенно сократить время на их обновление.

Важно! Document root у всех сайтов в связке должен быть один – корневая директория с установленным друпалом (там, где лежит index.php). Так же возможен вариант симлинка на эту папку.

Как назвать папки?

В процессе поиска файлов settings.php друпал «обрезает» имена поддоменов слева направо, а имена подпапок справа налево. Из примера должно стать понятно, что под этим имеется ввиду.

Допустим, сайт у нас должен быть установлен в 

www.example.ru/mysite/test/

Друпал будет искать файл settings.php в следующих папках в указанной последовательности:

1. sites/www.example.ru.mysite.test
2. sites/example.ru.mysite.test
3. sites/ru.mysite.test

4. sites/www.example.ru.mysite
5. sites/example.ru.mysite
6. sites/ru.mysite

7. sites/www.example.ru
8. sites/example.ru
9. sites/ru

10. sites/default

Первый найденный файл будет использован, остальные проигнорированы. Из примера видно, что для работы сайта example.ru достаточно разместить settings.php в 

sites/example.ru/settings.php

и не нужно дублировать его в 

sites/www.example.ru/settings.php

т.к. и по обращению через example.ru, и по обращению www.example.ru друпал найдёт один и тот же файл.

В случае, если необходимо привязать сайт, установленный на нестандартный порт, порт указывается как дополнительный поддомен. Так, для сайта 

www.example.ru:8080/mysite/test/

папка с файлом settings.php должна быть

sites/8080.www.example.ru.mysite.test

От себя добавлю, что я бы не советовал связывать сайты, установленные в подпапку, т.к. их корректное функционирование не гарантируется (о чём сказано в документации). Есть, конечно, рекомендации по исправлению возможных ошибок, такие как создать симлинк document root для www.example.ru.mysite на document root для www.example.ru:

(из document root для www.example.ru)
ln -s . mysite

но это не панацея и выбирать нужно этот метод только при крайней необходимости.

Что менять в settings.php?

 

1. Если мы хотим использовать абсолютно независимые сайты

то в settings.php в $db_url указываем отдельную БД. Пользователь так же может быть другим. Наличие или отсутствие префикса здесь не имеет никакого значения, но, опять же добавлю от себя, присваивать префиксы к БД сайта — это, хоть и не большая, но дань безопасности и не стоит этим пренебрегать.

2. Если мы хотим использовать сайты с общей БД или с общими таблицами

 

a. если сайты будут использовать одну и ту же БД

то нужно использовать разные префиксы для уникальных таблиц и одинаковые для общих. Например, common_ у нас задуман как префикс для общих таблиц пользователей и профилей, default_ для собственных таблиц БД основного сайта, а first_ для собственных таблиц БД сайта first.example.ru. 

В sites/first.ru/settings.php пишем:

// $db_prefix = '';

$db_prefix = array(
"default" => "first_",
"users" => "common_",
"sessions" => "common_",
"authmap" => "common_",
"profile_fields" => "common_",
"profile_values" => "common_",
);

В sites/default/settings.php

// $db_prefix = '';

$db_prefix = array(
"default" => "default_",
"users" => "common_",
"sessions" => "common_",
"authmap" => "common_",
"profile_fields" => "common_",
"profile_values" => "common_",
);

Таким образом, сайт first.example.ru будет использовать общую c сайтом example.ru базу пользователей и их профилей. Но не стоит увлекаться этим способом, т.к. в среднем с каждым новым сайтом в связке число таблиц будет увеличиваться на 60-70. Нетрудно посчитать что будет с БД уже при десяти сайтах. Прибавьте к этому ещё и зависимость всех сайтов от корректной работы одной БД.

b. если сайты будут использовать разные БД и некоторые общие таблицы.

Допустим, нам необходимо использовать:

  • общие представления (созданные модулем views)
  • общую базу пользователей и их профилей для сайтов example.ru и fisrt.example.ru

и допустим, что:

  • наименование БД для example.ru – example
  • префикс таблиц для example.ru – example_,
  • наименование БД для first_example.ru – first
  • префикс таблиц таблиц для fisrt.example.ru – first_.

В sites/first.ru/settings.php пишем:

// $db_prefix = '';

$db_prefix = array(
"default" => "first_",
"users" => "example.example_",
"sessions" => "example.example_",
"authmap" => "example.example_",
"profile_fields" => "example.example_",
"profile_values" => "example.example_",
"views_display" => "example.example_",
"views_view" => "example.example_",

);

В sites/default/settings.php

$db_prefix = 'example_';

Таким обазом, для first.example.ru данные о представлениях и пользователях будут браться из БД example, а все остальные – из БД example.ru

Важно! Точка здесь интерепретируется друпалом как конец названия БД, поэтому не стоит создавать префикс с точкой. 

Заключение

Мультисайтинг друпала довольно просто настраивается и стабильно работает. Мне не приходилось встречаться с проблемами, несмотря на то, что для реализации поставленной задачи мне потребовалось объединить таблицы views_display, views_view, blocks и blocks_roles, в то время как Влад Савицкийклассифицировал blocks* как таблицы, объединять которые нельзя, а views_* как таблицы, объединять которые нужно с большой осторожностью. 
Макс Кириленко же считает, что «Мультисайтниг на общих таблицах недокументированная возможность Друпала, в ней больше проблем чем достоинств». Но его статья относится к Drupal 5 и, возможно, причина именно в этом.
Жду комментариев по этому поводу.

Два пригодившихся мне модуля по теме:

Multisite search — позволяет индексировать содержимое сайтов в связке и произвоить поиск по ним
Multisite login — позволяет сохранять авторизацию для всех сайтов в связке даже на разных доменах

UPD: pvasili советует быть внимательным при обновлении модулей в папке /sites/all (обязательно запускать update.php на всех доменах, использующих эту папку).
UPD: Cначала друпал будет искать модуль в sites/example.ru/modules, а уже после в /sites/all/modules
UPD: Для обновления через drush andyceo написал скрипт

 Автора автора