web-dev-qa-db-ja.com

簡単な形式で画像をアップロードするにはどうすればいいですか?

私は自分のプロフィールページにプラグインを書いていて、アップロードして画像のURLを返す[参照]ボタンと[ディレクトリ]フィールドを介してアップロードを作成したいと思います。メディアアップロードを使用したくありません。

おすすめの画像フロントフロントエンドフォームを設定します ?そして私はコードを理解していない私がこの問題を解決するのを手伝ってくれる?

3
MonoGot

いくつかの部分があります。

プロファイルフォームに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>'.__('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');

そしてデータを保存します。

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はおそらく最も簡単です。コーデックスから:

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

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

6
s_ha_dum

PHPやファイルのアップロードには期限切れではないと思います。だから私はいくつかの基本から始め、簡単なクラスで終わります。

PHPで ファイルのアップロードに関する基本 をまだ読んでいない場合は、ここで行ってください。誰もあなたのためにここでそれを説明しません、それは話題ではありません。

基本的なHTMLフォームから始めましょう

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

それは静かな単純です。スーパーグローバル配列$_FILESが空の場合、これはファイルがアップロードされていないことを意味し、アップロードフォームを表示します。空でない場合は、アップロードを処理します。私はadmin_url()$pagenow変数を使ってアクションURLを作成します。フロントエンドでアップロードフォームを使用する場合は、home_url()またはそれに似たものを使用する必要があります。

ファイルをHTMLで送信したら、アップロードしたファイルを処理する必要があります。これは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;

    }

}

これは基本的なクラスで、本番用ではありません!ファイルのアップロードは非常に重要なトピックです。自分ですべてのデータを検証してサニタイズする必要があります。 !

今、ステップバイステップで何がどこでいつ起こるのか。

クラスのインスタンスを作成すると、クラスはスーパーグローバル配列$_FILESのコピーを作成しようとします。もしあなたがスーパーグローバルアレイを使っているならば、それらに触れないでください!コードの他の部分(プラグインやテーマ)もそれらの中のデータを必要としているかもしれません。次にコンストラクタで起こることは、インデックスキーを推測しようとしていることです。ご存じのとおり、私たちは1つ以上のファイルを渡すことができ、$_FILESはすべてのアップロードされたファイルのデータを含むことができます。複数のファイルを処理する必要がある場合は、$_FILESをループ処理して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();
}

HTMLフォームから特定のフィールドをピックしたい場合はset_field_name_for_file()も必要です。それ以外の場合、クラスは最初に見つけたインデックスを使用します。

次のステップはアップロードされたファイルを処理することです。メソッドcreate_attachment()はプロテクトメソッドhandle_uploaded_file()を呼び出します。手動で行う必要はありません。 handle_uploaded_file()メソッドは単に必要なパッチとファイル名を集めて設定します。

最後のステップは添付ファイルを作成することです。 create_atatchment()はすべての必要なデータをセットアップしてあなたのために添付ファイルを作成します。このメソッドは添付ファイルのID)を返すので、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 );

エラー処理に関するいくつかの単語

実稼働環境用のクラスコードにヒントをいくつか書きました。前述したように、ファイルのアップロードは非常に重要なトピックです。あなたは本当にすべてをチェックし、検証しそして消毒しなければなりません。 WordPressにはWP_Error()によるエラー処理が組み込まれています。これを使って!そしてアップロードがis_wp_error()で成功したかどうか確認してください。

PHPはアップロードが失敗した場合に失敗した理由をいくつか設定することができます。しかしPHPはクリアテキストメッセージを返さず、エラーコードを返します。このコードを平文に変換する方法は次のようになります。

保護された関数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';

}

アップロードが成功したかどうかを確認する必要があります。これは次のようになります(メソッド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 );
}

そして、あなたはクラスを呼び出すときにエラーを処理する必要があります

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

    }
}

常に覚えておく:失敗したアップロードを未処理にしないでください。

4
Ralf912