PageRenderTime 111ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/vendor/getid3-1.9.0/demos/demo.mp3header.php

http://streeme.googlecode.com/
PHP | 1789 lines | 1412 code | 218 blank | 159 comment | 410 complexity | 22fb20b651c5497fc0f4d4078d833ffb MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, ISC, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. if (!function_exists('PrintHexBytes')) {
  3. function PrintHexBytes($string) {
  4. $returnstring = '';
  5. for ($i = 0; $i < strlen($string); $i++) {
  6. $returnstring .= str_pad(dechex(ord(substr($string, $i, 1))), 2, '0', STR_PAD_LEFT).' ';
  7. }
  8. return $returnstring;
  9. }
  10. }
  11. if (!function_exists('PrintTextBytes')) {
  12. function PrintTextBytes($string) {
  13. $returnstring = '';
  14. for ($i = 0; $i < strlen($string); $i++) {
  15. if (ord(substr($string, $i, 1)) <= 31) {
  16. $returnstring .= ' ';
  17. } else {
  18. $returnstring .= ' '.substr($string, $i, 1).' ';
  19. }
  20. }
  21. return $returnstring;
  22. }
  23. }
  24. if (!function_exists('table_var_dump')) {
  25. function table_var_dump($variable) {
  26. $returnstring = '';
  27. switch (gettype($variable)) {
  28. case 'array':
  29. $returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">';
  30. foreach ($variable as $key => $value) {
  31. $returnstring .= '<TR><TD VALIGN="TOP"><B>'.str_replace(chr(0), ' ', $key).'</B></TD>';
  32. $returnstring .= '<TD VALIGN="TOP">'.gettype($value);
  33. if (is_array($value)) {
  34. $returnstring .= '&nbsp;('.count($value).')';
  35. } elseif (is_string($value)) {
  36. $returnstring .= '&nbsp;('.strlen($value).')';
  37. }
  38. if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
  39. require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php');
  40. $imageinfo = array();
  41. $imagechunkcheck = GetDataImageSize($value, $imageinfo);
  42. $DumpedImageSRC = (!empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3').'.'.$variable['dataoffset'].'.'.ImageTypesLookup($imagechunkcheck[2]);
  43. if ($tempimagefile = fopen($DumpedImageSRC, 'wb')) {
  44. fwrite($tempimagefile, $value);
  45. fclose($tempimagefile);
  46. }
  47. $returnstring .= '</TD><TD><IMG SRC="'.$DumpedImageSRC.'" WIDTH="'.$imagechunkcheck[0].'" HEIGHT="'.$imagechunkcheck[1].'"></TD></TR>';
  48. } else {
  49. $returnstring .= '</TD><TD>'.table_var_dump($value).'</TD></TR>';
  50. }
  51. }
  52. $returnstring .= '</TABLE>';
  53. break;
  54. case 'boolean':
  55. $returnstring .= ($variable ? 'TRUE' : 'FALSE');
  56. break;
  57. case 'integer':
  58. case 'double':
  59. case 'float':
  60. $returnstring .= $variable;
  61. break;
  62. case 'object':
  63. case 'null':
  64. $returnstring .= string_var_dump($variable);
  65. break;
  66. case 'string':
  67. $variable = str_replace(chr(0), ' ', $variable);
  68. $varlen = strlen($variable);
  69. for ($i = 0; $i < $varlen; $i++) {
  70. if (preg_match('#['.chr(0x0A).chr(0x0D).' -;0-9A-Za-z]#', $variable{$i})) {
  71. $returnstring .= $variable{$i};
  72. } else {
  73. $returnstring .= '&#'.str_pad(ord($variable{$i}), 3, '0', STR_PAD_LEFT).';';
  74. }
  75. }
  76. $returnstring = nl2br($returnstring);
  77. break;
  78. default:
  79. require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php');
  80. $imageinfo = array();
  81. $imagechunkcheck = GetDataImageSize(substr($variable, 0, 32768), $imageinfo);
  82. if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
  83. $returnstring .= '<table border="1" cellspacing="0" cellpadding="2">';
  84. $returnstring .= '<tr><td><b>type</b></td><td>'.ImageTypesLookup($imagechunkcheck[2]).'</td></tr>';
  85. $returnstring .= '<tr><td><b>width</b></td><td>'.number_format($imagechunkcheck[0]).' px</td></tr>';
  86. $returnstring .= '<tr><td><b>height</b></td><td>'.number_format($imagechunkcheck[1]).' px</td></tr>';
  87. $returnstring .= '<tr><td><b>size</b></td><td>'.number_format(strlen($variable)).' bytes</td></tr></table>';
  88. } else {
  89. $returnstring .= nl2br(htmlspecialchars(str_replace(chr(0), ' ', $variable)));
  90. }
  91. break;
  92. }
  93. return $returnstring;
  94. }
  95. }
  96. if (!function_exists('string_var_dump')) {
  97. function string_var_dump($variable) {
  98. if (version_compare(PHP_VERSION, '4.3.0', '>=')) {
  99. return print_r($variable, true);
  100. }
  101. ob_start();
  102. var_dump($variable);
  103. $dumpedvariable = ob_get_contents();
  104. ob_end_clean();
  105. return $dumpedvariable;
  106. }
  107. }
  108. if (!function_exists('fileextension')) {
  109. function fileextension($filename, $numextensions=1) {
  110. if (strstr($filename, '.')) {
  111. $reversedfilename = strrev($filename);
  112. $offset = 0;
  113. for ($i = 0; $i < $numextensions; $i++) {
  114. $offset = strpos($reversedfilename, '.', $offset + 1);
  115. if ($offset === false) {
  116. return '';
  117. }
  118. }
  119. return strrev(substr($reversedfilename, 0, $offset));
  120. }
  121. return '';
  122. }
  123. }
  124. if (!function_exists('RemoveAccents')) {
  125. function RemoveAccents($string) {
  126. // return strtr($string, '&#x160;&#x152;&#x17D;&#x161;&#x153;&#x17E;&#x;???ÁÂ?Ä??Ç?É?Ë?ÍÎ????ÓÔ?Ö??Ú?ÜÝß?áâ?ä??ç?é?ë?íî????óô?ö??ú?üý?', 'SOZsozYYuAAAAAAACEEEEIIIIDNOOOOOOUUUUYsaaaaaaaceeeeiiiionoooooouuuuyy');
  127. // Revised version by marksteward@hotmail.com
  128. return strtr(strtr($string, '&#x160;&#x17D;&#x161;&#x17E;&#x;?ÁÂ?Ä?Ç?É?Ë?ÍÎ???ÓÔ?Ö??Ú?ÜÝ?áâ?ä?ç?é?ë?íî???óô?ö??ú?üý?', 'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'), array('?' => 'TH', '?' => 'th', '?' => 'DH', '?' => 'dh', 'ß' => 'ss', '&#x152;' => 'OE', '&#x153;' => 'oe', '?' => 'AE', '?' => 'ae', '?' => 'u'));
  129. }
  130. }
  131. if (!function_exists('MoreNaturalSort')) {
  132. function MoreNaturalSort($ar1, $ar2) {
  133. if ($ar1 === $ar2) {
  134. return 0;
  135. }
  136. $len1 = strlen($ar1);
  137. $len2 = strlen($ar2);
  138. $shortest = min($len1, $len2);
  139. if (substr($ar1, 0, $shortest) === substr($ar2, 0, $shortest)) {
  140. // the shorter argument is the beginning of the longer one, like "str" and "string"
  141. if ($len1 < $len2) {
  142. return -1;
  143. } elseif ($len1 > $len2) {
  144. return 1;
  145. }
  146. return 0;
  147. }
  148. $ar1 = RemoveAccents(strtolower(trim($ar1)));
  149. $ar2 = RemoveAccents(strtolower(trim($ar2)));
  150. $translatearray = array('\''=>'', '"'=>'', '_'=>' ', '('=>'', ')'=>'', '-'=>' ', ' '=>' ', '.'=>'', ','=>'');
  151. foreach ($translatearray as $key => $val) {
  152. $ar1 = str_replace($key, $val, $ar1);
  153. $ar2 = str_replace($key, $val, $ar2);
  154. }
  155. if ($ar1 < $ar2) {
  156. return -1;
  157. } elseif ($ar1 > $ar2) {
  158. return 1;
  159. }
  160. return 0;
  161. }
  162. }
  163. if (!function_exists('trunc')) {
  164. function trunc($floatnumber) {
  165. // truncates a floating-point number at the decimal point
  166. // returns int (if possible, otherwise float)
  167. if ($floatnumber >= 1) {
  168. $truncatednumber = floor($floatnumber);
  169. } elseif ($floatnumber <= -1) {
  170. $truncatednumber = ceil($floatnumber);
  171. } else {
  172. $truncatednumber = 0;
  173. }
  174. if ($truncatednumber <= pow(2, 30)) {
  175. $truncatednumber = (int) $truncatednumber;
  176. }
  177. return $truncatednumber;
  178. }
  179. }
  180. if (!function_exists('CastAsInt')) {
  181. function CastAsInt($floatnum) {
  182. // convert to float if not already
  183. $floatnum = (float) $floatnum;
  184. // convert a float to type int, only if possible
  185. if (trunc($floatnum) == $floatnum) {
  186. // it's not floating point
  187. if ($floatnum <= pow(2, 30)) {
  188. // it's within int range
  189. $floatnum = (int) $floatnum;
  190. }
  191. }
  192. return $floatnum;
  193. }
  194. }
  195. if (!function_exists('getmicrotime')) {
  196. function getmicrotime() {
  197. list($usec, $sec) = explode(' ', microtime());
  198. return ((float) $usec + (float) $sec);
  199. }
  200. }
  201. if (!function_exists('DecimalBinary2Float')) {
  202. function DecimalBinary2Float($binarynumerator) {
  203. $numerator = Bin2Dec($binarynumerator);
  204. $denominator = Bin2Dec(str_repeat('1', strlen($binarynumerator)));
  205. return ($numerator / $denominator);
  206. }
  207. }
  208. if (!function_exists('NormalizeBinaryPoint')) {
  209. function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
  210. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
  211. if (strpos($binarypointnumber, '.') === false) {
  212. $binarypointnumber = '0.'.$binarypointnumber;
  213. } elseif ($binarypointnumber{0} == '.') {
  214. $binarypointnumber = '0'.$binarypointnumber;
  215. }
  216. $exponent = 0;
  217. while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
  218. if (substr($binarypointnumber, 1, 1) == '.') {
  219. $exponent--;
  220. $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
  221. } else {
  222. $pointpos = strpos($binarypointnumber, '.');
  223. $exponent += ($pointpos - 1);
  224. $binarypointnumber = str_replace('.', '', $binarypointnumber);
  225. $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
  226. }
  227. }
  228. $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
  229. return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
  230. }
  231. }
  232. if (!function_exists('Float2BinaryDecimal')) {
  233. function Float2BinaryDecimal($floatvalue) {
  234. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
  235. $maxbits = 128; // to how many bits of precision should the calculations be taken?
  236. $intpart = trunc($floatvalue);
  237. $floatpart = abs($floatvalue - $intpart);
  238. $pointbitstring = '';
  239. while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
  240. $floatpart *= 2;
  241. $pointbitstring .= (string) trunc($floatpart);
  242. $floatpart -= trunc($floatpart);
  243. }
  244. $binarypointnumber = decbin($intpart).'.'.$pointbitstring;
  245. return $binarypointnumber;
  246. }
  247. }
  248. if (!function_exists('Float2String')) {
  249. function Float2String($floatvalue, $bits) {
  250. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
  251. switch ($bits) {
  252. case 32:
  253. $exponentbits = 8;
  254. $fractionbits = 23;
  255. break;
  256. case 64:
  257. $exponentbits = 11;
  258. $fractionbits = 52;
  259. break;
  260. default:
  261. return false;
  262. break;
  263. }
  264. if ($floatvalue >= 0) {
  265. $signbit = '0';
  266. } else {
  267. $signbit = '1';
  268. }
  269. $normalizedbinary = NormalizeBinaryPoint(Float2BinaryDecimal($floatvalue), $fractionbits);
  270. $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
  271. $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
  272. $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
  273. return BigEndian2String(Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
  274. }
  275. }
  276. if (!function_exists('LittleEndian2Float')) {
  277. function LittleEndian2Float($byteword) {
  278. return BigEndian2Float(strrev($byteword));
  279. }
  280. }
  281. if (!function_exists('BigEndian2Float')) {
  282. function BigEndian2Float($byteword) {
  283. // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
  284. // http://www.psc.edu/general/software/packages/ieee/ieee.html
  285. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
  286. $bitword = BigEndian2Bin($byteword);
  287. $signbit = $bitword{0};
  288. switch (strlen($byteword) * 8) {
  289. case 32:
  290. $exponentbits = 8;
  291. $fractionbits = 23;
  292. break;
  293. case 64:
  294. $exponentbits = 11;
  295. $fractionbits = 52;
  296. break;
  297. case 80:
  298. $exponentbits = 16;
  299. $fractionbits = 64;
  300. break;
  301. default:
  302. return false;
  303. break;
  304. }
  305. $exponentstring = substr($bitword, 1, $exponentbits - 1);
  306. $fractionstring = substr($bitword, $exponentbits, $fractionbits);
  307. $exponent = Bin2Dec($exponentstring);
  308. $fraction = Bin2Dec($fractionstring);
  309. if (($exponentbits == 16) && ($fractionbits == 64)) {
  310. // 80-bit
  311. // As used in Apple AIFF for sample_rate
  312. // A bit of a hack, but it works ;)
  313. return pow(2, ($exponent - 16382)) * DecimalBinary2Float($fractionstring);
  314. }
  315. if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
  316. // Not a Number
  317. $floatvalue = false;
  318. } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
  319. if ($signbit == '1') {
  320. $floatvalue = '-infinity';
  321. } else {
  322. $floatvalue = '+infinity';
  323. }
  324. } elseif (($exponent == 0) && ($fraction == 0)) {
  325. if ($signbit == '1') {
  326. $floatvalue = -0;
  327. } else {
  328. $floatvalue = 0;
  329. }
  330. $floatvalue = ($signbit ? 0 : -0);
  331. } elseif (($exponent == 0) && ($fraction != 0)) {
  332. // These are 'unnormalized' values
  333. $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * DecimalBinary2Float($fractionstring);
  334. if ($signbit == '1') {
  335. $floatvalue *= -1;
  336. }
  337. } elseif ($exponent != 0) {
  338. $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + DecimalBinary2Float($fractionstring));
  339. if ($signbit == '1') {
  340. $floatvalue *= -1;
  341. }
  342. }
  343. return (float) $floatvalue;
  344. }
  345. }
  346. if (!function_exists('BigEndian2Int')) {
  347. function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
  348. $intvalue = 0;
  349. $bytewordlen = strlen($byteword);
  350. for ($i = 0; $i < $bytewordlen; $i++) {
  351. if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
  352. $intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7);
  353. } else {
  354. $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
  355. }
  356. }
  357. if ($signed && !$synchsafe) {
  358. // synchsafe ints are not allowed to be signed
  359. switch ($bytewordlen) {
  360. case 1:
  361. case 2:
  362. case 3:
  363. case 4:
  364. $signmaskbit = 0x80 << (8 * ($bytewordlen - 1));
  365. if ($intvalue & $signmaskbit) {
  366. $intvalue = 0 - ($intvalue & ($signmaskbit - 1));
  367. }
  368. break;
  369. default:
  370. die('ERROR: Cannot have signed integers larger than 32-bits in BigEndian2Int()');
  371. break;
  372. }
  373. }
  374. return CastAsInt($intvalue);
  375. }
  376. }
  377. if (!function_exists('LittleEndian2Int')) {
  378. function LittleEndian2Int($byteword, $signed=false) {
  379. return BigEndian2Int(strrev($byteword), false, $signed);
  380. }
  381. }
  382. if (!function_exists('BigEndian2Bin')) {
  383. function BigEndian2Bin($byteword) {
  384. $binvalue = '';
  385. $bytewordlen = strlen($byteword);
  386. for ($i = 0; $i < $bytewordlen; $i++) {
  387. $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
  388. }
  389. return $binvalue;
  390. }
  391. }
  392. if (!function_exists('BigEndian2String')) {
  393. function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
  394. if ($number < 0) {
  395. return false;
  396. }
  397. $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
  398. $intstring = '';
  399. if ($signed) {
  400. if ($minbytes > 4) {
  401. die('ERROR: Cannot have signed integers larger than 32-bits in BigEndian2String()');
  402. }
  403. $number = $number & (0x80 << (8 * ($minbytes - 1)));
  404. }
  405. while ($number != 0) {
  406. $quotient = ($number / ($maskbyte + 1));
  407. $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring;
  408. $number = floor($quotient);
  409. }
  410. return str_pad($intstring, $minbytes, chr(0), STR_PAD_LEFT);
  411. }
  412. }
  413. if (!function_exists('Dec2Bin')) {
  414. function Dec2Bin($number) {
  415. while ($number >= 256) {
  416. $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
  417. $number = floor($number / 256);
  418. }
  419. $bytes[] = $number;
  420. $binstring = '';
  421. for ($i = 0; $i < count($bytes); $i++) {
  422. $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
  423. }
  424. return $binstring;
  425. }
  426. }
  427. if (!function_exists('Bin2Dec')) {
  428. function Bin2Dec($binstring) {
  429. $decvalue = 0;
  430. for ($i = 0; $i < strlen($binstring); $i++) {
  431. $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
  432. }
  433. return CastAsInt($decvalue);
  434. }
  435. }
  436. if (!function_exists('Bin2String')) {
  437. function Bin2String($binstring) {
  438. // return 'hi' for input of '0110100001101001'
  439. $string = '';
  440. $binstringreversed = strrev($binstring);
  441. for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
  442. $string = chr(Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
  443. }
  444. return $string;
  445. }
  446. }
  447. if (!function_exists('LittleEndian2String')) {
  448. function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
  449. $intstring = '';
  450. while ($number > 0) {
  451. if ($synchsafe) {
  452. $intstring = $intstring.chr($number & 127);
  453. $number >>= 7;
  454. } else {
  455. $intstring = $intstring.chr($number & 255);
  456. $number >>= 8;
  457. }
  458. }
  459. return str_pad($intstring, $minbytes, chr(0), STR_PAD_RIGHT);
  460. }
  461. }
  462. if (!function_exists('Bool2IntString')) {
  463. function Bool2IntString($intvalue) {
  464. return ($intvalue ? '1' : '0');
  465. }
  466. }
  467. if (!function_exists('IntString2Bool')) {
  468. function IntString2Bool($char) {
  469. if ($char == '1') {
  470. return true;
  471. } elseif ($char == '0') {
  472. return false;
  473. }
  474. return null;
  475. }
  476. }
  477. if (!function_exists('InverseBoolean')) {
  478. function InverseBoolean($value) {
  479. return ($value ? false : true);
  480. }
  481. }
  482. if (!function_exists('DeUnSynchronise')) {
  483. function DeUnSynchronise($data) {
  484. return str_replace(chr(0xFF).chr(0x00), chr(0xFF), $data);
  485. }
  486. }
  487. if (!function_exists('Unsynchronise')) {
  488. function Unsynchronise($data) {
  489. // Whenever a false synchronisation is found within the tag, one zeroed
  490. // byte is inserted after the first false synchronisation byte. The
  491. // format of a correct sync that should be altered by ID3 encoders is as
  492. // follows:
  493. // %11111111 111xxxxx
  494. // And should be replaced with:
  495. // %11111111 00000000 111xxxxx
  496. // This has the side effect that all $FF 00 combinations have to be
  497. // altered, so they won't be affected by the decoding process. Therefore
  498. // all the $FF 00 combinations have to be replaced with the $FF 00 00
  499. // combination during the unsynchronisation.
  500. $data = str_replace(chr(0xFF).chr(0x00), chr(0xFF).chr(0x00).chr(0x00), $data);
  501. $unsyncheddata = '';
  502. for ($i = 0; $i < strlen($data); $i++) {
  503. $thischar = $data{$i};
  504. $unsyncheddata .= $thischar;
  505. if ($thischar == chr(255)) {
  506. $nextchar = ord(substr($data, $i + 1, 1));
  507. if (($nextchar | 0xE0) == 0xE0) {
  508. // previous byte = 11111111, this byte = 111?????
  509. $unsyncheddata .= chr(0);
  510. }
  511. }
  512. }
  513. return $unsyncheddata;
  514. }
  515. }
  516. if (!function_exists('is_hash')) {
  517. function is_hash($var) {
  518. // written by dev-null@christophe.vg
  519. // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
  520. if (is_array($var)) {
  521. $keys = array_keys($var);
  522. $all_num = true;
  523. for ($i = 0; $i < count($keys); $i++) {
  524. if (is_string($keys[$i])) {
  525. return true;
  526. }
  527. }
  528. }
  529. return false;
  530. }
  531. }
  532. if (!function_exists('array_join_merge')) {
  533. function array_join_merge($arr1, $arr2) {
  534. // written by dev-null@christophe.vg
  535. // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
  536. if (is_array($arr1) && is_array($arr2)) {
  537. // the same -> merge
  538. $new_array = array();
  539. if (is_hash($arr1) && is_hash($arr2)) {
  540. // hashes -> merge based on keys
  541. $keys = array_merge(array_keys($arr1), array_keys($arr2));
  542. foreach ($keys as $key) {
  543. $arr1[$key] = (isset($arr1[$key]) ? $arr1[$key] : '');
  544. $arr2[$key] = (isset($arr2[$key]) ? $arr2[$key] : '');
  545. $new_array[$key] = array_join_merge($arr1[$key], $arr2[$key]);
  546. }
  547. } else {
  548. // two real arrays -> merge
  549. $new_array = array_reverse(array_unique(array_reverse(array_merge($arr1,$arr2))));
  550. }
  551. return $new_array;
  552. } else {
  553. // not the same ... take new one if defined, else the old one stays
  554. return $arr2 ? $arr2 : $arr1;
  555. }
  556. }
  557. }
  558. if (!function_exists('array_merge_clobber')) {
  559. function array_merge_clobber($array1, $array2) {
  560. // written by kc@hireability.com
  561. // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
  562. if (!is_array($array1) || !is_array($array2)) {
  563. return false;
  564. }
  565. $newarray = $array1;
  566. foreach ($array2 as $key => $val) {
  567. if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
  568. $newarray[$key] = array_merge_clobber($newarray[$key], $val);
  569. } else {
  570. $newarray[$key] = $val;
  571. }
  572. }
  573. return $newarray;
  574. }
  575. }
  576. if (!function_exists('array_merge_noclobber')) {
  577. function array_merge_noclobber($array1, $array2) {
  578. if (!is_array($array1) || !is_array($array2)) {
  579. return false;
  580. }
  581. $newarray = $array1;
  582. foreach ($array2 as $key => $val) {
  583. if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
  584. $newarray[$key] = array_merge_noclobber($newarray[$key], $val);
  585. } elseif (!isset($newarray[$key])) {
  586. $newarray[$key] = $val;
  587. }
  588. }
  589. return $newarray;
  590. }
  591. }
  592. if (!function_exists('RoughTranslateUnicodeToASCII')) {
  593. function RoughTranslateUnicodeToASCII($rawdata, $frame_textencoding) {
  594. // rough translation of data for application that can't handle Unicode data
  595. $tempstring = '';
  596. switch ($frame_textencoding) {
  597. case 0: // ISO-8859-1. Terminated with $00.
  598. $asciidata = $rawdata;
  599. break;
  600. case 1: // UTF-16 encoded Unicode with BOM. Terminated with $00 00.
  601. $asciidata = $rawdata;
  602. if (substr($asciidata, 0, 2) == chr(0xFF).chr(0xFE)) {
  603. // remove BOM, only if present (it should be, but...)
  604. $asciidata = substr($asciidata, 2);
  605. }
  606. if (substr($asciidata, strlen($asciidata) - 2, 2) == chr(0).chr(0)) {
  607. $asciidata = substr($asciidata, 0, strlen($asciidata) - 2); // remove terminator, only if present (it should be, but...)
  608. }
  609. for ($i = 0; $i < strlen($asciidata); $i += 2) {
  610. if ((ord($asciidata{$i}) <= 0x7F) || (ord($asciidata{$i}) >= 0xA0)) {
  611. $tempstring .= $asciidata{$i};
  612. } else {
  613. $tempstring .= '?';
  614. }
  615. }
  616. $asciidata = $tempstring;
  617. break;
  618. case 2: // UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
  619. $asciidata = $rawdata;
  620. if (substr($asciidata, strlen($asciidata) - 2, 2) == chr(0).chr(0)) {
  621. $asciidata = substr($asciidata, 0, strlen($asciidata) - 2); // remove terminator, only if present (it should be, but...)
  622. }
  623. for ($i = 0; $i < strlen($asciidata); $i += 2) {
  624. if ((ord($asciidata{$i}) <= 0x7F) || (ord($asciidata{$i}) >= 0xA0)) {
  625. $tempstring .= $asciidata{$i};
  626. } else {
  627. $tempstring .= '?';
  628. }
  629. }
  630. $asciidata = $tempstring;
  631. break;
  632. case 3: // UTF-8 encoded Unicode. Terminated with $00.
  633. $asciidata = utf8_decode($rawdata);
  634. break;
  635. case 255: // Unicode, Big-Endian. Terminated with $00 00.
  636. $asciidata = $rawdata;
  637. if (substr($asciidata, strlen($asciidata) - 2, 2) == chr(0).chr(0)) {
  638. $asciidata = substr($asciidata, 0, strlen($asciidata) - 2); // remove terminator, only if present (it should be, but...)
  639. }
  640. for ($i = 0; ($i + 1) < strlen($asciidata); $i += 2) {
  641. if ((ord($asciidata{($i + 1)}) <= 0x7F) || (ord($asciidata{($i + 1)}) >= 0xA0)) {
  642. $tempstring .= $asciidata{($i + 1)};
  643. } else {
  644. $tempstring .= '?';
  645. }
  646. }
  647. $asciidata = $tempstring;
  648. break;
  649. default:
  650. // shouldn't happen, but in case $frame_textencoding is not 1 <= $frame_textencoding <= 4
  651. // just pass the data through unchanged.
  652. $asciidata = $rawdata;
  653. break;
  654. }
  655. if (substr($asciidata, strlen($asciidata) - 1, 1) == chr(0)) {
  656. // remove null terminator, if present
  657. $asciidata = NoNullString($asciidata);
  658. }
  659. return $asciidata;
  660. // return str_replace(chr(0), '', $asciidata); // just in case any nulls slipped through
  661. }
  662. }
  663. if (!function_exists('PlaytimeString')) {
  664. function PlaytimeString($playtimeseconds) {
  665. $contentseconds = round((($playtimeseconds / 60) - floor($playtimeseconds / 60)) * 60);
  666. $contentminutes = floor($playtimeseconds / 60);
  667. if ($contentseconds >= 60) {
  668. $contentseconds -= 60;
  669. $contentminutes++;
  670. }
  671. return number_format($contentminutes).':'.str_pad($contentseconds, 2, 0, STR_PAD_LEFT);
  672. }
  673. }
  674. if (!function_exists('CloseMatch')) {
  675. function CloseMatch($value1, $value2, $tolerance) {
  676. return (abs($value1 - $value2) <= $tolerance);
  677. }
  678. }
  679. if (!function_exists('ID3v1matchesID3v2')) {
  680. function ID3v1matchesID3v2($id3v1, $id3v2) {
  681. $requiredindices = array('title', 'artist', 'album', 'year', 'genre', 'comment');
  682. foreach ($requiredindices as $requiredindex) {
  683. if (!isset($id3v1["$requiredindex"])) {
  684. $id3v1["$requiredindex"] = '';
  685. }
  686. if (!isset($id3v2["$requiredindex"])) {
  687. $id3v2["$requiredindex"] = '';
  688. }
  689. }
  690. if (trim($id3v1['title']) != trim(substr($id3v2['title'], 0, 30))) {
  691. return false;
  692. }
  693. if (trim($id3v1['artist']) != trim(substr($id3v2['artist'], 0, 30))) {
  694. return false;
  695. }
  696. if (trim($id3v1['album']) != trim(substr($id3v2['album'], 0, 30))) {
  697. return false;
  698. }
  699. if (trim($id3v1['year']) != trim(substr($id3v2['year'], 0, 4))) {
  700. return false;
  701. }
  702. if (trim($id3v1['genre']) != trim($id3v2['genre'])) {
  703. return false;
  704. }
  705. if (isset($id3v1['track'])) {
  706. if (!isset($id3v1['track']) || (trim($id3v1['track']) != trim($id3v2['track']))) {
  707. return false;
  708. }
  709. if (trim($id3v1['comment']) != trim(substr($id3v2['comment'], 0, 28))) {
  710. return false;
  711. }
  712. } else {
  713. if (trim($id3v1['comment']) != trim(substr($id3v2['comment'], 0, 30))) {
  714. return false;
  715. }
  716. }
  717. return true;
  718. }
  719. }
  720. if (!function_exists('FILETIMEtoUNIXtime')) {
  721. function FILETIMEtoUNIXtime($FILETIME, $round=true) {
  722. // FILETIME is a 64-bit unsigned integer representing
  723. // the number of 100-nanosecond intervals since January 1, 1601
  724. // UNIX timestamp is number of seconds since January 1, 1970
  725. // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days
  726. if ($round) {
  727. return round(($FILETIME - 116444736000000000) / 10000000);
  728. }
  729. return ($FILETIME - 116444736000000000) / 10000000;
  730. }
  731. }
  732. if (!function_exists('GUIDtoBytestring')) {
  733. function GUIDtoBytestring($GUIDstring) {
  734. // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
  735. // first 4 bytes are in little-endian order
  736. // next 2 bytes are appended in little-endian order
  737. // next 2 bytes are appended in little-endian order
  738. // next 2 bytes are appended in big-endian order
  739. // next 6 bytes are appended in big-endian order
  740. // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string:
  741. // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp
  742. $hexbytecharstring = chr(hexdec(substr($GUIDstring, 6, 2)));
  743. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 4, 2)));
  744. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 2, 2)));
  745. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 0, 2)));
  746. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2)));
  747. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 9, 2)));
  748. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2)));
  749. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2)));
  750. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2)));
  751. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2)));
  752. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2)));
  753. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2)));
  754. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2)));
  755. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2)));
  756. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2)));
  757. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2)));
  758. return $hexbytecharstring;
  759. }
  760. }
  761. if (!function_exists('BytestringToGUID')) {
  762. function BytestringToGUID($Bytestring) {
  763. $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
  764. $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
  765. $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT);
  766. $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT);
  767. $GUIDstring .= '-';
  768. $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT);
  769. $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT);
  770. $GUIDstring .= '-';
  771. $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT);
  772. $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT);
  773. $GUIDstring .= '-';
  774. $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT);
  775. $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT);
  776. $GUIDstring .= '-';
  777. $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
  778. $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
  779. $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
  780. $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
  781. $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
  782. $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
  783. return strtoupper($GUIDstring);
  784. }
  785. }
  786. if (!function_exists('BitrateColor')) {
  787. function BitrateColor($bitrate) {
  788. $bitrate /= 3; // scale from 1-768kbps to 1-256kbps
  789. $bitrate--; // scale from 1-256kbps to 0-255kbps
  790. $bitrate = max($bitrate, 0);
  791. $bitrate = min($bitrate, 255);
  792. //$bitrate = max($bitrate, 32);
  793. //$bitrate = min($bitrate, 143);
  794. //$bitrate = ($bitrate * 2) - 32;
  795. $Rcomponent = max(255 - ($bitrate * 2), 0);
  796. $Gcomponent = max(($bitrate * 2) - 255, 0);
  797. if ($bitrate > 127) {
  798. $Bcomponent = max((255 - $bitrate) * 2, 0);
  799. } else {
  800. $Bcomponent = max($bitrate * 2, 0);
  801. }
  802. return str_pad(dechex($Rcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Gcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Bcomponent), 2, '0', STR_PAD_LEFT);
  803. }
  804. }
  805. if (!function_exists('BitrateText')) {
  806. function BitrateText($bitrate) {
  807. return '<SPAN STYLE="color: #'.BitrateColor($bitrate).'">'.round($bitrate).' kbps</SPAN>';
  808. }
  809. }
  810. if (!function_exists('image_type_to_mime_type')) {
  811. function image_type_to_mime_type($imagetypeid) {
  812. // only available in PHP v4.3.0+
  813. static $image_type_to_mime_type = array();
  814. if (empty($image_type_to_mime_type)) {
  815. $image_type_to_mime_type[1] = 'image/gif'; // GIF
  816. $image_type_to_mime_type[2] = 'image/jpeg'; // JPEG
  817. $image_type_to_mime_type[3] = 'image/png'; // PNG
  818. $image_type_to_mime_type[4] = 'application/x-shockwave-flash'; // Flash
  819. $image_type_to_mime_type[5] = 'image/psd'; // PSD
  820. $image_type_to_mime_type[6] = 'image/bmp'; // BMP
  821. $image_type_to_mime_type[7] = 'image/tiff'; // TIFF: little-endian (Intel)
  822. $image_type_to_mime_type[8] = 'image/tiff'; // TIFF: big-endian (Motorola)
  823. //$image_type_to_mime_type[9] = 'image/jpc'; // JPC
  824. //$image_type_to_mime_type[10] = 'image/jp2'; // JPC
  825. //$image_type_to_mime_type[11] = 'image/jpx'; // JPC
  826. //$image_type_to_mime_type[12] = 'image/jb2'; // JPC
  827. $image_type_to_mime_type[13] = 'application/x-shockwave-flash'; // Shockwave
  828. $image_type_to_mime_type[14] = 'image/iff'; // IFF
  829. }
  830. return (isset($image_type_to_mime_type[$imagetypeid]) ? $image_type_to_mime_type[$imagetypeid] : 'application/octet-stream');
  831. }
  832. }
  833. if (!function_exists('utf8_decode')) {
  834. // PHP has this function built-in if it's configured with the --with-xml option
  835. // This version of the function is only provided in case XML isn't installed
  836. function utf8_decode($utf8text) {
  837. // http://www.php.net/manual/en/function.utf8-encode.php
  838. // bytes bits representation
  839. // 1 7 0bbbbbbb
  840. // 2 11 110bbbbb 10bbbbbb
  841. // 3 16 1110bbbb 10bbbbbb 10bbbbbb
  842. // 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
  843. $utf8length = strlen($utf8text);
  844. $decodedtext = '';
  845. for ($i = 0; $i < $utf8length; $i++) {
  846. if ((ord($utf8text{$i}) & 0x80) == 0) {
  847. $decodedtext .= $utf8text{$i};
  848. } elseif ((ord($utf8text{$i}) & 0xF0) == 0xF0) {
  849. $decodedtext .= '?';
  850. $i += 3;
  851. } elseif ((ord($utf8text{$i}) & 0xE0) == 0xE0) {
  852. $decodedtext .= '?';
  853. $i += 2;
  854. } elseif ((ord($utf8text{$i}) & 0xC0) == 0xC0) {
  855. // 2 11 110bbbbb 10bbbbbb
  856. $decodedchar = Bin2Dec(substr(Dec2Bin(ord($utf8text{$i})), 3, 5).substr(Dec2Bin(ord($utf8text{($i + 1)})), 2, 6));
  857. if ($decodedchar <= 255) {
  858. $decodedtext .= chr($decodedchar);
  859. } else {
  860. $decodedtext .= '?';
  861. }
  862. $i += 1;
  863. }
  864. }
  865. return $decodedtext;
  866. }
  867. }
  868. if (!function_exists('DateMac2Unix')) {
  869. function DateMac2Unix($macdate) {
  870. // Macintosh timestamp: seconds since 00:00h January 1, 1904
  871. // UNIX timestamp: seconds since 00:00h January 1, 1970
  872. return CastAsInt($macdate - 2082844800);
  873. }
  874. }
  875. if (!function_exists('FixedPoint8_8')) {
  876. function FixedPoint8_8($rawdata) {
  877. return BigEndian2Int(substr($rawdata, 0, 1)) + (float) (BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
  878. }
  879. }
  880. if (!function_exists('FixedPoint16_16')) {
  881. function FixedPoint16_16($rawdata) {
  882. return BigEndian2Int(substr($rawdata, 0, 2)) + (float) (BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
  883. }
  884. }
  885. if (!function_exists('FixedPoint2_30')) {
  886. function FixedPoint2_30($rawdata) {
  887. $binarystring = BigEndian2Bin($rawdata);
  888. return Bin2Dec(substr($binarystring, 0, 2)) + (float) (Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
  889. }
  890. }
  891. if (!function_exists('Pascal2String')) {
  892. function Pascal2String($pascalstring) {
  893. // Pascal strings have 1 byte at the beginning saying how many chars are in the string
  894. return substr($pascalstring, 1);
  895. }
  896. }
  897. if (!function_exists('NoNullString')) {
  898. function NoNullString($nullterminatedstring) {
  899. // remove the single null terminator on null terminated strings
  900. if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === chr(0)) {
  901. return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
  902. }
  903. return $nullterminatedstring;
  904. }
  905. }
  906. if (!function_exists('FileSizeNiceDisplay')) {
  907. function FileSizeNiceDisplay($filesize, $precision=2) {
  908. if ($filesize < 1000) {
  909. $sizeunit = 'bytes';
  910. $precision = 0;
  911. } else {
  912. $filesize /= 1024;
  913. $sizeunit = 'kB';
  914. }
  915. if ($filesize >= 1000) {
  916. $filesize /= 1024;
  917. $sizeunit = 'MB';
  918. }
  919. if ($filesize >= 1000) {
  920. $filesize /= 1024;
  921. $sizeunit = 'GB';
  922. }
  923. return number_format($filesize, $precision).' '.$sizeunit;
  924. }
  925. }
  926. if (!function_exists('DOStime2UNIXtime')) {
  927. function DOStime2UNIXtime($DOSdate, $DOStime) {
  928. // wFatDate
  929. // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
  930. // Bits Contents
  931. // 0-4 Day of the month (1-31)
  932. // 5-8 Month (1 = January, 2 = February, and so on)
  933. // 9-15 Year offset from 1980 (add 1980 to get actual year)
  934. $UNIXday = ($DOSdate & 0x001F);
  935. $UNIXmonth = (($DOSdate & 0x01E0) >> 5);
  936. $UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980;
  937. // wFatTime
  938. // Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:
  939. // Bits Contents
  940. // 0-4 Second divided by 2
  941. // 5-10 Minute (0-59)
  942. // 11-15 Hour (0-23 on a 24-hour clock)
  943. $UNIXsecond = ($DOStime & 0x001F) * 2;
  944. $UNIXminute = (($DOStime & 0x07E0) >> 5);
  945. $UNIXhour = (($DOStime & 0xF800) >> 11);
  946. return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
  947. }
  948. }
  949. if (!function_exists('CreateDeepArray')) {
  950. function CreateDeepArray($ArrayPath, $Separator, $Value) {
  951. // assigns $Value to a nested array path:
  952. // $foo = CreateDeepArray('/path/to/my', '/', 'file.txt')
  953. // is the same as:
  954. // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
  955. // or
  956. // $foo['path']['to']['my'] = 'file.txt';
  957. while ($ArrayPath{0} == $Separator) {
  958. $ArrayPath = substr($ArrayPath, 1);
  959. }
  960. if (($pos = strpos($ArrayPath, $Separator)) !== false) {
  961. $ReturnedArray[substr($ArrayPath, 0, $pos)] = CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
  962. } else {
  963. $ReturnedArray["$ArrayPath"] = $Value;
  964. }
  965. return $ReturnedArray;
  966. }
  967. }
  968. if (!function_exists('md5_file')) {
  969. // Allan Hansen <ah@artemis.dk>
  970. // md5_file() exists in PHP 4.2.0.
  971. // The following works under UNIX only, but dies on windows
  972. function md5_file($file) {
  973. if (substr(php_uname(), 0, 7) == 'Windows') {
  974. die('PHP 4.2.0 or newer required for md5_file()');
  975. }
  976. $file = str_replace('`', '\\`', $file);
  977. if (preg_match("#^([0-9a-f]{32})[ \t\n\r]#i", `md5sum "$file"`, $r)) {
  978. return $r[1];
  979. }
  980. return false;
  981. }
  982. }
  983. if (!function_exists('md5_data')) {
  984. // Allan Hansen <ah@artemis.dk>
  985. // md5_data() - returns md5sum for a file from startuing position to absolute end position
  986. function md5_data($file, $offset, $end, $invertsign=false) {
  987. // first try and create a temporary file in the same directory as the file being scanned
  988. if (($dataMD5filename = tempnam(dirname($file), preg_replace('#[^[:alnum:]]#i', '', basename($file)))) === false) {
  989. // if that fails, create a temporary file in the system temp directory
  990. if (($dataMD5filename = tempnam('/tmp', 'getID3')) === false) {
  991. // if that fails, create a temporary file in the current directory
  992. if (($dataMD5filename = tempnam('.', preg_replace('#[^[:alnum:]]#i', '', basename($file)))) === false) {
  993. // can't find anywhere to create a temp file, just die
  994. return false;
  995. }
  996. }
  997. }
  998. $md5 = false;
  999. set_time_limit(max(filesize($file) / 1000000, 30));
  1000. // copy parts of file
  1001. ob_start();
  1002. if ($fp = fopen($file, 'rb')) {
  1003. ob_end_clean();
  1004. ob_start();
  1005. if ($MD5fp = fopen($dataMD5filename, 'wb')) {
  1006. ob_end_clean();
  1007. if ($invertsign) {
  1008. // Load conversion lookup strings for 8-bit unsigned->signed conversion below
  1009. $from = '';
  1010. $to = '';
  1011. for ($i = 0; $i < 128; $i++) {
  1012. $from .= chr($i);
  1013. $to .= chr($i + 128);
  1014. }
  1015. for ($i = 128; $i < 256; $i++) {
  1016. $from .= chr($i);
  1017. $to .= chr($i - 128);
  1018. }
  1019. }
  1020. fseek($fp, $offset, SEEK_SET);
  1021. $byteslefttowrite = $end - $offset;
  1022. while (($byteslefttowrite > 0) && ($buffer = fread($fp, 32768))) {
  1023. if ($invertsign) {
  1024. // Possibly FLAC-specific (?)
  1025. // FLAC calculates the MD5sum of the source data of 8-bit files
  1026. // not on the actual byte values in the source file, but of those
  1027. // values converted from unsigned to signed, or more specifcally,
  1028. // with the MSB inverted. ex: 01 -> 81; F5 -> 75; etc
  1029. // Therefore, 8-bit WAV data has to be converted before getting the
  1030. // md5_data value so as to match the FLAC value
  1031. // Flip the MSB for each byte in the buffer before copying
  1032. $buffer = strtr($buffer, $from, $to);
  1033. }
  1034. $byteswritten = fwrite($MD5fp, $buffer, $byteslefttowrite);
  1035. $byteslefttowrite -= $byteswritten;
  1036. }
  1037. fclose($MD5fp);
  1038. $md5 = md5_file($dataMD5filename);
  1039. } else {
  1040. $errormessage = ob_get_contents();
  1041. ob_end_clean();
  1042. }
  1043. fclose($fp);
  1044. } else {
  1045. $errormessage = ob_get_contents();
  1046. ob_end_clean();
  1047. }
  1048. unlink($dataMD5filename);
  1049. return $md5;
  1050. }
  1051. }
  1052. if (!function_exists('TwosCompliment2Decimal')) {
  1053. function TwosCompliment2Decimal($BinaryValue) {
  1054. // http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
  1055. // First check if the number is negative or positive by looking at the sign bit.
  1056. // If it is positive, simply convert it to decimal.
  1057. // If it is negative, make it positive by inverting the bits and adding one.
  1058. // Then, convert the result to decimal.
  1059. // The negative of this number is the value of the original binary.
  1060. if ($BinaryValue & 0x80) {
  1061. // negative number
  1062. return (0 - ((~$BinaryValue & 0xFF) + 1));
  1063. } else {
  1064. // positive number
  1065. return $BinaryValue;
  1066. }
  1067. }
  1068. }
  1069. if (!function_exists('LastArrayElement')) {
  1070. function LastArrayElement($MyArray) {
  1071. if (!is_array($MyArray)) {
  1072. return false;
  1073. }
  1074. if (empty($MyArray)) {
  1075. return null;
  1076. }
  1077. foreach ($MyArray as $key => $value) {
  1078. }
  1079. return $value;
  1080. }
  1081. }
  1082. if (!function_exists('safe_inc')) {
  1083. function safe_inc(&$variable, $increment=1) {
  1084. if (isset($variable)) {
  1085. $variable += $increment;
  1086. } else {
  1087. $variable = $increment;
  1088. }
  1089. return true;
  1090. }
  1091. }
  1092. if (!function_exists('CalculateCompressionRatioVideo')) {
  1093. function CalculateCompressionRatioVideo(&$ThisFileInfo) {
  1094. if (empty($ThisFileInfo['video'])) {
  1095. return false;
  1096. }
  1097. if (empty($ThisFileInfo['video']['resolution_x']) || empty($ThisFileInfo['video']['resolution_y'])) {
  1098. return false;
  1099. }
  1100. if (empty($ThisFileInfo['video']['bits_per_sample'])) {
  1101. return false;
  1102. }
  1103. switch ($ThisFileInfo['video']['dataformat']) {
  1104. case 'bmp':
  1105. case 'gif':
  1106. case 'jpeg':
  1107. case 'jpg':
  1108. case 'png':
  1109. case 'tiff':
  1110. $FrameRate = 1;
  1111. $PlaytimeSeconds = 1;
  1112. $BitrateCompressed = $ThisFileInfo['filesize'] * 8;
  1113. break;
  1114. default:
  1115. if (!empty($ThisFileInfo['video']['frame_rate'])) {
  1116. $FrameRate = $ThisFileInfo['video']['frame_rate'];
  1117. } else {
  1118. return false;
  1119. }
  1120. if (!empty($ThisFileInfo['playtime_seconds'])) {
  1121. $PlaytimeSeconds = $ThisFileInfo['playtime_seconds'];
  1122. } else {
  1123. return false;
  1124. }
  1125. if (!empty($ThisFileInfo['video']['bitrate'])) {
  1126. $BitrateCompressed = $ThisFileInfo['video']['bitrate'];
  1127. } else {
  1128. return false;
  1129. }
  1130. break;
  1131. }
  1132. $BitrateUncompressed = $ThisFileInfo['video']['resolution_x'] * $ThisFileInfo['video']['resolution_y'] * $ThisFileInfo['video']['bits_per_sample'] * $FrameRate;
  1133. $ThisFileInfo['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
  1134. return true;
  1135. }
  1136. }
  1137. if (!function_exists('CalculateCompressionRatioAudio')) {
  1138. function CalculateCompressionRatioAudio(&$ThisFileInfo) {
  1139. if (empty($ThisFileInfo['audio']['bitrate']) || empty($ThisFileInfo['audio']['channels']) || empty($ThisFileInfo['audio']['sample_rate']) || empty($ThisFileInfo['audio']['bits_per_sample'])) {
  1140. return false;
  1141. }
  1142. $ThisFileInfo['audio']['compression_ratio'] = $ThisFileInfo['audio']['bitrate'] / ($ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['bits_per_sample']);
  1143. return true;
  1144. }
  1145. }
  1146. if (!function_exists('IsValidMIMEstring')) {
  1147. function IsValidMIMEstring($mimestring) {
  1148. if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) {
  1149. return true;
  1150. }
  1151. return false;
  1152. }
  1153. }
  1154. if (!function_exists('IsWithinBitRange')) {
  1155. function IsWithinBitRange($number, $maxbits, $signed=false) {
  1156. if ($signed) {
  1157. if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) {
  1158. return true;
  1159. }
  1160. } else {
  1161. if (($number >= 0) && ($number <= pow(2, $maxbits))) {
  1162. return true;
  1163. }
  1164. }
  1165. return false;
  1166. }
  1167. }
  1168. if (!function_exists('safe_parse_url')) {
  1169. function safe_parse_url($url) {
  1170. ob_start();
  1171. $parts = parse_url($url);
  1172. $errormessage = ob_get_contents();
  1173. ob_end_clean();
  1174. $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : '');
  1175. $parts['host'] = (isset($parts['host']) ? $parts['host'] : '');
  1176. $parts['user'] = (isset($parts['user']) ? $parts['user'] : '');
  1177. $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : '');
  1178. $parts['path'] = (isset($parts['path']) ? $parts['path'] : '');
  1179. $parts['query'] = (isset($parts['query']) ? $parts['query'] : '');
  1180. return $parts;
  1181. }
  1182. }
  1183. if (!function_exists('IsValidURL')) {
  1184. function IsValidURL($url, $allowUserPass=false) {
  1185. if ($url == '') {
  1186. return false;
  1187. }
  1188. if ($allowUserPass !== true) {
  1189. if (strstr($url, '@')) {
  1190. // in the format http://user:pass@example.com or http://user@example.com
  1191. // but could easily be somebody incorrectly entering an email address in place of a URL
  1192. return false;
  1193. }
  1194. }
  1195. if ($parts = safe_parse_url($url)) {
  1196. if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) {
  1197. return false;
  1198. } elseif (!preg_match("#^[[:alnum:]]([-.]?[0-9a-z])*\.[a-z]{2,3}#i$", $parts['host'], $regs) && !preg_match('#^[0-9]{1,3}(\.[0-9]{1,3}){3}$#', $parts['host'])) {
  1199. return false;
  1200. } elseif (!preg_match("#^([[:alnum:]-]|[\_])*$#i", $parts['user'], $regs)) {
  1201. return false;
  1202. } elseif (!preg_match("#^([[:alnum:]-]|[\_])*$#i", $parts['pass'], $regs)) {
  1203. return false;
  1204. } elseif (!preg_match("#^[[:alnum:]/_\.@~-]*$#i", $parts['path'], $regs)) {
  1205. return false;
  1206. } elseif (!preg_match("#^[[:alnum:]?&=+:;_()%#/,\.-]*$#i", $parts['query'], $regs)) {
  1207. return false;
  1208. } else {
  1209. return true;
  1210. }
  1211. }
  1212. return false;
  1213. }
  1214. }
  1215. echo '<form action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'" method="get">';
  1216. echo 'Enter 4 hex bytes of MPEG-audio header (ie <I>FF FA 92 44</I>)<BR>';
  1217. echo '<input type="text" name="HeaderHexBytes" value="'.htmlentities(isset($_POST['HeaderHexBytes']) ? strtoupper($_POST['HeaderHexBytes']) : '', ENT_QUOTES).'" size="11" maxlength="11">';
  1218. echo '<input type="submit" name="Analyze" value="Analyze"></form>';
  1219. echo '<hr>';
  1220. echo '<form action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'" METHOD="get">';
  1221. echo 'Generate a MPEG-audio 4-byte header from these values:<BR>';
  1222. echo '<table border="0">';
  1223. $MPEGgenerateValues = array(
  1224. 'version'=>array('1', '2', '2.5'),
  1225. 'layer'=>array('I', 'II', 'III'),
  1226. 'protection'=>array('Y', 'N'),
  1227. 'bitrate'=>array('free', '8', '16', '24', '32', '40', '48', '56', '64', '80', '96', '112', '128', '144', '160', '176', '192', '224', '256', '288', '320', '352', '384', '416', '448'),
  1228. 'frequency'=>array('8000', '11025', '12000', '16000', '22050', '24000', '32000', '44100', '48000'),
  1229. 'padding'=>array('Y', 'N'),
  1230. 'private'=>array('Y', 'N'),
  1231. 'channelmode'=>array('stereo', 'joint stereo', 'dual channel', 'mono'),
  1232. 'modeextension'=>array('none', 'IS', 'MS', 'IS+MS', '4-31', '8-31', '12-31', '16-31'),
  1233. 'copyright'=>array('Y', 'N'),
  1234. 'original'=>array('Y', 'N'),
  1235. 'emphasis'=>array('none', '50/15ms', 'CCIT J.17')
  1236. );
  1237. foreach ($MPEGgenerateValues as $name => $dataarray) {
  1238. echo '<tr><th>'.$name.':</th><td><select name="'.$name.'">';
  1239. foreach ($dataarray as $key => $value) {
  1240. echo '<option'.((isset($_POST["$name"]) && ($_POST["$name"] == $value)) ? ' SELECTED' : '').'>'.$value.'</option>';
  1241. }
  1242. echo '</select></td></tr>';
  1243. }
  1244. if (isset($_POST['bitrate'])) {
  1245. echo '<tr><th>Frame Length:</th><td>'.(int) MPEGaudioFrameLength($_POST['bitrate'], $_POST['version'], $_POST['layer'], (($_POST['padding'] == 'Y') ? '1' : '0'), $_POST['frequency']).'</td></tr>';
  1246. }
  1247. echo '</table>';
  1248. echo '<input type="submit" name="Generate" value="Generate"></form>';
  1249. echo '<hr>';
  1250. if (isset($_POST['Analyze']) && $_POST['HeaderHexBytes']) {
  1251. $headerbytearray = explode(' ', $_POST['HeaderHexBytes']);
  1252. if (count($headerbytearray) != 4) {
  1253. die('Invalid byte pattern');
  1254. }
  1255. $headerstring = '';
  1256. foreach ($headerbytearray as $textbyte) {
  1257. $headerstring .= chr(hexdec($textbyte));
  1258. }
  1259. $MP3fileInfo['error'] = '';
  1260. $MPEGheaderRawArray = MPEGaudioHeaderDecode(substr($headerstring, 0, 4));
  1261. if (MPEGaudioHeaderValid($MPEGheaderRawArray, true)) {
  1262. $MP3fileInfo['raw'] = $MPEGheaderRawArray;
  1263. $MP3fileInfo['version'] = MPEGaudioVersionLookup($MP3fileInfo['raw']['version']);
  1264. $MP3fileInfo['layer'] = MPEGaudioLayerLookup($MP3fileInfo['raw']['layer']);
  1265. $MP3fileInfo['protection'] = MPEGaudioCRCLookup($MP3fileInfo['raw']['protection']);
  1266. $MP3fileInfo['bitrate'] = MPEGaudioBitrateLookup($MP3fileInfo['version'], $MP3fileInfo['layer'], $MP3fileInfo['raw']['bitrate']);
  1267. $MP3fileInfo['frequency'] = MPEGaudioFrequencyLookup($MP3fileInfo['version'], $MP3fileInfo['raw']['sample_rate']);
  1268. $MP3fileInfo['padding'] = (bool) $MP3fileInfo['raw']['padding'];
  1269. $MP3fileInfo['private'] = (bool) $MP3fileInfo['raw']['private'];
  1270. $MP3fileInfo['channelmode'] = MPEGaudioChannelModeLookup($MP3fileInfo['raw']['channelmode']);
  1271. $MP3fileInfo['channels'] = (($MP3fileInfo['channelmode'] == 'mono') ? 1 : 2);
  1272. $MP3fileInfo['modeextension'] = MPEGaudioModeExtensionLookup($MP3fileInfo['layer'], $MP3fileInfo['raw']['modeextension']);
  1273. $MP3fileInfo['copyright'] = (bool) $MP3fileInfo['raw']['copyright'];
  1274. $MP3fileInfo['original'] = (bool) $MP3fileInfo['raw']['original'];
  1275. $MP3fileInfo['emphasis'] = MPEGaudioEmphasisLookup($MP3fileInfo['raw']['emphasis']);
  1276. if ($MP3fileInfo['protection']) {
  1277. $MP3fileInfo['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
  1278. }
  1279. if ($MP3fileInfo['frequency'] > 0) {
  1280. $MP3fileInfo['framelength'] = MPEGaudioFrameLength($MP3fileInfo['bitrate'], $MP3fileInfo['version'], $MP3fileInfo['layer'], (int) $MP3fileInfo['padding'], $MP3fileInfo['frequency']);
  1281. }
  1282. if ($MP3fileInfo['bitrate'] != 'free') {
  1283. $MP3fileInfo['bitrate'] *= 1000;
  1284. }
  1285. } else {
  1286. $MP3fileInfo['error'] .= "\n".'Invalid MPEG audio header';
  1287. }
  1288. if (!$MP3fileInfo['error']) {
  1289. unset($MP3fileInfo['error']);
  1290. }
  1291. echo table_var_dump($MP3fileInfo);
  1292. } elseif (isset($_POST['Generate'])) {
  1293. // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
  1294. $headerbitstream = '11111111111'; // A - Frame sync (all bits set)
  1295. $MPEGversionLookup = array('2.5'=>'00', '2'=>'10', '1'=>'11');
  1296. $headerbitstream .= $MPEGversionLookup[$_POST['version']]; // B - MPEG Audio version ID
  1297. $MPEGlayerLookup = array('III'=>'01', 'II'=>'10', 'I'=>'11');
  1298. $headerbitstream .= $MPEGlayerLookup[$_POST['layer']]; // C - Layer description
  1299. $headerbitstream .= (($_POST['protection'] == 'Y') ? '0' : '1'); // D - Protection bit
  1300. $MPEGaudioBitrateLookup['1']['I'] = array('free'=>'0000', '32'=>'0001', '64'=>'0010', '96'=>'0011', '128'=>'0100', '160'=>'0101', '192'=>'0110', '224'=>'0111', '256'=>'1000', '288'=>'1001', '320'=>'1010', '352'=>'1011', '384'=>'1100', '416'=>'1101', '448'=>'1110');
  1301. $MPEGaudioBitrateLookup['1']['II'] = array('free'=>'0000', '32'=>'0001', '48'=>'0010', '56'=>'0011', '64'=>'0100', '80'=>'0101', '96'=>'0110', '112'=>'0111', '128'=>'1000', '160'=>'1001', '192'=>'1010', '224'=>'1011', '256'=>'1100', '320'=>'1101', '384'=>'1110');
  1302. $MPEGaudioBitrateLookup['1']['III'] = array('free'=>'0000', '32'=>'0001', '40'=>'0010', '48'=>'0011', '56'=>'0100', '64'=>'0101', '80'=>'0110', '96'=>'0111', '112'=>'1000', '128'=>'1001', '160'=>'1010', '192'=>'1011', '224'=>'1100', '256'=>'1101', '320'=>'1110');
  1303. $MPEGaudioBitrateLookup['2']['I'] = array('free'=>'0000', '32'=>'0001', '48'=>'0010', '56'=>'0011', '64'=>'0100', '80'=>'0101', '96'=>'0110', '112'=>'0111', '128'=>'1000', '144'=>'1001', '160'=>'1010', '176'=>'1011', '192'=>'1100', '224'=>'1101', '256'=>'1110');
  1304. $MPEGaudioBitrateLookup['2']['II'] = array('free'=>'0000', '8'=>'0001', '16'=>'0010', '24'=>'0011', '32'=>'0100', '40'=>'0101', '48'=>'0110', '56'=>'0111', '64'=>'1000', '80'=>'1001', '96'=>'1010', '112'=>'1011', '128'=>'1100', '144'=>'1101', '160'=>'1110');
  1305. $MPEGaudioBitrateLookup['2']['III'] = $MPEGaudioBitrateLookup['2']['II'];
  1306. $MPEGaudioBitrateLookup['2.5']['I'] = $MPEGaudioBitrateLookup['2']['I'];
  1307. $MPEGaudioBitrateLookup['2.5']['II'] = $MPEGaudioBitrateLookup['2']['II'];
  1308. $MPEGaudioBitrateLookup['2.5']['III'] = $MPEGaudioBitrateLookup['2']['II'];
  1309. if (isset($MPEGaudioBitrateLookup[$_POST['version']][$_POST['layer']][$_POST['bitrate']])) {
  1310. $headerbitstream .= $MPEGaudioBitrateLookup[$_POST['version']][$_POST['layer']][$_POST['bitrate']]; // E - Bitrate index
  1311. } else {
  1312. die('Invalid <B>Bitrate</B>');
  1313. }
  1314. $MPEGaudioFrequencyLookup['1'] = array('44100'=>'00', '48000'=>'01', '32000'=>'10');
  1315. $MPEGaudioFrequencyLookup['2'] = array('22050'=>'00', '24000'=>'01', '16000'=>'10');
  1316. $MPEGaudioFrequencyLookup['2.5'] = array('11025'=>'00', '12000'=>'01', '8000'=>'10');
  1317. if (isset($MPEGaudioFrequencyLookup[$_POST['version']][$_POST['frequency']])) {
  1318. $headerbitstream .= $MPEGaudioFrequencyLookup[$_POST['version']][$_POST['frequency']]; // F - Sampling rate frequency index
  1319. } else {
  1320. die('Invalid <B>Frequency</B>');
  1321. }
  1322. $headerbitstream .= (($_POST['padding'] == 'Y') ? '1' : '0'); // G - Padding bit
  1323. $headerbitstream .= (($_POST['private'] == 'Y') ? '1' : '0'); // H - Private bit
  1324. $MPEGaudioChannelModeLookup = array('stereo'=>'00', 'joint stereo'=>'01', 'dual channel'=>'10', 'mono'=>'11');
  1325. $headerbitstream .= $MPEGaudioChannelModeLookup[$_POST['channelmode']]; // I - Channel Mode
  1326. $MPEGaudioModeExtensionLookup['I'] = array('4-31'=>'00', '8-31'=>'01', '12-31'=>'10', '16-31'=>'11');
  1327. $MPEGaudioModeExtensionLookup['II'] = $MPEGaudioModeExtensionLookup['I'];
  1328. $MPEGaudioModeExtensionLookup['III'] = array('none'=>'00', 'IS'=>'01', 'MS'=>'10', 'IS+MS'=>'11');
  1329. if ($_POST['channelmode'] != 'joint stereo') {
  1330. $headerbitstream .= '00';
  1331. } elseif (isset($MPEGaudioModeExtensionLookup[$_POST['layer']][$_POST['modeextension']])) {
  1332. $headerbitstream .= $MPEGaudioModeExtensionLookup[$_POST['layer']][$_POST['modeextension']]; // J - Mode extension (Only if Joint stereo)
  1333. } else {
  1334. die('Invalid <B>Mode Extension</B>');
  1335. }
  1336. $headerbitstream .= (($_POST['copyright'] == 'Y') ? '1' : '0'); // K - Copyright
  1337. $headerbitstream .= (($_POST['original'] == 'Y') ? '1' : '0'); // L - Original
  1338. $MPEGaudioEmphasisLookup = array('none'=>'00', '50/15ms'=>'01', 'CCIT J.17'=>'11');
  1339. if (isset($MPEGaudioEmphasisLookup[$_POST['emphasis']])) {
  1340. $headerbitstream .= $MPEGaudioEmphasisLookup[$_POST['emphasis']]; // M - Emphasis
  1341. } else {
  1342. die('Invalid <B>Emphasis</B>');
  1343. }
  1344. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 0, 8))), 2, '0', STR_PAD_LEFT)).' ';
  1345. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 8, 8))), 2, '0', STR_PAD_LEFT)).' ';
  1346. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 16, 8))), 2, '0', STR_PAD_LEFT)).' ';
  1347. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 24, 8))), 2, '0', STR_PAD_LEFT)).'<BR>';
  1348. }
  1349. function MPEGaudioVersionLookup($rawversion) {
  1350. $MPEGaudioVersionLookup = array('2.5', FALSE, '2', '1');
  1351. return (isset($MPEGaudioVersionLookup["$rawversion"]) ? $MPEGaudioVersionLookup["$rawversion"] : FALSE);
  1352. }
  1353. function MPEGaudioLayerLookup($rawlayer) {
  1354. $MPEGaudioLayerLookup = array(FALSE, 'III', 'II', 'I');
  1355. return (isset($MPEGaudioLayerLookup["$rawlayer"]) ? $MPEGaudioLayerLookup["$rawlayer"] : FALSE);
  1356. }
  1357. function MPEGaudioBitrateLookup($version, $layer, $rawbitrate) {
  1358. static $MPEGaudioBitrateLookup;
  1359. if (empty($MPEGaudioBitrateLookup)) {
  1360. $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
  1361. }
  1362. return (isset($MPEGaudioBitrateLookup["$version"]["$layer"]["$rawbitrate"]) ? $MPEGaudioBitrateLookup["$version"]["$layer"]["$rawbitrate"] : FALSE);
  1363. }
  1364. function MPEGaudioFrequencyLookup($version, $rawfrequency) {
  1365. static $MPEGaudioFrequencyLookup;
  1366. if (empty($MPEGaudioFrequencyLookup)) {
  1367. $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
  1368. }
  1369. return (isset($MPEGaudioFrequencyLookup["$version"]["$rawfrequency"]) ? $MPEGaudioFrequencyLookup["$version"]["$rawfrequency"] : FALSE);
  1370. }
  1371. function MPEGaudioChannelModeLookup($rawchannelmode) {
  1372. $MPEGaudioChannelModeLookup = array('stereo', 'joint stereo', 'dual channel', 'mono');
  1373. return (isset($MPEGaudioChannelModeLookup["$rawchannelmode"]) ? $MPEGaudioChannelModeLookup["$rawchannelmode"] : FALSE);
  1374. }
  1375. function MPEGaudioModeExtensionLookup($layer, $rawmodeextension) {
  1376. $MPEGaudioModeExtensionLookup['I'] = array('4-31', '8-31', '12-31', '16-31');
  1377. $MPEGaudioModeExtensionLookup['II'] = array('4-31', '8-31', '12-31', '16-31');
  1378. $MPEGaudioModeExtensionLookup['III'] = array('', 'IS', 'MS', 'IS+MS');
  1379. return (isset($MPEGaudioModeExtensionLookup["$layer"]["$rawmodeextension"]) ? $MPEGaudioModeExtensionLookup["$layer"]["$rawmodeextension"] : FALSE);
  1380. }
  1381. function MPEGaudioEmphasisLookup($rawemphasis) {
  1382. $MPEGaudioEmphasisLookup = array('none', '50/15ms', FALSE, 'CCIT J.17');
  1383. return (isset($MPEGaudioEmphasisLookup["$rawemphasis"]) ? $MPEGaudioEmphasisLookup["$rawemphasis"] : FALSE);
  1384. }
  1385. function MPEGaudioCRCLookup($CRCbit) {
  1386. // inverse boolean cast :)
  1387. if ($CRCbit == '0') {
  1388. return TRUE;
  1389. } else {
  1390. return FALSE;
  1391. }
  1392. }
  1393. /////////////////////////////////////////////////////////////////
  1394. /// getID3() by James Heinrich <info@getid3.org> //
  1395. // available at http://getid3.sourceforge.net ///
  1396. // or http://www.getid3.org ///
  1397. /////////////////////////////////////////////////////////////////
  1398. // //
  1399. // getid3.mp3.php - part of getID3() //
  1400. // See getid3.readme.txt for more details //
  1401. // //
  1402. /////////////////////////////////////////////////////////////////
  1403. // number of frames to scan to determine if MPEG-audio sequence is valid
  1404. // Lower this number to 5-20 for faster scanning
  1405. // Increase this number to 50+ for most accurate detection of valid VBR/CBR
  1406. // mpeg-audio streams
  1407. define('MPEG_VALID_CHECK_FRAMES', 35);
  1408. function getMP3headerFilepointer(&$fd, &$ThisFileInfo) {
  1409. getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset']);
  1410. if (isset($ThisFileInfo['mpeg']['audio']['bitrate_mode'])) {
  1411. $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
  1412. }
  1413. if (((isset($ThisFileInfo['id3v2']) && ($ThisFileInfo['avdataoffset'] > $ThisFileInfo['id3v2']['headerlength'])) || (!isset($ThisFileInfo['id3v2']) && ($ThisFileInfo['avdataoffset'] > 0)))) {
  1414. $ThisFileInfo['warning'] .= "\n".'Unknown data before synch ';
  1415. if (isset($ThisFileInfo['id3v2']['headerlength'])) {
  1416. $ThisFileInfo['warning'] .= '(ID3v2 header ends at '.$ThisFileInfo['id3v2']['headerlength'].', then '.($ThisFileInfo['avdataoffset'] - $ThisFileInfo['id3v2']['headerlength']).' bytes garbage, ';
  1417. } else {
  1418. $ThisFileInfo['warning'] .= '(should be at beginning of file, ';
  1419. }
  1420. $ThisFileInfo['warning'] .= 'synch detected at '.$ThisFileInfo['avdataoffset'].')';
  1421. if ($ThisFileInfo['audio']['bitrate_mode'] == 'cbr') {
  1422. if (!empty($ThisFileInfo['id3v2']['headerlength']) && (($ThisFileInfo['avdataoffset'] - $ThisFileInfo['id3v2']['headerlength']) == $ThisFileInfo['mpeg']['audio']['framelength'])) {
  1423. $ThisFileInfo['warning'] .= '. This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
  1424. $ThisFileInfo['audio']['codec'] = 'LAME';
  1425. } elseif (empty($ThisFileInfo['id3v2']['headerlength']) && ($ThisFileInfo['avdataoffset'] == $ThisFileInfo['mpeg']['audio']['framelength'])) {
  1426. $ThisFileInfo['warning'] .= '. This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
  1427. $ThisFileInfo['audio']['codec'] = 'LAME';
  1428. }
  1429. }
  1430. }
  1431. if (isset($ThisFileInfo['mpeg']['audio']['layer']) && ($ThisFileInfo['mpeg']['audio']['layer'] == 'II')) {
  1432. $ThisFileInfo['audio']['dataformat'] = 'mp2';
  1433. } elseif (isset($ThisFileInfo['mpeg']['audio']['layer']) && ($ThisFileInfo['mpeg']['audio']['layer'] == 'I')) {
  1434. $ThisFileInfo['audio']['dataformat'] = 'mp1';
  1435. }
  1436. if ($ThisFileInfo['fileformat'] == 'mp3') {
  1437. switch ($ThisFileInfo['audio']['dataformat']) {
  1438. case 'mp1':
  1439. case 'mp2':
  1440. case 'mp3':
  1441. $ThisFileInfo['fileformat'] = $ThisFileInfo['audio']['dataformat'];
  1442. break;
  1443. default:
  1444. $ThisFileInfo['warning'] .= "\n".'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$ThisFileInfo['audio']['dataformat'].'"';
  1445. break;
  1446. }
  1447. }
  1448. if (empty($ThisFileInfo['fileformat'])) {
  1449. $ThisFileInfo['error'] .= "\n".'Synch not found';
  1450. unset($ThisFileInfo['fileformat']);
  1451. unset($ThisFileInfo['audio']['bitrate_mode']);
  1452. unset($ThisFileInfo['avdataoffset']);
  1453. unset($ThisFileInfo['avdataend']);
  1454. return false;
  1455. }
  1456. $ThisFileInfo['mime_type'] = 'audio/mpeg';
  1457. $ThisFileInfo['audio']['lossless'] = false;
  1458. // Calculate playtime
  1459. if (!isset($ThisFileInfo['playtime_seconds']) && isset($ThisFileInfo['audio']['bitrate']) && ($ThisFileInfo['audio']['bitrate'] > 0)) {
  1460. $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate'];
  1461. }
  1462. if (isset($ThisFileInfo['mpeg']['audio']['LAME'])) {
  1463. $ThisFileInfo['audio']['codec'] = 'LAME';
  1464. if (!empty($ThisFileInfo['mpeg']['audio']['LAME']['long_version'])) {
  1465. $ThisFileInfo['audio']['encoder'] = trim($ThisFileInfo['mpeg']['audio']['LAME']['long_version']);
  1466. }
  1467. }
  1468. return true;
  1469. }
  1470. function decodeMPEGaudioHeader($fd, $offset, &$ThisFileInfo, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
  1471. static $MPEGaudioVersionLookup;
  1472. static $MPEGaudioLayerLookup;
  1473. static $MPEGaudioBitrateLookup;
  1474. static $MPEGaudioFrequencyLookup;
  1475. static $MPEGaudioChannelModeLookup;
  1476. static $MPEGaudioModeExtensionLookup;
  1477. static $MPEGaudioEmphasisLookup;
  1478. if (empty($MPEGaudioVersionLookup)) {
  1479. $MPEGaudioVersionLookup = MPEGaudioVersionArray();
  1480. $MPEGaudioLayerLookup = MPEGaudioLayerArray();
  1481. $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
  1482. $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
  1483. $MPEGaudioChannelModeLookup = MPEGaudioChannelModeArray();
  1484. $MPEGaudioModeExtensionLookup = MPEGaudioModeExtensionArray();
  1485. $MPEGaudioEmphasisLookup = MPEGaudioEmphasisArray();
  1486. }
  1487. if ($offset >= $ThisFileInfo['avdataend']) {
  1488. $ThisFileInfo['error'] .= "\n".'end of file encounter looking for MPEG synch';
  1489. return false;
  1490. }
  1491. fseek($fd, $offset, SEEK_SET);
  1492. $headerstring = fread($fd, 1441); // worse-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
  1493. // MP3 audio frame structure:
  1494. // $aa $aa $aa $aa [$bb $bb] $cc...
  1495. // where $aa..$aa is the four-byte mpeg-audio header (below)
  1496. // $bb $bb is the optional 2-byte CRC
  1497. // and $cc... is the audio data
  1498. $head4 = substr($headerstring, 0, 4);
  1499. static $MPEGaudioHeaderDecodeCache = array();
  1500. if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
  1501. $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
  1502. } else {
  1503. $MPEGheaderRawArray = MPEGaudioHeaderDecode($head4);
  1504. $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
  1505. }
  1506. static $MPEGaudioHeaderValidCache = array();
  1507. // Not in cache
  1508. if (!isset($MPEGaudioHeaderValidCache[$head4])) {
  1509. $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGheaderRawArray);
  1510. }
  1511. if ($MPEGaudioHeaderValidCache[$head4]) {
  1512. $ThisFileInfo['mpeg']['audio']['raw'] = $MPEGheaderRawArray;
  1513. } else {
  1514. $ThisFileInfo['error'] .= "\n".'Invalid MPEG audio header at offset '.$offset;
  1515. return false;
  1516. }
  1517. if (!$FastMPEGheaderScan) {
  1518. $ThisFileInfo['mpeg']['audio']['version'] = $MPEGaudioVersionLookup[$ThisFileInfo['mpeg']['audio']['raw']['version']];
  1519. $ThisFileInfo['mpeg']['audio']['layer'] = $MPEGaudioLayerLookup[$ThisFileInfo['mpeg']['audio']['raw']['layer']];
  1520. $ThisFileInfo['mpeg']['audio']['channelmode'] = $MPEGaudioChannelModeLookup[$ThisFileInfo['mpeg']['audio']['raw']['channelmode']];
  1521. $ThisFileInfo['mpeg']['audio']['channels'] = (($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') ? 1 : 2);
  1522. $ThisFileInfo['mpeg']['audio']['sample_rate'] = $MPEGaudioFrequencyLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['raw']['sample_rate']];
  1523. $ThisFileInfo['mpeg']['audio']['protection'] = !$ThisFileInfo['mpeg']['audio']['raw']['protection'];
  1524. $ThisFileInfo['mpeg']['audio']['private'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['private'];
  1525. $ThisFileInfo['mpeg']['audio']['modeextension'] = $MPEGaudioModeExtensionLookup[$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['modeextension']];
  1526. $ThisFileInfo['mpeg']['audio']['copyright'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['copyright'];
  1527. $ThisFileInfo['mpeg']['audio']['original'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['original'];
  1528. $ThisFileInfo['mpeg']['audio']['emphasis'] = $MPEGaudioEmphasisLookup[$ThisFileInfo['mpeg']['audio']['raw']['emphasis']];
  1529. $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
  1530. $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
  1531. if ($ThisFileInfo['mpeg']['audio']['protection']) {
  1532. $ThisFileInfo['mpeg']['audio']['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
  1533. }
  1534. }
  1535. if ($ThisFileInfo['mpeg']['audio']['raw']['bitrate'] == 15) {
  1536. // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
  1537. $ThisFileInfo['warning'] .= "\n".'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
  1538. $ThisFileInfo['mpeg']['audio']['raw']['bitrate'] = 0;
  1539. }
  1540. $ThisFileInfo['mpeg']['audio']['padding'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['padding'];
  1541. $ThisFileInfo['mpeg']['audio']['bitrate'] = $MPEGaudioBitrateLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['bitrate']];
  1542. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') && ($offset == $ThisFileInfo['avdataoffset'])) {
  1543. // only skip multiple frame check if free-format bitstream found at beginning of file
  1544. // otherwise is quite possibly simply corrupted data
  1545. $recursivesearch = false;
  1546. }
  1547. // For Layer II there are some combinations of bitrate and mode which are not allowed.
  1548. if (!$FastMPEGheaderScan && ($ThisFileInfo['mpeg']['audio']['layer'] == 'II')) {
  1549. $ThisFileInfo['audio']['dataformat'] = 'mp2';
  1550. switch ($ThisFileInfo['mpeg']['audio']['channelmode']) {
  1551. case 'mono':
  1552. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') || ($ThisFileInfo['mpeg']['audio']['bitrate'] <= 192)) {
  1553. // these are ok
  1554. } else {
  1555. $ThisFileInfo['error'] .= "\n".$ThisFileInfo['mpeg']['audio']['bitrate'].'kbps not allowed in Layer II, '.$ThisFileInfo['mpeg']['audio']['channelmode'].'.';
  1556. return false;
  1557. }
  1558. break;
  1559. case 'stereo':
  1560. case 'joint stereo':
  1561. case 'dual channel':
  1562. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') || ($ThisFileInfo['mpeg']['audio']['bitrate'] == 64) || ($ThisFileInfo['mpeg']['audio']['bitrate'] >= 96)) {
  1563. // these are ok
  1564. } else {
  1565. $ThisFileInfo['error'] .= "\n".$ThisFileInfo['mpeg']['audio']['bitrate'].'kbps not allowed in Layer II, '.$ThisFileInfo['mpeg']['audio']['channelmode'].'.';
  1566. return false;
  1567. }
  1568. break;
  1569. }
  1570. }
  1571. if (