Как запустить несколько веб-сайтов на одном сервере с одной и той же базой кода в PHP?

Я создал пользовательскую специализированную CMS с несколькими клиентами на ней, каждый со своим доменным именем, веб-сайтом, административной областью и базой данных, но все они находятся на одном сервере.

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

звучит здорово до сих пор так?

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

9 ответов


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

затем вы можете поместить этот каталог исходного кода где-нибудь и просто создать символические ссылки на него.

например, ваша структура каталогов может выглядеть так:

/var/www/src/index.php
/var/www/src/more_source.php
/var/www/clients/client_a/settings.php
/var/www/clients/client_a/src -> ../../src/
/var/www/clients/client_b/settings.php
/var/www/clients/client_b/src -> ../../src/

Если вы выберете эту структуру, единственное, что вам нужно изменить, будет включить в настройках.php (например, от require "settings.php" to require "../settings.php").


лично у меня есть клиентская таблица в базе данных, которая содержит текущий номер версии кода, который они запускают. Когда пользователь входит в систему, он устанавливает cookie под названием CodeVersion, указывающий версию кода для этого клиента (например, "v5-09-00"). В Apache .htaccess, у меня есть:

RewriteEngine on

RewriteCond %{HTTP_COOKIE} CodeVersion=([^;]+) [NC]
RewriteRule ^(.*)$ http://v%1.%{HTTP_HOST}/${escape:} [R=302,P,L]

и в файле local hosts у меня есть:

127.0.0.1    myservername       myservername.myserverdomain.com

127.0.0.1    v5-08-00.myservername  v5-08-00.myservername.myserverdomain.com
127.0.0.1    v5-09-00.myservername  v5-09-00.myservername.myserverdomain.com
127.0.0.1    v5-10-00.myservername  v5-10-00.myservername.myserverdomain.com

который обрабатывает локальное перенаправление в Apache на запись в vhosts

файл vhosts устанавливает среда для каждой версии кода:

<VirtualHost *:80>
    ServerAdmin mark.baker@myserverdomain.com
    DocumentRoot /usr/local/apache/htdocs_5-09-00
    ServerName v5-09-00.myservername.myserverdomain.com
    ServerAlias v5-09-00.myservername
    ErrorLog logs/myservername-error_log_5-09-00
    CustomLog logs/myservername-access_log_5-09-00 common
    php_value include_path ".:/php/includes:/usr/local/include/5-09-00/API:/usr/local/include/5-09-00/library:/usr/local/include/5-09-00/businesslogic:/usr/local/include/5-09-00/configuration:/usr/local/include/5-09-00/library/PHPExcel/Classes"
</VirtualHost>

<Directory "/usr/local/apache/htdocs_5-09-00">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>

В каждом наборе каталогов я могу иметь символические ссылки, указывающие на общий код, и фактические файлы php/ini для клиентского кода или конфигурации.


просто чтобы вы знали, что у меня была эта проблема раньше. Легко попасть в плен к какому-нибудь призраку .нарушения htaccess или открытые эксплойты до других клиентов, если вы решите настроить через это.

Я рекомендую держать все отдельно между клиентами.

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

вы можете запустить свою основную кодовую базу на отдельном тестовом сервере для выполнения обновлений, а затем просто исправить файлы FTP клиента и SQL базы данных.

но держите его простым и отдельным!


я разделился на library (ваш код) и config (три строки для каждого пользователя, возможно подключения к базе данных и тому подобное).

разделить library вне к всеобщему положению например /home/library (в *nix) и разрешить атрибут чтения для других учетных записей пользователей.

теперь для каждого сайта есть config файл, который сначала включает library и second устанавливает конфигурацию для конкретного сайта. Обновление library обновления всех версий. Слово предостережения хотя - вы захотите иметь некоторые модульные тесты на месте, чтобы обновить library не разбивает ни один из отдельных сайтов.

например config: (по одному на сайт)

<?php
require_once('/home/library/include.php');
//Line 1 config
//Line 2 config
//Line 3 config
?>

если ваша библиотека кода также используется для отображения содержимого (index.php и т. д.), то у вас есть два варианта: (1) создать symlinks между веб-папками каждого сайта и library source или (2) разделите код на основные функциональные возможности и код рендеринга.

A symlink создает системную связь между двумя точками на диске (это похоже на указатель). Правильно созданная ссылка позволяет получить доступ к папке с другим именем, чтобы вы могли создать /home/user1/library, /home/user2/library /home/user3/library, и все они указывают и содержат содержание /home/library (они не являются копиями данных).

я был бы включен, чтобы пойти с #2, хотя это займет больше работы впереди. Ваш library выполняет работу, но рендеринг сайта выполняется второй частью кода, которая поставляется на основе каждого сайта (вероятно, включая вышеупомянутые config), это позволяет больше гибкости на сайте на основе сайта (даже если вы не предвидите, что вам это еще нужно). В качестве побочного эффекта вы находитесь на пути к многоуровневому приложению.


альтернативным подходом является использование заглушек. Просто переместите общий код, как библиотеку в общий каталог. Затем для каждого отдельного участка создайте пустоту .PHP-скрипты, которые просто включить общий код:

  // file: index.php
  include(".../shared/index.php");

вам придется повторить это для каждой точки входа приложения. Таким образом, у вас есть почти пустые скрипты на каждом сайте, и все изменения в общей кодовой базе автоматически применяются ко всем настройкам. Просто пусть config.php отличаются между установками.

для статические файлы (изображения, css и др.) Я бы также использовал подход символической ссылки или перезаписи.


когда я делаю что-то подобное, у меня есть папка каждого клиента на веб-сервере, которая является рабочей копией SVN (я использую SVN в качестве моей системы управления версиями, очевидно). Затем, когда я сделал несколько обновлений, протестировал и пометил выпуск, я просто переключаю папку клиента на новый выпуск. SVN автоматически снимает все изменения для меня. Есть одно предостережение: убедитесь, что вы настроили свой веб-сервер, чтобы не разрешить обслуживание содержимого .SVN папки в каждом каталоге (или эквивалент для вашего VCS выбора, если он есть). Я считаю, что впервые прочитал об этой технике в официальных документах SVN, поэтому я думаю, что она санкционирована их разработчиками, но я не могу найти ссылку на нее в документах прямо сейчас.


Если вы поместите свой код в систему управления версиями, то каждый веб-сайт клиента может быть отдельной проверкой. Вы можете проверить свои изменения и внедрить их в каждый клиент (или тестовый сайт), выполнив обновление управления версиями (или используя экспорт) в корне. Затем вы можете обновить и протестировать каждый клиент по одному, чтобы убедиться, что исправление применено правильно.


во-первых, вы должны быть осторожны с подводными камнями обмена кодом между сайтами. Обновление многих сайтов сразу умножает опасность ваших обновлений, вызывающих проблему - если общий код имеет ошибку, лучше узнать на одном сайте, чем на сотне сразу!

решение для управления развертыванием может быть лучше, чем прямое совместное использование кода. (если вы используете Drupal, например, вы можете использовать Aegir для управления всеми развертываниями и обновлениями вашего сайта)

Что сказал, что в некоторых случаях может быть полезно поделиться кодом. Я сделал что-то подобное на предыдущей работе, где они хотели несколько сайтов, используя одну общую базу кода. Мы поместили общие библиотеки в папку на сервере, и каждому сайту была дана символическая ссылка на эту папку, поэтому он рассматривал ее как локальную папку. Довольно легко сделать, и довольно легко управлять.


Как насчет чего-то, что использует тот же код, но у каждого есть собственный mysql.
Например,http://mycms.com/myuser/ приносит префикс myuser_ в таблицы, таким образом, позволяя 1 структуру src и несколько сайтов. Тебе понадобится .реврайт, хотя