it-swarm.com.de

Wie lade ich ein Bild mit einem einfachen Formular hoch?

Ich schreibe ein Plugin in meine Profilseite und möchte einen Upload über die Schaltfläche 'Durchsuchen' und das Feld 'Dir' erstellen, der die Bild-URL hochlädt und zurückgibt. Und ich möchte keinen Medien-Upload verwenden.

Ich habe gelesen, Vorgestelltes Bild festlegen Front-End-Formular ? und ich verstehe den Code nicht. Helfen Sie mir, dieses Problem zu lösen?

3
MonoGot

Es gibt mehrere Teile.

Sie müssen dem Profilformular eine enctype hinzufügen.

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

Fügen Sie dann dem Formular ein Feld hinzu.

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');

Und dann die Daten speichern.

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 ist wahrscheinlich der einfachste. Aus dem Kodex:

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";
}

Der Eingabetyp file funktioniert (meistens) wie jede andere Formulareingabe. Wenn Sie einen Namen wie my_uploads['profile_photo'] anstelle von nur profile_photo vergeben, erhalten Sie ein Array. Dies wird in der Variablen $_FILES berücksichtigt, wenn Sie die Formularübermittlung verarbeiten. Sie können so viele file Eingaben hinzufügen, wie Sie möchten, indem Sie dieses Array erstellen oder ihnen einfach andere Namen geben. Soweit man file Eingaben dynamisch hinzufügt, ist das recht einfaches Javascript.

Referenz

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

6
s_ha_dum

Ich vermute, Sie sind nicht sehr erfahren mit PHP und dem Hochladen von Dateien. Also beginne ich mit einigen Grundlagen und ende mit einem einfachen Kurs.

Wenn Sie die Grundlagen zum Hochladen von Dateien mit PHP noch nicht gelesen haben, tun Sie dies jetzt. Niemand wird es Ihnen hier erklären, es ist unangebracht.

Beginnen wir mit dem grundlegenden HTML-Formular

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 );
}

Das ist ganz einfach. Wenn das superglobale Array $_FILES leer ist, bedeutet dies, dass keine Datei hochgeladen wurde. Zeigen Sie das Upload-Formular an. Wenn es nicht leer ist, führen Sie den Upload durch. Ich benutze admin_url() und den $pagenow var, um die Aktions-URL zu erstellen. Wenn Sie das Upload-Formular im Frontend verwenden, müssen Sie home_url() oder ähnliches verwenden.

Nach dem Versenden der Datei mit HTML müssen Sie die hochgeladenen Dateien verarbeiten. Dies erfolgt in der Klasse 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;

    }

}

Dies ist eine Grundklasse und nicht für die Produktion ! Dateiuploads sind ein sehr sensibles Thema. Sie müssen alle Daten selbst validieren und bereinigen. Andernfalls kann jemand bösartigen Code hochladen und Ihren Server/Blog/Ihre Website hacken!

Nun Schritt für Schritt, was wo und wann passierte.

Beim Erstellen einer Instanz der Klasse versucht die Klasse, eine Kopie des superglobalen Arrays $_FILES zu erstellen. Wenn Sie mit superglobalen Arrays arbeiten, berühren Sie sie nicht! Möglicherweise benötigen auch andere Teile des Codes (Plugins oder Themes) die darin enthaltenen Daten. Das nächste, was im Konstruktor passierte, ist, dass wir versuchen, den Indexschlüssel zu erraten. Wie Sie wissen, können wir mehr als eine Datei übergeben und $_FILES kann Daten für alle hochgeladenen Dateien enthalten. Wenn Sie mehr als eine Datei verarbeiten müssen, führen Sie eine Schleife über $_FILES und setzen Sie den Indexschlüssel mit 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() wird auch benötigt, wenn Sie ein bestimmtes Feld aus Ihrem HTML-Formular auswählen möchten, andernfalls verwendet die Klasse den ersten Index, den sie finden kann.

Der nächste Schritt ist die Bearbeitung der hochgeladenen Datei. Die Methode create_attachment() ruft die geschützte Methode handle_uploaded_file() auf, Sie müssen dies nicht manuell tun. Die Methode handle_uploaded_file() sammelt und richtet einfach einige benötigte Pfade und Dateinamen ein.

Der letzte Schritt ist das Erstellen eines Anhangs. create_atatchment() richtet alle erforderlichen Daten ein und erstellt einen Anhang für Sie. Die Methode gibt dieIDdes Anhangs zurück, sodass Sie mit get_post( [id] ) auf alle Anhangsdaten zugreifen können.

$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 );

Einige Worte zur Fehlerbehandlung

Ich habe einige Hinweise in den Klassencode für die Produktionsumgebung geschrieben. Wie bereits erwähnt, sind Datei-Uploads ein sehr sensibles Thema. Sie müssen wirklich alles überprüfen, validieren und desinfizieren. WordPress hat eine eingebaute Fehlerbehandlung mit WP_Error(). Benutze es! Und überprüfen Sie, ob der Upload mit is_wp_error() erfolgreich war.

PHP kann einige Fehlermeldungen einrichten, warum der Upload fehlgeschlagen ist, wenn er fehlgeschlagen ist. Aber PHP gibt keine Klartextnachrichten zurück, sondern Fehlercodes. Eine Methode zum Konvertieren dieser Codes in Klartext könnte folgendermaßen aussehen:

geschützte Funktion 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';

}

Sie müssen überprüfen, ob der Upload erfolgreich war. Dies könnte folgendermaßen aussehen (in Methode 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 );
}

Und dann müssen Sie den Fehler behandeln, wenn Sie die Klasse aufrufen

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 );

    }
}

Denken Sie immer daran : Lassen Sie niemals einen fehlgeschlagenen Upload unbehandelt!

4
Ralf912