PHPで画像アップロード時に比率を保ったまま縮小する

PHPで画像アップロード時に比率を保ったまま縮小する


PHPの画像アップロードが任意のフォームで、
・新規画像アップロード
・上書き画像アップロード
・画像削除
の編集しDBにファイル名を保存する機能がある。
画像アップロードあった場合に、画像のサイズを取得し、縦横どちらかが基準値により大きい場合、比率を保ったまま縮小する。

php関連記事

関連記事をもっとみる

フォームのHTML

HTML

<form action="" method="post" enctype="multipart/form-data">
  <div class="form-group">
    <label for="image">画像</label>

    <input type="file" name="image" id="image"
      accept=".jpg,.gif,.png,image/gif,image/jpeg,image/png">
    <div>ファイルサイズ10MB以内</div>

    <div id="already" style="display: none;">
      <img id="preview">
      <a href="javascript:void(0)" id="imagedel">
        <img src="/img/icon/batu.jpg">
      </a>
    </div>
    

    <canvas id="trimed_image" style="display: none;"></canvas>

    <input type="hidden" name="" id="imagedel_send" value="del">

    <button type="submit">投稿する</button>
  </div>
</form>

formタグには、ファイルアップロードがあるので、enctype="multipart/form-data"をつけます。ファイルアップロードがある場合は、これを付けないとファイルの送信ができません。

input type="file"には、accept=".jpg,.gif,.png,image/gif,image/jpeg,image/png"をつけています。
ユーザーが選択できるファイル形式を、あらかじめ選択しておくことができます。

img id="preview"は、既存の画像がある場合の表示と、canvas id="trimed_image"アップロードされたファイルのプレビュー用です。

id="imagedel"は、既存の画像がある場合に表示される、画像削除用ボタンです。
aタグのjavascript:void(0)については、下記で確認してください。

HTML5のaタグのrel=”noopener noreferrer”や、ページ内リンク、JavaScript実行を解説
HTML5のaタグのrel=”noopener noreferrer”や、ページ内リンク、JavaScript実行を解説しながら、様々なaタグの使い方をまとめました。 HTML5関連記事 ...

画像アップロード時にプレビューを表示する

jQueryで画像アップロード時にプレビューを表示する詳細は、下記を参照してください。

jQueryでinput[type="file"]で画像アップロード時にプレビューを表示する
inputで画像アップロードするときに、jQueryで選択された画像をプレビューで表示するやり方です。画像選択画面で「キャンセル」を押された場合にも、添付されているか確認してプレビューのオンオフ処理する方法。 また、フ...

is_uploaded_fileで、アップロードがあったかの判別する

php

if (is_uploaded_file($_FILES['image']['tmp_name'])) {
  //アップロードがあった処理
}elseif(isset($_POST["img_d"])){
  //画像削除があった処理
}else{
  //アップロードがなかった処理
}

is_uploaded_fileで、アップロードがあったかの判別します。
あった場合は、アップロードされた画像が最優先で利用されます。

アップロードがなく、画像の削除ボタンが押されたときは、DBの更新やファイルの削除処理なんかをしていきます。

アップロードファイルが正しいかチェックする

php

if(!isset($_FILES['image']['error']) || !is_int($_FILES['image']['error'])){
  throw new ErrorException('パラメータが不正です');
}

// $_FILES['image']['error'] の値を確認
switch ($_FILES['image']['error']) {
  case UPLOAD_ERR_OK: // OK
      break;
  case UPLOAD_ERR_NO_FILE:   // ファイル未選択
      throw new ErrorException('ファイルが選択されていません');
  case UPLOAD_ERR_INI_SIZE:  // php.ini定義の最大サイズ超過
  case UPLOAD_ERR_FORM_SIZE: // フォーム定義の最大サイズ超過 (設定した場合のみ)
      throw new ErrorException('ファイルサイズが大きすぎます');
  default:
      throw new ErrorException('その他のエラーが発生しました');
}

$_FILES['image']['error']のerrorの値を調べて、アップロードファイルが正しいかチェックします。

ファイルサイズの大きさをチェックする

php

if ($_FILES['image']['size'] > 10485760) {
    throw new ErrorException('ファイルサイズが大きすぎます');
}

$_FILES['image']['size']の値を調べて、アップロードファイルのサイズが問題ないかをチェックします。

MIMEタイプに対応する拡張子をチェックする

php

if (!$ext = array_search(
  mime_content_type($_FILES['image']['tmp_name']),
  array(
    'gif' => 'image/gif',
    'jpg' => 'image/jpeg',
    'png' => 'image/png',
  ),
  true
)) {
  throw new ErrorException('ファイル形式が不正です');
}

mime_content_typeでアップロードされたファイルのMIMEタイプをチェックします。
今回は画像のアップロードなので、このくらいで問題ないと思います。

アップロードされた画像のファイル名を変更する

php

$rename_org = TALK_PFX.$insct_id."-".$local_id;
$rename_org = $rename_org.".".$ext;

if (!move_uploaded_file(
  $_FILES['image']['tmp_name'], 
  "./".UP_PATH_TALK.$rename_org
  )
) {
  throw new ErrorException('ファイル保存時にエラーが発生しました');
}

$fileimagename = $rename_org;

// ファイルのパーミッションを確実に0644に設定する
chmod("./".UP_PATH_TALK.$rename_org, 0644);

$rename_orgであらかじめファイルの命名規則を作成しておき、チェックした拡張子を、合わせます。
アップロードされたファイル名はそのまま使わないようにしましょう。

その後、move_uploaded_fileで、ファイルをコピーします。
さらに、そのファイルのパーミッションを0644に変更します。自分は読み書き、他の人は読み込みのみ可能な状態にします。

画像の縦横のサイズを取得して縮小後のサイズを計算するfunction

php

function ratio($w, $h){
  $newwidth = 0; // 新しい横幅
  $newheight = 0; // 新しい縦幅
  $res_w = 800; // 最大横幅
  $res_h = 800; // 最大縦幅

  if ($w > $h) {
    // 横長の画像は横のサイズを指定値にあわせる
    $ratio = $h / $w;
    $newwidth = $res_w;
    $newheight = $res_w * $ratio;
  } else {
    // 縦長の画像は縦のサイズを指定値にあわせる
    $ratio = $w / $h;
    $newwidth = $res_h * $ratio;
    $newheight = $res_h;
  }


  $rtn_wh = [
    'width' => $newwidth,
    'height' => $newheight,
  ];

  return $rtn_wh;
}

縦横どちらか大きい方の辺に合わせて、反対の辺を縮小した際の比率を計算します。

画像をリサイズするfunction

php

function img_resize($url, $res_w, $res_h, $p_w, $p_h, $x, $y, $picturename){
  list($w, $h, $type) = getimagesize($url);
  
  switch($type){
    case IMAGETYPE_JPEG:
      $in = imagecreatefromjpeg($url);
      break;
    case IMAGETYPE_GIF:
      $in = imagecreatefromgif($url);
      break;
    case IMAGETYPE_PNG:
      $in = imagecreatefrompng($url);
      break;
  }


  // コピー画像のリソース
  $out = imagecreatetruecolor($res_w, $res_h);
  imagealphablending($out, false);
  imagesavealpha($out, true); 
  // リサイズ
  ImageCopyResampled($out, $in, 0, 0, $x, $y, $res_w, $res_h, $p_w, $p_h);
  
  imagepng($out, UP_PATH_TALK.$picturename);

  imagedestroy($out);
  imagedestroy($in);
}

ratio関数で、取得した比率を元に画像を縮小するfunctionです。
ここでも拡張子をチェックします。

画像の縦横のサイズを取得してリサイズする

php

list($wid, $hei, $type) = getimagesize("./".UP_PATH_TALK.$rename_org);

if($wid >= 800 || $hei >= 800){
  $wh = ratio($wid, $hei);

  img_resize(
    "./".UP_PATH_TALK.$rename_org, 
    $wh['width'], $wh['height'],
    $wid, $hei,
    0, 0, $rename_org);
}

$image_change = true;

画像の縦横サイズを取得してから、必要ならratio関数と、img_resize関数を使って、辺の最大値より大きい場合に、画像をリサイズします。

リサイズをしてもしなくても、DBは更新するので$image_changeをtrueにします。

画像の削除をする場合

php

elseif(isset($_POST["img_d"])){
  $fileimagename = "";
  $image_change = true;
}

$fileimagenameがDBに入れるファイル名で値をブランクにし、DBは更新するので、$image_changeをtrueにします。

最終的なコード

HTML

//アップロードがあった
if (is_uploaded_file($_FILES['image']['tmp_name'])) {

  $rename_org = TALK_PFX.$insct_id."-".$local_id;

  if(!isset($_FILES['image']['error']) || !is_int($_FILES['image']['error'])){
    throw new ErrorException('パラメータが不正です');
  }
  
  // $_FILES['image']['error'] の値を確認
  switch ($_FILES['image']['error']) {
    case UPLOAD_ERR_OK: // OK
        break;
    case UPLOAD_ERR_NO_FILE:   // ファイル未選択
        throw new ErrorException('ファイルが選択されていません');
    case UPLOAD_ERR_INI_SIZE:  // php.ini定義の最大サイズ超過
    case UPLOAD_ERR_FORM_SIZE: // フォーム定義の最大サイズ超過 (設定した場合のみ)
        throw new ErrorException('ファイルサイズが大きすぎます');
    default:
        throw new ErrorException('その他のエラーが発生しました');
  }


  // ここで定義するサイズ上限のオーバーチェック
  if ($_FILES['image']['size'] > 10485760) {//
      throw new ErrorException('ファイルサイズが大きすぎます');
  }


  if (!$ext = array_search(
    mime_content_type($_FILES['image']['tmp_name']),
    array(
      'gif' => 'image/gif',
      'jpg' => 'image/jpeg',
      'png' => 'image/png',
    ),
    true
  )) {
    throw new ErrorException('ファイル形式が不正です');
  }

  $rename_org = $rename_org.".".$ext;

  
  if (!move_uploaded_file(
    $_FILES['image']['tmp_name'], 
    "./".UP_PATH_TALK.$rename_org
    )
  ) {
    throw new ErrorException('ファイル保存時にエラーが発生しました');
  }

  $fileimagename = $rename_org;

  // ファイルのパーミッションを確実に0644に設定する
  chmod("./".UP_PATH_TALK.$rename_org, 0644);

  list($wid, $hei, $type) = getimagesize("./".UP_PATH_TALK.$rename_org);

  if($wid >= 800 || $hei >= 800){
    $wh = ratio($wid, $hei);

    img_resize(
      "./".UP_PATH_TALK.$rename_org, 
      $wh['width'], $wh['height'],
      $wid, $hei,
      0, 0, $rename_org);
  }

  $image_change = true;
}elseif(isset($_POST["img_d"])){
  $fileimagename = "";
  $image_change = true;
}else{
  $fileimagename = "";
}

検証中のため、漏れ等あるかもしれませんので、ご注意ください。

コメント

タイトルとURLをコピーしました