PageRenderTime 62ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/osflvplayer/flash/write.id3v2.php

https://bitbucket.org/chamilo/chamilo-dev/
PHP | 1111 lines | 844 code | 79 blank | 188 comment | 154 complexity | 8e5b315522ac2a979e6acaa5c1340dc5 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. /// //
  10. // write.id3v2.php //
  11. // module for writing ID3v2 tags //
  12. // dependencies: module.tag.id3v2.php //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. getid3_lib :: IncludeDependency(GETID3_INCLUDEPATH . 'module.tag.id3v2.php', __FILE__, true);
  16. class getid3_write_id3v2
  17. {
  18. var $filename;
  19. var $tag_data;
  20. var $paddedlength = 4096; // minimum length of ID3v2 tag in bytes
  21. var $majorversion = 3; // ID3v2 major version (2, 3 (recommended), 4)
  22. var $minorversion = 0; // ID3v2 minor version - always 0
  23. var $merge_existing_data = false; // if true, merge new data with existing tags; if false, delete old tag data and only write new tags
  24. var $id3v2_default_encodingid = 0; // default text encoding (ISO-8859-1) if not explicitly passed
  25. var $id3v2_use_unsynchronisation = false; // the specs say it should be TRUE, but most other ID3v2-aware programs are broken if unsynchronization is used, so by default don't use it.
  26. var $warnings = array(); // any non-critical errors will be stored here
  27. var $errors = array(); // any critical errors will be stored here
  28. function getid3_write_id3v2()
  29. {
  30. return true;
  31. }
  32. function WriteID3v2()
  33. {
  34. // File MUST be writeable - CHMOD(646) at least. It's best if the
  35. // directory is also writeable, because that method is both faster and less susceptible to errors.
  36. if (is_writeable($this->filename) || (! file_exists($this->filename) && is_writeable(dirname($this->filename))))
  37. {
  38. // Initialize getID3 engine
  39. $getID3 = new getID3();
  40. $OldThisFileInfo = $getID3->analyze($this->filename);
  41. if ($this->merge_existing_data)
  42. {
  43. // merge with existing data
  44. if (! empty($OldThisFileInfo['id3v2']))
  45. {
  46. $this->tag_data = $this->array_join_merge($OldThisFileInfo['id3v2'], $this->tag_data);
  47. }
  48. }
  49. $this->paddedlength = max(@$OldThisFileInfo['id3v2']['headerlength'], $this->paddedlength);
  50. if ($NewID3v2Tag = $this->GenerateID3v2Tag())
  51. {
  52. if (file_exists($this->filename) && is_writeable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag)))
  53. {
  54. // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary)
  55. if (file_exists($this->filename))
  56. {
  57. ob_start();
  58. if ($fp = fopen($this->filename, 'r+b'))
  59. {
  60. rewind($fp);
  61. fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag));
  62. fclose($fp);
  63. }
  64. else
  65. {
  66. $this->errors[] = 'Could not open ' . $this->filename . ' mode "r+b" - ' . strip_tags(ob_get_contents());
  67. }
  68. ob_end_clean();
  69. }
  70. else
  71. {
  72. ob_start();
  73. if ($fp = fopen($this->filename, 'wb'))
  74. {
  75. rewind($fp);
  76. fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag));
  77. fclose($fp);
  78. }
  79. else
  80. {
  81. $this->errors[] = 'Could not open ' . $this->filename . ' mode "wb" - ' . strip_tags(ob_get_contents());
  82. }
  83. ob_end_clean();
  84. }
  85. }
  86. else
  87. {
  88. if ($tempfilename = tempnam('*', 'getID3'))
  89. {
  90. ob_start();
  91. if ($fp_source = fopen($this->filename, 'rb'))
  92. {
  93. if ($fp_temp = fopen($tempfilename, 'wb'))
  94. {
  95. fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag));
  96. rewind($fp_source);
  97. if (! empty($OldThisFileInfo['avdataoffset']))
  98. {
  99. fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET);
  100. }
  101. while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE))
  102. {
  103. fwrite($fp_temp, $buffer, strlen($buffer));
  104. }
  105. fclose($fp_temp);
  106. fclose($fp_source);
  107. copy($tempfilename, $this->filename);
  108. unlink($tempfilename);
  109. ob_end_clean();
  110. return true;
  111. }
  112. else
  113. {
  114. $this->errors[] = 'Could not open ' . $tempfilename . ' mode "wb" - ' . strip_tags(ob_get_contents());
  115. }
  116. fclose($fp_source);
  117. }
  118. else
  119. {
  120. $this->errors[] = 'Could not open ' . $this->filename . ' mode "rb" - ' . strip_tags(ob_get_contents());
  121. }
  122. ob_end_clean();
  123. }
  124. return false;
  125. }
  126. }
  127. else
  128. {
  129. $this->errors[] = '$this->GenerateID3v2Tag() failed';
  130. }
  131. if (! empty($this->errors))
  132. {
  133. return false;
  134. }
  135. return true;
  136. }
  137. else
  138. {
  139. $this->errors[] = '!is_writeable(' . $this->filename . ')';
  140. }
  141. return false;
  142. }
  143. function RemoveID3v2()
  144. {
  145. // File MUST be writeable - CHMOD(646) at least. It's best if the
  146. // directory is also writeable, because that method is both faster and less susceptible to errors.
  147. if (is_writeable(dirname($this->filename)))
  148. {
  149. // preferred method - only one copying operation, minimal chance of corrupting
  150. // original file if script is interrupted, but required directory to be writeable
  151. if ($fp_source = @fopen($this->filename, 'rb'))
  152. {
  153. // Initialize getID3 engine
  154. $getID3 = new getID3();
  155. $OldThisFileInfo = $getID3->analyze($this->filename);
  156. rewind($fp_source);
  157. if ($OldThisFileInfo['avdataoffset'] !== false)
  158. {
  159. fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET);
  160. }
  161. if ($fp_temp = @fopen($this->filename . 'getid3tmp', 'w+b'))
  162. {
  163. while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE))
  164. {
  165. fwrite($fp_temp, $buffer, strlen($buffer));
  166. }
  167. fclose($fp_temp);
  168. }
  169. else
  170. {
  171. $this->errors[] = 'Could not open ' . $this->filename . 'getid3tmp mode "w+b"';
  172. }
  173. fclose($fp_source);
  174. }
  175. else
  176. {
  177. $this->errors[] = 'Could not open ' . $this->filename . ' mode "rb"';
  178. }
  179. if (file_exists($this->filename))
  180. {
  181. unlink($this->filename);
  182. }
  183. rename($this->filename . 'getid3tmp', $this->filename);
  184. }
  185. elseif (is_writable($this->filename))
  186. {
  187. // less desirable alternate method - double-copies the file, overwrites original file
  188. // and could corrupt source file if the script is interrupted or an error occurs.
  189. if ($fp_source = @fopen($this->filename, 'rb'))
  190. {
  191. // Initialize getID3 engine
  192. $getID3 = new getID3();
  193. $OldThisFileInfo = $getID3->analyze($this->filename);
  194. rewind($fp_source);
  195. if ($OldThisFileInfo['avdataoffset'] !== false)
  196. {
  197. fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET);
  198. }
  199. if ($fp_temp = tmpfile())
  200. {
  201. while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE))
  202. {
  203. fwrite($fp_temp, $buffer, strlen($buffer));
  204. }
  205. fclose($fp_source);
  206. if ($fp_source = @fopen($this->filename, 'wb'))
  207. {
  208. rewind($fp_temp);
  209. while ($buffer = fread($fp_temp, GETID3_FREAD_BUFFER_SIZE))
  210. {
  211. fwrite($fp_source, $buffer, strlen($buffer));
  212. }
  213. fseek($fp_temp, - 128, SEEK_END);
  214. fclose($fp_source);
  215. }
  216. else
  217. {
  218. $this->errors[] = 'Could not open ' . $this->filename . ' mode "wb"';
  219. }
  220. fclose($fp_temp);
  221. }
  222. else
  223. {
  224. $this->errors[] = 'Could not create tmpfile()';
  225. }
  226. }
  227. else
  228. {
  229. $this->errors[] = 'Could not open ' . $this->filename . ' mode "rb"';
  230. }
  231. }
  232. else
  233. {
  234. $this->errors[] = 'Directory and file both not writeable';
  235. }
  236. if (! empty($this->errors))
  237. {
  238. return false;
  239. }
  240. return true;
  241. }
  242. function GenerateID3v2TagFlags($flags)
  243. {
  244. switch ($this->majorversion)
  245. {
  246. case 4 :
  247. // %abcd0000
  248. $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
  249. $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header
  250. $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator
  251. $flag .= (@$flags['footer'] ? '1' : '0'); // d - Footer present
  252. $flag .= '0000';
  253. break;
  254. case 3 :
  255. // %abc00000
  256. $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
  257. $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header
  258. $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator
  259. $flag .= '00000';
  260. break;
  261. case 2 :
  262. // %ab000000
  263. $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
  264. $flag .= (@$flags['compression'] ? '1' : '0'); // b - Compression
  265. $flag .= '000000';
  266. break;
  267. default :
  268. return false;
  269. break;
  270. }
  271. return chr(bindec($flag));
  272. }
  273. function GenerateID3v2FrameFlags($TagAlter = false, $FileAlter = false, $ReadOnly = false, $Compression = false, $Encryption = false, $GroupingIdentity = false, $Unsynchronisation = false, $DataLengthIndicator = false)
  274. {
  275. switch ($this->majorversion)
  276. {
  277. case 4 :
  278. // %0abc0000 %0h00kmnp
  279. $flag1 = '0';
  280. $flag1 .= $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard)
  281. $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard)
  282. $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only)
  283. $flag1 .= '0000';
  284. $flag2 = '0';
  285. $flag2 .= $GroupingIdentity ? '1' : '0'; // h - Grouping identity (true == contains group information)
  286. $flag2 .= '00';
  287. $flag2 .= $Compression ? '1' : '0'; // k - Compression (true == compressed)
  288. $flag2 .= $Encryption ? '1' : '0'; // m - Encryption (true == encrypted)
  289. $flag2 .= $Unsynchronisation ? '1' : '0'; // n - Unsynchronisation (true == unsynchronised)
  290. $flag2 .= $DataLengthIndicator ? '1' : '0'; // p - Data length indicator (true == data length indicator added)
  291. break;
  292. case 3 :
  293. // %abc00000 %ijk00000
  294. $flag1 = $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard)
  295. $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard)
  296. $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only)
  297. $flag1 .= '00000';
  298. $flag2 = $Compression ? '1' : '0'; // i - Compression (true == compressed)
  299. $flag2 .= $Encryption ? '1' : '0'; // j - Encryption (true == encrypted)
  300. $flag2 .= $GroupingIdentity ? '1' : '0'; // k - Grouping identity (true == contains group information)
  301. $flag2 .= '00000';
  302. break;
  303. default :
  304. return false;
  305. break;
  306. }
  307. return chr(bindec($flag1)) . chr(bindec($flag2));
  308. }
  309. function GenerateID3v2FrameData($frame_name, $source_data_array)
  310. {
  311. if (! getid3_id3v2 :: IsValidID3v2FrameName($frame_name, $this->majorversion))
  312. {
  313. return false;
  314. }
  315. $framedata = '';
  316. if (($this->majorversion < 3) || ($this->majorversion > 4))
  317. {
  318. $this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()';
  319. }
  320. else
  321. { // $this->majorversion 3 or 4
  322. switch ($frame_name)
  323. {
  324. case 'UFID' :
  325. // 4.1 UFID Unique file identifier
  326. // Owner identifier <text string> $00
  327. // Identifier <up to 64 bytes binary data>
  328. if (strlen($source_data_array['data']) > 64)
  329. {
  330. $this->errors[] = 'Identifier not allowed to be longer than 64 bytes in ' . $frame_name . ' (supplied data was ' . strlen($source_data_array['data']) . ' bytes long)';
  331. }
  332. else
  333. {
  334. $framedata .= str_replace("\x00", '', $source_data_array['ownerid']) . "\x00";
  335. $framedata .= substr($source_data_array['data'], 0, 64); // max 64 bytes - truncate anything longer
  336. }
  337. break;
  338. case 'TXXX' :
  339. // 4.2.2 TXXX User defined text information frame
  340. // Text encoding $xx
  341. // Description <text string according to encoding> $00 (00)
  342. // Value <text string according to encoding>
  343. $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
  344. if (! $this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion))
  345. {
  346. $this->errors[] = 'Invalid Text Encoding in ' . $frame_name . ' (' . $source_data_array['encodingid'] . ') for ID3v2.' . $this->majorversion;
  347. }
  348. else
  349. {
  350. $framedata .= chr($source_data_array['encodingid']);
  351. $framedata .= $source_data_array['description'] . getid3_id3v2 :: TextEncodingTerminatorLookup($source_data_array['encodingid']);
  352. $framedata .= $source_data_array['data'];
  353. }
  354. break;
  355. case 'WXXX' :
  356. // 4.3.2 WXXX User defined URL link frame
  357. // Text encoding $xx
  358. // Description <text string according to encoding> $00 (00)
  359. // URL <text string>
  360. $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
  361. if (! $this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion))
  362. {
  363. $this->errors[] = 'Invalid Text Encoding in ' . $frame_name . ' (' . $source_data_array['encodingid'] . ') for ID3v2.' . $this->majorversion;
  364. }
  365. elseif (! isset($source_data_array['data']) || ! $this->IsValidURL($source_data_array['data'], false, false))
  366. {
  367. //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
  368. // probably should be an error, need to rewrite IsValidURL() to handle other encodings
  369. $this->warnings[] = 'Invalid URL in ' . $frame_name . ' (' . $source_data_array['data'] . ')';
  370. }
  371. else
  372. {
  373. $framedata .= chr($source_data_array['encodingid']);
  374. $framedata .= $source_data_array['description'] . getid3_id3v2 :: TextEncodingTerminatorLookup($source_data_array['encodingid']);
  375. $framedata .= $source_data_array['data'];
  376. }
  377. break;
  378. case 'IPLS' :
  379. // 4.4 IPLS Involved people list (ID3v2.3 only)
  380. // Text encoding $xx
  381. // People list strings <textstrings>
  382. $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
  383. if (! $this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion))
  384. {
  385. $this->errors[] = 'Invalid Text Encoding in ' . $frame_name . ' (' . $source_data_array['encodingid'] . ') for ID3v2.' . $this->majorversion;
  386. }
  387. else
  388. {
  389. $framedata .= chr($source_data_array['encodingid']);
  390. $framedata .= $source_data_array['data'];
  391. }
  392. break;
  393. case 'MCDI' :
  394. // 4.4 MCDI Music CD identifier
  395. // CD TOC <binary data>
  396. $framedata .= $source_data_array['data'];
  397. break;
  398. case 'ETCO' :
  399. // 4.5 ETCO Event timing codes
  400. // Time stamp format $xx
  401. // Where time stamp format is:
  402. // $01 (32-bit value) MPEG frames from beginning of file
  403. // $02 (32-bit value) milliseconds from beginning of file
  404. // Followed by a list of key events in the following format:
  405. // Type of event $xx
  406. // Time stamp $xx (xx ...)
  407. // The 'Time stamp' is set to zero if directly at the beginning of the sound
  408. // or after the previous event. All events MUST be sorted in chronological order.
  409. if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1))
  410. {
  411. $this->errors[] = 'Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ')';
  412. }
  413. else
  414. {
  415. $framedata .= chr($source_data_array['timestampformat']);
  416. foreach ($source_data_array as $key => $val)
  417. {
  418. if (! $this->ID3v2IsValidETCOevent($val['typeid']))
  419. {
  420. $this->errors[] = 'Invalid Event Type byte in ' . $frame_name . ' (' . $val['typeid'] . ')';
  421. }
  422. elseif (($key != 'timestampformat') && ($key != 'flags'))
  423. {
  424. if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp']))
  425. {
  426. // The 'Time stamp' is set to zero if directly at the beginning of the sound
  427. // or after the previous event. All events MUST be sorted in chronological order.
  428. $this->errors[] = 'Out-of-order timestamp in ' . $frame_name . ' (' . $val['timestamp'] . ') for Event Type (' . $val['typeid'] . ')';
  429. }
  430. else
  431. {
  432. $framedata .= chr($val['typeid']);
  433. $framedata .= getid3_lib :: BigEndian2String($val['timestamp'], 4, false);
  434. }
  435. }
  436. }
  437. }
  438. break;
  439. case 'MLLT' :
  440. // 4.6 MLLT MPEG location lookup table
  441. // MPEG frames between reference $xx xx
  442. // Bytes between reference $xx xx xx
  443. // Milliseconds between reference $xx xx xx
  444. // Bits for bytes deviation $xx
  445. // Bits for milliseconds dev. $xx
  446. // Then for every reference the following data is included;
  447. // Deviation in bytes %xxx....
  448. // Deviation in milliseconds %xxx....
  449. if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535))
  450. {
  451. $framedata .= getid3_lib :: BigEndian2String($source_data_array['framesbetweenreferences'], 2, false);
  452. }
  453. else
  454. {
  455. $this->errors[] = 'Invalid MPEG Frames Between References in ' . $frame_name . ' (' . $source_data_array['framesbetweenreferences'] . ')';
  456. }
  457. if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215))
  458. {
  459. $framedata .= getid3_lib :: BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false);
  460. }
  461. else
  462. {
  463. $this->errors[] = 'Invalid bytes Between References in ' . $frame_name . ' (' . $source_data_array['bytesbetweenreferences'] . ')';
  464. }
  465. if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215))
  466. {
  467. $framedata .= getid3_lib :: BigEndian2String($source_data_array['msbetweenreferences'], 3, false);
  468. }
  469. else
  470. {
  471. $this->errors[] = 'Invalid Milliseconds Between References in ' . $frame_name . ' (' . $source_data_array['msbetweenreferences'] . ')';
  472. }
  473. if (! $this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false))
  474. {
  475. if (($source_data_array['bitsforbytesdeviation'] % 4) == 0)
  476. {
  477. $framedata .= chr($source_data_array['bitsforbytesdeviation']);
  478. }
  479. else
  480. {
  481. $this->errors[] = 'Bits For Bytes Deviation in ' . $frame_name . ' (' . $source_data_array['bitsforbytesdeviation'] . ') must be a multiple of 4.';
  482. }
  483. }
  484. else
  485. {
  486. $this->errors[] = 'Invalid Bits For Bytes Deviation in ' . $frame_name . ' (' . $source_data_array['bitsforbytesdeviation'] . ')';
  487. }
  488. if (! $this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false))
  489. {
  490. if (($source_data_array['bitsformsdeviation'] % 4) == 0)
  491. {
  492. $framedata .= chr($source_data_array['bitsformsdeviation']);
  493. }
  494. else
  495. {
  496. $this->errors[] = 'Bits For Milliseconds Deviation in ' . $frame_name . ' (' . $source_data_array['bitsforbytesdeviation'] . ') must be a multiple of 4.';
  497. }
  498. }
  499. else
  500. {
  501. $this->errors[] = 'Invalid Bits For Milliseconds Deviation in ' . $frame_name . ' (' . $source_data_array['bitsformsdeviation'] . ')';
  502. }
  503. foreach ($source_data_array as $key => $val)
  504. {
  505. if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags'))
  506. {
  507. $unwrittenbitstream .= str_pad(getid3_lib :: Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT);
  508. $unwrittenbitstream .= str_pad(getid3_lib :: Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT);
  509. }
  510. }
  511. for($i = 0; $i < strlen($unwrittenbitstream); $i += 8)
  512. {
  513. $highnibble = bindec(substr($unwrittenbitstream, $i, 4)) << 4;
  514. $lownibble = bindec(substr($unwrittenbitstream, $i + 4, 4));
  515. $framedata .= chr($highnibble & $lownibble);
  516. }
  517. break;
  518. case 'SYTC' :
  519. // 4.7 SYTC Synchronised tempo codes
  520. // Time stamp format $xx
  521. // Tempo data <binary data>
  522. // Where time stamp format is:
  523. // $01 (32-bit value) MPEG frames from beginning of file
  524. // $02 (32-bit value) milliseconds from beginning of file
  525. if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1))
  526. {
  527. $this->errors[] = 'Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ')';
  528. }
  529. else
  530. {
  531. $framedata .= chr($source_data_array['timestampformat']);
  532. foreach ($source_data_array as $key => $val)
  533. {
  534. if (! $this->ID3v2IsValidETCOevent($val['typeid']))
  535. {
  536. $this->errors[] = 'Invalid Event Type byte in ' . $frame_name . ' (' . $val['typeid'] . ')';
  537. }
  538. elseif (($key != 'timestampformat') && ($key != 'flags'))
  539. {
  540. if (($val['tempo'] < 0) || ($val['tempo'] > 510))
  541. {
  542. $this->errors[] = 'Invalid Tempo (max = 510) in ' . $frame_name . ' (' . $val['tempo'] . ') at timestamp (' . $val['timestamp'] . ')';
  543. }
  544. else
  545. {
  546. if ($val['tempo'] > 255)
  547. {
  548. $framedata .= chr(255);
  549. $val['tempo'] -= 255;
  550. }
  551. $framedata .= chr($val['tempo']);
  552. $framedata .= getid3_lib :: BigEndian2String($val['timestamp'], 4, false);
  553. }
  554. }
  555. }
  556. }
  557. break;
  558. case 'USLT' :
  559. // 4.8 USLT Unsynchronised lyric/text transcription
  560. // Text encoding $xx
  561. // Language $xx xx xx
  562. // Content descriptor <text string according to encoding> $00 (00)
  563. // Lyrics/text <full text string according to encoding>
  564. $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
  565. if (! $this->ID3v2IsValidTextEncoding($source_data_array['encodingid']))
  566. {
  567. $this->errors[] = 'Invalid Text Encoding in ' . $frame_name . ' (' . $source_data_array['encodingid'] . ') for ID3v2.' . $this->majorversion;
  568. }
  569. elseif (getid3_id3v2 :: LanguageLookup($source_data_array['language'], true) == '')
  570. {
  571. $this->errors[] = 'Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')';
  572. }
  573. else
  574. {
  575. $framedata .= chr($source_data_array['encodingid']);
  576. $framedata .= strtolower($source_data_array['language']);
  577. $framedata .= $source_data_array['description'] . getid3_id3v2 :: TextEncodingTerminatorLookup($source_data_array['encodingid']);
  578. $framedata .= $source_data_array['data'];
  579. }
  580. break;
  581. case 'SYLT' :
  582. // 4.9 SYLT Synchronised lyric/text
  583. // Text encoding $xx
  584. // Language $xx xx xx
  585. // Time stamp format $xx
  586. // $01 (32-bit value) MPEG frames from beginning of file
  587. // $02 (32-bit value) milliseconds from beginning of file
  588. // Content type $xx
  589. // Content descriptor <text string according to encoding> $00 (00)
  590. // Terminated text to be synced (typically a syllable)
  591. // Sync identifier (terminator to above string) $00 (00)
  592. // Time stamp $xx (xx ...)
  593. $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
  594. if (! $this->ID3v2IsValidTextEncoding($source_data_array['encodingid']))
  595. {
  596. $this->errors[] = 'Invalid Text Encoding in ' . $frame_name . ' (' . $source_data_array['encodingid'] . ') for ID3v2.' . $this->majorversion;
  597. }
  598. elseif (getid3_id3v2 :: LanguageLookup($source_data_array['language'], true) == '')
  599. {
  600. $this->errors[] = 'Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')';
  601. }
  602. elseif (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1))
  603. {
  604. $this->errors[] = 'Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ')';
  605. }
  606. elseif (! $this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid']))
  607. {
  608. $this->errors[] = 'Invalid Content Type byte in ' . $frame_name . ' (' . $source_data_array['contenttypeid'] . ')';
  609. }
  610. elseif (! is_array($source_data_array['data']))
  611. {
  612. $this->errors[] = 'Invalid Lyric/Timestamp data in ' . $frame_name . ' (must be an array)';
  613. }
  614. else
  615. {
  616. $framedata .= chr($source_data_array['encodingid']);
  617. $framedata .= strtolower($source_data_array['language']);
  618. $framedata .= chr($source_data_array['timestampformat']);
  619. $framedata .= chr($source_data_array['contenttypeid']);
  620. $framedata .= $source_data_array['description'] . getid3_id3v2 :: TextEncodingTerminatorLookup($source_data_array['encodingid']);
  621. ksort($source_data_array['data']);
  622. foreach ($source_data_array['data'] as $key => $val)
  623. {
  624. $framedata .= $val['data'] . getid3_id3v2 :: TextEncodingTerminatorLookup($source_data_array['encodingid']);
  625. $framedata .= getid3_lib :: BigEndian2String($val['timestamp'], 4, false);
  626. }
  627. }
  628. break;
  629. case 'COMM' :
  630. // 4.10 COMM Comments
  631. // Text encoding $xx
  632. // Language $xx xx xx
  633. // Short content descrip. <text string according to encoding> $00 (00)
  634. // The actual text <full text string according to encoding>
  635. $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
  636. if (! $this->ID3v2IsValidTextEncoding($source_data_array['encodingid']))
  637. {
  638. $this->errors[] = 'Invalid Text Encoding in ' . $frame_name . ' (' . $source_data_array['encodingid'] . ') for ID3v2.' . $this->majorversion;
  639. }
  640. elseif (getid3_id3v2 :: LanguageLookup($source_data_array['language'], true) == '')
  641. {
  642. $this->errors[] = 'Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')';
  643. }
  644. else
  645. {
  646. $framedata .= chr($source_data_array['encodingid']);
  647. $framedata .= strtolower($source_data_array['language']);
  648. $framedata .= $source_data_array['description'] . getid3_id3v2 :: TextEncodingTerminatorLookup($source_data_array['encodingid']);
  649. $framedata .= $source_data_array['data'];
  650. }
  651. break;
  652. case 'RVA2' :
  653. // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
  654. // Identification <text string> $00
  655. // The 'identification' string is used to identify the situation and/or
  656. // device where this adjustment should apply. The following is then
  657. // repeated for every channel:
  658. // Type of channel $xx
  659. // Volume adjustment $xx xx
  660. // Bits representing peak $xx
  661. // Peak volume $xx (xx ...)
  662. $framedata .= str_replace("\x00", '', $source_data_array['description']) . "\x00";
  663. foreach ($source_data_array as $key => $val)
  664. {
  665. if ($key != 'description')
  666. {
  667. $framedata .= chr($val['channeltypeid']);
  668. $framedata .= getid3_lib :: BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit
  669. if (! $this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false))
  670. {
  671. $framedata .= chr($val['bitspeakvolume']);
  672. if ($val['bitspeakvolume'] > 0)
  673. {
  674. $framedata .= getid3_lib :: BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false);
  675. }
  676. }
  677. else
  678. {
  679. $this->errors[] = 'Invalid Bits Representing Peak Volume in ' . $frame_name . ' (' . $val['bitspeakvolume'] . ') (range = 0 to 255)';
  680. }
  681. }
  682. }
  683. break;
  684. case 'RVAD' :
  685. // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
  686. // Increment/decrement %00fedcba
  687. // Bits used for volume descr. $xx
  688. // Relative volume change, right $xx xx (xx ...) // a
  689. // Relative volume change, left $xx xx (xx ...) // b
  690. // Peak volume right $xx xx (xx ...)
  691. // Peak volume left $xx xx (xx ...)
  692. // Relative volume change, right back $xx xx (xx ...) // c
  693. // Relative volume change, left back $xx xx (xx ...) // d
  694. // Peak volume right back $xx xx (xx ...)
  695. // Peak volume left back $xx xx (xx ...)
  696. // Relative volume change, center $xx xx (xx ...) // e
  697. // Peak volume center $xx xx (xx ...)
  698. // Relative volume change, bass $xx xx (xx ...) // f
  699. // Peak volume bass $xx xx (xx ...)
  700. if (! $this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false))
  701. {
  702. $this->errors[] = 'Invalid Bits For Volume Description byte in ' . $frame_name . ' (' . $source_data_array['bitsvolume'] . ') (range = 1 to 255)';
  703. }
  704. else
  705. {
  706. $incdecflag .= '00';
  707. $incdecflag .= $source_data_array['incdec']['right'] ? '1' : '0'; // a - Relative volume change, right
  708. $incdecflag .= $source_data_array['incdec']['left'] ? '1' : '0'; // b - Relative volume change, left
  709. $incdecflag .= $source_data_array['incdec']['rightrear'] ? '1' : '0'; // c - Relative volume change, right back
  710. $incdecflag .= $source_data_array['incdec']['leftrear'] ? '1' : '0'; // d - Relative volume change, left back
  711. $incdecflag .= $source_data_array['incdec']['center'] ? '1' : '0'; // e - Relative volume change, center
  712. $incdecflag .= $source_data_array['incdec']['bass'] ? '1' : '0'; // f - Relative volume change, bass
  713. $framedata .= chr(bindec($incdecflag));
  714. $framedata .= chr($source_data_array['bitsvolume']);
  715. $framedata .= getid3_lib :: BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
  716. $framedata .= getid3_lib :: BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
  717. $framedata .= getid3_lib :: BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
  718. $framedata .= getid3_lib :: BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
  719. if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] || $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] || $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass'])
  720. {
  721. $framedata .= getid3_lib :: BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume'] / 8), false);
  722. $framedata .= getid3_lib :: BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume'] / 8), false);
  723. $framedata .= getid3_lib :: BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume'] / 8), false);
  724. $framedata .= getid3_lib :: BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume'] / 8), false);
  725. }
  726. if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass'])
  727. {
  728. $framedata .= getid3_lib :: BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume'] / 8), false);
  729. $framedata .= getid3_lib :: BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume'] / 8), false);
  730. }
  731. if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass'])
  732. {
  733. $framedata .= getid3_lib :: BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume'] / 8), false);
  734. $framedata .= getid3_lib :: BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume'] / 8), false);
  735. }
  736. }
  737. break;
  738. case 'EQU2' :
  739. // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
  740. // Interpolation method $xx
  741. // $00 Band
  742. // $01 Linear
  743. // Identification <text string> $00
  744. // The following is then repeated for every adjustment point
  745. // Frequency $xx xx
  746. // Volume adjustment $xx xx
  747. if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1))
  748. {
  749. $this->errors[] = 'Invalid Interpolation Method byte in ' . $frame_name . ' (' . $source_data_array['interpolationmethod'] . ') (valid = 0 or 1)';
  750. }
  751. else
  752. {
  753. $framedata .= chr($source_data_array['interpolationmethod']);
  754. $framedata .= str_replace("\x00", '', $source_data_array['description']) . "\x00";
  755. foreach ($source_data_array['data'] as $key => $val)
  756. {
  757. $framedata .= getid3_lib :: BigEndian2String(intval(round($key * 2)), 2, false);
  758. $framedata .= getid3_lib :: BigEndian2String($val, 2, false, true); // signed 16-bit
  759. }
  760. }
  761. break;
  762. case 'EQUA' :
  763. // 4.12 EQUA Equalisation (ID3v2.3 only)
  764. // Adjustment bits $xx
  765. // This is followed by 2 bytes + ('adjustment bits' rounded up to the
  766. // nearest byte) for every equalisation band in the following format,
  767. // giving a frequency range of 0 - 32767Hz:
  768. // Increment/decrement %x (MSB of the Frequency)
  769. // Frequency (lower 15 bits)
  770. // Adjustment $xx (xx ...)
  771. if (! $this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false))
  772. {
  773. $this->errors[] = 'Invalid Adjustment Bits byte in ' . $frame_name . ' (' . $source_data_array['bitsvolume'] . ') (range = 1 to 255)';
  774. }
  775. else
  776. {
  777. $framedata .= chr($source_data_array['adjustmentbits']);
  778. foreach ($source_data_array as $key => $val)
  779. {
  780. if ($key != 'bitsvolume')
  781. {
  782. if (($key > 32767) || ($key < 0))
  783. {
  784. $this->errors[] = 'Invalid Frequency in ' . $frame_name . ' (' . $key . ') (range = 0 to 32767)';
  785. }
  786. else
  787. {
  788. if ($val >= 0)
  789. {
  790. // put MSB of frequency to 1 if increment, 0 if decrement
  791. $key |= 0x8000;
  792. }
  793. $framedata .= getid3_lib :: BigEndian2String($key, 2, false);
  794. $framedata .= getid3_lib :: BigEndian2String($val, ceil($source_data_array['adjustmentbits'] / 8), false);
  795. }
  796. }
  797. }
  798. }
  799. break;
  800. case 'RVRB' :
  801. // 4.13 RVRB Reverb
  802. // Reverb left (ms) $xx xx
  803. // Reverb right (ms) $xx xx
  804. // Reverb bounces, left $xx
  805. // Reverb bounces, right $xx
  806. // Reverb feedback, left to left $xx
  807. // Reverb feedback, left to right $xx
  808. // Reverb feedback, right to right $xx
  809. // Reverb feedback, right to left $xx
  810. // Premix left to right $xx
  811. // Premix right to left $xx
  812. if (! $this->IsWithinBitRange($source_data_array['left'], 16, false))
  813. {
  814. $this->errors[] = 'Invalid Reverb Left in ' . $frame_name . ' (' . $source_data_array['left'] . ') (range = 0 to 65535)';
  815. }
  816. elseif (! $this->IsWithinBitRange($source_da

Large files files are truncated, but you can click here to view the full file