3 /////////////////////////////////////////////////////////////////
4 /// getID3() by James Heinrich <info@getid3.org> //
5 // available at https://github.com/JamesHeinrich/getID3 //
6 // or https://www.getid3.org //
7 // or http://getid3.sourceforge.net //
8 // see readme.txt for more details //
9 /////////////////////////////////////////////////////////////////
12 // module for writing tags (APEv2, ID3v1, ID3v2) //
13 // dependencies: getid3.lib.php //
14 // write.apetag.php (optional) //
15 // write.id3v1.php (optional) //
16 // write.id3v2.php (optional) //
17 // write.vorbiscomment.php (optional) //
18 // write.metaflac.php (optional) //
19 // write.lyrics3.php (optional) //
21 /////////////////////////////////////////////////////////////////
23 if (!defined('GETID3_INCLUDEPATH')) {
24 throw new Exception('getid3.php MUST be included before calling getid3_writetags');
26 if (!include_once(GETID3_INCLUDEPATH
.'getid3.lib.php')) {
27 throw new Exception('write.php depends on getid3.lib.php, which is missing.');
33 * You should pass data here with standard field names as follows:
41 * * ATTACHED_PICTURE (ID3v2 only)
42 * The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead
43 * Pass data here as "TRACKNUMBER" for compatability with all formats
45 * @link http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
47 class getid3_writetags
50 * Absolute filename of file to write tags to.
57 * Array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment',
58 * 'metaflac', 'real').
62 public $tagformats = array();
65 * 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis').
69 public $tag_data = array(array());
72 * Text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', ).
76 public $tag_encoding = 'ISO-8859-1';
79 * If true will erase existing tag data and write only passed data; if false will merge passed data
80 * with existing tag data.
84 public $overwrite_tags = true;
87 * If true will erase remove all existing tags and only write those passed in $tagformats;
88 * If false will ignore any tags not mentioned in $tagformats.
92 public $remove_other_tags = false;
95 * ISO-639-2 3-character language code needed for some ID3v2 frames.
97 * @link http://www.id3.org/iso639-2.html
101 public $id3v2_tag_language = 'eng';
104 * Minimum length of ID3v2 tags (will be padded to this length if tag data is shorter).
108 public $id3v2_paddedlength = 4096;
111 * Any non-critical errors will be stored here.
115 public $warnings = array();
118 * Any critical errors will be stored here.
122 public $errors = array();
125 * Analysis of file before writing.
129 private $ThisFileInfo;
131 public function __construct() {
137 public function WriteTags() {
139 if (empty($this->filename
)) {
140 $this->errors
[] = 'filename is undefined in getid3_writetags';
142 } elseif (!file_exists($this->filename
)) {
143 $this->errors
[] = 'filename set to non-existant file "'.$this->filename
.'" in getid3_writetags';
147 if (!is_array($this->tagformats
)) {
148 $this->errors
[] = 'tagformats must be an array in getid3_writetags';
151 // prevent duplicate tag formats
152 $this->tagformats
= array_unique($this->tagformats
);
154 // prevent trying to specify more than one version of ID3v2 tag to write simultaneously
156 foreach ($this->tagformats
as $tagformat) {
157 if (substr(strtolower($tagformat), 0, 6) == 'id3v2.') {
161 if ($id3typecounter > 1) {
162 $this->errors
[] = 'tagformats must not contain more than one version of ID3v2';
166 $TagFormatsToRemove = array();
167 $AllowedTagFormats = array();
168 if (filesize($this->filename
) == 0) {
170 // empty file special case - allow any tag format, don't check existing format
171 // could be useful if you want to generate tag data for a non-existant file
172 $this->ThisFileInfo
= array('fileformat'=>'');
173 $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
177 $getID3 = new getID3
;
178 $getID3->encoding
= $this->tag_encoding
;
179 $this->ThisFileInfo
= $getID3->analyze($this->filename
);
181 // check for what file types are allowed on this fileformat
182 switch (isset($this->ThisFileInfo
['fileformat']) ?
$this->ThisFileInfo
['fileformat'] : '') {
186 case 'riff': // maybe not officially, but people do it anyway
187 $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
191 $AllowedTagFormats = array('ape');
195 $AllowedTagFormats = array('metaflac');
199 $AllowedTagFormats = array('real');
203 switch (isset($this->ThisFileInfo
['audio']['dataformat']) ?
$this->ThisFileInfo
['audio']['dataformat'] : '') {
205 //$AllowedTagFormats = array('metaflac');
206 $this->errors
[] = 'metaflac is not (yet) compatible with OggFLAC files';
210 $AllowedTagFormats = array('vorbiscomment');
213 $this->errors
[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis';
220 $AllowedTagFormats = array();
223 foreach ($this->tagformats
as $requested_tag_format) {
224 if (!in_array($requested_tag_format, $AllowedTagFormats)) {
225 $errormessage = 'Tag format "'.$requested_tag_format.'" is not allowed on "'.(isset($this->ThisFileInfo
['fileformat']) ?
$this->ThisFileInfo
['fileformat'] : '');
226 $errormessage .= (isset($this->ThisFileInfo
['audio']['dataformat']) ?
'.'.$this->ThisFileInfo
['audio']['dataformat'] : '');
227 $errormessage .= '" files';
228 $this->errors
[] = $errormessage;
233 // List of other tag formats, removed if requested
234 if ($this->remove_other_tags
) {
235 foreach ($AllowedTagFormats as $AllowedTagFormat) {
236 switch ($AllowedTagFormat) {
240 if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats
) && !in_array('id3v2.3', $this->tagformats
) && !in_array('id3v2.4', $this->tagformats
)) {
241 $TagFormatsToRemove[] = 'id3v2';
246 if (!in_array($AllowedTagFormat, $this->tagformats
)) {
247 $TagFormatsToRemove[] = $AllowedTagFormat;
255 $WritingFilesToInclude = array_merge($this->tagformats
, $TagFormatsToRemove);
257 // Check for required include files and include them
258 foreach ($WritingFilesToInclude as $tagformat) {
259 switch ($tagformat) {
261 $GETID3_ERRORARRAY = &$this->errors
;
262 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'write.apetag.php', __FILE__
, true);
267 case 'vorbiscomment':
270 $GETID3_ERRORARRAY = &$this->errors
;
271 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'write.'.$tagformat.'.php', __FILE__
, true);
278 $GETID3_ERRORARRAY = &$this->errors
;
279 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'write.id3v2.php', __FILE__
, true);
283 $this->errors
[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()';
290 // Validation of supplied data
291 if (!is_array($this->tag_data
)) {
292 $this->errors
[] = '$this->tag_data is not an array in WriteTags()';
295 // convert supplied data array keys to upper case, if they're not already
296 foreach ($this->tag_data
as $tag_key => $tag_array) {
297 if (strtoupper($tag_key) !== $tag_key) {
298 $this->tag_data
[strtoupper($tag_key)] = $this->tag_data
[$tag_key];
299 unset($this->tag_data
[$tag_key]);
302 // convert source data array keys to upper case, if they're not already
303 if (!empty($this->ThisFileInfo
['tags'])) {
304 foreach ($this->ThisFileInfo
['tags'] as $tag_format => $tag_data_array) {
305 foreach ($tag_data_array as $tag_key => $tag_array) {
306 if (strtoupper($tag_key) !== $tag_key) {
307 $this->ThisFileInfo
['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo
['tags'][$tag_format][$tag_key];
308 unset($this->ThisFileInfo
['tags'][$tag_format][$tag_key]);
314 // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats
315 if (isset($this->tag_data
['TRACK']) && !isset($this->tag_data
['TRACKNUMBER'])) {
316 $this->tag_data
['TRACKNUMBER'] = $this->tag_data
['TRACK'];
317 unset($this->tag_data
['TRACK']);
320 // Remove all other tag formats, if requested
321 if ($this->remove_other_tags
) {
322 $this->DeleteTags($TagFormatsToRemove);
325 // Write data for each tag format
326 foreach ($this->tagformats
as $tagformat) {
327 $success = false; // overridden if tag writing is successful
328 switch ($tagformat) {
330 $ape_writer = new getid3_write_apetag
;
331 if ($ape_writer->tag_data
= $this->FormatDataForAPE()) {
332 $ape_writer->filename
= $this->filename
;
333 if (($success = $ape_writer->WriteAPEtag()) === false) {
334 $this->errors
[] = 'WriteAPEtag() failed with message(s):<pre><ul><li>'.str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $ape_writer->errors
)))).'</li></ul></pre>';
337 $this->errors
[] = 'FormatDataForAPE() failed';
342 $id3v1_writer = new getid3_write_id3v1
;
343 if ($id3v1_writer->tag_data
= $this->FormatDataForID3v1()) {
344 $id3v1_writer->filename
= $this->filename
;
345 if (($success = $id3v1_writer->WriteID3v1()) === false) {
346 $this->errors
[] = 'WriteID3v1() failed with message(s):<pre><ul><li>'.str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $id3v1_writer->errors
)))).'</li></ul></pre>';
349 $this->errors
[] = 'FormatDataForID3v1() failed';
356 $id3v2_writer = new getid3_write_id3v2
;
357 $id3v2_writer->majorversion
= intval(substr($tagformat, -1));
358 $id3v2_writer->paddedlength
= $this->id3v2_paddedlength
;
359 $id3v2_writer_tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion
);
360 if ($id3v2_writer_tag_data !== false) {
361 $id3v2_writer->tag_data
= $id3v2_writer_tag_data;
362 unset($id3v2_writer_tag_data);
363 $id3v2_writer->filename
= $this->filename
;
364 if (($success = $id3v2_writer->WriteID3v2()) === false) {
365 $this->errors
[] = 'WriteID3v2() failed with message(s):<pre><ul><li>'.str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $id3v2_writer->errors
)))).'</li></ul></pre>';
368 $this->errors
[] = 'FormatDataForID3v2() failed';
372 case 'vorbiscomment':
373 $vorbiscomment_writer = new getid3_write_vorbiscomment
;
374 if ($vorbiscomment_writer->tag_data
= $this->FormatDataForVorbisComment()) {
375 $vorbiscomment_writer->filename
= $this->filename
;
376 if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) {
377 $this->errors
[] = 'WriteVorbisComment() failed with message(s):<pre><ul><li>'.str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $vorbiscomment_writer->errors
)))).'</li></ul></pre>';
380 $this->errors
[] = 'FormatDataForVorbisComment() failed';
385 $metaflac_writer = new getid3_write_metaflac
;
386 if ($metaflac_writer->tag_data
= $this->FormatDataForMetaFLAC()) {
387 $metaflac_writer->filename
= $this->filename
;
388 if (($success = $metaflac_writer->WriteMetaFLAC()) === false) {
389 $this->errors
[] = 'WriteMetaFLAC() failed with message(s):<pre><ul><li>'.str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $metaflac_writer->errors
)))).'</li></ul></pre>';
392 $this->errors
[] = 'FormatDataForMetaFLAC() failed';
397 $real_writer = new getid3_write_real
;
398 if ($real_writer->tag_data
= $this->FormatDataForReal()) {
399 $real_writer->filename
= $this->filename
;
400 if (($success = $real_writer->WriteReal()) === false) {
401 $this->errors
[] = 'WriteReal() failed with message(s):<pre><ul><li>'.str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $real_writer->errors
)))).'</li></ul></pre>';
404 $this->errors
[] = 'FormatDataForReal() failed';
409 $this->errors
[] = 'Invalid tag format to write: "'.$tagformat.'"';
422 * @param string[] $TagFormatsToDelete
426 public function DeleteTags($TagFormatsToDelete) {
427 foreach ($TagFormatsToDelete as $DeleteTagFormat) {
428 $success = false; // overridden if tag deletion is successful
429 switch ($DeleteTagFormat) {
431 $id3v1_writer = new getid3_write_id3v1
;
432 $id3v1_writer->filename
= $this->filename
;
433 if (($success = $id3v1_writer->RemoveID3v1()) === false) {
434 $this->errors
[] = 'RemoveID3v1() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v1_writer->errors
)).'</LI></UL></PRE>';
439 $id3v2_writer = new getid3_write_id3v2
;
440 $id3v2_writer->filename
= $this->filename
;
441 if (($success = $id3v2_writer->RemoveID3v2()) === false) {
442 $this->errors
[] = 'RemoveID3v2() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v2_writer->errors
)).'</LI></UL></PRE>';
447 $ape_writer = new getid3_write_apetag
;
448 $ape_writer->filename
= $this->filename
;
449 if (($success = $ape_writer->DeleteAPEtag()) === false) {
450 $this->errors
[] = 'DeleteAPEtag() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $ape_writer->errors
)).'</LI></UL></PRE>';
454 case 'vorbiscomment':
455 $vorbiscomment_writer = new getid3_write_vorbiscomment
;
456 $vorbiscomment_writer->filename
= $this->filename
;
457 if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) {
458 $this->errors
[] = 'DeleteVorbisComment() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $vorbiscomment_writer->errors
)).'</LI></UL></PRE>';
463 $metaflac_writer = new getid3_write_metaflac
;
464 $metaflac_writer->filename
= $this->filename
;
465 if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) {
466 $this->errors
[] = 'DeleteMetaFLAC() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $metaflac_writer->errors
)).'</LI></UL></PRE>';
471 $lyrics3_writer = new getid3_write_lyrics3
;
472 $lyrics3_writer->filename
= $this->filename
;
473 if (($success = $lyrics3_writer->DeleteLyrics3()) === false) {
474 $this->errors
[] = 'DeleteLyrics3() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $lyrics3_writer->errors
)).'</LI></UL></PRE>';
479 $real_writer = new getid3_write_real
;
480 $real_writer->filename
= $this->filename
;
481 if (($success = $real_writer->RemoveReal()) === false) {
482 $this->errors
[] = 'RemoveReal() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $real_writer->errors
)).'</LI></UL></PRE>';
487 $this->errors
[] = 'Invalid tag format to delete: "'.$DeleteTagFormat.'"';
499 * @param string $TagFormat
500 * @param array $tag_data
505 public function MergeExistingTagData($TagFormat, &$tag_data) {
506 // Merge supplied data with existing data, if requested
507 if ($this->overwrite_tags
) {
508 // do nothing - ignore previous data
510 throw new Exception('$this->overwrite_tags=false is known to be buggy in this version of getID3. Check http://github.com/JamesHeinrich/getID3 for a newer version.');
511 if (!isset($this->ThisFileInfo
['tags'][$TagFormat])) {
514 $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo
['tags'][$TagFormat]);
522 public function FormatDataForAPE() {
523 $ape_tag_data = array();
524 foreach ($this->tag_data
as $tag_key => $valuearray) {
526 case 'ATTACHED_PICTURE':
527 // ATTACHED_PICTURE is ID3v2 only - ignore
528 $this->warnings
[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag';
532 foreach ($valuearray as $key => $value) {
533 if (is_string($value) ||
is_numeric($value)) {
534 $ape_tag_data[$tag_key][$key] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'UTF-8', $value);
536 $this->warnings
[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag';
537 unset($ape_tag_data[$tag_key]);
544 $this->MergeExistingTagData('ape', $ape_tag_data);
545 return $ape_tag_data;
551 public function FormatDataForID3v1() {
552 $tag_data_id3v1 = array();
553 $tag_data_id3v1['genreid'] = 255;
554 if (!empty($this->tag_data
['GENRE'])) {
555 foreach ($this->tag_data
['GENRE'] as $key => $value) {
556 if (getid3_id3v1
::LookupGenreID($value) !== false) {
557 $tag_data_id3v1['genreid'] = getid3_id3v1
::LookupGenreID($value);
562 $tag_data_id3v1['title'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['TITLE'] ) ?
$this->tag_data
['TITLE'] : array())));
563 $tag_data_id3v1['artist'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['ARTIST'] ) ?
$this->tag_data
['ARTIST'] : array())));
564 $tag_data_id3v1['album'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['ALBUM'] ) ?
$this->tag_data
['ALBUM'] : array())));
565 $tag_data_id3v1['year'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['YEAR'] ) ?
$this->tag_data
['YEAR'] : array())));
566 $tag_data_id3v1['comment'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['COMMENT'] ) ?
$this->tag_data
['COMMENT'] : array())));
567 $tag_data_id3v1['track'] = intval(getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['TRACKNUMBER']) ?
$this->tag_data
['TRACKNUMBER'] : array()))));
568 if ($tag_data_id3v1['track'] <= 0) {
569 $tag_data_id3v1['track'] = '';
572 $this->MergeExistingTagData('id3v1', $tag_data_id3v1);
573 return $tag_data_id3v1;
577 * @param int $id3v2_majorversion
579 * @return array|false
581 public function FormatDataForID3v2($id3v2_majorversion) {
582 $tag_data_id3v2 = array();
584 $ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
585 $ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
586 $ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3);
587 foreach ($this->tag_data
as $tag_key => $valuearray) {
588 $ID3v2_framename = getid3_write_id3v2
::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key);
589 switch ($ID3v2_framename) {
591 foreach ($valuearray as $key => $apic_data_array) {
592 if (isset($apic_data_array['data']) &&
593 isset($apic_data_array['picturetypeid']) &&
594 isset($apic_data_array['description']) &&
595 isset($apic_data_array['mime'])) {
596 $tag_data_id3v2['APIC'][] = $apic_data_array;
598 $this->errors
[] = 'ID3v2 APIC data is not properly structured';
605 if (isset($valuearray['email']) &&
606 isset($valuearray['rating']) &&
607 isset($valuearray['data'])) {
608 $tag_data_id3v2['POPM'][] = $valuearray;
610 $this->errors
[] = 'ID3v2 POPM data is not properly structured';
617 isset($valuearray['groupsymbol']) &&
618 isset($valuearray['ownerid']) &&
619 isset($valuearray['data'])
621 $tag_data_id3v2['GRID'][] = $valuearray;
623 $this->errors
[] = 'ID3v2 GRID data is not properly structured';
629 if (isset($valuearray['ownerid']) &&
630 isset($valuearray['data'])) {
631 $tag_data_id3v2['UFID'][] = $valuearray;
633 $this->errors
[] = 'ID3v2 UFID data is not properly structured';
639 foreach ($valuearray as $key => $txxx_data_array) {
640 if (isset($txxx_data_array['description']) && isset($txxx_data_array['data'])) {
641 $tag_data_id3v2['TXXX'][] = $txxx_data_array;
643 $this->errors
[] = 'ID3v2 TXXX data is not properly structured';
650 $this->errors
[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type';
651 // some other data type, don't know how to handle it, ignore it
655 // most other (text) frames can be copied over as-is
656 foreach ($valuearray as $key => $value) {
657 if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding
])) {
658 // source encoding is valid in ID3v2 - use it with no conversion
659 $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding
];
660 $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
662 // source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first
663 if ($id3v2_majorversion < 4) {
664 // convert data from other encoding to UTF-16 (with BOM)
665 // note: some software, notably Windows Media Player and iTunes are broken and treat files tagged with UTF-16BE (with BOM) as corrupt
666 // therefore we force data to UTF-16LE and manually prepend the BOM
667 $ID3v2_tag_data_converted = false;
668 if (!$ID3v2_tag_data_converted && ($this->tag_encoding
== 'ISO-8859-1')) {
669 // great, leave data as-is for minimum compatability problems
670 $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0;
671 $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
672 $ID3v2_tag_data_converted = true;
674 if (!$ID3v2_tag_data_converted && ($this->tag_encoding
== 'UTF-8')) {
676 // if UTF-8 string does not include any characters above chr(127) then it is identical to ISO-8859-1
677 for ($i = 0; $i < strlen($value); $i++
) {
678 if (ord($value{$i}) > 127) {
682 $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0;
683 $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
684 $ID3v2_tag_data_converted = true;
687 if (!$ID3v2_tag_data_converted) {
688 $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1;
689 //$tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16', $value); // output is UTF-16LE+BOM or UTF-16BE+BOM depending on system architecture
690 $tag_data_id3v2[$ID3v2_framename][$key]['data'] = "\xFF\xFE".getid3_lib
::iconv_fallback($this->tag_encoding
, 'UTF-16LE', $value); // force LittleEndian order version of UTF-16
691 $ID3v2_tag_data_converted = true;
695 // convert data from other encoding to UTF-8
696 $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3;
697 $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'UTF-8', $value);
701 // These values are not needed for all frame types, but if they're not used no matter
702 $tag_data_id3v2[$ID3v2_framename][$key]['description'] = '';
703 $tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language
;
708 $this->MergeExistingTagData('id3v2', $tag_data_id3v2);
709 return $tag_data_id3v2;
715 public function FormatDataForVorbisComment() {
716 $tag_data_vorbiscomment = $this->tag_data
;
718 // check for multi-line comment values - split out to multiple comments if neccesary
719 // and convert data to UTF-8 strings
720 foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) {
721 foreach ($valuearray as $key => $value) {
722 if (($tag_key == 'ATTACHED_PICTURE') && is_array($value)) {
723 continue; // handled separately in write.metaflac.php
725 str_replace("\r", "\n", $value);
726 if (strstr($value, "\n")) {
727 unset($tag_data_vorbiscomment[$tag_key][$key]);
728 $multilineexploded = explode("\n", $value);
729 foreach ($multilineexploded as $newcomment) {
730 if (strlen(trim($newcomment)) > 0) {
731 $tag_data_vorbiscomment[$tag_key][] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'UTF-8', $newcomment);
734 } elseif (is_string($value) ||
is_numeric($value)) {
735 $tag_data_vorbiscomment[$tag_key][$key] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'UTF-8', $value);
737 $this->warnings
[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag';
738 unset($tag_data_vorbiscomment[$tag_key]);
744 $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment);
745 return $tag_data_vorbiscomment;
751 public function FormatDataForMetaFLAC() {
752 // FLAC & OggFLAC use VorbisComments same as OggVorbis
753 // but require metaflac to do the writing rather than vorbiscomment
754 return $this->FormatDataForVorbisComment();
760 public function FormatDataForReal() {
761 $tag_data_real['title'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['TITLE'] ) ?
$this->tag_data
['TITLE'] : array())));
762 $tag_data_real['artist'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['ARTIST'] ) ?
$this->tag_data
['ARTIST'] : array())));
763 $tag_data_real['copyright'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['COPYRIGHT']) ?
$this->tag_data
['COPYRIGHT'] : array())));
764 $tag_data_real['comment'] = getid3_lib
::iconv_fallback($this->tag_encoding
, 'ISO-8859-1', implode(' ', (isset($this->tag_data
['COMMENT'] ) ?
$this->tag_data
['COMMENT'] : array())));
766 $this->MergeExistingTagData('real', $tag_data_real);
767 return $tag_data_real;