Completed
Push — vendor/getid3 ( f84e24...1ec141 )
by Pauli
03:18
created

getid3_lib::LittleEndian2Bin()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
221
222
			default:
223
				return false;
224
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
$floatvalue is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
243
			} else {
244
				$floatvalue = 0;
0 ignored issues
show
Unused Code introduced by
$floatvalue is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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;
0 ignored issues
show
Bug introduced by
The variable $floatvalue does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
332
		while ($number >= 256) {
333
			$bytes[] = (($number / 256) - (floor($number / 256))) * 256;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$bytes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $bytes = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
334
			$number = floor($number / 256);
335
		}
336
		$bytes[] = $number;
0 ignored issues
show
Bug introduced by
The variable $bytes does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
337
		$binstring = '';
338
		for ($i = 0; $i < count($bytes); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
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++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
503
			$ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ReturnedArray was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ReturnedArray = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
504
		} else {
505
			$ReturnedArray[$ArrayPath] = $Value;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ReturnedArray was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ReturnedArray = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
506
		}
507
		return $ReturnedArray;
508
	}
509
510 View Code Duplication
	public static function array_max($arraydata, $returnkey=false) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
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);
0 ignored issues
show
Unused Code introduced by
fclose($fp_dest); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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('&#0;', '', 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);
0 ignored issues
show
Unused Code introduced by
$keylength is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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');
0 ignored issues
show
Unused Code introduced by
The call to com::__construct() has too many arguments starting with 'Scripting.FileSystemObject'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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