OSDN Git Service

Revert "FIX:プラグインに渡す引数が参照で無いためプラグインオブジェクトのイベントメソッドが呼ばれない問題を修正。"
[nucleus-jp/nucleus-next.git] / nucleus / libs / backup.php
1 <?php
2 /*
3  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
4  * Copyright (C) 2002-2009 The Nucleus Group
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  * (see nucleus/documentation/index.html#license for more info)
11  */
12 /**
13  * Scripts to create/restore a backup of the Nucleus database
14  *
15  * @license http://nucleuscms.org/license.txt GNU General Public License
16  * @copyright Copyright (C) 2002-2009 The Nucleus Group
17  * @version $Id: backup.php 1812 2012-05-01 14:59:07Z sakamocchi $
18  */
19
20 class Backup
21 {
22         /**
23          * Backup::Backup()
24          * Constructor, just for compatibility
25          *
26          * @deprecated
27          * @param       void
28          * @return      void
29          *
30          */
31         public function Backup()
32         {
33                 return;
34         }
35
36         /**
37          * Backup::do_backup()
38          * This function creates an sql dump of the database and sends it to
39          * the user as a file (can be gzipped if they want)
40          *
41          * NOTE: this remains not-static for compatibility
42          *
43          * @param boolean       $gzip   1 = compress backup file, 0 = no compression (default)
44          * @return      void
45          *
46          */
47         public function do_backup($gzip = 0)
48         {
49                 global $manager, $nucleus;
50
51                 // tables of which backup is needed
52                 $tables = array(
53                                 sql_table('actionlog'),
54                                 sql_table('ban'),
55                                 sql_table('blog'),
56                                 sql_table('comment'),
57                                 sql_table('config'),
58                                 sql_table('item'),
59                                 sql_table('karma'),
60                                 sql_table('member'),
61                                 sql_table('skin'),
62                                 sql_table('skin_desc'),
63                                 sql_table('team'),
64                                 sql_table('template'),
65                                 sql_table('template_desc'),
66                                 sql_table('plugin'),
67                                 sql_table('plugin_event'),
68                                 sql_table('plugin_option'),
69                                 sql_table('plugin_option_desc'),
70                                 sql_table('category'),
71                                 sql_table('activation'),
72                                 sql_table('tickets'),
73                 );
74
75                 // add tables that plugins want to backup to the list
76                 // catch all output generated by plugins
77                 ob_start();
78                 $query = sprintf('SELECT pfile FROM %s', sql_table('plugin'));
79                 $res = DB::getResult($query);
80                 foreach ( $res as $row )
81                 {
82                         $plug =& $manager->getPlugin($row['pfile']);
83                         if ( $plug )
84                         {
85                                 $tables = array_merge($tables, (array) $plug->getTableList());
86                         }
87                 }
88                 ob_end_clean();
89
90                 // remove duplicates
91                 $tables = array_unique($tables);
92
93                 // make sure browsers don't cache the backup
94                 header("Pragma: no-cache");
95
96                 // don't allow gzip compression when extension is not loaded
97                 if ( ($gzip != 0) && !extension_loaded("zlib") )
98                 {
99                         $gzip = 0;
100                 }
101
102                 if ( !$gzip )
103                 {
104                         $filename = 'nucleus_db_backup_' . i18n::formatted_datetime('%Y-%m-%d-%H-%M-%S', time()) . ".sql";
105                 }
106                 else
107                 {
108                         // use an output buffer
109                         @ob_start();
110                         @ob_implicit_flush(0);
111                                 
112                         // set filename
113                         $filename = 'nucleus_db_backup_' . i18n::formatted_datetime('%Y-%m-%d-%H-%M-%S', time()) . ".sql.gz";
114                 }
115
116                 // send headers that tell the browser a file is coming
117                 header("Content-Type: text/x-delimtext; name=\"$filename\"");
118                 header("Content-disposition: attachment; filename=$filename");
119
120                 // dump header
121                 echo "/*\n";
122                 echo " * This is a backup file generated by Nucleus \n";
123                 echo " * http://www.nucleuscms.org/\n";
124                 echo " * \n";
125                 echo " * backup-date: " . i18n::formatted_datetime('rfc822GMT', time()) . "\n";
126                 echo " * Nucleus CMS version: " . $nucleus['version'] . "\n";
127                 echo " * \n";
128                 echo " * WARNING: Only try to restore on servers running the exact same version of Nucleus\n";
129                 echo " */\n";
130
131                 // dump all tables
132                 reset($tables);
133                 /* NOTE: hope to use 'self' keyword here but works bad so here use __CLASS__ macro. */
134                 array_walk($tables, array(__CLASS__, 'dump_table'));
135
136                 if ( $gzip )
137                 {
138                         $Size = ob_get_length();
139                         $Crc = crc32(ob_get_contents());
140                         $contents = gzcompress(ob_get_contents());
141                         ob_end_clean();
142                         echo "\x1f\x8b\x08\x00\x00\x00\x00\x00" . substr($contents, 0, strlen($contents) - 4)
143                         . self::gzip_print_four_characters($Crc) . self::gzip_print_four_characters($Size);
144                 }
145                 exit;
146         }
147
148         /**
149          * Backup::dump_table()
150          * Creates a dump for a single table
151          * ($tablename and $key are filled in by array_walk)
152          *
153          * @static
154          * @param       string  $tablename
155          * @param       string  $key
156          */
157         static private function dump_table($tablename, $key)
158         {
159                 echo "/*\n";
160                 echo " * TABLE: " . $tablename . "\n";
161                 echo " */\n";
162
163                 // dump table structure
164                 self::dump_structure($tablename);
165
166                 // dump table contents
167                 self::dump_contents($tablename);
168                 return;
169         }
170
171         /**
172          * Backup::dump_structure()
173          * Creates a dump of the table structure for one table
174          *
175          * @static
176          * @param       string  $tablename
177          * @return      void
178          *
179          */
180         static private function dump_structure($tablename)
181         {
182                 // add command to drop table on restore
183                 echo "DROP TABLE IF EXISTS {$tablename};\n\n";
184                 $result = DB::getRow("SHOW CREATE TABLE {$tablename}");
185                 echo $result['Create Table'];
186                 echo ";\n\n";
187                 return;
188         }
189
190         /**
191          * Backup::get_field_names()
192          * Returns the field named for the given table in the
193          * following format:
194          * (column1, column2, ..., columnn)
195          *
196          * @static
197          * @param       resource        $result
198          * @param       integer $num_fields
199          * @return      string
200          */
201         static private function get_field_names($result, $num_fields)
202         {
203                 $fields = array();
204                 for ( $j = 0; $j < $num_fields; $j++ )
205                 {
206                         $col = $result->getColumnMeta($j);
207                         $fields[] = $col['name'];
208                 }
209
210                 return '(' . implode(', ', $fields) . ')';
211         }
212
213         /**
214          * Backup::dump_contents()
215          * Creates a dump of the table content for one table
216          *
217          * @static
218          * @param       string  $tablename
219          * @return      void
220          *
221          */
222         static private function dump_contents($tablename)
223         {
224                 /*
225                  * Grab the data from the table.
226                 */
227                 $result = DB::getResult("SELECT * FROM $tablename");
228
229                 if ( $result->rowCount() > 0 )
230                 {
231                         echo "\n";
232                         echo "/*\n";
233                         echo " * Table Data for {$tablename}\n";
234                         echo " */\n";
235                 }
236
237                 $num_fields = $result->columnCount();
238
239                 /*
240                  * Compose fieldname list
241                 */
242                 $tablename_list = self::get_field_names($result, $num_fields);
243
244                 /*
245                  * Loop through the resulting rows and build the sql statement.
246                 */
247                 foreach ( $result as $row )
248                 {
249                         // Start building the SQL statement.
250                         echo 'INSERT INTO ' . $tablename . ' ' . $tablename_list . ' VALUES(';
251                                 
252                         // Loop through the rows and fill in data for each column
253                         for ( $j = 0; $j < $num_fields; $j++ )
254                         {
255                                 if ( !isset($row[$j]) )
256                                 {
257                                         // no data for column
258                                         echo ' NULL';
259                                 }
260                                 elseif ( $row[$j] != '' )
261                                 {
262                                         // data
263                                         echo ' ' . DB::quoteValue($row[$j]);
264                                 }
265                                 else
266                                 {
267                                         // empty column (!= no data!)
268                                         echo "''";
269                                 }
270
271                                 // only add comma when not last column
272                                 if ( $j != ($num_fields - 1) )
273                                 {
274                                         echo ',';
275                                 }
276                         }
277                         echo ");\n";
278                 }
279                 echo "\n";
280                 return;
281         }
282
283         /**
284          * Backup::gzip_print_four_characters()
285          *
286          * @static
287          * @param       integer $val
288          * @return      integer
289          */
290         static private function gzip_print_four_characters($Val)
291         {
292                 for ( $i = 0; $i < 4; $i ++ )
293                 {
294                         $return .= chr($Val % 256);
295                         $Val = floor($Val / 256);
296                 }
297                 return $return;
298         }
299
300         /**
301          * Backup::do_restore()
302          * Restores a database backup
303          *
304          * NOTE: this remains not-static for compatibility
305          *
306          * @param       void
307          * @return      void
308          */
309         public function do_restore()
310         {
311                 $uploadInfo = postFileInfo('backup_file');
312
313                 // first of all: get uploaded file:
314                 if ( array_key_exists('name', $uploadInfo) && empty($uploadInfo['name']) )
315                 {
316                         return 'No file uploaded';
317                 }
318                 if ( !is_uploaded_file($uploadInfo['tmp_name']) )
319                 {
320                         return 'No file uploaded';
321                 }
322
323                 $backup_file_name = $uploadInfo['name'];
324                 $backup_file_tmpname = $uploadInfo['tmp_name'];
325                 $backup_file_type = $uploadInfo['type'];
326
327                 if ( !file_exists($backup_file_tmpname) )
328                 {
329                         return 'File Upload Error';
330                 }
331
332                 if ( !preg_match("#^(text/[a-zA-Z]+)|(application/(x\-)?gzip(\-compressed)?)|(application/octet-stream)$#i", $backup_file_type) )
333                 {
334                         return 'The uploaded file is not of the correct type';
335                 }
336
337                 $gzip = 0;
338                 if ( preg_match("#\.gz#i", $backup_file_name) )
339                 {
340                         $gzip = 1;
341                 }
342
343                 if ( !extension_loaded("zlib") && $gzip )
344                 {
345                         return 'Cannot decompress gzipped backup (zlib package not installed)';
346                 }
347
348                 // get sql query according to gzip setting (either decompress, or not)
349                 $contents = self::get_contents($backup_file_tmpname, $gzip);
350                 if ( $contents == '' )
351                 {
352                         return 'Cannot get contents from this file.';
353                 }
354
355                 /* detect lines */
356                 $lines = preg_split('/[\r\n]/', $contents);
357                 if( $lines === $contents )
358                 {
359                         return 'Cannot parse contents from this file';
360                 }
361
362                 /* get sql statements from each lines */
363                 $queries = self::get_queries($lines);
364                 if ( $queries === array() )
365                 {
366                         return "Cannot get SQL queries from this file.";
367                 }
368
369                 /* execute sql statements */
370                 foreach ( $queries as $query )
371                 {
372                         if ( DB::execute($query) === FALSE )
373                         {
374                                 $error = DB::getError();
375                                 debug('SQL Error: ' . $error[2]);
376                                 break;
377                         }
378                         continue;
379                 }
380                 return;
381         }
382
383         static private function get_contents($temporary_name, $gzip = 0)
384         {
385                 $contents = '';
386                 if ( $gzip )
387                 {
388                         // decompress and read
389                         $gz_ptr = gzopen($temporary_name, 'rb');
390                         while ( !gzeof($gz_ptr) )
391                         {
392                                 $contents .= gzgets($gz_ptr, 100000);
393                         }
394                 }
395                 else
396                 {
397                         // just read
398                         $fsize = filesize($temporary_name);
399                         if ( $fsize > 0 )
400                         {
401                                 $contents = fread(fopen($temporary_name, 'r'), $fsize);
402                         }
403                 }
404                 return $contents;
405         }
406
407         static private function get_queries($lines)
408         {
409                 $query = '';
410                 $queries = array();
411                 foreach ( $lines as $line )
412                 {
413                         $line = trim($line);
414                         if ( !$line || $line[0] == '#' || preg_match('#^[\s|/]?\*#', $line) )
415                         {
416                                 continue;
417                         }
418
419                         if ( preg_match('/^(.*);$/', $line, $matches) === 0 )
420                         {
421                                 $query .= $line;
422                         }
423                         else
424                         {
425                                 $query .= $matches[1];
426                                 $queries[] = $query;
427                                 $query = '';
428                         }
429                         continue;
430                 }
431                 return $queries;
432         }
433 }