Статьи

Пользовательские таблицы базы данных: импорт данных

В последнем уроке мы рассмотрели экспорт данных из пользовательской таблицы. Конечно, это только половина дела — нам, очевидно, необходимо предоставить способ импорта этих данных. Естественно, WordPress не справляется с этим — поэтому нам еще раз нужно развернуть свою собственную.

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

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


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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class WPTuts_Log_Export_Admin_Page {
 
    /**
     * The page hook suffix
     */
    static $hook_suffix=»;
 
    static function load() {
        add_action( ‘admin_menu’, array( __CLASS__, ‘add_submenu’ ) );
        add_action( ‘admin_init’, array( __CLASS__, ‘maybe_download’ ) );
        add_action( ‘admin_init’, array( __CLASS__, ‘maybe_upload’ ) );
        add_action( ‘admin_notices’,array( __CLASS__, ‘admin_notices’ ) );
    }
 
    static function add_submenu() {
        /* Defined in previous article */
    }
 
    static function maybe_download() {
        /* Defined in previous article */
    }
 
    static function display() {
        /* Defined in previous article — but we’ll make some modifications */
    }
 
    static function maybe_upload() {
 
    }
 
    static function admin_notices() {
 
    }
 
    static function import() {
 
    }
 
    static function parse() {
 
    }
}
WPTuts_Log_Export_Admin_Page::load();

Выше мы добавили следующие методы

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

Но сначала мы добавим форму, с помощью которой мы можем загрузить файл. Мы добавим это ниже кнопки экспорта, которую мы создали в предыдущей статье. Для этого нам нужно внести некоторые изменения в метод display() , отвечающий за создание разметки нашей страницы администратора. Так как эта вторая форма отправит файл, нам нужно установить тип кодирования ‘ multipart/form-data ‘.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
static function display() {
 
    echo ‘<div class=»wrap»>’;
    screen_icon();
    echo ‘<h2>’ .
    ?>
 
    <form id=»wptuts-export-log-form» method=»post» action=»»>
        <p>
            <label><?php _e( ‘Click to export the activity logs’,’wptuts-log’ );
            <input type=»hidden» name=»action» value=»export-logs» />
        </p>
        <?php wp_nonce_field( ‘wptuts-export-logs’, ‘_wplnonce’ );
        <?php submit_button( __( ‘Download Activity Logs’, ‘wptuts-log’ ), ‘button’ );
    </form>
 
    <form method=»post» action=»» enctype=»multipart/form-data»>
        <p>
            <label for=»wptuts_import_logs»><?php _e( ‘Import an .xml file.’, ‘wptuts-log’ );
            <input type=»file» id=»wptuts_import_logs» name=»wptuts_import» />
        </p>
        <input type=»hidden» name=»action» value=»import-logs» />
        <?php wp_nonce_field( ‘wptuts-import-logs’, ‘_wplnonce’ );
        <?php submit_button( __( ‘Upload Activity Logs’, ‘wptuts-log’ ), ‘secondary’ );
    </form>
    <?php
}
?>

Далее мы хотим прослушать, когда вышеприведенная форма отправлена, и запустить процедуру импорта. Перед этим важно выполнить несколько проверок:

  • Есть ли у пользователя разрешение на загрузку файлов? Здесь мы предоставили возможность загрузки только тем, кто может manage_options .
  • Намерен ли пользователь загрузить файлы (мы проверяем это, проверяя одноразовый номер )
  • Был ли файл действительно загружен? И это было правильного типа
  • Были ли ошибки в загрузке?

При желании вы можете установить ограничение на размер загружаемого файла в качестве «проверки работоспособности». В этом примере я ограничил его в 2 МБ. (Полезная функция для форматирования размеров файла «удобочитаемым способом» — это функция size_format ).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
static function maybe_upload() {
    /* Listen for form submission */
    if ( empty( $_POST[‘action’] ) || ‘import-logs’ !== $_POST[‘action’] )
        return;
 
    /* Check permissions and nonces */
    if ( ! current_user_can( ‘manage_options’ ) )
        wp_die(»);
 
    check_admin_referer( ‘wptuts-import-logs’, ‘_wplnonce’ );
 
    /* Perform checks on file: */
 
    // Sanity check
    if ( empty( $_FILES[«wptuts_import»] ) )
        wp_die( ‘No file found’ );
 
    $file = $_FILES[«wptuts_import»];
 
    // Is it of the expected type?
    if ( $file[«type»] != «text/xml» )
        wp_die( sprintf( __( «There was an error importing the logs. File type detected: ‘%s’. ‘text/xml’ expected», ‘wptuts-log’ ), $file[‘type’] ) );
 
    // Impose a limit on the size of the uploaded file.
    if ( $file[«size»] > 2097152 ) {
        $size = size_format( $file[‘size’], 2 );
        wp_die( sprintf( __( ‘File size too large (%s). Maximum 2MB’, ‘import-logs’ ), $size ) );
    }
 
    if( $file[«error»] > 0 )
        wp_die( sprintf( __( «Error encountered: %d», ‘wptuts-import’ ), $file[«error»] ) );
  
    /* If we’ve made it this far then we can import the data */
    $imported = self::import( $file[‘tmp_name’] );
 
    /* Everything is complete, now redirect back to the page */
    wp_redirect( add_query_arg( ‘imported’, $imported ) );
    exit();
}

Далее нам нужно импортировать файл. Сначала нам нужно извлечь журналы из загруженного файла — и мы передадим это задание методу parse() (мы немного дойдем до этого метода).

Получив эти журналы, мы сначала проверим, существуют ли они (чтобы избежать случайного дублирования), прежде чем вставлять их. При проверке логов мы просто проверяем идентификатор пользователя и дату активности. Мы могли бы, если захотим, быть более строгими (проверка активности, идентификатора объекта и типа и т. Д.), Но нам нужно было бы вернуться и расширить наш API (в частности, wptuts_get_logs() ).

После того, как мы импортировали журналы, мы перенаправили пользователя обратно на нашу страницу администратора. Мы добавим переменную запроса к URL-адресу ( imported ) для хранения количества импортированных журналов (если есть). Таким образом, мы можем отобразить соответствующее сообщение администратора.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function import( $file ) {
 
    // Parse file
    $logs = self::parse( $file );
 
    // No logs found ?
    if ( ! $logs )
        return 0;
 
    // Initialises a variable storing the number of logs successfully imported.
    $imported = 0;
 
    // Go through each log
    foreach ( $logs as $log_id => $log ) {
        /*
         * Check if the log already exists:
         * We’ll just check the date and the user ID, but we could check other details
         * if we extended our wptuts_get_logs() API
         */
        $exists = wptuts_get_logs( array(
            ‘user_id’ => $log[‘user_id’],
            ‘since’ => mysql2date( ‘G’, $log[‘activity_date’], false ),
            ‘until’ => mysql2date( ‘G’, $log[‘activity_date’], false ),
        ));
 
        // If it exists, don’t import it
        if ( $exists )
            continue;
 
        // Insert the log
        $successful = wptuts_insert_log( array(
            ‘user_id’=> $log[‘user_id’],
            ‘date’ => mysql2date( ‘G’, $log[‘activity_date’], false ),
            ‘object_id’ => $log[‘object_id’],
            ‘object_type’ => $log[‘object_type’],
            ‘activity’ => $log[‘activity’],
            ‘activity_date’ => $log[‘activity_date’],
        ));
 
        if ( $successful )
            $imported++;
    }
 
    return $imported;
}

Нам все еще нужно определить метод parse() который, учитывая загруженный файл, должен извлекать данные и возвращать их в виде массива логов. К счастью, с помощью встроенного в PHP обработчика XML это довольно простая задача.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function parse( $file ) {
    // Load the xml file
    $xml = simplexml_load_file( $file );
 
    // halt if loading produces an error
    if ( ! $xml )
        return false;
 
    // Initial logs array
    $logs = array();
    foreach ( $xml->xpath( ‘/logs/item’ ) as $log_obj ) {
 
        $log = $log_obj->children( );
        $log_id = (int) $log->log_id;
 
        $logs[$log_id] = array(
            ‘user_id’ => (int) $log->user_id,
            ‘object_id’ => (int) $log->object_id,
            ‘object_type’ => (string) $log->object_type,
            ‘activty’ => (string) $log->activity,
            ‘activity_date’ =>(string) $log->activity_date,
        );
    }
 
    return $logs;
}

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
function admin_notices() {
 
    // Was an import attempted and are we on the correct admin page?
    if ( ! isset( $_GET[‘imported’] ) || ‘tools_page_wptuts-export’ !== get_current_screen()->id )
        return;
 
    $imported = intval( $_GET[‘imported’] );
 
    if ( 1 == $imported ) {
        printf( ‘<div class=»updated»><p>%s</p></div>’, __( ‘1 log successfully imported’, ‘wptuts-import’ ) );
 
    }
    elseif ( intval( $_GET[‘imported’] ) ) {
        printf( ‘<div class=»updated»><p>%s</p></div>’, sprintf( __( ‘%d logs successfully imported’, ‘wptuts-import’ ), $imported ) );
    }
    else {
        printf( ‘<div class=»error»><p>%s</p></div>’, __( ‘ No logs were imported’, ‘wptuts-import’ ) );
    }
}