1 | <?php |
---|
2 | ///////////////////////////////////////////////////////////////// |
---|
3 | /// getID3() by James Heinrich <info@getid3.org> // |
---|
4 | // available at http://getid3.sourceforge.net // |
---|
5 | // or http://www.getid3.org // |
---|
6 | ///////////////////////////////////////////////////////////////// |
---|
7 | // // |
---|
8 | // Please see readme.txt for more information // |
---|
9 | // /// |
---|
10 | ///////////////////////////////////////////////////////////////// |
---|
11 | |
---|
12 | // Defines |
---|
13 | define('GETID3_VERSION', '1.7.9-20090308'); |
---|
14 | define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes |
---|
15 | |
---|
16 | |
---|
17 | |
---|
18 | class getID3 |
---|
19 | { |
---|
20 | // public: Settings |
---|
21 | var $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv()) |
---|
22 | // Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE |
---|
23 | |
---|
24 | var $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' |
---|
25 | |
---|
26 | var $tempdir = '*'; // default '*' should use system temp dir |
---|
27 | |
---|
28 | // public: Optional tag checks - disable for speed. |
---|
29 | var $option_tag_id3v1 = true; // Read and process ID3v1 tags |
---|
30 | var $option_tag_id3v2 = true; // Read and process ID3v2 tags |
---|
31 | var $option_tag_lyrics3 = true; // Read and process Lyrics3 tags |
---|
32 | var $option_tag_apetag = true; // Read and process APE tags |
---|
33 | var $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding |
---|
34 | var $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities |
---|
35 | |
---|
36 | // public: Optional tag/comment calucations |
---|
37 | var $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc |
---|
38 | |
---|
39 | // public: Optional calculations |
---|
40 | var $option_md5_data = false; // Get MD5 sum of data part - slow |
---|
41 | var $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG |
---|
42 | var $option_sha1_data = false; // Get SHA1 sum of data part - slow |
---|
43 | var $option_max_2gb_check = true; // Check whether file is larger than 2 Gb and thus not supported by PHP |
---|
44 | |
---|
45 | // private |
---|
46 | var $filename; |
---|
47 | |
---|
48 | |
---|
49 | // public: constructor |
---|
50 | function getID3() |
---|
51 | { |
---|
52 | |
---|
53 | $this->startup_error = ''; |
---|
54 | $this->startup_warning = ''; |
---|
55 | |
---|
56 | // Check for PHP version >= 4.2.0 |
---|
57 | if (phpversion() < '4.2.0') { |
---|
58 | $this->startup_error .= 'getID3() requires PHP v4.2.0 or higher - you are running v'.phpversion(); |
---|
59 | } |
---|
60 | |
---|
61 | // Check memory |
---|
62 | $memory_limit = ini_get('memory_limit'); |
---|
63 | if (eregi('([0-9]+)M', $memory_limit, $matches)) { |
---|
64 | // could be stored as "16M" rather than 16777216 for example |
---|
65 | $memory_limit = $matches[1] * 1048576; |
---|
66 | } |
---|
67 | if ($memory_limit <= 0) { |
---|
68 | // memory limits probably disabled |
---|
69 | } elseif ($memory_limit <= 3145728) { |
---|
70 | $this->startup_error .= 'PHP has less than 3MB available memory and will very likely run out. Increase memory_limit in php.ini'; |
---|
71 | } elseif ($memory_limit <= 12582912) { |
---|
72 | $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'; |
---|
73 | } |
---|
74 | |
---|
75 | // Check safe_mode off |
---|
76 | if ((bool) ini_get('safe_mode')) { |
---|
77 | $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.'); |
---|
78 | } |
---|
79 | |
---|
80 | |
---|
81 | // define a constant rather than looking up every time it is needed |
---|
82 | if (!defined('GETID3_OS_ISWINDOWS')) { |
---|
83 | if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { |
---|
84 | define('GETID3_OS_ISWINDOWS', true); |
---|
85 | } else { |
---|
86 | define('GETID3_OS_ISWINDOWS', false); |
---|
87 | } |
---|
88 | } |
---|
89 | |
---|
90 | // Get base path of getID3() - ONCE |
---|
91 | if (!defined('GETID3_INCLUDEPATH')) { |
---|
92 | foreach (get_included_files() as $key => $val) { |
---|
93 | if (basename($val) == 'getid3.php') { |
---|
94 | define('GETID3_INCLUDEPATH', dirname($val).DIRECTORY_SEPARATOR); |
---|
95 | break; |
---|
96 | } |
---|
97 | } |
---|
98 | } |
---|
99 | |
---|
100 | // Load support library |
---|
101 | if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { |
---|
102 | $this->startup_error .= 'getid3.lib.php is missing or corrupt'; |
---|
103 | } |
---|
104 | |
---|
105 | |
---|
106 | // Needed for Windows only: |
---|
107 | // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC |
---|
108 | // as well as other helper functions such as head, tail, md5sum, etc |
---|
109 | // IMPORTANT: This path cannot have spaces in it. If neccesary, use the 8dot3 equivalent |
---|
110 | // ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/" |
---|
111 | // IMPORTANT: This path must include the trailing slash |
---|
112 | if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) { |
---|
113 | |
---|
114 | $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path |
---|
115 | |
---|
116 | if (!is_dir($helperappsdir)) { |
---|
117 | $this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'; |
---|
118 | } elseif (strpos(realpath($helperappsdir), ' ') !== false) { |
---|
119 | $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir)); |
---|
120 | foreach ($DirPieces as $key => $value) { |
---|
121 | if ((strpos($value, '.') !== false) && (strpos($value, ' ') === false)) { |
---|
122 | if (strpos($value, '.') > 8) { |
---|
123 | $value = substr($value, 0, 6).'~1'; |
---|
124 | } |
---|
125 | } elseif ((strpos($value, ' ') !== false) || strlen($value) > 8) { |
---|
126 | $value = substr($value, 0, 6).'~1'; |
---|
127 | } |
---|
128 | $DirPieces[$key] = strtoupper($value); |
---|
129 | } |
---|
130 | $this->startup_error .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary (on this server that would be something like "'.implode(DIRECTORY_SEPARATOR, $DirPieces).'" - NOTE: this may or may not be the actual 8.3 equivalent of "'.$helperappsdir.'", please double-check). You can run "dir /x" from the commandline to see the correct 8.3-style names.'; |
---|
131 | } |
---|
132 | define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).DIRECTORY_SEPARATOR); |
---|
133 | } |
---|
134 | |
---|
135 | } |
---|
136 | |
---|
137 | |
---|
138 | // public: setOption |
---|
139 | function setOption($optArray) { |
---|
140 | if (!is_array($optArray) || empty($optArray)) { |
---|
141 | return false; |
---|
142 | } |
---|
143 | foreach ($optArray as $opt => $val) { |
---|
144 | //if (isset($this, $opt) === false) { |
---|
145 | if (isset($this->$opt) === false) { |
---|
146 | continue; |
---|
147 | } |
---|
148 | $this->$opt = $val; |
---|
149 | } |
---|
150 | return true; |
---|
151 | } |
---|
152 | |
---|
153 | |
---|
154 | // public: analyze file - replaces GetAllFileInfo() and GetTagOnly() |
---|
155 | function analyze($filename) { |
---|
156 | |
---|
157 | if (!empty($this->startup_error)) { |
---|
158 | return $this->error($this->startup_error); |
---|
159 | } |
---|
160 | if (!empty($this->startup_warning)) { |
---|
161 | $this->warning($this->startup_warning); |
---|
162 | } |
---|
163 | |
---|
164 | // init result array and set parameters |
---|
165 | $this->info = array(); |
---|
166 | $this->info['GETID3_VERSION'] = GETID3_VERSION; |
---|
167 | |
---|
168 | // Check encoding/iconv support |
---|
169 | if (!function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) { |
---|
170 | $errormessage = 'iconv() support is needed for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. '; |
---|
171 | if (GETID3_OS_ISWINDOWS) { |
---|
172 | $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32'; |
---|
173 | } else { |
---|
174 | $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch'; |
---|
175 | } |
---|
176 | return $this->error($errormessage); |
---|
177 | } |
---|
178 | |
---|
179 | // Disable magic_quotes_runtime, if neccesary |
---|
180 | $old_magic_quotes_runtime = get_magic_quotes_runtime(); // store current setting of magic_quotes_runtime |
---|
181 | if ($old_magic_quotes_runtime) { |
---|
182 | set_magic_quotes_runtime(0); // turn off magic_quotes_runtime |
---|
183 | if (get_magic_quotes_runtime()) { |
---|
184 | return $this->error('Could not disable magic_quotes_runtime - getID3() cannot work properly with this setting enabled'); |
---|
185 | } |
---|
186 | } |
---|
187 | |
---|
188 | // remote files not supported |
---|
189 | if (preg_match('/^(ht|f)tp:\/\//', $filename)) { |
---|
190 | return $this->error('Remote files are not supported in this version of getID3() - please copy the file locally first'); |
---|
191 | } |
---|
192 | |
---|
193 | $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); |
---|
194 | $filename = preg_replace('#'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#', DIRECTORY_SEPARATOR, $filename); |
---|
195 | |
---|
196 | // open local file |
---|
197 | if (file_exists($filename) && ($fp = @fopen($filename, 'rb'))) { |
---|
198 | // great |
---|
199 | } else { |
---|
200 | return $this->error('Could not open file "'.$filename.'"'); |
---|
201 | } |
---|
202 | |
---|
203 | // set parameters |
---|
204 | $this->info['filesize'] = filesize($filename); |
---|
205 | |
---|
206 | // option_max_2gb_check |
---|
207 | if ($this->option_max_2gb_check) { |
---|
208 | // PHP doesn't support integers larger than 31-bit (~2GB) |
---|
209 | // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize |
---|
210 | // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer |
---|
211 | fseek($fp, 0, SEEK_END); |
---|
212 | if ((($this->info['filesize'] != 0) && (ftell($fp) == 0)) || |
---|
213 | ($this->info['filesize'] < 0) || |
---|
214 | (ftell($fp) < 0)) { |
---|
215 | $real_filesize = false; |
---|
216 | if (GETID3_OS_ISWINDOWS) { |
---|
217 | $commandline = 'dir /-C "'.str_replace('/', DIRECTORY_SEPARATOR, $filename).'"'; |
---|
218 | $dir_output = `$commandline`; |
---|
219 | if (eregi('1 File\(s\)[ ]+([0-9]+) bytes', $dir_output, $matches)) { |
---|
220 | $real_filesize = (float) $matches[1]; |
---|
221 | } |
---|
222 | } else { |
---|
223 | $commandline = 'ls -o -g -G --time-style=long-iso '.escapeshellarg($filename); |
---|
224 | $dir_output = `$commandline`; |
---|
225 | if (eregi('([0-9]+) ([0-9]{4}-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}) '.preg_quote($filename).'$', $dir_output, $matches)) { |
---|
226 | $real_filesize = (float) $matches[1]; |
---|
227 | } |
---|
228 | } |
---|
229 | if ($real_filesize === false) { |
---|
230 | unset($this->info['filesize']); |
---|
231 | fclose($fp); |
---|
232 | return $this->error('File is most likely larger than 2GB and is not supported by PHP'); |
---|
233 | } elseif ($real_filesize < pow(2, 31)) { |
---|
234 | unset($this->info['filesize']); |
---|
235 | fclose($fp); |
---|
236 | return $this->error('PHP seems to think the file is larger than 2GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org'); |
---|
237 | } |
---|
238 | $this->info['filesize'] = $real_filesize; |
---|
239 | $this->error('File is larger than 2GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.'); |
---|
240 | } |
---|
241 | } |
---|
242 | |
---|
243 | // set more parameters |
---|
244 | $this->info['avdataoffset'] = 0; |
---|
245 | $this->info['avdataend'] = $this->info['filesize']; |
---|
246 | $this->info['fileformat'] = ''; // filled in later |
---|
247 | $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used |
---|
248 | $this->info['video']['dataformat'] = ''; // filled in later, unset if not used |
---|
249 | $this->info['tags'] = array(); // filled in later, unset if not used |
---|
250 | $this->info['error'] = array(); // filled in later, unset if not used |
---|
251 | $this->info['warning'] = array(); // filled in later, unset if not used |
---|
252 | $this->info['comments'] = array(); // filled in later, unset if not used |
---|
253 | $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired |
---|
254 | |
---|
255 | // set redundant parameters - might be needed in some include file |
---|
256 | $this->info['filename'] = basename($filename); |
---|
257 | $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); |
---|
258 | $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; |
---|
259 | |
---|
260 | |
---|
261 | // handle ID3v2 tag - done first - already at beginning of file |
---|
262 | // ID3v2 detection (even if not parsing) is always done otherwise fileformat is much harder to detect |
---|
263 | if ($this->option_tag_id3v2) { |
---|
264 | |
---|
265 | $GETID3_ERRORARRAY = &$this->info['warning']; |
---|
266 | if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, false)) { |
---|
267 | $tag = new getid3_id3v2($fp, $this->info); |
---|
268 | unset($tag); |
---|
269 | } |
---|
270 | |
---|
271 | } else { |
---|
272 | |
---|
273 | fseek($fp, 0, SEEK_SET); |
---|
274 | $header = fread($fp, 10); |
---|
275 | if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { |
---|
276 | $this->info['id3v2']['header'] = true; |
---|
277 | $this->info['id3v2']['majorversion'] = ord($header{3}); |
---|
278 | $this->info['id3v2']['minorversion'] = ord($header{4}); |
---|
279 | $this->info['id3v2']['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length |
---|
280 | |
---|
281 | $this->info['id3v2']['tag_offset_start'] = 0; |
---|
282 | $this->info['id3v2']['tag_offset_end'] = $this->info['id3v2']['tag_offset_start'] + $this->info['id3v2']['headerlength']; |
---|
283 | $this->info['avdataoffset'] = $this->info['id3v2']['tag_offset_end']; |
---|
284 | } |
---|
285 | |
---|
286 | } |
---|
287 | |
---|
288 | |
---|
289 | // handle ID3v1 tag |
---|
290 | if ($this->option_tag_id3v1) { |
---|
291 | if (!@include_once(GETID3_INCLUDEPATH.'module.tag.id3v1.php')) { |
---|
292 | return $this->error('module.tag.id3v1.php is missing - you may disable option_tag_id3v1.'); |
---|
293 | } |
---|
294 | $tag = new getid3_id3v1($fp, $this->info); |
---|
295 | unset($tag); |
---|
296 | } |
---|
297 | |
---|
298 | // handle APE tag |
---|
299 | if ($this->option_tag_apetag) { |
---|
300 | if (!@include_once(GETID3_INCLUDEPATH.'module.tag.apetag.php')) { |
---|
301 | return $this->error('module.tag.apetag.php is missing - you may disable option_tag_apetag.'); |
---|
302 | } |
---|
303 | $tag = new getid3_apetag($fp, $this->info); |
---|
304 | unset($tag); |
---|
305 | } |
---|
306 | |
---|
307 | // handle lyrics3 tag |
---|
308 | if ($this->option_tag_lyrics3) { |
---|
309 | if (!@include_once(GETID3_INCLUDEPATH.'module.tag.lyrics3.php')) { |
---|
310 | return $this->error('module.tag.lyrics3.php is missing - you may disable option_tag_lyrics3.'); |
---|
311 | } |
---|
312 | $tag = new getid3_lyrics3($fp, $this->info); |
---|
313 | unset($tag); |
---|
314 | } |
---|
315 | |
---|
316 | // read 32 kb file data |
---|
317 | fseek($fp, $this->info['avdataoffset'], SEEK_SET); |
---|
318 | $formattest = fread($fp, 32774); |
---|
319 | |
---|
320 | // determine format |
---|
321 | $determined_format = $this->GetFileFormat($formattest, $filename); |
---|
322 | |
---|
323 | // unable to determine file format |
---|
324 | if (!$determined_format) { |
---|
325 | fclose($fp); |
---|
326 | return $this->error('unable to determine file format'); |
---|
327 | } |
---|
328 | |
---|
329 | // check for illegal ID3 tags |
---|
330 | if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) { |
---|
331 | if ($determined_format['fail_id3'] === 'ERROR') { |
---|
332 | fclose($fp); |
---|
333 | return $this->error('ID3 tags not allowed on this file type.'); |
---|
334 | } elseif ($determined_format['fail_id3'] === 'WARNING') { |
---|
335 | $this->info['warning'][] = 'ID3 tags not allowed on this file type.'; |
---|
336 | } |
---|
337 | } |
---|
338 | |
---|
339 | // check for illegal APE tags |
---|
340 | if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) { |
---|
341 | if ($determined_format['fail_ape'] === 'ERROR') { |
---|
342 | fclose($fp); |
---|
343 | return $this->error('APE tags not allowed on this file type.'); |
---|
344 | } elseif ($determined_format['fail_ape'] === 'WARNING') { |
---|
345 | $this->info['warning'][] = 'APE tags not allowed on this file type.'; |
---|
346 | } |
---|
347 | } |
---|
348 | |
---|
349 | // set mime type |
---|
350 | $this->info['mime_type'] = $determined_format['mime_type']; |
---|
351 | |
---|
352 | // supported format signature pattern detected, but module deleted |
---|
353 | if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) { |
---|
354 | fclose($fp); |
---|
355 | return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.'); |
---|
356 | } |
---|
357 | |
---|
358 | // module requires iconv support |
---|
359 | if (!function_exists('iconv') && @$determined_format['iconv_req']) { |
---|
360 | return $this->error('iconv support is required for this module ('.$determined_format['include'].').'); |
---|
361 | } |
---|
362 | |
---|
363 | // include module |
---|
364 | include_once(GETID3_INCLUDEPATH.$determined_format['include']); |
---|
365 | |
---|
366 | // instantiate module class |
---|
367 | $class_name = 'getid3_'.$determined_format['module']; |
---|
368 | if (!class_exists($class_name)) { |
---|
369 | return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.'); |
---|
370 | } |
---|
371 | if (isset($determined_format['option'])) { |
---|
372 | $class = new $class_name($fp, $this->info, $determined_format['option']); |
---|
373 | } else { |
---|
374 | $class = new $class_name($fp, $this->info); |
---|
375 | } |
---|
376 | unset($class); |
---|
377 | |
---|
378 | // close file |
---|
379 | fclose($fp); |
---|
380 | |
---|
381 | // process all tags - copy to 'tags' and convert charsets |
---|
382 | if ($this->option_tags_process) { |
---|
383 | $this->HandleAllTags(); |
---|
384 | } |
---|
385 | |
---|
386 | // perform more calculations |
---|
387 | if ($this->option_extra_info) { |
---|
388 | $this->ChannelsBitratePlaytimeCalculations(); |
---|
389 | $this->CalculateCompressionRatioVideo(); |
---|
390 | $this->CalculateCompressionRatioAudio(); |
---|
391 | $this->CalculateReplayGain(); |
---|
392 | $this->ProcessAudioStreams(); |
---|
393 | } |
---|
394 | |
---|
395 | // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags |
---|
396 | if ($this->option_md5_data) { |
---|
397 | // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too |
---|
398 | if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) { |
---|
399 | $this->getHashdata('md5'); |
---|
400 | } |
---|
401 | } |
---|
402 | |
---|
403 | // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags |
---|
404 | if ($this->option_sha1_data) { |
---|
405 | $this->getHashdata('sha1'); |
---|
406 | } |
---|
407 | |
---|
408 | // remove undesired keys |
---|
409 | $this->CleanUp(); |
---|
410 | |
---|
411 | // restore magic_quotes_runtime setting |
---|
412 | set_magic_quotes_runtime($old_magic_quotes_runtime); |
---|
413 | |
---|
414 | // return info array |
---|
415 | return $this->info; |
---|
416 | } |
---|
417 | |
---|
418 | |
---|
419 | // private: error handling |
---|
420 | function error($message) { |
---|
421 | |
---|
422 | $this->CleanUp(); |
---|
423 | |
---|
424 | $this->info['error'][] = $message; |
---|
425 | return $this->info; |
---|
426 | } |
---|
427 | |
---|
428 | |
---|
429 | // private: warning handling |
---|
430 | function warning($message) { |
---|
431 | $this->info['warning'][] = $message; |
---|
432 | return true; |
---|
433 | } |
---|
434 | |
---|
435 | |
---|
436 | // private: CleanUp |
---|
437 | function CleanUp() { |
---|
438 | |
---|
439 | // remove possible empty keys |
---|
440 | $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate'); |
---|
441 | foreach ($AVpossibleEmptyKeys as $dummy => $key) { |
---|
442 | if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) { |
---|
443 | unset($this->info['audio'][$key]); |
---|
444 | } |
---|
445 | if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) { |
---|
446 | unset($this->info['video'][$key]); |
---|
447 | } |
---|
448 | } |
---|
449 | |
---|
450 | // remove empty root keys |
---|
451 | if (!empty($this->info)) { |
---|
452 | foreach ($this->info as $key => $value) { |
---|
453 | if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) { |
---|
454 | unset($this->info[$key]); |
---|
455 | } |
---|
456 | } |
---|
457 | } |
---|
458 | |
---|
459 | // remove meaningless entries from unknown-format files |
---|
460 | if (empty($this->info['fileformat'])) { |
---|
461 | if (isset($this->info['avdataoffset'])) { |
---|
462 | unset($this->info['avdataoffset']); |
---|
463 | } |
---|
464 | if (isset($this->info['avdataend'])) { |
---|
465 | unset($this->info['avdataend']); |
---|
466 | } |
---|
467 | } |
---|
468 | } |
---|
469 | |
---|
470 | |
---|
471 | // return array containing information about all supported formats |
---|
472 | function GetFileFormatArray() { |
---|
473 | static $format_info = array(); |
---|
474 | if (empty($format_info)) { |
---|
475 | $format_info = array( |
---|
476 | |
---|
477 | // Audio formats |
---|
478 | |
---|
479 | // AC-3 - audio - Dolby AC-3 / Dolby Digital |
---|
480 | 'ac3' => array( |
---|
481 | 'pattern' => '^\x0B\x77', |
---|
482 | 'group' => 'audio', |
---|
483 | 'module' => 'ac3', |
---|
484 | 'mime_type' => 'audio/ac3', |
---|
485 | ), |
---|
486 | |
---|
487 | // AAC - audio - Advanced Audio Coding (AAC) - ADIF format |
---|
488 | 'adif' => array( |
---|
489 | 'pattern' => '^ADIF', |
---|
490 | 'group' => 'audio', |
---|
491 | 'module' => 'aac', |
---|
492 | 'option' => 'adif', |
---|
493 | 'mime_type' => 'application/octet-stream', |
---|
494 | 'fail_ape' => 'WARNING', |
---|
495 | ), |
---|
496 | |
---|
497 | |
---|
498 | // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) |
---|
499 | 'adts' => array( |
---|
500 | 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', |
---|
501 | 'group' => 'audio', |
---|
502 | 'module' => 'aac', |
---|
503 | 'option' => 'adts', |
---|
504 | 'mime_type' => 'application/octet-stream', |
---|
505 | 'fail_ape' => 'WARNING', |
---|
506 | ), |
---|
507 | |
---|
508 | |
---|
509 | // AU - audio - NeXT/Sun AUdio (AU) |
---|
510 | 'au' => array( |
---|
511 | 'pattern' => '^\.snd', |
---|
512 | 'group' => 'audio', |
---|
513 | 'module' => 'au', |
---|
514 | 'mime_type' => 'audio/basic', |
---|
515 | ), |
---|
516 | |
---|
517 | // AVR - audio - Audio Visual Research |
---|
518 | 'avr' => array( |
---|
519 | 'pattern' => '^2BIT', |
---|
520 | 'group' => 'audio', |
---|
521 | 'module' => 'avr', |
---|
522 | 'mime_type' => 'application/octet-stream', |
---|
523 | ), |
---|
524 | |
---|
525 | // BONK - audio - Bonk v0.9+ |
---|
526 | 'bonk' => array( |
---|
527 | 'pattern' => '^\x00(BONK|INFO|META| ID3)', |
---|
528 | 'group' => 'audio', |
---|
529 | 'module' => 'bonk', |
---|
530 | 'mime_type' => 'audio/xmms-bonk', |
---|
531 | ), |
---|
532 | |
---|
533 | // DSS - audio - Digital Speech Standard |
---|
534 | 'dss' => array( |
---|
535 | 'pattern' => '^[\x02]dss', |
---|
536 | 'group' => 'audio', |
---|
537 | 'module' => 'dss', |
---|
538 | 'mime_type' => 'application/octet-stream', |
---|
539 | ), |
---|
540 | |
---|
541 | // DTS - audio - Dolby Theatre System |
---|
542 | 'dts' => array( |
---|
543 | 'pattern' => '^\x7F\xFE\x80\x01', |
---|
544 | 'group' => 'audio', |
---|
545 | 'module' => 'dts', |
---|
546 | 'mime_type' => 'audio/dts', |
---|
547 | ), |
---|
548 | |
---|
549 | // FLAC - audio - Free Lossless Audio Codec |
---|
550 | 'flac' => array( |
---|
551 | 'pattern' => '^fLaC', |
---|
552 | 'group' => 'audio', |
---|
553 | 'module' => 'flac', |
---|
554 | 'mime_type' => 'audio/x-flac', |
---|
555 | ), |
---|
556 | |
---|
557 | // LA - audio - Lossless Audio (LA) |
---|
558 | 'la' => array( |
---|
559 | 'pattern' => '^LA0[2-4]', |
---|
560 | 'group' => 'audio', |
---|
561 | 'module' => 'la', |
---|
562 | 'mime_type' => 'application/octet-stream', |
---|
563 | ), |
---|
564 | |
---|
565 | // LPAC - audio - Lossless Predictive Audio Compression (LPAC) |
---|
566 | 'lpac' => array( |
---|
567 | 'pattern' => '^LPAC', |
---|
568 | 'group' => 'audio', |
---|
569 | 'module' => 'lpac', |
---|
570 | 'mime_type' => 'application/octet-stream', |
---|
571 | ), |
---|
572 | |
---|
573 | // MIDI - audio - MIDI (Musical Instrument Digital Interface) |
---|
574 | 'midi' => array( |
---|
575 | 'pattern' => '^MThd', |
---|
576 | 'group' => 'audio', |
---|
577 | 'module' => 'midi', |
---|
578 | 'mime_type' => 'audio/midi', |
---|
579 | ), |
---|
580 | |
---|
581 | // MAC - audio - Monkey's Audio Compressor |
---|
582 | 'mac' => array( |
---|
583 | 'pattern' => '^MAC ', |
---|
584 | 'group' => 'audio', |
---|
585 | 'module' => 'monkey', |
---|
586 | 'mime_type' => 'application/octet-stream', |
---|
587 | ), |
---|
588 | |
---|
589 | // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available |
---|
590 | // // MOD - audio - MODule (assorted sub-formats) |
---|
591 | // 'mod' => array( |
---|
592 | // 'pattern' => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)', |
---|
593 | // 'group' => 'audio', |
---|
594 | // 'module' => 'mod', |
---|
595 | // 'option' => 'mod', |
---|
596 | // 'mime_type' => 'audio/mod', |
---|
597 | // ), |
---|
598 | |
---|
599 | // MOD - audio - MODule (Impulse Tracker) |
---|
600 | 'it' => array( |
---|
601 | 'pattern' => '^IMPM', |
---|
602 | 'group' => 'audio', |
---|
603 | 'module' => 'mod', |
---|
604 | 'option' => 'it', |
---|
605 | 'mime_type' => 'audio/it', |
---|
606 | ), |
---|
607 | |
---|
608 | // MOD - audio - MODule (eXtended Module, various sub-formats) |
---|
609 | 'xm' => array( |
---|
610 | 'pattern' => '^Extended Module', |
---|
611 | 'group' => 'audio', |
---|
612 | 'module' => 'mod', |
---|
613 | 'option' => 'xm', |
---|
614 | 'mime_type' => 'audio/xm', |
---|
615 | ), |
---|
616 | |
---|
617 | // MOD - audio - MODule (ScreamTracker) |
---|
618 | 's3m' => array( |
---|
619 | 'pattern' => '^.{44}SCRM', |
---|
620 | 'group' => 'audio', |
---|
621 | 'module' => 'mod', |
---|
622 | 'option' => 's3m', |
---|
623 | 'mime_type' => 'audio/s3m', |
---|
624 | ), |
---|
625 | |
---|
626 | // MPC - audio - Musepack / MPEGplus |
---|
627 | 'mpc' => array( |
---|
628 | 'pattern' => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])', |
---|
629 | 'group' => 'audio', |
---|
630 | 'module' => 'mpc', |
---|
631 | 'mime_type' => 'audio/x-musepack', |
---|
632 | ), |
---|
633 | |
---|
634 | // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) |
---|
635 | 'mp3' => array( |
---|
636 | 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]', |
---|
637 | 'group' => 'audio', |
---|
638 | 'module' => 'mp3', |
---|
639 | 'mime_type' => 'audio/mpeg', |
---|
640 | ), |
---|
641 | |
---|
642 | // OFR - audio - OptimFROG |
---|
643 | 'ofr' => array( |
---|
644 | 'pattern' => '^(\*RIFF|OFR)', |
---|
645 | 'group' => 'audio', |
---|
646 | 'module' => 'optimfrog', |
---|
647 | 'mime_type' => 'application/octet-stream', |
---|
648 | ), |
---|
649 | |
---|
650 | // RKAU - audio - RKive AUdio compressor |
---|
651 | 'rkau' => array( |
---|
652 | 'pattern' => '^RKA', |
---|
653 | 'group' => 'audio', |
---|
654 | 'module' => 'rkau', |
---|
655 | 'mime_type' => 'application/octet-stream', |
---|
656 | ), |
---|
657 | |
---|
658 | // SHN - audio - Shorten |
---|
659 | 'shn' => array( |
---|
660 | 'pattern' => '^ajkg', |
---|
661 | 'group' => 'audio', |
---|
662 | 'module' => 'shorten', |
---|
663 | 'mime_type' => 'audio/xmms-shn', |
---|
664 | 'fail_id3' => 'ERROR', |
---|
665 | 'fail_ape' => 'ERROR', |
---|
666 | ), |
---|
667 | |
---|
668 | // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) |
---|
669 | 'tta' => array( |
---|
670 | 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' |
---|
671 | 'group' => 'audio', |
---|
672 | 'module' => 'tta', |
---|
673 | 'mime_type' => 'application/octet-stream', |
---|
674 | ), |
---|
675 | |
---|
676 | // VOC - audio - Creative Voice (VOC) |
---|
677 | 'voc' => array( |
---|
678 | 'pattern' => '^Creative Voice File', |
---|
679 | 'group' => 'audio', |
---|
680 | 'module' => 'voc', |
---|
681 | 'mime_type' => 'audio/voc', |
---|
682 | ), |
---|
683 | |
---|
684 | // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) |
---|
685 | 'vqf' => array( |
---|
686 | 'pattern' => '^TWIN', |
---|
687 | 'group' => 'audio', |
---|
688 | 'module' => 'vqf', |
---|
689 | 'mime_type' => 'application/octet-stream', |
---|
690 | ), |
---|
691 | |
---|
692 | // WV - audio - WavPack (v4.0+) |
---|
693 | 'wv' => array( |
---|
694 | 'pattern' => '^wvpk', |
---|
695 | 'group' => 'audio', |
---|
696 | 'module' => 'wavpack', |
---|
697 | 'mime_type' => 'application/octet-stream', |
---|
698 | ), |
---|
699 | |
---|
700 | |
---|
701 | // Audio-Video formats |
---|
702 | |
---|
703 | // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio |
---|
704 | 'asf' => array( |
---|
705 | 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', |
---|
706 | 'group' => 'audio-video', |
---|
707 | 'module' => 'asf', |
---|
708 | 'mime_type' => 'video/x-ms-asf', |
---|
709 | 'iconv_req' => false, |
---|
710 | ), |
---|
711 | |
---|
712 | // BINK - audio/video - Bink / Smacker |
---|
713 | 'bink' => array( |
---|
714 | 'pattern' => '^(BIK|SMK)', |
---|
715 | 'group' => 'audio-video', |
---|
716 | 'module' => 'bink', |
---|
717 | 'mime_type' => 'application/octet-stream', |
---|
718 | ), |
---|
719 | |
---|
720 | // FLV - audio/video - FLash Video |
---|
721 | 'flv' => array( |
---|
722 | 'pattern' => '^FLV\x01', |
---|
723 | 'group' => 'audio-video', |
---|
724 | 'module' => 'flv', |
---|
725 | 'mime_type' => 'video/x-flv', |
---|
726 | ), |
---|
727 | |
---|
728 | // MKAV - audio/video - Mastroka |
---|
729 | 'matroska' => array( |
---|
730 | 'pattern' => '^\x1A\x45\xDF\xA3', |
---|
731 | 'group' => 'audio-video', |
---|
732 | 'module' => 'matroska', |
---|
733 | 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska |
---|
734 | ), |
---|
735 | |
---|
736 | // MPEG - audio/video - MPEG (Moving Pictures Experts Group) |
---|
737 | 'mpeg' => array( |
---|
738 | 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', |
---|
739 | 'group' => 'audio-video', |
---|
740 | 'module' => 'mpeg', |
---|
741 | 'mime_type' => 'video/mpeg', |
---|
742 | ), |
---|
743 | |
---|
744 | // NSV - audio/video - Nullsoft Streaming Video (NSV) |
---|
745 | 'nsv' => array( |
---|
746 | 'pattern' => '^NSV[sf]', |
---|
747 | 'group' => 'audio-video', |
---|
748 | 'module' => 'nsv', |
---|
749 | 'mime_type' => 'application/octet-stream', |
---|
750 | ), |
---|
751 | |
---|
752 | // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*)) |
---|
753 | 'ogg' => array( |
---|
754 | 'pattern' => '^OggS', |
---|
755 | 'group' => 'audio', |
---|
756 | 'module' => 'ogg', |
---|
757 | 'mime_type' => 'application/ogg', |
---|
758 | 'fail_id3' => 'WARNING', |
---|
759 | 'fail_ape' => 'WARNING', |
---|
760 | ), |
---|
761 | |
---|
762 | // QT - audio/video - Quicktime |
---|
763 | 'quicktime' => array( |
---|
764 | 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', |
---|
765 | 'group' => 'audio-video', |
---|
766 | 'module' => 'quicktime', |
---|
767 | 'mime_type' => 'video/quicktime', |
---|
768 | ), |
---|
769 | |
---|
770 | // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF) |
---|
771 | 'riff' => array( |
---|
772 | 'pattern' => '^(RIFF|SDSS|FORM)', |
---|
773 | 'group' => 'audio-video', |
---|
774 | 'module' => 'riff', |
---|
775 | 'mime_type' => 'audio/x-wave', |
---|
776 | 'fail_ape' => 'WARNING', |
---|
777 | ), |
---|
778 | |
---|
779 | // Real - audio/video - RealAudio, RealVideo |
---|
780 | 'real' => array( |
---|
781 | 'pattern' => '^(\\.RMF|\\.ra)', |
---|
782 | 'group' => 'audio-video', |
---|
783 | 'module' => 'real', |
---|
784 | 'mime_type' => 'audio/x-realaudio', |
---|
785 | ), |
---|
786 | |
---|
787 | // SWF - audio/video - ShockWave Flash |
---|
788 | 'swf' => array( |
---|
789 | 'pattern' => '^(F|C)WS', |
---|
790 | 'group' => 'audio-video', |
---|
791 | 'module' => 'swf', |
---|
792 | 'mime_type' => 'application/x-shockwave-flash', |
---|
793 | ), |
---|
794 | |
---|
795 | |
---|
796 | // Still-Image formats |
---|
797 | |
---|
798 | // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) |
---|
799 | 'bmp' => array( |
---|
800 | 'pattern' => '^BM', |
---|
801 | 'group' => 'graphic', |
---|
802 | 'module' => 'bmp', |
---|
803 | 'mime_type' => 'image/bmp', |
---|
804 | 'fail_id3' => 'ERROR', |
---|
805 | 'fail_ape' => 'ERROR', |
---|
806 | ), |
---|
807 | |
---|
808 | // GIF - still image - Graphics Interchange Format |
---|
809 | 'gif' => array( |
---|
810 | 'pattern' => '^GIF', |
---|
811 | 'group' => 'graphic', |
---|
812 | 'module' => 'gif', |
---|
813 | 'mime_type' => 'image/gif', |
---|
814 | 'fail_id3' => 'ERROR', |
---|
815 | 'fail_ape' => 'ERROR', |
---|
816 | ), |
---|
817 | |
---|
818 | // JPEG - still image - Joint Photographic Experts Group (JPEG) |
---|
819 | 'jpg' => array( |
---|
820 | 'pattern' => '^\xFF\xD8\xFF', |
---|
821 | 'group' => 'graphic', |
---|
822 | 'module' => 'jpg', |
---|
823 | 'mime_type' => 'image/jpeg', |
---|
824 | 'fail_id3' => 'ERROR', |
---|
825 | 'fail_ape' => 'ERROR', |
---|
826 | ), |
---|
827 | |
---|
828 | // PCD - still image - Kodak Photo CD |
---|
829 | 'pcd' => array( |
---|
830 | 'pattern' => '^.{2048}PCD_IPI\x00', |
---|
831 | 'group' => 'graphic', |
---|
832 | 'module' => 'pcd', |
---|
833 | 'mime_type' => 'image/x-photo-cd', |
---|
834 | 'fail_id3' => 'ERROR', |
---|
835 | 'fail_ape' => 'ERROR', |
---|
836 | ), |
---|
837 | |
---|
838 | |
---|
839 | // PNG - still image - Portable Network Graphics (PNG) |
---|
840 | 'png' => array( |
---|
841 | 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', |
---|
842 | 'group' => 'graphic', |
---|
843 | 'module' => 'png', |
---|
844 | 'mime_type' => 'image/png', |
---|
845 | 'fail_id3' => 'ERROR', |
---|
846 | 'fail_ape' => 'ERROR', |
---|
847 | ), |
---|
848 | |
---|
849 | |
---|
850 | // SVG - still image - Scalable Vector Graphics (SVG) |
---|
851 | 'svg' => array( |
---|
852 | 'pattern' => '<!DOCTYPE svg PUBLIC ', |
---|
853 | 'group' => 'graphic', |
---|
854 | 'module' => 'svg', |
---|
855 | 'mime_type' => 'image/svg+xml', |
---|
856 | 'fail_id3' => 'ERROR', |
---|
857 | 'fail_ape' => 'ERROR', |
---|
858 | ), |
---|
859 | |
---|
860 | |
---|
861 | // TIFF - still image - Tagged Information File Format (TIFF) |
---|
862 | 'tiff' => array( |
---|
863 | 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', |
---|
864 | 'group' => 'graphic', |
---|
865 | 'module' => 'tiff', |
---|
866 | 'mime_type' => 'image/tiff', |
---|
867 | 'fail_id3' => 'ERROR', |
---|
868 | 'fail_ape' => 'ERROR', |
---|
869 | ), |
---|
870 | |
---|
871 | |
---|
872 | // Data formats |
---|
873 | |
---|
874 | // ISO - data - International Standards Organization (ISO) CD-ROM Image |
---|
875 | 'iso' => array( |
---|
876 | 'pattern' => '^.{32769}CD001', |
---|
877 | 'group' => 'misc', |
---|
878 | 'module' => 'iso', |
---|
879 | 'mime_type' => 'application/octet-stream', |
---|
880 | 'fail_id3' => 'ERROR', |
---|
881 | 'fail_ape' => 'ERROR', |
---|
882 | 'iconv_req' => false, |
---|
883 | ), |
---|
884 | |
---|
885 | // RAR - data - RAR compressed data |
---|
886 | 'rar' => array( |
---|
887 | 'pattern' => '^Rar\!', |
---|
888 | 'group' => 'archive', |
---|
889 | 'module' => 'rar', |
---|
890 | 'mime_type' => 'application/octet-stream', |
---|
891 | 'fail_id3' => 'ERROR', |
---|
892 | 'fail_ape' => 'ERROR', |
---|
893 | ), |
---|
894 | |
---|
895 | // SZIP - audio/data - SZIP compressed data |
---|
896 | 'szip' => array( |
---|
897 | 'pattern' => '^SZ\x0A\x04', |
---|
898 | 'group' => 'archive', |
---|
899 | 'module' => 'szip', |
---|
900 | 'mime_type' => 'application/octet-stream', |
---|
901 | 'fail_id3' => 'ERROR', |
---|
902 | 'fail_ape' => 'ERROR', |
---|
903 | ), |
---|
904 | |
---|
905 | // TAR - data - TAR compressed data |
---|
906 | 'tar' => array( |
---|
907 | 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}', |
---|
908 | 'group' => 'archive', |
---|
909 | 'module' => 'tar', |
---|
910 | 'mime_type' => 'application/x-tar', |
---|
911 | 'fail_id3' => 'ERROR', |
---|
912 | 'fail_ape' => 'ERROR', |
---|
913 | ), |
---|
914 | |
---|
915 | // GZIP - data - GZIP compressed data |
---|
916 | 'gz' => array( |
---|
917 | 'pattern' => '^\x1F\x8B\x08', |
---|
918 | 'group' => 'archive', |
---|
919 | 'module' => 'gzip', |
---|
920 | 'mime_type' => 'application/x-gzip', |
---|
921 | 'fail_id3' => 'ERROR', |
---|
922 | 'fail_ape' => 'ERROR', |
---|
923 | ), |
---|
924 | |
---|
925 | // ZIP - data - ZIP compressed data |
---|
926 | 'zip' => array( |
---|
927 | 'pattern' => '^PK\x03\x04', |
---|
928 | 'group' => 'archive', |
---|
929 | 'module' => 'zip', |
---|
930 | 'mime_type' => 'application/zip', |
---|
931 | 'fail_id3' => 'ERROR', |
---|
932 | 'fail_ape' => 'ERROR', |
---|
933 | ), |
---|
934 | |
---|
935 | |
---|
936 | // Misc other formats |
---|
937 | |
---|
938 | // PAR2 - data - Parity Volume Set Specification 2.0 |
---|
939 | 'par2' => array ( |
---|
940 | 'pattern' => '^PAR2\x00PKT', |
---|
941 | 'group' => 'misc', |
---|
942 | 'module' => 'par2', |
---|
943 | 'mime_type' => 'application/octet-stream', |
---|
944 | 'fail_id3' => 'ERROR', |
---|
945 | 'fail_ape' => 'ERROR', |
---|
946 | ), |
---|
947 | |
---|
948 | // PDF - data - Portable Document Format |
---|
949 | 'pdf' => array( |
---|
950 | 'pattern' => '^\x25PDF', |
---|
951 | 'group' => 'misc', |
---|
952 | 'module' => 'pdf', |
---|
953 | 'mime_type' => 'application/pdf', |
---|
954 | 'fail_id3' => 'ERROR', |
---|
955 | 'fail_ape' => 'ERROR', |
---|
956 | ), |
---|
957 | |
---|
958 | // MSOFFICE - data - ZIP compressed data |
---|
959 | 'msoffice' => array( |
---|
960 | 'pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document |
---|
961 | 'group' => 'misc', |
---|
962 | 'module' => 'msoffice', |
---|
963 | 'mime_type' => 'application/octet-stream', |
---|
964 | 'fail_id3' => 'ERROR', |
---|
965 | 'fail_ape' => 'ERROR', |
---|
966 | ), |
---|
967 | ); |
---|
968 | } |
---|
969 | |
---|
970 | return $format_info; |
---|
971 | } |
---|
972 | |
---|
973 | |
---|
974 | |
---|
975 | function GetFileFormat(&$filedata, $filename='') { |
---|
976 | // this function will determine the format of a file based on usually |
---|
977 | // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, |
---|
978 | // and in the case of ISO CD image, 6 bytes offset 32kb from the start |
---|
979 | // of the file). |
---|
980 | |
---|
981 | // Identify file format - loop through $format_info and detect with reg expr |
---|
982 | foreach ($this->GetFileFormatArray() as $format_name => $info) { |
---|
983 | // Using preg_match() instead of ereg() - much faster |
---|
984 | // The /s switch on preg_match() forces preg_match() NOT to treat |
---|
985 | // newline (0x0A) characters as special chars but do a binary match |
---|
986 | if (preg_match('/'.$info['pattern'].'/s', $filedata)) { |
---|
987 | $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; |
---|
988 | return $info; |
---|
989 | } |
---|
990 | } |
---|
991 | |
---|
992 | |
---|
993 | if (preg_match('/\.mp[123a]$/i', $filename)) { |
---|
994 | // Too many mp3 encoders on the market put gabage in front of mpeg files |
---|
995 | // use assume format on these if format detection failed |
---|
996 | $GetFileFormatArray = $this->GetFileFormatArray(); |
---|
997 | $info = $GetFileFormatArray['mp3']; |
---|
998 | $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; |
---|
999 | return $info; |
---|
1000 | } |
---|
1001 | |
---|
1002 | return false; |
---|
1003 | } |
---|
1004 | |
---|
1005 | |
---|
1006 | // converts array to $encoding charset from $this->encoding |
---|
1007 | function CharConvert(&$array, $encoding) { |
---|
1008 | |
---|
1009 | // identical encoding - end here |
---|
1010 | if ($encoding == $this->encoding) { |
---|
1011 | return; |
---|
1012 | } |
---|
1013 | |
---|
1014 | // loop thru array |
---|
1015 | foreach ($array as $key => $value) { |
---|
1016 | |
---|
1017 | // go recursive |
---|
1018 | if (is_array($value)) { |
---|
1019 | $this->CharConvert($array[$key], $encoding); |
---|
1020 | } |
---|
1021 | |
---|
1022 | // convert string |
---|
1023 | elseif (is_string($value)) { |
---|
1024 | $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value)); |
---|
1025 | } |
---|
1026 | } |
---|
1027 | } |
---|
1028 | |
---|
1029 | |
---|
1030 | function HandleAllTags() { |
---|
1031 | |
---|
1032 | // key name => array (tag name, character encoding) |
---|
1033 | static $tags; |
---|
1034 | if (empty($tags)) { |
---|
1035 | $tags = array( |
---|
1036 | 'asf' => array('asf' , 'UTF-16LE'), |
---|
1037 | 'midi' => array('midi' , 'ISO-8859-1'), |
---|
1038 | 'nsv' => array('nsv' , 'ISO-8859-1'), |
---|
1039 | 'ogg' => array('vorbiscomment' , 'UTF-8'), |
---|
1040 | 'png' => array('png' , 'UTF-8'), |
---|
1041 | 'tiff' => array('tiff' , 'ISO-8859-1'), |
---|
1042 | 'quicktime' => array('quicktime' , 'ISO-8859-1'), |
---|
1043 | 'real' => array('real' , 'ISO-8859-1'), |
---|
1044 | 'vqf' => array('vqf' , 'ISO-8859-1'), |
---|
1045 | 'zip' => array('zip' , 'ISO-8859-1'), |
---|
1046 | 'riff' => array('riff' , 'ISO-8859-1'), |
---|
1047 | 'lyrics3' => array('lyrics3' , 'ISO-8859-1'), |
---|
1048 | 'id3v1' => array('id3v1' , $this->encoding_id3v1), |
---|
1049 | 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8 |
---|
1050 | 'ape' => array('ape' , 'UTF-8') |
---|
1051 | ); |
---|
1052 | } |
---|
1053 | |
---|
1054 | // loop thru comments array |
---|
1055 | foreach ($tags as $comment_name => $tagname_encoding_array) { |
---|
1056 | list($tag_name, $encoding) = $tagname_encoding_array; |
---|
1057 | |
---|
1058 | // fill in default encoding type if not already present |
---|
1059 | if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) { |
---|
1060 | $this->info[$comment_name]['encoding'] = $encoding; |
---|
1061 | } |
---|
1062 | |
---|
1063 | // copy comments if key name set |
---|
1064 | if (!empty($this->info[$comment_name]['comments'])) { |
---|
1065 | |
---|
1066 | foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) { |
---|
1067 | foreach ($valuearray as $key => $value) { |
---|
1068 | if (strlen(trim($value)) > 0) { |
---|
1069 | $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed! |
---|
1070 | } |
---|
1071 | } |
---|
1072 | } |
---|
1073 | |
---|
1074 | if (!isset($this->info['tags'][$tag_name])) { |
---|
1075 | // comments are set but contain nothing but empty strings, so skip |
---|
1076 | continue; |
---|
1077 | } |
---|
1078 | |
---|
1079 | if ($this->option_tags_html) { |
---|
1080 | foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { |
---|
1081 | foreach ($valuearray as $key => $value) { |
---|
1082 | if (is_string($value)) { |
---|
1083 | //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding); |
---|
1084 | $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', getid3_lib::MultiByteCharString2HTML($value, $encoding)); |
---|
1085 | } else { |
---|
1086 | $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; |
---|
1087 | } |
---|
1088 | } |
---|
1089 | } |
---|
1090 | } |
---|
1091 | |
---|
1092 | $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! |
---|
1093 | } |
---|
1094 | |
---|
1095 | } |
---|
1096 | return true; |
---|
1097 | } |
---|
1098 | |
---|
1099 | |
---|
1100 | function getHashdata($algorithm) { |
---|
1101 | switch ($algorithm) { |
---|
1102 | case 'md5': |
---|
1103 | case 'sha1': |
---|
1104 | break; |
---|
1105 | |
---|
1106 | default: |
---|
1107 | return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()'); |
---|
1108 | break; |
---|
1109 | } |
---|
1110 | |
---|
1111 | if ((@$this->info['fileformat'] == 'ogg') && (@$this->info['audio']['dataformat'] == 'vorbis')) { |
---|
1112 | |
---|
1113 | // We cannot get an identical md5_data value for Ogg files where the comments |
---|
1114 | // span more than 1 Ogg page (compared to the same audio data with smaller |
---|
1115 | // comments) using the normal getID3() method of MD5'ing the data between the |
---|
1116 | // end of the comments and the end of the file (minus any trailing tags), |
---|
1117 | // because the page sequence numbers of the pages that the audio data is on |
---|
1118 | // do not match. Under normal circumstances, where comments are smaller than |
---|
1119 | // the nominal 4-8kB page size, then this is not a problem, but if there are |
---|
1120 | // very large comments, the only way around it is to strip off the comment |
---|
1121 | // tags with vorbiscomment and MD5 that file. |
---|
1122 | // This procedure must be applied to ALL Ogg files, not just the ones with |
---|
1123 | // comments larger than 1 page, because the below method simply MD5's the |
---|
1124 | // whole file with the comments stripped, not just the portion after the |
---|
1125 | // comments block (which is the standard getID3() method. |
---|
1126 | |
---|
1127 | // The above-mentioned problem of comments spanning multiple pages and changing |
---|
1128 | // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but |
---|
1129 | // currently vorbiscomment only works on OggVorbis files. |
---|
1130 | |
---|
1131 | if ((bool) ini_get('safe_mode')) { |
---|
1132 | |
---|
1133 | $this->info['warning'][] = 'Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'; |
---|
1134 | $this->info[$algorithm.'_data'] = false; |
---|
1135 | |
---|
1136 | } else { |
---|
1137 | |
---|
1138 | // Prevent user from aborting script |
---|
1139 | $old_abort = ignore_user_abort(true); |
---|
1140 | |
---|
1141 | // Create empty file |
---|
1142 | $empty = tempnam('*', 'getID3'); |
---|
1143 | touch($empty); |
---|
1144 | |
---|
1145 | |
---|
1146 | // Use vorbiscomment to make temp file without comments |
---|
1147 | $temp = tempnam('*', 'getID3'); |
---|
1148 | $file = $this->info['filenamepath']; |
---|
1149 | |
---|
1150 | if (GETID3_OS_ISWINDOWS) { |
---|
1151 | |
---|
1152 | if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { |
---|
1153 | |
---|
1154 | $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"'; |
---|
1155 | $VorbisCommentError = `$commandline`; |
---|
1156 | |
---|
1157 | } else { |
---|
1158 | |
---|
1159 | $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; |
---|
1160 | |
---|
1161 | } |
---|
1162 | |
---|
1163 | } else { |
---|
1164 | |
---|
1165 | $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1'; |
---|
1166 | $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; |
---|
1167 | $VorbisCommentError = `$commandline`; |
---|
1168 | |
---|
1169 | } |
---|
1170 | |
---|
1171 | if (!empty($VorbisCommentError)) { |
---|
1172 | |
---|
1173 | $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError; |
---|
1174 | $this->info[$algorithm.'_data'] = false; |
---|
1175 | |
---|
1176 | } else { |
---|
1177 | |
---|
1178 | // Get hash of newly created file |
---|
1179 | switch ($algorithm) { |
---|
1180 | case 'md5': |
---|
1181 | $this->info[$algorithm.'_data'] = getid3_lib::md5_file($temp); |
---|
1182 | break; |
---|
1183 | |
---|
1184 | case 'sha1': |
---|
1185 | $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($temp); |
---|
1186 | break; |
---|
1187 | } |
---|
1188 | } |
---|
1189 | |
---|
1190 | // Clean up |
---|
1191 | unlink($empty); |
---|
1192 | unlink($temp); |
---|
1193 | |
---|
1194 | // Reset abort setting |
---|
1195 | ignore_user_abort($old_abort); |
---|
1196 | |
---|
1197 | } |
---|
1198 | |
---|
1199 | } else { |
---|
1200 | |
---|
1201 | if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) { |
---|
1202 | |
---|
1203 | // get hash from part of file |
---|
1204 | $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm); |
---|
1205 | |
---|
1206 | } else { |
---|
1207 | |
---|
1208 | // get hash from whole file |
---|
1209 | switch ($algorithm) { |
---|
1210 | case 'md5': |
---|
1211 | $this->info[$algorithm.'_data'] = getid3_lib::md5_file($this->info['filenamepath']); |
---|
1212 | break; |
---|
1213 | |
---|
1214 | case 'sha1': |
---|
1215 | $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($this->info['filenamepath']); |
---|
1216 | break; |
---|
1217 | } |
---|
1218 | } |
---|
1219 | |
---|
1220 | } |
---|
1221 | return true; |
---|
1222 | } |
---|
1223 | |
---|
1224 | |
---|
1225 | function ChannelsBitratePlaytimeCalculations() { |
---|
1226 | |
---|
1227 | // set channelmode on audio |
---|
1228 | if (@$this->info['audio']['channels'] == '1') { |
---|
1229 | $this->info['audio']['channelmode'] = 'mono'; |
---|
1230 | } elseif (@$this->info['audio']['channels'] == '2') { |
---|
1231 | $this->info['audio']['channelmode'] = 'stereo'; |
---|
1232 | } |
---|
1233 | |
---|
1234 | // Calculate combined bitrate - audio + video |
---|
1235 | $CombinedBitrate = 0; |
---|
1236 | $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); |
---|
1237 | $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); |
---|
1238 | if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) { |
---|
1239 | $this->info['bitrate'] = $CombinedBitrate; |
---|
1240 | } |
---|
1241 | //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) { |
---|
1242 | // // for example, VBR MPEG video files cannot determine video bitrate: |
---|
1243 | // // should not set overall bitrate and playtime from audio bitrate only |
---|
1244 | // unset($this->info['bitrate']); |
---|
1245 | //} |
---|
1246 | |
---|
1247 | // video bitrate undetermined, but calculable |
---|
1248 | if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) { |
---|
1249 | // if video bitrate not set |
---|
1250 | if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) { |
---|
1251 | // AND if audio bitrate is set to same as overall bitrate |
---|
1252 | if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) { |
---|
1253 | // AND if playtime is set |
---|
1254 | if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) { |
---|
1255 | // AND if AV data offset start/end is known |
---|
1256 | // THEN we can calculate the video bitrate |
---|
1257 | $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']); |
---|
1258 | $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate']; |
---|
1259 | } |
---|
1260 | } |
---|
1261 | } |
---|
1262 | } |
---|
1263 | |
---|
1264 | if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) { |
---|
1265 | $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; |
---|
1266 | } |
---|
1267 | |
---|
1268 | if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) { |
---|
1269 | $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']; |
---|
1270 | } |
---|
1271 | //echo '<pre>'; |
---|
1272 | //var_dump($this->info['bitrate']); |
---|
1273 | //var_dump($this->info['audio']['bitrate']); |
---|
1274 | //var_dump($this->info['video']['bitrate']); |
---|
1275 | //echo '</pre>'; |
---|
1276 | if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) { |
---|
1277 | if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) { |
---|
1278 | // audio only |
---|
1279 | $this->info['audio']['bitrate'] = $this->info['bitrate']; |
---|
1280 | } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) { |
---|
1281 | // video only |
---|
1282 | $this->info['video']['bitrate'] = $this->info['bitrate']; |
---|
1283 | } |
---|
1284 | } |
---|
1285 | |
---|
1286 | // Set playtime string |
---|
1287 | if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { |
---|
1288 | $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']); |
---|
1289 | } |
---|
1290 | } |
---|
1291 | |
---|
1292 | |
---|
1293 | function CalculateCompressionRatioVideo() { |
---|
1294 | if (empty($this->info['video'])) { |
---|
1295 | return false; |
---|
1296 | } |
---|
1297 | if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) { |
---|
1298 | return false; |
---|
1299 | } |
---|
1300 | if (empty($this->info['video']['bits_per_sample'])) { |
---|
1301 | return false; |
---|
1302 | } |
---|
1303 | |
---|
1304 | switch ($this->info['video']['dataformat']) { |
---|
1305 | case 'bmp': |
---|
1306 | case 'gif': |
---|
1307 | case 'jpeg': |
---|
1308 | case 'jpg': |
---|
1309 | case 'png': |
---|
1310 | case 'tiff': |
---|
1311 | $FrameRate = 1; |
---|
1312 | $PlaytimeSeconds = 1; |
---|
1313 | $BitrateCompressed = $this->info['filesize'] * 8; |
---|
1314 | break; |
---|
1315 | |
---|
1316 | default: |
---|
1317 | if (!empty($this->info['video']['frame_rate'])) { |
---|
1318 | $FrameRate = $this->info['video']['frame_rate']; |
---|
1319 | } else { |
---|
1320 | return false; |
---|
1321 | } |
---|
1322 | if (!empty($this->info['playtime_seconds'])) { |
---|
1323 | $PlaytimeSeconds = $this->info['playtime_seconds']; |
---|
1324 | } else { |
---|
1325 | return false; |
---|
1326 | } |
---|
1327 | if (!empty($this->info['video']['bitrate'])) { |
---|
1328 | $BitrateCompressed = $this->info['video']['bitrate']; |
---|
1329 | } else { |
---|
1330 | return false; |
---|
1331 | } |
---|
1332 | break; |
---|
1333 | } |
---|
1334 | $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; |
---|
1335 | |
---|
1336 | $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; |
---|
1337 | return true; |
---|
1338 | } |
---|
1339 | |
---|
1340 | |
---|
1341 | function CalculateCompressionRatioAudio() { |
---|
1342 | if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate'])) { |
---|
1343 | return false; |
---|
1344 | } |
---|
1345 | $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); |
---|
1346 | |
---|
1347 | if (!empty($this->info['audio']['streams'])) { |
---|
1348 | foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) { |
---|
1349 | if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) { |
---|
1350 | $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16)); |
---|
1351 | } |
---|
1352 | } |
---|
1353 | } |
---|
1354 | return true; |
---|
1355 | } |
---|
1356 | |
---|
1357 | |
---|
1358 | function CalculateReplayGain() { |
---|
1359 | if (isset($this->info['replay_gain'])) { |
---|
1360 | $this->info['replay_gain']['reference_volume'] = 89; |
---|
1361 | if (isset($this->info['replay_gain']['track']['adjustment'])) { |
---|
1362 | $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; |
---|
1363 | } |
---|
1364 | if (isset($this->info['replay_gain']['album']['adjustment'])) { |
---|
1365 | $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; |
---|
1366 | } |
---|
1367 | |
---|
1368 | if (isset($this->info['replay_gain']['track']['peak'])) { |
---|
1369 | $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']); |
---|
1370 | } |
---|
1371 | if (isset($this->info['replay_gain']['album']['peak'])) { |
---|
1372 | $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']); |
---|
1373 | } |
---|
1374 | } |
---|
1375 | return true; |
---|
1376 | } |
---|
1377 | |
---|
1378 | function ProcessAudioStreams() { |
---|
1379 | if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) { |
---|
1380 | if (!isset($this->info['audio']['streams'])) { |
---|
1381 | foreach ($this->info['audio'] as $key => $value) { |
---|
1382 | if ($key != 'streams') { |
---|
1383 | $this->info['audio']['streams'][0][$key] = $value; |
---|
1384 | } |
---|
1385 | } |
---|
1386 | } |
---|
1387 | } |
---|
1388 | return true; |
---|
1389 | } |
---|
1390 | |
---|
1391 | function getid3_tempnam() { |
---|
1392 | return tempnam($this->tempdir, 'gI3'); |
---|
1393 | } |
---|
1394 | |
---|
1395 | } |
---|
1396 | |
---|
1397 | ?> |
---|