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