質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.77%

jQuery+PHPで複数画像ファイルをリサイズしアップロードする方法を知りたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,035

score 1

jQueryで、複数(三つ)の画像ファイルを選択しリサイズした後、PHPでサーバーにアップロード(指定のディレクトリー"./images/"に保存)したいのですが、
後述のスクリプトでは、最後に選択したファイルだけしか、リサイズ・保存されません。
クロームのデベロッパーツールで確認するとBlobは、複数確認できているので、
アップロード開始ボタン(投稿)をクリックした後の  jQuery('#upload').click(function()内で、
ループ配列化して、phpに送ればよいのでは、色々と試してみたのですが、jQuery javascript php等々、プログラム全般について初心者のため、
うまく配列化できません。
配列での送受信あるいは、別の方法での複数画像ファイルのリサイズアップロードのやり方について、ご教授頂けないでしょうか。

なお、複数ファイル選択で、下のように
<input type="file" name="file1" id="idtmp1" accept="image/*">
「multiple」を使っていないのは、サーバー側で値を出力する際、順位を特定したいからです。

よろしくお願いいたします。

HTML+ javascript部分
[index.html]

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="content-script-type" content="text/javascript" />
<meta http-equiv="content-style-type" content="text/css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div>
<form enctype="multipart/form-data" method="post">
<table align="center">
<tr>
<td align="center">
<input type="file" name="upfile[]" id="idtmp1" accept="image/*"><br><canvas id="canvas1" width="0" height="0"></canvas><br>
<input type="file" name="upfile[]" id="idtmp2" accept="image/*"><br><canvas id="canvas2" width="0" height="0"></canvas><br>
<input type="file" name="upfile[]" id="idtmp3" accept="image/*"><br><canvas id="canvas3" width="0" height="0"></canvas><br>
</td>
</tr>
</table>
<table align="center">
<tr>
<td align="center">
<!-- アップロード開始ボタン -->
<button class="btn btn-primary" id="upload">投稿</button>
<button type=reset class="gryBtn100">Reset</button>
</td>
</tr>
</table>
</form>
</div>

<script type="text/javascript">
// 縮小後 アップロード 

jQuery(function() {
var file = null; // 選択されるファイル
var blob = null; // 画像(BLOBデータ)
const THUMBNAIL_WIDTH = 500; // 画像リサイズ後の横の長さの最大値
const THUMBNAIL_HEIGHT = 500; // 画像リサイズ後の縦の長さの最大値

// ファイルが選択されたら
jQuery('input[type=file]').change(function() {

//    サムネ描画位置指定のためid名から番号取得
var idName = jQuery(this).attr("id");
var n =  idName.slice( -1 ) ;

// ファイルを取得
file = jQuery(this).prop('files')[0];

// 選択されたファイルが画像かどうか判定
if (file.type != 'image/jpeg' && file.type != 'image/jpg' && file.type != 'image/gif' && file.type != 'image/png') {
alert("Only the following file types can be uploaded:JPG, JPEG, PNG, GIF");
file = null;
blob = null;
// 選択されたファイルをクリア
jQuery('input[type=file]').val('');
return;
}

// 選択されたファイルが制限サイズ内かどうか判定 
if((1200 * 1024)< file.size){
alert("ファイル容量を超えています");
file = null;
blob = null;
// 選択されたファイルをクリア
jQuery('input[type=file]').val('');
return;
}

// 画像をリサイズする
var image = new Image();
var reader = new FileReader();
reader.onload = function(e) {
image.onload = function() {
var width, height;
if(image.width > image.height){
// 横長の画像は横のサイズを指定値にあわせる
var ratio = image.height/image.width;
width = THUMBNAIL_WIDTH;
height = THUMBNAIL_WIDTH * ratio;
} else {
// 縦長の画像は縦のサイズを指定値にあわせる
var ratio = image.width/image.height;
width = THUMBNAIL_HEIGHT * ratio;
height = THUMBNAIL_HEIGHT;
}

// サムネ描画位置取得
var canvas_n = '#canvas' + n;
// サムネ描画用canvasのサイズを上で算出した値に変更
var canvas = jQuery(canvas_n)
.attr('width', width)
.attr('height', height);
var ctx = canvas[0].getContext('2d');
// canvasに既に描画されている画像をクリア
ctx.clearRect(0,0,width,height);
// canvasにサムネイルを描画
ctx.drawImage(image,0,0,image.width,image.height,0,0,width,height);

// canvasからbase64画像データを取得
var base64 = canvas.get(0).toDataURL('image/jpeg');        
// base64からBlobデータを作成
var barr, bin, i, len;
bin = atob(base64.split('base64,')[1]);
len = bin.length;
barr = new Uint8Array(len);
i = 0;
while (i < len) {
barr[i] = bin.charCodeAt(i);
i++;
}

blob = new Blob([barr], {type: 'image/jpeg'});

console.log(blob);
}
image.src = e.target.result;
}
reader.readAsDataURL(file);
});

// アップロード開始ボタンがクリックされたら
jQuery('#upload').click(function(){

// ファイルが指定されていなければ何も起こらない
if(!file || !blob) {
return;
}

var name, fd = new FormData();
fd.append('file', blob); // ファイルを添付する

jQuery.ajax({
url: 'upload.php', // 送信先
type: 'POST',
dataType: 'html',
data: fd,
processData: false,
contentType: false
})
.done(function( data, textStatus, jqXHR ) {
// 送信成功
alert(data);
location.href = "./"; // ページリロード
})
.fail(function( jqXHR, textStatus, errorThrown ) {
// 送信失敗
alert('ERROR : ' + status + ' : ' + errorThrown);
});  

});

});

</script>

</body>
</html>

PHP部分
[upload.php]

<?php

/* 拡張子情報の取得・セット */
$imginfo = getimagesize($_FILES['file']['tmp_name']);
if($imginfo['mime'] == 'image/jpeg'){ $extension = ".jpg"; }
if($imginfo['mime'] == 'image/png'){ $extension = ".png"; }
if($imginfo['mime'] == 'image/gif'){ $extension = ".gif"; }

/* 拡張子存在チェック */
if(!empty($extension)){

/* 画像登録処理 */
$file_tmp = $_FILES['file']['tmp_name'];
$file_name = "sample" . $extension; // アップロード時のファイル名を設定
$file_save = "./images/" . $file_name; // アップロード対象のディレクトリを指定
move_uploaded_file($file_tmp, $file_save); // アップロード処理

echo "success"; // jquery側にレスポンス

} else {

echo "fail"; // jquery側にレスポンス

}

?>

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

原則画像のリサイズはサーバー側にやらせた方がいいでしょう
(canvasでクオリティが満足ならそれもあるかもしれませんが)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/11/09 16:48

    最後のデータだけなのは
    fd = new FormData();
    で初期化しているからでは?
    予めfdをつくっておいて、各file毎にappendしてあげてください

    キャンセル

  • 2020/11/09 22:46

    せっかくなのでざっくり作ってみました。


    <form>
    <input type="file" name="upfile[]" id="idtmp1" accept="image/*"><br>
    <input type="file" name="upfile[]" id="idtmp2" accept="image/*"><br>
    <input type="file" name="upfile[]" id="idtmp3" accept="image/*"><br>
    <button type="submit" class="btn btn-primary" id="upload">投稿</button>
    </form>

    キャンセル

  • 2020/11/09 22:46

    window.addEventListener('DOMContentLoaded', ()=>{
    document.querySelector('#upload').addEventListener('click',async e=>{
    e.preventDefault();
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const files=[...document.querySelectorAll('[type=file]')].filter(x=>x.value).map(x=>({name:x.name,file:x.files[0]}));
    const method="post";
    const body = new FormData();
    for(var x of files){
    const file=x.file;
    const name=x.name;
    var scale=0.2;
    const type=file.type;
    const blob=new Blob([file],{type:type});
    const url = URL.createObjectURL(blob);
    await new Promise(resolve=>{
    const image = new Image();
    image.addEventListener('load',()=>{
    const dstWidth = image.width * scale;
    const dstHeight = image.height * scale;
    canvas.width = dstWidth;
    canvas.height = dstHeight;
    ctx.drawImage(image, 0, 0, image.width,image.height, 0, 0, dstWidth, dstHeight);
    const base64 = canvas.toDataURL(type);
    const bin = atob(base64.replace(/^.*,/, ''));
    const buffer = new Uint8Array(bin.length);
    for (var i = 0; i < bin.length; i++) {
    buffer[i] = bin.charCodeAt(i);
    }
    const blob = new Blob([buffer.buffer], {type});
    resolve([name,blob,file.name]);
    });
    image.src=url;
    }).then(res=>{
    body.append(res[0],res[1],res[2]);
    });
    }
    fetch("send.php",{method,body}).then(res=>res.text()).then(console.log);
    });
    });

    キャンセル

  • 2020/11/10 06:04

    yambejp様、

    このたびは、ご親切にコードを書いていただきありがとうございました。
    実は、最初に頂いたアドバイスを参考に、あれこれ、何度となく試してもvar_dump($_FILES)
    を確認すると全く、配列化できませんでした。

    今朝、早朝に、テラテイルからのメールを見たら、新たにyambejp様からご助言を頂いており、なんと
    コードが書かれていました。
    さっそく、下のphpで確認したところ、期待通りに、リサイズされた画像ファイルをサーバーに
    保存することができました。

    3日あまり、これに悩んでいたのが解決でき、大変うれしい限りです。
    本当にありがとうございました。


    <?php

    // ファイルがあれば処理実行
    if(isset($_FILES["upfile"])){

    // アップロードされたファイル件を処理
    for($i = 0; $i < count($_FILES["upfile"]["name"]); $i++ ){

    // アップロードされたファイルか検査
    if(is_uploaded_file($_FILES["upfile"]["tmp_name"][$i])){

    // ファイルをお好みの場所に移動
    move_uploaded_file($_FILES["upfile"]["tmp_name"][$i], "./images/" . $_FILES["upfile"]["name"][$i]);
    }
    }
    }

    ?>

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る