OSDN Git Service

added NP_SkinFiles
[nucleus-jp/nucleus-jp-ancient.git] / euc / nucleus / libs / backup.php
1 <?php\r
2 /**\r
3   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) \r
4   * Copyright (C) 2002-2005 The Nucleus Group\r
5   *\r
6   * This program is free software; you can redistribute it and/or\r
7   * modify it under the terms of the GNU General Public License\r
8   * as published by the Free Software Foundation; either version 2\r
9   * of the License, or (at your option) any later version.\r
10   * (see nucleus/documentation/index.html#license for more info)\r
11   *\r
12   * Scripts to create/restore a backup of the Nucleus database\r
13   *\r
14   * Based on code in phpBB (http://phpBB.sourceforge.net)\r
15   *\r
16   * $Id: backup.php,v 1.3 2005-03-16 08:10:35 kimitake Exp $\r
17   * $NucleusJP: backup.php,v 1.3 2005/03/12 06:19:05 kimitake Exp $\r
18   */\r
19 \r
20  \r
21 /**\r
22   * This function creates an sql dump of the database and sends it to\r
23   * the user as a file (can be gzipped if they want)\r
24   *\r
25   * @requires \r
26   *             no output may have preceded (new headers are sent)\r
27   * @param gzip \r
28   *             1 = compress backup file, 0 = no compression (default)\r
29   */\r
30 function do_backup($gzip = 0) {\r
31         global $manager;\r
32 \r
33         // tables of which backup is needed\r
34         $tables = array(\r
35                                         sql_table('actionlog'),\r
36                                         sql_table('ban'),\r
37                                         sql_table('blog'),\r
38                                         sql_table('comment'),\r
39                                         sql_table('config'),\r
40                                         sql_table('item'),\r
41                                         sql_table('karma'),\r
42                                         sql_table('member'),\r
43                                         sql_table('skin'),\r
44                                         sql_table('skin_desc'),\r
45                                         sql_table('team'),\r
46                                         sql_table('template'),\r
47                                         sql_table('template_desc'),\r
48                                         sql_table('plugin'),\r
49                                         sql_table('plugin_event'),\r
50                                         sql_table('plugin_option'),\r
51                                         sql_table('plugin_option_desc'),\r
52                                         sql_table('category'),\r
53                                         sql_table('activation'),\r
54                                         sql_table('tickets'),\r
55                           );\r
56 \r
57         // add tables that plugins want to backup to the list\r
58         // catch all output generated by plugins\r
59         ob_start();\r
60         $res = sql_query('SELECT pfile FROM '.sql_table('plugin'));\r
61         while ($plugName = mysql_fetch_object($res)) {\r
62                 $plug =& $manager->getPlugin($plugName->pfile);\r
63                 if ($plug) $tables = array_merge($tables, $plug->getTableList());\r
64         }\r
65         ob_end_clean();\r
66                 \r
67         // remove duplicates\r
68         $tables = array_unique($tables);\r
69                           \r
70         // make sure browsers don't cache the backup\r
71         header("Pragma: no-cache");\r
72         \r
73         // don't allow gzip compression when extension is not loaded\r
74         if (($gzip != 0) && !extension_loaded("zlib"))\r
75                 $gzip = 0;\r
76                 \r
77         \r
78 \r
79         if ($gzip) {\r
80                 // use an output buffer\r
81                 @ob_start();\r
82                 @ob_implicit_flush(0);\r
83                 \r
84                 // set filename\r
85                 $filename = 'nucleus_db_backup_'.strftime("%Y%m%d", time()).".sql.gz";\r
86         } else {\r
87                 $filename = 'nucleus_db_backup_'.strftime("%Y%m%d", time()).".sql";\r
88         }\r
89         \r
90         \r
91         // send headers that tell the browser a file is coming\r
92         header("Content-Type: text/x-delimtext; name=\"$filename\"");\r
93         header("Content-disposition: attachment; filename=$filename");\r
94                 \r
95         // dump header\r
96         echo "#\n";\r
97         echo "# This is a backup file generated by Nucleus \n";\r
98         echo "# http://www.nucleuscms.org/\n";\r
99         echo "#\n";\r
100         echo "# backup-date: " .  gmdate("d-m-Y H:i:s", time()) . " GMT\n";\r
101         global $nucleus;\r
102         echo "# Nucleus CMS version: " . $nucleus['version'] . "\n";    \r
103         echo "#\n";\r
104         echo "# WARNING: Only try to restore on servers running the exact same version of Nucleus\n";\r
105         echo "#\n";\r
106         \r
107         // dump all tables\r
108         reset($tables);\r
109         array_walk($tables, '_backup_dump_table');\r
110         \r
111         if($gzip)\r
112         {\r
113                 $Size = ob_get_length();\r
114                 $Crc = crc32(ob_get_contents());\r
115                 $contents = gzcompress(ob_get_contents());\r
116                 ob_end_clean();\r
117                 echo "\x1f\x8b\x08\x00\x00\x00\x00\x00".substr($contents, 0, strlen($contents) - 4).gzip_PrintFourChars($Crc).gzip_PrintFourChars($Size);\r
118         }\r
119         \r
120         exit;\r
121 \r
122 }\r
123 \r
124 \r
125 /**\r
126   * Creates a dump for a single table\r
127   * ($tablename and $key are filled in by array_walk)\r
128   */\r
129 function _backup_dump_table($tablename, $key) {\r
130 \r
131         echo "#\n";\r
132         echo "# TABLE: " . $tablename . "\n";\r
133         echo "#\n";\r
134         \r
135         // dump table structure\r
136         _backup_dump_structure($tablename);\r
137 \r
138         // dump table contents\r
139         _backup_dump_contents($tablename);\r
140 }\r
141 \r
142 function _backup_dump_structure($tablename) {\r
143         \r
144         // add command to drop table on restore\r
145         echo "DROP TABLE IF EXISTS $tablename;\n";\r
146         echo "CREATE TABLE $tablename(\n";\r
147 \r
148         //\r
149         // Ok lets grab the fields...\r
150         //\r
151         $result = mysql_query("SHOW FIELDS FROM $tablename");\r
152         $row = mysql_fetch_array($result);\r
153         while ($row) {\r
154 \r
155                 echo '  ' . $row['Field'] . ' ' . $row['Type'];\r
156 \r
157                 if(!empty($row['Default']))\r
158                         echo ' DEFAULT \'' . $row['Default'] . '\'';\r
159 \r
160                 if($row['Null'] != "YES")\r
161                         echo ' NOT NULL';\r
162 \r
163                 if($row['Extra'] != "")\r
164                         echo ' ' . $row['Extra'];\r
165 \r
166                 $row = mysql_fetch_array($result);\r
167 \r
168                 // add comma's except for last one\r
169                 if ($row)\r
170                         echo ",\n";\r
171         }\r
172 \r
173         //\r
174         // Get any Indexed fields from the database...\r
175         //\r
176         $result = mysql_query("SHOW KEYS FROM $tablename");\r
177         while($row = mysql_fetch_array($result)) {\r
178                 $kname = $row['Key_name'];\r
179 \r
180                 if(($kname != 'PRIMARY') && ($row['Non_unique'] == 0))\r
181                         $kname = "UNIQUE|$kname";\r
182                 if(($kname != 'PRIMARY') && ($row['Index_type'] == 'FULLTEXT'))\r
183                         $kname = "FULLTEXT|$kname";\r
184                         \r
185                 if(!is_array($index[$kname]))\r
186                         $index[$kname] = array();\r
187         \r
188                 $index[$kname][] = $row['Column_name'];\r
189         }\r
190 \r
191         while(list($x, $columns) = @each($index)) {\r
192                 echo ", \n";\r
193 \r
194                 if($x == 'PRIMARY')\r
195                         echo '  PRIMARY KEY (' . implode($columns, ', ') . ')';\r
196                 elseif (substr($x,0,6) == 'UNIQUE')\r
197                         echo '  UNIQUE KEY ' . substr($x,7) . ' (' . implode($columns, ', ') . ')';\r
198                 elseif (substr($x,0,8) == 'FULLTEXT')\r
199                         echo '  FULLTEXT KEY ' . substr($x,9) . ' (' . implode($columns, ', ') . ')';\r
200                 elseif (($x == 'ibody') || ($x == 'cbody'))                     // karma 2004-05-30 quick and dirty fix. fulltext keys were not in SQL correctly.\r
201                         echo '  FULLTEXT KEY ' . substr($x,9) . ' (' . implode($columns, ', ') . ')';                   \r
202                 else \r
203                         echo "  KEY $x (" . implode($columns, ', ') . ')';\r
204         }\r
205 \r
206         echo "\n);\n\n";\r
207 }\r
208 \r
209 function _backup_dump_contents($tablename) {\r
210         //\r
211         // Grab the data from the table.\r
212         //\r
213         $result = mysql_query("SELECT * FROM $tablename");\r
214 \r
215         if(mysql_numrows($result) > 0)\r
216                 echo "\n#\n# Table Data for $tablename\n#\n";\r
217 \r
218         //\r
219         // Loop through the resulting rows and build the sql statement.\r
220         //\r
221         while ($row = mysql_fetch_array($result))\r
222         {\r
223                 $tablename_list = '(';\r
224                 $num_fields = mysql_num_fields($result);\r
225 \r
226                 //\r
227                 // Grab the list of field names.\r
228                 //\r
229                 for ($j = 0; $j < $num_fields; $j++)\r
230                         $tablename_list .= mysql_field_name($result, $j) . ', ';\r
231 \r
232                 //\r
233                 // Get rid of the last comma\r
234                 //\r
235                 $tablename_list = ereg_replace(', $', '', $tablename_list);\r
236                 $tablename_list .= ')';\r
237 \r
238                 // Start building the SQL statement.\r
239 \r
240                 echo "INSERT INTO $tablename $tablename_list VALUES(";\r
241 \r
242                 // Loop through the rows and fill in data for each column\r
243                 for ($j = 0; $j < $num_fields; $j++) {\r
244                         if(!isset($row[$j])) {\r
245                                 // no data for column\r
246                                 echo ' NULL';\r
247                         } elseif ($row[$j] != '') {\r
248                                 // data\r
249                                 echo " '" . addslashes($row[$j]) . "'";\r
250                         } else {\r
251                                 // empty column (!= no data!)\r
252                                 echo "''";\r
253                         }\r
254 \r
255                         // only add comma when not last column\r
256                         if ($j != ($num_fields - 1))\r
257                                 echo ",";\r
258                 }\r
259 \r
260                 echo ");\n";\r
261 \r
262         }\r
263         \r
264         \r
265         echo "\n";\r
266 \r
267 }\r
268 \r
269 // copied from phpBB\r
270 function gzip_PrintFourChars($Val)\r
271 {\r
272         for ($i = 0; $i < 4; $i ++)\r
273         {\r
274                 $return .= chr($Val % 256);\r
275                 $Val = floor($Val / 256);\r
276         }\r
277         return $return;\r
278\r
279 \r
280 function do_restore() {\r
281         \r
282         $uploadInfo = postFileInfo('backup_file');\r
283         \r
284         // first of all: get uploaded file:\r
285         if (empty($uploadInfo['name']))\r
286                 return 'No file uploaded';\r
287         if (!is_uploaded_file($uploadInfo['tmp_name']))\r
288                 return 'No file uploaded';\r
289                 \r
290         $backup_file_name = $uploadInfo['name'];\r
291         $backup_file_tmpname = $uploadInfo['tmp_name'];\r
292         $backup_file_type = $uploadInfo['type'];\r
293 \r
294         if (!file_exists($backup_file_tmpname))\r
295                 return 'File Upload Error';\r
296         \r
297         if (!preg_match("/^(text\/[a-zA-Z]+)|(application\/(x\-)?gzip(\-compressed)?)|(application\/octet-stream)$/is", $backup_file_type) )\r
298                 return 'The uploaded file is not of the correct type';\r
299                 \r
300                 \r
301         \r
302         if (preg_match("/\.gz/is",$backup_file_name)) \r
303                 $gzip = 1;\r
304         else\r
305                 $gzip = 0;\r
306                 \r
307         if (!extension_loaded("zlib") && $gzip)\r
308                 return "Cannot decompress gzipped backup (zlib package not installed)";\r
309 \r
310         // get sql query according to gzip setting (either decompress, or not)\r
311         if($gzip)\r
312         {\r
313                 // decompress and read\r
314                 $gz_ptr = gzopen($backup_file_tmpname, 'rb');\r
315                 $sql_query = "";\r
316                 while( !gzeof($gz_ptr) )\r
317                         $sql_query .= gzgets($gz_ptr, 100000);\r
318         } else {\r
319                 // just read\r
320                 $fsize = filesize($backup_file_tmpname);\r
321                 if ($fsize <= 0)\r
322                         $sql_query = '';\r
323                 else\r
324                         $sql_query = fread(fopen($backup_file_tmpname, 'r'), $fsize);\r
325         }\r
326 \r
327         // time to execute the query\r
328         _execute_queries($sql_query);\r
329 }\r
330 \r
331 function _execute_queries($sql_query) {\r
332         if (!$sql_query) return;\r
333 \r
334         // Strip out sql comments...\r
335         $sql_query = remove_remarks($sql_query);\r
336         $pieces = split_sql_file($sql_query);\r
337 \r
338         $sql_count = count($pieces);\r
339         for($i = 0; $i < $sql_count; $i++)\r
340         {\r
341                 $sql = trim($pieces[$i]);\r
342 \r
343                 if(!empty($sql) and $sql[0] != "#")\r
344                 {\r
345                         // DEBUG\r
346 //                      debug("Executing: " . htmlspecialchars($sql) . "\n");\r
347 \r
348                         $result = mysql_query($sql);\r
349                         if (!$result) debug("SQL Error: " + mysql_error());\r
350 \r
351                 }\r
352         }\r
353 \r
354 }\r
355 \r
356 //\r
357 // remove_remarks will strip the sql comment lines out of an uploaded sql file\r
358 //\r
359 function remove_remarks($sql)\r
360 {\r
361         $lines = explode("\n", $sql);\r
362         \r
363         // try to keep mem. use down\r
364         $sql = "";\r
365         \r
366         $linecount = count($lines);\r
367         $output = "";\r
368 \r
369         for ($i = 0; $i < $linecount; $i++)\r
370         {\r
371                 if (($i != ($linecount - 1)) || (strlen($lines[$i]) > 0))\r
372                 {\r
373                         if ($lines[$i][0] != "#")\r
374                         {\r
375                                 $output .= $lines[$i] . "\n";\r
376                         }\r
377                         else\r
378                         {\r
379                                 $output .= "\n";\r
380                         }\r
381                         // Trading a bit of speed for lower mem. use here.\r
382                         $lines[$i] = "";\r
383                 }\r
384         }\r
385         \r
386         return $output;\r
387         \r
388 }\r
389 \r
390 \r
391 //\r
392 // split_sql_file will split an uploaded sql file into single sql statements.\r
393 // Note: expects trim() to have already been run on $sql.\r
394 //\r
395 // taken from phpBB\r
396 //\r
397 function split_sql_file($sql)\r
398 {\r
399         // Split up our string into "possible" SQL statements.\r
400         $tokens = explode( ";", $sql);\r
401 \r
402         // try to save mem.\r
403         $sql = "";\r
404         $output = array();\r
405         \r
406         // we don't actually care about the matches preg gives us.\r
407         $matches = array();\r
408         \r
409         // this is faster than calling count($tokens) every time thru the loop.\r
410         $token_count = count($tokens);\r
411         for ($i = 0; $i < $token_count; $i++)\r
412         {\r
413                 // Don't wanna add an empty string as the last thing in the array.\r
414                 if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0)))\r
415                 {\r
416                         \r
417                         // even number of quotes means a complete SQL statement\r
418                         if (_evenNumberOfQuotes($tokens[$i]))\r
419                         {\r
420                                 $output[] = $tokens[$i];\r
421                                 $tokens[$i] = "";       // save memory.\r
422                         }\r
423                         else\r
424                         {\r
425                                 // incomplete sql statement. keep adding tokens until we have a complete one.\r
426                                 // $temp will hold what we have so far.\r
427                                 $temp = $tokens[$i] .  ";";\r
428                                 $tokens[$i] = "";       // save memory..\r
429                                 \r
430                                 // Do we have a complete statement yet? \r
431                                 $complete_stmt = false;\r
432                                 \r
433                                 for ($j = $i + 1; (!$complete_stmt && ($j < $token_count)); $j++)\r
434                                 {\r
435                                         // odd number of quotes means a completed statement \r
436                                         // (in combination with the odd number we had already)\r
437                                         if (!_evenNumberOfQuotes($tokens[$j]))\r
438                                         {\r
439                                                 $output[] = $temp . $tokens[$j];\r
440 \r
441                                                 // save memory.\r
442                                                 $tokens[$j] = "";\r
443                                                 $temp = "";\r
444                                                 \r
445                                                 // exit the loop.\r
446                                                 $complete_stmt = true;\r
447                                                 // make sure the outer loop continues at the right point.\r
448                                                 $i = $j;\r
449                                         }\r
450                                         else\r
451                                         {\r
452                                                 // even number of unescaped quotes. We still don't have a complete statement. \r
453                                                 // (1 odd and 1 even always make an odd)\r
454                                                 $temp .= $tokens[$j] .  ";";\r
455                                                 // save memory.\r
456                                                 $tokens[$j] = "";\r
457                                         }\r
458                                         \r
459                                 } // for..\r
460                         } // else\r
461                 }\r
462         }\r
463 \r
464         return $output;\r
465 }\r
466 \r
467 \r
468 function _evenNumberOfQuotes($text) {\r
469                 // This is the total number of single quotes in the token.\r
470                 $total_quotes = preg_match_all("/'/", $text, $matches);\r
471                 // Counts single quotes that are preceded by an odd number of backslashes, \r
472                 // which means they're escaped quotes.\r
473                 $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $text, $matches);\r
474 \r
475                 $unescaped_quotes = $total_quotes - $escaped_quotes;\r
476 //              debug($total_quotes . "-" . $escaped_quotes . "-" . $unescaped_quotes);\r
477                 return (($unescaped_quotes % 2) == 0);\r
478 }\r
479 \r
480 ?>\r