PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/podpress/getid3/write.real.php

https://github.com/AJenbo/ubuntudanmark.dk
PHP | 303 lines | 232 code | 49 blank | 22 comment | 47 complexity | 1ba26a1c4f12eb9195c84e847927725d MD5 | raw 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.real.php //
  11. // module for writing RealAudio/RealVideo tags //
  12. // dependencies: module.tag.real.php //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. class getid3_write_real
  16. {
  17. var $filename;
  18. var $tag_data = array();
  19. var $warnings = array(); // any non-critical errors will be stored here
  20. var $errors = array(); // any critical errors will be stored here
  21. var $paddedlength = 512; // minimum length of CONT tag in bytes
  22. function getid3_write_real() {
  23. return true;
  24. }
  25. function WriteReal() {
  26. // File MUST be writeable - CHMOD(646) at least
  27. if (is_writeable($this->filename)) {
  28. ob_start();
  29. if ($fp_source = fopen($this->filename, 'r+b')) {
  30. ob_end_clean();
  31. // Initialize getID3 engine
  32. $getID3 = new getID3;
  33. $OldThisFileInfo = $getID3->analyze($this->filename);
  34. if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
  35. $this->errors[] = 'Cannot write Real tags on old-style file format';
  36. fclose($fp_source);
  37. return false;
  38. }
  39. if (empty($OldThisFileInfo['real']['chunks'])) {
  40. $this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file';
  41. fclose($fp_source);
  42. return false;
  43. }
  44. foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
  45. $oldChunkInfo[$chunkarray['name']] = $chunkarray;
  46. }
  47. if (!empty($oldChunkInfo['CONT']['length'])) {
  48. $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength);
  49. }
  50. $new_CONT_tag_data = $this->GenerateCONTchunk();
  51. $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data);
  52. $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']);
  53. if (isset($oldChunkInfo['.RMF']['length']) && ($oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data))) {
  54. fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET);
  55. fwrite($fp_source, $new__RMF_tag_data);
  56. } else {
  57. $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)';
  58. fclose($fp_source);
  59. return false;
  60. }
  61. if (isset($oldChunkInfo['PROP']['length']) && ($oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data))) {
  62. fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET);
  63. fwrite($fp_source, $new_PROP_tag_data);
  64. } else {
  65. $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)';
  66. fclose($fp_source);
  67. return false;
  68. }
  69. if (isset($oldChunkInfo['CONT']['length']) && ($oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data))) {
  70. // new data length is same as old data length - just overwrite
  71. fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET);
  72. fwrite($fp_source, $new_CONT_tag_data);
  73. fclose($fp_source);
  74. return true;
  75. } else {
  76. if (empty($oldChunkInfo['CONT'])) {
  77. // no existing CONT chunk
  78. $BeforeOffset = $oldChunkInfo['DATA']['offset'];
  79. $AfterOffset = $oldChunkInfo['DATA']['offset'];
  80. } else {
  81. // new data is longer than old data
  82. $BeforeOffset = $oldChunkInfo['CONT']['offset'];
  83. $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
  84. }
  85. if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
  86. ob_start();
  87. if ($fp_temp = fopen($tempfilename, 'wb')) {
  88. rewind($fp_source);
  89. fwrite($fp_temp, fread($fp_source, $BeforeOffset));
  90. fwrite($fp_temp, $new_CONT_tag_data);
  91. fseek($fp_source, $AfterOffset, SEEK_SET);
  92. while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
  93. fwrite($fp_temp, $buffer, strlen($buffer));
  94. }
  95. fclose($fp_temp);
  96. if (copy($tempfilename, $this->filename)) {
  97. unlink($tempfilename);
  98. fclose($fp_source);
  99. return true;
  100. }
  101. unlink($tempfilename);
  102. $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
  103. } else {
  104. $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
  105. }
  106. ob_end_clean();
  107. }
  108. fclose($fp_source);
  109. return false;
  110. }
  111. } else {
  112. $errormessage = ob_get_contents();
  113. ob_end_clean();
  114. $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
  115. return false;
  116. }
  117. }
  118. $this->errors[] = 'File is not writeable: '.$this->filename;
  119. return false;
  120. }
  121. function GenerateRMFchunk(&$chunks) {
  122. $oldCONTexists = false;
  123. foreach ($chunks as $key => $chunk) {
  124. $chunkNameKeys[$chunk['name']] = $key;
  125. if ($chunk['name'] == 'CONT') {
  126. $oldCONTexists = true;
  127. }
  128. }
  129. $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
  130. $RMFchunk = "\x00\x00"; // object version
  131. $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
  132. $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4);
  133. $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length
  134. return $RMFchunk;
  135. }
  136. function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
  137. $old_CONT_length = 0;
  138. $old_DATA_offset = 0;
  139. $old_INDX_offset = 0;
  140. foreach ($chunks as $key => $chunk) {
  141. $chunkNameKeys[$chunk['name']] = $key;
  142. if ($chunk['name'] == 'CONT') {
  143. $old_CONT_length = $chunk['length'];
  144. } elseif ($chunk['name'] == 'DATA') {
  145. if (!$old_DATA_offset) {
  146. $old_DATA_offset = $chunk['offset'];
  147. }
  148. } elseif ($chunk['name'] == 'INDX') {
  149. if (!$old_INDX_offset) {
  150. $old_INDX_offset = $chunk['offset'];
  151. }
  152. }
  153. }
  154. $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
  155. $PROPchunk = "\x00\x00"; // object version
  156. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4);
  157. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4);
  158. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
  159. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
  160. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4);
  161. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4);
  162. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4);
  163. $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4);
  164. $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4);
  165. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2);
  166. $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2);
  167. $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length
  168. return $PROPchunk;
  169. }
  170. function GenerateCONTchunk() {
  171. foreach ($this->tag_data as $key => $value) {
  172. // limit each value to 0xFFFF bytes
  173. $this->tag_data[$key] = substr($value, 0, 65535);
  174. }
  175. $CONTchunk = "\x00\x00"; // object version
  176. $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : 0), 2);
  177. $CONTchunk .= (!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : '');
  178. $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : 0), 2);
  179. $CONTchunk .= (!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : '');
  180. $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : 0), 2);
  181. $CONTchunk .= (!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : '');
  182. $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : 0), 2);
  183. $CONTchunk .= (!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : '');
  184. if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
  185. $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
  186. }
  187. $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length
  188. return $CONTchunk;
  189. }
  190. function RemoveReal() {
  191. // File MUST be writeable - CHMOD(646) at least
  192. if (is_writeable($this->filename)) {
  193. ob_start();
  194. if ($fp_source = fopen($this->filename, 'r+b')) {
  195. ob_end_clean();
  196. // Initialize getID3 engine
  197. $getID3 = new getID3;
  198. $OldThisFileInfo = $getID3->analyze($this->filename);
  199. if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
  200. $this->errors[] = 'Cannot remove Real tags from old-style file format';
  201. fclose($fp_source);
  202. return false;
  203. }
  204. if (empty($OldThisFileInfo['real']['chunks'])) {
  205. $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
  206. fclose($fp_source);
  207. return false;
  208. }
  209. foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
  210. $oldChunkInfo[$chunkarray['name']] = $chunkarray;
  211. }
  212. if (empty($oldChunkInfo['CONT'])) {
  213. // no existing CONT chunk
  214. fclose($fp_source);
  215. return true;
  216. }
  217. $BeforeOffset = $oldChunkInfo['CONT']['offset'];
  218. $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
  219. if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
  220. ob_start();
  221. if ($fp_temp = fopen($tempfilename, 'wb')) {
  222. rewind($fp_source);
  223. fwrite($fp_temp, fread($fp_source, $BeforeOffset));
  224. fseek($fp_source, $AfterOffset, SEEK_SET);
  225. while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
  226. fwrite($fp_temp, $buffer, strlen($buffer));
  227. }
  228. fclose($fp_temp);
  229. if (copy($tempfilename, $this->filename)) {
  230. unlink($tempfilename);
  231. fclose($fp_source);
  232. return true;
  233. }
  234. unlink($tempfilename);
  235. $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
  236. } else {
  237. $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
  238. }
  239. ob_end_clean();
  240. }
  241. fclose($fp_source);
  242. return false;
  243. } else {
  244. $errormessage = ob_get_contents();
  245. ob_end_clean();
  246. $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
  247. return false;
  248. }
  249. }
  250. $this->errors[] = 'File is not writeable: '.$this->filename;
  251. return false;
  252. }
  253. }
  254. ?>