POSTで送信された画像をPHP(GD)でリサイズし、DB(MySQL)に保存

POSTされた画像をリサイズするのに今までは指定した画像の大きさに対して力業で縮小し、DB(MySQL)に保存していたのですが、これに加えてGDにて圧縮してDBの肥大化も防ごうと思いました。すでに色々な記事がありますが、自身の忘却防止として残しておきます。

DB(MySQL)に縮小した画像ファイルを入れる

DBのテーブルはこんな感じ。

`attach_img` (
`img_id` bigint(20) NOT NULL AUTO_INCREMENT,
`nickname` varchar(255) NOT NULL COMMENT 'ニックネーム',
`ipaddr` varchar(255) NOT NULL COMMENT 'IPAddress',
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '日時',
`img_user_name` varchar(255) NOT NULL COMMENT '元のファイル名',
`img_name` varchar(255) NOT NULL COMMENT 'ファイル名(img_YmdHisu)',
`img_type` varchar(255) NOT NULL COMMENT '画像タイプ',
`img_size` varchar(255) NOT NULL COMMENT '画像サイズ',
`img_height` varchar(255) NOT NULL COMMENT '画像の縦サイズ',
`img_width` varchar(255) NOT NULL COMMENT '画像の横サイズ',
`image` mediumblob NOT NULL COMMENT '画像',
PRIMARY KEY (`img_id`)
);

ファイルを受け取ります。これも無いと始まらない。
$img_user_name は元々のファイル名となります。あっても無くともどちらでも良いです。
$imgは画像イメージが格納されます。

$img_user_name = $_FILES["imgfile"]["name"];
$img = $_FILES["imgfile"]["tmp_name"];

リサイズする画像の大きさを決めます。ここでは縦横350px × 350pxを最大値として指定します。

// 画像の大きさ指定
$img_max_height = "350";
$img_max_width = "350";

画像ファイルの拡張子を取得します。
なぜかスマホ(Xperia)のカメラで取得した写真をそのままアップロードしようとしたら拡張子が取れない事象が発生した。PCで画像を少しでも弄って保存すると行けるようになる。exif関係か?知っている人が居たら教えてください。

// 拡張子取得
$img_type = image_type_to_mime_type(exif_imagetype($img));

画像の大きさを取得します。

// 画像の大きさを取得
list($img_width,$img_height) = getimagesize($img);

現在の時刻をミリ秒まで取得します。これはDB(MySQL)に格納するファイル名として利用します。

// ミリ秒まで取得
$date_str = ceil(microtime(true)*1000);

ここまでが前置き。これからが本番です。
取得した拡張子が、gif・jpeg・pngであれば処理を実行します。

// 拡張子を判定してDBに入れる
if(preg_match("/gif/i",$img_type) || preg_match("/png/i",$img_type) || preg_match("/jpeg/i",$img_type)){

画像の大きさが規定以上だったら縮小させます。
画像最大サイズ(縦横)を規定内に収めるサイズをwhileで回し続けます。

// 画像の大きさが規定値以内であれば、そのまま
// それ以上であれば、規定値に縮小
if(($img_max_height > $img_height) && ($img_max_width > $img_width)){
	$resize_height = $img_height;
	$resize_width = $img_width;
}else{
	$per = 1.0; // 倍率
	$resize_height = $img_height;
	$resize_width = $img_width;
	while($img_max_width < $resize_width){
		$resize_height = floor($resize_height * $per);
		$resize_width = floor($resize_width * $per);
		$per = $per - 0.1;
	}
	while($img_max_height < $resize_height){
		$resize_height = floor($resize_height * $per);
		$resize_width = floor($resize_width * $per);
		$per = $per - 0.1;
	}
}

ここからGDの出番です。
ここでは、縮小(サムネイル)した画像、オリジナル画像、そしてファイル名が確定します。
拡張子毎に処理が変わります。途中で書いてある透過処理は行わなくとも構わないです。透過処理を行うとファイルサイズが肥大化します。

// サムネイルの画像リソース
$thumb_image = imagecreatetruecolor($resize_width,$resize_height);

if(preg_match("/gif/i",$img_type)){
	$extension = ".gif";
	$original_image = imagecreatefromgif($img);
}elseif(preg_match("/png/i",$img_type)){
	$extension = ".png";

	// 透過処理
	imagealphablending($thumb_image,false);
	imagesavealpha($thumb_image,true);

	$original_image = imagecreatefrompng($img);
}elseif(preg_match("/jpeg/i",$img_type)){
	$extension = ".jpg";
	$original_image = imagecreatefromjpeg($img);
}
// ファイル名確定
$img_name = "img_".$date_str.$extension;

// サムネイル画像の作成
imagecopyresampled($thumb_image, $original_image, 0, 0, 0, 0,
	$resize_width,$resize_height,
	$img_width,$img_height);

縮小(サムネイル)化した画像ファイルをDB(MySQL)に格納するための準備を行います。
途中で書いてある透過処理は行わなくとも構わないです。透過処理を行うとファイルサイズが肥大化します。
画像圧縮もここで行います。

// サムネイル画像の出力
if(preg_match("/gif/i",$img_type)){
	ob_start();
	// 透過処理
	$bgcolor = imagecolorallocatealpha($thumb_image,0,0,0,127);
	imagefill($thumb_image, 0, 0, $bgcolor);
	imagecolortransparent($thumb_image,$bgcolor);

	imagegif($thumb_image);
	$outimage = ob_get_contents();
	ob_end_clean;
}elseif(preg_match("/png/i",$img_type)){
	ob_start();
	imagepng($thumb_image,NULL,8); // 0(圧縮しない)-9 デフォルト6
	$outimage = ob_get_contents();
	ob_end_clean;
}elseif(preg_match("/jpeg/i",$img_type)){
	ob_start();
	imagejpeg($thumb_image,NULL,60); // 0-100 デフォルト75
	$outimage = ob_get_contents();
	ob_end_clean;
}

DB(MySQL)に格納する画像($outimage)のファイルサイズを取得します。
その後、オリジナル画像と縮小(サムネイル)した画像は破棄します。

// ファイルサイズの取得
$img_size = strlen($outimage);
// 画像リソースの破棄
imagedestroy($original_image);
imagedestroy($thumb_image);

エンコードして、DB(MySQL)に入れます。

$outimage = base64_encode($outimage);

// 画像をDBに入れる
$str = "insert into attach_img
(img_user_name,img_name,img_type,img_size,img_height,img_width,image)
values
('$img_user_name','$img_name','$img_type','$img_size','$resize_height','$resize_width','$outimage')
";
$into_img_res = mysql_query($str);

 

 

ソースはこんな感じ

 

$img_user_name = $_FILES["imgfile"]["name"];
$img = $_FILES["imgfile"]["tmp_name"];

// 画像の大きさ指定
$img_max_height = "350";
$img_max_width = "350";

// 拡張子取得
$img_type = image_type_to_mime_type(exif_imagetype($img));

// 画像の大きさを取得
list($img_width,$img_height) = getimagesize($img);

// ミリ秒まで取得
$date_str = ceil(microtime(true)*1000);

// 拡張子を判定してDBに入れる
if(preg_match("/gif/i",$img_type) || preg_match("/png/i",$img_type) || preg_match("/jpeg/i",$img_type)){

// 画像の大きさが規定値以内であれば、そのまま
// それ以上であれば、規定値に縮小
if(($img_max_height > $img_height) && ($img_max_width > $img_width)){
	$resize_height = $img_height;
	$resize_width = $img_width;
}else{
	$per = 1.0; // 倍率
	$resize_height = $img_height;
	$resize_width = $img_width;
	while($img_max_width < $resize_width){
		$resize_height = floor($resize_height * $per);
		$resize_width = floor($resize_width * $per);
		$per = $per - 0.1;
	}
	while($img_max_height < $resize_height){
		$resize_height = floor($resize_height * $per);
		$resize_width = floor($resize_width * $per);
		$per = $per - 0.1;
	}
}

// サムネイルの画像リソース
$thumb_image = imagecreatetruecolor($resize_width,$resize_height);

if(preg_match("/gif/i",$img_type)){
	$extension = ".gif";
	$original_image = imagecreatefromgif($img);
}elseif(preg_match("/png/i",$img_type)){
	$extension = ".png";

	// 透過処理
	imagealphablending($thumb_image,false);
	imagesavealpha($thumb_image,true);

	$original_image = imagecreatefrompng($img);
}elseif(preg_match("/jpeg/i",$img_type)){
	$extension = ".jpg";
	$original_image = imagecreatefromjpeg($img);
}
// ファイル名確定
$img_name = "img_".$date_str.$extension;

// サムネイル画像の作成
imagecopyresampled($thumb_image, $original_image, 0, 0, 0, 0,
	$resize_width,$resize_height,
	$img_width,$img_height);

// サムネイル画像の出力
if(preg_match("/gif/i",$img_type)){
	ob_start();
	// 透過処理
	$bgcolor = imagecolorallocatealpha($thumb_image,0,0,0,127);
	imagefill($thumb_image, 0, 0, $bgcolor);
	imagecolortransparent($thumb_image,$bgcolor);

	imagegif($thumb_image);
	$outimage = ob_get_contents();
	ob_end_clean;
}elseif(preg_match("/png/i",$img_type)){
	ob_start();
	imagepng($thumb_image,NULL,8); // 0(圧縮しない)-9 デフォルト6
	$outimage = ob_get_contents();
	ob_end_clean;
}elseif(preg_match("/jpeg/i",$img_type)){
	ob_start();
	imagejpeg($thumb_image,NULL,60); // 0-100 デフォルト75
	$outimage = ob_get_contents();
	ob_end_clean;
}

// ファイルサイズの再取得
$img_size = strlen($outimage);
// 画像リソースの破棄
imagedestroy($original_image);
imagedestroy($thumb_image);

$outimage = base64_encode($outimage);

// 画像をDBに入れる
$str = "insert into attach_img
(img_user_name,img_name,img_type,img_size,img_height,img_width,image)
values
('$img_user_name','$img_name','$img_type','$img_size','$resize_height','$resize_width','$outimage')
";
$into_img_res = mysql_query($str);

end