Ajaxで画像を送受信する方法。
なかなかに手こずったのでメモ。
まずは、page.phpなどにいれておくHTML。
1 2 3 4 5 6 |
<input id="input_image" type="file" accept="image/*"> <button id="save">保存</button> <div id="responce"></div> <input id="load_filename" > <button id="load">読み込み</button> <img id="load_image" > |
つぎに、function.phpなどに以下を。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
//ドキュメントルートの親ディレクトリに画像ファイル保存用のディレクトリを用意する define("F_DIR", dirname($_SERVER['DOCUMENT_ROOT']) . "/images/"); //画像保存用ディレクトリ作成 if (!file_exists(F_DIR)){ mkdir(F_DIR, 0777); } add_action( 'wp_enqueue_scripts','register_myscript' ); function register_myscript() { //JSファイルを登録して呼び出し。 wp_register_script( 'myscript', get_stylesheet_directory_uri() . '/myscript.js' ); wp_enqueue_script( 'myscript' ); //ajaxのエンドポイントとnonceをJSで使えるようにしておく。 wp_localize_script( 'myscript', 'myajax', [ 'nonce' => wp_create_nonce( 'my_nonce' ), 'ajaxurl' => admin_url( 'admin-ajax.php'), ] ); } add_action( 'wp_ajax_my_action_save', 'my_action_function_save' ); add_action( 'wp_ajax_nopriv_my_action_save', 'my_action_function_save' ); function my_action_function_save() { //noneをチェック もし、nonceが一致しなければここでdie();を返す。 check_ajax_referer( 'my_nonce', 'nonce' ); // print_r($_POST);←こうしておくと、$_PSOTや // print_r($_FILES); $_FILES の内容が表示される。 // if (array_key_exists('data', $_FILES)){ //$_FILESにFormDataで送信したファイルがはいっているので、取り出す。 $name = $_FILES['data']['name'];//もとのファイル名 $type = $_FILES['data']['type'];//たとえばjpegだと、image/jpeg となる $tmp_name = $_FILES['data']['tmp_name'];//一時的に保存されているファイルデータのパス //$error = $_FILES['data']['error'];//エラー情報。通常は0 //$size = $_FILES['data']['size'];//ファイルサイズ //画像ファイルかどうかをチェック if (strpos($type, 'image/') !== false) { //一時保存ファイルを読み込み $file_data = file_get_contents($tmp_name); //画像ファイルを保存 if (file_put_contents(F_DIR . $name , $file_data)){ echo "OK"; }else{ echo "ERROR"; } } } die; } add_action( 'wp_ajax_my_action_load', 'my_action_function_load' ); add_action( 'wp_ajax_nopriv_my_action_load', 'my_action_function_load' ); function my_action_function_load() { //noneをチェック もし、nonceが一致しなければここでdie();を返す。 check_ajax_referer( 'my_nonce', 'nonce' ); if (array_key_exists('filename', $_POST)){ $filename = F_DIR . $_POST['filename']; if (file_exists($filename)) { $file_data = file_get_contents($filename); //while (@ob_end_clean()); ←もし、画像がちゃんと出力できなかったら、これを追加して無駄なバッファをクリアにする。 echo "data:" . $_FILES['filename'] .";base64," . base64_encode($file_data) ; } } die; } |
JSをmyscript.jpというファイル名でfunction.phpと同じフォルダに作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
jQuery(function ($) { $(document).on('click', 'button#save' , function (event) { //ファイルデータを読み込み var files = $('input#input_image').prop("files"); //FormDataオブジェクト作成 var fd = new FormData(); fd.append('data' , files[0] );//データを含むファイル情報がfiles[0]にはいっている。 fd.append('action', 'my_action_save');//アクション名を指定 fd.append('nonce', myajax.nonce);//nonceを設定 $.ajax({ type: 'post', url: myajax.ajaxurl, data: fd, processData : false, contentType : false, }).done(function (response) { $('#responce').text(response);//戻り値を表示 }).fail(function(jqXHR, textStatus, errorThrown) { $('#responce').text(errorThrown.message);//エラーを表示 }); }); $(document).on('click', 'button#load' , function (event) { //ファイル名を取得 var filename = $('input#load_filename').val(); var fd = new FormData(); fd.append('filename' , filename ); fd.append('action', 'my_action_load'); fd.append('nonce', myajax.nonce); $.ajax({ type: 'post', url: myajax.ajaxurl, data: fd, processData : false, contentType : false, }).done(function (response) { //console.log(response);←うまく行かないときは、console.logで戻り値をチェック $("#load_image").attr('src', response); }).fail(function(jqXHR, textStatus, errorThrown) { $('#responce').text(textStatus); }); }); }); |
まず、ファイルを選んで、保存ボタンをクリックします。
すると、ちゃんとアップロードできたら、OKが表示されます。ファイル名を入れて読み込みボタンを押すと、保存した画像を読み込んで表示できることがわかります。
こんなかんじで。
アップロードしたファイルを安全に保存する
HTMLでアクセスできないように保存するために、今回はドキュメントルートの親ディレクトリに保存するようにしました。でも、パーミッションをきちんと設定すれば問題ないように思います。ただ、ドキュメントルートの親ディレクトリだとFTPでファイルを確認することができるので、その点で便利です。
ほかにも、データベースに直接保存する方法もあります。その場合blob型を使うとうまくいきました。でも、レンタルサーバーだと、データベースに保存できる容量が小さいので難しいです。例えば、エックスサーバーでは1GBしか保存できないので。VPSや専用サーバが使えるなら、データベースへの保存も視野にいれていいのかなと思います。データベースに画像を入れると負荷が大きくなるので、よろしくないという意見と、そんなこともないという意見があるようですが、そのあたりは使い方にもよるんでしょうね。