1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Imparse; |
4
|
|
|
|
5
|
|
|
class Parser |
6
|
|
|
{ |
7
|
|
|
private $iptclabels = [ |
8
|
|
|
'1#000' => 'Model Version', |
9
|
|
|
'1#005' => 'Destination', |
10
|
|
|
'1#020' => 'File Format', |
11
|
|
|
'1#022' => 'File Format Version', |
12
|
|
|
'1#030' => 'Service Identifier', |
13
|
|
|
'1#040' => 'Envelope Number', |
14
|
|
|
'1#050' => 'Product I.D.', |
15
|
|
|
'1#060' => 'Envelope Priority', |
16
|
|
|
'1#070' => 'Date Sent', |
17
|
|
|
'1#080' => 'Time Sent', |
18
|
|
|
'1#090' => 'Coded Character Set', |
19
|
|
|
'1#100' => 'UNO', |
20
|
|
|
'1#120' => 'ARM Identifier', |
21
|
|
|
'1#122' => 'ARM Version', |
22
|
|
|
'2#000' => 'Record Version', |
23
|
|
|
'2#003' => 'Object Type Reference', |
24
|
|
|
'2#004' => 'Object Attribute Reference', |
25
|
|
|
'2#005' => 'Object Name', |
26
|
|
|
'2#007' => 'Edit Status', |
27
|
|
|
'2#008' => 'EditorialUpdate', |
28
|
|
|
'2#010' => 'Urgency', |
29
|
|
|
'2#012' => 'Subject Reference', |
30
|
|
|
'2#015' => 'Category', |
31
|
|
|
'2#020' => 'Supplemental Category', |
32
|
|
|
'2#022' => 'Fixture Identifier', |
33
|
|
|
'2#025' => 'Keywords', |
34
|
|
|
'2#026' => 'Content Location Code', |
35
|
|
|
'2#027' => 'Content Location Name', |
36
|
|
|
'2#030' => 'Release Date', |
37
|
|
|
'2#035' => 'Release Time', |
38
|
|
|
'2#037' => 'ExpirationDate', |
39
|
|
|
'2#038' => 'Expiration Time', |
40
|
|
|
'2#040' => 'Special Instructions', |
41
|
|
|
'2#042' => 'Action Advised', |
42
|
|
|
'2#045' => 'Reference Service', |
43
|
|
|
'2#047' => 'Reference Date', |
44
|
|
|
'2#050' => 'Reference Number', |
45
|
|
|
'2#055' => 'Date Created', |
46
|
|
|
'2#060' => 'Time Created', |
47
|
|
|
'2#062' => 'Digital Creation Date', |
48
|
|
|
'2#063' => 'Digital Creation Time', |
49
|
|
|
'2#065' => 'Originating Program', |
50
|
|
|
'2#070' => 'Program Version', |
51
|
|
|
'2#075' => 'Object Cycle', |
52
|
|
|
'2#080' => 'By-line', |
53
|
|
|
'2#085' => 'By-line Title', |
54
|
|
|
'2#090' => 'City', |
55
|
|
|
'2#092' => 'Sublocation', |
56
|
|
|
'2#095' => 'Province/State', |
57
|
|
|
'2#100' => 'Country/Primary Location Code', |
58
|
|
|
'2#101' => 'Country/Primary Location Name', |
59
|
|
|
'2#103' => 'Original Transmission Reference', |
60
|
|
|
'2#105' => 'Headline', |
61
|
|
|
'2#110' => 'Credit', |
62
|
|
|
'2#115' => 'Source', |
63
|
|
|
'2#116' => 'Copyright Notice', |
64
|
|
|
'2#118' => 'Contact', |
65
|
|
|
'2#120' => 'Caption/Abstract', |
66
|
|
|
'2#122' => 'Writer/Editor', |
67
|
|
|
'2#125' => 'Rasterized Caption', |
68
|
|
|
'2#130' => 'Image Type', |
69
|
|
|
'2#131' => 'Image Orientation', |
70
|
|
|
'2#135' => 'Language Identifier', |
71
|
|
|
'2#150' => 'Audio Type', |
72
|
|
|
'2#151' => 'Audio SamplingRate', |
73
|
|
|
'2#152' => 'Audio Sampling Resolution', |
74
|
|
|
'2#153' => 'Audio Duration', |
75
|
|
|
'2#154' => 'Audio Outcue', |
76
|
|
|
'2#200' => 'ObjectData Preview File Format', |
77
|
|
|
'2#201' => 'ObjectData Preview File Format Version', |
78
|
|
|
'2#202' => 'ObjectData Preview Data' |
79
|
|
|
]; |
80
|
|
|
|
81
|
|
|
private $metadata = array( |
82
|
|
|
'exif' => null, |
83
|
|
|
'iptc' => null, |
84
|
|
|
'xmp' => null |
85
|
|
|
); |
86
|
|
|
|
87
|
|
|
private $resource; |
88
|
|
|
|
89
|
|
|
private $file_pointer; |
90
|
|
|
|
91
|
3 |
|
public function __construct($resource) |
92
|
|
|
{ |
93
|
3 |
|
$this->resource = $resource; |
94
|
3 |
|
} |
95
|
|
|
|
96
|
1 |
|
public function readExif() |
97
|
|
|
{ |
98
|
1 |
|
$this->metadata['exif'] = exif_read_data($this->resource); |
99
|
1 |
|
} |
100
|
|
|
|
101
|
1 |
|
public function readIptc() |
102
|
|
|
{ |
103
|
1 |
|
getimagesize($this->resource, $info); |
104
|
|
|
|
105
|
1 |
|
if (isset($info['APP13'])) { |
106
|
1 |
|
$iptc = iptcparse($info['APP13']); |
107
|
1 |
|
$map = $this->iptclabels; |
108
|
|
|
|
109
|
1 |
|
if ($iptc !== false) { |
110
|
1 |
|
$data = []; |
111
|
|
|
|
112
|
1 |
|
foreach ($iptc as $key => $value) { |
113
|
1 |
|
$data[$map[$key]] = $value; |
114
|
1 |
|
} |
115
|
|
|
|
116
|
1 |
|
$this->metadata['iptc'] = $data; |
117
|
1 |
|
} |
118
|
1 |
|
} |
119
|
1 |
|
} |
120
|
|
|
|
121
|
1 |
|
public function readXmp() |
122
|
|
|
{ |
123
|
1 |
|
$xml = $this->readXmpData(); |
124
|
1 |
|
if ($xml !== null) { |
125
|
1 |
|
$xml = (new \DOMDocument())->loadXML($xml); |
126
|
1 |
|
} |
127
|
1 |
|
$this->metadata['xmp'] = $xml; |
128
|
1 |
|
} |
129
|
|
|
|
130
|
1 |
|
private function readXmpData($chunk_size = 1024) |
131
|
|
|
{ |
132
|
1 |
|
if ($this->file_pointer === null) { |
133
|
1 |
|
$this->file_pointer = fopen($this->resource, 'r'); |
134
|
1 |
|
} |
135
|
|
|
|
136
|
1 |
|
$buffer = $this->extractXmpChunk($chunk_size); |
137
|
|
|
|
138
|
1 |
|
fclose($this->file_pointer); |
139
|
|
|
|
140
|
1 |
|
return $buffer; |
141
|
|
|
} |
142
|
|
|
|
143
|
1 |
|
private function extractXmpChunk($chunk_size) |
144
|
|
|
{ |
145
|
1 |
|
$buffer = null; |
146
|
|
|
|
147
|
|
|
do { |
148
|
1 |
|
$chunk = fread($this->file_pointer, $chunk_size); |
149
|
|
|
|
150
|
1 |
|
$eof = feof($this->file_pointer); |
151
|
1 |
|
$posStart = strpos($chunk, '<x:xmpmeta'); |
152
|
|
|
|
153
|
1 |
|
if ($buffer !== null) { |
154
|
1 |
|
$buffer .= $chunk; |
155
|
1 |
|
} else if ($posStart !== false) { |
156
|
1 |
|
$buffer = substr($chunk, $posStart); |
157
|
1 |
|
} |
158
|
|
|
|
159
|
1 |
|
$posEnd = strpos($buffer, '</x:xmpmeta>'); |
160
|
1 |
|
if ($posEnd) { |
161
|
1 |
|
$buffer = substr($buffer, 0, $posEnd + 12); |
162
|
1 |
|
} |
163
|
1 |
|
} while (!$eof); |
164
|
|
|
|
165
|
1 |
|
return $buffer; |
166
|
|
|
} |
167
|
|
|
|
168
|
3 |
|
public function getMetaData() |
169
|
|
|
{ |
170
|
3 |
|
return $this->metadata; |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|