Как загрузить изображение с помощью простой формы?

5 мая 2013 г., 13:48:15
Просмотры: 33.5K
Голосов: 4

Я разрабатываю плагин для страницы профиля и хочу создать возможность загрузки через кнопку 'Обзор' и поле 'Директория', которые будут загружать и возвращать URL изображения. При этом я не хочу использовать media-upload.

Я читал Установка изображения записи через форму на фронтенде, но я не понимаю код. Помогите решить эту проблему?

0
Все ответы на вопрос 3
2

Существует несколько частей.

Вам нужно добавить атрибут enctype в форму профиля.

function edit_form_type_wpse_98375() {
    echo ' enctype="multipart/form-data"';
}
add_action('user_edit_form_tag','edit_form_type_wpse_98375');

Затем добавить поле в форму.

function user_fields_wpse_98375($profileuser) {
  $_profile_photo = get_user_meta($profileuser->data->ID,'_profile_photo',true);

  echo '<h3>'.__('Дополнительные данные пользователя',THEME_TEXTDOMAIN).'</h3>';
    echo '<tr class="show-admin-bar">';
      echo '<th scope="row">'.__('Фото профиля', THEME_TEXTDOMAIN).'</th>';
      echo '<td'.$tspan.'>';
        echo '<fieldset>';
          echo '<legend class="screen-reader-text"><span>'.__('Фото профиля', THEME_TEXTDOMAIN).'</span></legend>';
          echo '<label for="profile_photo">';
            echo '<input name="profile_photo" type="file" id="profile_photo" value="" />';
          echo '</label><br />';
        echo '</fieldset>';
      echo '</td>';
    echo '</tr>';
  echo '</table>';
}
add_action('show_user_profile', 'user_fields_wpse_98375');
add_action('edit_user_profile', 'user_fields_wpse_98375');

И затем сохранить данные.

function save_user_custom($id=false) {
  global $_FILES,$_POST;
  if (false === $id) return false;

  // сохраняем изображение
  if (isset($_FILES)) {
    if (isset($_FILES['profile_photo'])){
      if (0 === $_FILES['profile_photo']['error']) {
        // Здесь вы сохраняете файл
        // Можно использовать wp_handle_upload
        // Или Filesystem API
        // не уверен, что именно вы хотите сделать
      }
    }
    unset($up);
  }
}
add_action('personal_options_update','save_user_custom');
add_action('edit_user_profile_update','save_user_custom');

wp_handle_upload вероятно самый простой вариант. Из Codex:

if ( ! function_exists( 'wp_handle_upload' ) ) 
    require_once( ABSPATH . 'wp-admin/includes/file.php' );
$uploadedfile = $_FILES['file'];
$upload_overrides = array( 'test_form' => false );
$movefile = wp_handle_upload( $uploadedfile, $upload_overrides );
if ( $movefile ) {
    echo "Файл корректен и был успешно загружен.\n";
    var_dump( $movefile);
} else {
    echo "Возможная атака при загрузке файла!\n";
}

Поле ввода типа file работает (в основном) как любое другое поле формы. Если вы дадите ему имя вроде my_uploads['profile_photo'] вместо просто profile_photo, вы получите массив. Это отразится в переменной $_FILES при обработке отправки формы. Вы можете добавить столько полей file, сколько захотите, создавая этот массив или просто давая им разные имена. Что касается динамического добавления полей file, это довольно простая задача для JavaScript.

Ссылки

http://codex.wordpress.org/Function_Reference/wp_handle_upload
http://codex.wordpress.org/Filesystem_API

5 мая 2013 г. 16:36:21
Комментарии

Спасибо s_ha_dum ^_^ и вот пример, который мне действительно нужен http://i165.photobucket.com/albums/u56/zectdropper/Capture_zpsea5fdfc7.png Пояснение -> поле загрузки может добавлять или удалять больше одного файла. Я думаю, они должны сохраняться как массив. Как я могу записать и сохранить их в WordPress?

Monogot Monogot
5 мая 2013 г. 17:12:01

И если вам нужно тестировать ошибки, вы можете использовать этот хук: user_profile_update_errors

JMau JMau
5 мая 2013 г. 18:06:28
1

Я предполагаю, что вы не очень опытны в работе с PHP и загрузкой файлов. Поэтому начну с основ и закончу простым классом.

Если вы еще не читали основы загрузки файлов с помощью PHP, сделайте это сейчас. Никто не будет объяснять это здесь, это не по теме.

Начнем с базовой HTML формы:

if( empty( $_FILES ) ) {
global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- Тип кодирования данных enctype ДОЛЖЕН быть указан как ниже -->
<form enctype="multipart/form-data" action="<?php echo $url; ?>" method="POST">
    <!-- MAX_FILE_SIZE должен предшествовать полю ввода файла -->
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    <!-- Имя элемента input определяет имя в массиве $_FILES -->
    Отправить этот файл: <input name="userfile" type="file" />
    <input type="submit" value="Отправить файл" />
</form>
<?php
} else {
    $imageupload = new File_Upload();
    $attachment_id = $imageupload->create_attachment();
    var_dump( $attachment_id );
}

Это довольно просто. Если суперглобальный массив $_FILES пуст, это значит, что файл не был загружен — отображаем форму загрузки. Если он не пуст — обрабатываем загрузку. Я использую admin_url() и переменную $pagenow для создания URL действия. Если вы используете форму загрузки на фронтенде, вам нужно использовать home_url() или что-то подобное.

После отправки файла через HTML вам нужно обработать загруженные файлы. Это будет сделано в классе File_Upload.

class File_Upload
{
    /**
     * Ключ индекса из формы загрузки
     * @var string
     */
    public $index_key = '';

    /**
     * Копия суперглобального массива $_FILES
     * @var array
     */
    public $files = array();

    /**
     * Конструктор
     * Настраивает массив файлов и угадывает ключ индекса
     */
    public function __construct(){

        if ( isset( $_FILES ) && ! empty( $_FILES ) ) {
            $this->files = $_FILES;
            $this->guess_index_key();
        }

    }

    /**
     * Устанавливает/перезаписывает ключ индекса
     * Преобразует $name с приведением типа (string)
     *
     * @param   string  $name   Имя ключа индекса
     * @return  string  ::name  Имя сохраненного ключа индекса
     */
    public function set_field_name_for_file( $name = '' ) {
        $this->index_key = ( ! empty( $name ) ) ? (string) $name : '';
        return $this->index_key;
    }

    /**
     * Преобразует загруженный файл в вложение WordPress
     *
     * @return  boolean     Был ли создан вложение (true) или нет (false)
     */
    public function create_attachment(){

        // перемещаем загруженный файл из временной папки и создаем базовые данные
        $imagedata = $this->handle_uploaded_file();

        // если перемещение не удалось, останавливаемся здесь
        /*
         * Для продакшена
         * Установите и верните объект ошибки с WP_Error()
         */
        if ( empty( $imagedata ) )
            return false;

        /*
         * Для продакшена
         * Проверьте, содержит ли $imagedata ожидаемые (и необходимые)
         * значения. Каждый метод может завершиться неудачей и вернуть вредоносные данные!!
         */
        $filename = $imagedata['filename'];

        // создаем массив данных вложения
        $attachment = array(
                'guid'           => $imagedata['url'] . '/' . $filename,
                'post_mime_type' => $imagedata['type'],
                'post_title'     => preg_replace('/\.[^.]+$/', '', $filename ),
                'post_content'   => '',
                'post_status'    => 'inherit'
        );

        // вставляем вложение (тип записи attachment)
        $attach_id = wp_insert_attachment( $attachment, $filename );

        // сначала нужно подключить файл image.php
        // для работы функции wp_generate_attachment_metadata()
        require_once( ABSPATH . 'wp-admin/includes/image.php' );

        /*
         * Для продакшена
         * Проверьте $attach_data, wp_generate_attachment_metadata() может завершиться неудачей
         * Проверьте, если wp_update_attachment_metadata() завершится неудачей (вернет false),
         * верните объект ошибки с WP_Error()
         */
        $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
        wp_update_attachment_metadata( $attach_id, $attach_data );

        return $attach_id;

    }

    /**
     * Обрабатывает загрузку
     *
     * @return  array   $return_data    Массив с информацией о загруженном файле
     */
    protected function handle_uploaded_file() {

        // получаем базовые данные
        $return_data = wp_upload_dir();

        // получаем временный путь к файлу и имя файла из $_FILES ($this->files)
        $tmp_file = ( isset( $this->files[$this->index_key] ) && ! empty( $this->files[$this->index_key] ) ) ?
            (string) $this->files[$this->index_key]['tmp_name'] : '';

        $tmp_name = ( isset( $this->files[$this->index_key] ) && ! empty( $this->files[$this->index_key] ) ) ?
            (string) $this->files[$this->index_key]['name'] : '';

        // останавливаемся, если что-то пошло не так
        if ( empty( $tmp_file ) )
            return false;

        // устанавливаем путь к файлу
        $filepath = $return_data['filepath'] = $return_data['path'] . '/' . basename( $tmp_name );

        // перемещаем загруженный файл из временной директории в директорию загрузки
        move_uploaded_file( $tmp_file , $filepath );

        // устанавливаем имя файла
        $filename = $return_data['filename'] = basename( $filepath );

        // устанавливаем тип файла
        /*
         * Для продакшена
         * Вы ДОЛЖНЫ действительно проверять расширение файла и тип файла
         * при КАЖДОЙ загрузке. Если вы этого не сделаете, возможно загрузить
         * ЛЮБОЙ вид файла, включая вредоносный код.
         */
        $type = wp_check_filetype( $filename, null );
        $return_data['file_ext'] = ( isset( $type['ext'] ) && ! empty( $type['ext'] ) ) ?
        $type['ext'] : '';

        $return_data['type'] = ( isset( $type['type'] ) && ! empty( $type['type'] ) ) ?
        $type['type'] : '';

        // возвращаем результаты
        return $return_data;

    }

    /**
     * Пытается получить первый индекс из $_FILES
     *
     * @return  boolean     Был ли найден ключ или нет
     */
    protected function guess_index_key() {

        $keys = array_keys( $_FILES );

        if ( ! empty( $keys ) ) {
            $this->index_key = $keys[0];
            return true;
        }

        return false;

    }

}

Это базовый класс и не для продакшена! Загрузка файлов — очень чувствительная тема, вы должны самостоятельно проверять и очищать все данные. В противном случае возможно, что кто-то загрузит вредоносный код и взломает ваш сервер/блог/сайт!

Теперь шаг за шагом о том, что происходит, где и когда.

При создании экземпляра класса класс пытается создать копию суперглобального массива $_FILES. Если вы работаете с суперглобальными массивами, не трогайте их! Возможно, другим частям кода (плагинам или темам) также нужны данные внутри них. Следующее, что происходит в конструкторе — это попытка угадать ключ индекса. Как вы знаете, мы можем передать больше, чем один файл, и $_FILES может содержать данные для всех загруженных файлов. Если вам нужно обработать больше одного файла, пройдитесь циклом по $_FILES и установите ключ индекса с помощью set_field_name_for_file()

// получаем индексы из $_FILES
$keys = array_keys( $_FILES );
$upload_processor = new File_Upload();
foreach ( $keys as $key ) {
  $upload_processor->set_field_name_for_file( $key );
  $upload_processor->create_attachment();
}

set_field_name_for_file() также необходим, если вы хотите выбрать конкретное поле из вашей HTML формы, в противном случае класс использует первый найденный индекс.

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

Последний шаг — создание вложения. create_attachment() установит все необходимые данные и создаст для вас вложение. Метод возвращает ID вложения, так что вы можете получить доступ ко всем данным вложения с помощью get_post( [id] )

$imageupload = new File_Upload();
$attachment_id = $imageupload->create_attachment();
[некоторый другой код]        
$attachment = get_post( $attachment_id );
$image_url  = $attachment->guid;

printf( '<p><img src="%s"></p>', $image_url );

Несколько слов об обработке ошибок

Я написал несколько подсказок в коде класса для продакшена. Как я упоминал выше, загрузка файлов — очень чувствительная тема. Вы должны проверять, валидировать и очищать абсолютно все. В WordPress есть встроенная обработка ошибок с помощью WP_Error(). Используйте ее! И проверяйте, была ли загрузка успешной, с помощью is_wp_error().

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

protected function guess_upload_error( $err = 0 ) {

    $errcodes = array(
        'Неизвестная ошибка',
        'Загружаемый файл превышает директиву upload_max_filesize в php.ini.',
        'Загружаемый файл превышает директиву MAX_FILE_SIZE, указанную в HTML форме.',
        'Загружаемый файл был загружен только частично.',
        'Файл не был загружен.',
        'Отсутствует временная папка.',
        'Не удалось записать файл на диск.',
        'Расширение PHP остановило загрузку файла. PHP не предоставляет способа определить, какое расширение вызвало остановку загрузки файла; просмотр списка загруженных расширений с помощью phpinfo() может помочь.'
    );

    return ( isset( $errcodes[$err] ) ) ?
        $errcodes[$err] : 'Неизвестная ошибка';
}

Вы должны проверить, была ли загрузка успешной, это может выглядеть так (в методе handle_upload_file()):

// останавливаемся, если что-то пошло не так
if ( empty( $tmp_file ) ) {

    $code = ( isset( $this->files[$this->index_key]['error'] ) ) ?
        $this->files[$this->index_key]['error'] : 0;

    $msg = $this->guess_upload_error( $code );

    return new WP_Error( 'uploaderror', 'Ошибка загрузки с сообщением: ' . $msg );
}

И тогда вам нужно обработать ошибку при вызове класса:

if ( empty( $_FILES ) ) {

global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- HTML форма -->
<?php
} else {
    $imageupload = new File_Upload();
    $attachment_id = $imageupload->create_attachment();

    if ( is_wp_error( $attachment_id ) ) {

        echo '<ol>';
        foreach ( $attachment_id->get_error_messages() as $err )
            printf( '<li>%s</li>', $err );
        echo '</ol>';

    } else {

        // делаем что-то с созданным вложением
        $attachment = get_post( $attachment_id );
        $image_url  = $attachment->guid;

        printf( '<p><img src="%s"></p>', $image_url );

    }
}

Всегда помните: Никогда не оставляйте неудачную загрузку без обработки!

5 мая 2013 г. 17:58:02
Комментарии

В базовой HTML-форме в приведённом выше коде я не увидел if перед else

Monogot Monogot
5 мая 2013 г. 23:52:29
0

Добавьте код в файл функций

add_action('wp_ajax_custom_action', 'custom_action');
add_action('wp_ajax_nopriv_custom_action', 'custom_action');
function custom_action() {

$post_id =12;
    //print_r($_FILES); exit;
    global $wpdb;
    //$response = array();

    if( $_FILES['uploadedfiles']) {

    $file = $_FILES['uploadedfiles'];
    require_once( ABSPATH . 'wp-admin/includes/admin.php' );
    $file_return = wp_handle_upload( $file, array('test_form' => false ) );
    if( isset( $file_return['error'] ) || isset( $file_return['upload_error_handler'] ) ) {
        return false;
    } else {
        $filename = $file_return['file'];
        $attachment = array(
            'post_mime_type' => $file_return['type'],
            'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
            'post_content' => '',
            'post_status' => 'inherit',
            'guid' => $file_return['url']
        );
        $attachment_id = wp_insert_attachment( $attachment, $file_return['url'] );
        require_once(ABSPATH . 'wp-admin/includes/image.php');
        $attachment_data = wp_generate_attachment_metadata( $attachment_id, $filename );
        wp_update_attachment_metadata( $attachment_id, $attachment_data );

        update_post_meta($post_id, '_thumbnail_id', $attachment_id);
        if( 0 < intval( $attachment_id ) ) {
          return $attachment_id;
        }
    }
    return false;

    }

    //$response['message'] = 'Изображение загружено!!!';
    //echo json_encode($response);
    wp_die();


}
13 февр. 2020 г. 09:40:15