1 <?php |
1 <?php |
|
2 |
2 ///////////////////////////////////////////////////////////////// |
3 ///////////////////////////////////////////////////////////////// |
3 /// getID3() by James Heinrich <info@getid3.org> // |
4 /// getID3() by James Heinrich <info@getid3.org> // |
4 // available at http://getid3.sourceforge.net // |
5 // available at https://github.com/JamesHeinrich/getID3 // |
5 // or http://www.getid3.org // |
6 // or https://www.getid3.org // |
6 // also https://github.com/JamesHeinrich/getID3 // |
7 // or http://getid3.sourceforge.net // |
7 ///////////////////////////////////////////////////////////////// |
|
8 // // |
8 // // |
9 // getid3.lib.php - part of getID3() // |
9 // getid3.lib.php - part of getID3() // |
10 // See readme.txt for more details // |
10 // see readme.txt for more details // |
11 // /// |
11 // /// |
12 ///////////////////////////////////////////////////////////////// |
12 ///////////////////////////////////////////////////////////////// |
13 |
13 |
14 |
14 |
15 class getid3_lib |
15 class getid3_lib |
16 { |
16 { |
17 |
17 /** |
|
18 * @param string $string |
|
19 * @param bool $hex |
|
20 * @param bool $spaces |
|
21 * @param string|bool $htmlencoding |
|
22 * |
|
23 * @return string |
|
24 */ |
18 public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') { |
25 public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') { |
19 $returnstring = ''; |
26 $returnstring = ''; |
20 for ($i = 0; $i < strlen($string); $i++) { |
27 for ($i = 0; $i < strlen($string); $i++) { |
21 if ($hex) { |
28 if ($hex) { |
22 $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); |
29 $returnstring .= str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT); |
23 } else { |
30 } else { |
24 $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤'); |
31 $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string[$i]) ? $string[$i] : '¤'); |
25 } |
32 } |
26 if ($spaces) { |
33 if ($spaces) { |
27 $returnstring .= ' '; |
34 $returnstring .= ' '; |
28 } |
35 } |
29 } |
36 } |
50 $truncatednumber = (int) $truncatednumber; |
62 $truncatednumber = (int) $truncatednumber; |
51 } |
63 } |
52 return $truncatednumber; |
64 return $truncatednumber; |
53 } |
65 } |
54 |
66 |
55 |
67 /** |
|
68 * @param int|null $variable |
|
69 * @param int $increment |
|
70 * |
|
71 * @return bool |
|
72 */ |
56 public static function safe_inc(&$variable, $increment=1) { |
73 public static function safe_inc(&$variable, $increment=1) { |
57 if (isset($variable)) { |
74 if (isset($variable)) { |
58 $variable += $increment; |
75 $variable += $increment; |
59 } else { |
76 } else { |
60 $variable = $increment; |
77 $variable = $increment; |
61 } |
78 } |
62 return true; |
79 return true; |
63 } |
80 } |
64 |
81 |
|
82 /** |
|
83 * @param int|float $floatnum |
|
84 * |
|
85 * @return int|float |
|
86 */ |
65 public static function CastAsInt($floatnum) { |
87 public static function CastAsInt($floatnum) { |
66 // convert to float if not already |
88 // convert to float if not already |
67 $floatnum = (float) $floatnum; |
89 $floatnum = (float) $floatnum; |
68 |
90 |
69 // convert a float to type int, only if possible |
91 // convert a float to type int, only if possible |
75 } |
97 } |
76 } |
98 } |
77 return $floatnum; |
99 return $floatnum; |
78 } |
100 } |
79 |
101 |
|
102 /** |
|
103 * @param int $num |
|
104 * |
|
105 * @return bool |
|
106 */ |
80 public static function intValueSupported($num) { |
107 public static function intValueSupported($num) { |
81 // check if integers are 64-bit |
108 // check if integers are 64-bit |
82 static $hasINT64 = null; |
109 static $hasINT64 = null; |
83 if ($hasINT64 === null) { // 10x faster than is_null() |
110 if ($hasINT64 === null) { // 10x faster than is_null() |
84 $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1 |
111 $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1 |
85 if (!$hasINT64 && !defined('PHP_INT_MIN')) { |
112 if (!$hasINT64 && !defined('PHP_INT_MIN')) { |
86 define('PHP_INT_MIN', ~PHP_INT_MAX); |
113 define('PHP_INT_MIN', ~PHP_INT_MAX); |
87 } |
114 } |
88 } |
115 } |
89 // if integers are 64-bit - no other check required |
116 // if integers are 64-bit - no other check required |
90 if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { |
117 if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { // phpcs:ignore PHPCompatibility.Constants.NewConstants.php_int_minFound |
91 return true; |
118 return true; |
92 } |
119 } |
93 return false; |
120 return false; |
94 } |
121 } |
95 |
122 |
|
123 /** |
|
124 * @param string $fraction |
|
125 * |
|
126 * @return float |
|
127 */ |
96 public static function DecimalizeFraction($fraction) { |
128 public static function DecimalizeFraction($fraction) { |
97 list($numerator, $denominator) = explode('/', $fraction); |
129 list($numerator, $denominator) = explode('/', $fraction); |
98 return $numerator / ($denominator ? $denominator : 1); |
130 return $numerator / ($denominator ? $denominator : 1); |
99 } |
131 } |
100 |
132 |
101 |
133 /** |
|
134 * @param string $binarynumerator |
|
135 * |
|
136 * @return float |
|
137 */ |
102 public static function DecimalBinary2Float($binarynumerator) { |
138 public static function DecimalBinary2Float($binarynumerator) { |
103 $numerator = self::Bin2Dec($binarynumerator); |
139 $numerator = self::Bin2Dec($binarynumerator); |
104 $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); |
140 $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); |
105 return ($numerator / $denominator); |
141 return ($numerator / $denominator); |
106 } |
142 } |
107 |
143 |
108 |
144 /** |
|
145 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html |
|
146 * |
|
147 * @param string $binarypointnumber |
|
148 * @param int $maxbits |
|
149 * |
|
150 * @return array |
|
151 */ |
109 public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { |
152 public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { |
110 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html |
|
111 if (strpos($binarypointnumber, '.') === false) { |
153 if (strpos($binarypointnumber, '.') === false) { |
112 $binarypointnumber = '0.'.$binarypointnumber; |
154 $binarypointnumber = '0.'.$binarypointnumber; |
113 } elseif ($binarypointnumber{0} == '.') { |
155 } elseif ($binarypointnumber[0] == '.') { |
114 $binarypointnumber = '0'.$binarypointnumber; |
156 $binarypointnumber = '0'.$binarypointnumber; |
115 } |
157 } |
116 $exponent = 0; |
158 $exponent = 0; |
117 while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) { |
159 while (($binarypointnumber[0] != '1') || (substr($binarypointnumber, 1, 1) != '.')) { |
118 if (substr($binarypointnumber, 1, 1) == '.') { |
160 if (substr($binarypointnumber, 1, 1) == '.') { |
119 $exponent--; |
161 $exponent--; |
120 $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); |
162 $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); |
121 } else { |
163 } else { |
122 $pointpos = strpos($binarypointnumber, '.'); |
164 $pointpos = strpos($binarypointnumber, '.'); |
123 $exponent += ($pointpos - 1); |
165 $exponent += ($pointpos - 1); |
124 $binarypointnumber = str_replace('.', '', $binarypointnumber); |
166 $binarypointnumber = str_replace('.', '', $binarypointnumber); |
125 $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1); |
167 $binarypointnumber = $binarypointnumber[0].'.'.substr($binarypointnumber, 1); |
126 } |
168 } |
127 } |
169 } |
128 $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); |
170 $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); |
129 return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); |
171 return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); |
130 } |
172 } |
131 |
173 |
132 |
174 /** |
|
175 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html |
|
176 * |
|
177 * @param float $floatvalue |
|
178 * |
|
179 * @return string |
|
180 */ |
133 public static function Float2BinaryDecimal($floatvalue) { |
181 public static function Float2BinaryDecimal($floatvalue) { |
134 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html |
|
135 $maxbits = 128; // to how many bits of precision should the calculations be taken? |
182 $maxbits = 128; // to how many bits of precision should the calculations be taken? |
136 $intpart = self::trunc($floatvalue); |
183 $intpart = self::trunc($floatvalue); |
137 $floatpart = abs($floatvalue - $intpart); |
184 $floatpart = abs($floatvalue - $intpart); |
138 $pointbitstring = ''; |
185 $pointbitstring = ''; |
139 while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) { |
186 while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) { |
174 $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT); |
228 $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT); |
175 |
229 |
176 return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); |
230 return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); |
177 } |
231 } |
178 |
232 |
179 |
233 /** |
|
234 * @param string $byteword |
|
235 * |
|
236 * @return float|false |
|
237 */ |
180 public static function LittleEndian2Float($byteword) { |
238 public static function LittleEndian2Float($byteword) { |
181 return self::BigEndian2Float(strrev($byteword)); |
239 return self::BigEndian2Float(strrev($byteword)); |
182 } |
240 } |
183 |
241 |
184 |
242 /** |
|
243 * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic |
|
244 * |
|
245 * @link http://www.psc.edu/general/software/packages/ieee/ieee.html |
|
246 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html |
|
247 * |
|
248 * @param string $byteword |
|
249 * |
|
250 * @return float|false |
|
251 */ |
185 public static function BigEndian2Float($byteword) { |
252 public static function BigEndian2Float($byteword) { |
186 // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic |
|
187 // http://www.psc.edu/general/software/packages/ieee/ieee.html |
|
188 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html |
|
189 |
|
190 $bitword = self::BigEndian2Bin($byteword); |
253 $bitword = self::BigEndian2Bin($byteword); |
191 if (!$bitword) { |
254 if (!$bitword) { |
192 return 0; |
255 return 0; |
193 } |
256 } |
194 $signbit = $bitword{0}; |
257 $signbit = $bitword[0]; |
|
258 $floatvalue = 0; |
|
259 $exponentbits = 0; |
|
260 $fractionbits = 0; |
195 |
261 |
196 switch (strlen($byteword) * 8) { |
262 switch (strlen($byteword) * 8) { |
197 case 32: |
263 case 32: |
198 $exponentbits = 8; |
264 $exponentbits = 8; |
199 $fractionbits = 23; |
265 $fractionbits = 23; |
206 |
272 |
207 case 80: |
273 case 80: |
208 // 80-bit Apple SANE format |
274 // 80-bit Apple SANE format |
209 // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ |
275 // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ |
210 $exponentstring = substr($bitword, 1, 15); |
276 $exponentstring = substr($bitword, 1, 15); |
211 $isnormalized = intval($bitword{16}); |
277 $isnormalized = intval($bitword[16]); |
212 $fractionstring = substr($bitword, 17, 63); |
278 $fractionstring = substr($bitword, 17, 63); |
213 $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383); |
279 $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383); |
214 $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring); |
280 $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring); |
215 $floatvalue = $exponent * $fraction; |
281 $floatvalue = $exponent * $fraction; |
216 if ($signbit == '1') { |
282 if ($signbit == '1') { |
217 $floatvalue *= -1; |
283 $floatvalue *= -1; |
218 } |
284 } |
219 return $floatvalue; |
285 return $floatvalue; |
220 break; |
|
221 |
286 |
222 default: |
287 default: |
223 return false; |
288 return false; |
224 break; |
|
225 } |
289 } |
226 $exponentstring = substr($bitword, 1, $exponentbits); |
290 $exponentstring = substr($bitword, 1, $exponentbits); |
227 $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); |
291 $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); |
228 $exponent = self::Bin2Dec($exponentstring); |
292 $exponent = self::Bin2Dec($exponentstring); |
229 $fraction = self::Bin2Dec($fractionstring); |
293 $fraction = self::Bin2Dec($fractionstring); |
257 } |
321 } |
258 } |
322 } |
259 return (float) $floatvalue; |
323 return (float) $floatvalue; |
260 } |
324 } |
261 |
325 |
262 |
326 /** |
|
327 * @param string $byteword |
|
328 * @param bool $synchsafe |
|
329 * @param bool $signed |
|
330 * |
|
331 * @return int|float|false |
|
332 * @throws Exception |
|
333 */ |
263 public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { |
334 public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { |
264 $intvalue = 0; |
335 $intvalue = 0; |
265 $bytewordlen = strlen($byteword); |
336 $bytewordlen = strlen($byteword); |
266 if ($bytewordlen == 0) { |
337 if ($bytewordlen == 0) { |
267 return false; |
338 return false; |
268 } |
339 } |
269 for ($i = 0; $i < $bytewordlen; $i++) { |
340 for ($i = 0; $i < $bytewordlen; $i++) { |
270 if ($synchsafe) { // disregard MSB, effectively 7-bit bytes |
341 if ($synchsafe) { // disregard MSB, effectively 7-bit bytes |
271 //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems |
342 //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems |
272 $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7); |
343 $intvalue += (ord($byteword[$i]) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7); |
273 } else { |
344 } else { |
274 $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i)); |
345 $intvalue += ord($byteword[$i]) * pow(256, ($bytewordlen - 1 - $i)); |
275 } |
346 } |
276 } |
347 } |
277 if ($signed && !$synchsafe) { |
348 if ($signed && !$synchsafe) { |
278 // synchsafe ints are not allowed to be signed |
349 // synchsafe ints are not allowed to be signed |
279 if ($bytewordlen <= PHP_INT_SIZE) { |
350 if ($bytewordlen <= PHP_INT_SIZE) { |
286 } |
357 } |
287 } |
358 } |
288 return self::CastAsInt($intvalue); |
359 return self::CastAsInt($intvalue); |
289 } |
360 } |
290 |
361 |
291 |
362 /** |
|
363 * @param string $byteword |
|
364 * @param bool $signed |
|
365 * |
|
366 * @return int|float|false |
|
367 */ |
292 public static function LittleEndian2Int($byteword, $signed=false) { |
368 public static function LittleEndian2Int($byteword, $signed=false) { |
293 return self::BigEndian2Int(strrev($byteword), false, $signed); |
369 return self::BigEndian2Int(strrev($byteword), false, $signed); |
294 } |
370 } |
295 |
371 |
|
372 /** |
|
373 * @param string $byteword |
|
374 * |
|
375 * @return string |
|
376 */ |
296 public static function LittleEndian2Bin($byteword) { |
377 public static function LittleEndian2Bin($byteword) { |
297 return self::BigEndian2Bin(strrev($byteword)); |
378 return self::BigEndian2Bin(strrev($byteword)); |
298 } |
379 } |
299 |
380 |
|
381 /** |
|
382 * @param string $byteword |
|
383 * |
|
384 * @return string |
|
385 */ |
300 public static function BigEndian2Bin($byteword) { |
386 public static function BigEndian2Bin($byteword) { |
301 $binvalue = ''; |
387 $binvalue = ''; |
302 $bytewordlen = strlen($byteword); |
388 $bytewordlen = strlen($byteword); |
303 for ($i = 0; $i < $bytewordlen; $i++) { |
389 for ($i = 0; $i < $bytewordlen; $i++) { |
304 $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT); |
390 $binvalue .= str_pad(decbin(ord($byteword[$i])), 8, '0', STR_PAD_LEFT); |
305 } |
391 } |
306 return $binvalue; |
392 return $binvalue; |
307 } |
393 } |
308 |
394 |
309 |
395 /** |
|
396 * @param int $number |
|
397 * @param int $minbytes |
|
398 * @param bool $synchsafe |
|
399 * @param bool $signed |
|
400 * |
|
401 * @return string |
|
402 * @throws Exception |
|
403 */ |
310 public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { |
404 public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { |
311 if ($number < 0) { |
405 if ($number < 0) { |
312 throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers'); |
406 throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers'); |
313 } |
407 } |
314 $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF); |
408 $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF); |
355 $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); |
458 $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); |
356 } |
459 } |
357 return self::CastAsInt($decvalue * $signmult); |
460 return self::CastAsInt($decvalue * $signmult); |
358 } |
461 } |
359 |
462 |
360 |
463 /** |
|
464 * @param string $binstring |
|
465 * |
|
466 * @return string |
|
467 */ |
361 public static function Bin2String($binstring) { |
468 public static function Bin2String($binstring) { |
362 // return 'hi' for input of '0110100001101001' |
469 // return 'hi' for input of '0110100001101001' |
363 $string = ''; |
470 $string = ''; |
364 $binstringreversed = strrev($binstring); |
471 $binstringreversed = strrev($binstring); |
365 for ($i = 0; $i < strlen($binstringreversed); $i += 8) { |
472 for ($i = 0; $i < strlen($binstringreversed); $i += 8) { |
366 $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string; |
473 $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string; |
367 } |
474 } |
368 return $string; |
475 return $string; |
369 } |
476 } |
370 |
477 |
371 |
478 /** |
|
479 * @param int $number |
|
480 * @param int $minbytes |
|
481 * @param bool $synchsafe |
|
482 * |
|
483 * @return string |
|
484 */ |
372 public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { |
485 public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { |
373 $intstring = ''; |
486 $intstring = ''; |
374 while ($number > 0) { |
487 while ($number > 0) { |
375 if ($synchsafe) { |
488 if ($synchsafe) { |
376 $intstring = $intstring.chr($number & 127); |
489 $intstring = $intstring.chr($number & 127); |
455 return strrev(substr($reversedfilename, 0, $offset)); |
594 return strrev(substr($reversedfilename, 0, $offset)); |
456 } |
595 } |
457 return ''; |
596 return ''; |
458 } |
597 } |
459 |
598 |
460 |
599 /** |
|
600 * @param int $seconds |
|
601 * |
|
602 * @return string |
|
603 */ |
461 public static function PlaytimeString($seconds) { |
604 public static function PlaytimeString($seconds) { |
462 $sign = (($seconds < 0) ? '-' : ''); |
605 $sign = (($seconds < 0) ? '-' : ''); |
463 $seconds = round(abs($seconds)); |
606 $seconds = round(abs($seconds)); |
464 $H = (int) floor( $seconds / 3600); |
607 $H = (int) floor( $seconds / 3600); |
465 $M = (int) floor(($seconds - (3600 * $H) ) / 60); |
608 $M = (int) floor(($seconds - (3600 * $H) ) / 60); |
466 $S = (int) round( $seconds - (3600 * $H) - (60 * $M) ); |
609 $S = (int) round( $seconds - (3600 * $H) - (60 * $M) ); |
467 return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT); |
610 return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT); |
468 } |
611 } |
469 |
612 |
470 |
613 /** |
|
614 * @param int $macdate |
|
615 * |
|
616 * @return int|float |
|
617 */ |
471 public static function DateMac2Unix($macdate) { |
618 public static function DateMac2Unix($macdate) { |
472 // Macintosh timestamp: seconds since 00:00h January 1, 1904 |
619 // Macintosh timestamp: seconds since 00:00h January 1, 1904 |
473 // UNIX timestamp: seconds since 00:00h January 1, 1970 |
620 // UNIX timestamp: seconds since 00:00h January 1, 1970 |
474 return self::CastAsInt($macdate - 2082844800); |
621 return self::CastAsInt($macdate - 2082844800); |
475 } |
622 } |
476 |
623 |
477 |
624 /** |
|
625 * @param string $rawdata |
|
626 * |
|
627 * @return float |
|
628 */ |
478 public static function FixedPoint8_8($rawdata) { |
629 public static function FixedPoint8_8($rawdata) { |
479 return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); |
630 return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); |
480 } |
631 } |
481 |
632 |
482 |
633 /** |
|
634 * @param string $rawdata |
|
635 * |
|
636 * @return float |
|
637 */ |
483 public static function FixedPoint16_16($rawdata) { |
638 public static function FixedPoint16_16($rawdata) { |
484 return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); |
639 return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); |
485 } |
640 } |
486 |
641 |
487 |
642 /** |
|
643 * @param string $rawdata |
|
644 * |
|
645 * @return float |
|
646 */ |
488 public static function FixedPoint2_30($rawdata) { |
647 public static function FixedPoint2_30($rawdata) { |
489 $binarystring = self::BigEndian2Bin($rawdata); |
648 $binarystring = self::BigEndian2Bin($rawdata); |
490 return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30)); |
649 return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30)); |
491 } |
650 } |
492 |
651 |
493 |
652 |
|
653 /** |
|
654 * @param string $ArrayPath |
|
655 * @param string $Separator |
|
656 * @param mixed $Value |
|
657 * |
|
658 * @return array |
|
659 */ |
494 public static function CreateDeepArray($ArrayPath, $Separator, $Value) { |
660 public static function CreateDeepArray($ArrayPath, $Separator, $Value) { |
495 // assigns $Value to a nested array path: |
661 // assigns $Value to a nested array path: |
496 // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt') |
662 // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt') |
497 // is the same as: |
663 // is the same as: |
498 // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt')))); |
664 // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt')))); |
505 $ReturnedArray[$ArrayPath] = $Value; |
671 $ReturnedArray[$ArrayPath] = $Value; |
506 } |
672 } |
507 return $ReturnedArray; |
673 return $ReturnedArray; |
508 } |
674 } |
509 |
675 |
|
676 /** |
|
677 * @param array $arraydata |
|
678 * @param bool $returnkey |
|
679 * |
|
680 * @return int|false |
|
681 */ |
510 public static function array_max($arraydata, $returnkey=false) { |
682 public static function array_max($arraydata, $returnkey=false) { |
511 $maxvalue = false; |
683 $maxvalue = false; |
512 $maxkey = false; |
684 $maxkey = false; |
513 foreach ($arraydata as $key => $value) { |
685 foreach ($arraydata as $key => $value) { |
514 if (!is_array($value)) { |
686 if (!is_array($value)) { |
515 if ($value > $maxvalue) { |
687 if (($maxvalue === false) || ($value > $maxvalue)) { |
516 $maxvalue = $value; |
688 $maxvalue = $value; |
517 $maxkey = $key; |
689 $maxkey = $key; |
518 } |
690 } |
519 } |
691 } |
520 } |
692 } |
521 return ($returnkey ? $maxkey : $maxvalue); |
693 return ($returnkey ? $maxkey : $maxvalue); |
522 } |
694 } |
523 |
695 |
|
696 /** |
|
697 * @param array $arraydata |
|
698 * @param bool $returnkey |
|
699 * |
|
700 * @return int|false |
|
701 */ |
524 public static function array_min($arraydata, $returnkey=false) { |
702 public static function array_min($arraydata, $returnkey=false) { |
525 $minvalue = false; |
703 $minvalue = false; |
526 $minkey = false; |
704 $minkey = false; |
527 foreach ($arraydata as $key => $value) { |
705 foreach ($arraydata as $key => $value) { |
528 if (!is_array($value)) { |
706 if (!is_array($value)) { |
529 if ($value > $minvalue) { |
707 if (($minvalue === false) || ($value < $minvalue)) { |
530 $minvalue = $value; |
708 $minvalue = $value; |
531 $minkey = $key; |
709 $minkey = $key; |
532 } |
710 } |
533 } |
711 } |
534 } |
712 } |
535 return ($returnkey ? $minkey : $minvalue); |
713 return ($returnkey ? $minkey : $minvalue); |
536 } |
714 } |
537 |
715 |
|
716 /** |
|
717 * @param string $XMLstring |
|
718 * |
|
719 * @return array|false |
|
720 */ |
538 public static function XML2array($XMLstring) { |
721 public static function XML2array($XMLstring) { |
539 if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) { |
722 if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) { |
540 // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html |
723 // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html |
541 // https://core.trac.wordpress.org/changeset/29378 |
724 // https://core.trac.wordpress.org/changeset/29378 |
542 $loader = libxml_disable_entity_loader(true); |
725 $loader = libxml_disable_entity_loader(true); |
546 return $return; |
729 return $return; |
547 } |
730 } |
548 return false; |
731 return false; |
549 } |
732 } |
550 |
733 |
|
734 /** |
|
735 * @param SimpleXMLElement|array|mixed $XMLobject |
|
736 * |
|
737 * @return mixed |
|
738 */ |
551 public static function SimpleXMLelement2array($XMLobject) { |
739 public static function SimpleXMLelement2array($XMLobject) { |
552 if (!is_object($XMLobject) && !is_array($XMLobject)) { |
740 if (!is_object($XMLobject) && !is_array($XMLobject)) { |
553 return $XMLobject; |
741 return $XMLobject; |
554 } |
742 } |
555 $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject); |
743 $XMLarray = $XMLobject instanceof SimpleXMLElement ? get_object_vars($XMLobject) : $XMLobject; |
556 foreach ($XMLarray as $key => $value) { |
744 foreach ($XMLarray as $key => $value) { |
557 $XMLarray[$key] = self::SimpleXMLelement2array($value); |
745 $XMLarray[$key] = self::SimpleXMLelement2array($value); |
558 } |
746 } |
559 return $XMLarray; |
747 return $XMLarray; |
560 } |
748 } |
561 |
749 |
562 |
750 /** |
563 // Allan Hansen <ahØartemis*dk> |
751 * Returns checksum for a file from starting position to absolute end position. |
564 // self::md5_data() - returns md5sum for a file from startuing position to absolute end position |
752 * |
|
753 * @param string $file |
|
754 * @param int $offset |
|
755 * @param int $end |
|
756 * @param string $algorithm |
|
757 * |
|
758 * @return string|false |
|
759 * @throws getid3_exception |
|
760 */ |
565 public static function hash_data($file, $offset, $end, $algorithm) { |
761 public static function hash_data($file, $offset, $end, $algorithm) { |
566 static $tempdir = ''; |
|
567 if (!self::intValueSupported($end)) { |
762 if (!self::intValueSupported($end)) { |
568 return false; |
763 return false; |
569 } |
764 } |
570 switch ($algorithm) { |
765 if (!in_array($algorithm, array('md5', 'sha1'))) { |
571 case 'md5': |
766 throw new getid3_exception('Invalid algorithm ('.$algorithm.') in self::hash_data()'); |
572 $hash_function = 'md5_file'; |
767 } |
573 $unix_call = 'md5sum'; |
768 |
574 $windows_call = 'md5sum.exe'; |
|
575 $hash_length = 32; |
|
576 break; |
|
577 |
|
578 case 'sha1': |
|
579 $hash_function = 'sha1_file'; |
|
580 $unix_call = 'sha1sum'; |
|
581 $windows_call = 'sha1sum.exe'; |
|
582 $hash_length = 40; |
|
583 break; |
|
584 |
|
585 default: |
|
586 throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()'); |
|
587 break; |
|
588 } |
|
589 $size = $end - $offset; |
769 $size = $end - $offset; |
590 while (true) { |
770 |
591 if (GETID3_OS_ISWINDOWS) { |
771 $fp = fopen($file, 'rb'); |
592 |
772 fseek($fp, $offset); |
593 // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data |
773 $ctx = hash_init($algorithm); |
594 // Fall back to create-temp-file method: |
774 while ($size > 0) { |
595 if ($algorithm == 'sha1') { |
775 $buffer = fread($fp, min($size, getID3::FREAD_BUFFER_SIZE)); |
596 break; |
776 hash_update($ctx, $buffer); |
597 } |
777 $size -= getID3::FREAD_BUFFER_SIZE; |
598 |
778 } |
599 $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); |
779 $hash = hash_final($ctx); |
600 foreach ($RequiredFiles as $required_file) { |
780 fclose($fp); |
601 if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { |
781 |
602 // helper apps not available - fall back to old method |
782 return $hash; |
603 break 2; |
783 } |
604 } |
784 |
605 } |
785 /** |
606 $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | '; |
786 * @param string $filename_source |
607 $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | '; |
787 * @param string $filename_dest |
608 $commandline .= GETID3_HELPERAPPSDIR.$windows_call; |
788 * @param int $offset |
609 |
789 * @param int $length |
610 } else { |
790 * |
611 |
791 * @return bool |
612 $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | '; |
792 * @throws Exception |
613 $commandline .= 'tail -c'.$size.' | '; |
793 * |
614 $commandline .= $unix_call; |
794 * @deprecated Unused, may be removed in future versions of getID3 |
615 |
795 */ |
616 } |
|
617 if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { |
|
618 //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm'); |
|
619 break; |
|
620 } |
|
621 return substr(`$commandline`, 0, $hash_length); |
|
622 } |
|
623 |
|
624 if (empty($tempdir)) { |
|
625 // yes this is ugly, feel free to suggest a better way |
|
626 require_once(dirname(__FILE__).'/getid3.php'); |
|
627 $getid3_temp = new getID3(); |
|
628 $tempdir = $getid3_temp->tempdir; |
|
629 unset($getid3_temp); |
|
630 } |
|
631 // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir |
|
632 if (($data_filename = tempnam($tempdir, 'gI3')) === false) { |
|
633 // can't find anywhere to create a temp file, just fail |
|
634 return false; |
|
635 } |
|
636 |
|
637 // Init |
|
638 $result = false; |
|
639 |
|
640 // copy parts of file |
|
641 try { |
|
642 self::CopyFileParts($file, $data_filename, $offset, $end - $offset); |
|
643 $result = $hash_function($data_filename); |
|
644 } catch (Exception $e) { |
|
645 throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage()); |
|
646 } |
|
647 unlink($data_filename); |
|
648 return $result; |
|
649 } |
|
650 |
|
651 public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) { |
796 public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) { |
652 if (!self::intValueSupported($offset + $length)) { |
797 if (!self::intValueSupported($offset + $length)) { |
653 throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit'); |
798 throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit'); |
654 } |
799 } |
655 if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) { |
800 if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) { |
658 $byteslefttowrite = $length; |
803 $byteslefttowrite = $length; |
659 while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) { |
804 while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) { |
660 $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite); |
805 $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite); |
661 $byteslefttowrite -= $byteswritten; |
806 $byteslefttowrite -= $byteswritten; |
662 } |
807 } |
|
808 fclose($fp_dest); |
663 return true; |
809 return true; |
664 } else { |
810 } else { |
|
811 fclose($fp_src); |
665 throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source); |
812 throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source); |
666 } |
813 } |
667 fclose($fp_dest); |
|
668 } else { |
814 } else { |
669 throw new Exception('failed to create file for writing '.$filename_dest); |
815 throw new Exception('failed to create file for writing '.$filename_dest); |
670 } |
816 } |
671 fclose($fp_src); |
|
672 } else { |
817 } else { |
673 throw new Exception('failed to open file for reading '.$filename_source); |
818 throw new Exception('failed to open file for reading '.$filename_source); |
674 } |
819 } |
675 return false; |
820 } |
676 } |
821 |
677 |
822 /** |
|
823 * @param int $charval |
|
824 * |
|
825 * @return string |
|
826 */ |
678 public static function iconv_fallback_int_utf8($charval) { |
827 public static function iconv_fallback_int_utf8($charval) { |
679 if ($charval < 128) { |
828 if ($charval < 128) { |
680 // 0bbbbbbb |
829 // 0bbbbbbb |
681 $newcharstring = chr($charval); |
830 $newcharstring = chr($charval); |
682 } elseif ($charval < 2048) { |
831 } elseif ($charval < 2048) { |
696 $newcharstring .= chr(($charval & 0x3F) | 0x80); |
845 $newcharstring .= chr(($charval & 0x3F) | 0x80); |
697 } |
846 } |
698 return $newcharstring; |
847 return $newcharstring; |
699 } |
848 } |
700 |
849 |
701 // ISO-8859-1 => UTF-8 |
850 /** |
|
851 * ISO-8859-1 => UTF-8 |
|
852 * |
|
853 * @param string $string |
|
854 * @param bool $bom |
|
855 * |
|
856 * @return string |
|
857 */ |
702 public static function iconv_fallback_iso88591_utf8($string, $bom=false) { |
858 public static function iconv_fallback_iso88591_utf8($string, $bom=false) { |
703 if (function_exists('utf8_encode')) { |
859 if (function_exists('utf8_encode')) { |
704 return utf8_encode($string); |
860 return utf8_encode($string); |
705 } |
861 } |
706 // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) |
862 // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) |
707 $newcharstring = ''; |
863 $newcharstring = ''; |
708 if ($bom) { |
864 if ($bom) { |
709 $newcharstring .= "\xEF\xBB\xBF"; |
865 $newcharstring .= "\xEF\xBB\xBF"; |
710 } |
866 } |
711 for ($i = 0; $i < strlen($string); $i++) { |
867 for ($i = 0; $i < strlen($string); $i++) { |
712 $charval = ord($string{$i}); |
868 $charval = ord($string[$i]); |
713 $newcharstring .= self::iconv_fallback_int_utf8($charval); |
869 $newcharstring .= self::iconv_fallback_int_utf8($charval); |
714 } |
870 } |
715 return $newcharstring; |
871 return $newcharstring; |
716 } |
872 } |
717 |
873 |
718 // ISO-8859-1 => UTF-16BE |
874 /** |
|
875 * ISO-8859-1 => UTF-16BE |
|
876 * |
|
877 * @param string $string |
|
878 * @param bool $bom |
|
879 * |
|
880 * @return string |
|
881 */ |
719 public static function iconv_fallback_iso88591_utf16be($string, $bom=false) { |
882 public static function iconv_fallback_iso88591_utf16be($string, $bom=false) { |
720 $newcharstring = ''; |
883 $newcharstring = ''; |
721 if ($bom) { |
884 if ($bom) { |
722 $newcharstring .= "\xFE\xFF"; |
885 $newcharstring .= "\xFE\xFF"; |
723 } |
886 } |
724 for ($i = 0; $i < strlen($string); $i++) { |
887 for ($i = 0; $i < strlen($string); $i++) { |
725 $newcharstring .= "\x00".$string{$i}; |
888 $newcharstring .= "\x00".$string[$i]; |
726 } |
889 } |
727 return $newcharstring; |
890 return $newcharstring; |
728 } |
891 } |
729 |
892 |
730 // ISO-8859-1 => UTF-16LE |
893 /** |
|
894 * ISO-8859-1 => UTF-16LE |
|
895 * |
|
896 * @param string $string |
|
897 * @param bool $bom |
|
898 * |
|
899 * @return string |
|
900 */ |
731 public static function iconv_fallback_iso88591_utf16le($string, $bom=false) { |
901 public static function iconv_fallback_iso88591_utf16le($string, $bom=false) { |
732 $newcharstring = ''; |
902 $newcharstring = ''; |
733 if ($bom) { |
903 if ($bom) { |
734 $newcharstring .= "\xFF\xFE"; |
904 $newcharstring .= "\xFF\xFE"; |
735 } |
905 } |
736 for ($i = 0; $i < strlen($string); $i++) { |
906 for ($i = 0; $i < strlen($string); $i++) { |
737 $newcharstring .= $string{$i}."\x00"; |
907 $newcharstring .= $string[$i]."\x00"; |
738 } |
908 } |
739 return $newcharstring; |
909 return $newcharstring; |
740 } |
910 } |
741 |
911 |
742 // ISO-8859-1 => UTF-16LE (BOM) |
912 /** |
|
913 * ISO-8859-1 => UTF-16LE (BOM) |
|
914 * |
|
915 * @param string $string |
|
916 * |
|
917 * @return string |
|
918 */ |
743 public static function iconv_fallback_iso88591_utf16($string) { |
919 public static function iconv_fallback_iso88591_utf16($string) { |
744 return self::iconv_fallback_iso88591_utf16le($string, true); |
920 return self::iconv_fallback_iso88591_utf16le($string, true); |
745 } |
921 } |
746 |
922 |
747 // UTF-8 => ISO-8859-1 |
923 /** |
|
924 * UTF-8 => ISO-8859-1 |
|
925 * |
|
926 * @param string $string |
|
927 * |
|
928 * @return string |
|
929 */ |
748 public static function iconv_fallback_utf8_iso88591($string) { |
930 public static function iconv_fallback_utf8_iso88591($string) { |
749 if (function_exists('utf8_decode')) { |
931 if (function_exists('utf8_decode')) { |
750 return utf8_decode($string); |
932 return utf8_decode($string); |
751 } |
933 } |
752 // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) |
934 // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) |
753 $newcharstring = ''; |
935 $newcharstring = ''; |
754 $offset = 0; |
936 $offset = 0; |
755 $stringlength = strlen($string); |
937 $stringlength = strlen($string); |
756 while ($offset < $stringlength) { |
938 while ($offset < $stringlength) { |
757 if ((ord($string{$offset}) | 0x07) == 0xF7) { |
939 if ((ord($string[$offset]) | 0x07) == 0xF7) { |
758 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
940 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
759 $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & |
941 $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) & |
760 ((ord($string{($offset + 1)}) & 0x3F) << 12) & |
942 ((ord($string[($offset + 1)]) & 0x3F) << 12) & |
761 ((ord($string{($offset + 2)}) & 0x3F) << 6) & |
943 ((ord($string[($offset + 2)]) & 0x3F) << 6) & |
762 (ord($string{($offset + 3)}) & 0x3F); |
944 (ord($string[($offset + 3)]) & 0x3F); |
763 $offset += 4; |
945 $offset += 4; |
764 } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { |
946 } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) { |
765 // 1110bbbb 10bbbbbb 10bbbbbb |
947 // 1110bbbb 10bbbbbb 10bbbbbb |
766 $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & |
948 $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) & |
767 ((ord($string{($offset + 1)}) & 0x3F) << 6) & |
949 ((ord($string[($offset + 1)]) & 0x3F) << 6) & |
768 (ord($string{($offset + 2)}) & 0x3F); |
950 (ord($string[($offset + 2)]) & 0x3F); |
769 $offset += 3; |
951 $offset += 3; |
770 } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { |
952 } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) { |
771 // 110bbbbb 10bbbbbb |
953 // 110bbbbb 10bbbbbb |
772 $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & |
954 $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) & |
773 (ord($string{($offset + 1)}) & 0x3F); |
955 (ord($string[($offset + 1)]) & 0x3F); |
774 $offset += 2; |
956 $offset += 2; |
775 } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { |
957 } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) { |
776 // 0bbbbbbb |
958 // 0bbbbbbb |
777 $charval = ord($string{$offset}); |
959 $charval = ord($string[$offset]); |
778 $offset += 1; |
960 $offset += 1; |
779 } else { |
961 } else { |
780 // error? throw some kind of warning here? |
962 // error? throw some kind of warning here? |
781 $charval = false; |
963 $charval = false; |
782 $offset += 1; |
964 $offset += 1; |
786 } |
968 } |
787 } |
969 } |
788 return $newcharstring; |
970 return $newcharstring; |
789 } |
971 } |
790 |
972 |
791 // UTF-8 => UTF-16BE |
973 /** |
|
974 * UTF-8 => UTF-16BE |
|
975 * |
|
976 * @param string $string |
|
977 * @param bool $bom |
|
978 * |
|
979 * @return string |
|
980 */ |
792 public static function iconv_fallback_utf8_utf16be($string, $bom=false) { |
981 public static function iconv_fallback_utf8_utf16be($string, $bom=false) { |
793 $newcharstring = ''; |
982 $newcharstring = ''; |
794 if ($bom) { |
983 if ($bom) { |
795 $newcharstring .= "\xFE\xFF"; |
984 $newcharstring .= "\xFE\xFF"; |
796 } |
985 } |
797 $offset = 0; |
986 $offset = 0; |
798 $stringlength = strlen($string); |
987 $stringlength = strlen($string); |
799 while ($offset < $stringlength) { |
988 while ($offset < $stringlength) { |
800 if ((ord($string{$offset}) | 0x07) == 0xF7) { |
989 if ((ord($string[$offset]) | 0x07) == 0xF7) { |
801 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
990 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
802 $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & |
991 $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) & |
803 ((ord($string{($offset + 1)}) & 0x3F) << 12) & |
992 ((ord($string[($offset + 1)]) & 0x3F) << 12) & |
804 ((ord($string{($offset + 2)}) & 0x3F) << 6) & |
993 ((ord($string[($offset + 2)]) & 0x3F) << 6) & |
805 (ord($string{($offset + 3)}) & 0x3F); |
994 (ord($string[($offset + 3)]) & 0x3F); |
806 $offset += 4; |
995 $offset += 4; |
807 } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { |
996 } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) { |
808 // 1110bbbb 10bbbbbb 10bbbbbb |
997 // 1110bbbb 10bbbbbb 10bbbbbb |
809 $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & |
998 $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) & |
810 ((ord($string{($offset + 1)}) & 0x3F) << 6) & |
999 ((ord($string[($offset + 1)]) & 0x3F) << 6) & |
811 (ord($string{($offset + 2)}) & 0x3F); |
1000 (ord($string[($offset + 2)]) & 0x3F); |
812 $offset += 3; |
1001 $offset += 3; |
813 } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { |
1002 } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) { |
814 // 110bbbbb 10bbbbbb |
1003 // 110bbbbb 10bbbbbb |
815 $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & |
1004 $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) & |
816 (ord($string{($offset + 1)}) & 0x3F); |
1005 (ord($string[($offset + 1)]) & 0x3F); |
817 $offset += 2; |
1006 $offset += 2; |
818 } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { |
1007 } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) { |
819 // 0bbbbbbb |
1008 // 0bbbbbbb |
820 $charval = ord($string{$offset}); |
1009 $charval = ord($string[$offset]); |
821 $offset += 1; |
1010 $offset += 1; |
822 } else { |
1011 } else { |
823 // error? throw some kind of warning here? |
1012 // error? throw some kind of warning here? |
824 $charval = false; |
1013 $charval = false; |
825 $offset += 1; |
1014 $offset += 1; |
829 } |
1018 } |
830 } |
1019 } |
831 return $newcharstring; |
1020 return $newcharstring; |
832 } |
1021 } |
833 |
1022 |
834 // UTF-8 => UTF-16LE |
1023 /** |
|
1024 * UTF-8 => UTF-16LE |
|
1025 * |
|
1026 * @param string $string |
|
1027 * @param bool $bom |
|
1028 * |
|
1029 * @return string |
|
1030 */ |
835 public static function iconv_fallback_utf8_utf16le($string, $bom=false) { |
1031 public static function iconv_fallback_utf8_utf16le($string, $bom=false) { |
836 $newcharstring = ''; |
1032 $newcharstring = ''; |
837 if ($bom) { |
1033 if ($bom) { |
838 $newcharstring .= "\xFF\xFE"; |
1034 $newcharstring .= "\xFF\xFE"; |
839 } |
1035 } |
840 $offset = 0; |
1036 $offset = 0; |
841 $stringlength = strlen($string); |
1037 $stringlength = strlen($string); |
842 while ($offset < $stringlength) { |
1038 while ($offset < $stringlength) { |
843 if ((ord($string{$offset}) | 0x07) == 0xF7) { |
1039 if ((ord($string[$offset]) | 0x07) == 0xF7) { |
844 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
1040 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
845 $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & |
1041 $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) & |
846 ((ord($string{($offset + 1)}) & 0x3F) << 12) & |
1042 ((ord($string[($offset + 1)]) & 0x3F) << 12) & |
847 ((ord($string{($offset + 2)}) & 0x3F) << 6) & |
1043 ((ord($string[($offset + 2)]) & 0x3F) << 6) & |
848 (ord($string{($offset + 3)}) & 0x3F); |
1044 (ord($string[($offset + 3)]) & 0x3F); |
849 $offset += 4; |
1045 $offset += 4; |
850 } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { |
1046 } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) { |
851 // 1110bbbb 10bbbbbb 10bbbbbb |
1047 // 1110bbbb 10bbbbbb 10bbbbbb |
852 $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & |
1048 $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) & |
853 ((ord($string{($offset + 1)}) & 0x3F) << 6) & |
1049 ((ord($string[($offset + 1)]) & 0x3F) << 6) & |
854 (ord($string{($offset + 2)}) & 0x3F); |
1050 (ord($string[($offset + 2)]) & 0x3F); |
855 $offset += 3; |
1051 $offset += 3; |
856 } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { |
1052 } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) { |
857 // 110bbbbb 10bbbbbb |
1053 // 110bbbbb 10bbbbbb |
858 $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & |
1054 $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) & |
859 (ord($string{($offset + 1)}) & 0x3F); |
1055 (ord($string[($offset + 1)]) & 0x3F); |
860 $offset += 2; |
1056 $offset += 2; |
861 } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { |
1057 } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) { |
862 // 0bbbbbbb |
1058 // 0bbbbbbb |
863 $charval = ord($string{$offset}); |
1059 $charval = ord($string[$offset]); |
864 $offset += 1; |
1060 $offset += 1; |
865 } else { |
1061 } else { |
866 // error? maybe throw some warning here? |
1062 // error? maybe throw some warning here? |
867 $charval = false; |
1063 $charval = false; |
868 $offset += 1; |
1064 $offset += 1; |
933 $newcharstring .= (($charval < 256) ? chr($charval) : '?'); |
1159 $newcharstring .= (($charval < 256) ? chr($charval) : '?'); |
934 } |
1160 } |
935 return $newcharstring; |
1161 return $newcharstring; |
936 } |
1162 } |
937 |
1163 |
938 // UTF-16 (BOM) => ISO-8859-1 |
1164 /** |
|
1165 * UTF-16 (BOM) => ISO-8859-1 |
|
1166 * |
|
1167 * @param string $string |
|
1168 * |
|
1169 * @return string |
|
1170 */ |
939 public static function iconv_fallback_utf16_iso88591($string) { |
1171 public static function iconv_fallback_utf16_iso88591($string) { |
940 $bom = substr($string, 0, 2); |
1172 $bom = substr($string, 0, 2); |
941 if ($bom == "\xFE\xFF") { |
1173 if ($bom == "\xFE\xFF") { |
942 return self::iconv_fallback_utf16be_iso88591(substr($string, 2)); |
1174 return self::iconv_fallback_utf16be_iso88591(substr($string, 2)); |
943 } elseif ($bom == "\xFF\xFE") { |
1175 } elseif ($bom == "\xFF\xFE") { |
944 return self::iconv_fallback_utf16le_iso88591(substr($string, 2)); |
1176 return self::iconv_fallback_utf16le_iso88591(substr($string, 2)); |
945 } |
1177 } |
946 return $string; |
1178 return $string; |
947 } |
1179 } |
948 |
1180 |
949 // UTF-16 (BOM) => UTF-8 |
1181 /** |
|
1182 * UTF-16 (BOM) => UTF-8 |
|
1183 * |
|
1184 * @param string $string |
|
1185 * |
|
1186 * @return string |
|
1187 */ |
950 public static function iconv_fallback_utf16_utf8($string) { |
1188 public static function iconv_fallback_utf16_utf8($string) { |
951 $bom = substr($string, 0, 2); |
1189 $bom = substr($string, 0, 2); |
952 if ($bom == "\xFE\xFF") { |
1190 if ($bom == "\xFE\xFF") { |
953 return self::iconv_fallback_utf16be_utf8(substr($string, 2)); |
1191 return self::iconv_fallback_utf16be_utf8(substr($string, 2)); |
954 } elseif ($bom == "\xFF\xFE") { |
1192 } elseif ($bom == "\xFF\xFE") { |
955 return self::iconv_fallback_utf16le_utf8(substr($string, 2)); |
1193 return self::iconv_fallback_utf16le_utf8(substr($string, 2)); |
956 } |
1194 } |
957 return $string; |
1195 return $string; |
958 } |
1196 } |
959 |
1197 |
|
1198 /** |
|
1199 * @param string $in_charset |
|
1200 * @param string $out_charset |
|
1201 * @param string $string |
|
1202 * |
|
1203 * @return string |
|
1204 * @throws Exception |
|
1205 */ |
960 public static function iconv_fallback($in_charset, $out_charset, $string) { |
1206 public static function iconv_fallback($in_charset, $out_charset, $string) { |
961 |
1207 |
962 if ($in_charset == $out_charset) { |
1208 if ($in_charset == $out_charset) { |
963 return $string; |
1209 return $string; |
964 } |
1210 } |
965 |
1211 |
966 // mb_convert_encoding() availble |
1212 // mb_convert_encoding() available |
967 if (function_exists('mb_convert_encoding')) { |
1213 if (function_exists('mb_convert_encoding')) { |
|
1214 if ((strtoupper($in_charset) == 'UTF-16') && (substr($string, 0, 2) != "\xFE\xFF") && (substr($string, 0, 2) != "\xFF\xFE")) { |
|
1215 // if BOM missing, mb_convert_encoding will mishandle the conversion, assume UTF-16BE and prepend appropriate BOM |
|
1216 $string = "\xFF\xFE".$string; |
|
1217 } |
|
1218 if ((strtoupper($in_charset) == 'UTF-16') && (strtoupper($out_charset) == 'UTF-8')) { |
|
1219 if (($string == "\xFF\xFE") || ($string == "\xFE\xFF")) { |
|
1220 // if string consists of only BOM, mb_convert_encoding will return the BOM unmodified |
|
1221 return ''; |
|
1222 } |
|
1223 } |
968 if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) { |
1224 if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) { |
969 switch ($out_charset) { |
1225 switch ($out_charset) { |
970 case 'ISO-8859-1': |
1226 case 'ISO-8859-1': |
971 $converted_string = rtrim($converted_string, "\x00"); |
1227 $converted_string = rtrim($converted_string, "\x00"); |
972 break; |
1228 break; |
973 } |
1229 } |
974 return $converted_string; |
1230 return $converted_string; |
975 } |
1231 } |
976 return $string; |
1232 return $string; |
977 } |
1233 |
978 // iconv() availble |
1234 // iconv() available |
979 else if (function_exists('iconv')) { |
1235 } elseif (function_exists('iconv')) { |
980 if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { |
1236 if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { |
981 switch ($out_charset) { |
1237 switch ($out_charset) { |
982 case 'ISO-8859-1': |
1238 case 'ISO-8859-1': |
983 $converted_string = rtrim($converted_string, "\x00"); |
1239 $converted_string = rtrim($converted_string, "\x00"); |
984 break; |
1240 break; |
1067 break; |
1335 break; |
1068 |
1336 |
1069 case 'utf-8': |
1337 case 'utf-8': |
1070 $strlen = strlen($string); |
1338 $strlen = strlen($string); |
1071 for ($i = 0; $i < $strlen; $i++) { |
1339 for ($i = 0; $i < $strlen; $i++) { |
1072 $char_ord_val = ord($string{$i}); |
1340 $char_ord_val = ord($string[$i]); |
1073 $charval = 0; |
1341 $charval = 0; |
1074 if ($char_ord_val < 0x80) { |
1342 if ($char_ord_val < 0x80) { |
1075 $charval = $char_ord_val; |
1343 $charval = $char_ord_val; |
1076 } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) { |
1344 } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) { |
1077 $charval = (($char_ord_val & 0x07) << 18); |
1345 $charval = (($char_ord_val & 0x07) << 18); |
1078 $charval += ((ord($string{++$i}) & 0x3F) << 12); |
1346 $charval += ((ord($string[++$i]) & 0x3F) << 12); |
1079 $charval += ((ord($string{++$i}) & 0x3F) << 6); |
1347 $charval += ((ord($string[++$i]) & 0x3F) << 6); |
1080 $charval += (ord($string{++$i}) & 0x3F); |
1348 $charval += (ord($string[++$i]) & 0x3F); |
1081 } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) { |
1349 } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) { |
1082 $charval = (($char_ord_val & 0x0F) << 12); |
1350 $charval = (($char_ord_val & 0x0F) << 12); |
1083 $charval += ((ord($string{++$i}) & 0x3F) << 6); |
1351 $charval += ((ord($string[++$i]) & 0x3F) << 6); |
1084 $charval += (ord($string{++$i}) & 0x3F); |
1352 $charval += (ord($string[++$i]) & 0x3F); |
1085 } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) { |
1353 } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) { |
1086 $charval = (($char_ord_val & 0x1F) << 6); |
1354 $charval = (($char_ord_val & 0x1F) << 6); |
1087 $charval += (ord($string{++$i}) & 0x3F); |
1355 $charval += (ord($string[++$i]) & 0x3F); |
1088 } |
1356 } |
1089 if (($charval >= 32) && ($charval <= 127)) { |
1357 if (($charval >= 32) && ($charval <= 127)) { |
1090 $HTMLstring .= htmlentities(chr($charval)); |
1358 $HTMLstring .= htmlentities(chr($charval)); |
1091 } else { |
1359 } else { |
1092 $HTMLstring .= '&#'.$charval.';'; |
1360 $HTMLstring .= '&#'.$charval.';'; |
1172 $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT); |
1458 $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT); |
1173 |
1459 |
1174 return $gainstring; |
1460 return $gainstring; |
1175 } |
1461 } |
1176 |
1462 |
|
1463 /** |
|
1464 * @param float $amplitude |
|
1465 * |
|
1466 * @return float |
|
1467 */ |
1177 public static function RGADamplitude2dB($amplitude) { |
1468 public static function RGADamplitude2dB($amplitude) { |
1178 return 20 * log10($amplitude); |
1469 return 20 * log10($amplitude); |
1179 } |
1470 } |
1180 |
1471 |
1181 |
1472 /** |
|
1473 * @param string $imgData |
|
1474 * @param array $imageinfo |
|
1475 * |
|
1476 * @return array|false |
|
1477 */ |
1182 public static function GetDataImageSize($imgData, &$imageinfo=array()) { |
1478 public static function GetDataImageSize($imgData, &$imageinfo=array()) { |
|
1479 if (PHP_VERSION_ID >= 50400) { |
|
1480 $GetDataImageSize = @getimagesizefromstring($imgData, $imageinfo); |
|
1481 if ($GetDataImageSize === false || !isset($GetDataImageSize[0], $GetDataImageSize[1])) { |
|
1482 return false; |
|
1483 } |
|
1484 $GetDataImageSize['height'] = $GetDataImageSize[0]; |
|
1485 $GetDataImageSize['width'] = $GetDataImageSize[1]; |
|
1486 return $GetDataImageSize; |
|
1487 } |
1183 static $tempdir = ''; |
1488 static $tempdir = ''; |
1184 if (empty($tempdir)) { |
1489 if (empty($tempdir)) { |
1185 if (function_exists('sys_get_temp_dir')) { |
1490 if (function_exists('sys_get_temp_dir')) { |
1186 $tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52 |
1491 $tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52 |
1187 } |
1492 } |
1188 |
1493 |
1189 // yes this is ugly, feel free to suggest a better way |
1494 // yes this is ugly, feel free to suggest a better way |
1190 if (include_once(dirname(__FILE__).'/getid3.php')) { |
1495 if (include_once(dirname(__FILE__).'/getid3.php')) { |
1191 if ($getid3_temp = new getID3()) { |
1496 $getid3_temp = new getID3(); |
1192 if ($getid3_temp_tempdir = $getid3_temp->tempdir) { |
1497 if ($getid3_temp_tempdir = $getid3_temp->tempdir) { |
1193 $tempdir = $getid3_temp_tempdir; |
1498 $tempdir = $getid3_temp_tempdir; |
1194 } |
|
1195 unset($getid3_temp, $getid3_temp_tempdir); |
|
1196 } |
1499 } |
|
1500 unset($getid3_temp, $getid3_temp_tempdir); |
1197 } |
1501 } |
1198 } |
1502 } |
1199 $GetDataImageSize = false; |
1503 $GetDataImageSize = false; |
1200 if ($tempfilename = tempnam($tempdir, 'gI3')) { |
1504 if ($tempfilename = tempnam($tempdir, 'gI3')) { |
1201 if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) { |
1505 if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) { |
1211 unlink($tempfilename); |
1515 unlink($tempfilename); |
1212 } |
1516 } |
1213 return $GetDataImageSize; |
1517 return $GetDataImageSize; |
1214 } |
1518 } |
1215 |
1519 |
|
1520 /** |
|
1521 * @param string $mime_type |
|
1522 * |
|
1523 * @return string |
|
1524 */ |
1216 public static function ImageExtFromMime($mime_type) { |
1525 public static function ImageExtFromMime($mime_type) { |
1217 // temporary way, works OK for now, but should be reworked in the future |
1526 // temporary way, works OK for now, but should be reworked in the future |
1218 return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type); |
1527 return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type); |
1219 } |
1528 } |
1220 |
1529 |
1221 public static function ImageTypesLookup($imagetypeid) { |
1530 /** |
1222 static $ImageTypesLookup = array(); |
1531 * @param array $ThisFileInfo |
1223 if (empty($ImageTypesLookup)) { |
1532 * @param bool $option_tags_html default true (just as in the main getID3 class) |
1224 $ImageTypesLookup[1] = 'gif'; |
1533 * |
1225 $ImageTypesLookup[2] = 'jpeg'; |
1534 * @return bool |
1226 $ImageTypesLookup[3] = 'png'; |
1535 */ |
1227 $ImageTypesLookup[4] = 'swf'; |
1536 public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) { |
1228 $ImageTypesLookup[5] = 'psd'; |
|
1229 $ImageTypesLookup[6] = 'bmp'; |
|
1230 $ImageTypesLookup[7] = 'tiff (little-endian)'; |
|
1231 $ImageTypesLookup[8] = 'tiff (big-endian)'; |
|
1232 $ImageTypesLookup[9] = 'jpc'; |
|
1233 $ImageTypesLookup[10] = 'jp2'; |
|
1234 $ImageTypesLookup[11] = 'jpx'; |
|
1235 $ImageTypesLookup[12] = 'jb2'; |
|
1236 $ImageTypesLookup[13] = 'swc'; |
|
1237 $ImageTypesLookup[14] = 'iff'; |
|
1238 } |
|
1239 return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : ''); |
|
1240 } |
|
1241 |
|
1242 public static function CopyTagsToComments(&$ThisFileInfo) { |
|
1243 |
|
1244 // Copy all entries from ['tags'] into common ['comments'] |
1537 // Copy all entries from ['tags'] into common ['comments'] |
1245 if (!empty($ThisFileInfo['tags'])) { |
1538 if (!empty($ThisFileInfo['tags'])) { |
|
1539 if (isset($ThisFileInfo['tags']['id3v1'])) { |
|
1540 // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings |
|
1541 $ID3v1 = $ThisFileInfo['tags']['id3v1']; |
|
1542 unset($ThisFileInfo['tags']['id3v1']); |
|
1543 $ThisFileInfo['tags']['id3v1'] = $ID3v1; |
|
1544 unset($ID3v1); |
|
1545 } |
1246 foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { |
1546 foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { |
1247 foreach ($tagarray as $tagname => $tagdata) { |
1547 foreach ($tagarray as $tagname => $tagdata) { |
1248 foreach ($tagdata as $key => $value) { |
1548 foreach ($tagdata as $key => $value) { |
1249 if (!empty($value)) { |
1549 if (!empty($value)) { |
1250 if (empty($ThisFileInfo['comments'][$tagname])) { |
1550 if (empty($ThisFileInfo['comments'][$tagname])) { |
1259 if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) { |
1559 if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) { |
1260 // new value is identical but shorter-than (or equal-length to) one already in comments - skip |
1560 // new value is identical but shorter-than (or equal-length to) one already in comments - skip |
1261 break 2; |
1561 break 2; |
1262 } |
1562 } |
1263 } |
1563 } |
|
1564 if (function_exists('mb_convert_encoding')) { |
|
1565 if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) { |
|
1566 // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1. |
|
1567 // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character |
|
1568 break 2; |
|
1569 } |
|
1570 } |
1264 |
1571 |
1265 } elseif (!is_array($value)) { |
1572 } elseif (!is_array($value)) { |
1266 |
1573 |
1267 $newvaluelength = strlen(trim($value)); |
1574 $newvaluelength = strlen(trim($value)); |
1268 foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { |
1575 foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { |
1269 $oldvaluelength = strlen(trim($existingvalue)); |
1576 $oldvaluelength = strlen(trim($existingvalue)); |
1270 if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { |
1577 if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { |
1271 $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); |
1578 $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); |
1272 //break 2; |
|
1273 break; |
1579 break; |
1274 } |
1580 } |
1275 } |
1581 } |
1276 |
1582 |
1277 } |
1583 } |
1278 if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { |
1584 if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { |
1279 $value = (is_string($value) ? trim($value) : $value); |
1585 $value = (is_string($value) ? trim($value) : $value); |
1280 if (!is_int($key) && !ctype_digit($key)) { |
1586 if (!is_int($key) && !ctype_digit($key)) { |
1281 $ThisFileInfo['comments'][$tagname][$key] = $value; |
1587 $ThisFileInfo['comments'][$tagname][$key] = $value; |
1282 } else { |
1588 } else { |
1283 if (isset($ThisFileInfo['comments'][$tagname])) { |
1589 if (!isset($ThisFileInfo['comments'][$tagname])) { |
1284 $ThisFileInfo['comments'][$tagname] = array($value); |
1590 $ThisFileInfo['comments'][$tagname] = array($value); |
1285 } else { |
1591 } else { |
1286 $ThisFileInfo['comments'][$tagname][] = $value; |
1592 $ThisFileInfo['comments'][$tagname][] = $value; |
1287 } |
1593 } |
1288 } |
1594 } |
1302 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; |
1608 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; |
1303 unset($ThisFileInfo['comments'][$badkey]); |
1609 unset($ThisFileInfo['comments'][$badkey]); |
1304 } |
1610 } |
1305 } |
1611 } |
1306 |
1612 |
1307 // Copy to ['comments_html'] |
1613 if ($option_tags_html) { |
1308 if (!empty($ThisFileInfo['comments'])) { |
1614 // Copy ['comments'] to ['comments_html'] |
1309 foreach ($ThisFileInfo['comments'] as $field => $values) { |
1615 if (!empty($ThisFileInfo['comments'])) { |
1310 if ($field == 'picture') { |
1616 foreach ($ThisFileInfo['comments'] as $field => $values) { |
1311 // pictures can take up a lot of space, and we don't need multiple copies of them |
1617 if ($field == 'picture') { |
1312 // let there be a single copy in [comments][picture], and not elsewhere |
1618 // pictures can take up a lot of space, and we don't need multiple copies of them |
1313 continue; |
1619 // let there be a single copy in [comments][picture], and not elsewhere |
1314 } |
1620 continue; |
1315 foreach ($values as $index => $value) { |
1621 } |
1316 if (is_array($value)) { |
1622 foreach ($values as $index => $value) { |
1317 $ThisFileInfo['comments_html'][$field][$index] = $value; |
1623 if (is_array($value)) { |
1318 } else { |
1624 $ThisFileInfo['comments_html'][$field][$index] = $value; |
1319 $ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding'])); |
1625 } else { |
|
1626 $ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding'])); |
|
1627 } |
1320 } |
1628 } |
1321 } |
1629 } |
1322 } |
1630 } |
1323 } |
1631 } |
1324 |
1632 |
1325 } |
1633 } |
1326 return true; |
1634 return true; |
1327 } |
1635 } |
1328 |
1636 |
1329 |
1637 /** |
|
1638 * @param string $key |
|
1639 * @param int $begin |
|
1640 * @param int $end |
|
1641 * @param string $file |
|
1642 * @param string $name |
|
1643 * |
|
1644 * @return string |
|
1645 */ |
1330 public static function EmbeddedLookup($key, $begin, $end, $file, $name) { |
1646 public static function EmbeddedLookup($key, $begin, $end, $file, $name) { |
1331 |
1647 |
1332 // Cached |
1648 // Cached |
1333 static $cache; |
1649 static $cache; |
1334 if (isset($cache[$file][$name])) { |
1650 if (isset($cache[$file][$name])) { |
1419 } |
1753 } |
1420 } |
1754 } |
1421 return $filesize; |
1755 return $filesize; |
1422 } |
1756 } |
1423 |
1757 |
1424 |
1758 /** |
1425 /** |
1759 * @param string $filename |
1426 * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268) |
1760 * |
1427 * @param string $path A path. |
1761 * @return string|false |
1428 * @param string $suffix If the name component ends in suffix this will also be cut off. |
1762 */ |
1429 * @return string |
1763 public static function truepath($filename) { |
1430 */ |
1764 // 2017-11-08: this could use some improvement, patches welcome |
|
1765 if (preg_match('#^(\\\\\\\\|//)[a-z0-9]#i', $filename, $matches)) { |
|
1766 // PHP's built-in realpath function does not work on UNC Windows shares |
|
1767 $goodpath = array(); |
|
1768 foreach (explode('/', str_replace('\\', '/', $filename)) as $part) { |
|
1769 if ($part == '.') { |
|
1770 continue; |
|
1771 } |
|
1772 if ($part == '..') { |
|
1773 if (count($goodpath)) { |
|
1774 array_pop($goodpath); |
|
1775 } else { |
|
1776 // cannot step above this level, already at top level |
|
1777 return false; |
|
1778 } |
|
1779 } else { |
|
1780 $goodpath[] = $part; |
|
1781 } |
|
1782 } |
|
1783 return implode(DIRECTORY_SEPARATOR, $goodpath); |
|
1784 } |
|
1785 return realpath($filename); |
|
1786 } |
|
1787 |
|
1788 /** |
|
1789 * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268) |
|
1790 * |
|
1791 * @param string $path A path. |
|
1792 * @param string $suffix If the name component ends in suffix this will also be cut off. |
|
1793 * |
|
1794 * @return string |
|
1795 */ |
1431 public static function mb_basename($path, $suffix = null) { |
1796 public static function mb_basename($path, $suffix = null) { |
1432 $splited = preg_split('#/#', rtrim($path, '/ ')); |
1797 $splited = preg_split('#/#', rtrim($path, '/ ')); |
1433 return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1); |
1798 return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1); |
1434 } |
1799 } |
1435 |
1800 |