1
|
|
|
<?php |
2
|
|
|
///////////////////////////////////////////////////////////////// |
3
|
|
|
/// getID3() by James Heinrich <[email protected]> // |
4
|
|
|
// available at http://getid3.sourceforge.net // |
5
|
|
|
// or http://www.getid3.org // |
6
|
|
|
// also https://github.com/JamesHeinrich/getID3 // |
7
|
|
|
///////////////////////////////////////////////////////////////// |
8
|
|
|
// // |
9
|
|
|
// getid3.lib.php - part of getID3() // |
10
|
|
|
// See readme.txt for more details // |
11
|
|
|
// /// |
12
|
|
|
///////////////////////////////////////////////////////////////// |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
class getid3_lib |
16
|
|
|
{ |
17
|
|
|
|
18
|
|
|
public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') { |
19
|
|
|
$returnstring = ''; |
20
|
|
|
for ($i = 0; $i < strlen($string); $i++) { |
21
|
|
|
if ($hex) { |
22
|
|
|
$returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); |
23
|
|
|
} else { |
24
|
|
|
$returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤'); |
25
|
|
|
} |
26
|
|
|
if ($spaces) { |
27
|
|
|
$returnstring .= ' '; |
28
|
|
|
} |
29
|
|
|
} |
30
|
|
|
if (!empty($htmlencoding)) { |
31
|
|
|
if ($htmlencoding === true) { |
32
|
|
|
$htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean |
33
|
|
|
} |
34
|
|
|
$returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding); |
35
|
|
|
} |
36
|
|
|
return $returnstring; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
View Code Duplication |
public static function trunc($floatnumber) { |
|
|
|
|
40
|
|
|
// truncates a floating-point number at the decimal point |
41
|
|
|
// returns int (if possible, otherwise float) |
42
|
|
|
if ($floatnumber >= 1) { |
43
|
|
|
$truncatednumber = floor($floatnumber); |
44
|
|
|
} elseif ($floatnumber <= -1) { |
45
|
|
|
$truncatednumber = ceil($floatnumber); |
46
|
|
|
} else { |
47
|
|
|
$truncatednumber = 0; |
48
|
|
|
} |
49
|
|
|
if (self::intValueSupported($truncatednumber)) { |
50
|
|
|
$truncatednumber = (int) $truncatednumber; |
51
|
|
|
} |
52
|
|
|
return $truncatednumber; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
|
56
|
|
|
public static function safe_inc(&$variable, $increment=1) { |
57
|
|
|
if (isset($variable)) { |
58
|
|
|
$variable += $increment; |
59
|
|
|
} else { |
60
|
|
|
$variable = $increment; |
61
|
|
|
} |
62
|
|
|
return true; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
public static function CastAsInt($floatnum) { |
66
|
|
|
// convert to float if not already |
67
|
|
|
$floatnum = (float) $floatnum; |
68
|
|
|
|
69
|
|
|
// convert a float to type int, only if possible |
70
|
|
|
if (self::trunc($floatnum) == $floatnum) { |
71
|
|
|
// it's not floating point |
72
|
|
|
if (self::intValueSupported($floatnum)) { |
73
|
|
|
// it's within int range |
74
|
|
|
$floatnum = (int) $floatnum; |
75
|
|
|
} |
76
|
|
|
} |
77
|
|
|
return $floatnum; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
public static function intValueSupported($num) { |
81
|
|
|
// check if integers are 64-bit |
82
|
|
|
static $hasINT64 = null; |
83
|
|
|
if ($hasINT64 === null) { // 10x faster than is_null() |
84
|
|
|
$hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1 |
85
|
|
|
if (!$hasINT64 && !defined('PHP_INT_MIN')) { |
86
|
|
|
define('PHP_INT_MIN', ~PHP_INT_MAX); |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
// if integers are 64-bit - no other check required |
90
|
|
|
if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { |
91
|
|
|
return true; |
92
|
|
|
} |
93
|
|
|
return false; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public static function DecimalizeFraction($fraction) { |
97
|
|
|
list($numerator, $denominator) = explode('/', $fraction); |
98
|
|
|
return $numerator / ($denominator ? $denominator : 1); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
|
102
|
|
|
public static function DecimalBinary2Float($binarynumerator) { |
103
|
|
|
$numerator = self::Bin2Dec($binarynumerator); |
104
|
|
|
$denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); |
105
|
|
|
return ($numerator / $denominator); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
|
109
|
|
View Code Duplication |
public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { |
|
|
|
|
110
|
|
|
// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html |
111
|
|
|
if (strpos($binarypointnumber, '.') === false) { |
112
|
|
|
$binarypointnumber = '0.'.$binarypointnumber; |
113
|
|
|
} elseif ($binarypointnumber{0} == '.') { |
114
|
|
|
$binarypointnumber = '0'.$binarypointnumber; |
115
|
|
|
} |
116
|
|
|
$exponent = 0; |
117
|
|
|
while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) { |
118
|
|
|
if (substr($binarypointnumber, 1, 1) == '.') { |
119
|
|
|
$exponent--; |
120
|
|
|
$binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); |
121
|
|
|
} else { |
122
|
|
|
$pointpos = strpos($binarypointnumber, '.'); |
123
|
|
|
$exponent += ($pointpos - 1); |
124
|
|
|
$binarypointnumber = str_replace('.', '', $binarypointnumber); |
125
|
|
|
$binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
$binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); |
129
|
|
|
return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
|
133
|
|
|
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? |
136
|
|
|
$intpart = self::trunc($floatvalue); |
137
|
|
|
$floatpart = abs($floatvalue - $intpart); |
138
|
|
|
$pointbitstring = ''; |
139
|
|
View Code Duplication |
while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) { |
|
|
|
|
140
|
|
|
$floatpart *= 2; |
141
|
|
|
$pointbitstring .= (string) self::trunc($floatpart); |
142
|
|
|
$floatpart -= self::trunc($floatpart); |
143
|
|
|
} |
144
|
|
|
$binarypointnumber = decbin($intpart).'.'.$pointbitstring; |
145
|
|
|
return $binarypointnumber; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
|
149
|
|
|
public static function Float2String($floatvalue, $bits) { |
150
|
|
|
// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html |
151
|
|
View Code Duplication |
switch ($bits) { |
|
|
|
|
152
|
|
|
case 32: |
153
|
|
|
$exponentbits = 8; |
154
|
|
|
$fractionbits = 23; |
155
|
|
|
break; |
156
|
|
|
|
157
|
|
|
case 64: |
158
|
|
|
$exponentbits = 11; |
159
|
|
|
$fractionbits = 52; |
160
|
|
|
break; |
161
|
|
|
|
162
|
|
|
default: |
163
|
|
|
return false; |
164
|
|
|
break; |
|
|
|
|
165
|
|
|
} |
166
|
|
|
if ($floatvalue >= 0) { |
167
|
|
|
$signbit = '0'; |
168
|
|
|
} else { |
169
|
|
|
$signbit = '1'; |
170
|
|
|
} |
171
|
|
|
$normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits); |
172
|
|
|
$biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent |
173
|
|
|
$exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT); |
174
|
|
|
$fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT); |
175
|
|
|
|
176
|
|
|
return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
|
180
|
|
|
public static function LittleEndian2Float($byteword) { |
181
|
|
|
return self::BigEndian2Float(strrev($byteword)); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
|
185
|
|
|
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); |
191
|
|
|
if (!$bitword) { |
192
|
|
|
return 0; |
193
|
|
|
} |
194
|
|
|
$signbit = $bitword{0}; |
195
|
|
|
|
196
|
|
|
switch (strlen($byteword) * 8) { |
197
|
|
|
case 32: |
198
|
|
|
$exponentbits = 8; |
199
|
|
|
$fractionbits = 23; |
200
|
|
|
break; |
201
|
|
|
|
202
|
|
|
case 64: |
203
|
|
|
$exponentbits = 11; |
204
|
|
|
$fractionbits = 52; |
205
|
|
|
break; |
206
|
|
|
|
207
|
|
|
case 80: |
208
|
|
|
// 80-bit Apple SANE format |
209
|
|
|
// http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ |
210
|
|
|
$exponentstring = substr($bitword, 1, 15); |
211
|
|
|
$isnormalized = intval($bitword{16}); |
212
|
|
|
$fractionstring = substr($bitword, 17, 63); |
213
|
|
|
$exponent = pow(2, self::Bin2Dec($exponentstring) - 16383); |
214
|
|
|
$fraction = $isnormalized + self::DecimalBinary2Float($fractionstring); |
215
|
|
|
$floatvalue = $exponent * $fraction; |
216
|
|
|
if ($signbit == '1') { |
217
|
|
|
$floatvalue *= -1; |
218
|
|
|
} |
219
|
|
|
return $floatvalue; |
220
|
|
|
break; |
|
|
|
|
221
|
|
|
|
222
|
|
|
default: |
223
|
|
|
return false; |
224
|
|
|
break; |
|
|
|
|
225
|
|
|
} |
226
|
|
|
$exponentstring = substr($bitword, 1, $exponentbits); |
227
|
|
|
$fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); |
228
|
|
|
$exponent = self::Bin2Dec($exponentstring); |
229
|
|
|
$fraction = self::Bin2Dec($fractionstring); |
230
|
|
|
|
231
|
|
View Code Duplication |
if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) { |
|
|
|
|
232
|
|
|
// Not a Number |
233
|
|
|
$floatvalue = false; |
234
|
|
|
} elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) { |
235
|
|
|
if ($signbit == '1') { |
236
|
|
|
$floatvalue = '-infinity'; |
237
|
|
|
} else { |
238
|
|
|
$floatvalue = '+infinity'; |
239
|
|
|
} |
240
|
|
|
} elseif (($exponent == 0) && ($fraction == 0)) { |
241
|
|
|
if ($signbit == '1') { |
242
|
|
|
$floatvalue = -0; |
|
|
|
|
243
|
|
|
} else { |
244
|
|
|
$floatvalue = 0; |
|
|
|
|
245
|
|
|
} |
246
|
|
|
$floatvalue = ($signbit ? 0 : -0); |
247
|
|
|
} elseif (($exponent == 0) && ($fraction != 0)) { |
248
|
|
|
// These are 'unnormalized' values |
249
|
|
|
$floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring); |
250
|
|
|
if ($signbit == '1') { |
251
|
|
|
$floatvalue *= -1; |
252
|
|
|
} |
253
|
|
|
} elseif ($exponent != 0) { |
254
|
|
|
$floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring)); |
255
|
|
|
if ($signbit == '1') { |
256
|
|
|
$floatvalue *= -1; |
257
|
|
|
} |
258
|
|
|
} |
259
|
|
|
return (float) $floatvalue; |
|
|
|
|
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
|
263
|
|
|
public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { |
264
|
|
|
$intvalue = 0; |
265
|
|
|
$bytewordlen = strlen($byteword); |
266
|
|
|
if ($bytewordlen == 0) { |
267
|
|
|
return false; |
268
|
|
|
} |
269
|
|
View Code Duplication |
for ($i = 0; $i < $bytewordlen; $i++) { |
|
|
|
|
270
|
|
|
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 |
272
|
|
|
$intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7); |
273
|
|
|
} else { |
274
|
|
|
$intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i)); |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
if ($signed && !$synchsafe) { |
278
|
|
|
// synchsafe ints are not allowed to be signed |
279
|
|
|
if ($bytewordlen <= PHP_INT_SIZE) { |
280
|
|
|
$signMaskBit = 0x80 << (8 * ($bytewordlen - 1)); |
281
|
|
|
if ($intvalue & $signMaskBit) { |
282
|
|
|
$intvalue = 0 - ($intvalue & ($signMaskBit - 1)); |
283
|
|
|
} |
284
|
|
|
} else { |
285
|
|
|
throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()'); |
286
|
|
|
} |
287
|
|
|
} |
288
|
|
|
return self::CastAsInt($intvalue); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
|
292
|
|
|
public static function LittleEndian2Int($byteword, $signed=false) { |
293
|
|
|
return self::BigEndian2Int(strrev($byteword), false, $signed); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
public static function LittleEndian2Bin($byteword) { |
297
|
|
|
return self::BigEndian2Bin(strrev($byteword)); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
View Code Duplication |
public static function BigEndian2Bin($byteword) { |
|
|
|
|
301
|
|
|
$binvalue = ''; |
302
|
|
|
$bytewordlen = strlen($byteword); |
303
|
|
|
for ($i = 0; $i < $bytewordlen; $i++) { |
304
|
|
|
$binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT); |
305
|
|
|
} |
306
|
|
|
return $binvalue; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
|
310
|
|
|
public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { |
311
|
|
|
if ($number < 0) { |
312
|
|
|
throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers'); |
313
|
|
|
} |
314
|
|
|
$maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF); |
315
|
|
|
$intstring = ''; |
316
|
|
|
if ($signed) { |
317
|
|
|
if ($minbytes > PHP_INT_SIZE) { |
318
|
|
|
throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()'); |
319
|
|
|
} |
320
|
|
|
$number = $number & (0x80 << (8 * ($minbytes - 1))); |
321
|
|
|
} |
322
|
|
View Code Duplication |
while ($number != 0) { |
|
|
|
|
323
|
|
|
$quotient = ($number / ($maskbyte + 1)); |
324
|
|
|
$intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring; |
325
|
|
|
$number = floor($quotient); |
326
|
|
|
} |
327
|
|
|
return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT); |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
|
331
|
|
View Code Duplication |
public static function Dec2Bin($number) { |
|
|
|
|
332
|
|
|
while ($number >= 256) { |
333
|
|
|
$bytes[] = (($number / 256) - (floor($number / 256))) * 256; |
|
|
|
|
334
|
|
|
$number = floor($number / 256); |
335
|
|
|
} |
336
|
|
|
$bytes[] = $number; |
|
|
|
|
337
|
|
|
$binstring = ''; |
338
|
|
|
for ($i = 0; $i < count($bytes); $i++) { |
|
|
|
|
339
|
|
|
$binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring; |
340
|
|
|
} |
341
|
|
|
return $binstring; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
|
345
|
|
|
public static function Bin2Dec($binstring, $signed=false) { |
346
|
|
|
$signmult = 1; |
347
|
|
|
if ($signed) { |
348
|
|
|
if ($binstring{0} == '1') { |
349
|
|
|
$signmult = -1; |
350
|
|
|
} |
351
|
|
|
$binstring = substr($binstring, 1); |
352
|
|
|
} |
353
|
|
|
$decvalue = 0; |
354
|
|
View Code Duplication |
for ($i = 0; $i < strlen($binstring); $i++) { |
|
|
|
|
355
|
|
|
$decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); |
356
|
|
|
} |
357
|
|
|
return self::CastAsInt($decvalue * $signmult); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
|
361
|
|
View Code Duplication |
public static function Bin2String($binstring) { |
|
|
|
|
362
|
|
|
// return 'hi' for input of '0110100001101001' |
363
|
|
|
$string = ''; |
364
|
|
|
$binstringreversed = strrev($binstring); |
365
|
|
|
for ($i = 0; $i < strlen($binstringreversed); $i += 8) { |
366
|
|
|
$string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string; |
367
|
|
|
} |
368
|
|
|
return $string; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
|
372
|
|
View Code Duplication |
public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { |
|
|
|
|
373
|
|
|
$intstring = ''; |
374
|
|
|
while ($number > 0) { |
375
|
|
|
if ($synchsafe) { |
376
|
|
|
$intstring = $intstring.chr($number & 127); |
377
|
|
|
$number >>= 7; |
378
|
|
|
} else { |
379
|
|
|
$intstring = $intstring.chr($number & 255); |
380
|
|
|
$number >>= 8; |
381
|
|
|
} |
382
|
|
|
} |
383
|
|
|
return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
|
387
|
|
|
public static function array_merge_clobber($array1, $array2) { |
388
|
|
|
// written by kcØhireability*com |
389
|
|
|
// taken from http://www.php.net/manual/en/function.array-merge-recursive.php |
390
|
|
|
if (!is_array($array1) || !is_array($array2)) { |
391
|
|
|
return false; |
392
|
|
|
} |
393
|
|
|
$newarray = $array1; |
394
|
|
|
foreach ($array2 as $key => $val) { |
395
|
|
|
if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { |
396
|
|
|
$newarray[$key] = self::array_merge_clobber($newarray[$key], $val); |
397
|
|
|
} else { |
398
|
|
|
$newarray[$key] = $val; |
399
|
|
|
} |
400
|
|
|
} |
401
|
|
|
return $newarray; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
|
405
|
|
|
public static function array_merge_noclobber($array1, $array2) { |
406
|
|
|
if (!is_array($array1) || !is_array($array2)) { |
407
|
|
|
return false; |
408
|
|
|
} |
409
|
|
|
$newarray = $array1; |
410
|
|
|
foreach ($array2 as $key => $val) { |
411
|
|
|
if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { |
412
|
|
|
$newarray[$key] = self::array_merge_noclobber($newarray[$key], $val); |
413
|
|
|
} elseif (!isset($newarray[$key])) { |
414
|
|
|
$newarray[$key] = $val; |
415
|
|
|
} |
416
|
|
|
} |
417
|
|
|
return $newarray; |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
public static function flipped_array_merge_noclobber($array1, $array2) { |
421
|
|
|
if (!is_array($array1) || !is_array($array2)) { |
422
|
|
|
return false; |
423
|
|
|
} |
424
|
|
|
# naturally, this only works non-recursively |
425
|
|
|
$newarray = array_flip($array1); |
426
|
|
|
foreach (array_flip($array2) as $key => $val) { |
427
|
|
|
if (!isset($newarray[$key])) { |
428
|
|
|
$newarray[$key] = count($newarray); |
429
|
|
|
} |
430
|
|
|
} |
431
|
|
|
return array_flip($newarray); |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
|
435
|
|
|
public static function ksort_recursive(&$theArray) { |
436
|
|
|
ksort($theArray); |
437
|
|
|
foreach ($theArray as $key => $value) { |
438
|
|
|
if (is_array($value)) { |
439
|
|
|
self::ksort_recursive($theArray[$key]); |
440
|
|
|
} |
441
|
|
|
} |
442
|
|
|
return true; |
443
|
|
|
} |
444
|
|
|
|
445
|
|
View Code Duplication |
public static function fileextension($filename, $numextensions=1) { |
|
|
|
|
446
|
|
|
if (strstr($filename, '.')) { |
447
|
|
|
$reversedfilename = strrev($filename); |
448
|
|
|
$offset = 0; |
449
|
|
|
for ($i = 0; $i < $numextensions; $i++) { |
450
|
|
|
$offset = strpos($reversedfilename, '.', $offset + 1); |
451
|
|
|
if ($offset === false) { |
452
|
|
|
return ''; |
453
|
|
|
} |
454
|
|
|
} |
455
|
|
|
return strrev(substr($reversedfilename, 0, $offset)); |
456
|
|
|
} |
457
|
|
|
return ''; |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
|
461
|
|
|
public static function PlaytimeString($seconds) { |
462
|
|
|
$sign = (($seconds < 0) ? '-' : ''); |
463
|
|
|
$seconds = round(abs($seconds)); |
464
|
|
|
$H = (int) floor( $seconds / 3600); |
465
|
|
|
$M = (int) floor(($seconds - (3600 * $H) ) / 60); |
466
|
|
|
$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); |
468
|
|
|
} |
469
|
|
|
|
470
|
|
|
|
471
|
|
|
public static function DateMac2Unix($macdate) { |
472
|
|
|
// Macintosh timestamp: seconds since 00:00h January 1, 1904 |
473
|
|
|
// UNIX timestamp: seconds since 00:00h January 1, 1970 |
474
|
|
|
return self::CastAsInt($macdate - 2082844800); |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
|
478
|
|
|
public static function FixedPoint8_8($rawdata) { |
479
|
|
|
return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
|
483
|
|
|
public static function FixedPoint16_16($rawdata) { |
484
|
|
|
return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
|
488
|
|
|
public static function FixedPoint2_30($rawdata) { |
489
|
|
|
$binarystring = self::BigEndian2Bin($rawdata); |
490
|
|
|
return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30)); |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
|
494
|
|
|
public static function CreateDeepArray($ArrayPath, $Separator, $Value) { |
495
|
|
|
// assigns $Value to a nested array path: |
496
|
|
|
// $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt') |
497
|
|
|
// is the same as: |
498
|
|
|
// $foo = array('path'=>array('to'=>'array('my'=>array('file.txt')))); |
499
|
|
|
// or |
500
|
|
|
// $foo['path']['to']['my'] = 'file.txt'; |
501
|
|
|
$ArrayPath = ltrim($ArrayPath, $Separator); |
502
|
|
View Code Duplication |
if (($pos = strpos($ArrayPath, $Separator)) !== false) { |
|
|
|
|
503
|
|
|
$ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value); |
|
|
|
|
504
|
|
|
} else { |
505
|
|
|
$ReturnedArray[$ArrayPath] = $Value; |
|
|
|
|
506
|
|
|
} |
507
|
|
|
return $ReturnedArray; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
View Code Duplication |
public static function array_max($arraydata, $returnkey=false) { |
|
|
|
|
511
|
|
|
$maxvalue = false; |
512
|
|
|
$maxkey = false; |
513
|
|
|
foreach ($arraydata as $key => $value) { |
514
|
|
|
if (!is_array($value)) { |
515
|
|
|
if ($value > $maxvalue) { |
516
|
|
|
$maxvalue = $value; |
517
|
|
|
$maxkey = $key; |
518
|
|
|
} |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
return ($returnkey ? $maxkey : $maxvalue); |
522
|
|
|
} |
523
|
|
|
|
524
|
|
View Code Duplication |
public static function array_min($arraydata, $returnkey=false) { |
|
|
|
|
525
|
|
|
$minvalue = false; |
526
|
|
|
$minkey = false; |
527
|
|
|
foreach ($arraydata as $key => $value) { |
528
|
|
|
if (!is_array($value)) { |
529
|
|
|
if ($value > $minvalue) { |
530
|
|
|
$minvalue = $value; |
531
|
|
|
$minkey = $key; |
532
|
|
|
} |
533
|
|
|
} |
534
|
|
|
} |
535
|
|
|
return ($returnkey ? $minkey : $minvalue); |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
public static function XML2array($XMLstring) { |
539
|
|
|
if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) { |
540
|
|
|
// http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html |
541
|
|
|
// https://core.trac.wordpress.org/changeset/29378 |
542
|
|
|
$loader = libxml_disable_entity_loader(true); |
543
|
|
|
$XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT); |
544
|
|
|
$return = self::SimpleXMLelement2array($XMLobject); |
545
|
|
|
libxml_disable_entity_loader($loader); |
546
|
|
|
return $return; |
547
|
|
|
} |
548
|
|
|
return false; |
549
|
|
|
} |
550
|
|
|
|
551
|
|
|
public static function SimpleXMLelement2array($XMLobject) { |
552
|
|
|
if (!is_object($XMLobject) && !is_array($XMLobject)) { |
553
|
|
|
return $XMLobject; |
554
|
|
|
} |
555
|
|
|
$XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject); |
556
|
|
|
foreach ($XMLarray as $key => $value) { |
557
|
|
|
$XMLarray[$key] = self::SimpleXMLelement2array($value); |
558
|
|
|
} |
559
|
|
|
return $XMLarray; |
560
|
|
|
} |
561
|
|
|
|
562
|
|
|
|
563
|
|
|
// Allan Hansen <ahØartemis*dk> |
564
|
|
|
// self::md5_data() - returns md5sum for a file from startuing position to absolute end position |
565
|
|
|
public static function hash_data($file, $offset, $end, $algorithm) { |
566
|
|
|
static $tempdir = ''; |
567
|
|
|
if (!self::intValueSupported($end)) { |
568
|
|
|
return false; |
569
|
|
|
} |
570
|
|
|
switch ($algorithm) { |
571
|
|
|
case 'md5': |
572
|
|
|
$hash_function = 'md5_file'; |
573
|
|
|
$unix_call = 'md5sum'; |
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; |
590
|
|
|
while (true) { |
591
|
|
|
if (GETID3_OS_ISWINDOWS) { |
592
|
|
|
|
593
|
|
|
// It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data |
594
|
|
|
// Fall back to create-temp-file method: |
595
|
|
|
if ($algorithm == 'sha1') { |
596
|
|
|
break; |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
$RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); |
600
|
|
|
foreach ($RequiredFiles as $required_file) { |
601
|
|
|
if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { |
602
|
|
|
// helper apps not available - fall back to old method |
603
|
|
|
break 2; |
604
|
|
|
} |
605
|
|
|
} |
606
|
|
|
$commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | '; |
607
|
|
|
$commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | '; |
608
|
|
|
$commandline .= GETID3_HELPERAPPSDIR.$windows_call; |
609
|
|
|
|
610
|
|
|
} else { |
611
|
|
|
|
612
|
|
|
$commandline = 'head -c'.$end.' '.escapeshellarg($file).' | '; |
613
|
|
|
$commandline .= 'tail -c'.$size.' | '; |
614
|
|
|
$commandline .= $unix_call; |
615
|
|
|
|
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) { |
652
|
|
|
if (!self::intValueSupported($offset + $length)) { |
653
|
|
|
throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit'); |
654
|
|
|
} |
655
|
|
|
if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) { |
656
|
|
|
if (($fp_dest = fopen($filename_dest, 'wb'))) { |
657
|
|
|
if (fseek($fp_src, $offset) == 0) { |
658
|
|
|
$byteslefttowrite = $length; |
659
|
|
|
while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) { |
660
|
|
|
$byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite); |
661
|
|
|
$byteslefttowrite -= $byteswritten; |
662
|
|
|
} |
663
|
|
|
return true; |
664
|
|
|
} else { |
665
|
|
|
throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source); |
666
|
|
|
} |
667
|
|
|
fclose($fp_dest); |
|
|
|
|
668
|
|
|
} else { |
669
|
|
|
throw new Exception('failed to create file for writing '.$filename_dest); |
670
|
|
|
} |
671
|
|
|
fclose($fp_src); |
672
|
|
|
} else { |
673
|
|
|
throw new Exception('failed to open file for reading '.$filename_source); |
674
|
|
|
} |
675
|
|
|
return false; |
676
|
|
|
} |
677
|
|
|
|
678
|
|
|
public static function iconv_fallback_int_utf8($charval) { |
679
|
|
|
if ($charval < 128) { |
680
|
|
|
// 0bbbbbbb |
681
|
|
|
$newcharstring = chr($charval); |
682
|
|
|
} elseif ($charval < 2048) { |
683
|
|
|
// 110bbbbb 10bbbbbb |
684
|
|
|
$newcharstring = chr(($charval >> 6) | 0xC0); |
685
|
|
|
$newcharstring .= chr(($charval & 0x3F) | 0x80); |
686
|
|
|
} elseif ($charval < 65536) { |
687
|
|
|
// 1110bbbb 10bbbbbb 10bbbbbb |
688
|
|
|
$newcharstring = chr(($charval >> 12) | 0xE0); |
689
|
|
|
$newcharstring .= chr(($charval >> 6) | 0xC0); |
690
|
|
|
$newcharstring .= chr(($charval & 0x3F) | 0x80); |
691
|
|
|
} else { |
692
|
|
|
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
693
|
|
|
$newcharstring = chr(($charval >> 18) | 0xF0); |
694
|
|
|
$newcharstring .= chr(($charval >> 12) | 0xC0); |
695
|
|
|
$newcharstring .= chr(($charval >> 6) | 0xC0); |
696
|
|
|
$newcharstring .= chr(($charval & 0x3F) | 0x80); |
697
|
|
|
} |
698
|
|
|
return $newcharstring; |
699
|
|
|
} |
700
|
|
|
|
701
|
|
|
// ISO-8859-1 => UTF-8 |
702
|
|
|
public static function iconv_fallback_iso88591_utf8($string, $bom=false) { |
703
|
|
|
if (function_exists('utf8_encode')) { |
704
|
|
|
return utf8_encode($string); |
705
|
|
|
} |
706
|
|
|
// utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) |
707
|
|
|
$newcharstring = ''; |
708
|
|
|
if ($bom) { |
709
|
|
|
$newcharstring .= "\xEF\xBB\xBF"; |
710
|
|
|
} |
711
|
|
|
for ($i = 0; $i < strlen($string); $i++) { |
712
|
|
|
$charval = ord($string{$i}); |
713
|
|
|
$newcharstring .= self::iconv_fallback_int_utf8($charval); |
714
|
|
|
} |
715
|
|
|
return $newcharstring; |
716
|
|
|
} |
717
|
|
|
|
718
|
|
|
// ISO-8859-1 => UTF-16BE |
719
|
|
View Code Duplication |
public static function iconv_fallback_iso88591_utf16be($string, $bom=false) { |
|
|
|
|
720
|
|
|
$newcharstring = ''; |
721
|
|
|
if ($bom) { |
722
|
|
|
$newcharstring .= "\xFE\xFF"; |
723
|
|
|
} |
724
|
|
|
for ($i = 0; $i < strlen($string); $i++) { |
725
|
|
|
$newcharstring .= "\x00".$string{$i}; |
726
|
|
|
} |
727
|
|
|
return $newcharstring; |
728
|
|
|
} |
729
|
|
|
|
730
|
|
|
// ISO-8859-1 => UTF-16LE |
731
|
|
View Code Duplication |
public static function iconv_fallback_iso88591_utf16le($string, $bom=false) { |
|
|
|
|
732
|
|
|
$newcharstring = ''; |
733
|
|
|
if ($bom) { |
734
|
|
|
$newcharstring .= "\xFF\xFE"; |
735
|
|
|
} |
736
|
|
|
for ($i = 0; $i < strlen($string); $i++) { |
737
|
|
|
$newcharstring .= $string{$i}."\x00"; |
738
|
|
|
} |
739
|
|
|
return $newcharstring; |
740
|
|
|
} |
741
|
|
|
|
742
|
|
|
// ISO-8859-1 => UTF-16LE (BOM) |
743
|
|
|
public static function iconv_fallback_iso88591_utf16($string) { |
744
|
|
|
return self::iconv_fallback_iso88591_utf16le($string, true); |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
// UTF-8 => ISO-8859-1 |
748
|
|
|
public static function iconv_fallback_utf8_iso88591($string) { |
749
|
|
|
if (function_exists('utf8_decode')) { |
750
|
|
|
return utf8_decode($string); |
751
|
|
|
} |
752
|
|
|
// utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) |
753
|
|
|
$newcharstring = ''; |
754
|
|
|
$offset = 0; |
755
|
|
|
$stringlength = strlen($string); |
756
|
|
|
while ($offset < $stringlength) { |
757
|
|
|
if ((ord($string{$offset}) | 0x07) == 0xF7) { |
758
|
|
|
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
759
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & |
760
|
|
|
((ord($string{($offset + 1)}) & 0x3F) << 12) & |
761
|
|
|
((ord($string{($offset + 2)}) & 0x3F) << 6) & |
762
|
|
|
(ord($string{($offset + 3)}) & 0x3F); |
763
|
|
|
$offset += 4; |
764
|
|
|
} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { |
765
|
|
|
// 1110bbbb 10bbbbbb 10bbbbbb |
766
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & |
767
|
|
|
((ord($string{($offset + 1)}) & 0x3F) << 6) & |
768
|
|
|
(ord($string{($offset + 2)}) & 0x3F); |
769
|
|
|
$offset += 3; |
770
|
|
|
} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { |
771
|
|
|
// 110bbbbb 10bbbbbb |
772
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & |
773
|
|
|
(ord($string{($offset + 1)}) & 0x3F); |
774
|
|
|
$offset += 2; |
775
|
|
|
} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { |
776
|
|
|
// 0bbbbbbb |
777
|
|
|
$charval = ord($string{$offset}); |
778
|
|
|
$offset += 1; |
779
|
|
|
} else { |
780
|
|
|
// error? throw some kind of warning here? |
781
|
|
|
$charval = false; |
782
|
|
|
$offset += 1; |
783
|
|
|
} |
784
|
|
|
if ($charval !== false) { |
785
|
|
|
$newcharstring .= (($charval < 256) ? chr($charval) : '?'); |
786
|
|
|
} |
787
|
|
|
} |
788
|
|
|
return $newcharstring; |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
// UTF-8 => UTF-16BE |
792
|
|
View Code Duplication |
public static function iconv_fallback_utf8_utf16be($string, $bom=false) { |
|
|
|
|
793
|
|
|
$newcharstring = ''; |
794
|
|
|
if ($bom) { |
795
|
|
|
$newcharstring .= "\xFE\xFF"; |
796
|
|
|
} |
797
|
|
|
$offset = 0; |
798
|
|
|
$stringlength = strlen($string); |
799
|
|
|
while ($offset < $stringlength) { |
800
|
|
|
if ((ord($string{$offset}) | 0x07) == 0xF7) { |
801
|
|
|
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
802
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & |
803
|
|
|
((ord($string{($offset + 1)}) & 0x3F) << 12) & |
804
|
|
|
((ord($string{($offset + 2)}) & 0x3F) << 6) & |
805
|
|
|
(ord($string{($offset + 3)}) & 0x3F); |
806
|
|
|
$offset += 4; |
807
|
|
|
} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { |
808
|
|
|
// 1110bbbb 10bbbbbb 10bbbbbb |
809
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & |
810
|
|
|
((ord($string{($offset + 1)}) & 0x3F) << 6) & |
811
|
|
|
(ord($string{($offset + 2)}) & 0x3F); |
812
|
|
|
$offset += 3; |
813
|
|
|
} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { |
814
|
|
|
// 110bbbbb 10bbbbbb |
815
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & |
816
|
|
|
(ord($string{($offset + 1)}) & 0x3F); |
817
|
|
|
$offset += 2; |
818
|
|
|
} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { |
819
|
|
|
// 0bbbbbbb |
820
|
|
|
$charval = ord($string{$offset}); |
821
|
|
|
$offset += 1; |
822
|
|
|
} else { |
823
|
|
|
// error? throw some kind of warning here? |
824
|
|
|
$charval = false; |
825
|
|
|
$offset += 1; |
826
|
|
|
} |
827
|
|
|
if ($charval !== false) { |
828
|
|
|
$newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?'); |
829
|
|
|
} |
830
|
|
|
} |
831
|
|
|
return $newcharstring; |
832
|
|
|
} |
833
|
|
|
|
834
|
|
|
// UTF-8 => UTF-16LE |
835
|
|
View Code Duplication |
public static function iconv_fallback_utf8_utf16le($string, $bom=false) { |
|
|
|
|
836
|
|
|
$newcharstring = ''; |
837
|
|
|
if ($bom) { |
838
|
|
|
$newcharstring .= "\xFF\xFE"; |
839
|
|
|
} |
840
|
|
|
$offset = 0; |
841
|
|
|
$stringlength = strlen($string); |
842
|
|
|
while ($offset < $stringlength) { |
843
|
|
|
if ((ord($string{$offset}) | 0x07) == 0xF7) { |
844
|
|
|
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb |
845
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & |
846
|
|
|
((ord($string{($offset + 1)}) & 0x3F) << 12) & |
847
|
|
|
((ord($string{($offset + 2)}) & 0x3F) << 6) & |
848
|
|
|
(ord($string{($offset + 3)}) & 0x3F); |
849
|
|
|
$offset += 4; |
850
|
|
|
} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { |
851
|
|
|
// 1110bbbb 10bbbbbb 10bbbbbb |
852
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & |
853
|
|
|
((ord($string{($offset + 1)}) & 0x3F) << 6) & |
854
|
|
|
(ord($string{($offset + 2)}) & 0x3F); |
855
|
|
|
$offset += 3; |
856
|
|
|
} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { |
857
|
|
|
// 110bbbbb 10bbbbbb |
858
|
|
|
$charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & |
859
|
|
|
(ord($string{($offset + 1)}) & 0x3F); |
860
|
|
|
$offset += 2; |
861
|
|
|
} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { |
862
|
|
|
// 0bbbbbbb |
863
|
|
|
$charval = ord($string{$offset}); |
864
|
|
|
$offset += 1; |
865
|
|
|
} else { |
866
|
|
|
// error? maybe throw some warning here? |
867
|
|
|
$charval = false; |
868
|
|
|
$offset += 1; |
869
|
|
|
} |
870
|
|
|
if ($charval !== false) { |
871
|
|
|
$newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00"); |
872
|
|
|
} |
873
|
|
|
} |
874
|
|
|
return $newcharstring; |
875
|
|
|
} |
876
|
|
|
|
877
|
|
|
// UTF-8 => UTF-16LE (BOM) |
878
|
|
|
public static function iconv_fallback_utf8_utf16($string) { |
879
|
|
|
return self::iconv_fallback_utf8_utf16le($string, true); |
880
|
|
|
} |
881
|
|
|
|
882
|
|
|
// UTF-16BE => UTF-8 |
883
|
|
View Code Duplication |
public static function iconv_fallback_utf16be_utf8($string) { |
|
|
|
|
884
|
|
|
if (substr($string, 0, 2) == "\xFE\xFF") { |
885
|
|
|
// strip BOM |
886
|
|
|
$string = substr($string, 2); |
887
|
|
|
} |
888
|
|
|
$newcharstring = ''; |
889
|
|
|
for ($i = 0; $i < strlen($string); $i += 2) { |
890
|
|
|
$charval = self::BigEndian2Int(substr($string, $i, 2)); |
891
|
|
|
$newcharstring .= self::iconv_fallback_int_utf8($charval); |
892
|
|
|
} |
893
|
|
|
return $newcharstring; |
894
|
|
|
} |
895
|
|
|
|
896
|
|
|
// UTF-16LE => UTF-8 |
897
|
|
View Code Duplication |
public static function iconv_fallback_utf16le_utf8($string) { |
|
|
|
|
898
|
|
|
if (substr($string, 0, 2) == "\xFF\xFE") { |
899
|
|
|
// strip BOM |
900
|
|
|
$string = substr($string, 2); |
901
|
|
|
} |
902
|
|
|
$newcharstring = ''; |
903
|
|
|
for ($i = 0; $i < strlen($string); $i += 2) { |
904
|
|
|
$charval = self::LittleEndian2Int(substr($string, $i, 2)); |
905
|
|
|
$newcharstring .= self::iconv_fallback_int_utf8($charval); |
906
|
|
|
} |
907
|
|
|
return $newcharstring; |
908
|
|
|
} |
909
|
|
|
|
910
|
|
|
// UTF-16BE => ISO-8859-1 |
911
|
|
View Code Duplication |
public static function iconv_fallback_utf16be_iso88591($string) { |
|
|
|
|
912
|
|
|
if (substr($string, 0, 2) == "\xFE\xFF") { |
913
|
|
|
// strip BOM |
914
|
|
|
$string = substr($string, 2); |
915
|
|
|
} |
916
|
|
|
$newcharstring = ''; |
917
|
|
|
for ($i = 0; $i < strlen($string); $i += 2) { |
918
|
|
|
$charval = self::BigEndian2Int(substr($string, $i, 2)); |
919
|
|
|
$newcharstring .= (($charval < 256) ? chr($charval) : '?'); |
920
|
|
|
} |
921
|
|
|
return $newcharstring; |
922
|
|
|
} |
923
|
|
|
|
924
|
|
|
// UTF-16LE => ISO-8859-1 |
925
|
|
View Code Duplication |
public static function iconv_fallback_utf16le_iso88591($string) { |
|
|
|
|
926
|
|
|
if (substr($string, 0, 2) == "\xFF\xFE") { |
927
|
|
|
// strip BOM |
928
|
|
|
$string = substr($string, 2); |
929
|
|
|
} |
930
|
|
|
$newcharstring = ''; |
931
|
|
|
for ($i = 0; $i < strlen($string); $i += 2) { |
932
|
|
|
$charval = self::LittleEndian2Int(substr($string, $i, 2)); |
933
|
|
|
$newcharstring .= (($charval < 256) ? chr($charval) : '?'); |
934
|
|
|
} |
935
|
|
|
return $newcharstring; |
936
|
|
|
} |
937
|
|
|
|
938
|
|
|
// UTF-16 (BOM) => ISO-8859-1 |
939
|
|
View Code Duplication |
public static function iconv_fallback_utf16_iso88591($string) { |
|
|
|
|
940
|
|
|
$bom = substr($string, 0, 2); |
941
|
|
|
if ($bom == "\xFE\xFF") { |
942
|
|
|
return self::iconv_fallback_utf16be_iso88591(substr($string, 2)); |
943
|
|
|
} elseif ($bom == "\xFF\xFE") { |
944
|
|
|
return self::iconv_fallback_utf16le_iso88591(substr($string, 2)); |
945
|
|
|
} |
946
|
|
|
return $string; |
947
|
|
|
} |
948
|
|
|
|
949
|
|
|
// UTF-16 (BOM) => UTF-8 |
950
|
|
View Code Duplication |
public static function iconv_fallback_utf16_utf8($string) { |
|
|
|
|
951
|
|
|
$bom = substr($string, 0, 2); |
952
|
|
|
if ($bom == "\xFE\xFF") { |
953
|
|
|
return self::iconv_fallback_utf16be_utf8(substr($string, 2)); |
954
|
|
|
} elseif ($bom == "\xFF\xFE") { |
955
|
|
|
return self::iconv_fallback_utf16le_utf8(substr($string, 2)); |
956
|
|
|
} |
957
|
|
|
return $string; |
958
|
|
|
} |
959
|
|
|
|
960
|
|
|
public static function iconv_fallback($in_charset, $out_charset, $string) { |
961
|
|
|
|
962
|
|
|
if ($in_charset == $out_charset) { |
963
|
|
|
return $string; |
964
|
|
|
} |
965
|
|
|
|
966
|
|
|
// mb_convert_encoding() availble |
967
|
|
|
if (function_exists('mb_convert_encoding')) { |
968
|
|
View Code Duplication |
if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) { |
|
|
|
|
969
|
|
|
switch ($out_charset) { |
970
|
|
|
case 'ISO-8859-1': |
971
|
|
|
$converted_string = rtrim($converted_string, "\x00"); |
972
|
|
|
break; |
973
|
|
|
} |
974
|
|
|
return $converted_string; |
975
|
|
|
} |
976
|
|
|
return $string; |
977
|
|
|
} |
978
|
|
|
// iconv() availble |
979
|
|
|
else if (function_exists('iconv')) { |
980
|
|
View Code Duplication |
if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { |
|
|
|
|
981
|
|
|
switch ($out_charset) { |
982
|
|
|
case 'ISO-8859-1': |
983
|
|
|
$converted_string = rtrim($converted_string, "\x00"); |
984
|
|
|
break; |
985
|
|
|
} |
986
|
|
|
return $converted_string; |
987
|
|
|
} |
988
|
|
|
|
989
|
|
|
// iconv() may sometimes fail with "illegal character in input string" error message |
990
|
|
|
// and return an empty string, but returning the unconverted string is more useful |
991
|
|
|
return $string; |
992
|
|
|
} |
993
|
|
|
|
994
|
|
|
|
995
|
|
|
// neither mb_convert_encoding or iconv() is available |
996
|
|
|
static $ConversionFunctionList = array(); |
997
|
|
|
if (empty($ConversionFunctionList)) { |
998
|
|
|
$ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8'; |
999
|
|
|
$ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16'; |
1000
|
|
|
$ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be'; |
1001
|
|
|
$ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le'; |
1002
|
|
|
$ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591'; |
1003
|
|
|
$ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16'; |
1004
|
|
|
$ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be'; |
1005
|
|
|
$ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le'; |
1006
|
|
|
$ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591'; |
1007
|
|
|
$ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8'; |
1008
|
|
|
$ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591'; |
1009
|
|
|
$ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8'; |
1010
|
|
|
$ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591'; |
1011
|
|
|
$ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8'; |
1012
|
|
|
} |
1013
|
|
|
if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) { |
1014
|
|
|
$ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)]; |
1015
|
|
|
return self::$ConversionFunction($string); |
1016
|
|
|
} |
1017
|
|
|
throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset); |
1018
|
|
|
} |
1019
|
|
|
|
1020
|
|
|
public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') { |
1021
|
|
|
if (is_string($data)) { |
1022
|
|
|
return self::MultiByteCharString2HTML($data, $charset); |
1023
|
|
|
} elseif (is_array($data)) { |
1024
|
|
|
$return_data = array(); |
1025
|
|
|
foreach ($data as $key => $value) { |
1026
|
|
|
$return_data[$key] = self::recursiveMultiByteCharString2HTML($value, $charset); |
1027
|
|
|
} |
1028
|
|
|
return $return_data; |
1029
|
|
|
} |
1030
|
|
|
// integer, float, objects, resources, etc |
1031
|
|
|
return $data; |
1032
|
|
|
} |
1033
|
|
|
|
1034
|
|
|
public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') { |
1035
|
|
|
$string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string |
1036
|
|
|
$HTMLstring = ''; |
1037
|
|
|
|
1038
|
|
|
switch (strtolower($charset)) { |
1039
|
|
|
case '1251': |
1040
|
|
|
case '1252': |
1041
|
|
|
case '866': |
1042
|
|
|
case '932': |
1043
|
|
|
case '936': |
1044
|
|
|
case '950': |
1045
|
|
|
case 'big5': |
1046
|
|
|
case 'big5-hkscs': |
1047
|
|
|
case 'cp1251': |
1048
|
|
|
case 'cp1252': |
1049
|
|
|
case 'cp866': |
1050
|
|
|
case 'euc-jp': |
1051
|
|
|
case 'eucjp': |
1052
|
|
|
case 'gb2312': |
1053
|
|
|
case 'ibm866': |
1054
|
|
|
case 'iso-8859-1': |
1055
|
|
|
case 'iso-8859-15': |
1056
|
|
|
case 'iso8859-1': |
1057
|
|
|
case 'iso8859-15': |
1058
|
|
|
case 'koi8-r': |
1059
|
|
|
case 'koi8-ru': |
1060
|
|
|
case 'koi8r': |
1061
|
|
|
case 'shift_jis': |
1062
|
|
|
case 'sjis': |
1063
|
|
|
case 'win-1251': |
1064
|
|
|
case 'windows-1251': |
1065
|
|
|
case 'windows-1252': |
1066
|
|
|
$HTMLstring = htmlentities($string, ENT_COMPAT, $charset); |
1067
|
|
|
break; |
1068
|
|
|
|
1069
|
|
|
case 'utf-8': |
1070
|
|
|
$strlen = strlen($string); |
1071
|
|
|
for ($i = 0; $i < $strlen; $i++) { |
1072
|
|
|
$char_ord_val = ord($string{$i}); |
1073
|
|
|
$charval = 0; |
1074
|
|
|
if ($char_ord_val < 0x80) { |
1075
|
|
|
$charval = $char_ord_val; |
1076
|
|
|
} elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) { |
1077
|
|
|
$charval = (($char_ord_val & 0x07) << 18); |
1078
|
|
|
$charval += ((ord($string{++$i}) & 0x3F) << 12); |
1079
|
|
|
$charval += ((ord($string{++$i}) & 0x3F) << 6); |
1080
|
|
|
$charval += (ord($string{++$i}) & 0x3F); |
1081
|
|
|
} elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) { |
1082
|
|
|
$charval = (($char_ord_val & 0x0F) << 12); |
1083
|
|
|
$charval += ((ord($string{++$i}) & 0x3F) << 6); |
1084
|
|
|
$charval += (ord($string{++$i}) & 0x3F); |
1085
|
|
|
} elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) { |
1086
|
|
|
$charval = (($char_ord_val & 0x1F) << 6); |
1087
|
|
|
$charval += (ord($string{++$i}) & 0x3F); |
1088
|
|
|
} |
1089
|
|
|
if (($charval >= 32) && ($charval <= 127)) { |
1090
|
|
|
$HTMLstring .= htmlentities(chr($charval)); |
1091
|
|
|
} else { |
1092
|
|
|
$HTMLstring .= '&#'.$charval.';'; |
1093
|
|
|
} |
1094
|
|
|
} |
1095
|
|
|
break; |
1096
|
|
|
|
1097
|
|
View Code Duplication |
case 'utf-16le': |
|
|
|
|
1098
|
|
|
for ($i = 0; $i < strlen($string); $i += 2) { |
1099
|
|
|
$charval = self::LittleEndian2Int(substr($string, $i, 2)); |
1100
|
|
|
if (($charval >= 32) && ($charval <= 127)) { |
1101
|
|
|
$HTMLstring .= chr($charval); |
1102
|
|
|
} else { |
1103
|
|
|
$HTMLstring .= '&#'.$charval.';'; |
1104
|
|
|
} |
1105
|
|
|
} |
1106
|
|
|
break; |
1107
|
|
|
|
1108
|
|
View Code Duplication |
case 'utf-16be': |
|
|
|
|
1109
|
|
|
for ($i = 0; $i < strlen($string); $i += 2) { |
1110
|
|
|
$charval = self::BigEndian2Int(substr($string, $i, 2)); |
1111
|
|
|
if (($charval >= 32) && ($charval <= 127)) { |
1112
|
|
|
$HTMLstring .= chr($charval); |
1113
|
|
|
} else { |
1114
|
|
|
$HTMLstring .= '&#'.$charval.';'; |
1115
|
|
|
} |
1116
|
|
|
} |
1117
|
|
|
break; |
1118
|
|
|
|
1119
|
|
|
default: |
1120
|
|
|
$HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()'; |
1121
|
|
|
break; |
1122
|
|
|
} |
1123
|
|
|
return $HTMLstring; |
1124
|
|
|
} |
1125
|
|
|
|
1126
|
|
|
|
1127
|
|
|
|
1128
|
|
View Code Duplication |
public static function RGADnameLookup($namecode) { |
|
|
|
|
1129
|
|
|
static $RGADname = array(); |
1130
|
|
|
if (empty($RGADname)) { |
1131
|
|
|
$RGADname[0] = 'not set'; |
1132
|
|
|
$RGADname[1] = 'Track Gain Adjustment'; |
1133
|
|
|
$RGADname[2] = 'Album Gain Adjustment'; |
1134
|
|
|
} |
1135
|
|
|
|
1136
|
|
|
return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : ''); |
1137
|
|
|
} |
1138
|
|
|
|
1139
|
|
|
|
1140
|
|
|
public static function RGADoriginatorLookup($originatorcode) { |
1141
|
|
|
static $RGADoriginator = array(); |
1142
|
|
|
if (empty($RGADoriginator)) { |
1143
|
|
|
$RGADoriginator[0] = 'unspecified'; |
1144
|
|
|
$RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer'; |
1145
|
|
|
$RGADoriginator[2] = 'set by user'; |
1146
|
|
|
$RGADoriginator[3] = 'determined automatically'; |
1147
|
|
|
} |
1148
|
|
|
|
1149
|
|
|
return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : ''); |
1150
|
|
|
} |
1151
|
|
|
|
1152
|
|
|
|
1153
|
|
|
public static function RGADadjustmentLookup($rawadjustment, $signbit) { |
1154
|
|
|
$adjustment = $rawadjustment / 10; |
1155
|
|
|
if ($signbit == 1) { |
1156
|
|
|
$adjustment *= -1; |
1157
|
|
|
} |
1158
|
|
|
return (float) $adjustment; |
1159
|
|
|
} |
1160
|
|
|
|
1161
|
|
|
|
1162
|
|
|
public static function RGADgainString($namecode, $originatorcode, $replaygain) { |
1163
|
|
|
if ($replaygain < 0) { |
1164
|
|
|
$signbit = '1'; |
1165
|
|
|
} else { |
1166
|
|
|
$signbit = '0'; |
1167
|
|
|
} |
1168
|
|
|
$storedreplaygain = intval(round($replaygain * 10)); |
1169
|
|
|
$gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT); |
1170
|
|
|
$gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT); |
1171
|
|
|
$gainstring .= $signbit; |
1172
|
|
|
$gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT); |
1173
|
|
|
|
1174
|
|
|
return $gainstring; |
1175
|
|
|
} |
1176
|
|
|
|
1177
|
|
|
public static function RGADamplitude2dB($amplitude) { |
1178
|
|
|
return 20 * log10($amplitude); |
1179
|
|
|
} |
1180
|
|
|
|
1181
|
|
|
|
1182
|
|
|
public static function GetDataImageSize($imgData, &$imageinfo=array()) { |
1183
|
|
|
static $tempdir = ''; |
1184
|
|
|
if (empty($tempdir)) { |
1185
|
|
|
if (function_exists('sys_get_temp_dir')) { |
1186
|
|
|
$tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52 |
1187
|
|
|
} |
1188
|
|
|
|
1189
|
|
|
// yes this is ugly, feel free to suggest a better way |
1190
|
|
|
if (include_once(dirname(__FILE__).'/getid3.php')) { |
1191
|
|
|
if ($getid3_temp = new getID3()) { |
1192
|
|
|
if ($getid3_temp_tempdir = $getid3_temp->tempdir) { |
1193
|
|
|
$tempdir = $getid3_temp_tempdir; |
1194
|
|
|
} |
1195
|
|
|
unset($getid3_temp, $getid3_temp_tempdir); |
1196
|
|
|
} |
1197
|
|
|
} |
1198
|
|
|
} |
1199
|
|
|
$GetDataImageSize = false; |
1200
|
|
|
if ($tempfilename = tempnam($tempdir, 'gI3')) { |
1201
|
|
|
if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) { |
1202
|
|
|
fwrite($tmp, $imgData); |
1203
|
|
|
fclose($tmp); |
1204
|
|
|
$GetDataImageSize = @getimagesize($tempfilename, $imageinfo); |
1205
|
|
|
if (($GetDataImageSize === false) || !isset($GetDataImageSize[0]) || !isset($GetDataImageSize[1])) { |
1206
|
|
|
return false; |
1207
|
|
|
} |
1208
|
|
|
$GetDataImageSize['height'] = $GetDataImageSize[0]; |
1209
|
|
|
$GetDataImageSize['width'] = $GetDataImageSize[1]; |
1210
|
|
|
} |
1211
|
|
|
unlink($tempfilename); |
1212
|
|
|
} |
1213
|
|
|
return $GetDataImageSize; |
1214
|
|
|
} |
1215
|
|
|
|
1216
|
|
|
public static function ImageExtFromMime($mime_type) { |
1217
|
|
|
// 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); |
1219
|
|
|
} |
1220
|
|
|
|
1221
|
|
|
public static function ImageTypesLookup($imagetypeid) { |
1222
|
|
|
static $ImageTypesLookup = array(); |
1223
|
|
|
if (empty($ImageTypesLookup)) { |
1224
|
|
|
$ImageTypesLookup[1] = 'gif'; |
1225
|
|
|
$ImageTypesLookup[2] = 'jpeg'; |
1226
|
|
|
$ImageTypesLookup[3] = 'png'; |
1227
|
|
|
$ImageTypesLookup[4] = 'swf'; |
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'] |
1245
|
|
|
if (!empty($ThisFileInfo['tags'])) { |
1246
|
|
|
foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { |
1247
|
|
|
foreach ($tagarray as $tagname => $tagdata) { |
1248
|
|
|
foreach ($tagdata as $key => $value) { |
1249
|
|
|
if (!empty($value)) { |
1250
|
|
|
if (empty($ThisFileInfo['comments'][$tagname])) { |
1251
|
|
|
|
1252
|
|
|
// fall through and append value |
1253
|
|
|
|
1254
|
|
|
} elseif ($tagtype == 'id3v1') { |
1255
|
|
|
|
1256
|
|
|
$newvaluelength = strlen(trim($value)); |
1257
|
|
|
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { |
1258
|
|
|
$oldvaluelength = strlen(trim($existingvalue)); |
1259
|
|
|
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 |
1261
|
|
|
break 2; |
1262
|
|
|
} |
1263
|
|
|
} |
1264
|
|
|
|
1265
|
|
|
} elseif (!is_array($value)) { |
1266
|
|
|
|
1267
|
|
|
$newvaluelength = strlen(trim($value)); |
1268
|
|
|
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { |
1269
|
|
|
$oldvaluelength = strlen(trim($existingvalue)); |
1270
|
|
|
if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { |
1271
|
|
|
$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); |
1272
|
|
|
//break 2; |
1273
|
|
|
break; |
1274
|
|
|
} |
1275
|
|
|
} |
1276
|
|
|
|
1277
|
|
|
} |
1278
|
|
|
if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { |
1279
|
|
|
$value = (is_string($value) ? trim($value) : $value); |
1280
|
|
|
if (!is_int($key) && !ctype_digit($key)) { |
1281
|
|
|
$ThisFileInfo['comments'][$tagname][$key] = $value; |
1282
|
|
|
} else { |
1283
|
|
|
if (isset($ThisFileInfo['comments'][$tagname])) { |
1284
|
|
|
$ThisFileInfo['comments'][$tagname] = array($value); |
1285
|
|
|
} else { |
1286
|
|
|
$ThisFileInfo['comments'][$tagname][] = $value; |
1287
|
|
|
} |
1288
|
|
|
} |
1289
|
|
|
} |
1290
|
|
|
} |
1291
|
|
|
} |
1292
|
|
|
} |
1293
|
|
|
} |
1294
|
|
|
|
1295
|
|
|
// attempt to standardize spelling of returned keys |
1296
|
|
|
$StandardizeFieldNames = array( |
1297
|
|
|
'tracknumber' => 'track_number', |
1298
|
|
|
'track' => 'track_number', |
1299
|
|
|
); |
1300
|
|
|
foreach ($StandardizeFieldNames as $badkey => $goodkey) { |
1301
|
|
|
if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) { |
1302
|
|
|
$ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; |
1303
|
|
|
unset($ThisFileInfo['comments'][$badkey]); |
1304
|
|
|
} |
1305
|
|
|
} |
1306
|
|
|
|
1307
|
|
|
// Copy to ['comments_html'] |
1308
|
|
|
if (!empty($ThisFileInfo['comments'])) { |
1309
|
|
|
foreach ($ThisFileInfo['comments'] as $field => $values) { |
1310
|
|
|
if ($field == 'picture') { |
1311
|
|
|
// pictures can take up a lot of space, and we don't need multiple copies of them |
1312
|
|
|
// let there be a single copy in [comments][picture], and not elsewhere |
1313
|
|
|
continue; |
1314
|
|
|
} |
1315
|
|
|
foreach ($values as $index => $value) { |
1316
|
|
|
if (is_array($value)) { |
1317
|
|
|
$ThisFileInfo['comments_html'][$field][$index] = $value; |
1318
|
|
|
} else { |
1319
|
|
|
$ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding'])); |
1320
|
|
|
} |
1321
|
|
|
} |
1322
|
|
|
} |
1323
|
|
|
} |
1324
|
|
|
|
1325
|
|
|
} |
1326
|
|
|
return true; |
1327
|
|
|
} |
1328
|
|
|
|
1329
|
|
|
|
1330
|
|
|
public static function EmbeddedLookup($key, $begin, $end, $file, $name) { |
1331
|
|
|
|
1332
|
|
|
// Cached |
1333
|
|
|
static $cache; |
1334
|
|
|
if (isset($cache[$file][$name])) { |
1335
|
|
|
return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); |
1336
|
|
|
} |
1337
|
|
|
|
1338
|
|
|
// Init |
1339
|
|
|
$keylength = strlen($key); |
|
|
|
|
1340
|
|
|
$line_count = $end - $begin - 7; |
1341
|
|
|
|
1342
|
|
|
// Open php file |
1343
|
|
|
$fp = fopen($file, 'r'); |
1344
|
|
|
|
1345
|
|
|
// Discard $begin lines |
1346
|
|
|
for ($i = 0; $i < ($begin + 3); $i++) { |
1347
|
|
|
fgets($fp, 1024); |
1348
|
|
|
} |
1349
|
|
|
|
1350
|
|
|
// Loop thru line |
1351
|
|
|
while (0 < $line_count--) { |
1352
|
|
|
|
1353
|
|
|
// Read line |
1354
|
|
|
$line = ltrim(fgets($fp, 1024), "\t "); |
1355
|
|
|
|
1356
|
|
|
// METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key |
1357
|
|
|
//$keycheck = substr($line, 0, $keylength); |
1358
|
|
|
//if ($key == $keycheck) { |
1359
|
|
|
// $cache[$file][$name][$keycheck] = substr($line, $keylength + 1); |
1360
|
|
|
// break; |
1361
|
|
|
//} |
1362
|
|
|
|
1363
|
|
|
// METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key |
1364
|
|
|
//$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1)); |
1365
|
|
|
$explodedLine = explode("\t", $line, 2); |
1366
|
|
|
$ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : ''); |
1367
|
|
|
$ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : ''); |
1368
|
|
|
$cache[$file][$name][$ThisKey] = trim($ThisValue); |
1369
|
|
|
} |
1370
|
|
|
|
1371
|
|
|
// Close and return |
1372
|
|
|
fclose($fp); |
1373
|
|
|
return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); |
1374
|
|
|
} |
1375
|
|
|
|
1376
|
|
|
public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) { |
1377
|
|
|
global $GETID3_ERRORARRAY; |
1378
|
|
|
|
1379
|
|
|
if (file_exists($filename)) { |
1380
|
|
|
if (include_once($filename)) { |
1381
|
|
|
return true; |
1382
|
|
|
} else { |
1383
|
|
|
$diemessage = basename($sourcefile).' depends on '.$filename.', which has errors'; |
1384
|
|
|
} |
1385
|
|
|
} else { |
1386
|
|
|
$diemessage = basename($sourcefile).' depends on '.$filename.', which is missing'; |
1387
|
|
|
} |
1388
|
|
|
if ($DieOnFailure) { |
1389
|
|
|
throw new Exception($diemessage); |
1390
|
|
|
} else { |
1391
|
|
|
$GETID3_ERRORARRAY[] = $diemessage; |
1392
|
|
|
} |
1393
|
|
|
return false; |
1394
|
|
|
} |
1395
|
|
|
|
1396
|
|
|
public static function trimNullByte($string) { |
1397
|
|
|
return trim($string, "\x00"); |
1398
|
|
|
} |
1399
|
|
|
|
1400
|
|
|
public static function getFileSizeSyscall($path) { |
1401
|
|
|
$filesize = false; |
1402
|
|
|
|
1403
|
|
|
if (GETID3_OS_ISWINDOWS) { |
1404
|
|
|
if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini: |
1405
|
|
|
$filesystem = new COM('Scripting.FileSystemObject'); |
|
|
|
|
1406
|
|
|
$file = $filesystem->GetFile($path); |
1407
|
|
|
$filesize = $file->Size(); |
1408
|
|
|
unset($filesystem, $file); |
1409
|
|
|
} else { |
1410
|
|
|
$commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI'; |
1411
|
|
|
} |
1412
|
|
|
} else { |
1413
|
|
|
$commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\''; |
1414
|
|
|
} |
1415
|
|
|
if (isset($commandline)) { |
1416
|
|
|
$output = trim(`$commandline`); |
1417
|
|
|
if (ctype_digit($output)) { |
1418
|
|
|
$filesize = (float) $output; |
1419
|
|
|
} |
1420
|
|
|
} |
1421
|
|
|
return $filesize; |
1422
|
|
|
} |
1423
|
|
|
|
1424
|
|
|
|
1425
|
|
|
/** |
1426
|
|
|
* Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268) |
1427
|
|
|
* @param string $path A path. |
1428
|
|
|
* @param string $suffix If the name component ends in suffix this will also be cut off. |
1429
|
|
|
* @return string |
1430
|
|
|
*/ |
1431
|
|
|
public static function mb_basename($path, $suffix = null) { |
1432
|
|
|
$splited = preg_split('#/#', rtrim($path, '/ ')); |
1433
|
|
|
return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1); |
1434
|
|
|
} |
1435
|
|
|
|
1436
|
|
|
} |
1437
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.