6月 09
26.AJAXファイルアップロード
次に管理側の会員情報の編集を作ります。
公開側の会員登録と同じようなものになりますが、今回管理側は画像ファイルアップロードを jquery でやります。
ajaxでやるとなると普通はあれですよね、
・なにか結果を返すphpプログラムが別にあって、
・画面上のボタンをクリックとかのアクションで、そのphpが呼び出されて、
・そのphpからの返り値とかを画面のDOMに反映さす
みたいな動きですよね。
なので今回はその別のphpプログラムを、例えば members_controller.php の中に admin_result() というようなアクションで用意しておいて、一方のビューでは、
<div class="input file"> <label for="MemberSolid1">画像1</label> <input type="file" name="data[Member][solid1]" value="" id="MemberSolid1" /> <input type="button" id="button1" value="Upload" /> <div id="output1"></div> </div>
こんな感じの、ファイル参照の脇にアップロードボタンがあって、処理の結果を表示するための空っぽのdivが用意してあって、というものを想定します。
で、jquery側は、ボタンクリックで、
$(':button').click(function(){
$('#MemberEditForm').ajaxSubmit({url: '/admin/members/result', success: upImage});
return false;
});
urlのところに admin_result を指定したアクションを呼び出して、結果を upImage という function に渡す。
function upImage は以下のようにして、
function upImage(responseText, statusText) {
if (responseText) {
// なにがしかのDOM操作処理
}
}
admin_result からのレスポンスは、上記 responseText に入りますので、それをもとに処理するということでいいかと思います。この javascript を upload.js のファイル名で用意することにします。
ということで、まずはビューから行きます。admin_edit.ctp を開きます
一行目には
<?php echo $javascript->codeBlock('var upurl = "'.$this->base.'/admin/members/result/";', array('inline' => false)); ?>
これを入れておきます。 codeBlock はヘッダー部分に javascript のコードを入れるためのもので、こんな感じに出力されます。
<script type="text/javascript"> //<![CDATA[ var upurl = "/~bob/cake/index.php/admin/members/result/"; //]]> </script>
内容としては、呼び出すアクションのパスを変数 upurl に入れています。
さらにその下に、
<?php echo $javascript->link(array('jquery','form','util','upload'), false); ?>
を入れておきます。
画像アップロード用の javascript を ‘upload’ の名前で用意しようということです。
次にフォーム開始部分を
<?php echo $form->create('Member', array('type'=>'file')); ?>
<fieldset style="display:none;">
<?php
echo $form->input('img1', array('type'=>'hidden','id'=>'img1'));
echo $form->input('img2', array('type'=>'hidden','id'=>'img2'));
echo $form->input('id');
?>
</fieldset>
にします。
好きな物のフォームも公開側と同じにします。
echo $form->input('favorites', array('multiple'=>'checkbox', 'label' => '好きな物'));
画像登録の部分は、
echo $form->input('solid1', array('type'=>'file','label' => '画像1','after'=>'<input type="button" id="button1" value="Upload" /><div id="output1"></div>'));
echo $form->input('solid2', array('type'=>'file','label' => '画像2','after'=>'<input type="button" id="button2" value="Upload" /><div id="output2"></div>'));
としておきます。after を使って、参照ボタンの後ろにボタンと空の div をくっつけておきます。
で、コントローラ members_controller.php のアップロード用アクションですが、以下のようにしておきます。
function admin_result($id = null) {
ini_set('default_charset', 'UTF-8');
Configure::write('debug', 0);
$this->layout = 'ajax';
if ($id) {
$key = "solid" . $id;
if ($this->data['Member'][$key]['tmp_name']){
if (!(($this->data['Member'][$key]['type'] == 'image/pjpeg')||($this->data['Member'][$key]['type'] == 'image/jpeg'))){
$emes = "画像はJPEG形式で登録してください";
}
if (!$emes){
$fd = fopen($this->data['Member'][$key]['tmp_name'], "r");
$filesize = $this->data['Member'][$key]['size'];
$filedata = fread ($fd, $filesize);
fclose ($fd);
$img_file = md5($filedata). ".jpg";
$res = fopen(WWW_ROOT . "files/" . $img_file,'w');
fwrite($res,$filedata);
fclose($res);
}
}
$this->set('filename', $id. "_" .$img_file. "_" .$emes);
}
}
引数で $id を受け取って処理していますが、これは画像1か2か、の引数です。
やってる内容は通常版のファイルアップロードとほとんど同じですが、 javascript に id (画像1か2か)と、今回生成したファイル名と、ついでにエラーメッセージを”_”でつないだ文字列として戻しています。
戻すために、レイアウトを、
$this->layout = 'ajax';
にしておいて、専用のビュー admin_result.ctp を用意しておきます。
それには、
<?php echo $filename;?>
だけが書いてあります。
以上をふまえて、 javascript の upload.js を作ります。
最初に、
var reg = /(\d+)$/i;
と入れておきます。正規表現で数字をヒットさせるためのもので、何回も出てくるので、最初に変数に入れておきます。
続いて、例によって、
$(document).ready(function() {
});
の中に書いていきます。
$(':button').click(function(){
var id = $(this)[0].id.match(reg)[0];
$('.error-message').empty();
$('#output' + id).html('');
$('#MemberEditForm').ajaxSubmit({url: upurl+id, success: upImage});
return false;
});
アップロードボタンをクリックした時の処理です。
2行目で、クリックされたボタンの id から数字を取り出して変数 id に入れています。
5行目で、ajaxサブミットしています。 admin_result アクションの url に id を付けています。
3、4行目はエラー表示と結果出力部分をリセットしているだけです。
さらに、以下を追加します。
$("input[id^='img']").each(function(){
if ($(this).attr('value')){
id = $(this).attr('id').match(reg)[0];
$('#output'+id).html('<span class="previmg">'+$(this).attr('value')+'</span><label id="del' +id+ '"><input type="checkbox" name="del' +id+ '" value="1" />削除</label>');
}
});
既に画像が登録されている場合、それを引っ張ってこないといけないので、登録されているかどうか、を img1 、 img2 の “hidden” から取り出しています。
1行目で img1 、 img2 の “hidden” にヒットします。
3行目で正規表現を使って数字だけ取り出します。
4行目で output の div に表示をセットしています。
最後に以下のfunctionを追加しておきます。
delCheck();
この function には、削除のチェックボックスをチェックした時の処理を入れておきます。
で、それぞれの function を作ります。
function upImage(responseText, statusText) {
if (responseText) {
var res = responseText.split("_");
if (!res[2]){
$('#img' + res[0]).val(res[1]);
$('#output' + res[0]).html('<span class="previmg">'+res[1]+'</span><input type="checkbox" name="del' + res[0] + '" id="del' + res[0] + '" value="1" /> <label for="del' + res[0] + '">削除</label>');
}
$('<div class="error-message">'+res[2]+'</div>').insertAfter('input[id="button'+res[0]+'"]');
$('label[for^=del]').css({'display' : 'inline','float' : 'none'});
delCheck();
}
}
前述のアクションからの返り値が “_” で区切られて responseText に入っていますので、
3行目で分割して配列に入れます。
5行目でimg1 or img2 の “hidden” にファイル名を入れます。
6行目でoutput の div に表示をセットします。ファイル名と削除のチェックボックスです。
7行目でアップロードボタンの後ろにエラーメッセージ表示を入れています。
8行目は削除チェックボックスの見た目の調整です。
9行目で削除チェックのfunctionを呼び出します。
削除チェックは以下のようになります。
function delCheck() {
$("input:checkbox[name^='del']").click(function(){
var del_id = $("input:checkbox:checked[name^='del']")[0].name.match(reg)[0];
$('#MemberEditForm').ajaxSubmit({url: upurl+ del_id, success: delImage});
return false;
});
}
アクションから戻って、 delImage を呼び出します。
function delImage(responseText, statusText) {
var res = responseText.split("_");
$('#img' + res[0]).val('');
$('#output' + res[0]).html('');
}
“hidden” やoutput の div をクリアしています。
上記では画像はファイル名を表示してるだけですが、パスは分かってる訳ですから、マウスオーバーなどで画像を表示させることも十分可能だと思います。
