Aún así, puede ser un recurso útil si estamos interesados en mostrar la información de las fotos, tal como lo hacen sitios como Flickr, y más aún con el buzz de geolocalizar a los usuarios y sus contenidos. ¿Qué tipo de contenidos incluye el EXIF?

  • Fecha y hora en que fue tomada la foto (independiente de las del archivo en sí)
  • Información de la cámara con que fue tomada (modelo y fabricante)
  • Condiciones en que fue capturada (Valor ISO, Orientación de la cámara, apertura, longitud focal, etc..).
  • Coordenadas GPS del lugar donde fue capturada. (Solo si la cámara incluye un receptor GPS, es más común en las cámaras de los smartphones)

Hay que tener en cuenta que el EXIF no es un estándar, ni es controlado por una entidad, asi que cada fabricante puede incluir diferente información en este, incluso entre diferentes modelos de cámaras.

Desde PHP hay dos opciones para leer la información contenida en el EXIF:

Extensión EXIF

PHP ya incluye una extensión para leer el EXIF, esta quizás la forma más recomendada. Al ser una extensión, dependes de que tu servidor ya la tenga instalada/habilitada antes usarla; si tienes el acceso apropiado probablemente puedas instalarla tu mismo si es necesario.

En caso que queramos conocer la información genérica del EXIF, basta con hacer una llamada a exif_read_data() y ver que elementos del array están definidos:

$exif = exif_read_data( $file );

if ( !empty($exif['FNumber'] ) )
	$aperture = $exif['FNumber'];
if ( !empty($exif['Model'] ) )
	$camera = trim( $exif['Model'] );
if ( !empty($exif['DateTimeDigitized'] ) )
	$pic_date = $exif['DateTimeDigitized'];
if ( !empty($exif['FocalLength'] ) )
	$focal_length = $exif['FocalLength'];
if ( !empty($exif['ISOSpeedRatings'] ) )
	$iso = trim( $exif['ISOSpeedRatings'];
if ( !empty($exif['ExposureTime'] ) )
	$shutter_speed = $exif['ExposureTime'];

Es importante revisar que cada elemento esté definido, ya que no hay garantías de estarlo. Esta extensión entrega los datos tal cual vienen en el EXIF (y como strings), necesitamos convertirlos a un formato a apropiado según sea.

// Convertir un string "1/123" a su representación float
function exif_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);
} 

// Esta función de WordPress convierte la fecha del EXIF (YYYY:MM:DD HH:MM:SS) a Unixtime
// /wp-admin/includes/image.php
function wp_exif_date2ts($str) {
	@list( $date, $time ) = explode( ' ', trim($str) );
	@list( $y, $m, $d ) = explode( ':', $date );
  
	return strtotime( "{$y}-{$m}-{$d} {$time}" );
}

$shutter_speed = exif_float( $exif['ExposureTime'] );
$pic_date = wp_exif_date2ts($exif['DateTimeDigitized'] );

Similar para leer las coordenadas GPS en el EXIF y convertirlas de formato Grados, minutos y segundos a Grados en decimal:

if ( !empty($exif['GPSLongitude']) && !empty($exif['GPSLatitude']) ) {
	$d = (float) $exif['GPSLongitude'][0];
	$m = exif_float($exif['GPSLongitude'][1] );
	$s = exif_float( $exif['GPSLongitude'][2] );
	
	$gps_longitude = (float) $d + $m/60 + $s/3600;
	if ( $exif['GPSLongitudeRef'] == 'W')
		$gps_longitude = -$gps_longitude;
	
	$d = $exif['GPSLatitude'][0];
	$m = exif_float($exif['GPSLatitude'][1] );
	$s = exif_float( $exif['GPSLatitude'][2] );
	
	$gps_latitude = (float) $d + $m/60 + $s/3600;
	if ( $exif['GPSLatitudeRef'] == 'S')
		$gps_latitude = -$gps_latitude;
}

Exifixer

Otra opción es usar Exifixer de Zenphoto que en teoría debería leer datos específicos de ciertos fabricantes; y además que es independiente de la configuración de PHP, para los que requieran mayor portabilidad de su aplicación PHP, o bien no tienen opción a modificar el servidor.

La forma de leer los datos es similar, aunque la estructura del array es diferente:

$exif = read_exif_data_raw( $file, false );

if ( !empty($exif['SubIFD']['FNumber']) )
	$aperture = $exif['SubIFD']['FNumber'];
if ( !empty($exif['IFD0']['Model']) )
	$model = $exif['IFD0']['Model'];
if ( !empty($exif['SubIFD']['DateTimeOriginal']) )
	$pic_date = $exif['SubIFD']['DateTimeOriginal'];
if ( !empty(['SubIFD']['FocalLength']) )
	$focal_length = ['SubIFD']['FocalLength'];
if ( !empty(['SubIFD']['ISOSpeedRatings']) )
	$iso = ['SubIFD']['ISOSpeedRatings'];
if ( !empty(['SubIFD']['ExposureTime']) )
	$shutter_speed = ['SubIFD']['ExposureTime'];

if ( !empty($exif['GPS'] )) {
	$gps_longitude = $exif['GPS']['Longitude']; 
	if ( $exif['GPS']['Longitude Reference'] == 'W')
		$gps_longitude = -$gps_longitude;
	
	$gps_latitude = $exif['GPS']['Latitude']; 
	if ( $exif['GPS']['Latitude Reference'] == 'S')
		$gps_latitude = -$gps_latitude;
}

Un detalle con Exifixer es que las fracciones ya las convierte a su representación float (y en muchos casos hay un equivalente string con diferente nombre).

Bonus: Eliminar el EXIF de una foto

Muchos programas de edición/administración de fotografías digitales ya incluyen una opción para eliminar el EXIF; sino existe Exifremover.com y ExifTool para dicho fin :)