source: extensions/charlies_content/getid3/getid3/write.real.php @ 3544

Last change on this file since 3544 was 3544, checked in by vdigital, 15 years ago

Change: getid3 upgraded to -> 1.7.9

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 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 $warnings     = array(); // any non-critical errors will be stored here
21        var $errors       = array(); // any critical errors will be stored here
22        var $paddedlength = 512;     // minimum length of CONT tag in bytes
23
24        function getid3_write_real() {
25                return true;
26        }
27
28        function WriteReal() {
29                // File MUST be writeable - CHMOD(646) at least
30                if (is_writeable($this->filename)) {
31                        if ($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 (@$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 (@$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 (@$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')) {
96                                                ob_start();
97                                                if ($fp_temp = fopen($tempfilename, 'wb')) {
98
99                                                        rewind($fp_source);
100                                                        fwrite($fp_temp, fread($fp_source, $BeforeOffset));
101                                                        fwrite($fp_temp, $new_CONT_tag_data);
102                                                        fseek($fp_source, $AfterOffset, SEEK_SET);
103                                                        while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
104                                                                fwrite($fp_temp, $buffer, strlen($buffer));
105                                                        }
106                                                        fclose($fp_temp);
107
108                                                        if (copy($tempfilename, $this->filename)) {
109                                                                unlink($tempfilename);
110                                                                fclose($fp_source);
111                                                                return true;
112                                                        }
113                                                        unlink($tempfilename);
114                                                        $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
115
116                                                } else {
117
118                                                        $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
119
120                                                }
121                                                ob_end_clean();
122                                        }
123                                        fclose($fp_source);
124                                        return false;
125
126                                }
127
128
129                        } else {
130                                $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
131                                return false;
132                        }
133                }
134                $this->errors[] = 'File is not writeable: '.$this->filename;
135                return false;
136        }
137
138        function GenerateRMFchunk(&$chunks) {
139                $oldCONTexists = false;
140                foreach ($chunks as $key => $chunk) {
141                        $chunkNameKeys[$chunk['name']] = $key;
142                        if ($chunk['name'] == 'CONT') {
143                                $oldCONTexists = true;
144                        }
145                }
146                $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
147
148                $RMFchunk  = "\x00\x00"; // object version
149                $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
150                $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount,                                4);
151
152                $RMFchunk  = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length
153                return $RMFchunk;
154        }
155
156        function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
157                $old_CONT_length = 0;
158                $old_DATA_offset = 0;
159                $old_INDX_offset = 0;
160                foreach ($chunks as $key => $chunk) {
161                        $chunkNameKeys[$chunk['name']] = $key;
162                        if ($chunk['name'] == 'CONT') {
163                                $old_CONT_length = $chunk['length'];
164                        } elseif ($chunk['name'] == 'DATA') {
165                                if (!$old_DATA_offset) {
166                                        $old_DATA_offset = $chunk['offset'];
167                                }
168                        } elseif ($chunk['name'] == 'INDX') {
169                                if (!$old_INDX_offset) {
170                                        $old_INDX_offset = $chunk['offset'];
171                                }
172                        }
173                }
174                $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
175
176                $PROPchunk  = "\x00\x00"; // object version
177                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'],    4);
178                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'],    4);
179                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
180                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
181                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'],     4);
182                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'],        4);
183                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'],         4);
184                $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta),              4);
185                $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta),              4);
186                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'],     2);
187                $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'],       2);
188
189                $PROPchunk  = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length
190                return $PROPchunk;
191        }
192
193        function GenerateCONTchunk() {
194                foreach ($this->tag_data as $key => $value) {
195                        // limit each value to 0xFFFF bytes
196                        $this->tag_data[$key] = substr($value, 0, 65535);
197                }
198
199                $CONTchunk  = "\x00\x00"; // object version
200
201                $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['title']), 2);
202                $CONTchunk .= @$this->tag_data['title'];
203
204                $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['artist']), 2);
205                $CONTchunk .= @$this->tag_data['artist'];
206
207                $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['copyright']), 2);
208                $CONTchunk .= @$this->tag_data['copyright'];
209
210                $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['comment']), 2);
211                $CONTchunk .= @$this->tag_data['comment'];
212
213                if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
214                        $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
215                }
216
217                $CONTchunk  = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length
218
219                return $CONTchunk;
220        }
221
222        function RemoveReal() {
223                // File MUST be writeable - CHMOD(646) at least
224                if (is_writeable($this->filename)) {
225                        if ($fp_source = @fopen($this->filename, 'r+b')) {
226
227                                // Initialize getID3 engine
228                                $getID3 = new getID3;
229                                $OldThisFileInfo = $getID3->analyze($this->filename);
230                                if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
231                                        $this->errors[] = 'Cannot remove Real tags from old-style file format';
232                                        fclose($fp_source);
233                                        return false;
234                                }
235
236                                if (empty($OldThisFileInfo['real']['chunks'])) {
237                                        $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
238                                        fclose($fp_source);
239                                        return false;
240                                }
241                                foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
242                                        $oldChunkInfo[$chunkarray['name']] = $chunkarray;
243                                }
244
245                                if (empty($oldChunkInfo['CONT'])) {
246                                        // no existing CONT chunk
247                                        fclose($fp_source);
248                                        return true;
249                                }
250
251                                $BeforeOffset = $oldChunkInfo['CONT']['offset'];
252                                $AfterOffset  = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
253                                if ($tempfilename = tempnam('*', 'getID3')) {
254                                        ob_start();
255                                        if ($fp_temp = fopen($tempfilename, 'wb')) {
256
257                                                rewind($fp_source);
258                                                fwrite($fp_temp, fread($fp_source, $BeforeOffset));
259                                                fseek($fp_source, $AfterOffset, SEEK_SET);
260                                                while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
261                                                        fwrite($fp_temp, $buffer, strlen($buffer));
262                                                }
263                                                fclose($fp_temp);
264
265                                                if (copy($tempfilename, $this->filename)) {
266                                                        unlink($tempfilename);
267                                                        fclose($fp_source);
268                                                        return true;
269                                                }
270                                                unlink($tempfilename);
271                                                $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
272
273                                        } else {
274
275                                                $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
276
277                                        }
278                                        ob_end_clean();
279                                }
280                                fclose($fp_source);
281                                return false;
282
283
284                        } else {
285                                $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
286                                return false;
287                        }
288                }
289                $this->errors[] = 'File is not writeable: '.$this->filename;
290                return false;
291        }
292
293}
294
295?>
Note: See TracBrowser for help on using the repository browser.