Сейчас веду работы по переносу сайта с древней Joomla 1.5 (уже несколько раз пахабно взломанной) на MODX Revolution с соблюдением всех мер безопасности.
Провёл эксперимент по импортированию содержимого старого сайта не путём написания php скрипта, работающего через процессоры, а напрямую манипулируя БД MySQL в phpMyAdmin.
Эксперимент удался: новые записи в БД MODX Revo принял как родные объекты.
Дано: бекап сайта на Joomla (дамп базы данных и архив с файлами)
Задача: переносим весь сайт на MODX последней версии
Так как исходный сайт на Joomla был взломан многократно (факт), и хакерские шеллы могут лежать абсолютно где угодно, то из файлового архива я буду брать только картинки, причём только те, в которых записаны реально картинки.
Текстовые документы в Joomla хранятся в базе данных MySQL, так же как и в MODX Revo, поэтому я подумал, что можно попробовать произвести импорт нативными (родными) средствами СУБД. О чём собственно и повествует данная статья.
Последовательность действий
- На сервере с новым создаваемым сайтом создаём вторую пустую базу данных и импортируем в неё дамп старого Joomla-сайта.
- В БД нового сайта создаём на время таблицу идентичную по структуре таблице modx_site_content, но без ключей.
- Путём сопоставления записей одной CMS и другой копируем содержимое из БД старого сайта в БД нового сайта, в нашу временную таблицу.
- Просматриваем всю временную таблицу, чистим по возможности от мусора.
- Делаем бекап и полностью очищаем таблицу modx_site_content. Сбрасываем счётчик auto_increment в 1.
- Копируем содержимое из временной таблицы в девственно чистую таблицу modx_site_content. (дабы не было конфликтов с дублированием записей с уникальными ключами, а ключей в modx_site_content очень много...)
На этом собственно всё. Можно на всякий пожарный почистить кэш сайта. Из всех перечисленных действий самый сложные - шаги №№ 2,3. Поэтому разберём некоторые из шагов более детально.
По шагам
шаг 2)
Создаём временную таблицу идентичную modx_site_content. "Временная" у меня чисто условно, я не стал использовать ключ TEMPORARY, чтобы иметь возможность просматривать результирующее содержимое.
CREATE TABLE `content` LIKE `modx_site_content`;
Создастся пустая таблица полностью повторяющая структуру образца.
Далее во вкладке Структура новой таблицы, нужно домотать страницу до раздела Индексы и удалить все ключи в этой таблице (с помощью красных крестиков). Ключ PRIMARY не будет удаляться, пока вы не отмените свойство auto_increment у столбца id.
Должно получится так:
шаг 3)
Затем начинаем копировать содержимое из старой базы - в новую, прописывая соответствие полей.
Следующий код копирует секции (родительские каталоги). Соответствие следующее: "значение" as "имя столбца в таблице modx_site_content", причём значение мы либо берём из старой таблицы, либо указываем своё статичное значение в одинарных кавычках.
INSERT INTO `db_new_site`.`content` ( SELECT `id` as id, 'document' as type, 'text/html' as contentType, title as pagetitle, '' as longtitle, '' as description, alias as alias, '' as link_attributes, '1' as published, '0' as pub_date, '0' as unpub_date, '0' as parent, '0' as isfolder, '' as introtext, '' as content, '1' as richtext, '1' as template, `id` as menuindex, '1' as searchable, '1' as cacheable, '1' as createdby, '1396331126' as createdon, '1' as editedby, '1396331304' as editedon, '0' as deleted, '0' as deletedon, '0' as deletedby, '0' as publishedon, '0' as publishedby, '' as menutitle, '0' as donthit, '0' as privateweb, '0' as privatemgr, '0' as content_dispo, '0' as hidemenu, 'modDocument' as class_key, 'web' as context_key, '1' as content_type, '' as uri, '0' as uri_override, '0' as hide_children_in_tree, '1' as show_in_tree, NULL as properties FROM `db_old_site`.`jos_sections` as j )
Следующий код копирует сами текстовые материалы. Соответствие следующее: "значение" as "имя столбца в таблице modx_site_content". Причём id я решил присвоить в своём порядке, для этого добавил переменную @a. А так как разделы мы уже внесли и часть id уже занята, то нужно сделать отступ, указав в @a = id последней внесённой записи предыдущим запросом. В этом запросе нужно обратить внимание на соответствие id родителей (parent) идентификаторам секций, которые мы добавляли во временную таблицу предыдущим запросом.
set @a = 20; INSERT INTO `db_new_site`.`content` (SELECT @a:=@a+1 as id, 'document' as type, 'text/html' as contentType, title as pagetitle, '' as longtitle, metadesc as description, alias as alias, '' as link_attributes, '1' as published, '0' as pub_date, '0' as unpub_date, sectionid as parent, '0' as isfolder, `introtext` as introtext, `fulltext` as content, '1' as richtext, '1' as template, @a as menuindex, '1' as searchable, '1' as cacheable, '1' as createdby, '1396331126' as createdon, '1' as editedby, '1396331304' as editedon, '0' as deleted, '0' as deletedon, '0' as deletedby, '0' as publishedon, '0' as publishedby, '' as menutitle, '0' as donthit, '0' as privateweb, '0' as privatemgr, '0' as content_dispo, '0' as hidemenu, 'modDocument' as class_key, 'web' as context_key, '1' as content_type, '' as uri, '0' as uri_override, '0' as hide_children_in_tree, '1' as show_in_tree, NULL as properties FROM `db_old_site`.`jos_content` as j )
шаг 4)
Самостоятельно проверьте получившуюся таблицу, чтобы всё было нормально
шаг 5)
Сделайте бекап таблицы modx_site_content (в phpMyAdmin вкладка экспорт) и опустошите её и сбросьте счётчик auto_index:
TRUNCATE TABLE `modx_site_content`; ALTER TABLE `modx_site_content` AUTO_INCREMENT = 0;
шаг 6)
Последний шаг: из временной таблицы копируем всё содержимое в рабочую таблицу.
INSERT INTO `modx_site_content` (SELECT * FROM `content`);
Этих действий достаточно, для того чтобы скопировать содержимое из Joomla в MODX. Это возможно благодаря тому, что по сути строка в БД - это сериализованый объект API MODX. Прямое добавление строки в базу данных, приводит к появлению самого обычного объекта в системе. За это - спасибо моделям и схемам.