write.id3v1.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at https://github.com/JamesHeinrich/getID3 //
  5. // or https://www.getid3.org //
  6. // or http://getid3.sourceforge.net //
  7. // see readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. // //
  10. // write.id3v1.php //
  11. // module for writing ID3v1 tags //
  12. // dependencies: module.tag.id3v1.php //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
  16. exit;
  17. }
  18. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
  19. class getid3_write_id3v1
  20. {
  21. /**
  22. * @var string
  23. */
  24. public $filename;
  25. /**
  26. * @var int
  27. */
  28. public $filesize;
  29. /**
  30. * @var array
  31. */
  32. public $tag_data;
  33. /**
  34. * Any non-critical errors will be stored here.
  35. *
  36. * @var array
  37. */
  38. public $warnings = array();
  39. /**
  40. * Any critical errors will be stored here.
  41. *
  42. * @var array
  43. */
  44. public $errors = array();
  45. public function __construct() {
  46. }
  47. /**
  48. * @return bool
  49. */
  50. public function WriteID3v1() {
  51. // File MUST be writeable - CHMOD(646) at least
  52. if (!empty($this->filename) && is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename)) {
  53. $this->setRealFileSize();
  54. if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) {
  55. $this->errors[] = 'Unable to WriteID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
  56. return false;
  57. }
  58. if ($fp_source = fopen($this->filename, 'r+b')) {
  59. fseek($fp_source, -128, SEEK_END);
  60. if (fread($fp_source, 3) == 'TAG') {
  61. fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag
  62. } else {
  63. fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag
  64. }
  65. $this->tag_data['track_number'] = (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : '');
  66. $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag(
  67. (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''),
  68. (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''),
  69. (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''),
  70. (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''),
  71. (isset($this->tag_data['genreid'] ) ? $this->tag_data['genreid'] : ''),
  72. (isset($this->tag_data['comment'] ) ? $this->tag_data['comment'] : ''),
  73. (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : ''));
  74. fwrite($fp_source, $new_id3v1_tag_data, 128);
  75. fclose($fp_source);
  76. return true;
  77. } else {
  78. $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")';
  79. return false;
  80. }
  81. }
  82. $this->errors[] = 'File is not writeable: '.$this->filename;
  83. return false;
  84. }
  85. /**
  86. * @return bool
  87. */
  88. public function FixID3v1Padding() {
  89. // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces
  90. // This function rewrites the ID3v1 tag with correct padding
  91. // Initialize getID3 engine
  92. $getID3 = new getID3;
  93. $getID3->option_tag_id3v2 = false;
  94. $getID3->option_tag_apetag = false;
  95. $getID3->option_tags_html = false;
  96. $getID3->option_extra_info = false;
  97. $getID3->option_tag_id3v1 = true;
  98. $ThisFileInfo = $getID3->analyze($this->filename);
  99. if (isset($ThisFileInfo['tags']['id3v1'])) {
  100. $id3v1data = array();
  101. foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) {
  102. $id3v1data[$key] = implode(',', $value);
  103. }
  104. $this->tag_data = $id3v1data;
  105. return $this->WriteID3v1();
  106. }
  107. return false;
  108. }
  109. /**
  110. * @return bool
  111. */
  112. public function RemoveID3v1() {
  113. // File MUST be writeable - CHMOD(646) at least
  114. if (!empty($this->filename) && is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename)) {
  115. $this->setRealFileSize();
  116. if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) {
  117. $this->errors[] = 'Unable to RemoveID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
  118. return false;
  119. }
  120. if ($fp_source = fopen($this->filename, 'r+b')) {
  121. fseek($fp_source, -128, SEEK_END);
  122. if (fread($fp_source, 3) == 'TAG') {
  123. ftruncate($fp_source, $this->filesize - 128);
  124. } else {
  125. // no ID3v1 tag to begin with - do nothing
  126. }
  127. fclose($fp_source);
  128. return true;
  129. } else {
  130. $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")';
  131. }
  132. } else {
  133. $this->errors[] = $this->filename.' is not writeable';
  134. }
  135. return false;
  136. }
  137. /**
  138. * @return bool
  139. */
  140. public function setRealFileSize() {
  141. if (PHP_INT_MAX > 2147483647) {
  142. $this->filesize = filesize($this->filename);
  143. return true;
  144. }
  145. // 32-bit PHP will not return correct values for filesize() if file is >=2GB
  146. // but getID3->analyze() has workarounds to get actual filesize
  147. $getID3 = new getID3;
  148. $getID3->option_tag_id3v1 = false;
  149. $getID3->option_tag_id3v2 = false;
  150. $getID3->option_tag_apetag = false;
  151. $getID3->option_tags_html = false;
  152. $getID3->option_extra_info = false;
  153. $ThisFileInfo = $getID3->analyze($this->filename);
  154. $this->filesize = $ThisFileInfo['filesize'];
  155. return true;
  156. }
  157. }