Переезд с Ucoz на Drupal. Шаг 1: перенос пользователей.

Главные вкладки

Аватар пользователя yar-web yar-web 3 августа 2009 в 14:02
1

Есть у меня сайт на Ucoz. Точнее, не у меня, но у хорошего знакомого. Я на этом сайте являюсь постоянным посетителем и администратором. Сайт довольно неплохо развивается, и тот факт, что он по большому счету не принадлежит создателям, в последнее время стал напрягать. Задумки перенести сайт на другую CMS появились уже давно, но вопрос – на какую и как – оставался актуальным. Видела предложения перенести на Joomla за $100, но такой подход меня как программиста не устраивает. Хочется разбираться в той системе, куда собираемся переезжать. Я уже было взялась разбираться с Джумлой, как появился очередной заказ на сайт на Друпале, и, выполнив его, я поняла – это же то, что мне нужно! Да, система сложна для новичка, и на первый достаточно простой сайт я потратила почти 3 месяца. Ядро было хакнуто не раз в порыве отчаяния понять API… Но после третьего сайта всё более-менее встало на свои места.

Поискав информацию по поводу производительности (т.к. она мне видится слабым местом Друпала), нашла некоторые сравнительные характеристики с Джумлой.
http://cpcs.ws/news/2009/04/03/cahephp-joomla-drupal
http://buytaert.net/drupal-vs-joomla-performance
http://buytaert.net/drupal-vs-joomla-hosting-costs
http://buytaert.net/cms-code-base-comparison
В общем, Друпал выглядит не так уж и плохо!

Ну что ж, приступим.

Для начала я поставила на localhost девственно чистый Drupal. Включила только модули Profile (он нам понадобится для данных пользователей) и Administration menu (для удобства администрирования сайта).

Готового решения (модуля) для импорта данных я не нашла, поэтому придется писать свой модуль. Но нашла модули для переезда с Джумлы, их я взяла на заметку при создании своего модуля.

Итак, первой задачей будет перенести пользователей.

Бэкап данных на Ucoz можно получить в виде текстовых файлов. Данные о пользователях хранятся в файле users.txt. Формат файла таков:

Admin|0|$1$EW9d$R/szWQXqeIcG/C5skBY90|http://******.ucoz.ru/avatar/53/435992.jpg|18|Евгений|1|admin@mail.ru|http://*****.ucoz.ru/||0|||Моя подпись|Admin|1190520411|195.112.227.234|0mysite||||0|1984-01-11|0||1192225866

Так выглядит одна строка с данными о пользователе. Поля разделены знаком «|». Значения полей следующие:

0. user
1. unetID
2. password
3. avatar
4. flags
5. fullname
6. gender
7. email
8. homepage
9. icq
10. country
11. state
12. city
13. signature
14. title
15. regdate
16. ip
17. old-field
18. aol
19. msn
20. yahoo
21. ispm
22. birthday
23. verify
24. options
25. lastmodified

Приступим к написанию модуля. Для этого в папке sites/all/ создадим папку modules (у меня она уже была создана, туда я сохранила модуль Administration menu перед его установкой), а в ней – папку ucoz. Создадим файл ucoz.info. Его содержимое:

; $Id$
name = Ucoz
description = "Ucoz2Drupal import module"
dependencies[] = profile
dependencies[] = taxonomy
core = 6.x

Следующий шаг – создание файла модуля ucoz.module.
Начинаем наш код описанием модуля

<?php
// $Id$

/**
 * file
 * The Ucoz module used for migrate Ucoz to Drupal.
 */

Определим права доступа

/**
 * Implementation of hook_perm().
 */

function ucoz_perm() {
        return array('administer ucoz');
}

Добавим пункты меню
admin/settings/ucoz – страница настроек модуля
admin/content/ucoz_import – страница импорта

/**
 * Menu callback. Prints a listing of active nodes on the site.
 */

function ucoz_menu() {
        $items = array();

        $items['admin/content/ucoz_import'] = array(
        'title' => 'Import from Ucoz',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('ucoz_import_form'),
        'access arguments' => array('administer ucoz'),
        'description' => 'Import content, categories and users from a Ucoz website',
        );

        $items['admin/settings/ucoz'] = array(
        'title' => 'Ucoz to Drupal',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('ucoz_admin_settings'),
        'access arguments' => array('administer ucoz'),
        'description' => 'Migrate Ucoz to Drupal.'
        );

        return $items;
}

Далее создадим форму настроек.
Добавим следующие настройки:

  • Тип переносимого контента (пока – только пользователи)
  • Обновлять ли ранее перенесенные данные
  • Название папки, в которой лежат файлы бэкапа
  • URL сайта, с которого делается импорт (он мне понадобится позже).
function ucoz_admin_settings() {

        // only administrators can access this function

        $weight = -20;

        // Generate the form - settings applying to all patterns first
        $form['ucoz_import_settings'] = array(
        '#type' => 'fieldset',
        '#weight' => $weight,
        '#title' => t('Import defaults'),
        '#collapsible' => FALSE,
        '#collapsed' => FALSE,
        '#description' => 'Set the default values for the '. l('Import from Ucoz', 'admin/content/ucoz_import') .' form',
        );

        $form['ucoz_import_settings'][] = ucoz_import_form_checkboxes();
        $weight++;

        $form['ucoz_settings_files'] = array(
        '#type' => 'fieldset',
        '#title' => t('Files settings'),
        '#collapsible' => TRUE,
        '#collapsed' => false
        );

        $form['ucoz_settings_files']['ucoz_path'] = array(
        '#type' => 'textfield',
        '#title' => 'Path of your Ucoz files',
        '#default_value' => variable_get('ucoz_path', UCOZ_PATH),
        '#description' => 'The path where you saved backup Ucoz files.');

        $form['ucoz_settings_files']['ucoz_live_url'] = array(
        '#type' => 'textfield',
        '#title' => 'URL of your Ucoz site',
        '#default_value' => variable_get('ucoz_live_url', UCOZ_LIVE_URL),
        '#description' => 'The URL of a live version of your Ucoz site'
        );

        return system_settings_form($form);
}

Поля (а точнее чекбоксы), которые будут повторяться также и в форме импорта, я вынесла в отдельную функцию ucoz_import_form_checkboxes

/**
 * These checkboxes are used on both the admin and import forms
 */

function ucoz_import_form_checkboxes(&$form_state = NULL) {

        $form['ucoz_import'] = array(
        '#type' => 'fieldset',
        '#title' => t('Items to import'),
        '#collapsible' => FALSE,
        '#collapsed' => FALSE,
        );

        $form['ucoz_import']['ucoz_import_users'] = array(
        '#type' => 'checkbox',
        '#title' => t('Import users'),
        '#default_value' => variable_get('ucoz_import_users', UCOZ_IMPORT_USERS),
        );

        $form['ucoz_update_duplicate'] = array(
        '#type' => 'checkbox',
        '#title' => t('Update previously imported items?'),
        '#description' => t('If selected, any items which have already been imported, and which have been updated on the Ucoz website, will be updated.'),
        '#default_value' => variable_get('ucoz_update_duplicate', UCOZ_UPDATE_DUPLICATE),
        );

        return $form;
}

Данные функции сгенерируют нужные нам элементы формы настроек и автоматически запомнят указанные пользователями значения.

Для сохранения исходных данных о пользователях (которые нам еще понадобятся в дальнейшем) создадим таблицу в базе данных, назовем ее ucoz_users. В нее занесем ID пользователя (uid), имя пользователя в базе Ucoz (ucoz_name) его пароль в формате Ucoz (password) и метку converted, которая будет показывать, был ли конвертирован пароль в формат Drupal (это произойдет при первой авторизации пользователя на новом сайте). Таблицу будем создавать при подключении модуля. Для этого создадим файл ucoz.install.

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

/**
 * Implementation of hook_schema().
 */

function ucoz_schema() {
  $schema['ucoz_users'] = array(
  'description' => 'Stores the original Ucoz user ID and password and links to the {users} table',
    'fields' => array(
      'uid' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'description' => "The users {users}.uid.",
      ),
      'ucoz_uid' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'description' => "The users id from the Ucoz database.",
      ),
      'password' => array(
        'type' => 'varchar',
        'length' => 100,
        'not null' => TRUE,
        'default' => '',
        'description' => "The users original Ucoz password.",
      ),
      'converted' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'description' => "Boolean value storing whether or not the users Ucoz password has been converted to an entry in the {users}.pass table.",
      ),
    ),
    'primary key' => array('uid'),
    'unique keys' => array(
      'ucoz_uid' => array('ucoz_uid'),
    ),
  );

  return $schema;
}

Функция ucoz_install() выполняется при первой активации модуля ucoz и читает схему, которую мы описали. Она переводит ее в SQL-код и создает нужные нам таблицы.

/**
 * Implementation of hook_install().
 */

function ucoz_install() {
  // Create tables.
  drupal_install_schema('ucoz');
}

Чтобы удалить ненужные таблицы при удалении модуля, используем функцию ucoz_uninstall(), которая будет удалять таблицы из БД и переменные, используемые модулем.

function ucoz_uninstall() {
        // Remove tables.
        drupal_uninstall_schema('ucoz');
}

Теперь попробуем включить наш модуль. Т.к. он уже был однажды запущен (проверка правильности создания), то его нужно переустановить. Сначала мы отключим модуль на странице Главная › Управление › Конструкция сайта, а затем удалим на вкладке Удалить. Drupal выдал ошибку, т.к. не смог удалить таблицу из базы данных – и это правильно, ведь таблица еще не была создана. Снова подключим наш модуль. Всё получилось, таблица в БД была создана.

Итак, пришло время для самой функции импорта.
Для переноса данных нам нужно прочитать файл users.txt, находящийся в указанной пользователем папке, распарсить его и занести полученные данные в БД.

Сначала проверим наличие нужного файла.

/**
 * Test whether a valid ucoz path has been configured
 */

function ucoz_path_test() {
        print file_directory_path().'/'.variable_get('ucoz_path', UCOZ_PATH).'/users.txt';

        if (!is_file(file_directory_path().'/'.variable_get('ucoz_path', UCOZ_PATH).'/users.txt')){
                return FALSE;
        }

        return TRUE;
}

Если файл users.txt не найден, то пользователю выдается текст ошибки и импорт не состоится.

function ucoz_import_users($ucoz_update_duplicate = NULL) {
        $ucoz_path = variable_get('ucoz_path', UCOZ_PATH);
        $file_handle = fopen(file_directory_path().'/'.variable_get('ucoz_path', UCOZ_PATH).'/users.txt', "r");

        while (!feof($file_handle)) {

                $line = fgets($file_handle);
                if (!empty($line)){
                        $data = explode('|',$line);
                        echo "<pre>";
                        print_r($data);
                        echo "</pre>";
                }
        }
}

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

function ucoz_import_users($ucoz_update_duplicate = NULL) {
        if ($ucoz_update_duplicate === NULL) {
                $ucoz_update_duplicate = variable_get('ucoz_update_duplicate', UCOZ_UPDATE_DUPLICATE);
        }

        $ucoz_path = variable_get('ucoz_path', UCOZ_PATH);
        $file_handle = fopen(file_directory_path().'/'.variable_get('ucoz_path', UCOZ_PATH).'/users.txt', "r");

        $users_total = 0;
        $users_updated = 0;
        $users_new = 0;
        $users_failed =  0;

        while (!feof($file_handle)) {
                $line = fgets($file_handle);
                if (!empty($line)){
                        $data = explode('|',$line);

                        // проверка, был ли такой пользователь импортирован ранее
                        $uid = db_result(db_query("SELECT uid FROM {ucoz_users} WHERE ucoz_name = '%s'", $data[0]));

                        // Нужно ли обновлять данные пользователя
                        if ($uid && !$ucoz_update_duplicate) {
                                continue;
                        }

                        // создание записи пользователя
                        $user = new stdClass();
                        if ($uid) {
                                $user->uid = $uid;
                        }
                        $user->name = $data[0];
                        $user->mail = $data[7];
                        $user->status = 1;
                        $user->created = $data[15];
                        $user->access = $data[25];

                        $res = FALSE;
                        // запись данных в БД
                        if ($uid) {
                                $res = drupal_write_record('users', $user, 'uid');
                        }elseif ($ucoz_update_duplicate) {
                                $res = drupal_write_record('users', $user);
                        }

                        if ($res) {
                                // если пользователь создан, записываем его данные во вспомогательную таблицу ucoz_users
                                $ucoz_user = new stdClass();
                                $ucoz_user->uid = $user->uid;
                                $ucoz_user->ucoz_name = $user->name;
                                $ucoz_user->password = $data[2];

                                // Был ли пароль конвертирован в формат Друпал
                                if (!empty($user->pass)) {
                                        $ucoz_user->converted = 1;
                                }
                                // запись данных в БД
                                if ($uid) {
                                        drupal_write_record('ucoz_users', $ucoz_user, 'uid');
                                }else {
                                        drupal_write_record('ucoz_users', $ucoz_user);
                                }

                                // подсчет статистики
                                switch ($res) {
                                        case SAVED_NEW:
                                        $users_new++;
                                        break;

                                        case SAVED_UPDATED;
                                        $users_updated++;
                                        break;

                                        default:
                                        $users_failed++;
                                        break;
                                }

                        }
                }
        }
        drupal_set_message(t('Processed users_total users (users_new new, users_updated updated, users_failed errors)', array('users_total' => $users_total, 'users_new' => $users_new, 'users_updated' => $users_updated, 'users_failed' => $users_failed)));
}

Запускаем импорт данных.

Обработано 281 пользователей, 0 обновлений, 0 ошибок. Отлично. Наши пользователи в базе (можно проверить, пройдя на страницу Управление › Управление пользователями). Но перенеслись только самые основные данные о пользователе, а у нас есть еще много дополнительных.

Дополнительные поля для пользователей позволяет добавлять модуль Profile. Добавим поле Realname к профилю пользователя

//Add Realname to Profile
if (db_result(db_query("SELECT COUNT(*) FROM {profile_fields} WHERE name='profile_realname'")) == 0) {
                db_query(" INSERT INTO {profile_fields} (title,name,type,weight,visibility,category) VALUES ('Real Name','profile_realname','textfield','0','2','Личные данные')");
        }
        $results_fid_realname = db_query("SELECT fid from {profile_fields} WHERE name='profile_realname'");
        $data_fid_realname = db_fetch_object($results_fid_realname);
        $fid_realname = $data_fid_realname->fid;

В функции ucoz_import_users для каждого пользователя заполним это поле.

//Check and Update Realname
$profile_value = new stdClass();
$profile_value->fid = $fid_realname;
$profile_value->uid = $user->uid;
$profile_value->value = $data[5];

if ($uid) {
        drupal_write_record('profile_values', $profile_value, array('fid', 'uid'));
}
else {
        drupal_write_record('profile_values', $profile_value);
}

То же самое сделаем с полями пол, город, web-сайт, ICQ, AOL, MSN и Yahoo. Эти поля могут иметь другое название и назначение на сайте Ucoz. На сайте Друпал мы также сможем их переименовать и настроить.

Ах, да, у пользователей же еще есть аватары!

if (!empty($data[3])){
        $new_file = file_directory_path().'/'.variable_get('user_picture_path', 'pictures') .'/picture-'.$uid.'.'.substr(strrchr($data[3], '.'), 1);
        // Удаление старого аватара
        if (file_exists($new_file)) {
                file_delete($new_file);
        }
        //echo '<img src="'.$data[3].'"><br>';
        if ($avatar=file_get_contents($data[3])){
                file_put_contents($new_file,$avatar);
                $user->picture = $new_file;
        }
}

Данный код я вставила перед сохранением объекта $user. Он собирает изображения (аватары) и сохраняет их на наш сервер, а также записывает в базу данные об аватаре. К сожалению, мне удалось таким образом скопировать лишь часть аватаров пользователей (вида http://src.ucoz.net/a/02/1298.jpg). Остальные выдали ошибку

warning: file_get_contents(http://****.ucoz.ru/avatar/53/435992.jpg) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden in ***\www\sites\all\modules\ucoz\ucoz.module on line 267.

Обидно, конечно, но не смертельно. Что-нибудь придумаем.

Осталась самая малость – конвертация паролей. Скажу честно, взяла функции с модуля Joomla, только изменила метод проверки пароля.

function ucoz_form_alter(&$form, $form_state, $form_id) {
        if ($form_id == 'user_login' || $form_id == 'user_login_block') {
                if (isset($form_state['post']['name'])) {
                        $last_validator = array_pop($form['#validate']);
                        $form['#validate'][] = 'ucoz_login_validate';
                        $form['#validate'][] = $last_validator;
                }
        }
}

function ucoz_login_validate($form, &$form_state) {
        ucoz_authenticate($form_state['values']);
}

function ucoz_authenticate($form_values = array()) {
        global $user;

        if (!empty($user->uid)) {
                // Пользователь уже авторизован
                return;
        }

        if (form_get_errors() || empty($form_values['name']) || empty($form_values['pass'])) {
                // Проверка правильности введенных данных
                return;
        }

        $account = user_load(array('name' => $form_values['name'], 'status' => 1));
        // Пользовтель не существует
        if (!$account) {
                return;
        }

        // Ищем запись пользователя в таблице ucoz_user
        $ucoz_user = db_fetch_object(db_query("SELECT * FROM {ucoz_users} WHERE converted=%s and uid = %d", 0, $account->uid));
        if (!$ucoz_user) {
                return;
        }

        // Проверяем правильность введенного пароля
        $hash = $ucoz_user->password;
        preg_match('/(\$1\$[^\$]+)/',$hash,$salt);
        $salt = $salt[0];
        if ($hash == crypt($form_values['pass'],$salt)) {
                $user = $account;
                watchdog('ucoz', 'Converting password for user name (Ucoz id juid)', array('name' => $user->name, 'juid' => $ucoz_user->juid));

                // Обновляем пароль пользователя Drupal
                user_save($user, array('pass' => $form_values['pass']));

                $ucoz_user->converted = 1;
                drupal_write_record('ucoz_users', $ucoz_user, array('uid'));

                user_authenticate_finalize($form_values);
                return $user;
        }
}

Попробовала зайти под своим пользователем в системе ucoz – авторизация прошла успешно. Пароль добавился в таблицу users. Задача успешно выполнена. Правда, остались еще роли пользователей, но думаю, к этому я вернусь уже позже. Следующая задача – перенос материалов сайта.

ВложениеРазмер
Иконка пакета ucoz.zip4.91 КБ

Комментарии

Аватар пользователя run run 3 августа 2009 в 15:56

Хорошо, буду ждать продолжения. Там наверное содержание и таксономию нужно будет перенести Wink

Аватар пользователя marazmus marazmus 4 августа 2009 в 8:07

Супер, спасибо большое за такую подробную и качественную статью!

p.s. Если найти мейнтейнеров, можно оформить в виде модуля и запулить на drupal.org Smile

Аватар пользователя yar-web yar-web 4 августа 2009 в 8:15

"Химический Али" wrote:
Вас сейчас на Юкозе забанят.

На самом форуме тех. поддержки Ucoz активно обсуждалась тема переносов на другие движки, и никого не банили за это.

"marazmus" wrote:
можно оформить в виде модуля и запулить на drupal.org :)

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

Аватар пользователя gn@drupal.org gn@drupal.org 4 августа 2009 в 10:23

Наработки есть на drupal.org - модули по импорту содержания и юзеров из чужих таблиц, не привязанные к формату конкретных CMS, например
Content and User Import and Export Modules:

а также модули для импорта из конкретных систем - Joomla, Wordpress, Typepad, Phorum, phpbb2 и т.д.

Аватар пользователя gn@drupal.org gn@drupal.org 4 августа 2009 в 11:19

"Химический Али" wrote:
Юкоз не отдает таблицы. Только текстовый дамп в своем формате.

Да, я вижу. Поэтому можно специально затачивать модуль под работу с "текстовыми дампами в формате Ucoz", а можно, наверное, сделать перекодировщик из Ucoz text dump в CSV или какой-то другой стандартный формат, и дальше использовать то, что с этим форматом могут сделать модули более общего назначения.

Аватар пользователя yar-web yar-web 4 августа 2009 в 14:32

Можно и так конечно, только все равно придется делать всю ту же самую работу по разбору-структуризации данных, плюс разбираться со всеми этими модулями и подпиливать напильничком, если что работает не так, как хочется. Дописывать всё равно придется. А так будет уже готовое решение, в котором я могу сразу учесть все нюансы.

Модуль импорта из Джумлы очень помог при написании. Сегодня сделала импорт оставшихся аватаров и новостей/блогов.

Аватар пользователя yar-web yar-web 18 сентября 2009 в 13:54

"<a href="mailto:gn@drupal.org">gn@drupal.org</a>" wrote:
Most women in open source, after they've done or said some geeky thing, hear, "wow will you marry me?"

по-английски плохо понимаю Sad

"mamba" wrote:
развожусь с женой и женюсь на Анне. Эх, жаль не Краснодарская она ))

Аватар пользователя kudrjashv kudrjashv 28 декабря 2009 в 21:53

Здравствуйте, помогите мне, пожалуйста, кто разбирается в php. Пробую конвертировать дамп блога юкоза в таблицу со статьями в базе данных joomla.
Дамп распарсивается, массив создается, все хорошо.
Можно как-то теперь записывать элементы массива в базу данных без drupal_write_record?

В общем, я распарсил blog.txt (дамп записей блога) в массив $data, как по инструкции написано, затем создал таблицу для jos_content (в ней хранятся статьи), как теперь нужный элемент массива вставить в нужное поле таблицы?

Вот начало моего кода:

<?php
$file_handle = fopen('http://localhost/convert/blog.txt', 'r'); //парсится дамп блога и создается массив

while (!feof($file_handle)) {

$line = fgets($file_handle);
if (!empty($line)){
$data = explode('|',$line);
echo '

';
			print_r($data);
			echo '

';
}
}
//подключаемся к базе данных Joomla:

$host='localhost'; // имя хоста (уточняется у провайдера)
$database='joomla'; // имя базы данных, которую вы должны создать
$user='joomla'; // заданное вами имя пользователя, либо определенное провайдером
$pswd='*********'; // заданный вами пароль

$dbh = mysql_connect($host, $user, $pswd) or die("Не могу соединиться с MySQL.");
mysql_select_db($database) or die("Не могу подключиться к базе.");

//создаем таблицу jos_content:

$query = "CREATE TABLE `jos_content` (
`id` int(11) unsigned NOT NULL auto_increment,
`title` varchar(255) NOT NULL default '',
`alias` varchar(255) NOT NULL default '',
`title_alias` varchar(255) NOT NULL default '',
`introtext` mediumtext NOT NULL,
`fulltext` mediumtext NOT NULL,
`state` tinyint(3) NOT NULL default '0',
`sectionid` int(11) unsigned NOT NULL default '0',
`mask` int(11) unsigned NOT NULL default '0',
`catid` int(11) unsigned NOT NULL default '0',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`created_by` int(11) unsigned NOT NULL default '0',
`created_by_alias` varchar(255) NOT NULL default '',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
`modified_by` int(11) unsigned NOT NULL default '0',
`checked_out` int(11) unsigned NOT NULL default '0',
`checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00',
`publish_up` datetime NOT NULL default '0000-00-00 00:00:00',
`publish_down` datetime NOT NULL default '0000-00-00 00:00:00',
`images` text NOT NULL,
`urls` text NOT NULL,
`attribs` text NOT NULL,
`version` int(11) unsigned NOT NULL default '1',
`parentid` int(11) unsigned NOT NULL default '0',
`ordering` int(11) NOT NULL default '0',
`metakey` text NOT NULL,
`metadesc` text NOT NULL,
`access` int(11) unsigned NOT NULL default '0',
`hits` int(11) unsigned NOT NULL default '0',
`metadata` text NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_section` (`sectionid`),
KEY `idx_access` (`access`),
KEY `idx_checkout` (`checked_out`),
KEY `idx_state` (`state`),
KEY `idx_catid` (`catid`),
KEY `idx_createdby` (`created_by`)
) ENGINE=MyISAM AUTO_INCREMENT=112 DEFAULT CHARSET=utf8 AUTO_INCREMENT=112 ;" ;
$result = mysql_query($query);

$query2 = "INSERT INTO `jos_content` VALUES (СЮДА, НАДО, ВСТАВИТЬ, ЭЛЕМЕНТЫ, МАССИВА, $data, В, НУЖНОМ, ПОРЯДКЕ, ЧЕРЕЗ, ЗАПЯТУЮ)";
\\И нужно еще как-то цикл использовать, наверно что бы перебрать все имеющиеся значения элемента массива с нужным ключом?

?>

В php - полный профан, но видно, что истина где то рядом, помогите кто может программить, только если можно по- понятнее.

Аватар пользователя kudrjashv kudrjashv 30 декабря 2009 в 18:36

В общем то с этим разобрался, код у меня получается такой:

<?php

 
$host

='localhost'// имя хоста (уточняется у провайдера)
$database='joomla2'// имя базы данных, которую вы должны создать
$user='joomla2'// заданное вами имя пользователя, либо определенное провайдером
$pswd='s8dfg31564gf'// заданный вами пароль
 
$dbh mysql_connect($host$user$pswd) or die("Не могу соединиться с MySQL.");
mysql_select_db($database) or die("Не могу подключиться к базе.");
    
$query "CREATE TABLE `jos_content` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `title` varchar(255) NOT NULL default '',
  `alias` varchar(255) NOT NULL default '',
  `title_alias` varchar(255) NOT NULL default '',
  `introtext` mediumtext NOT NULL,
  `fulltext` mediumtext NOT NULL,
  `state` tinyint(3) NOT NULL default '0',
  `sectionid` int(11) unsigned NOT NULL default '0',
  `mask` int(11) unsigned NOT NULL default '0',
  `catid` int(11) unsigned NOT NULL default '0',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_by` int(11) unsigned NOT NULL default '0',
  `created_by_alias` varchar(255) NOT NULL default '',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified_by` int(11) unsigned NOT NULL default '0',
  `checked_out` int(11) unsigned NOT NULL default '0',
  `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00',
  `publish_up` datetime NOT NULL default '0000-00-00 00:00:00',
  `publish_down` datetime NOT NULL default '0000-00-00 00:00:00',
  `images` text NOT NULL,
  `urls` text NOT NULL,
  `attribs` text NOT NULL,
  `version` int(11) unsigned NOT NULL default '1',
  `parentid` int(11) unsigned NOT NULL default '0',
  `ordering` int(11) NOT NULL default '0',
  `metakey` text NOT NULL,
  `metadesc` text NOT NULL,
  `access` int(11) unsigned NOT NULL default '0',
  `hits` int(11) unsigned NOT NULL default '0',
  `metadata` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `idx_section` (`sectionid`),
  KEY `idx_access` (`access`),
  KEY `idx_checkout` (`checked_out`),
  KEY `idx_state` (`state`),
  KEY `idx_catid` (`catid`),
  KEY `idx_createdby` (`created_by`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;" 
;
$result mysql_query($query);

    

$file_handle fopen('http://localhost/convert/blog.txt''r');
 
    while (!
feof($file_handle)) {
 
        
$line fgets($file_handle);
        
        if (!empty(
$line)){
            
$data explode('|',$line);
            echo 
'<pre>';
            
print_r($data);
            echo 
'</pre>';
            
        }
        
$sql "INSERT INTO `jos_content` VALUES ( '', '$data[11]', '$data[2]-$data[3]-$data[4]-$data[0]', '', '$data[13]', '', 1, 1, 0, 1, '2009-12-08 14:30:38', 62, '', '2009-12-10 16:51:32', 62, 0, '0000-00-00 00:00:00', '2009-12-08 14:30:38', '0000-00-00 00:00:00', '', '', 'show_title=\nlink_titles=\nshow_intro=\nshow_section=\nlink_section=\nshow_category=\nlink_category=\nshow_vote=\nshow_author=\nshow_create_date=\nshow_modify_date=\nshow_pdf_icon=\nshow_print_icon=\nshow_email_icon=\nlanguage=\nkeyref=\nreadmore=', 10, 0, 0, '', '', 0, 8, 'robots=\nauthor=' ); " ;
$result mysql_query($sql);
    }

?>

все работает, но теперь обнаружилась еще некоторые проблемки :

1) иногда в файле бэкапа ucoz данные записываются не в одну строку, а в несколько, поэтому конвертация сбивается. К примеру вот разные текстовые файлы бэкапа блога.

Пример1:
1|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
2|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
3|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546

При таком виде текста все будет работать правильно, но если будет так:

Пример2:
1|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
2|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста
с переводами строк, не позволяет обработать бэкап правильно, тут как то нужно привести к одной строке|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
3|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546

- то все собьется
Как убрать эти переводы строк, что бы записи были в одну строку, как в первом примере?

2) Проблемы с кодировкой. Текстовый файл в utf-8 (проверено в notepad++), таблица создается то же в utf-8, даже положил в папку со скриптом .htaccess и прописал в нем php_value mbstring.internal_encoding "utf-8" и AddDefaultCharset utf-8 (где-то вычитал об этом на форумах), НО если смотреть в phpmyadmin`е таблицу jos_content - русские буквы выглядят кракозябрами, выбрав в браузере кодировку utf-8 все становится вокруг кракозябрами, но в таблице русские буквы отображаются. Когда смотришь сайт с импортированными статьями - они все кракозябры и выбор кодировок не помогает.

Подмогните, интересно стало, надо дописать конвертер. Злые люди переносят сайты на ucoz`е за 100 баксов.

Аватар пользователя kudrjashv kudrjashv 30 декабря 2009 в 22:28

Друпал.ру никак не относится к джумле.
Просто тема о переносе сайта с ucoz только здесь немножко раскрыта. Я не собираюсь переносить за $50 никому сайты, и код скрипта я выкладываю, который хочу написать.
В друпале - смысл переноса тот же, что и в джумле и других кмс, я думаю. Просто другие отличаются названия и поля в таблицах базы данных.
Про перенос статей или блога у уважаемой yar-web пока не написана инструкция, поэтому мои комментарии, думаю, тут уместны. Можно конечно убрать упоминания о джумле, ведь мне нужен лишь код преобразования бэкапа из вида:

1|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
2|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста
с переводами строк, не позволяет обработать бэкап правильно, тут как то нужно привести к одной строке|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
3|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546

к виду:
1|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
2|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546
3|3|2006|7|27|0|0|1|1153993546|0|имя_польз|название поста||Текст поста|1|0`0`0|196|0.00|0|0|||||||2|0|1153993546

И решить проблему с кодировкой.

После этого (или, если надо - перед этим) могу скрипт и для друпала переписать ради такого дела.
А так извените конечно, если с джумлой в сообщество друпал.ру лезу. Но по существу вопросов может кто-нибуть ответить?

Аватар пользователя yar-web yar-web 31 декабря 2009 в 7:20

Вот мой кусочек кода для преноса блога

while (!feof($file_handle)) {
                // в тексте могут находиться переносы строк, поэтому если строка заканчивается знаком '\', мы его обрезаем, а строку соединяем со следующей.
                $line = $s.fgets($file_handle);
                if (substr($line,strlen($line)-2,1)=='\\'){
                        $s = substr($line,0,strlen($line)-3);
                        continue;
                }else{
                        $s='';
                }
                if (!empty($line)){
                        $data = explode('|',$line);
...
Аватар пользователя kudrjashv kudrjashv 31 декабря 2009 в 15:04

Как я рад, что появилась yar-web!
Но с этим кодом пока не выходит. Остаются переносы и \, вот что мне выводит в браузере:

<?php
Array
(
    [
0] => 3
    
[1] => 0
    
[2] => 2008
    
[3] => 10
    
[4] => 9
    
[5] => 0
    
[6] => 0
    
[7] => 1
    
[8] => 1223574372
    
[9] => 0
    
[10] => starfeed
    
[11] => Первая заметка в Звездном фиде.
    [
12] => 
    [
13] => Вот и первая заметка в Блоге о звездных блогах. \

)
Array
(
    [

0] => Желаю ему стремительного роста посещаемостимногочисленных пользователей и одобрения со стороны звезд.
    [
1] => 0
    
[2] => 82823.gif
    
[3] => 1504
    
[4] => 5.00
    
[5] => 1
    
[6] => 5
    
[7] => 92.101.69.240
    
[8] => 
    [
9] => 
    [
10] => 
    [
11] => 
    [
12] => 
    [
13] => 1
    
[14] => 0
    
[15] => 
    [
16] => 1223574372?>

Это я только то место привел, где обрыв строки.
Код у меня такой с вашим участком (кстати я сделал кодировку, теперь ОК 6-):


 <?php

 
$host

='localhost'// имя хоста (уточняется у провайдера)
$database='joomla2'// имя базы данных, которую вы должны создать
$user='joomla2'// заданное вами имя пользователя, либо определенное провайдером
$pswd='sanya0210'// заданный вами пароль
 
$dbh mysql_connect($host$user$pswd) or die("Не могу соединиться с MySQL.");
mysql_select_db($database) or die("Не могу подключиться к базе.");
mysql_query("SET NAMES 'utf8'");
    
$query "CREATE TABLE `jos_content` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `title` varchar(255) NOT NULL default '',
  `alias` varchar(255) NOT NULL default '',
  `title_alias` varchar(255) NOT NULL default '',
  `introtext` mediumtext NOT NULL,
  `fulltext` mediumtext NOT NULL,
  `state` tinyint(3) NOT NULL default '0',
  `sectionid` int(11) unsigned NOT NULL default '0',
  `mask` int(11) unsigned NOT NULL default '0',
  `catid` int(11) unsigned NOT NULL default '0',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_by` int(11) unsigned NOT NULL default '0',
  `created_by_alias` varchar(255) NOT NULL default '',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified_by` int(11) unsigned NOT NULL default '0',
  `checked_out` int(11) unsigned NOT NULL default '0',
  `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00',
  `publish_up` datetime NOT NULL default '0000-00-00 00:00:00',
  `publish_down` datetime NOT NULL default '0000-00-00 00:00:00',
  `images` text NOT NULL,
  `urls` text NOT NULL,
  `attribs` text NOT NULL,
  `version` int(11) unsigned NOT NULL default '1',
  `parentid` int(11) unsigned NOT NULL default '0',
  `ordering` int(11) NOT NULL default '0',
  `metakey` text NOT NULL,
  `metadesc` text NOT NULL,
  `access` int(11) unsigned NOT NULL default '0',
  `hits` int(11) unsigned NOT NULL default '0',
  `metadata` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `idx_section` (`sectionid`),
  KEY `idx_access` (`access`),
  KEY `idx_checkout` (`checked_out`),
  KEY `idx_state` (`state`),
  KEY `idx_catid` (`catid`),
  KEY `idx_createdby` (`created_by`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;" 
;
$result mysql_query($query);

    

$file_handle fopen('http://localhost/convert/blog.txt''r');
 
    while (!
feof($file_handle)) {
        
// в тексте могут находиться переносы строк, поэтому если строка заканчивается знаком '\', мы его обрезаем, а строку соединяем со следующей.
        
$line $s.fgets($file_handle);
        if (
substr($line,strlen($line)-2,1)=='\\n'){
            
$s substr($line,0,strlen($line)-3);
            continue;
        }else{
            
$s='';
        }
        if (!empty(
$line)){
            
$data explode('|',$line);
            echo 
'<pre>';
            
print_r($data);
            echo 
'</pre>';
        }
        
        
mysql_query("SET NAMES 'utf8'");
        
mysql_query("INSERT INTO `jos_content` VALUES ( '', '$data[11]', '$data[2]-$data[3]-$data[4]-$data[0]', '', '$data[13]', '', 1, 1, 0, 1, '2009-12-08 14:30:38', 62, '', '2009-12-10 16:51:32', 62, 0, '0000-00-00 00:00:00', '2009-12-08 14:30:38', '0000-00-00 00:00:00', '', '', 'show_title=\nlink_titles=\nshow_intro=\nshow_section=\nlink_section=\nshow_category=\nlink_category=\nshow_vote=\nshow_author=\nshow_create_date=\nshow_modify_date=\nshow_pdf_icon=\nshow_print_icon=\nshow_email_icon=\nlanguage=\nkeyref=\nreadmore=', 10, 0, 0, '', '', 0, 8, 'robots=\nauthor=' ); ");
    }
?>
Аватар пользователя kudrjashv kudrjashv 31 декабря 2009 в 18:13

Ну это я попробовал еще и так. Так, как вы написали я то же пробовал - результат тот же. Скажите, а у вас получается удалять переносы строк?

Аватар пользователя kudrjashv kudrjashv 31 декабря 2009 в 18:10

Ура! Поигрался со значениями, вот так получается правильно:

<?php
if (substr($line,strlen($line)-3,1)=='\\')
?>

Интересно, почему тогда у вас получалось с

<?php
if (substr($line,strlen($line)-2,1)=='\\')
?>

Или тут нужен индивидуальный подход к бэкапу :-)?

Аватар пользователя kudrjashv kudrjashv 31 декабря 2009 в 19:10

Рано порадовался, большинство постов перенеслось правильно, но нашлось парочка, которые опять все сбили.
Как я понял в постах блога может быть не просто символ переноса '\' а еще и '\'с пробелом. К тому же нужно не просто обрезать '\' и строку соединять со следующей, а заменять '\' тегом <br /> и соединять со следующей. Иначе в постах исчезнут нужные переносы строк. Или я не прав?

Аватар пользователя kudrjashv kudrjashv 10 ноября 2015 в 11:46

Прикрепляю текстовый файл записей блога.
Весь дамп целиком выкладывать не буду - он большой, в нем много всяких папок и файлов (видео, картинки, аудио файлы.
Играйтесь на здоровье!

Аватар пользователя fernand fernand 12 августа 2010 в 19:53

Девушка-программист, да ещё какой программист Smile
Кстати, юкоз нередко модифицируется, так что скрипт переноса без постоянной поддержки устареет

Аватар пользователя RomanovDF RomanovDF 10 ноября 2015 в 11:47

Заморочен переносом форума с Ucoz на Drupal. Никто не занимался подобным делом? Если кому нужно выкладываю скрипты для переноса на DLE (те за которые деньги берут).

Аватар пользователя zhivcheg zhivcheg 14 октября 2011 в 8:50

никак не могу понять как вы проверили правильность ввода пароля. Функция crypt() всегда генерит разный хеш если не указана соль. А откуда берете соль в вашем модуле никак разобратья не могу. Помогите пожалуйста.

Аватар пользователя Viola Viola 27 октября 2011 в 18:05

"zhivcheg" wrote:
никак не могу понять как вы проверили правильность ввода пароля. Функция crypt() всегда генерит разный хеш если не указана соль. А откуда берете соль в вашем модуле никак разобратья не могу. Помогите пожалуйста.

Так из уже зашифрованного пароля и берется.

<?php$hash = $ucoz_user->password;
    preg_match('/(\$1\$[^\$]+)/',$hash,$salt);
    $salt = $salt[0];?>

В данном случае используется MD5, поэтому с помощью регулярного выражения ищется соответствующая строка, которая помещается в нулевой элемент массива $salt.

И я могу с полной уверенностью утверждать, что код работает, т.к. я сама использую его на своем сайте, благополучно перенесенном с юкоза на друпал почти без потерь. Wink

Аватар пользователя taecelle taecelle 3 декабря 2011 в 16:26

Добрый день.
Попыталась воспользоваться вышим модулем переноса пользователей с Юкоза. Правда, у меня друпал 7.
Модуль встал нормально, я подправила код, чтобы пункты меню отображались в Конфигурации, исправила отсутствующий в 7 версии друпала file_directory_path() на другой код. Ошибок никаких вроде нет, функция ucoz_admin_settings работает нормально. Я ввожу адрес сайта на юкозе и папку, куда сбросила бекап. Но когда я пытаюсь перейти к импорту, у меня ничего нет. Сам пункт в меню работает, но когда я нажимаю его - ничего не открывается. Пустое место и по-прежнему никаких сообщений об ошибках.
Подскажите пожалуйста, что может быть неправильно?

Аватар пользователя taecelle taecelle 3 декабря 2011 в 19:28

Дамп (я не очень в этом сильна...)? Что это?
Мне интересно по какой причине может не работать конкретно эта функция 'ucoz_import_settings'?
Если бы она работала, но с ошибками, эти ошибки как-то отобразились. Увы, я очень мало что знаю об отличиях друпала 7 от 6. Где-то там зарыта собака....

Аватар пользователя taecelle taecelle 3 декабря 2011 в 22:30

Добилась того, что выводится сообщение об ошибке (ну типа "Измените настройки доступа к файлам бекапа". При этом сколько я их не меняю (как бы ни задавала папку, куда слила файлы) нифига не выходит((
Подозреваю, в ucoz.module надо теперь иначе указывать путь к файлу. Вот только как?

Аватар пользователя Viola Viola 7 декабря 2011 в 18:18

Для начала, разберитесь в отличиях между file_directory_path() и "другим кодом", на который вы его заменили. И выведите путь, который вы пытаетесь передать - верный ли он, и если нет, что в чем ошибка?

Аватар пользователя Viola Viola 7 декабря 2011 в 18:27

Чем вы заменили file_directory_path()? Если conf_path(), то нужно прицепить еще директорию с файлами:

<?php
$files_path 
conf_path() . "/files";
?>

Либо

<?php
variable_get
('file_public_path');
?>
Аватар пользователя alons alons 4 апреля 2012 в 15:32

Большое человеческое спасибо, модуль очень полезен, сэкономлено куча времени, работает прекрасно Smile