ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
write.php
Go to the documentation of this file.
1 <?php
4 // available at http://getid3.sourceforge.net //
5 // or http://www.getid3.org //
6 // also https://github.com/JamesHeinrich/getID3 //
8 // See readme.txt for more details //
11 // write.php //
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) //
20 // ///
22 
23 if (!defined('GETID3_INCLUDEPATH')) {
24  throw new Exception('getid3.php MUST be included before calling getid3_writetags');
25 }
26 if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
27  throw new Exception('write.php depends on getid3.lib.php, which is missing.');
28 }
29 
30 
31 // NOTES:
32 //
33 // You should pass data here with standard field names as follows:
34 // * TITLE
35 // * ARTIST
36 // * ALBUM
37 // * TRACKNUMBER
38 // * COMMENT
39 // * GENRE
40 // * YEAR
41 // * ATTACHED_PICTURE (ID3v2 only)
42 //
43 // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
44 // The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead
45 // Pass data here as "TRACKNUMBER" for compatability with all formats
46 
47 
49 {
50  // public
51  public $filename; // absolute filename of file to write tags to
52  public $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real')
53  public $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis')
54  public $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', )
55  public $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data
56  public $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats
57 
58  public $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html)
59  public $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter)
60 
61  public $warnings = array(); // any non-critical errors will be stored here
62  public $errors = array(); // any critical errors will be stored here
63 
64  // private
65  private $ThisFileInfo; // analysis of file before writing
66 
67  public function __construct() {
68  return true;
69  }
70 
71 
72  public function WriteTags() {
73 
74  if (empty($this->filename)) {
75  $this->errors[] = 'filename is undefined in getid3_writetags';
76  return false;
77  } elseif (!file_exists($this->filename)) {
78  $this->errors[] = 'filename set to non-existant file "'.$this->filename.'" in getid3_writetags';
79  return false;
80  }
81 
82  if (!is_array($this->tagformats)) {
83  $this->errors[] = 'tagformats must be an array in getid3_writetags';
84  return false;
85  }
86 
87  $TagFormatsToRemove = array();
88  if (filesize($this->filename) == 0) {
89 
90  // empty file special case - allow any tag format, don't check existing format
91  // could be useful if you want to generate tag data for a non-existant file
92  $this->ThisFileInfo = array('fileformat'=>'');
93  $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
94 
95  } else {
96 
97  $getID3 = new getID3;
98  $getID3->encoding = $this->tag_encoding;
99  $this->ThisFileInfo = $getID3->analyze($this->filename);
100 
101  // check for what file types are allowed on this fileformat
102  switch (isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : '') {
103  case 'mp3':
104  case 'mp2':
105  case 'mp1':
106  case 'riff': // maybe not officially, but people do it anyway
107  $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
108  break;
109 
110  case 'mpc':
111  $AllowedTagFormats = array('ape');
112  break;
113 
114  case 'flac':
115  $AllowedTagFormats = array('metaflac');
116  break;
117 
118  case 'real':
119  $AllowedTagFormats = array('real');
120  break;
121 
122  case 'ogg':
123  switch (isset($this->ThisFileInfo['audio']['dataformat']) ? $this->ThisFileInfo['audio']['dataformat'] : '') {
124  case 'flac':
125  //$AllowedTagFormats = array('metaflac');
126  $this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files';
127  return false;
128  break;
129  case 'vorbis':
130  $AllowedTagFormats = array('vorbiscomment');
131  break;
132  default:
133  $this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis';
134  return false;
135  break;
136  }
137  break;
138 
139  default:
140  $AllowedTagFormats = array();
141  break;
142  }
143  foreach ($this->tagformats as $requested_tag_format) {
144  if (!in_array($requested_tag_format, $AllowedTagFormats)) {
145  $errormessage = 'Tag format "'.$requested_tag_format.'" is not allowed on "'.(isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : '');
146  $errormessage .= (isset($this->ThisFileInfo['audio']['dataformat']) ? '.'.$this->ThisFileInfo['audio']['dataformat'] : '');
147  $errormessage .= '" files';
148  $this->errors[] = $errormessage;
149  return false;
150  }
151  }
152 
153  // List of other tag formats, removed if requested
154  if ($this->remove_other_tags) {
155  foreach ($AllowedTagFormats as $AllowedTagFormat) {
156  switch ($AllowedTagFormat) {
157  case 'id3v2.2':
158  case 'id3v2.3':
159  case 'id3v2.4':
160  if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats) && !in_array('id3v2.3', $this->tagformats) && !in_array('id3v2.4', $this->tagformats)) {
161  $TagFormatsToRemove[] = 'id3v2';
162  }
163  break;
164 
165  default:
166  if (!in_array($AllowedTagFormat, $this->tagformats)) {
167  $TagFormatsToRemove[] = $AllowedTagFormat;
168  }
169  break;
170  }
171  }
172  }
173  }
174 
175  $WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove);
176 
177  // Check for required include files and include them
178  foreach ($WritingFilesToInclude as $tagformat) {
179  switch ($tagformat) {
180  case 'ape':
181  $GETID3_ERRORARRAY = &$this->errors;
182  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, true);
183  break;
184 
185  case 'id3v1':
186  case 'lyrics3':
187  case 'vorbiscomment':
188  case 'metaflac':
189  case 'real':
190  $GETID3_ERRORARRAY = &$this->errors;
191  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, true);
192  break;
193 
194  case 'id3v2.2':
195  case 'id3v2.3':
196  case 'id3v2.4':
197  case 'id3v2':
198  $GETID3_ERRORARRAY = &$this->errors;
199  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, true);
200  break;
201 
202  default:
203  $this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()';
204  return false;
205  break;
206  }
207 
208  }
209 
210  // Validation of supplied data
211  if (!is_array($this->tag_data)) {
212  $this->errors[] = '$this->tag_data is not an array in WriteTags()';
213  return false;
214  }
215  // convert supplied data array keys to upper case, if they're not already
216  foreach ($this->tag_data as $tag_key => $tag_array) {
217  if (strtoupper($tag_key) !== $tag_key) {
218  $this->tag_data[strtoupper($tag_key)] = $this->tag_data[$tag_key];
219  unset($this->tag_data[$tag_key]);
220  }
221  }
222  // convert source data array keys to upper case, if they're not already
223  if (!empty($this->ThisFileInfo['tags'])) {
224  foreach ($this->ThisFileInfo['tags'] as $tag_format => $tag_data_array) {
225  foreach ($tag_data_array as $tag_key => $tag_array) {
226  if (strtoupper($tag_key) !== $tag_key) {
227  $this->ThisFileInfo['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo['tags'][$tag_format][$tag_key];
228  unset($this->ThisFileInfo['tags'][$tag_format][$tag_key]);
229  }
230  }
231  }
232  }
233 
234  // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats
235  if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) {
236  $this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK'];
237  unset($this->tag_data['TRACK']);
238  }
239 
240  // Remove all other tag formats, if requested
241  if ($this->remove_other_tags) {
242  $this->DeleteTags($TagFormatsToRemove);
243  }
244 
245  // Write data for each tag format
246  foreach ($this->tagformats as $tagformat) {
247  $success = false; // overridden if tag writing is successful
248  switch ($tagformat) {
249  case 'ape':
250  $ape_writer = new getid3_write_apetag;
251  if (($ape_writer->tag_data = $this->FormatDataForAPE()) !== false) {
252  $ape_writer->filename = $this->filename;
253  if (($success = $ape_writer->WriteAPEtag()) === false) {
254  $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>';
255  }
256  } else {
257  $this->errors[] = 'FormatDataForAPE() failed';
258  }
259  break;
260 
261  case 'id3v1':
262  $id3v1_writer = new getid3_write_id3v1;
263  if (($id3v1_writer->tag_data = $this->FormatDataForID3v1()) !== false) {
264  $id3v1_writer->filename = $this->filename;
265  if (($success = $id3v1_writer->WriteID3v1()) === false) {
266  $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>';
267  }
268  } else {
269  $this->errors[] = 'FormatDataForID3v1() failed';
270  }
271  break;
272 
273  case 'id3v2.2':
274  case 'id3v2.3':
275  case 'id3v2.4':
276  $id3v2_writer = new getid3_write_id3v2;
277  $id3v2_writer->majorversion = intval(substr($tagformat, -1));
278  $id3v2_writer->paddedlength = $this->id3v2_paddedlength;
279  if (($id3v2_writer->tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion)) !== false) {
280  $id3v2_writer->filename = $this->filename;
281  if (($success = $id3v2_writer->WriteID3v2()) === false) {
282  $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>';
283  }
284  } else {
285  $this->errors[] = 'FormatDataForID3v2() failed';
286  }
287  break;
288 
289  case 'vorbiscomment':
290  $vorbiscomment_writer = new getid3_write_vorbiscomment;
291  if (($vorbiscomment_writer->tag_data = $this->FormatDataForVorbisComment()) !== false) {
292  $vorbiscomment_writer->filename = $this->filename;
293  if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) {
294  $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>';
295  }
296  } else {
297  $this->errors[] = 'FormatDataForVorbisComment() failed';
298  }
299  break;
300 
301  case 'metaflac':
302  $metaflac_writer = new getid3_write_metaflac;
303  if (($metaflac_writer->tag_data = $this->FormatDataForMetaFLAC()) !== false) {
304  $metaflac_writer->filename = $this->filename;
305  if (($success = $metaflac_writer->WriteMetaFLAC()) === false) {
306  $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>';
307  }
308  } else {
309  $this->errors[] = 'FormatDataForMetaFLAC() failed';
310  }
311  break;
312 
313  case 'real':
314  $real_writer = new getid3_write_real;
315  if (($real_writer->tag_data = $this->FormatDataForReal()) !== false) {
316  $real_writer->filename = $this->filename;
317  if (($success = $real_writer->WriteReal()) === false) {
318  $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>';
319  }
320  } else {
321  $this->errors[] = 'FormatDataForReal() failed';
322  }
323  break;
324 
325  default:
326  $this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"';
327  return false;
328  break;
329  }
330  if (!$success) {
331  return false;
332  }
333  }
334  return true;
335 
336  }
337 
338 
339  public function DeleteTags($TagFormatsToDelete) {
340  foreach ($TagFormatsToDelete as $DeleteTagFormat) {
341  $success = false; // overridden if tag deletion is successful
342  switch ($DeleteTagFormat) {
343  case 'id3v1':
344  $id3v1_writer = new getid3_write_id3v1;
345  $id3v1_writer->filename = $this->filename;
346  if (($success = $id3v1_writer->RemoveID3v1()) === false) {
347  $this->errors[] = 'RemoveID3v1() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v1_writer->errors)).'</LI></UL></PRE>';
348  }
349  break;
350 
351  case 'id3v2':
352  $id3v2_writer = new getid3_write_id3v2;
353  $id3v2_writer->filename = $this->filename;
354  if (($success = $id3v2_writer->RemoveID3v2()) === false) {
355  $this->errors[] = 'RemoveID3v2() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v2_writer->errors)).'</LI></UL></PRE>';
356  }
357  break;
358 
359  case 'ape':
360  $ape_writer = new getid3_write_apetag;
361  $ape_writer->filename = $this->filename;
362  if (($success = $ape_writer->DeleteAPEtag()) === false) {
363  $this->errors[] = 'DeleteAPEtag() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $ape_writer->errors)).'</LI></UL></PRE>';
364  }
365  break;
366 
367  case 'vorbiscomment':
368  $vorbiscomment_writer = new getid3_write_vorbiscomment;
369  $vorbiscomment_writer->filename = $this->filename;
370  if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) {
371  $this->errors[] = 'DeleteVorbisComment() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $vorbiscomment_writer->errors)).'</LI></UL></PRE>';
372  }
373  break;
374 
375  case 'metaflac':
376  $metaflac_writer = new getid3_write_metaflac;
377  $metaflac_writer->filename = $this->filename;
378  if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) {
379  $this->errors[] = 'DeleteMetaFLAC() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $metaflac_writer->errors)).'</LI></UL></PRE>';
380  }
381  break;
382 
383  case 'lyrics3':
384  $lyrics3_writer = new getid3_write_lyrics3;
385  $lyrics3_writer->filename = $this->filename;
386  if (($success = $lyrics3_writer->DeleteLyrics3()) === false) {
387  $this->errors[] = 'DeleteLyrics3() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $lyrics3_writer->errors)).'</LI></UL></PRE>';
388  }
389  break;
390 
391  case 'real':
392  $real_writer = new getid3_write_real;
393  $real_writer->filename = $this->filename;
394  if (($success = $real_writer->RemoveReal()) === false) {
395  $this->errors[] = 'RemoveReal() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $real_writer->errors)).'</LI></UL></PRE>';
396  }
397  break;
398 
399  default:
400  $this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"';
401  return false;
402  break;
403  }
404  if (!$success) {
405  return false;
406  }
407  }
408  return true;
409  }
410 
411 
412  public function MergeExistingTagData($TagFormat, &$tag_data) {
413  // Merge supplied data with existing data, if requested
414  if ($this->overwrite_tags) {
415  // do nothing - ignore previous data
416  } else {
417 throw new Exception('$this->overwrite_tags=false is known to be buggy in this version of getID3. Will be fixed in the near future, check www.getid3.org for a newer version.');
418  if (!isset($this->ThisFileInfo['tags'][$TagFormat])) {
419  return false;
420  }
421  $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]);
422  }
423  return true;
424  }
425 
426  public function FormatDataForAPE() {
427  $ape_tag_data = array();
428  foreach ($this->tag_data as $tag_key => $valuearray) {
429  switch ($tag_key) {
430  case 'ATTACHED_PICTURE':
431  // ATTACHED_PICTURE is ID3v2 only - ignore
432  $this->warnings[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag';
433  break;
434 
435  default:
436  foreach ($valuearray as $key => $value) {
437  if (is_string($value) || is_numeric($value)) {
438  $ape_tag_data[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
439  } else {
440  $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag';
441  unset($ape_tag_data[$tag_key]);
442  break;
443  }
444  }
445  break;
446  }
447  }
448  $this->MergeExistingTagData('ape', $ape_tag_data);
449  return $ape_tag_data;
450  }
451 
452 
453  public function FormatDataForID3v1() {
454  $tag_data_id3v1['genreid'] = 255;
455  if (!empty($this->tag_data['GENRE'])) {
456  foreach ($this->tag_data['GENRE'] as $key => $value) {
457  if (getid3_id3v1::LookupGenreID($value) !== false) {
458  $tag_data_id3v1['genreid'] = getid3_id3v1::LookupGenreID($value);
459  break;
460  }
461  }
462  }
463  $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())));
464  $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())));
465  $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())));
466  $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())));
467  $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())));
468  $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()))));
469  if ($tag_data_id3v1['track'] <= 0) {
470  $tag_data_id3v1['track'] = '';
471  }
472 
473  $this->MergeExistingTagData('id3v1', $tag_data_id3v1);
474  return $tag_data_id3v1;
475  }
476 
477  public function FormatDataForID3v2($id3v2_majorversion) {
478  $tag_data_id3v2 = array();
479 
480  $ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
481  $ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
482  $ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3);
483  foreach ($this->tag_data as $tag_key => $valuearray) {
484  $ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key);
485  switch ($ID3v2_framename) {
486  case 'APIC':
487  foreach ($valuearray as $key => $apic_data_array) {
488  if (isset($apic_data_array['data']) &&
489  isset($apic_data_array['picturetypeid']) &&
490  isset($apic_data_array['description']) &&
491  isset($apic_data_array['mime'])) {
492  $tag_data_id3v2['APIC'][] = $apic_data_array;
493  } else {
494  $this->errors[] = 'ID3v2 APIC data is not properly structured';
495  return false;
496  }
497  }
498  break;
499 
500  case 'POPM':
501  if (isset($valuearray['email']) &&
502  isset($valuearray['rating']) &&
503  isset($valuearray['data'])) {
504  $tag_data_id3v2['POPM'][] = $valuearray;
505  } else {
506  $this->errors[] = 'ID3v2 POPM data is not properly structured';
507  return false;
508  }
509  break;
510 
511  case 'GRID':
512  if (
513  isset($valuearray['groupsymbol']) &&
514  isset($valuearray['ownerid']) &&
515  isset($valuearray['data'])
516  ) {
517  $tag_data_id3v2['GRID'][] = $valuearray;
518  } else {
519  $this->errors[] = 'ID3v2 GRID data is not properly structured';
520  return false;
521  }
522  break;
523 
524  case 'UFID':
525  if (isset($valuearray['ownerid']) &&
526  isset($valuearray['data'])) {
527  $tag_data_id3v2['UFID'][] = $valuearray;
528  } else {
529  $this->errors[] = 'ID3v2 UFID data is not properly structured';
530  return false;
531  }
532  break;
533 
534  case 'TXXX':
535  foreach ($valuearray as $key => $txxx_data_array) {
536  if (isset($txxx_data_array['description']) && isset($txxx_data_array['data'])) {
537  $tag_data_id3v2['TXXX'][] = $txxx_data_array;
538  } else {
539  $this->errors[] = 'ID3v2 TXXX data is not properly structured';
540  return false;
541  }
542  }
543  break;
544 
545  case '':
546  $this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type';
547  // some other data type, don't know how to handle it, ignore it
548  break;
549 
550  default:
551  // most other (text) frames can be copied over as-is
552  foreach ($valuearray as $key => $value) {
553  if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding])) {
554  // source encoding is valid in ID3v2 - use it with no conversion
555  $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding];
556  $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
557  } else {
558  // source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first
559  if ($id3v2_majorversion < 4) {
560  // convert data from other encoding to UTF-16 (with BOM)
561  // note: some software, notably Windows Media Player and iTunes are broken and treat files tagged with UTF-16BE (with BOM) as corrupt
562  // therefore we force data to UTF-16LE and manually prepend the BOM
563  $ID3v2_tag_data_converted = false;
564  if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'ISO-8859-1')) {
565  // great, leave data as-is for minimum compatability problems
566  $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0;
567  $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
568  $ID3v2_tag_data_converted = true;
569  }
570  if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'UTF-8')) {
571  do {
572  // if UTF-8 string does not include any characters above chr(127) then it is identical to ISO-8859-1
573  for ($i = 0; $i < strlen($value); $i++) {
574  if (ord($value{$i}) > 127) {
575  break 2;
576  }
577  }
578  $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0;
579  $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
580  $ID3v2_tag_data_converted = true;
581  } while (false);
582  }
583  if (!$ID3v2_tag_data_converted) {
584  $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1;
585  //$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
586  $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
587  $ID3v2_tag_data_converted = true;
588  }
589 
590  } else {
591  // convert data from other encoding to UTF-8
592  $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3;
593  $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
594  }
595  }
596 
597  // These values are not needed for all frame types, but if they're not used no matter
598  $tag_data_id3v2[$ID3v2_framename][$key]['description'] = '';
599  $tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language;
600  }
601  break;
602  }
603  }
604  $this->MergeExistingTagData('id3v2', $tag_data_id3v2);
605  return $tag_data_id3v2;
606  }
607 
608  public function FormatDataForVorbisComment() {
609  $tag_data_vorbiscomment = $this->tag_data;
610 
611  // check for multi-line comment values - split out to multiple comments if neccesary
612  // and convert data to UTF-8 strings
613  foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) {
614  foreach ($valuearray as $key => $value) {
615  str_replace("\r", "\n", $value);
616  if (strstr($value, "\n")) {
617  unset($tag_data_vorbiscomment[$tag_key][$key]);
618  $multilineexploded = explode("\n", $value);
619  foreach ($multilineexploded as $newcomment) {
620  if (strlen(trim($newcomment)) > 0) {
621  $tag_data_vorbiscomment[$tag_key][] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $newcomment);
622  }
623  }
624  } elseif (is_string($value) || is_numeric($value)) {
625  $tag_data_vorbiscomment[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
626  } else {
627  $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag';
628  unset($tag_data_vorbiscomment[$tag_key]);
629  break;
630  }
631  }
632  }
633  $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment);
634  return $tag_data_vorbiscomment;
635  }
636 
637  public function FormatDataForMetaFLAC() {
638  // FLAC & OggFLAC use VorbisComments same as OggVorbis
639  // but require metaflac to do the writing rather than vorbiscomment
640  return $this->FormatDataForVorbisComment();
641  }
642 
643  public function FormatDataForReal() {
644  $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())));
645  $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())));
646  $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())));
647  $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())));
648 
649  $this->MergeExistingTagData('real', $tag_data_real);
650  return $tag_data_real;
651  }
652 
653 }
static ID3v2ShortFrameNameLookup($majorversion, $long_description)
getID3() by James Heinrich info@getid3.org //
FormatDataForVorbisComment()
Definition: write.php:608
FormatDataForID3v1()
Definition: write.php:453
getID3() by James Heinrich info@getid3.org //
Definition: write.php:48
static LookupGenreID($genre, $allowSCMPXextended=false)
static iconv_fallback($in_charset, $out_charset, $string)
Definition: getid3.lib.php:957
static IncludeDependency($filename, $sourcefile, $DieOnFailure=false)
DeleteTags($TagFormatsToDelete)
Definition: write.php:339
getID3() by James Heinrich info@getid3.org //
$success
Definition: Utf8Test.php:86
getID3() by James Heinrich info@getid3.org //
getID3() by James Heinrich info@getid3.org //
Definition: write.real.php:17
$i
Definition: disco.tpl.php:19
FormatDataForID3v2($id3v2_majorversion)
Definition: write.php:477
FormatDataForMetaFLAC()
Definition: write.php:637
$key
Definition: croninfo.php:18
MergeExistingTagData($TagFormat, &$tag_data)
Definition: write.php:412