[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ID3/ -> getid3.lib.php (source)

   1  <?php
   2  
   3  /////////////////////////////////////////////////////////////////
   4  /// getID3() by James Heinrich <info@getid3.org>               //
   5  //  available at https://github.com/JamesHeinrich/getID3       //
   6  //            or https://www.getid3.org                        //
   7  //            or http://getid3.sourceforge.net                 //
   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       * @param string $string
  19       * @param bool   $hex
  20       * @param bool   $spaces
  21       * @param string $htmlencoding
  22       *
  23       * @return string
  24       */
  25  	public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
  26          $returnstring = '';
  27          for ($i = 0; $i < strlen($string); $i++) {
  28              if ($hex) {
  29                  $returnstring .= str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT);
  30              } else {
  31                  $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string[$i]) ? $string[$i] : '¤');
  32              }
  33              if ($spaces) {
  34                  $returnstring .= ' ';
  35              }
  36          }
  37          if (!empty($htmlencoding)) {
  38              if ($htmlencoding === true) {
  39                  $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean
  40              }
  41              $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
  42          }
  43          return $returnstring;
  44      }
  45  
  46      /**
  47       * Truncates a floating-point number at the decimal point.
  48       *
  49       * @param float $floatnumber
  50       *
  51       * @return float|int returns int (if possible, otherwise float)
  52       */
  53  	public static function trunc($floatnumber) {
  54          if ($floatnumber >= 1) {
  55              $truncatednumber = floor($floatnumber);
  56          } elseif ($floatnumber <= -1) {
  57              $truncatednumber = ceil($floatnumber);
  58          } else {
  59              $truncatednumber = 0;
  60          }
  61          if (self::intValueSupported($truncatednumber)) {
  62              $truncatednumber = (int) $truncatednumber;
  63          }
  64          return $truncatednumber;
  65      }
  66  
  67      /**
  68       * @param int|null $variable
  69       * @param int      $increment
  70       *
  71       * @return bool
  72       */
  73  	public static function safe_inc(&$variable, $increment=1) {
  74          if (isset($variable)) {
  75              $variable += $increment;
  76          } else {
  77              $variable = $increment;
  78          }
  79          return true;
  80      }
  81  
  82      /**
  83       * @param int|float $floatnum
  84       *
  85       * @return int|float
  86       */
  87  	public static function CastAsInt($floatnum) {
  88          // convert to float if not already
  89          $floatnum = (float) $floatnum;
  90  
  91          // convert a float to type int, only if possible
  92          if (self::trunc($floatnum) == $floatnum) {
  93              // it's not floating point
  94              if (self::intValueSupported($floatnum)) {
  95                  // it's within int range
  96                  $floatnum = (int) $floatnum;
  97              }
  98          }
  99          return $floatnum;
 100      }
 101  
 102      /**
 103       * @param int $num
 104       *
 105       * @return bool
 106       */
 107  	public static function intValueSupported($num) {
 108          // check if integers are 64-bit
 109          static $hasINT64 = null;
 110          if ($hasINT64 === null) { // 10x faster than is_null()
 111              $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
 112              if (!$hasINT64 && !defined('PHP_INT_MIN')) {
 113                  define('PHP_INT_MIN', ~PHP_INT_MAX);
 114              }
 115          }
 116          // if integers are 64-bit - no other check required
 117          if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
 118              return true;
 119          }
 120          return false;
 121      }
 122  
 123      /**
 124       * @param string $fraction
 125       *
 126       * @return float
 127       */
 128  	public static function DecimalizeFraction($fraction) {
 129          list($numerator, $denominator) = explode('/', $fraction);
 130          return $numerator / ($denominator ? $denominator : 1);
 131      }
 132  
 133      /**
 134       * @param string $binarynumerator
 135       *
 136       * @return float
 137       */
 138  	public static function DecimalBinary2Float($binarynumerator) {
 139          $numerator   = self::Bin2Dec($binarynumerator);
 140          $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
 141          return ($numerator / $denominator);
 142      }
 143  
 144      /**
 145       * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
 146       *
 147       * @param string $binarypointnumber
 148       * @param int    $maxbits
 149       *
 150       * @return array
 151       */
 152  	public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
 153          if (strpos($binarypointnumber, '.') === false) {
 154              $binarypointnumber = '0.'.$binarypointnumber;
 155          } elseif ($binarypointnumber[0] == '.') {
 156              $binarypointnumber = '0'.$binarypointnumber;
 157          }
 158          $exponent = 0;
 159          while (($binarypointnumber[0] != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
 160              if (substr($binarypointnumber, 1, 1) == '.') {
 161                  $exponent--;
 162                  $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
 163              } else {
 164                  $pointpos = strpos($binarypointnumber, '.');
 165                  $exponent += ($pointpos - 1);
 166                  $binarypointnumber = str_replace('.', '', $binarypointnumber);
 167                  $binarypointnumber = $binarypointnumber[0].'.'.substr($binarypointnumber, 1);
 168              }
 169          }
 170          $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
 171          return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
 172      }
 173  
 174      /**
 175       * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
 176       *
 177       * @param float $floatvalue
 178       *
 179       * @return string
 180       */
 181  	public static function Float2BinaryDecimal($floatvalue) {
 182          $maxbits = 128; // to how many bits of precision should the calculations be taken?
 183          $intpart   = self::trunc($floatvalue);
 184          $floatpart = abs($floatvalue - $intpart);
 185          $pointbitstring = '';
 186          while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
 187              $floatpart *= 2;
 188              $pointbitstring .= (string) self::trunc($floatpart);
 189              $floatpart -= self::trunc($floatpart);
 190          }
 191          $binarypointnumber = decbin($intpart).'.'.$pointbitstring;
 192          return $binarypointnumber;
 193      }
 194  
 195      /**
 196       * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
 197       *
 198       * @param float $floatvalue
 199       * @param int $bits
 200       *
 201       * @return string|false
 202       */
 203  	public static function Float2String($floatvalue, $bits) {
 204          $exponentbits = 0;
 205          $fractionbits = 0;
 206          switch ($bits) {
 207              case 32:
 208                  $exponentbits = 8;
 209                  $fractionbits = 23;
 210                  break;
 211  
 212              case 64:
 213                  $exponentbits = 11;
 214                  $fractionbits = 52;
 215                  break;
 216  
 217              default:
 218                  return false;
 219                  break;
 220          }
 221          if ($floatvalue >= 0) {
 222              $signbit = '0';
 223          } else {
 224              $signbit = '1';
 225          }
 226          $normalizedbinary  = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits);
 227          $biasedexponent    = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
 228          $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
 229          $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
 230  
 231          return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
 232      }
 233  
 234      /**
 235       * @param string $byteword
 236       *
 237       * @return float|false
 238       */
 239  	public static function LittleEndian2Float($byteword) {
 240          return self::BigEndian2Float(strrev($byteword));
 241      }
 242  
 243      /**
 244       * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
 245       *
 246       * @link http://www.psc.edu/general/software/packages/ieee/ieee.html
 247       * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
 248       *
 249       * @param string $byteword
 250       *
 251       * @return float|false
 252       */
 253  	public static function BigEndian2Float($byteword) {
 254          $bitword = self::BigEndian2Bin($byteword);
 255          if (!$bitword) {
 256              return 0;
 257          }
 258          $signbit = $bitword[0];
 259          $floatvalue = 0;
 260          $exponentbits = 0;
 261          $fractionbits = 0;
 262  
 263          switch (strlen($byteword) * 8) {
 264              case 32:
 265                  $exponentbits = 8;
 266                  $fractionbits = 23;
 267                  break;
 268  
 269              case 64:
 270                  $exponentbits = 11;
 271                  $fractionbits = 52;
 272                  break;
 273  
 274              case 80:
 275                  // 80-bit Apple SANE format
 276                  // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
 277                  $exponentstring = substr($bitword, 1, 15);
 278                  $isnormalized = intval($bitword[16]);
 279                  $fractionstring = substr($bitword, 17, 63);
 280                  $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
 281                  $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
 282                  $floatvalue = $exponent * $fraction;
 283                  if ($signbit == '1') {
 284                      $floatvalue *= -1;
 285                  }
 286                  return $floatvalue;
 287                  break;
 288  
 289              default:
 290                  return false;
 291                  break;
 292          }
 293          $exponentstring = substr($bitword, 1, $exponentbits);
 294          $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
 295          $exponent = self::Bin2Dec($exponentstring);
 296          $fraction = self::Bin2Dec($fractionstring);
 297  
 298          if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
 299              // Not a Number
 300              $floatvalue = false;
 301          } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
 302              if ($signbit == '1') {
 303                  $floatvalue = '-infinity';
 304              } else {
 305                  $floatvalue = '+infinity';
 306              }
 307          } elseif (($exponent == 0) && ($fraction == 0)) {
 308              if ($signbit == '1') {
 309                  $floatvalue = -0;
 310              } else {
 311                  $floatvalue = 0;
 312              }
 313              $floatvalue = ($signbit ? 0 : -0);
 314          } elseif (($exponent == 0) && ($fraction != 0)) {
 315              // These are 'unnormalized' values
 316              $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring);
 317              if ($signbit == '1') {
 318                  $floatvalue *= -1;
 319              }
 320          } elseif ($exponent != 0) {
 321              $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring));
 322              if ($signbit == '1') {
 323                  $floatvalue *= -1;
 324              }
 325          }
 326          return (float) $floatvalue;
 327      }
 328  
 329      /**
 330       * @param string $byteword
 331       * @param bool   $synchsafe
 332       * @param bool   $signed
 333       *
 334       * @return int|float|false
 335       * @throws Exception
 336       */
 337  	public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
 338          $intvalue = 0;
 339          $bytewordlen = strlen($byteword);
 340          if ($bytewordlen == 0) {
 341              return false;
 342          }
 343          for ($i = 0; $i < $bytewordlen; $i++) {
 344              if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
 345                  //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
 346                  $intvalue += (ord($byteword[$i]) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
 347              } else {
 348                  $intvalue += ord($byteword[$i]) * pow(256, ($bytewordlen - 1 - $i));
 349              }
 350          }
 351          if ($signed && !$synchsafe) {
 352              // synchsafe ints are not allowed to be signed
 353              if ($bytewordlen <= PHP_INT_SIZE) {
 354                  $signMaskBit = 0x80 << (8 * ($bytewordlen - 1));
 355                  if ($intvalue & $signMaskBit) {
 356                      $intvalue = 0 - ($intvalue & ($signMaskBit - 1));
 357                  }
 358              } else {
 359                  throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()');
 360              }
 361          }
 362          return self::CastAsInt($intvalue);
 363      }
 364  
 365      /**
 366       * @param string $byteword
 367       * @param bool   $signed
 368       *
 369       * @return int|float|false
 370       */
 371  	public static function LittleEndian2Int($byteword, $signed=false) {
 372          return self::BigEndian2Int(strrev($byteword), false, $signed);
 373      }
 374  
 375      /**
 376       * @param string $byteword
 377       *
 378       * @return string
 379       */
 380  	public static function LittleEndian2Bin($byteword) {
 381          return self::BigEndian2Bin(strrev($byteword));
 382      }
 383  
 384      /**
 385       * @param string $byteword
 386       *
 387       * @return string
 388       */
 389  	public static function BigEndian2Bin($byteword) {
 390          $binvalue = '';
 391          $bytewordlen = strlen($byteword);
 392          for ($i = 0; $i < $bytewordlen; $i++) {
 393              $binvalue .= str_pad(decbin(ord($byteword[$i])), 8, '0', STR_PAD_LEFT);
 394          }
 395          return $binvalue;
 396      }
 397  
 398      /**
 399       * @param int  $number
 400       * @param int  $minbytes
 401       * @param bool $synchsafe
 402       * @param bool $signed
 403       *
 404       * @return string
 405       * @throws Exception
 406       */
 407  	public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
 408          if ($number < 0) {
 409              throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
 410          }
 411          $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
 412          $intstring = '';
 413          if ($signed) {
 414              if ($minbytes > PHP_INT_SIZE) {
 415                  throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()');
 416              }
 417              $number = $number & (0x80 << (8 * ($minbytes - 1)));
 418          }
 419          while ($number != 0) {
 420              $quotient = ($number / ($maskbyte + 1));
 421              $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring;
 422              $number = floor($quotient);
 423          }
 424          return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
 425      }
 426  
 427      /**
 428       * @param int $number
 429       *
 430       * @return string
 431       */
 432  	public static function Dec2Bin($number) {
 433          while ($number >= 256) {
 434              $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
 435              $number = floor($number / 256);
 436          }
 437          $bytes[] = $number;
 438          $binstring = '';
 439          for ($i = 0; $i < count($bytes); $i++) {
 440              $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
 441          }
 442          return $binstring;
 443      }
 444  
 445      /**
 446       * @param string $binstring
 447       * @param bool   $signed
 448       *
 449       * @return int|float
 450       */
 451  	public static function Bin2Dec($binstring, $signed=false) {
 452          $signmult = 1;
 453          if ($signed) {
 454              if ($binstring[0] == '1') {
 455                  $signmult = -1;
 456              }
 457              $binstring = substr($binstring, 1);
 458          }
 459          $decvalue = 0;
 460          for ($i = 0; $i < strlen($binstring); $i++) {
 461              $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
 462          }
 463          return self::CastAsInt($decvalue * $signmult);
 464      }
 465  
 466      /**
 467       * @param string $binstring
 468       *
 469       * @return string
 470       */
 471  	public static function Bin2String($binstring) {
 472          // return 'hi' for input of '0110100001101001'
 473          $string = '';
 474          $binstringreversed = strrev($binstring);
 475          for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
 476              $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
 477          }
 478          return $string;
 479      }
 480  
 481      /**
 482       * @param int  $number
 483       * @param int  $minbytes
 484       * @param bool $synchsafe
 485       *
 486       * @return string
 487       */
 488  	public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
 489          $intstring = '';
 490          while ($number > 0) {
 491              if ($synchsafe) {
 492                  $intstring = $intstring.chr($number & 127);
 493                  $number >>= 7;
 494              } else {
 495                  $intstring = $intstring.chr($number & 255);
 496                  $number >>= 8;
 497              }
 498          }
 499          return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
 500      }
 501  
 502      /**
 503       * @param array $array1
 504       * @param array $array2
 505       *
 506       * @return array|false
 507       */
 508  	public static function array_merge_clobber($array1, $array2) {
 509          // written by kcØhireability*com
 510          // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
 511          if (!is_array($array1) || !is_array($array2)) {
 512              return false;
 513          }
 514          $newarray = $array1;
 515          foreach ($array2 as $key => $val) {
 516              if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
 517                  $newarray[$key] = self::array_merge_clobber($newarray[$key], $val);
 518              } else {
 519                  $newarray[$key] = $val;
 520              }
 521          }
 522          return $newarray;
 523      }
 524  
 525      /**
 526       * @param array $array1
 527       * @param array $array2
 528       *
 529       * @return array|false
 530       */
 531  	public static function array_merge_noclobber($array1, $array2) {
 532          if (!is_array($array1) || !is_array($array2)) {
 533              return false;
 534          }
 535          $newarray = $array1;
 536          foreach ($array2 as $key => $val) {
 537              if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
 538                  $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val);
 539              } elseif (!isset($newarray[$key])) {
 540                  $newarray[$key] = $val;
 541              }
 542          }
 543          return $newarray;
 544      }
 545  
 546      /**
 547       * @param array $array1
 548       * @param array $array2
 549       *
 550       * @return array|false|null
 551       */
 552  	public static function flipped_array_merge_noclobber($array1, $array2) {
 553          if (!is_array($array1) || !is_array($array2)) {
 554              return false;
 555          }
 556          # naturally, this only works non-recursively
 557          $newarray = array_flip($array1);
 558          foreach (array_flip($array2) as $key => $val) {
 559              if (!isset($newarray[$key])) {
 560                  $newarray[$key] = count($newarray);
 561              }
 562          }
 563          return array_flip($newarray);
 564      }
 565  
 566      /**
 567       * @param array $theArray
 568       *
 569       * @return bool
 570       */
 571  	public static function ksort_recursive(&$theArray) {
 572          ksort($theArray);
 573          foreach ($theArray as $key => $value) {
 574              if (is_array($value)) {
 575                  self::ksort_recursive($theArray[$key]);
 576              }
 577          }
 578          return true;
 579      }
 580  
 581      /**
 582       * @param string $filename
 583       * @param int    $numextensions
 584       *
 585       * @return string
 586       */
 587  	public static function fileextension($filename, $numextensions=1) {
 588          if (strstr($filename, '.')) {
 589              $reversedfilename = strrev($filename);
 590              $offset = 0;
 591              for ($i = 0; $i < $numextensions; $i++) {
 592                  $offset = strpos($reversedfilename, '.', $offset + 1);
 593                  if ($offset === false) {
 594                      return '';
 595                  }
 596              }
 597              return strrev(substr($reversedfilename, 0, $offset));
 598          }
 599          return '';
 600      }
 601  
 602      /**
 603       * @param int $seconds
 604       *
 605       * @return string
 606       */
 607  	public static function PlaytimeString($seconds) {
 608          $sign = (($seconds < 0) ? '-' : '');
 609          $seconds = round(abs($seconds));
 610          $H = (int) floor( $seconds                            / 3600);
 611          $M = (int) floor(($seconds - (3600 * $H)            ) /   60);
 612          $S = (int) round( $seconds - (3600 * $H) - (60 * $M)        );
 613          return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
 614      }
 615  
 616      /**
 617       * @param int $macdate
 618       *
 619       * @return int|float
 620       */
 621  	public static function DateMac2Unix($macdate) {
 622          // Macintosh timestamp: seconds since 00:00h January 1, 1904
 623          // UNIX timestamp:      seconds since 00:00h January 1, 1970
 624          return self::CastAsInt($macdate - 2082844800);
 625      }
 626  
 627      /**
 628       * @param string $rawdata
 629       *
 630       * @return float
 631       */
 632  	public static function FixedPoint8_8($rawdata) {
 633          return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
 634      }
 635  
 636      /**
 637       * @param string $rawdata
 638       *
 639       * @return float
 640       */
 641  	public static function FixedPoint16_16($rawdata) {
 642          return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
 643      }
 644  
 645      /**
 646       * @param string $rawdata
 647       *
 648       * @return float
 649       */
 650  	public static function FixedPoint2_30($rawdata) {
 651          $binarystring = self::BigEndian2Bin($rawdata);
 652          return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
 653      }
 654  
 655  
 656      /**
 657       * @param string $ArrayPath
 658       * @param string $Separator
 659       * @param mixed $Value
 660       *
 661       * @return array
 662       */
 663  	public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
 664          // assigns $Value to a nested array path:
 665          //   $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
 666          // is the same as:
 667          //   $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
 668          // or
 669          //   $foo['path']['to']['my'] = 'file.txt';
 670          $ArrayPath = ltrim($ArrayPath, $Separator);
 671          if (($pos = strpos($ArrayPath, $Separator)) !== false) {
 672              $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
 673          } else {
 674              $ReturnedArray[$ArrayPath] = $Value;
 675          }
 676          return $ReturnedArray;
 677      }
 678  
 679      /**
 680       * @param array $arraydata
 681       * @param bool  $returnkey
 682       *
 683       * @return int|false
 684       */
 685  	public static function array_max($arraydata, $returnkey=false) {
 686          $maxvalue = false;
 687          $maxkey = false;
 688          foreach ($arraydata as $key => $value) {
 689              if (!is_array($value)) {
 690                  if ($value > $maxvalue) {
 691                      $maxvalue = $value;
 692                      $maxkey = $key;
 693                  }
 694              }
 695          }
 696          return ($returnkey ? $maxkey : $maxvalue);
 697      }
 698  
 699      /**
 700       * @param array $arraydata
 701       * @param bool  $returnkey
 702       *
 703       * @return int|false
 704       */
 705  	public static function array_min($arraydata, $returnkey=false) {
 706          $minvalue = false;
 707          $minkey = false;
 708          foreach ($arraydata as $key => $value) {
 709              if (!is_array($value)) {
 710                  if ($value > $minvalue) {
 711                      $minvalue = $value;
 712                      $minkey = $key;
 713                  }
 714              }
 715          }
 716          return ($returnkey ? $minkey : $minvalue);
 717      }
 718  
 719      /**
 720       * @param string $XMLstring
 721       *
 722       * @return array|false
 723       */
 724  	public static function XML2array($XMLstring) {
 725          if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
 726              // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
 727              // https://core.trac.wordpress.org/changeset/29378
 728              $loader = libxml_disable_entity_loader(true);
 729              $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT);
 730              $return = self::SimpleXMLelement2array($XMLobject);
 731              libxml_disable_entity_loader($loader);
 732              return $return;
 733          }
 734          return false;
 735      }
 736  
 737      /**
 738      * @param SimpleXMLElement|array $XMLobject
 739      *
 740      * @return array
 741      */
 742  	public static function SimpleXMLelement2array($XMLobject) {
 743          if (!is_object($XMLobject) && !is_array($XMLobject)) {
 744              return $XMLobject;
 745          }
 746          $XMLarray = $XMLobject instanceof SimpleXMLElement ? get_object_vars($XMLobject) : $XMLobject;
 747          foreach ($XMLarray as $key => $value) {
 748              $XMLarray[$key] = self::SimpleXMLelement2array($value);
 749          }
 750          return $XMLarray;
 751      }
 752  
 753      /**
 754       * Returns checksum for a file from starting position to absolute end position.
 755       *
 756       * @param string $file
 757       * @param int    $offset
 758       * @param int    $end
 759       * @param string $algorithm
 760       *
 761       * @return string|false
 762       * @throws getid3_exception
 763       */
 764  	public static function hash_data($file, $offset, $end, $algorithm) {
 765          if (!self::intValueSupported($end)) {
 766              return false;
 767          }
 768          if (!in_array($algorithm, array('md5', 'sha1'))) {
 769              throw new getid3_exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
 770          }
 771  
 772          $size = $end - $offset;
 773  
 774          $fp = fopen($file, 'rb');
 775          fseek($fp, $offset);
 776          $ctx = hash_init($algorithm);
 777          while ($size > 0) {
 778              $buffer = fread($fp, min($size, getID3::FREAD_BUFFER_SIZE));
 779              hash_update($ctx, $buffer);
 780              $size -= getID3::FREAD_BUFFER_SIZE;
 781          }
 782          $hash = hash_final($ctx);
 783          fclose($fp);
 784  
 785          return $hash;
 786      }
 787  
 788      /**
 789       * @param string $filename_source
 790       * @param string $filename_dest
 791       * @param int    $offset
 792       * @param int    $length
 793       *
 794       * @return bool
 795       * @throws Exception
 796       *
 797       * @deprecated Unused, may be removed in future versions of getID3
 798       */
 799  	public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
 800          if (!self::intValueSupported($offset + $length)) {
 801              throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
 802          }
 803          if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
 804              if (($fp_dest = fopen($filename_dest, 'wb'))) {
 805                  if (fseek($fp_src, $offset) == 0) {
 806                      $byteslefttowrite = $length;
 807                      while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
 808                          $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
 809                          $byteslefttowrite -= $byteswritten;
 810                      }
 811                      fclose($fp_dest);
 812                      return true;
 813                  } else {
 814                      fclose($fp_src);
 815                      throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
 816                  }
 817              } else {
 818                  throw new Exception('failed to create file for writing '.$filename_dest);
 819              }
 820          } else {
 821              throw new Exception('failed to open file for reading '.$filename_source);
 822          }
 823      }
 824  
 825      /**
 826       * @param int $charval
 827       *
 828       * @return string
 829       */
 830  	public static function iconv_fallback_int_utf8($charval) {
 831          if ($charval < 128) {
 832              // 0bbbbbbb
 833              $newcharstring = chr($charval);
 834          } elseif ($charval < 2048) {
 835              // 110bbbbb 10bbbbbb
 836              $newcharstring  = chr(($charval >>   6) | 0xC0);
 837              $newcharstring .= chr(($charval & 0x3F) | 0x80);
 838          } elseif ($charval < 65536) {
 839              // 1110bbbb 10bbbbbb 10bbbbbb
 840              $newcharstring  = chr(($charval >>  12) | 0xE0);
 841              $newcharstring .= chr(($charval >>   6) | 0xC0);
 842              $newcharstring .= chr(($charval & 0x3F) | 0x80);
 843          } else {
 844              // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
 845              $newcharstring  = chr(($charval >>  18) | 0xF0);
 846              $newcharstring .= chr(($charval >>  12) | 0xC0);
 847              $newcharstring .= chr(($charval >>   6) | 0xC0);
 848              $newcharstring .= chr(($charval & 0x3F) | 0x80);
 849          }
 850          return $newcharstring;
 851      }
 852  
 853      /**
 854       * ISO-8859-1 => UTF-8
 855       *
 856       * @param string $string
 857       * @param bool   $bom
 858       *
 859       * @return string
 860       */
 861  	public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
 862          if (function_exists('utf8_encode')) {
 863              return utf8_encode($string);
 864          }
 865          // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
 866          $newcharstring = '';
 867          if ($bom) {
 868              $newcharstring .= "\xEF\xBB\xBF";
 869          }
 870          for ($i = 0; $i < strlen($string); $i++) {
 871              $charval = ord($string[$i]);
 872              $newcharstring .= self::iconv_fallback_int_utf8($charval);
 873          }
 874          return $newcharstring;
 875      }
 876  
 877      /**
 878       * ISO-8859-1 => UTF-16BE
 879       *
 880       * @param string $string
 881       * @param bool   $bom
 882       *
 883       * @return string
 884       */
 885  	public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
 886          $newcharstring = '';
 887          if ($bom) {
 888              $newcharstring .= "\xFE\xFF";
 889          }
 890          for ($i = 0; $i < strlen($string); $i++) {
 891              $newcharstring .= "\x00".$string[$i];
 892          }
 893          return $newcharstring;
 894      }
 895  
 896      /**
 897       * ISO-8859-1 => UTF-16LE
 898       *
 899       * @param string $string
 900       * @param bool   $bom
 901       *
 902       * @return string
 903       */
 904  	public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
 905          $newcharstring = '';
 906          if ($bom) {
 907              $newcharstring .= "\xFF\xFE";
 908          }
 909          for ($i = 0; $i < strlen($string); $i++) {
 910              $newcharstring .= $string[$i]."\x00";
 911          }
 912          return $newcharstring;
 913      }
 914  
 915      /**
 916       * ISO-8859-1 => UTF-16LE (BOM)
 917       *
 918       * @param string $string
 919       *
 920       * @return string
 921       */
 922  	public static function iconv_fallback_iso88591_utf16($string) {
 923          return self::iconv_fallback_iso88591_utf16le($string, true);
 924      }
 925  
 926      /**
 927       * UTF-8 => ISO-8859-1
 928       *
 929       * @param string $string
 930       *
 931       * @return string
 932       */
 933  	public static function iconv_fallback_utf8_iso88591($string) {
 934          if (function_exists('utf8_decode')) {
 935              return utf8_decode($string);
 936          }
 937          // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
 938          $newcharstring = '';
 939          $offset = 0;
 940          $stringlength = strlen($string);
 941          while ($offset < $stringlength) {
 942              if ((ord($string[$offset]) | 0x07) == 0xF7) {
 943                  // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
 944                  $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
 945                             ((ord($string[($offset + 1)]) & 0x3F) << 12) &
 946                             ((ord($string[($offset + 2)]) & 0x3F) <<  6) &
 947                              (ord($string[($offset + 3)]) & 0x3F);
 948                  $offset += 4;
 949              } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
 950                  // 1110bbbb 10bbbbbb 10bbbbbb
 951                  $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
 952                             ((ord($string[($offset + 1)]) & 0x3F) <<  6) &
 953                              (ord($string[($offset + 2)]) & 0x3F);
 954                  $offset += 3;
 955              } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
 956                  // 110bbbbb 10bbbbbb
 957                  $charval = ((ord($string[($offset + 0)]) & 0x1F) <<  6) &
 958                              (ord($string[($offset + 1)]) & 0x3F);
 959                  $offset += 2;
 960              } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
 961                  // 0bbbbbbb
 962                  $charval = ord($string[$offset]);
 963                  $offset += 1;
 964              } else {
 965                  // error? throw some kind of warning here?
 966                  $charval = false;
 967                  $offset += 1;
 968              }
 969              if ($charval !== false) {
 970                  $newcharstring .= (($charval < 256) ? chr($charval) : '?');
 971              }
 972          }
 973          return $newcharstring;
 974      }
 975  
 976      /**
 977       * UTF-8 => UTF-16BE
 978       *
 979       * @param string $string
 980       * @param bool   $bom
 981       *
 982       * @return string
 983       */
 984  	public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
 985          $newcharstring = '';
 986          if ($bom) {
 987              $newcharstring .= "\xFE\xFF";
 988          }
 989          $offset = 0;
 990          $stringlength = strlen($string);
 991          while ($offset < $stringlength) {
 992              if ((ord($string[$offset]) | 0x07) == 0xF7) {
 993                  // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
 994                  $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
 995                             ((ord($string[($offset + 1)]) & 0x3F) << 12) &
 996                             ((ord($string[($offset + 2)]) & 0x3F) <<  6) &
 997                              (ord($string[($offset + 3)]) & 0x3F);
 998                  $offset += 4;
 999              } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
1000                  // 1110bbbb 10bbbbbb 10bbbbbb
1001                  $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
1002                             ((ord($string[($offset + 1)]) & 0x3F) <<  6) &
1003                              (ord($string[($offset + 2)]) & 0x3F);
1004                  $offset += 3;
1005              } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
1006                  // 110bbbbb 10bbbbbb
1007                  $charval = ((ord($string[($offset + 0)]) & 0x1F) <<  6) &
1008                              (ord($string[($offset + 1)]) & 0x3F);
1009                  $offset += 2;
1010              } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
1011                  // 0bbbbbbb
1012                  $charval = ord($string[$offset]);
1013                  $offset += 1;
1014              } else {
1015                  // error? throw some kind of warning here?
1016                  $charval = false;
1017                  $offset += 1;
1018              }
1019              if ($charval !== false) {
1020                  $newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?');
1021              }
1022          }
1023          return $newcharstring;
1024      }
1025  
1026      /**
1027       * UTF-8 => UTF-16LE
1028       *
1029       * @param string $string
1030       * @param bool   $bom
1031       *
1032       * @return string
1033       */
1034  	public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
1035          $newcharstring = '';
1036          if ($bom) {
1037              $newcharstring .= "\xFF\xFE";
1038          }
1039          $offset = 0;
1040          $stringlength = strlen($string);
1041          while ($offset < $stringlength) {
1042              if ((ord($string[$offset]) | 0x07) == 0xF7) {
1043                  // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
1044                  $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
1045                             ((ord($string[($offset + 1)]) & 0x3F) << 12) &
1046                             ((ord($string[($offset + 2)]) & 0x3F) <<  6) &
1047                              (ord($string[($offset + 3)]) & 0x3F);
1048                  $offset += 4;
1049              } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
1050                  // 1110bbbb 10bbbbbb 10bbbbbb
1051                  $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
1052                             ((ord($string[($offset + 1)]) & 0x3F) <<  6) &
1053                              (ord($string[($offset + 2)]) & 0x3F);
1054                  $offset += 3;
1055              } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
1056                  // 110bbbbb 10bbbbbb
1057                  $charval = ((ord($string[($offset + 0)]) & 0x1F) <<  6) &
1058                              (ord($string[($offset + 1)]) & 0x3F);
1059                  $offset += 2;
1060              } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
1061                  // 0bbbbbbb
1062                  $charval = ord($string[$offset]);
1063                  $offset += 1;
1064              } else {
1065                  // error? maybe throw some warning here?
1066                  $charval = false;
1067                  $offset += 1;
1068              }
1069              if ($charval !== false) {
1070                  $newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00");
1071              }
1072          }
1073          return $newcharstring;
1074      }
1075  
1076      /**
1077       * UTF-8 => UTF-16LE (BOM)
1078       *
1079       * @param string $string
1080       *
1081       * @return string
1082       */
1083  	public static function iconv_fallback_utf8_utf16($string) {
1084          return self::iconv_fallback_utf8_utf16le($string, true);
1085      }
1086  
1087      /**
1088       * UTF-16BE => UTF-8
1089       *
1090       * @param string $string
1091       *
1092       * @return string
1093       */
1094  	public static function iconv_fallback_utf16be_utf8($string) {
1095          if (substr($string, 0, 2) == "\xFE\xFF") {
1096              // strip BOM
1097              $string = substr($string, 2);
1098          }
1099          $newcharstring = '';
1100          for ($i = 0; $i < strlen($string); $i += 2) {
1101              $charval = self::BigEndian2Int(substr($string, $i, 2));
1102              $newcharstring .= self::iconv_fallback_int_utf8($charval);
1103          }
1104          return $newcharstring;
1105      }
1106  
1107      /**
1108       * UTF-16LE => UTF-8
1109       *
1110       * @param string $string
1111       *
1112       * @return string
1113       */
1114  	public static function iconv_fallback_utf16le_utf8($string) {
1115          if (substr($string, 0, 2) == "\xFF\xFE") {
1116              // strip BOM
1117              $string = substr($string, 2);
1118          }
1119          $newcharstring = '';
1120          for ($i = 0; $i < strlen($string); $i += 2) {
1121              $charval = self::LittleEndian2Int(substr($string, $i, 2));
1122              $newcharstring .= self::iconv_fallback_int_utf8($charval);
1123          }
1124          return $newcharstring;
1125      }
1126  
1127      /**
1128       * UTF-16BE => ISO-8859-1
1129       *
1130       * @param string $string
1131       *
1132       * @return string
1133       */
1134  	public static function iconv_fallback_utf16be_iso88591($string) {
1135          if (substr($string, 0, 2) == "\xFE\xFF") {
1136              // strip BOM
1137              $string = substr($string, 2);
1138          }
1139          $newcharstring = '';
1140          for ($i = 0; $i < strlen($string); $i += 2) {
1141              $charval = self::BigEndian2Int(substr($string, $i, 2));
1142              $newcharstring .= (($charval < 256) ? chr($charval) : '?');
1143          }
1144          return $newcharstring;
1145      }
1146  
1147      /**
1148       * UTF-16LE => ISO-8859-1
1149       *
1150       * @param string $string
1151       *
1152       * @return string
1153       */
1154  	public static function iconv_fallback_utf16le_iso88591($string) {
1155          if (substr($string, 0, 2) == "\xFF\xFE") {
1156              // strip BOM
1157              $string = substr($string, 2);
1158          }
1159          $newcharstring = '';
1160          for ($i = 0; $i < strlen($string); $i += 2) {
1161              $charval = self::LittleEndian2Int(substr($string, $i, 2));
1162              $newcharstring .= (($charval < 256) ? chr($charval) : '?');
1163          }
1164          return $newcharstring;
1165      }
1166  
1167      /**
1168       * UTF-16 (BOM) => ISO-8859-1
1169       *
1170       * @param string $string
1171       *
1172       * @return string
1173       */
1174  	public static function iconv_fallback_utf16_iso88591($string) {
1175          $bom = substr($string, 0, 2);
1176          if ($bom == "\xFE\xFF") {
1177              return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
1178          } elseif ($bom == "\xFF\xFE") {
1179              return self::iconv_fallback_utf16le_iso88591(substr($string, 2));
1180          }
1181          return $string;
1182      }
1183  
1184      /**
1185       * UTF-16 (BOM) => UTF-8
1186       *
1187       * @param string $string
1188       *
1189       * @return string
1190       */
1191  	public static function iconv_fallback_utf16_utf8($string) {
1192          $bom = substr($string, 0, 2);
1193          if ($bom == "\xFE\xFF") {
1194              return self::iconv_fallback_utf16be_utf8(substr($string, 2));
1195          } elseif ($bom == "\xFF\xFE") {
1196              return self::iconv_fallback_utf16le_utf8(substr($string, 2));
1197          }
1198          return $string;
1199      }
1200  
1201      /**
1202       * @param string $in_charset
1203       * @param string $out_charset
1204       * @param string $string
1205       *
1206       * @return string
1207       * @throws Exception
1208       */
1209  	public static function iconv_fallback($in_charset, $out_charset, $string) {
1210  
1211          if ($in_charset == $out_charset) {
1212              return $string;
1213          }
1214  
1215          // mb_convert_encoding() available
1216          if (function_exists('mb_convert_encoding')) {
1217              if ((strtoupper($in_charset) == 'UTF-16') && (substr($string, 0, 2) != "\xFE\xFF") && (substr($string, 0, 2) != "\xFF\xFE")) {
1218                  // if BOM missing, mb_convert_encoding will mishandle the conversion, assume UTF-16BE and prepend appropriate BOM
1219                  $string = "\xFF\xFE".$string;
1220              }
1221              if ((strtoupper($in_charset) == 'UTF-16') && (strtoupper($out_charset) == 'UTF-8')) {
1222                  if (($string == "\xFF\xFE") || ($string == "\xFE\xFF")) {
1223                      // if string consists of only BOM, mb_convert_encoding will return the BOM unmodified
1224                      return '';
1225                  }
1226              }
1227              if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) {
1228                  switch ($out_charset) {
1229                      case 'ISO-8859-1':
1230                          $converted_string = rtrim($converted_string, "\x00");
1231                          break;
1232                  }
1233                  return $converted_string;
1234              }
1235              return $string;
1236  
1237          // iconv() available
1238          } elseif (function_exists('iconv')) {
1239              if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
1240                  switch ($out_charset) {
1241                      case 'ISO-8859-1':
1242                          $converted_string = rtrim($converted_string, "\x00");
1243                          break;
1244                  }
1245                  return $converted_string;
1246              }
1247  
1248              // iconv() may sometimes fail with "illegal character in input string" error message
1249              // and return an empty string, but returning the unconverted string is more useful
1250              return $string;
1251          }
1252  
1253  
1254          // neither mb_convert_encoding or iconv() is available
1255          static $ConversionFunctionList = array();
1256          if (empty($ConversionFunctionList)) {
1257              $ConversionFunctionList['ISO-8859-1']['UTF-8']    = 'iconv_fallback_iso88591_utf8';
1258              $ConversionFunctionList['ISO-8859-1']['UTF-16']   = 'iconv_fallback_iso88591_utf16';
1259              $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be';
1260              $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le';
1261              $ConversionFunctionList['UTF-8']['ISO-8859-1']    = 'iconv_fallback_utf8_iso88591';
1262              $ConversionFunctionList['UTF-8']['UTF-16']        = 'iconv_fallback_utf8_utf16';
1263              $ConversionFunctionList['UTF-8']['UTF-16BE']      = 'iconv_fallback_utf8_utf16be';
1264              $ConversionFunctionList['UTF-8']['UTF-16LE']      = 'iconv_fallback_utf8_utf16le';
1265              $ConversionFunctionList['UTF-16']['ISO-8859-1']   = 'iconv_fallback_utf16_iso88591';
1266              $ConversionFunctionList['UTF-16']['UTF-8']        = 'iconv_fallback_utf16_utf8';
1267              $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591';
1268              $ConversionFunctionList['UTF-16LE']['UTF-8']      = 'iconv_fallback_utf16le_utf8';
1269              $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591';
1270              $ConversionFunctionList['UTF-16BE']['UTF-8']      = 'iconv_fallback_utf16be_utf8';
1271          }
1272          if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) {
1273              $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
1274              return self::$ConversionFunction($string);
1275          }
1276          throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
1277      }
1278  
1279      /**
1280       * @param mixed  $data
1281       * @param string $charset
1282       *
1283       * @return mixed
1284       */
1285  	public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
1286          if (is_string($data)) {
1287              return self::MultiByteCharString2HTML($data, $charset);
1288          } elseif (is_array($data)) {
1289              $return_data = array();
1290              foreach ($data as $key => $value) {
1291                  $return_data[$key] = self::recursiveMultiByteCharString2HTML($value, $charset);
1292              }
1293              return $return_data;
1294          }
1295          // integer, float, objects, resources, etc
1296          return $data;
1297      }
1298  
1299      /**
1300       * @param string|int|float $string
1301       * @param string           $charset
1302       *
1303       * @return string
1304       */
1305  	public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
1306          $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
1307          $HTMLstring = '';
1308  
1309          switch (strtolower($charset)) {
1310              case '1251':
1311              case '1252':
1312              case '866':
1313              case '932':
1314              case '936':
1315              case '950':
1316              case 'big5':
1317              case 'big5-hkscs':
1318              case 'cp1251':
1319              case 'cp1252':
1320              case 'cp866':
1321              case 'euc-jp':
1322              case 'eucjp':
1323              case 'gb2312':
1324              case 'ibm866':
1325              case 'iso-8859-1':
1326              case 'iso-8859-15':
1327              case 'iso8859-1':
1328              case 'iso8859-15':
1329              case 'koi8-r':
1330              case 'koi8-ru':
1331              case 'koi8r':
1332              case 'shift_jis':
1333              case 'sjis':
1334              case 'win-1251':
1335              case 'windows-1251':
1336              case 'windows-1252':
1337                  $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
1338                  break;
1339  
1340              case 'utf-8':
1341                  $strlen = strlen($string);
1342                  for ($i = 0; $i < $strlen; $i++) {
1343                      $char_ord_val = ord($string[$i]);
1344                      $charval = 0;
1345                      if ($char_ord_val < 0x80) {
1346                          $charval = $char_ord_val;
1347                      } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F  &&  $i+3 < $strlen) {
1348                          $charval  = (($char_ord_val & 0x07) << 18);
1349                          $charval += ((ord($string[++$i]) & 0x3F) << 12);
1350                          $charval += ((ord($string[++$i]) & 0x3F) << 6);
1351                          $charval +=  (ord($string[++$i]) & 0x3F);
1352                      } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07  &&  $i+2 < $strlen) {
1353                          $charval  = (($char_ord_val & 0x0F) << 12);
1354                          $charval += ((ord($string[++$i]) & 0x3F) << 6);
1355                          $charval +=  (ord($string[++$i]) & 0x3F);
1356                      } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03  &&  $i+1 < $strlen) {
1357                          $charval  = (($char_ord_val & 0x1F) << 6);
1358                          $charval += (ord($string[++$i]) & 0x3F);
1359                      }
1360                      if (($charval >= 32) && ($charval <= 127)) {
1361                          $HTMLstring .= htmlentities(chr($charval));
1362                      } else {
1363                          $HTMLstring .= '&#'.$charval.';';
1364                      }
1365                  }
1366                  break;
1367  
1368              case 'utf-16le':
1369                  for ($i = 0; $i < strlen($string); $i += 2) {
1370                      $charval = self::LittleEndian2Int(substr($string, $i, 2));
1371                      if (($charval >= 32) && ($charval <= 127)) {
1372                          $HTMLstring .= chr($charval);
1373                      } else {
1374                          $HTMLstring .= '&#'.$charval.';';
1375                      }
1376                  }
1377                  break;
1378  
1379              case 'utf-16be':
1380                  for ($i = 0; $i < strlen($string); $i += 2) {
1381                      $charval = self::BigEndian2Int(substr($string, $i, 2));
1382                      if (($charval >= 32) && ($charval <= 127)) {
1383                          $HTMLstring .= chr($charval);
1384                      } else {
1385                          $HTMLstring .= '&#'.$charval.';';
1386                      }
1387                  }
1388                  break;
1389  
1390              default:
1391                  $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()';
1392                  break;
1393          }
1394          return $HTMLstring;
1395      }
1396  
1397      /**
1398       * @param int $namecode
1399       *
1400       * @return string
1401       */
1402  	public static function RGADnameLookup($namecode) {
1403          static $RGADname = array();
1404          if (empty($RGADname)) {
1405              $RGADname[0] = 'not set';
1406              $RGADname[1] = 'Track Gain Adjustment';
1407              $RGADname[2] = 'Album Gain Adjustment';
1408          }
1409  
1410          return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
1411      }
1412  
1413      /**
1414       * @param int $originatorcode
1415       *
1416       * @return string
1417       */
1418  	public static function RGADoriginatorLookup($originatorcode) {
1419          static $RGADoriginator = array();
1420          if (empty($RGADoriginator)) {
1421              $RGADoriginator[0] = 'unspecified';
1422              $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
1423              $RGADoriginator[2] = 'set by user';
1424              $RGADoriginator[3] = 'determined automatically';
1425          }
1426  
1427          return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
1428      }
1429  
1430      /**
1431       * @param int $rawadjustment
1432       * @param int $signbit
1433       *
1434       * @return float
1435       */
1436  	public static function RGADadjustmentLookup($rawadjustment, $signbit) {
1437          $adjustment = (float) $rawadjustment / 10;
1438          if ($signbit == 1) {
1439              $adjustment *= -1;
1440          }
1441          return $adjustment;
1442      }
1443  
1444      /**
1445       * @param int $namecode
1446       * @param int $originatorcode
1447       * @param int $replaygain
1448       *
1449       * @return string
1450       */
1451  	public static function RGADgainString($namecode, $originatorcode, $replaygain) {
1452          if ($replaygain < 0) {
1453              $signbit = '1';
1454          } else {
1455              $signbit = '0';
1456          }
1457          $storedreplaygain = intval(round($replaygain * 10));
1458          $gainstring  = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT);
1459          $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT);
1460          $gainstring .= $signbit;
1461          $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT);
1462  
1463          return $gainstring;
1464      }
1465  
1466      /**
1467       * @param float $amplitude
1468       *
1469       * @return float
1470       */
1471  	public static function RGADamplitude2dB($amplitude) {
1472          return 20 * log10($amplitude);
1473      }
1474  
1475      /**
1476       * @param string $imgData
1477       * @param array  $imageinfo
1478       *
1479       * @return array|false
1480       */
1481  	public static function GetDataImageSize($imgData, &$imageinfo=array()) {
1482          static $tempdir = '';
1483          if (empty($tempdir)) {
1484              if (function_exists('sys_get_temp_dir')) {
1485                  $tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52
1486              }
1487  
1488              // yes this is ugly, feel free to suggest a better way
1489              if (include_once(dirname(__FILE__).'/getid3.php')) {
1490                  if ($getid3_temp = new getID3()) {
1491                      if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
1492                          $tempdir = $getid3_temp_tempdir;
1493                      }
1494                      unset($getid3_temp, $getid3_temp_tempdir);
1495                  }
1496              }
1497          }
1498          $GetDataImageSize = false;
1499          if ($tempfilename = tempnam($tempdir, 'gI3')) {
1500              if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
1501                  fwrite($tmp, $imgData);
1502                  fclose($tmp);
1503                  $GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
1504                  if (($GetDataImageSize === false) || !isset($GetDataImageSize[0]) || !isset($GetDataImageSize[1])) {
1505                      return false;
1506                  }
1507                  $GetDataImageSize['height'] = $GetDataImageSize[0];
1508                  $GetDataImageSize['width']  = $GetDataImageSize[1];
1509              }
1510              unlink($tempfilename);
1511          }
1512          return $GetDataImageSize;
1513      }
1514  
1515      /**
1516       * @param string $mime_type
1517       *
1518       * @return string
1519       */
1520  	public static function ImageExtFromMime($mime_type) {
1521          // temporary way, works OK for now, but should be reworked in the future
1522          return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
1523      }
1524  
1525      /**
1526       * @param array $ThisFileInfo
1527       *
1528       * @return bool
1529       */
1530  	public static function CopyTagsToComments(&$ThisFileInfo) {
1531  
1532          // Copy all entries from ['tags'] into common ['comments']
1533          if (!empty($ThisFileInfo['tags'])) {
1534              foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
1535                  foreach ($tagarray as $tagname => $tagdata) {
1536                      foreach ($tagdata as $key => $value) {
1537                          if (!empty($value)) {
1538                              if (empty($ThisFileInfo['comments'][$tagname])) {
1539  
1540                                  // fall through and append value
1541  
1542                              } elseif ($tagtype == 'id3v1') {
1543  
1544                                  $newvaluelength = strlen(trim($value));
1545                                  foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
1546                                      $oldvaluelength = strlen(trim($existingvalue));
1547                                      if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) {
1548                                          // new value is identical but shorter-than (or equal-length to) one already in comments - skip
1549                                          break 2;
1550                                      }
1551                                  }
1552  
1553                              } elseif (!is_array($value)) {
1554  
1555                                  $newvaluelength = strlen(trim($value));
1556                                  foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
1557                                      $oldvaluelength = strlen(trim($existingvalue));
1558                                      if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
1559                                          $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
1560                                          //break 2;
1561                                          break;
1562                                      }
1563                                  }
1564  
1565                              }
1566                              if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
1567                                  $value = (is_string($value) ? trim($value) : $value);
1568                                  if (!is_int($key) && !ctype_digit($key)) {
1569                                      $ThisFileInfo['comments'][$tagname][$key] = $value;
1570                                  } else {
1571                                      if (isset($ThisFileInfo['comments'][$tagname])) {
1572                                          $ThisFileInfo['comments'][$tagname] = array($value);
1573                                      } else {
1574                                          $ThisFileInfo['comments'][$tagname][] = $value;
1575                                      }
1576                                  }
1577                              }
1578                          }
1579                      }
1580                  }
1581              }
1582  
1583              // attempt to standardize spelling of returned keys
1584              $StandardizeFieldNames = array(
1585                  'tracknumber' => 'track_number',
1586                  'track'       => 'track_number',
1587              );
1588              foreach ($StandardizeFieldNames as $badkey => $goodkey) {
1589                  if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) {
1590                      $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
1591                      unset($ThisFileInfo['comments'][$badkey]);
1592                  }
1593              }
1594  
1595              // Copy to ['comments_html']
1596              if (!empty($ThisFileInfo['comments'])) {
1597                  foreach ($ThisFileInfo['comments'] as $field => $values) {
1598                      if ($field == 'picture') {
1599                          // pictures can take up a lot of space, and we don't need multiple copies of them
1600                          // let there be a single copy in [comments][picture], and not elsewhere
1601                          continue;
1602                      }
1603                      foreach ($values as $index => $value) {
1604                          if (is_array($value)) {
1605                              $ThisFileInfo['comments_html'][$field][$index] = $value;
1606                          } else {
1607                              $ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
1608                          }
1609                      }
1610                  }
1611              }
1612  
1613          }
1614          return true;
1615      }
1616  
1617      /**
1618       * @param string $key
1619       * @param int    $begin
1620       * @param int    $end
1621       * @param string $file
1622       * @param string $name
1623       *
1624       * @return string
1625       */
1626  	public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
1627  
1628          // Cached
1629          static $cache;
1630          if (isset($cache[$file][$name])) {
1631              return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
1632          }
1633  
1634          // Init
1635          $keylength  = strlen($key);
1636          $line_count = $end - $begin - 7;
1637  
1638          // Open php file
1639          $fp = fopen($file, 'r');
1640  
1641          // Discard $begin lines
1642          for ($i = 0; $i < ($begin + 3); $i++) {
1643              fgets($fp, 1024);
1644          }
1645  
1646          // Loop thru line
1647          while (0 < $line_count--) {
1648  
1649              // Read line
1650              $line = ltrim(fgets($fp, 1024), "\t ");
1651  
1652              // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key
1653              //$keycheck = substr($line, 0, $keylength);
1654              //if ($key == $keycheck)  {
1655              //    $cache[$file][$name][$keycheck] = substr($line, $keylength + 1);
1656              //    break;
1657              //}
1658  
1659              // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key
1660              //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1));
1661              $explodedLine = explode("\t", $line, 2);
1662              $ThisKey   = (isset($explodedLine[0]) ? $explodedLine[0] : '');
1663              $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : '');
1664              $cache[$file][$name][$ThisKey] = trim($ThisValue);
1665          }
1666  
1667          // Close and return
1668          fclose($fp);
1669          return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
1670      }
1671  
1672      /**
1673       * @param string $filename
1674       * @param string $sourcefile
1675       * @param bool   $DieOnFailure
1676       *
1677       * @return bool
1678       * @throws Exception
1679       */
1680  	public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
1681          global $GETID3_ERRORARRAY;
1682  
1683          if (file_exists($filename)) {
1684              if (include_once($filename)) {
1685                  return true;
1686              } else {
1687                  $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors';
1688              }
1689          } else {
1690              $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing';
1691          }
1692          if ($DieOnFailure) {
1693              throw new Exception($diemessage);
1694          } else {
1695              $GETID3_ERRORARRAY[] = $diemessage;
1696          }
1697          return false;
1698      }
1699  
1700      /**
1701       * @param string $string
1702       *
1703       * @return string
1704       */
1705  	public static function trimNullByte($string) {
1706          return trim($string, "\x00");
1707      }
1708  
1709      /**
1710       * @param string $path
1711       *
1712       * @return float|bool
1713       */
1714  	public static function getFileSizeSyscall($path) {
1715          $filesize = false;
1716  
1717          if (GETID3_OS_ISWINDOWS) {
1718              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:
1719                  $filesystem = new COM('Scripting.FileSystemObject');
1720                  $file = $filesystem->GetFile($path);
1721                  $filesize = $file->Size();
1722                  unset($filesystem, $file);
1723              } else {
1724                  $commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI';
1725              }
1726          } else {
1727              $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\'';
1728          }
1729          if (isset($commandline)) {
1730              $output = trim(`$commandline`);
1731              if (ctype_digit($output)) {
1732                  $filesize = (float) $output;
1733              }
1734          }
1735          return $filesize;
1736      }
1737  
1738      /**
1739       * @param string $filename
1740       *
1741       * @return string|false
1742       */
1743  	public static function truepath($filename) {
1744          // 2017-11-08: this could use some improvement, patches welcome
1745          if (preg_match('#^(\\\\\\\\|//)[a-z0-9]#i', $filename, $matches)) {
1746              // PHP's built-in realpath function does not work on UNC Windows shares
1747              $goodpath = array();
1748              foreach (explode('/', str_replace('\\', '/', $filename)) as $part) {
1749                  if ($part == '.') {
1750                      continue;
1751                  }
1752                  if ($part == '..') {
1753                      if (count($goodpath)) {
1754                          array_pop($goodpath);
1755                      } else {
1756                          // cannot step above this level, already at top level
1757                          return false;
1758                      }
1759                  } else {
1760                      $goodpath[] = $part;
1761                  }
1762              }
1763              return implode(DIRECTORY_SEPARATOR, $goodpath);
1764          }
1765          return realpath($filename);
1766      }
1767  
1768      /**
1769       * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
1770       *
1771       * @param string $path A path.
1772       * @param string $suffix If the name component ends in suffix this will also be cut off.
1773       *
1774       * @return string
1775       */
1776  	public static function mb_basename($path, $suffix = null) {
1777          $splited = preg_split('#/#', rtrim($path, '/ '));
1778          return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
1779      }
1780  
1781  }


Generated: Tue Oct 22 08:20:01 2019 Cross-referenced by PHPXref 0.7