<?php

class EXIF
{
	public $aperture = 0;
	public $credit = '';
	public $camera = '';
	public $caption = '';
	public $created_timestamp = 0;
	public $copyright = '';
	public $focal_length = 0;
	public $iso = 0;
	public $shutter_speed = 0;
	public $title = '';
	public $software = '';

	private function __construct(array $meta)
	{
		foreach ($meta as $key => $value)
			$this->$key = $value;
	}

	public static function fromFile($file, $as_array = false, $override_cache = false)
	{
		if (!file_exists($file))
			return false;

		$meta = [
			'aperture' => 0,
			'credit' => '',
			'camera' => '',
			'caption' => '',
			'created_timestamp' => 0,
			'copyright' => '',
			'focal_length' => 0,
			'iso' => 0,
			'shutter_speed' => 0,
			'title' => '',
			'software' => '',
		];

		if (!function_exists('exif_read_data'))
			throw new Exception("The PHP module 'exif' appears to be disabled. Please enable it to use EXIF functions.");

		list(, , $image_type) = getimagesize($file);
		if (!in_array($image_type, [IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM]))
			return new self($meta);

		$exif = @exif_read_data($file);

		if (!empty($exif['Title']))
			$meta['title'] = trim($exif['Title']);

		if (!empty($exif['ImageDescription']))
		{
			if (empty($meta['title']) && strlen($exif['ImageDescription']) < 80)
			{
				$meta['title'] = trim($exif['ImageDescription']);
				if (!empty($exif['COMPUTED']['UserComment']) && trim($exif['COMPUTED']['UserComment']) != $meta['title'])
					$meta['caption'] = trim($exif['COMPUTED']['UserComment']);
			}
			elseif (trim($exif['ImageDescription']) != $meta['title'])
				$meta['caption'] = trim($exif['ImageDescription']);
		}
		elseif (!empty($exif['Comments']) && trim($exif['Comments']) != $meta['title'])
			$meta['caption'] = trim($exif['Comments']);

		if (!empty($exif['Artist']))
			$meta['credit'] = trim($exif['Artist']);
		elseif (!empty($exif['Author']))
			$meta['credit'] = trim($exif['Author']);

		if (!empty($exif['Copyright']))
			$meta['copyright'] = trim($exif['Copyright']);

		if (!empty($exif['ExposureTime']))
			$meta['shutter_speed'] = (string) self::frac2dec($exif['ExposureTime']);

		if (!empty($exif['FNumber']))
			$meta['aperture'] = round(self::frac2dec($exif['FNumber']), 2);

		if (!empty($exif['FocalLength']))
			$meta['focal_length'] = (string) self::frac2dec($exif['FocalLength']);

		if (!empty($exif['ISOSpeedRatings']))
		{
			$meta['iso'] = is_array($exif['ISOSpeedRatings']) ? reset($exif['ISOSpeedRatings']) : $exif['ISOSpeedRatings'];
			$meta['iso'] = trim($meta['iso']);
		}

		if (!empty($exif['Model']))
		{
			if (strpos($exif['Model'], 'PENTAX') !== false)
				$meta['camera'] = trim($exif['Model']);
			elseif (!empty($exif['Make']) && strpos($exif['Model'], $exif['Make']) === false)
				$meta['camera'] = trim($exif['Make']) . ' ' . trim($exif['Model']);
			else
				$meta['camera'] = trim($exif['Model']);
		}
		elseif (!empty($exif['Make']))
			$meta['camera'] = trim($exif['Make']);

		if (!empty($exif['DateTimeOriginal']))
			$meta['created_timestamp'] = self::toUnixTime($exif['DateTimeOriginal']);
		elseif (!empty($exif['DateTimeDigitized']))
			$meta['created_timestamp'] = self::toUnixTime($exif['DateTimeDigitized']);

		if (!empty($exif['Software']))
			$meta['software'] = $exif['Software'];

		return new self($meta);
	}

	public function shutterSpeedFraction()
	{
		$speed = $this->shutter_speed;
		if (empty($this->shutter_speed))
			return '';

		if (1 / $this->shutter_speed <= 1)
			return $this->shutter_speed . ' seconds';

		$speed = (float) 1 / $this->shutter_speed;
		if (in_array($speed, [1.3, 1.5, 1.6, 2.5]))
			return "1/" . number_format($speed, 1, '.', '') . ' second';
		else
			return "1/" . number_format($speed, 0, '.', '') . ' second';
	}

	// Convert a fraction string to a decimal.
	private static function frac2dec($str)
	{
		@list($n, $d) = explode('/', $str);
		return !empty($d) ? $n / $d : $str;
	}

	// Convert an EXIF formatted date to a UNIX timestamp.
	private static function toUnixTime($str)
	{
		@list($date, $time) = explode(' ', trim($str));
		@list($y, $m, $d) = explode(':', $date);
		return strtotime("{$y}-{$m}-{$d} {$time}");
	}
}