source: spip-zone/_core_/branches/spip-3.1/plugins/medias/lib/getid3/write.php @ 113163

Last change on this file since 113163 was 113163, checked in by spip.franck@…, 7 months ago

Mise à jour de la lib getid en version 1.9.16, nous étions en 1.9.12
https://github.com/JamesHeinrich/getID3/blob/master/changelog.txt

File size: 27.7 KB
Line 
1<?php
2
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/////////////////////////////////////////////////////////////////
10///                                                            //
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//                                                            ///
21/////////////////////////////////////////////////////////////////
22
23if (!defined('GETID3_INCLUDEPATH')) {
24        throw new Exception('getid3.php MUST be included before calling getid3_writetags');
25}
26if (!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 * 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
44 *
45 * @link http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
46 */
47class getid3_writetags
48{
49        /**
50         * Absolute filename of file to write tags to.
51         *
52         * @var string
53         */
54        public $filename;
55
56        /**
57         * Array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment',
58         * 'metaflac', 'real').
59         *
60         * @var array
61         */
62        public $tagformats         = array();
63
64        /**
65         * 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis').
66         *
67         * @var array
68         */
69        public $tag_data           = array(array());
70
71        /**
72         * Text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', ).
73         *
74         * @var string
75         */
76        public $tag_encoding       = 'ISO-8859-1';
77
78        /**
79         * If true will erase existing tag data and write only passed data; if false will merge passed data
80         * with existing tag data.
81         *
82         * @var bool
83         */
84        public $overwrite_tags     = true;
85
86        /**
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.
89         *
90         * @var bool
91         */
92        public $remove_other_tags  = false;
93
94        /**
95         * ISO-639-2 3-character language code needed for some ID3v2 frames.
96         *
97         * @link http://www.id3.org/iso639-2.html
98         *
99         * @var string
100         */
101        public $id3v2_tag_language = 'eng';
102
103        /**
104         * Minimum length of ID3v2 tags (will be padded to this length if tag data is shorter).
105         *
106         * @var int
107         */
108        public $id3v2_paddedlength = 4096;
109
110        /**
111         * Any non-critical errors will be stored here.
112         *
113         * @var array
114         */
115        public $warnings           = array();
116
117        /**
118         * Any critical errors will be stored here.
119         *
120         * @var array
121         */
122        public $errors             = array();
123
124        /**
125         * Analysis of file before writing.
126         *
127         * @var array
128         */
129        private $ThisFileInfo;
130
131        public function __construct() {
132        }
133
134        /**
135         * @return bool
136         */
137        public function WriteTags() {
138
139                if (empty($this->filename)) {
140                        $this->errors[] = 'filename is undefined in getid3_writetags';
141                        return false;
142                } elseif (!file_exists($this->filename)) {
143                        $this->errors[] = 'filename set to non-existant file "'.$this->filename.'" in getid3_writetags';
144                        return false;
145                }
146
147                if (!is_array($this->tagformats)) {
148                        $this->errors[] = 'tagformats must be an array in getid3_writetags';
149                        return false;
150                }
151                // prevent duplicate tag formats
152                $this->tagformats = array_unique($this->tagformats);
153
154                // prevent trying to specify more than one version of ID3v2 tag to write simultaneously
155                $id3typecounter = 0;
156                foreach ($this->tagformats as $tagformat) {
157                        if (substr(strtolower($tagformat), 0, 6) == 'id3v2.') {
158                                $id3typecounter++;
159                        }
160                }
161                if ($id3typecounter > 1) {
162                        $this->errors[] = 'tagformats must not contain more than one version of ID3v2';
163                        return false;
164                }
165
166                $TagFormatsToRemove = array();
167                $AllowedTagFormats = array();
168                if (filesize($this->filename) == 0) {
169
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');
174
175                } else {
176
177                        $getID3 = new getID3;
178                        $getID3->encoding = $this->tag_encoding;
179                        $this->ThisFileInfo = $getID3->analyze($this->filename);
180
181                        // check for what file types are allowed on this fileformat
182                        switch (isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : '') {
183                                case 'mp3':
184                                case 'mp2':
185                                case 'mp1':
186                                case 'riff': // maybe not officially, but people do it anyway
187                                        $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
188                                        break;
189
190                                case 'mpc':
191                                        $AllowedTagFormats = array('ape');
192                                        break;
193
194                                case 'flac':
195                                        $AllowedTagFormats = array('metaflac');
196                                        break;
197
198                                case 'real':
199                                        $AllowedTagFormats = array('real');
200                                        break;
201
202                                case 'ogg':
203                                        switch (isset($this->ThisFileInfo['audio']['dataformat']) ? $this->ThisFileInfo['audio']['dataformat'] : '') {
204                                                case 'flac':
205                                                        //$AllowedTagFormats = array('metaflac');
206                                                        $this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files';
207                                                        return false;
208                                                        break;
209                                                case 'vorbis':
210                                                        $AllowedTagFormats = array('vorbiscomment');
211                                                        break;
212                                                default:
213                                                        $this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis';
214                                                        return false;
215                                                        break;
216                                        }
217                                        break;
218
219                                default:
220                                        $AllowedTagFormats = array();
221                                        break;
222                        }
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;
229                                        return false;
230                                }
231                        }
232
233                        // List of other tag formats, removed if requested
234                        if ($this->remove_other_tags) {
235                                foreach ($AllowedTagFormats as $AllowedTagFormat) {
236                                        switch ($AllowedTagFormat) {
237                                                case 'id3v2.2':
238                                                case 'id3v2.3':
239                                                case 'id3v2.4':
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';
242                                                        }
243                                                        break;
244
245                                                default:
246                                                        if (!in_array($AllowedTagFormat, $this->tagformats)) {
247                                                                $TagFormatsToRemove[] = $AllowedTagFormat;
248                                                        }
249                                                        break;
250                                        }
251                                }
252                        }
253                }
254
255                $WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove);
256
257                // Check for required include files and include them
258                foreach ($WritingFilesToInclude as $tagformat) {
259                        switch ($tagformat) {
260                                case 'ape':
261                                        $GETID3_ERRORARRAY = &$this->errors;
262                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, true);
263                                        break;
264
265                                case 'id3v1':
266                                case 'lyrics3':
267                                case 'vorbiscomment':
268                                case 'metaflac':
269                                case 'real':
270                                        $GETID3_ERRORARRAY = &$this->errors;
271                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, true);
272                                        break;
273
274                                case 'id3v2.2':
275                                case 'id3v2.3':
276                                case 'id3v2.4':
277                                case 'id3v2':
278                                        $GETID3_ERRORARRAY = &$this->errors;
279                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, true);
280                                        break;
281
282                                default:
283                                        $this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()';
284                                        return false;
285                                        break;
286                        }
287
288                }
289
290                // Validation of supplied data
291                if (!is_array($this->tag_data)) {
292                        $this->errors[] = '$this->tag_data is not an array in WriteTags()';
293                        return false;
294                }
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]);
300                        }
301                }
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]);
309                                        }
310                                }
311                        }
312                }
313
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']);
318                }
319
320                // Remove all other tag formats, if requested
321                if ($this->remove_other_tags) {
322                        $this->DeleteTags($TagFormatsToRemove);
323                }
324
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) {
329                                case 'ape':
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>';
335                                                }
336                                        } else {
337                                                $this->errors[] = 'FormatDataForAPE() failed';
338                                        }
339                                        break;
340
341                                case 'id3v1':
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>';
347                                                }
348                                        } else {
349                                                $this->errors[] = 'FormatDataForID3v1() failed';
350                                        }
351                                        break;
352
353                                case 'id3v2.2':
354                                case 'id3v2.3':
355                                case 'id3v2.4':
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>';
366                                                }
367                                        } else {
368                                                $this->errors[] = 'FormatDataForID3v2() failed';
369                                        }
370                                        break;
371
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>';
378                                                }
379                                        } else {
380                                                $this->errors[] = 'FormatDataForVorbisComment() failed';
381                                        }
382                                        break;
383
384                                case 'metaflac':
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>';
390                                                }
391                                        } else {
392                                                $this->errors[] = 'FormatDataForMetaFLAC() failed';
393                                        }
394                                        break;
395
396                                case 'real':
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>';
402                                                }
403                                        } else {
404                                                $this->errors[] = 'FormatDataForReal() failed';
405                                        }
406                                        break;
407
408                                default:
409                                        $this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"';
410                                        return false;
411                                        break;
412                        }
413                        if (!$success) {
414                                return false;
415                        }
416                }
417                return true;
418
419        }
420
421        /**
422         * @param string[] $TagFormatsToDelete
423         *
424         * @return bool
425         */
426        public function DeleteTags($TagFormatsToDelete) {
427                foreach ($TagFormatsToDelete as $DeleteTagFormat) {
428                        $success = false; // overridden if tag deletion is successful
429                        switch ($DeleteTagFormat) {
430                                case 'id3v1':
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>';
435                                        }
436                                        break;
437
438                                case 'id3v2':
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>';
443                                        }
444                                        break;
445
446                                case 'ape':
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>';
451                                        }
452                                        break;
453
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>';
459                                        }
460                                        break;
461
462                                case 'metaflac':
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>';
467                                        }
468                                        break;
469
470                                case 'lyrics3':
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>';
475                                        }
476                                        break;
477
478                                case 'real':
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>';
483                                        }
484                                        break;
485
486                                default:
487                                        $this->errors[] = 'Invalid tag format to delete: "'.$DeleteTagFormat.'"';
488                                        return false;
489                                        break;
490                        }
491                        if (!$success) {
492                                return false;
493                        }
494                }
495                return true;
496        }
497
498        /**
499         * @param string $TagFormat
500         * @param array  $tag_data
501         *
502         * @return bool
503         * @throws Exception
504         */
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
509                } else {
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])) {
512                                return false;
513                        }
514                        $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]);
515                }
516                return true;
517        }
518
519        /**
520         * @return array
521         */
522        public function FormatDataForAPE() {
523                $ape_tag_data = array();
524                foreach ($this->tag_data as $tag_key => $valuearray) {
525                        switch ($tag_key) {
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';
529                                        break;
530
531                                default:
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);
535                                                } else {
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]);
538                                                        break;
539                                                }
540                                        }
541                                        break;
542                        }
543                }
544                $this->MergeExistingTagData('ape', $ape_tag_data);
545                return $ape_tag_data;
546        }
547
548        /**
549         * @return array
550         */
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);
558                                        break;
559                                }
560                        }
561                }
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'] = '';
570                }
571
572                $this->MergeExistingTagData('id3v1', $tag_data_id3v1);
573                return $tag_data_id3v1;
574        }
575
576        /**
577         * @param int $id3v2_majorversion
578         *
579         * @return array|false
580         */
581        public function FormatDataForID3v2($id3v2_majorversion) {
582                $tag_data_id3v2 = array();
583
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) {
590                                case 'APIC':
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;
597                                                } else {
598                                                        $this->errors[] = 'ID3v2 APIC data is not properly structured';
599                                                        return false;
600                                                }
601                                        }
602                                        break;
603
604                                case 'POPM':
605                                        if (isset($valuearray['email']) &&
606                                                isset($valuearray['rating']) &&
607                                                isset($valuearray['data'])) {
608                                                        $tag_data_id3v2['POPM'][] = $valuearray;
609                                        } else {
610                                                $this->errors[] = 'ID3v2 POPM data is not properly structured';
611                                                return false;
612                                        }
613                                        break;
614
615                                case 'GRID':
616                                        if (
617                                                isset($valuearray['groupsymbol']) &&
618                                                isset($valuearray['ownerid']) &&
619                                                isset($valuearray['data'])
620                                        ) {
621                                                        $tag_data_id3v2['GRID'][] = $valuearray;
622                                        } else {
623                                                $this->errors[] = 'ID3v2 GRID data is not properly structured';
624                                                return false;
625                                        }
626                                        break;
627
628                                case 'UFID':
629                                        if (isset($valuearray['ownerid']) &&
630                                                isset($valuearray['data'])) {
631                                                        $tag_data_id3v2['UFID'][] = $valuearray;
632                                        } else {
633                                                $this->errors[] = 'ID3v2 UFID data is not properly structured';
634                                                return false;
635                                        }
636                                        break;
637
638                                case 'TXXX':
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;
642                                                } else {
643                                                        $this->errors[] = 'ID3v2 TXXX data is not properly structured';
644                                                        return false;
645                                                }
646                                        }
647                                        break;
648
649                                case '':
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
652                                        break;
653
654                                default:
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;
661                                                } else {
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;
673                                                                }
674                                                                if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'UTF-8')) {
675                                                                        do {
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) {
679                                                                                                break 2;
680                                                                                        }
681                                                                                }
682                                                                                $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0;
683                                                                                $tag_data_id3v2[$ID3v2_framename][$key]['data']       = $value;
684                                                                                $ID3v2_tag_data_converted = true;
685                                                                        } while (false);
686                                                                }
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;
692                                                                }
693
694                                                        } else {
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);
698                                                        }
699                                                }
700
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;
704                                        }
705                                        break;
706                        }
707                }
708                $this->MergeExistingTagData('id3v2', $tag_data_id3v2);
709                return $tag_data_id3v2;
710        }
711
712        /**
713         * @return array
714         */
715        public function FormatDataForVorbisComment() {
716                $tag_data_vorbiscomment = $this->tag_data;
717
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
724                                } else {
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);
732                                                        }
733                                                }
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);
736                                        } else {
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]);
739                                                break;
740                                        }
741                                }
742                        }
743                }
744                $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment);
745                return $tag_data_vorbiscomment;
746        }
747
748        /**
749         * @return array
750         */
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();
755        }
756
757        /**
758         * @return array
759         */
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())));
765
766                $this->MergeExistingTagData('real', $tag_data_real);
767                return $tag_data_real;
768        }
769
770}
Note: See TracBrowser for help on using the repository browser.