Como fazer upload de uma imagem com um formulário simples?

3

Eu escrevo o plugin na minha página de perfil e quero criar o upload por meio do botão 'Browse' e do campo 'Dir' que farão upload e retornarão o URL da imagem.E eu não quero usar o upload de mídia.

Eu costumava ler Definir formulário de front-end frontal de imagem em destaque e eu não entendo código Ajude-me a resolver este problema?

    
por MonoGot 05.05.2013 / 12:48

2 respostas

6

Existem várias partes.

Você precisa adicionar um enctype ao formulário de perfil.

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

Em seguida, adicione um campo ao formulário.

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

  echo '<h3>'.__('Additional User Data',THEME_TEXTDOMAIN).'</h3>';
    echo '<tr class="show-admin-bar">';
      echo '<th scope="row">'.__('Profile Photo', THEME_TEXTDOMAIN).'</th>';
      echo '<td'.$tspan.'>';
        echo '<fieldset>';
          echo '<legend class="screen-reader-text"><span>'.__('Profile Photo', 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');

E salve os dados.

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

  // save image
  if (isset($_FILES)) {
    if (isset($_FILES['profile_photo'])){
      if (0 === $_FILES['profile_photo']['error']) {
        // This is where you save the file
        // Maybe use wp_handle_upload
        // Or use the Filesystem API
        // not sure what you want to do
      }
    }
    unset($up);
  }
}
add_action('personal_options_update','save_user_custom');
add_action('edit_user_profile_update','save_user_custom');

wp_handle_upload é provavelmente o mais simples. Do 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 "File is valid, and was successfully uploaded.\n";
    var_dump( $movefile);
} else {
    echo "Possible file upload attack!\n";
}

O tipo de entrada file funciona (principalmente) como qualquer outra entrada de formulário. Se você der um nome como my_uploads['profile_photo'] em vez de apenas profile_photo , você receberá uma matriz. Isso será refletido na variável $_FILES quando você processar o envio do formulário. Você pode adicionar quantas file entradas desejar construindo essa matriz ou apenas dando-lhes nomes diferentes. Tanto quanto adicionar dinamicamente file entradas, isso é um simples Javascript.

Referência

enlace
enlace

    
por s_ha_dum 05.05.2013 / 15:36
4

Eu acho que você não é muito expirado com PHP e arquivos de uploads. Então começo com algumas noções básicas e termino com uma aula simples.

Se você ainda não leu os noções básicas sobre uploads de arquivos com PHP, faça agora. Ninguém vai explicá-lo aqui para você, está fora do tópico.

Vamos começar com o formulário HTML básico

if( empty( $_FILES ) ) {
global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- The data encoding type, enctype, MUST be specified as below -->
<form enctype="multipart/form-data" action="<?php echo $url; ?>" method="POST">
    <!-- MAX_FILE_SIZE must precede the file input field -->
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    <!-- Name of input element determines name in $_FILES array -->
    Send this file: <input name="userfile" type="file" />
    <input type="submit" value="Send File" />
</form>
<?php
} else {
    $imageupload = new File_Upload();
    $attachment_id = $imageupload->create_attachment();
    var_dump( $attachment_id );
}

Isso é muito simples. Se a matriz superglobal $_FILES estiver vazia, isso significa que nenhum arquivo foi carregado, exiba o formulário de upload. Se não estiver vazio, processe o upload. Eu uso admin_url() e $pagenow var para criar o URL de ação. Se você usar o formulário de upload no frontend, precisará usar home_url() ou algo semelhante.

Depois de enviar o arquivo com HTML, você precisa processar os arquivos enviados. Isso será feito na classe File_Upload .

class File_Upload
{
    /**
     * Index key from upload form
     * @var string
     */
    public $index_key = '';

    /**
     * Copy of superglobal array $_FILES
     * @var array
     */
    public $files = array();

    /**
     * Constructor
     * Setup files array and guess index key
     */
    public function __construct(){

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

    }

    /**
     * Set/overwrites the index key
     * Converts $name with type casting (string)
     *
     * @param   string  $name   Name of the index key
     * @return  string  ::name  Name of the stored index key
     */
    public function set_field_name_for_file( $name = '' ) {
        $this->index_key = ( ! empty( $name ) ) ? (string) $name : '';
        return $this->index_key;
    }

    /**
     * Converts uploaded file into WordPress attachment
     *
     * @return  boolean     Whether if the attachment was created (true) or not (false)
     */
    public function create_attachment(){

        // move the uploaded file from temp folder and create basic data
        $imagedata = $this->handle_uploaded_file();

        // if moving fails, stop here
        /*
         * For Production
         * Set and return an error object with WP_Error()
         */
        if ( empty( $imagedata ) )
            return false;

        /*
         * For Production
         * Check if $imagedata contains the expected (and needed)
         * values. Every method could fail and return malicious data!!
         */
        $filename = $imagedata['filename'];

        // create the attachment data array
        $attachment = array(
                'guid'           => $imagedata['url'] . '/' . $filename,
                'post_mime_type' => $imagedata['type'],
                'post_title'     => preg_replace('/\.[^.]+$/', '', $filename ),
                'post_content'   => '',
                'post_status'    => 'inherit'
        );

        // insert attachment (posttype attachment)
        $attach_id = wp_insert_attachment( $attachment, $filename );

        // you must first include the image.php file
        // for the function wp_generate_attachment_metadata() to work
        require_once( ABSPATH . 'wp-admin/includes/image.php' );

        /*
         * For Production
         * Check $attach_data, wp_generate_attachment_metadata() could fail
         * Check if wp_update_attachment_metadata() fails (returns false),
         * return an error object with WP_Error()
         */
        $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
        wp_update_attachment_metadata( $attach_id, $attach_data );

        return $attach_id;

    }

    /**
     * Handles the upload
     *
     * @return  array   $return_data    Array with informations about the uploaded file
     */
    protected function handle_uploaded_file() {

        // get the basic data
        $return_data = wp_upload_dir();

        // get temporary filepath and filename from $_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'] : '';

        // stop if something went wrong
        if ( empty( $tmp_file ) )
            return false;

        // set filepath
        $filepath = $return_data['filepath'] = $return_data['path'] . '/' . basename( $tmp_name );

        // move uploaded file from temp dir to upload dir
        move_uploaded_file( $tmp_file , $filepath );

        // set filename
        $filename = $return_data['filename'] = basename( $filepath );

        // set filetype
        /*
         * For Production
         * You should really, really check the file extension and filetype on 
         * EVERY upload. If you do not, it is possible to upload EVERY kind of 
         * file including malicious code.
         */
        $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 the results
        return $return_data;

    }

    /**
     * Try to fetch the first index from $_FILES
     *
     * @return  boolean     Whether if a key was found or not
     */
    protected function guess_index_key() {

        $keys = array_keys( $_FILES );

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

        return false;

    }

}

Esta é uma classe básica e não para produção ! Os uploads de arquivos são um tópico muito delicado, você precisa validar e limpar todos os dados por conta própria. Caso contrário, é possível que alguém envie um código malicioso e hackue seu servidor / blog / site!

Agora, passo a passo, o que aconteceu onde e quando.

Com a criação de uma instância da classe, a classe tenta criar uma cópia da matriz superglobal $_FILES . Se você trabalha com matrizes superglobais, não toque nelas! Talvez outras partes do código (plugins ou temas) também precisem dos dados dentro delas. A próxima coisa que aconteceu no construtor é que tentamos adivinhar a chave do índice. Como você sabe, podemos transmitir mais de um arquivo e $_FILES pode conter dados para todos os arquivos enviados. Se você precisar processar mais de um arquivo, faça um loop sobre $_FILES e defina a chave de índice com set_field_name_for_file()

// get the indexes from $_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() também é necessário se você quiser inserir um campo específico em seu formulário HTML, caso contrário, a classe usará o primeiro índice que encontrar.

O próximo passo é manipular o arquivo enviado. O método create_attachment() chama o método protegido handle_uploaded_file() , você não precisa fazer isso manualmente. O método handle_uploaded_file() simplesmente coleta e configura alguns caminhos e nomes de arquivos necessários.

O último passo é criar um anexo. create_atatchment() configurará todos os dados necessários e criará um anexo para você. O método retorna o ID do anexo, para que você possa acessar todos os dados do anexo com get_post( [id] )

$imageupload = new File_Upload();
$attachment_id = $imageupload->create_attachment();
[some other code]        
$attachment = get_post( $attachment_id );
$image_url  = $attachment->guid;

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

Algumas palavras sobre o tratamento de erros

Eu escrevi algumas dicas no código da classe para o ambiente de produção. A eu mencionei acima, uploads de arquivos são um tópico muito sensível. Você tem que verificar, validar e higienizar realmente tudo. O WordPress tem um erro na manipulação de erros com WP_Error() . Use-o! E verifique se o upload foi bem-sucedido com is_wp_error() .

O PHP pode configurar algumas mensagens de erro por que o upload falhou se falhou. Mas o PHP não retorna mensagens de texto claras, ele retorna códigos de erro. Um método para converter esses códigos em texto não criptografado poderia ser assim:

função protegida guess_upload_error ($ err = 0) {

$errcodes = array(
    'Unknown error',
    'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
    'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
    'The uploaded file was only partially uploaded.',
    'No file was uploaded.',
    'Missing a temporary folder.',
    'Failed to write file to disk.',
    'A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help.'
);

return ( isset( $errcodes[$err] ) ) ?
    $errcodes[$err] : 'Unknown error';

}

Você tem que verificar se o upload foi bem-sucedido, isso pode ser assim (no método handle_upload_file() )

// stop if something went wrong
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', 'Upload failed with message: ' . $msg );
}

E então você tem que lidar com o erro ao chamar a classe

if ( empty( $_FILES ) ) {

global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- HTML form-->
<?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 {

        // do something with the created attachment
        $attachment = get_post( $attachment_id );
        $image_url  = $attachment->guid;

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

    }
}

Lembre-se sempre : nunca deixe um upload com falha não ser tratado!

    
por Ralf912 05.05.2013 / 16:58