source: spip-zone/_plugins_/getID3/getid3/write.real.php @ 51852

Last change on this file since 51852 was 51852, checked in by kent1@…, 9 years ago

Mise à jour de getid3 en 1.9.0-20110620 (nécessite PHP 5)

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