WordPress. Загрузка файлов. Часть 1 из 3

31.07.2019

Теги: CMSPOSTWeb-разработкаWordPressФайлФорма

В WordPress есть множество функций, предназначенных для загрузки файлов. Сразу разобраться в них трудно — названия похожие и функционал часто дублируется. Рассмотрим последовательно все функции и попробуем загрузить файлы на сервер сначала в панели управления, а потом и в публичной части сайта. Для этого создадим плагин и будем его постепенно изменять, чтобы рассмотреть все возможности WordPress по загрузке файлов.

Загрузка файлов в панели управления

Простая загрузка одного файла

На первом этапе плагин просто загружает файл в соответствующую поддиректорию (year/month) директории /wp-content/uploads. Запись в таблицу базы данных wp_posts при этом не добавляется, т.е. этот файл не является вложением и недоступен для просмотра в библиотеке медиафайлов. Всю работу по загрузке файла выполняет функция wp_handle_upload(), которая является оберткой для нативной php-функции move_uploaded_file().

<?php
/*
 * Plugin name: Загрузка файлов
 * Description: Пример загрузки файлов в панели управления
 */

/*
 * Добавляем страницу плагина в панели управления
 */
add_action('admin_menu', function () {
    add_menu_page(
        // содержимое тега title этой страницы
        'Загрузка файлов',
        // название пункта меню для этой страницы
        'Загрузка файлов',
        // права доступа, чтобы был показан этот пункт меню
        'upload_files',
        // уникальный идентификатор меню (страницы)
        'tokmakov_upload_page',
        // функция выводит содержимое этой страницы
        function () {
            ?>
            <div class="wrap">
                <h1>Загрузка файлов</h1>
                <p>
                    Плагин позволяет загружать файлы в директорию <code>/wp-content/uploads</code>.
                    Обратите внимание, что загружаются только файлы, это не вложения (attachments).
                    Записи в таблицу <code>wp_posts</code> не добавляются, поэтому в библиотеке
                    медиафайлов эти файлы будут не видны.
                </p>
                <?php if (isset($_SESSION['tokmakov_upload_file'])): ?>
                    <p><?= $_SESSION['tokmakov_upload_file']; ?></p>
                    <?php unset($_SESSION['tokmakov_upload_file']); ?>
                <?php endif; ?>
                <?php
                $action = admin_url('admin-post.php');
                $redirect = $_SERVER['REQUEST_URI'];
                ?>
                <form action="<?= $action; ?>" method="post" enctype="multipart/form-data">
                    <?php wp_nonce_field('tokmakov_upload_file'); ?>
                    <input type="hidden" name="action" value="tokmakov_upload_file" />
                    <input type="hidden" name="redirect" value="<?= $redirect ?>" />
                    <input type="file" name="tokmakov_upload_file" required />
                    <input type="submit" value="Загрузить файл" />
                </form>
            </div>
            <?php
        },
        // иконка для страницы настроек плагина
        'dashicons-upload',
        // позиция страницы, в конце списка
        90
    );
});

/*
 * Запускаем сессию, чтобы передавать сообщение о результате
 * обработки файла после перезагрузки страницы
 */
add_action('init', function () {
    if (session_id() == '') {
        session_start();
    }
});

/*
 * Обрабатываем отправленные данные формы
 */
add_action('admin_post_tokmakov_upload_file', function () {
    // проверяем защиту nonce и права пользователя
    $check1 = wp_verify_nonce(
        $_POST['_wpnonce'],
        'tokmakov_upload_file'
    );
    $check2 = current_user_can('upload_files');
    ob_start();
    if ($check1 && $check2) {
        // проверка пройдена, можно загружать файл
        $overrides = ['test_form' => false];
        $result = wp_handle_upload(
            $_FILES['tokmakov_upload_file'],
            $overrides
        );
        // показываем результаты загрузки файла
        if (isset($result['error'])) {
            echo 'Ошибка при загрузке файла';
        } else {
            echo 'Файл был успешно загружен';
        }
    } else {
        echo 'Проверка не пройдена, файл не загружен';
    }
    $_SESSION['tokmakov_upload_file'] = ob_get_clean();
    // после отправки формы делаем редирект, чтобы предотвратить
    // повторную отправку, если пользователь обновит страницу
    $redirect = home_url();
    if (isset($_POST['redirect'])) {
        $redirect = $_POST['redirect'];
        $redirect = wp_validate_redirect($redirect, home_url());
    }
    wp_redirect($redirect);
    die();
});

Массив $_FILES, который содержит всю информацию о загруженном файле:

Array (
    [tokmakov_upload_file] => Array (
            [name] => sunrise.jpg
            [type] => image/jpeg
            [tmp_name] => D:\work\temp\phpED8F.tmp
            [error] => 0
            [size] => 490815
        )
)

И массив, который возвращает функция wp_handle_upload() в случае успешной загрузки файла:

Array
(
    [file] => D:/work/localhost24/www/wp-content/uploads/2019/08/sunrise.jpg
    [url] => http://www.host24.ru/wp-content/uploads/2019/08/sunrise.jpg
    [type] => image/jpeg
)

Если файл не был загружен, функция возвращает сообщение об ошибке:

Array
(
    [error] => Извините, этот тип файла недопустим по соображениям безопасности.
)

Загрузка одного вложения (attachment)

Хорошо, файл загружать мы умеем, посмотрим, как теперь из файла сделать вложение. Для этого достаточно указать функции media_handle_upload() ключ массива $_FILES, который содержит данные о загружаемом файле. И функция сама загрузит файл в директорию uploads и создаст запись о вложении в таблице wp_posts в базе данных.

<?php
/*
 * Plugin name: Загрузка файлов
 * Description: Пример загрузки файлов в панели управления
 */

/*
 * Добавляем страницу плагина в панели управления
 */
add_action('admin_menu', function () {
    add_menu_page(
    // содержимое тега title этой страницы
        'Загрузка файлов',
        // название пункта меню для этой страницы
        'Загрузка файлов',
        // права доступа, чтобы был показан этот пункт меню
        'upload_files',
        // уникальный идентификатор меню (страницы)
        'tokmakov_upload_page',
        // функция выводит содержимое этой страницы
        function () {
            ?>
            <div class="wrap">
                <h1>Загрузка файлов</h1>
                <p>
                    Плагин позволяет загружать файлы в директорию <code>/wp-content/uploads</code>.
                    При этом создаются записи в таблице БД <code>wp_posts</code>, то есть эти файлы
                    являются вложениями и доступны для просмотра в библиотеке медиафайлов.
                </p>
                <?php if (isset($_SESSION['tokmakov_upload_file'])): ?>
                    <p><?= $_SESSION['tokmakov_upload_file']; ?></p>
                    <?php unset($_SESSION['tokmakov_upload_file']); ?>
                <?php endif; ?>
                <?php
                $action = admin_url('admin-post.php');
                $redirect = $_SERVER['REQUEST_URI'];
                ?>
                <form action="<?= $action; ?>" method="post" enctype="multipart/form-data">
                    <?php wp_nonce_field('tokmakov_upload_file'); ?>
                    <input type="hidden" name="action" value="tokmakov_upload_file" />
                    <input type="hidden" name="redirect" value="<?= $redirect ?>" />
                    <input type="file" name="tokmakov_upload_file" required />
                    <input type="submit" value="Загрузить файл" />
                </form>
            </div>
            <?php
        },
        // иконка для страницы настроек плагина
        'dashicons-upload',
        // позиция страницы, в конце списка
        90
    );
});

/*
 * Запускаем сессию, чтобы передавать сообщение о результате
 * обработки файла после перезагрузки страницы
 */
add_action('init', function () {
    if (session_id() == '') {
        session_start();
    }
});

/*
 * Обрабатываем отправленные данные формы
 */
add_action('admin_post_tokmakov_upload_file', function () {
    // проверяем защиту nonce и права пользователя
    $check1 = wp_verify_nonce(
        $_POST['_wpnonce'],
        'tokmakov_upload_file'
    );
    $check2 = current_user_can('upload_files');
    ob_start();
    if ($check1 && $check2) {
        // проверка пройдена, можно загружать файл
        $result = media_handle_upload('tokmakov_upload_file', 0);
        if (is_wp_error($result)) {
            echo 'Ошибка при загрузке файла', PHP_EOL;
        } else {
            echo 'Файл был успешно загружен', PHP_EOL;
        }
    } else {
        echo 'Проверка не пройдена, файл не загружен';
    }
    $_SESSION['tokmakov_upload_file'] = ob_get_clean();
    // после отправки формы делаем редирект, чтобы предотвратить
    // повторную отправку, если пользователь обновит страницу
    $redirect = home_url();
    if (isset($_POST['redirect'])) {
        $redirect = $_POST['redirect'];
        $redirect = wp_validate_redirect($redirect, home_url());
    }
    wp_redirect($redirect);
    die();
});

Простая загрузка нескольких файлов

Давайте теперь загрузим несколько файлов. Для этого добавим атрибут multiple для элемента формы и будем «скармливать» функции wp_handle_upload() по одному загруженному файлу за раз:

<?php
/*
 * Plugin name: Загрузка файлов
 * Description: Пример загрузки файлов в панели управления
 */

/*
 * Добавляем страницу плагина в панели управления
 */
add_action('admin_menu', function () {
    add_menu_page(
    // содержимое тега title этой страницы
        'Загрузка файлов',
        // название пункта меню для этой страницы
        'Загрузка файлов',
        // права доступа, чтобы был показан этот пункт меню
        'upload_files',
        // уникальный идентификатор меню (страницы)
        'tokmakov_upload_page',
        // функция выводит содержимое этой страницы
        function () {
            ?>
            <div class="wrap">
                <h1>Загрузка файлов</h1>
                <p>
                    Плагин позволяет загружать файлы в директорию <code>/wp-content/uploads</code>.
                    Обратите внимание, что загружаются только файлы, это не вложения (attachments).
                    Записи в таблицу <code>wp_posts</code> не добавляются, поэтому в библиотеке
                    медиафайлов эти файлы будут не видны.
                </p>
                <?php if (isset($_SESSION['tokmakov_upload_file'])): ?>
                    <ul>
                    <?php foreach ($_SESSION['tokmakov_upload_file'] as $message): ?>
                        <li><?= $message; ?></li>
                    <?php endforeach; ?>
                    </ul>
                    <?php unset($_SESSION['tokmakov_upload_file']); ?>
                <?php endif; ?>
                <?php
                $action = admin_url('admin-post.php');
                $redirect = $_SERVER['REQUEST_URI'];
                ?>
                <form action="<?= $action; ?>" method="post" enctype="multipart/form-data">
                    <?php wp_nonce_field('tokmakov_upload_file'); ?>
                    <input type="hidden" name="action" value="tokmakov_upload_file" />
                    <input type="hidden" name="redirect" value="<?= $redirect ?>" />
                    <input type="file" name="tokmakov_upload_file[]" multiple required />
                    <input type="submit" value="Загрузить файлы" />
                </form>
            </div>
            <?php
        },
        // иконка для страницы настроек плагина
        'dashicons-upload',
        // позиция страницы, в конце списка
        90
    );
});

/*
 * Запускаем сессию, чтобы передавать сообщение о результате
 * обработки файла после перезагрузки страницы
 */
add_action('init', function () {
    if (session_id() == '') {
        session_start();
    }
});

/*
 * Обрабатываем отправленные данные формы
 */
add_action('admin_post_tokmakov_upload_file', function () {
    // проверяем защиту nonce и права пользователя
    $check1 = wp_verify_nonce(
        $_POST['_wpnonce'],
        'tokmakov_upload_file'
    );
    $check2 = current_user_can('upload_files');
    if ($check1 && $check2) {
        // перебираем все файлы в цикле и загружаем по одному
        $messages = [];
        $overrides = ['test_form' => false];
        foreach ($_FILES['tokmakov_upload_file']['name'] as $i => $v) {
            $file = [
                'name' => $_FILES['tokmakov_upload_file']['name'][$i],
                'type' => $_FILES['tokmakov_upload_file']['type'][$i],
                'tmp_name' => $_FILES['tokmakov_upload_file']['tmp_name'][$i],
                'error' => $_FILES['tokmakov_upload_file']['error'][$i],
                'size' => $_FILES['tokmakov_upload_file']['size'][$i],
            ];
            // загружаем очередной файл в директорию uploads
            $result = wp_handle_upload($file, $overrides);
            // показываем результаты загрузки очередного файла
            if (isset($result['error'])) {
                $messages[] = 'Ошибка при загрузке файла ' . $file['name'];
            } else {
                $messages[] = 'Файл ' . $file['name'] . ' успешно загружен';
            }
        }
    } else {
        $messages[] = 'Проверка не пройдена, файлы не загружены';
    }
    $_SESSION['tokmakov_upload_file'] = $messages;
    // после отправки формы делаем редирект, чтобы предотвратить
    // повторную отправку, если пользователь обновит страницу
    $redirect = home_url();
    if (isset($_POST['redirect'])) {
        $redirect = $_POST['redirect'];
        $redirect = wp_validate_redirect($redirect, home_url());
    }
    wp_redirect($redirect);
    die();
});

Массив $_FILES, который содержит всю информацию о загруженных файлах:

Array (
    [tokmakov_upload_file] => Array (
            [name] => Array (
                    [0] => sunrise-1.jpg
                    [1] => sunrise-2.jpg
                    [2] => sunrise-3.jpg
                )
            [type] => Array (
                    [0] => image/jpeg
                    [1] => image/jpeg
                    [2] => image/jpeg
                )
            [tmp_name] => Array (
                    [0] => D:\work\temp\phpC9BC.tmp
                    [1] => D:\work\temp\phpC9CC.tmp
                    [2] => D:\work\temp\phpC9CD.tmp
                )
            [error] => Array (
                    [0] => 0
                    [1] => 0
                    [2] => 0
                )
            [size] => Array (
                    [0] => 490815
                    [1] => 161294
                    [2] => 207875
                )
        )
)

Загрузка нескольких вложений (attachments)

Использовать, как и раньше, функцию media_handle_upload() уже не получится. Она работает напрямую с массивом $_FILES и в качестве первого аргумента требует индекс массива, который содержит информацию о файле. При этом функция не умеет работать с несколькими файлами. Здесь нам на помощь придет функция media_handle_sideload(). Будем перебирать все загруженные файлы в цикле и «скармливать» функции media_handle_sideload() по одному.

<?php
/*
 * Plugin name: Загрузка файлов
 * Description: Пример загрузки файлов в панели управления
 */

/*
 * Добавляем страницу плагина в панели управления
 */
add_action('admin_menu', function () {
    add_menu_page(
    // содержимое тега title этой страницы
        'Загрузка файлов',
        // название пункта меню для этой страницы
        'Загрузка файлов',
        // права доступа, чтобы был показан этот пункт меню
        'upload_files',
        // уникальный идентификатор меню (страницы)
        'tokmakov_upload_page',
        // функция выводит содержимое этой страницы
        function () {
            ?>
            <div class="wrap">
                <h1>Загрузка файлов</h1>
                <p>
                    Плагин позволяет загружать файлы в директорию <code>/wp-content/uploads</code>.
                    При этом создаются записи в таблице БД <code>wp_posts</code>, то есть эти файлы
                    являются вложениями и доступны для просмотра в библиотеке медиафайлов.
                </p>
                <?php if (isset($_SESSION['tokmakov_upload_file'])): ?>
                    <ul>
                    <?php foreach ($_SESSION['tokmakov_upload_file'] as $message): ?>
                        <li><?= $message; ?></li>
                    <?php endforeach; ?>
                    </ul>
                    <?php unset($_SESSION['tokmakov_upload_file']); ?>
                <?php endif; ?>
                <?php
                $action = admin_url('admin-post.php');
                $redirect = $_SERVER['REQUEST_URI'];
                ?>
                <form action="<?= $action; ?>" method="post" enctype="multipart/form-data">
                    <?php wp_nonce_field('tokmakov_upload_file'); ?>
                    <input type="hidden" name="action" value="tokmakov_upload_file" />
                    <input type="hidden" name="redirect" value="<?= $redirect ?>" />
                    <input type="file" name="tokmakov_upload_file[]" multiple required />
                    <input type="submit" value="Загрузить файлы" />
                </form>
            </div>
            <?php
        },
        // иконка для страницы настроек плагина
        'dashicons-upload',
        // позиция страницы, в конце списка
        90
    );
});

/*
 * Запускаем сессию, чтобы передавать сообщение о результате
 * обработки файла после перезагрузки страницы
 */
add_action('init', function () {
    if (session_id() == '') {
        session_start();
    }
});

/*
 * Обрабатываем отправленные данные формы
 */
add_action('admin_post_tokmakov_upload_file', function () {
    // проверяем защиту nonce и права пользователя
    $check1 = wp_verify_nonce(
        $_POST['_wpnonce'],
        'tokmakov_upload_file'
    );
    $check2 = current_user_can('upload_files');
    if ($check1 && $check2) {
        // перебираем все файлы в цикле и загружаем по одному
        $messages = [];
        foreach ($_FILES['tokmakov_upload_file']['name'] as $i => $v) {
            $file = [
                'name' => $_FILES['tokmakov_upload_file']['name'][$i],
                'type' => $_FILES['tokmakov_upload_file']['type'][$i],
                'tmp_name' => $_FILES['tokmakov_upload_file']['tmp_name'][$i],
                'error' => $_FILES['tokmakov_upload_file']['error'][$i],
                'size' => $_FILES['tokmakov_upload_file']['size'][$i],
            ];
            // загружаем очередной файл в директорию uploads
            $result = media_handle_sideload($file, 0);
            // показываем результаты загрузки очередного файла
            if (is_wp_error($result)) {
                $messages[] = 'Ошибка при загрузке файла ' . $file['name'];
            } else {
                $messages[] = 'Файл ' . $file['name'] . ' успешно загружен';
            }
        }
    } else {
        $messages[] = 'Проверка не пройдена, файлы не загружены';
    }
    $_SESSION['tokmakov_upload_file'] = $messages;
    // после отправки формы делаем редирект, чтобы предотвратить
    // повторную отправку, если пользователь обновит страницу
    $redirect = home_url();
    if (isset($_POST['redirect'])) {
        $redirect = $_POST['redirect'];
        $redirect = wp_validate_redirect($redirect, home_url());
    }
    wp_redirect($redirect);
    die();
});

В случае ошибки при загрузке файла функция media_handle_sideload() возвращает объект

WP_Error Object (
    [errors] => Array (
            [upload_error] => Array
                (
                    [0] => Извините, этот тип файла недопустим по соображениям безопасности.
                )
        )
    [error_data] => Array ()
)

Если файл загружен успешно, функция возвращает идентификатор вложения.

Поиск: Web-разработка • WordPress • Файл • Форма • Загрузка • Upload • File • wp_handle_upload • media_handle_upload • CMS • POST

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.