exif_read_data
(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)
exif_read_data — 画像ファイルから EXIF ヘッダを読み込む
説明
resource|string
$file
,?string
$required_sections
= null
,bool
$as_arrays
= false
,bool
$read_thumbnail
= false
): array|false
exif_read_data() は、 画像ファイルから EXIF ヘッダを読み込みます。この方法で、デジタルカメラが生成したメタデータを 読み込むことが可能です。
EXIF ヘッダは、デジタルカメラが作成した JPEG/TIFF 画像によく含まれています。しかし残念なことに、 そのタグ付けの方法はメーカーによって異なります。 したがって、特定の Exif ヘッダが常に存在すると仮定することはできません。
Height
および Width
は、getimagesize() と同じ方法で計算されます。
よって、これらの値は決してヘッダの一部として返してはいけません。
また、html
は高さ/幅を表すテキスト文字列で、
通常の HTML の中で用いられます。
Exif ヘッダに著作権表示が含まれている場合、それ自身には 2 つの値を
含めることが可能です。Exif 2.10 のこの矛盾した規格に対応するため、
COMPUTED
セクションは Copyright.Photographer
および Copyright.Editor
の両方を返します。
また IFD0
セクションには 2 つのエントリを NULL 文字で区切った
バイト配列を含めます。データ型が間違っている場合は最初のエントリのみを
かえします(Exif の通常の挙動)。COMPUTED
には、元の著作権文字列あるいは
カンマで区切られた写真と編集者の著作権表示のどちらかを
Copyright
エントリに含めることが可能です。
UserComment
タグにも Copyright タグと同様の問題があります。ここにも
2 つの値を格納することが可能です。それは使用しているエンコーディングと
値自身の 2 つです。そうなると、IFD
セクションにはエンコーディングのみを
含めるか、あるいはバイト配列を格納することになります。COMPUTED
セクションは
UserCommentEncoding
および UserComment
を両方格納することができます。UserComment
はどちらの
場合でも有効なので、IFD0
セクションではこちらを優先すべきです。
exif_read_data() は、EXIF 仕様(» http://exif.org/Exif2-2.PDF, 20 ページ)に基づいて EXIF データタグの検証も行います。
パラメータ
file
-
画像ファイルの位置。 ファイルのパス (ストリームラッパーもいつもどおりサポートされています) またはストリームresource。
required_sections
-
結果の配列を作成するために存在する必要のあるセクションのカンマ区切り リスト。要求されたセクションがひとつも見つからなかった場合の戻り値は
false
となります。FILE FileName, FileSize, FileDateTime, SectionsFound COMPUTED html, Width, Height, IsColor, および他の取得可能なもの。Height および Width は getimagesize() と同じ方法で取得した もので、その値はヘッダの一部ではありません。また、 html
は 通常の HTML 内で使用される height/width の 文字列です。ANY_TAG タグを有するすべての情報。例えば IFD0
,EXIF
, ...IFD0 IFD0 のすべてのタグつきデータ。通常の画像ファイルでは、 ここに画像のサイズが含まれます。 THUMBNAIL 2 番目の IFD
がある場合、ファイルにサムネイルが含まれている 可能性があります。埋め込まれたサムネイルに関するすべての タグつき情報はこのセクションに格納されます。COMMENT JPEG 画像のコメントヘッダ。 EXIF EXIF セクションは IFD0
のサブセクションです。ここには 画像に関する詳細な情報が含まれています。これらのエントリの ほとんどはデジタルカメラに関連するものです。 as_arrays
-
各セクションを配列とするかどうかを指定します。
required_sections
のCOMPUTED
、THUMBNAIL
およびCOMMENT
は常に配列となります。これは、これらのセクションに 含まれる値の名前が他のセクションと衝突する可能性があるからです。 read_thumbnail
-
true
を指定すると、サムネイル本体を読み込みます。それ以外の場合は タグつきデータのみを読み込みます。
戻り値
ヘッダ名がキー・ヘッダの内容が値となる連想配列を返します。
返されるデータがない場合は
exif_read_data() は false
を返します。
エラー / 例外
サポートされていないタグや、エラーが起きうる条件が指定された場合は、
E_WARNING
かつ/または E_NOTICE
が発生します。
警告が発生しても、この関数は対応する情報を全て読み取ろうとします。
変更履歴
バージョン | 説明 |
---|---|
8.0.0 |
required_sections は、nullable になりました。
|
7.2.0 |
file パラメータは
ローカルファイルとストリームリソースを両方サポートするようになりました。
|
7.2.0 |
以下の EXIF フォーマットのサポートが追加されました:
|
例
例1 exif_read_data() の例
<?php
echo "test1.jpg:<br />\n";
$exif = exif_read_data('tests/test1.jpg', 'IFD0');
echo $exif===false ? "No header data found.<br />\n" : "Image contains headers<br />\n";
$exif = exif_read_data('tests/test2.jpg', 0, true);
echo "test2.jpg:<br />\n";
foreach ($exif as $key => $section) {
foreach ($section as $name => $val) {
echo "$key.$name: $val<br />\n";
}
}
?>
最初のコールは失敗します。画像がヘッダ情報を有していないためです。
上の例の出力は、 たとえば以下のようになります。
test1.jpg: No header data found. test2.jpg: FILE.FileName: test2.jpg FILE.FileDateTime: 1017666176 FILE.FileSize: 1240 FILE.FileType: 2 FILE.SectionsFound: ANY_TAG, IFD0, THUMBNAIL, COMMENT COMPUTED.html: width="1" height="1" COMPUTED.Height: 1 COMPUTED.Width: 1 COMPUTED.IsColor: 1 COMPUTED.ByteOrderMotorola: 1 COMPUTED.UserComment: Exif test image. COMPUTED.UserCommentEncoding: ASCII COMPUTED.Copyright: Photo (c) M.Boerger, Edited by M.Boerger. COMPUTED.Copyright.Photographer: Photo (c) M.Boerger COMPUTED.Copyright.Editor: Edited by M.Boerger. IFD0.Copyright: Photo (c) M.Boerger IFD0.UserComment: ASCII THUMBNAIL.JPEGInterchangeFormat: 134 THUMBNAIL.JPEGInterchangeFormatLength: 523 COMMENT.0: Comment #1. COMMENT.1: Comment #2. COMMENT.2: Comment #3end THUMBNAIL.JPEGInterchangeFormat: 134 THUMBNAIL.Thumbnail.Height: 1 THUMBNAIL.Thumbnail.Height: 1
例2 PHP 7.2.0 で利用できるストリームを exif_read_data() で使う例
<?php
// Open a the file, this should be in binary mode
$fp = fopen('/path/to/image.jpg', 'rb');
if (!$fp) {
echo 'Error: Unable to open image for reading';
exit;
}
// Attempt to read the exif headers
$headers = exif_read_data($fp);
if (!$headers) {
echo 'Error: Unable to read exif headers';
exit;
}
// Print the 'COMPUTED' headers
echo 'EXIF Headers:' . PHP_EOL;
foreach ($headers['COMPUTED'] as $header => $value) {
printf(' %s => %s%s', $header, $value, PHP_EOL);
}
?>
上の例の出力は、 たとえば以下のようになります。
EXIF Headers: Height => 576 Width => 1024 IsColor => 1 ByteOrderMotorola => 0 ApertureFNumber => f/5.6 UserComment => UserCommentEncoding => UNDEFINED Copyright => Denis Thumbnail.FileType => 2 Thumbnail.MimeType => image/jpeg
注意
注意:
mbstring が有効な場合、 exif はUnicodeを処理し、 exif.decode_unicode_motorola および exif.decode_unicode_intel で指定された文字コードとして取り出そうとします。 exif 拡張モジュールはエンコーディングを自分自身で探そうとはしないので、 exif_read_data() を呼ぶ前に、 これらの ini ディレクティブのうちのひとつに どのエンコーディングをデコードに使うかを適切に設定するのはユーザーの責任です。
注意:
この関数にストリームを渡すために
file
を使った場合、 ストリームはシーク可能でなければなりません。 ファイルポインタの位置は、関数から戻った後でも変化しないことに注意してください。
User Contributed Notes 19 notes
When the new update came out from Apple for iOS6 it provided the ability for iPad, iPod, and iPhones to be able to upload files from the device through Safari. Obviously this will open up an array of implementations where at one point it was just not possible.
The issue comes when a photo is uploaded it will be dependent on the location of the "button" when the photo was taken. Imagine if you will that you have your iPhone turned with the button at the top and you take a photo. The photo when uploaded to your server might be "upside down".
The following code will ensure that all uploaded photos will be oriented correctly upon upload:
<?php
$image = imagecreatefromstring(file_get_contents($_FILES['image_upload']['tmp_name']));
$exif = exif_read_data($_FILES['image_upload']['tmp_name']);
if(!empty($exif['Orientation'])) {
switch($exif['Orientation']) {
case 8:
$image = imagerotate($image,90,0);
break;
case 3:
$image = imagerotate($image,180,0);
break;
case 6:
$image = imagerotate($image,-90,0);
break;
}
}
// $image now contains a resource with the image oriented correctly
?>
What you do with the image resource from there is entirely up to you.
I hope that this helps you identify and orient any image that's uploaded from an iPad, iPhone, or iPod. Orientation for the photo is the key to knowing how to rotate it correctly.
The following code:
<?php
$data = exif_read_data('foo.jpg');
var_dump($data['Keywords']);
?>
produces string(15) "???????????????"
Adding
<?php
ini_set('exif.decode_unicode_motorola', 'UCS-2LE');
?>
before the call to exif_red_data produces
string(15) "landscape;;field"
I wanted some quick and easy functions for computing the shutter speed and f-stop. I couldn't find any anywhere, so I made some. It took some research :
<?php
function exif_get_float($value) {
$pos = strpos($value, '/');
if ($pos === false) return (float) $value;
$a = (float) substr($value, 0, $pos);
$b = (float) substr($value, $pos+1);
return ($b == 0) ? ($a) : ($a / $b);
}
function exif_get_shutter(&$exif) {
if (!isset($exif['ShutterSpeedValue'])) return false;
$apex = exif_get_float($exif['ShutterSpeedValue']);
$shutter = pow(2, -$apex);
if ($shutter == 0) return false;
if ($shutter >= 1) return round($shutter) . 's';
return '1/' . round(1 / $shutter) . 's';
}
function exif_get_fstop(&$exif) {
if (!isset($exif['ApertureValue'])) return false;
$apex = exif_get_float($exif['ApertureValue']);
$fstop = pow(2, $apex/2);
if ($fstop == 0) return false;
return 'f/' . round($fstop,1);
}
?>
Please note that when resizing images with GD and most image processing scripts or applications you will loose the EXIF information. What I did as a workaround is book this information into MySQL before I re-size images.
<?php
// This function is used to determine the camera details for a specific image. It returns an array with the parameters.
function cameraUsed($imagePath) {
// Check if the variable is set and if the file itself exists before continuing
if ((isset($imagePath)) and (file_exists($imagePath))) {
// There are 2 arrays which contains the information we are after, so it's easier to state them both
$exif_ifd0 = read_exif_data($imagePath ,'IFD0' ,0);
$exif_exif = read_exif_data($imagePath ,'EXIF' ,0);
//error control
$notFound = "Unavailable";
// Make
if (@array_key_exists('Make', $exif_ifd0)) {
$camMake = $exif_ifd0['Make'];
} else { $camMake = $notFound; }
// Model
if (@array_key_exists('Model', $exif_ifd0)) {
$camModel = $exif_ifd0['Model'];
} else { $camModel = $notFound; }
// Exposure
if (@array_key_exists('ExposureTime', $exif_ifd0)) {
$camExposure = $exif_ifd0['ExposureTime'];
} else { $camExposure = $notFound; }
// Aperture
if (@array_key_exists('ApertureFNumber', $exif_ifd0['COMPUTED'])) {
$camAperture = $exif_ifd0['COMPUTED']['ApertureFNumber'];
} else { $camAperture = $notFound; }
// Date
if (@array_key_exists('DateTime', $exif_ifd0)) {
$camDate = $exif_ifd0['DateTime'];
} else { $camDate = $notFound; }
// ISO
if (@array_key_exists('ISOSpeedRatings',$exif_exif)) {
$camIso = $exif_exif['ISOSpeedRatings'];
} else { $camIso = $notFound; }
$return = array();
$return['make'] = $camMake;
$return['model'] = $camModel;
$return['exposure'] = $camExposure;
$return['aperture'] = $camAperture;
$return['date'] = $camDate;
$return['iso'] = $camIso;
return $return;
} else {
return false;
}
}
?>
An example of it's use follows:
<?php
$camera = cameraUsed("/img/myphoto.jpg");
echo "Camera Used: " . $camera['make'] . " " . $camera['model'] . "<br />";
echo "Exposure Time: " . $camera['exposure'] . "<br />";
echo "Aperture: " . $camera['aperture'] . "<br />";
echo "ISO: " . $camera['iso'] . "<br />";
echo "Date Taken: " . $camera['date'] . "<br />";
?>
Will display the following, depending on the data:
Camera Used: SONY DSC-S930
Exposure Time: 1/400
Aperture: f/4.3
ISO: 100
Date Taken: 2010:12:10 18:18:45
If the image has been re-sized and the information is no longer available then you should receive the following when echoing the same:
Camera Used: Unavailable
Exposure Time: Unavailable
Aperture: Unavailable
ISO: Unavailable
Date Taken: Unavailable
Some cameras do not capture all the information, for instance Blackberry phones do not record an aperture, or iso and you will get Unavailable for those fields.
I hope you find this helpful.