Issues (902)

exif/exif.php (1 issue)

1
<?php
2
/**
3
*
4
* @package phpBB Gallery - Exif Extension
5
* @copyright (c) 2012 nickvergessen - http://www.flying-bits.org/
6
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
7
*
8
*/
9
10
namespace phpbbgallery\exif;
11
12
/**
13
* Base class for Exif handling
14
*/
15
class exif
16
{
17
	/**
18
	* Default value for new users
19
	*/
20
	const DEFAULT_DISPLAY	= true;
21
22
	/**
23
	* phpBB will treat the time from the Exif data like UTC.
24
	* If your images were taken with an other timezone, you can insert an offset here.
25
	* The offset is than added to the timestamp before it is converted into the users time.
26
	*
27
	* Offset must be set in seconds.
28
	*/
29
	const TIME_OFFSET	= 0;
30
31
	/**
32
	* Constants for the status of the Exif data.
33
	*/
34
	const UNAVAILABLE	= 0;
35
	const AVAILABLE		= 1;
36
	const UNKNOWN		= 2;
37
	const DBSAVED		= 3;
38
39
	/**
40
	* Is the function available?
41
	*/
42
	static public $function_exists = null;
43
44
	/**
45
	* Exif data array with all allowed groups and keys.
46
	*/
47
	public $data		= array();
48
49
	/**
50
	* Filtered data array. We don't have empty or invalid values here.
51
	*/
52
	public $prepared_data	= array();
53
54
	/**
55
	* Does the image have exif data?
56
	* Values see constant declaration at the beginning of the class.
57
	*/
58
	public $status		= 2;
59
60
	/**
61
	* Full data array, but serialized to a string
62
	*/
63
	public $serialized	= '';
64
65
	/**
66
	* Full link to the image-file
67
	*/
68
	public $file		= '';
69
70
	/**
71
	* Original status of the Exif data.
72
	*/
73
	public $orig_status = null;
74
75
	/**
76
	* Image-ID, just needed to update the Exif status
77
	*/
78
	public $image_id	= false;
79
80
	/**
81
	* Constructor
82
	*
83
	* @param	string	$file		Full link to the image-file
84
	* @param	mixed	$image_id	False or integer
85
	*/
86
	public function __construct($file, $image_id = false)
87
	{
88
		if (self::$function_exists === null)
89
		{
90
			self::$function_exists = (function_exists('exif_read_data')) ? true : false;
91
		}
92
		if ($image_id)
93
		{
94
			$this->image_id = (int) $image_id;
95
		}
96
97
		$this->file = $file;
98
	}
99
100
	/**
101
	* Interpret the values from the database, and read the data if we don't have it.
102
	*
103
	* @param	int		$status		Value of a status constant (see beginning of the class)
104
	* @param	mixed	$data		Either an empty string or the serialized array of the Exif from the database
105
	*/
106
	public function interpret($status, $data)
107
	{
108
		$this->orig_status = $status;
109
		$this->status = $status;
110
		if ($this->status == self::DBSAVED)
111
		{
112
			$this->data = @unserialize($data);
113
		}
114
		else if (($this->status == self::AVAILABLE) || ($this->status == self::UNKNOWN))
115
		{
116
			$this->read();
117
		}
118
	}
119
120
	/**
121
	* Read Exif data from the image
122
	*/
123
	public function read()
124
	{
125
		if (!self::$function_exists || !$this->file || !file_exists($this->file))
126
		{
127
			return;
128
		}
129
130
		$this->data = @exif_read_data($this->file, 0, true);
131
132
		if (!empty($this->data["EXIF"]))
133
		{
134
			// Unset invalid Exif's
135
			foreach ($this->data as $key => $array)
136
			{
137
				if (!in_array($key, self::$allowed_groups))
138
				{
139
					unset($this->data[$key]);
140
				}
141
				else
142
				{
143
					foreach ($this->data[$key] as $subkey => $array)
0 ignored issues
show
Comprehensibility Bug introduced by
$array is overwriting a variable from outer foreach loop.
Loading history...
144
					{
145
						if (!in_array($subkey, self::$allowed_keys))
146
						{
147
							unset($this->data[$key][$subkey]);
148
						}
149
					}
150
				}
151
			}
152
153
			$this->serialized = serialize($this->data);
154
			$this->status = self::DBSAVED;
155
		}
156
		else
157
		{
158
			$this->status = self::UNAVAILABLE;
159
		}
160
161
		if ($this->image_id)
162
		{
163
			$this->set_status();
164
		}
165
	}
166
167
	/**
168
	* Validate and prepare the data, so we can send it into the template.
169
	*/
170
	private function prepare_data()
171
	{
172
		global $user;
173
174
		$user->add_lang_ext('phpbbgallery/exif', 'exif');
175
176
		$this->prepared_data = array();
177
		if (isset($this->data["EXIF"]["DateTimeOriginal"]))
178
		{
179
			$timestamp_year = (int) substr($this->data["EXIF"]["DateTimeOriginal"], 0, 4);
180
			$timestamp_month = (int) substr($this->data["EXIF"]["DateTimeOriginal"], 5, 2);
181
			$timestamp_day = (int) substr($this->data["EXIF"]["DateTimeOriginal"], 8, 2);
182
			$timestamp_hour = (int) substr($this->data["EXIF"]["DateTimeOriginal"], 11, 2);
183
			$timestamp_minute = (int) substr($this->data["EXIF"]["DateTimeOriginal"], 14, 2);
184
			$timestamp_second = (int) substr($this->data["EXIF"]["DateTimeOriginal"], 17, 2);
185
			$timestamp = (int) @mktime($timestamp_hour, $timestamp_minute, $timestamp_second, $timestamp_month, $timestamp_day, $timestamp_year);
186
			if ($timestamp)
187
			{
188
				$this->prepared_data['exif_date'] = $user->format_date($timestamp + self::TIME_OFFSET);
189
			}
190
		}
191
		if (isset($this->data["EXIF"]["FocalLength"]))
192
		{
193
			list($num, $den) = explode("/", $this->data["EXIF"]["FocalLength"]);
194
			if ($den)
195
			{
196
				$this->prepared_data['exif_focal'] = sprintf($user->lang['EXIF_FOCAL_EXP'], ($num / $den));
197
			}
198
		}
199
		if (isset($this->data["EXIF"]["ExposureTime"]))
200
		{
201
			list($num, $den) = explode("/", $this->data["EXIF"]["ExposureTime"]);
202
			$exif_exposure = '';
203
			if (($num > $den) && $den)
204
			{
205
				$exif_exposure = $num / $den;
206
			}
207
			else if ($num)
208
			{
209
				$exif_exposure = ' 1/' . $den / $num ;
210
			}
211
			if ($exif_exposure)
212
			{
213
				$this->prepared_data['exif_exposure'] = sprintf($user->lang['EXIF_EXPOSURE_EXP'], $exif_exposure);
214
			}
215
		}
216
		if (isset($this->data["EXIF"]["FNumber"]))
217
		{
218
			list($num, $den) = explode("/", $this->data["EXIF"]["FNumber"]);
219
			if ($den)
220
			{
221
				$this->prepared_data['exif_aperture'] = "F/" . ($num / $den);
222
			}
223
		}
224
		if (isset($this->data["EXIF"]["ISOSpeedRatings"]) && !is_array($this->data["EXIF"]["ISOSpeedRatings"]))
225
		{
226
			$this->prepared_data['exif_iso'] = $this->data["EXIF"]["ISOSpeedRatings"];
227
		}
228
		if (isset($this->data["EXIF"]["WhiteBalance"]))
229
		{
230
			$this->prepared_data['exif_whiteb'] = $user->lang['EXIF_WHITEB_' . (($this->data["EXIF"]["WhiteBalance"]) ? 'MANU' : 'AUTO')];
231
		}
232
		if (isset($this->data["EXIF"]["Flash"]))
233
		{
234
			if (isset($user->lang['EXIF_FLASH_CASE_' . $this->data["EXIF"]["Flash"]]))
235
			{
236
				$this->prepared_data['exif_flash'] = $user->lang['EXIF_FLASH_CASE_' . $this->data["EXIF"]["Flash"]];
237
			}
238
		}
239
		if (isset($this->data["IFD0"]["Model"]))
240
		{
241
			$this->prepared_data['exif_cam_model'] = ucwords($this->data["IFD0"]["Model"]);
242
		}
243
		if (isset($this->data["EXIF"]["ExposureProgram"]))
244
		{
245
			if (isset($user->lang['EXIF_EXPOSURE_PROG_' . $this->data["EXIF"]["ExposureProgram"]]))
246
			{
247
				$this->prepared_data['exif_exposure_prog'] = $user->lang['EXIF_EXPOSURE_PROG_' . $this->data["EXIF"]["ExposureProgram"]];
248
			}
249
		}
250
		if (isset($this->data["EXIF"]["ExposureBiasValue"]))
251
		{
252
			list($num,$den) = explode("/", $this->data["EXIF"]["ExposureBiasValue"]);
253
			if ($den)
254
			{
255
				if (($num / $den) == 0)
256
				{
257
					$exif_exposure_bias = 0;
258
				}
259
				else
260
				{
261
					$exif_exposure_bias = $this->data["EXIF"]["ExposureBiasValue"];
262
				}
263
				$this->prepared_data['exif_exposure_bias'] = sprintf($user->lang['EXIF_EXPOSURE_BIAS_EXP'], $exif_exposure_bias);
264
			}
265
		}
266
		if (isset($this->data["EXIF"]["MeteringMode"]))
267
		{
268
			if (isset($user->lang['EXIF_METERING_MODE_' . $this->data["EXIF"]["MeteringMode"]]))
269
			{
270
				$this->prepared_data['exif_metering_mode'] = $user->lang['EXIF_METERING_MODE_' . $this->data["EXIF"]["MeteringMode"]];
271
			}
272
		}
273
	}
274
275
	/**
276
	* Sends the Exif into the template
277
	*
278
	* @param	bool	$expand_view	Shall we expand the Exif data on page view or collapse?
279
	* @param	string	$block			Name of the template loop the Exif's are displayed in.
280
	*/
281
	public function send_to_template($expand_view = true, $block = 'exif_value')
282
	{
283
		$this->prepare_data();
284
285
		if (!empty($this->prepared_data))
286
		{
287
			global $template, $user;
288
289
			foreach ($this->prepared_data as $exif => $value)
290
			{
291
				$template->assign_block_vars($block, array(
292
					'EXIF_NAME'			=> $user->lang[strtoupper($exif)],
293
					'EXIF_VALUE'		=> htmlspecialchars($value),
294
				));
295
			}
296
			$template->assign_vars(array(
297
				'S_EXIF_DATA'	=> true,
298
				'S_VIEWEXIF'	=> $expand_view,
299
			));
300
		}
301
	}
302
303
	/**
304
	* Save the new Exif status in the database
305
	*/
306
	public function set_status()
307
	{
308
		if (!$this->image_id || ($this->orig_status == $this->status))
309
		{
310
			return false;
311
		}
312
313
		global $db, $table_prefix;
314
315
		$update_data = ($this->status == self::DBSAVED) ? ", image_exif_data = '" . $db->sql_escape($this->serialized) . "'" : '';
316
		$sql = 'UPDATE ' . $table_prefix . 'gallery_images 
317
			SET image_has_exif = ' . $this->status . $update_data . '
318
			WHERE image_id = ' . (int) $this->image_id;
319
		$db->sql_query($sql);
320
	}
321
322
	/**
323
	* There are lots of possible Exif Groups and Values.
324
	* But you will never heard of the missing ones. so we just allow the most common ones.
325
	*/
326
	static private $allowed_groups		= array(
327
		'EXIF',
328
		'IFD0',
329
	);
330
331
	static private $allowed_keys		= array(
332
		'DateTimeOriginal',
333
		'FocalLength',
334
		'ExposureTime',
335
		'FNumber',
336
		'ISOSpeedRatings',
337
		'WhiteBalance',
338
		'Flash',
339
		'Model',
340
		'ExposureProgram',
341
		'ExposureBiasValue',
342
		'MeteringMode',
343
	);
344
}
345