写真ギャラリーのソース解説② ~PHPによる画像リストとEXIF情報の取得~

先日公開した写真ギャラリーのソースコードを解説していきます。

今回は、第2回目ということであるディレクトリ下にあるJPEGファイルを自動的に全てリストアップするPHPについてです。
それに併せてEXIF情報も取得していきます。

機能などの紹介は紹介の記事を見て下さい。



ソースコード

では、まずは、ソースコードを見ていきましょう。
ファイルをダウンロードする方はこちらを右クリックしてリンク先を保存して下さい。

<?php

// 親ディレクトリを指定
$dir = dirname(__FILE__). '/';  // PHPファイルのディレクトリ

// 出力する変数名をURLから取得
$var_name = 'gallery_list';
if (!empty($_GET['var'])) {
	$var_name = $_GET['var'];
}
 
$result = getImagesList($dir);

print_r('var '.$var_name.'=[');

foreach($result as $file){
	$exif_data = exif_read_data($file, 0, true);
	$date      = isset($exif_data['EXIF']['DateTimeOriginal']) ? $exif_data['EXIF']['DateTimeOriginal'] : date('Y:m:d H:i:s', filemtime($file));
	$lens      = @end($exif_data['EXIF']);  // レンズ名
	$focal     = $exif_data['EXIF']['FocalLength'];  // 焦点距離 : '***'mm
	$focal     = explode('/', $focal);
	if($focal[1]){
		$focal = $focal[0]/$focal[1];
	} else{
		$focal = '不明';
	}
	$aperture  = $exif_data['COMPUTED']['ApertureFNumber'];  // 絞り値 : 'f/***'
	$shutter   = $exif_data['EXIF']['ExposureTime'];  // シャッター速度 : '***' sec
	$shutter   = explode('/', $shutter);
	if($shutter[1]){
		if($shutter[0]/$shutter[1] > 0.2){
			$shutter = $shutter[0]/$shutter[1];
		} else{
			$shutter = $shutter[0].'/'.$shutter[1];
		}
	} else{
		$shutter = '不明';
	}
	$ISO       = $exif_data['EXIF']['ISOSpeedRatings'];  // ISO感度 : ISO'***'
	$camera    = $exif_data['IFD0']['Make'].' '.$exif_data['IFD0']['Model'];  // 機種名 : 'メーカ 機種名'
	if($camera == ''){ $camera = '不明'; }
	$EVvias    = $exif_data['EXIF']['ExposureBiasValue'];  // 露出補正値 : '***'EV
	if($EVvias*1 == 0){ $EVvias = '±0.0'; }
	$modeN     = $exif_data['EXIF']['ExposureProgram'];
	     if($modeN == 1){ $mode = 'M-mode'; }
	else if($modeN == 2){ $mode = 'P-mode'; }
	else if($modeN == 3){ $mode = 'A-mode'; }
	else if($modeN == 4){ $mode = 'S-mode'; }
	else                { $mode = 'Undifined-mode'; }
	$rotate    = 0;
	switch($exif_data['IFD0']['Orientation']){
		case 3:
			$rotate = 180;
		break;
		case 6:
			$rotate = 270;
		break;
		case 8:
			$rotate =  90;
		break;
	}

	$path = explode($dir, $file);
	$path = './'.$path[1];
	print_r('{\n');
	print_r('\t"path"     : "'.$path.'", \n');
	print_r('\t"date"     : "'.$date.'", \n');
	print_r('\t"lens"     : "'.$lens.'", \n');
	print_r('\t"focal"    : "'.$focal.'", \n');
	print_r('\t"aperture" : "'.$aperture.'", \n');
	print_r('\t"shutter"  : "'.$shutter.'", \n');
	print_r('\t"ISO"      : "'.$ISO.'", \n');
	print_r('\t"camera"   : "'.$camera.'", \n');
	print_r('\t"EV"       : "'.$EVvias.'", \n');
	print_r('\t"mode"     : "'.$mode.'",\n');
	print_r('\t"rotate"   :  '.$rotate.'\n');
	print_r('}, \n');
}

print_r('];');

// 画像一覧の相対パスを取得
function getImagesList($dir){
	$list = array();
	$files = scandir($dir);
	foreach($files as $file){
		if($file == '.' || $file == '..' || (!preg_match('/jpg$/i', $file) && is_file($dir. $file)) || preg_match('/(default.jpg|loading.jpg|cache)/i', $file)){
			continue;
		} else if(is_file($dir. $file)){
			$list[] = $dir. $file;
		} else if( is_dir($dir. $file)){
			$list   = array_merge($list, getImagesList($dir.$file.'/'));
		}
	}

	// $list をファイルの更新日時でソート
	usort($list, 'order_by_desc') ;
	
	return $list;
}

// 撮影日時でソートする
function order_by_desc($a, $b){
	$a_exif_data = exif_read_data($a, 0, true);
	$b_exif_data = exif_read_data($b, 0, true);
	$a_date      = isset($a_exif_data['EXIF']['DateTimeOriginal']) ? $a_exif_data['EXIF']['DateTimeOriginal'] : filemtime($a);
	$b_date      = isset($b_exif_data['EXIF']['DateTimeOriginal']) ? $b_exif_data['EXIF']['DateTimeOriginal'] : filemtime($b);
	if($a_date > $b_date){
		return -1;
	} else if($a_date < $b_date){
		return 1;
	} else{
		return 0;
	}
}

?>

解説

今回は定義した関数から解説していきます。

ファイルの一覧を取得

ファイルの一覧を取得するにはscandirメソッドを利用します。
scandirでは指定したディレクトリにあるファイルとディレクトリを全てリスト化できます。

ここでWindowsユーザには余り馴染みが無い “.” と “..” という特殊なファイルが出てきます。
LinuxやHTMLを触ったことがある方ならなんとなく分かると思いますが、 “.” は今いるディレクトリを、 “..” は一つ上の階層のディレクトリを表します。
従って、これらをリストから削除する必要があります。

また、scandirは下位のディレクトリのファイルは取得できないのでディレクトリがある場合には再帰的に取得していく必要があります。

// 画像一覧の相対パスを取得
function getImagesList($dir){
	$list = array();
	$files = scandir($dir);
	foreach($files as $file){
		if($file == '.' || $file == '..' || (!preg_match('/jpg$/i', $file) && is_file($dir. $file)) || preg_match('/(default.jpg|loading.jpg|cache)/i', $file)){
			continue;
		} else if(is_file($dir. $file)){
			$list[] = $dir. $file;
		} else if( is_dir($dir. $file)){
			$list   = array_merge($list, getImagesList($dir.$file.'/'));
		}
	}

	// $list をファイルの更新日時でソート
	usort($list, 'order_by_desc') ;
	
	return $list;
}

foreachでは指定された配列の一つ一つを順番に変数に代入して処理を行います。
foreach(配列 as 代入される変数) と書きます。

ここでは先ほどscandirで現在のディレクトリにあるファイルとディレクトリが配列に入っているので一つずつ確認していき、”jpg” が末尾にあるファイルだけを取得します。
但し、default.jpgとloading.jpgはリンク切れや読み込み中に表示させる画像にしているので除外します。また、キャッシュ用の画像も除外します。(必要に応じて)

PHPでは$array[]に代入すると配列$arrayの最後に要素が追加されます。
そして、ディレクトリだった時はそのディレクトリパスを指定して関数を再帰させます。
array_mergeメソッドで配列を結合します。

こうすることで指定ディレクトリ以下にある全てのファイルをリストアップできます。

ファイル一覧の並び替え

Javascriptでも処理できますが、PHPで処理させます。
どちらでやっても同じようにできるのでお好きな方で処理して下さい。
(理由は忘れましたが)

// 撮影日時でソートする
function order_by_desc($a, $b){
	$a_exif_data = exif_read_data($a, 0, true);
	$b_exif_data = exif_read_data($b, 0, true);
	$a_date      = isset($a_exif_data['EXIF']['DateTimeOriginal']) ? $a_exif_data['EXIF']['DateTimeOriginal'] : filemtime($a);
	$b_date      = isset($b_exif_data['EXIF']['DateTimeOriginal']) ? $b_exif_data['EXIF']['DateTimeOriginal'] : filemtime($b);
	if($a_date > $b_date){
		return -1;
	} else if($a_date < $b_date){
		return 1;
	} else{
		return 0;
	}
}

ここではEXIFから撮影日時を取得してより新しものが前にくるようにします。
※並べ替え自体はusort($list, 'order_by_desc')で実行します。

ここで、EXIFが無い画像の場合はファイルの更新日時を取得するようにしています。
三項演算子でスッキリと記述しています。

EXIF情報の取得

最後にファイル一覧の画像からEXIF情報を取得していきます。

外部からJavascriptで呼び出して、直接グローバル変数として使用する為に変数名をアドレスのサーチ情報に入れて変数名とします。
"file_list.php?var=任意の変数名" で任意の変数名にリストが代入できます。

// 出力する変数名をURLから取得
$var_name = 'gallery_list';
if (!empty($_GET['var'])) {
	$var_name = $_GET['var'];
}
 
$result = getImagesList($dir);

print_r('var '.$var_name.'=[');

foreach($result as $file){
	$exif_data = exif_read_data($file, 0, true);
	$date      = isset($exif_data['EXIF']['DateTimeOriginal']) ? $exif_data['EXIF']['DateTimeOriginal'] : date('Y:m:d H:i:s', filemtime($file));
	$lens      = @end($exif_data['EXIF']);  // レンズ名
	$focal     = $exif_data['EXIF']['FocalLength'];  // 焦点距離 : '***'mm
	$focal     = explode('/', $focal);
	if($focal[1]){
		$focal = $focal[0]/$focal[1];
	} else{
		$focal = '不明';
	}
	$aperture  = $exif_data['COMPUTED']['ApertureFNumber'];  // 絞り値 : 'f/***'
	$shutter   = $exif_data['EXIF']['ExposureTime'];  // シャッター速度 : '***' sec
	$shutter   = explode('/', $shutter);
	if($shutter[1]){
		if($shutter[0]/$shutter[1] > 0.2){
			$shutter = $shutter[0]/$shutter[1];
		} else{
			$shutter = $shutter[0].'/'.$shutter[1];
		}
	} else{
		$shutter = '不明';
	}
	$ISO       = $exif_data['EXIF']['ISOSpeedRatings'];  // ISO感度 : ISO'***'
	$camera    = $exif_data['IFD0']['Make'].' '.$exif_data['IFD0']['Model'];  // 機種名 : 'メーカ 機種名'
	if($camera == ''){ $camera = '不明'; }
	$EVvias    = $exif_data['EXIF']['ExposureBiasValue'];  // 露出補正値 : '***'EV
	if($EVvias*1 == 0){ $EVvias = '±0.0'; }
	$modeN     = $exif_data['EXIF']['ExposureProgram'];
	     if($modeN == 1){ $mode = 'M-mode'; }
	else if($modeN == 2){ $mode = 'P-mode'; }
	else if($modeN == 3){ $mode = 'A-mode'; }
	else if($modeN == 4){ $mode = 'S-mode'; }
	else                { $mode = 'Undifined-mode'; }
	$rotate    = 0;
	switch($exif_data['IFD0']['Orientation']){
		case 3:
			$rotate = 180;
		break;
		case 6:
			$rotate = 270;
		break;
		case 8:
			$rotate =  90;
		break;
	}

	$path = explode($dir, $file);
	$path = './'.$path[1];
	print_r('{\n');
	print_r('\t"path"     : "'.$path.'", \n');
	print_r('\t"date"     : "'.$date.'", \n');
	print_r('\t"lens"     : "'.$lens.'", \n');
	print_r('\t"focal"    : "'.$focal.'", \n');
	print_r('\t"aperture" : "'.$aperture.'", \n');
	print_r('\t"shutter"  : "'.$shutter.'", \n');
	print_r('\t"ISO"      : "'.$ISO.'", \n');
	print_r('\t"camera"   : "'.$camera.'", \n');
	print_r('\t"EV"       : "'.$EVvias.'", \n');
	print_r('\t"mode"     : "'.$mode.'",\n');
	print_r('\t"rotate"   :  '.$rotate.'\n');
	print_r('}, \n');
}

特殊変数の "$_GET" にサーチ情報が格納されているので、それを取得します。
指定がない場合は、"gallery_list" という変数とします。

EXIF情報はexif_read_dataメソッドで一括で色々な情報が取得できます。
どんなデータ形式で保存されているかは以下のページを参考にして下さい。

・PHP & JavaScript Room - Exif関数(変更可能な画像情報)
・ObjecTips - 画像のExifデータの取得方法と取得データの比較 iOS
・eto-noriaki.net - Exifデータの表示方法

必要なEXIF情報が取得できたら、Javascriptの連想配列の形で (文字列として) 出力していきます。
連想配列とすることで分かりやすい名前で後から利用できます。

まとめ

以上、ファイルリストの取得とEXIF情報取得の方法でした。

もっと簡単に書けないかなーと調べたらあったのですが、PHPのバージョンによっては対応していないらしいので今回の方法としました。

間違いやご指摘、ご質問等あればコメントやお問合せからお願いします。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)