Из блога
http://shaman.asiadata.ru.
Оригинал сообщения находится здесь.
Ваши комментарии.
Если вам необходимо на друпал-сайте использовать данные из другой базы (может быть даже с другого хоста), то это достаточно просто сделать. Предоставленные для этого возможности не затрагивают кода ядра и могут быть использованы, как в виде вставок PHP-кода в материалы сайта, так и в собственных модулях и темах.
Находим в папке sites/default файл settings.php.
Редактируем его. Вместо строчки
$db_url = 'mysql://username:password@localhost/databasename';
ставим
$db_url =
array(
'default'=>'mysql://username:pass@localhost/databasename',
'db1'=>'mysql://username1:pass@host1/databasename1',
'db2'=>'mysql://username2:pass@host2/databasename2',
/*
** Сколько угодно параметров для требуемого количества баз данных
** Индексы кроме 'default' могут быть любыми.
*/
);
Теперь если в сниппете, модуле, блоке или материале вам понадобятся данные из других баз, используем следующий код:
/*
** Делаем активной базу с параметрами под индексом 'db1'
*/
db_set_active('db1');
$result =
db_query("Здесь нужный вам запрос к таблицам в db1")
/*
** Здесь обрабатываем результат первого запроса
*/
// Делаем активной базу с параметрами под индексом 'db2'
db_set_active('db2');
$result =
db_query("Здесь нужный вам запрос к таблицам в db2")
/*
** Здесь обрабатываем результат второго запроса
*/
/*
** В конце ОБЯЗАТЕЛЬНО делаем активной «родную» базу,
** чтобы Drupal мог нормально завершить обработку страницы.
*/
db_set_active('default');
Переключаться между базами можно сколько угодно раз - после первого обращения Drupal кеширует ресурс соединения с БД в массиве $db_conns и повторного соединения не производится.
Если вам недоступно редактирование файла установок, то можно установить требуемое соединение сразу в PHP-коде:
/*
** Получаем глобальные переменные Drupal
*/
global $db_url;
/*
** Добавляем свою строку подключения к БД, а родную оставляем под индексом 'default'
*/
$db_url =
array(
"default"=>$db_url,
"db1"=>"mysql://username1:pass@host1/databasename1"
);
/*
** Делаем активной базу с параметрами под индексом 'db1'
*/
db_set_active('db1');
$result =
db_query("Здесь нужный вам запрос к таблицам в db1")
/*
** Здесь обрабатываем результат запроса
*/
/*
** В конце ОБЯЗАТЕЛЬНО делаем активной «родную» базу,
** чтобы Drupal мог нормально завершить обработку страницы.
*/
db_set_active('default');
Указанные решения работают в D5 и D6.
Единственное ограничение - тип баз данных должен быть одним для всех соединений, т.е. следующий код вызовет ошибку:
$db_url =
array(
'default'=>'mysqli://username:pass@localhost/databasename',
'db1'=>'pgsql://username1:pass@host1/databasename1',
);
Вы получите: Cannot redeclare db_status_report() (previously declared in /var/www/mysite/includes/database.mysqli.inc:23) in /var/www/mysite.ru/includes/database.pgsql.inc
Устранить данное ограничение можно только хаком ядра Drupal. Хак получается весьма объемистым. С указанной ошибкой все дело не в функции db_status_report(), а со способом которым Drupal подключает интерфейс требуемого типа баз данных. Дело в том, что названия всех функций (за исключением одной - db_check_setup) находящихся в файлах database.pgsql.inc, database.mysql.inc, database.mysqli.inc и database.mysql-common.inc совпадают, что приводит к конфликту в именах 41 функции. Поэтому использовать несколько подключений к базам разных типов можно только полностью переписав слой абстракции баз данных в Drupal.
Чтобы сделать это откроем все упомянутые файлы в редакторе.
Из файлов database.mysql.inc и database.mysqli.inc удаляем строчку
require_once './includes/database.mysql-common.inc';
Содержимое файла database.mysql-common.inc копируем в файлы database.mysql.inc и database.mysqli.inc, а сам файл делаем пустым.
Далее во всех трех файлах database.pgsql.inc, database.mysql.inc, database.mysqli.inc переименовываем все функции добавляя к их именам постфикс типа базы данных: в файле database.pgsql.inc - _pgsql; в файле database.mysql.inc - _mysql; в файле database.mysqli.inc - _mysqli. Переименовывать не надо только функцию db_check_setup - она уникальна для файла database.pgsql.inc.
Открываем файл database.inc и создаем там 41(!!!) функцию со следующими именами.
_db_create_field_sql()
_db_create_key_sql()
_db_create_keys_sql()
_db_process_field()
_db_process_field()
_db_query()
db_add_field()
db_add_index()
db_add_primary_key()
db_add_unique_key()
db_affected_rows()
db_change_field()
db_column_exists()
db_connect()
db_create_table_sql()
db_decode_blob()
db_distinct_field()
db_drop_field()
db_drop_index()
db_drop_primary_key()
db_drop_table()
db_drop_unique_key()
db_encode_blob()
db_error ()
db_escape_string()
db_fetch_array()
db_fetch_object()
db_field_set_default()
db_field_set_no_default()
db_last_insert_id()
db_lock_table()
db_query()
db_query_range()
db_query_temporary()
db_rename_table()
db_result()
db_status_report()
db_table_exists()
db_type_map()
db_unlock_tables()
db_version()
Все функции выглядят однотипно, различаясь только названием.
function имя
_функции () {
global $db_type;
$args =
func_get_args();
return
call_user_func_array("имя_функции_".$db_type, $args);
}
Несомненно, большой объем правок кода ядра может отпугнуть желающих использовать это. Есть еще один способ, требующий меньшего объема кода. Основная проблема в том, что в PHP обычно нет возможности удаления или переопределения (перегрузки) функций. Правда, одно из расширений PHP - Runkit позволяет сделать это. Если runkit подключен, то достаточно сделать небольшую вставку в код функции db_set_active(). Находим строчки:
$db_type =
substr($connect_url, 0,
strpos($connect_url, '://'));
$handler = "./includes/database.$db_type.inc";
if (
is_file($handler)) {
include_once $handler;
}
else {
_db_error_page("The database type '". $db_type ."' is unsupported. Please use either
'mysql' or 'mysqli' for MySQL, or 'pgsql' for PostgreSQL databases.");
}
$db_conns[$name] =
db_connect($connect_url);
}
и добавляем свой код:
$db_type =
substr($connect_url, 0,
strpos($connect_url, '://'));
$handler = "./includes/database.$db_type.inc";
if (
is_file($handler)) {
$fnames =
array(
'_db_create_field_sql', '_db_create_key_sql', '_db_create_keys_sql',
'_db_process_field', '_db_process_field', '_db_query',
'db_add_field', 'db_add_index', 'db_add_primary_key',
'db_add_unique_key', 'db_affected_rows', 'db_change_field',
'db_column_exists', 'db_connect', 'db_create_table_sql',
'db_decode_blob', 'db_distinct_field', 'db_drop_field',
'db_drop_index', 'db_drop_primary_key', 'db_drop_table',
'db_drop_unique_key', 'db_encode_blob', 'db_error',
'db_escape_string', 'db_fetch_array', 'db_fetch_object',
'db_field_set_default', 'db_field_set_no_default', 'db_last_insert_id',
'db_lock_table', 'db_query', 'db_query_range', 'db_query_temporary',
'db_rename_table', 'db_result', 'db_status_report',
'db_table_exists', 'db_type_map', 'db_unlock_tables', 'db_version',
);
foreach ($fnames as $fname) {
@runkit_function_remove($fname);
}
include $handler;
}
else {
_db_error_page("The database type '". $db_type ."' is unsupported. Please use either
'mysql' or 'mysqli' for MySQL, or 'pgsql' for PostgreSQL databases.");
}
$db_conns[$name] =
db_connect($connect_url);
}
В этом случае определения всех функций баз данных будут удалены, а при подключении файла другого типа БД определены заново.
Источники:
db_set_active()
runkit_function_remove()
2 соединения с БД
Переключение между базами