[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 /** 15 * @ignore 16 */ 17 if (!defined('IN_PHPBB')) 18 { 19 exit; 20 } 21 22 class acp_database 23 { 24 var $db_tools; 25 var $u_action; 26 27 function main($id, $mode) 28 { 29 global $cache, $db, $user, $auth, $template, $table_prefix; 30 global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; 31 32 $this->db_tools = new \phpbb\db\tools($db); 33 34 $user->add_lang('acp/database'); 35 36 $this->tpl_name = 'acp_database'; 37 $this->page_title = 'ACP_DATABASE'; 38 39 $action = request_var('action', ''); 40 $submit = (isset($_POST['submit'])) ? true : false; 41 42 $form_key = 'acp_database'; 43 add_form_key($form_key); 44 45 $template->assign_vars(array( 46 'MODE' => $mode 47 )); 48 49 switch ($mode) 50 { 51 case 'backup': 52 53 $this->page_title = 'ACP_BACKUP'; 54 55 switch ($action) 56 { 57 case 'download': 58 $type = request_var('type', ''); 59 $table = array_intersect($this->db_tools->sql_list_tables(), request_var('table', array(''))); 60 $format = request_var('method', ''); 61 $where = request_var('where', ''); 62 63 if (!sizeof($table)) 64 { 65 trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING); 66 } 67 68 if (!check_form_key($form_key)) 69 { 70 trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); 71 } 72 73 $store = $download = $structure = $schema_data = false; 74 75 if ($where == 'store_and_download' || $where == 'store') 76 { 77 $store = true; 78 } 79 80 if ($where == 'store_and_download' || $where == 'download') 81 { 82 $download = true; 83 } 84 85 if ($type == 'full' || $type == 'structure') 86 { 87 $structure = true; 88 } 89 90 if ($type == 'full' || $type == 'data') 91 { 92 $schema_data = true; 93 } 94 95 @set_time_limit(1200); 96 @set_time_limit(0); 97 98 $time = time(); 99 100 $filename = 'backup_' . $time . '_' . unique_id(); 101 switch ($db->get_sql_layer()) 102 { 103 case 'mysqli': 104 case 'mysql4': 105 case 'mysql': 106 $extractor = new mysql_extractor($format, $filename, $time, $download, $store); 107 break; 108 109 case 'sqlite': 110 $extractor = new sqlite_extractor($format, $filename, $time, $download, $store); 111 break; 112 113 case 'sqlite3': 114 $extractor = new sqlite3_extractor($format, $filename, $time, $download, $store); 115 break; 116 117 case 'postgres': 118 $extractor = new postgres_extractor($format, $filename, $time, $download, $store); 119 break; 120 121 case 'oracle': 122 $extractor = new oracle_extractor($format, $filename, $time, $download, $store); 123 break; 124 125 case 'mssql': 126 case 'mssql_odbc': 127 case 'mssqlnative': 128 $extractor = new mssql_extractor($format, $filename, $time, $download, $store); 129 break; 130 } 131 132 $extractor->write_start($table_prefix); 133 134 foreach ($table as $table_name) 135 { 136 // Get the table structure 137 if ($structure) 138 { 139 $extractor->write_table($table_name); 140 } 141 else 142 { 143 // We might wanna empty out all that junk :D 144 switch ($db->get_sql_layer()) 145 { 146 case 'sqlite': 147 case 'sqlite3': 148 $extractor->flush('DELETE FROM ' . $table_name . ";\n"); 149 break; 150 151 case 'mssql': 152 case 'mssql_odbc': 153 case 'mssqlnative': 154 $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n"); 155 break; 156 157 case 'oracle': 158 $extractor->flush('TRUNCATE TABLE ' . $table_name . "/\n"); 159 break; 160 161 default: 162 $extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n"); 163 break; 164 } 165 } 166 167 // Data 168 if ($schema_data) 169 { 170 $extractor->write_data($table_name); 171 } 172 } 173 174 $extractor->write_end(); 175 176 add_log('admin', 'LOG_DB_BACKUP'); 177 178 if ($download == true) 179 { 180 exit; 181 } 182 183 trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action)); 184 break; 185 186 default: 187 $tables = $this->db_tools->sql_list_tables(); 188 asort($tables); 189 foreach ($tables as $table_name) 190 { 191 if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0) 192 { 193 $template->assign_block_vars('tables', array( 194 'TABLE' => $table_name 195 )); 196 } 197 } 198 unset($tables); 199 200 $template->assign_vars(array( 201 'U_ACTION' => $this->u_action . '&action=download' 202 )); 203 204 $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2'); 205 206 foreach ($available_methods as $type => $module) 207 { 208 if (!@extension_loaded($module)) 209 { 210 continue; 211 } 212 213 $template->assign_block_vars('methods', array( 214 'TYPE' => $type 215 )); 216 } 217 218 $template->assign_block_vars('methods', array( 219 'TYPE' => 'text' 220 )); 221 break; 222 } 223 break; 224 225 case 'restore': 226 227 $this->page_title = 'ACP_RESTORE'; 228 229 switch ($action) 230 { 231 case 'submit': 232 $delete = request_var('delete', ''); 233 $file = request_var('file', ''); 234 $download = request_var('download', ''); 235 236 if (!preg_match('#^backup_\d{10,}_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches)) 237 { 238 trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); 239 } 240 241 $file_name = $phpbb_root_path . 'store/' . $matches[0]; 242 243 if (!file_exists($file_name) || !is_readable($file_name)) 244 { 245 trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); 246 } 247 248 if ($delete) 249 { 250 if (confirm_box(true)) 251 { 252 unlink($file_name); 253 add_log('admin', 'LOG_DB_DELETE'); 254 trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action)); 255 } 256 else 257 { 258 confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file))); 259 } 260 } 261 else if ($download || confirm_box(true)) 262 { 263 if ($download) 264 { 265 $name = $matches[0]; 266 267 switch ($matches[1]) 268 { 269 case 'sql': 270 $mimetype = 'text/x-sql'; 271 break; 272 case 'sql.bz2': 273 $mimetype = 'application/x-bzip2'; 274 break; 275 case 'sql.gz': 276 $mimetype = 'application/x-gzip'; 277 break; 278 } 279 280 header('Cache-Control: private, no-cache'); 281 header("Content-Type: $mimetype; name=\"$name\""); 282 header("Content-disposition: attachment; filename=$name"); 283 284 @set_time_limit(0); 285 286 $fp = @fopen($file_name, 'rb'); 287 288 if ($fp !== false) 289 { 290 while (!feof($fp)) 291 { 292 echo fread($fp, 8192); 293 } 294 fclose($fp); 295 } 296 297 flush(); 298 exit; 299 } 300 301 switch ($matches[1]) 302 { 303 case 'sql': 304 $fp = fopen($file_name, 'rb'); 305 $read = 'fread'; 306 $seek = 'fseek'; 307 $eof = 'feof'; 308 $close = 'fclose'; 309 $fgetd = 'fgetd'; 310 break; 311 312 case 'sql.bz2': 313 $fp = bzopen($file_name, 'r'); 314 $read = 'bzread'; 315 $seek = ''; 316 $eof = 'feof'; 317 $close = 'bzclose'; 318 $fgetd = 'fgetd_seekless'; 319 break; 320 321 case 'sql.gz': 322 $fp = gzopen($file_name, 'rb'); 323 $read = 'gzread'; 324 $seek = 'gzseek'; 325 $eof = 'gzeof'; 326 $close = 'gzclose'; 327 $fgetd = 'fgetd'; 328 break; 329 } 330 331 switch ($db->get_sql_layer()) 332 { 333 case 'mysql': 334 case 'mysql4': 335 case 'mysqli': 336 case 'sqlite': 337 case 'sqlite3': 338 while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) 339 { 340 $db->sql_query($sql); 341 } 342 break; 343 344 case 'postgres': 345 $delim = ";\n"; 346 while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false) 347 { 348 $query = trim($sql); 349 350 if (substr($query, 0, 13) == 'CREATE DOMAIN') 351 { 352 list(, , $domain) = explode(' ', $query); 353 $sql = "SELECT domain_name 354 FROM information_schema.domains 355 WHERE domain_name = '$domain';"; 356 $result = $db->sql_query($sql); 357 if (!$db->sql_fetchrow($result)) 358 { 359 $db->sql_query($query); 360 } 361 $db->sql_freeresult($result); 362 } 363 else 364 { 365 $db->sql_query($query); 366 } 367 368 if (substr($query, 0, 4) == 'COPY') 369 { 370 while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.') 371 { 372 if ($sub === false) 373 { 374 trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING); 375 } 376 pg_put_line($db->get_db_connect_id(), $sub . "\n"); 377 } 378 pg_put_line($db->get_db_connect_id(), "\\.\n"); 379 pg_end_copy($db->get_db_connect_id()); 380 } 381 } 382 break; 383 384 case 'oracle': 385 while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false) 386 { 387 $db->sql_query($sql); 388 } 389 break; 390 391 case 'mssql': 392 case 'mssql_odbc': 393 case 'mssqlnative': 394 while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false) 395 { 396 $db->sql_query($sql); 397 } 398 break; 399 } 400 401 $close($fp); 402 403 // Purge the cache due to updated data 404 $cache->purge(); 405 406 add_log('admin', 'LOG_DB_RESTORE'); 407 trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action)); 408 break; 409 } 410 else if (!$download) 411 { 412 confirm_box(false, $user->lang['RESTORE_SELECTED_BACKUP'], build_hidden_fields(array('file' => $file))); 413 } 414 415 default: 416 $methods = array('sql'); 417 $available_methods = array('sql.gz' => 'zlib', 'sql.bz2' => 'bz2'); 418 419 foreach ($available_methods as $type => $module) 420 { 421 if (!@extension_loaded($module)) 422 { 423 continue; 424 } 425 $methods[] = $type; 426 } 427 428 $dir = $phpbb_root_path . 'store/'; 429 $dh = @opendir($dir); 430 431 $backup_files = array(); 432 433 if ($dh) 434 { 435 while (($file = readdir($dh)) !== false) 436 { 437 if (preg_match('#^backup_(\d{10,})_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches)) 438 { 439 if (in_array($matches[2], $methods)) 440 { 441 $backup_files[(int) $matches[1]] = $file; 442 } 443 } 444 } 445 closedir($dh); 446 } 447 448 if (!empty($backup_files)) 449 { 450 krsort($backup_files); 451 452 foreach ($backup_files as $name => $file) 453 { 454 $template->assign_block_vars('files', array( 455 'FILE' => $file, 456 'NAME' => $user->format_date($name, 'd-m-Y H:i:s', true), 457 'SUPPORTED' => true, 458 )); 459 } 460 } 461 462 $template->assign_vars(array( 463 'U_ACTION' => $this->u_action . '&action=submit' 464 )); 465 break; 466 } 467 break; 468 } 469 } 470 } 471 472 class base_extractor 473 { 474 var $fh; 475 var $fp; 476 var $write; 477 var $close; 478 var $store; 479 var $download; 480 var $time; 481 var $format; 482 var $run_comp = false; 483 484 function base_extractor($format, $filename, $time, $download = false, $store = false) 485 { 486 global $request; 487 488 $this->download = $download; 489 $this->store = $store; 490 $this->time = $time; 491 $this->format = $format; 492 493 switch ($format) 494 { 495 case 'text': 496 $ext = '.sql'; 497 $open = 'fopen'; 498 $this->write = 'fwrite'; 499 $this->close = 'fclose'; 500 $mimetype = 'text/x-sql'; 501 break; 502 case 'bzip2': 503 $ext = '.sql.bz2'; 504 $open = 'bzopen'; 505 $this->write = 'bzwrite'; 506 $this->close = 'bzclose'; 507 $mimetype = 'application/x-bzip2'; 508 break; 509 case 'gzip': 510 $ext = '.sql.gz'; 511 $open = 'gzopen'; 512 $this->write = 'gzwrite'; 513 $this->close = 'gzclose'; 514 $mimetype = 'application/x-gzip'; 515 break; 516 } 517 518 if ($download == true) 519 { 520 $name = $filename . $ext; 521 header('Cache-Control: private, no-cache'); 522 header("Content-Type: $mimetype; name=\"$name\""); 523 header("Content-disposition: attachment; filename=$name"); 524 525 switch ($format) 526 { 527 case 'bzip2': 528 ob_start(); 529 break; 530 531 case 'gzip': 532 if (strpos($request->header('Accept-Encoding'), 'gzip') !== false && strpos(strtolower($request->header('User-Agent')), 'msie') === false) 533 { 534 ob_start('ob_gzhandler'); 535 } 536 else 537 { 538 $this->run_comp = true; 539 } 540 break; 541 } 542 } 543 544 if ($store == true) 545 { 546 global $phpbb_root_path; 547 $file = $phpbb_root_path . 'store/' . $filename . $ext; 548 549 $this->fp = $open($file, 'w'); 550 551 if (!$this->fp) 552 { 553 trigger_error('FILE_WRITE_FAIL', E_USER_ERROR); 554 } 555 } 556 } 557 558 function write_end() 559 { 560 static $close; 561 562 if ($this->store) 563 { 564 if ($close === null) 565 { 566 $close = $this->close; 567 } 568 $close($this->fp); 569 } 570 571 // bzip2 must be written all the way at the end 572 if ($this->download && $this->format === 'bzip2') 573 { 574 $c = ob_get_clean(); 575 echo bzcompress($c); 576 } 577 } 578 579 function flush($data) 580 { 581 static $write; 582 if ($this->store === true) 583 { 584 if ($write === null) 585 { 586 $write = $this->write; 587 } 588 $write($this->fp, $data); 589 } 590 591 if ($this->download === true) 592 { 593 if ($this->format === 'bzip2' || $this->format === 'text' || ($this->format === 'gzip' && !$this->run_comp)) 594 { 595 echo $data; 596 } 597 598 // we can write the gzip data as soon as we get it 599 if ($this->format === 'gzip') 600 { 601 if ($this->run_comp) 602 { 603 echo gzencode($data); 604 } 605 else 606 { 607 ob_flush(); 608 flush(); 609 } 610 } 611 } 612 } 613 } 614 615 class mysql_extractor extends base_extractor 616 { 617 function write_start($table_prefix) 618 { 619 $sql_data = "#\n"; 620 $sql_data .= "# phpBB Backup Script\n"; 621 $sql_data .= "# Dump of tables for $table_prefix\n"; 622 $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; 623 $sql_data .= "#\n"; 624 $this->flush($sql_data); 625 } 626 627 function write_table($table_name) 628 { 629 global $db; 630 static $new_extract; 631 632 if ($new_extract === null) 633 { 634 if ($db->get_sql_layer() === 'mysqli' || version_compare($db->sql_server_info(true), '3.23.20', '>=')) 635 { 636 $new_extract = true; 637 } 638 else 639 { 640 $new_extract = false; 641 } 642 } 643 644 if ($new_extract) 645 { 646 $this->new_write_table($table_name); 647 } 648 else 649 { 650 $this->old_write_table($table_name); 651 } 652 } 653 654 function write_data($table_name) 655 { 656 global $db; 657 if ($db->get_sql_layer() === 'mysqli') 658 { 659 $this->write_data_mysqli($table_name); 660 } 661 else 662 { 663 $this->write_data_mysql($table_name); 664 } 665 } 666 667 function write_data_mysqli($table_name) 668 { 669 global $db; 670 $sql = "SELECT * 671 FROM $table_name"; 672 $result = mysqli_query($db->get_db_connect_id(), $sql, MYSQLI_USE_RESULT); 673 if ($result != false) 674 { 675 $fields_cnt = mysqli_num_fields($result); 676 677 // Get field information 678 $field = mysqli_fetch_fields($result); 679 $field_set = array(); 680 681 for ($j = 0; $j < $fields_cnt; $j++) 682 { 683 $field_set[] = $field[$j]->name; 684 } 685 686 $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"'); 687 $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"'); 688 $fields = implode(', ', $field_set); 689 $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES '; 690 $first_set = true; 691 $query_len = 0; 692 $max_len = get_usable_memory(); 693 694 while ($row = mysqli_fetch_row($result)) 695 { 696 $values = array(); 697 if ($first_set) 698 { 699 $query = $sql_data . '('; 700 } 701 else 702 { 703 $query .= ',('; 704 } 705 706 for ($j = 0; $j < $fields_cnt; $j++) 707 { 708 if (!isset($row[$j]) || is_null($row[$j])) 709 { 710 $values[$j] = 'NULL'; 711 } 712 else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024)) 713 { 714 $values[$j] = $row[$j]; 715 } 716 else 717 { 718 $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'"; 719 } 720 } 721 $query .= implode(', ', $values) . ')'; 722 723 $query_len += strlen($query); 724 if ($query_len > $max_len) 725 { 726 $this->flush($query . ";\n\n"); 727 $query = ''; 728 $query_len = 0; 729 $first_set = true; 730 } 731 else 732 { 733 $first_set = false; 734 } 735 } 736 mysqli_free_result($result); 737 738 // check to make sure we have nothing left to flush 739 if (!$first_set && $query) 740 { 741 $this->flush($query . ";\n\n"); 742 } 743 } 744 } 745 746 function write_data_mysql($table_name) 747 { 748 global $db; 749 $sql = "SELECT * 750 FROM $table_name"; 751 $result = mysql_unbuffered_query($sql, $db->get_db_connect_id()); 752 753 if ($result != false) 754 { 755 $fields_cnt = mysql_num_fields($result); 756 757 // Get field information 758 $field = array(); 759 for ($i = 0; $i < $fields_cnt; $i++) 760 { 761 $field[] = mysql_fetch_field($result, $i); 762 } 763 $field_set = array(); 764 765 for ($j = 0; $j < $fields_cnt; $j++) 766 { 767 $field_set[] = $field[$j]->name; 768 } 769 770 $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"'); 771 $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"'); 772 $fields = implode(', ', $field_set); 773 $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES '; 774 $first_set = true; 775 $query_len = 0; 776 $max_len = get_usable_memory(); 777 778 while ($row = mysql_fetch_row($result)) 779 { 780 $values = array(); 781 if ($first_set) 782 { 783 $query = $sql_data . '('; 784 } 785 else 786 { 787 $query .= ',('; 788 } 789 790 for ($j = 0; $j < $fields_cnt; $j++) 791 { 792 if (!isset($row[$j]) || is_null($row[$j])) 793 { 794 $values[$j] = 'NULL'; 795 } 796 else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp')) 797 { 798 $values[$j] = $row[$j]; 799 } 800 else 801 { 802 $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'"; 803 } 804 } 805 $query .= implode(', ', $values) . ')'; 806 807 $query_len += strlen($query); 808 if ($query_len > $max_len) 809 { 810 $this->flush($query . ";\n\n"); 811 $query = ''; 812 $query_len = 0; 813 $first_set = true; 814 } 815 else 816 { 817 $first_set = false; 818 } 819 } 820 mysql_free_result($result); 821 822 // check to make sure we have nothing left to flush 823 if (!$first_set && $query) 824 { 825 $this->flush($query . ";\n\n"); 826 } 827 } 828 } 829 830 function new_write_table($table_name) 831 { 832 global $db; 833 834 $sql = 'SHOW CREATE TABLE ' . $table_name; 835 $result = $db->sql_query($sql); 836 $row = $db->sql_fetchrow($result); 837 838 $sql_data = '# Table: ' . $table_name . "\n"; 839 $sql_data .= "DROP TABLE IF EXISTS $table_name;\n"; 840 $this->flush($sql_data . $row['Create Table'] . ";\n\n"); 841 842 $db->sql_freeresult($result); 843 } 844 845 function old_write_table($table_name) 846 { 847 global $db; 848 849 $sql_data = '# Table: ' . $table_name . "\n"; 850 $sql_data .= "DROP TABLE IF EXISTS $table_name;\n"; 851 $sql_data .= "CREATE TABLE $table_name(\n"; 852 $rows = array(); 853 854 $sql = "SHOW FIELDS 855 FROM $table_name"; 856 $result = $db->sql_query($sql); 857 858 while ($row = $db->sql_fetchrow($result)) 859 { 860 $line = ' ' . $row['Field'] . ' ' . $row['Type']; 861 862 if (!is_null($row['Default'])) 863 { 864 $line .= " DEFAULT '{$row['Default']}'"; 865 } 866 867 if ($row['Null'] != 'YES') 868 { 869 $line .= ' NOT NULL'; 870 } 871 872 if ($row['Extra'] != '') 873 { 874 $line .= ' ' . $row['Extra']; 875 } 876 877 $rows[] = $line; 878 } 879 $db->sql_freeresult($result); 880 881 $sql = "SHOW KEYS 882 FROM $table_name"; 883 884 $result = $db->sql_query($sql); 885 886 $index = array(); 887 while ($row = $db->sql_fetchrow($result)) 888 { 889 $kname = $row['Key_name']; 890 891 if ($kname != 'PRIMARY') 892 { 893 if ($row['Non_unique'] == 0) 894 { 895 $kname = "UNIQUE|$kname"; 896 } 897 } 898 899 if ($row['Sub_part']) 900 { 901 $row['Column_name'] .= '(' . $row['Sub_part'] . ')'; 902 } 903 $index[$kname][] = $row['Column_name']; 904 } 905 $db->sql_freeresult($result); 906 907 foreach ($index as $key => $columns) 908 { 909 $line = ' '; 910 911 if ($key == 'PRIMARY') 912 { 913 $line .= 'PRIMARY KEY (' . implode(', ', $columns) . ')'; 914 } 915 else if (strpos($key, 'UNIQUE') === 0) 916 { 917 $line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')'; 918 } 919 else if (strpos($key, 'FULLTEXT') === 0) 920 { 921 $line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')'; 922 } 923 else 924 { 925 $line .= "KEY $key (" . implode(', ', $columns) . ')'; 926 } 927 928 $rows[] = $line; 929 } 930 931 $sql_data .= implode(",\n", $rows); 932 $sql_data .= "\n);\n\n"; 933 934 $this->flush($sql_data); 935 } 936 } 937 938 class sqlite_extractor extends base_extractor 939 { 940 function write_start($prefix) 941 { 942 $sql_data = "--\n"; 943 $sql_data .= "-- phpBB Backup Script\n"; 944 $sql_data .= "-- Dump of tables for $prefix\n"; 945 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; 946 $sql_data .= "--\n"; 947 $sql_data .= "BEGIN TRANSACTION;\n"; 948 $this->flush($sql_data); 949 } 950 951 function write_table($table_name) 952 { 953 global $db; 954 $sql_data = '-- Table: ' . $table_name . "\n"; 955 $sql_data .= "DROP TABLE $table_name;\n"; 956 957 $sql = "SELECT sql 958 FROM sqlite_master 959 WHERE type = 'table' 960 AND name = '" . $db->sql_escape($table_name) . "' 961 ORDER BY type DESC, name;"; 962 $result = $db->sql_query($sql); 963 $row = $db->sql_fetchrow($result); 964 $db->sql_freeresult($result); 965 966 // Create Table 967 $sql_data .= $row['sql'] . ";\n"; 968 969 $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');"); 970 971 $ar = array(); 972 while ($row = $db->sql_fetchrow($result)) 973 { 974 $ar[] = $row; 975 } 976 $db->sql_freeresult($result); 977 978 foreach ($ar as $value) 979 { 980 if (strpos($value['name'], 'autoindex') !== false) 981 { 982 continue; 983 } 984 985 $result = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($value['name']) . "');"); 986 987 $fields = array(); 988 while ($row = $db->sql_fetchrow($result)) 989 { 990 $fields[] = $row['name']; 991 } 992 $db->sql_freeresult($result); 993 994 $sql_data .= 'CREATE ' . ($value['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $value['name'] . ' on ' . $table_name . ' (' . implode(', ', $fields) . ");\n"; 995 } 996 997 $this->flush($sql_data . "\n"); 998 } 999 1000 function write_data($table_name) 1001 { 1002 global $db; 1003 1004 $col_types = sqlite_fetch_column_types($db->get_db_connect_id(), $table_name); 1005 1006 $sql = "SELECT * 1007 FROM $table_name"; 1008 $result = sqlite_unbuffered_query($db->get_db_connect_id(), $sql); 1009 $rows = sqlite_fetch_all($result, SQLITE_ASSOC); 1010 $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; 1011 foreach ($rows as $row) 1012 { 1013 foreach ($row as $column_name => $column_data) 1014 { 1015 if (is_null($column_data)) 1016 { 1017 $row[$column_name] = 'NULL'; 1018 } 1019 else if ($column_data == '') 1020 { 1021 $row[$column_name] = "''"; 1022 } 1023 else if (strpos($col_types[$column_name], 'text') !== false || strpos($col_types[$column_name], 'char') !== false || strpos($col_types[$column_name], 'blob') !== false) 1024 { 1025 $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data)); 1026 } 1027 } 1028 $this->flush($sql_insert . implode(', ', $row) . ");\n"); 1029 } 1030 } 1031 1032 function write_end() 1033 { 1034 $this->flush("COMMIT;\n"); 1035 parent::write_end(); 1036 } 1037 } 1038 1039 class sqlite3_extractor extends base_extractor 1040 { 1041 function write_start($prefix) 1042 { 1043 $sql_data = "--\n"; 1044 $sql_data .= "-- phpBB Backup Script\n"; 1045 $sql_data .= "-- Dump of tables for $prefix\n"; 1046 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; 1047 $sql_data .= "--\n"; 1048 $sql_data .= "BEGIN TRANSACTION;\n"; 1049 $this->flush($sql_data); 1050 } 1051 1052 function write_table($table_name) 1053 { 1054 global $db; 1055 $sql_data = '-- Table: ' . $table_name . "\n"; 1056 $sql_data .= "DROP TABLE $table_name;\n"; 1057 1058 $sql = "SELECT sql 1059 FROM sqlite_master 1060 WHERE type = 'table' 1061 AND name = '" . $db->sql_escape($table_name) . "' 1062 ORDER BY name ASC;"; 1063 $result = $db->sql_query($sql); 1064 $row = $db->sql_fetchrow($result); 1065 $db->sql_freeresult($result); 1066 1067 // Create Table 1068 $sql_data .= $row['sql'] . ";\n"; 1069 1070 $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');"); 1071 1072 while ($row = $db->sql_fetchrow($result)) 1073 { 1074 if (strpos($row['name'], 'autoindex') !== false) 1075 { 1076 continue; 1077 } 1078 1079 $result2 = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($row['name']) . "');"); 1080 1081 $fields = array(); 1082 while ($row2 = $db->sql_fetchrow($result2)) 1083 { 1084 $fields[] = $row2['name']; 1085 } 1086 $db->sql_freeresult($result2); 1087 1088 $sql_data .= 'CREATE ' . ($row['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $row['name'] . ' ON ' . $table_name . ' (' . implode(', ', $fields) . ");\n"; 1089 } 1090 $db->sql_freeresult($result); 1091 1092 $this->flush($sql_data . "\n"); 1093 } 1094 1095 function write_data($table_name) 1096 { 1097 global $db; 1098 1099 $result = $db->sql_query("PRAGMA table_info('" . $db->sql_escape($table_name) . "');"); 1100 1101 $col_types = array(); 1102 while ($row = $db->sql_fetchrow($result)) 1103 { 1104 $col_types[$row['name']] = $row['type']; 1105 } 1106 $db->sql_freeresult($result); 1107 1108 $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; 1109 1110 $sql = "SELECT * 1111 FROM $table_name"; 1112 $result = $db->sql_query($sql); 1113 1114 while ($row = $db->sql_fetchrow($result)) 1115 { 1116 foreach ($row as $column_name => $column_data) 1117 { 1118 if (is_null($column_data)) 1119 { 1120 $row[$column_name] = 'NULL'; 1121 } 1122 else if ($column_data === '') 1123 { 1124 $row[$column_name] = "''"; 1125 } 1126 else if (stripos($col_types[$column_name], 'text') !== false || stripos($col_types[$column_name], 'char') !== false || stripos($col_types[$column_name], 'blob') !== false) 1127 { 1128 $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data)); 1129 } 1130 } 1131 $this->flush($sql_insert . implode(', ', $row) . ");\n"); 1132 } 1133 } 1134 1135 function write_end() 1136 { 1137 $this->flush("COMMIT;\n"); 1138 parent::write_end(); 1139 } 1140 } 1141 1142 class postgres_extractor extends base_extractor 1143 { 1144 function write_start($prefix) 1145 { 1146 $sql_data = "--\n"; 1147 $sql_data .= "-- phpBB Backup Script\n"; 1148 $sql_data .= "-- Dump of tables for $prefix\n"; 1149 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; 1150 $sql_data .= "--\n"; 1151 $sql_data .= "BEGIN TRANSACTION;\n"; 1152 $this->flush($sql_data); 1153 } 1154 1155 function write_table($table_name) 1156 { 1157 global $db; 1158 static $domains_created = array(); 1159 1160 $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default 1161 FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b 1162 WHERE a.domain_name = b.domain_name 1163 AND b.table_name = '{$table_name}'"; 1164 $result = $db->sql_query($sql); 1165 while ($row = $db->sql_fetchrow($result)) 1166 { 1167 if (empty($domains_created[$row['domain_name']])) 1168 { 1169 $domains_created[$row['domain_name']] = true; 1170 //$sql_data = "DROP DOMAIN {$row['domain_name']};\n"; 1171 $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}"; 1172 if (!empty($row['character_maximum_length'])) 1173 { 1174 $sql_data .= '(' . $row['character_maximum_length'] . ')'; 1175 } 1176 $sql_data .= ' NOT NULL'; 1177 if (!empty($row['domain_default'])) 1178 { 1179 $sql_data .= ' DEFAULT ' . $row['domain_default']; 1180 } 1181 $this->flush($sql_data . ";\n"); 1182 } 1183 } 1184 $db->sql_freeresult($result); 1185 1186 $sql_data = '-- Table: ' . $table_name . "\n"; 1187 $sql_data .= "DROP TABLE $table_name;\n"; 1188 // PGSQL does not "tightly" bind sequences and tables, we must guess... 1189 $sql = "SELECT relname 1190 FROM pg_class 1191 WHERE relkind = 'S' 1192 AND relname = '{$table_name}_seq'"; 1193 $result = $db->sql_query($sql); 1194 // We don't even care about storing the results. We already know the answer if we get rows back. 1195 if ($db->sql_fetchrow($result)) 1196 { 1197 $sql_data .= "DROP SEQUENCE {$table_name}_seq;\n"; 1198 $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n"; 1199 } 1200 $db->sql_freeresult($result); 1201 1202 $field_query = "SELECT a.attnum, a.attname as field, t.typname as type, a.attlen as length, a.atttypmod as lengthvar, a.attnotnull as notnull 1203 FROM pg_class c, pg_attribute a, pg_type t 1204 WHERE c.relname = '" . $db->sql_escape($table_name) . "' 1205 AND a.attnum > 0 1206 AND a.attrelid = c.oid 1207 AND a.atttypid = t.oid 1208 ORDER BY a.attnum"; 1209 $result = $db->sql_query($field_query); 1210 1211 $sql_data .= "CREATE TABLE $table_name(\n"; 1212 $lines = array(); 1213 while ($row = $db->sql_fetchrow($result)) 1214 { 1215 // Get the data from the table 1216 $sql_get_default = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault 1217 FROM pg_attrdef d, pg_class c 1218 WHERE (c.relname = '" . $db->sql_escape($table_name) . "') 1219 AND (c.oid = d.adrelid) 1220 AND d.adnum = " . $row['attnum']; 1221 $def_res = $db->sql_query($sql_get_default); 1222 $def_row = $db->sql_fetchrow($def_res); 1223 $db->sql_freeresult($def_res); 1224 1225 if (empty($def_row)) 1226 { 1227 unset($row['rowdefault']); 1228 } 1229 else 1230 { 1231 $row['rowdefault'] = $def_row['rowdefault']; 1232 } 1233 1234 if ($row['type'] == 'bpchar') 1235 { 1236 // Internally stored as bpchar, but isn't accepted in a CREATE TABLE statement. 1237 $row['type'] = 'char'; 1238 } 1239 1240 $line = ' ' . $row['field'] . ' ' . $row['type']; 1241 1242 if (strpos($row['type'], 'char') !== false) 1243 { 1244 if ($row['lengthvar'] > 0) 1245 { 1246 $line .= '(' . ($row['lengthvar'] - 4) . ')'; 1247 } 1248 } 1249 1250 if (strpos($row['type'], 'numeric') !== false) 1251 { 1252 $line .= '('; 1253 $line .= sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff)); 1254 $line .= ')'; 1255 } 1256 1257 if (isset($row['rowdefault'])) 1258 { 1259 $line .= ' DEFAULT ' . $row['rowdefault']; 1260 } 1261 1262 if ($row['notnull'] == 't') 1263 { 1264 $line .= ' NOT NULL'; 1265 } 1266 1267 $lines[] = $line; 1268 } 1269 $db->sql_freeresult($result); 1270 1271 // Get the listing of primary keys. 1272 $sql_pri_keys = "SELECT ic.relname as index_name, bc.relname as tab_name, ta.attname as column_name, i.indisunique as unique_key, i.indisprimary as primary_key 1273 FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia 1274 WHERE (bc.oid = i.indrelid) 1275 AND (ic.oid = i.indexrelid) 1276 AND (ia.attrelid = i.indexrelid) 1277 AND (ta.attrelid = bc.oid) 1278 AND (bc.relname = '" . $db->sql_escape($table_name) . "') 1279 AND (ta.attrelid = i.indrelid) 1280 AND (ta.attnum = i.indkey[ia.attnum-1]) 1281 ORDER BY index_name, tab_name, column_name"; 1282 1283 $result = $db->sql_query($sql_pri_keys); 1284 1285 $index_create = $index_rows = $primary_key = array(); 1286 1287 // We do this in two steps. It makes placing the comma easier 1288 while ($row = $db->sql_fetchrow($result)) 1289 { 1290 if ($row['primary_key'] == 't') 1291 { 1292 $primary_key[] = $row['column_name']; 1293 $primary_key_name = $row['index_name']; 1294 } 1295 else 1296 { 1297 // We have to store this all this info because it is possible to have a multi-column key... 1298 // we can loop through it again and build the statement 1299 $index_rows[$row['index_name']]['table'] = $table_name; 1300 $index_rows[$row['index_name']]['unique'] = ($row['unique_key'] == 't') ? true : false; 1301 $index_rows[$row['index_name']]['column_names'][] = $row['column_name']; 1302 } 1303 } 1304 $db->sql_freeresult($result); 1305 1306 if (!empty($index_rows)) 1307 { 1308 foreach ($index_rows as $idx_name => $props) 1309 { 1310 $index_create[] = 'CREATE ' . ($props['unique'] ? 'UNIQUE ' : '') . "INDEX $idx_name ON $table_name (" . implode(', ', $props['column_names']) . ");"; 1311 } 1312 } 1313 1314 if (!empty($primary_key)) 1315 { 1316 $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (" . implode(', ', $primary_key) . ")"; 1317 } 1318 1319 // Generate constraint clauses for CHECK constraints 1320 $sql_checks = "SELECT conname as index_name, consrc 1321 FROM pg_constraint, pg_class bc 1322 WHERE conrelid = bc.oid 1323 AND bc.relname = '" . $db->sql_escape($table_name) . "' 1324 AND NOT EXISTS ( 1325 SELECT * 1326 FROM pg_constraint as c, pg_inherits as i 1327 WHERE i.inhrelid = pg_constraint.conrelid 1328 AND c.conname = pg_constraint.conname 1329 AND c.consrc = pg_constraint.consrc 1330 AND c.conrelid = i.inhparent 1331 )"; 1332 $result = $db->sql_query($sql_checks); 1333 1334 // Add the constraints to the sql file. 1335 while ($row = $db->sql_fetchrow($result)) 1336 { 1337 if (!is_null($row['consrc'])) 1338 { 1339 $lines[] = ' CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['consrc']; 1340 } 1341 } 1342 $db->sql_freeresult($result); 1343 1344 $sql_data .= implode(", \n", $lines); 1345 $sql_data .= "\n);\n"; 1346 1347 if (!empty($index_create)) 1348 { 1349 $sql_data .= implode("\n", $index_create) . "\n\n"; 1350 } 1351 $this->flush($sql_data); 1352 } 1353 1354 function write_data($table_name) 1355 { 1356 global $db; 1357 // Grab all of the data from current table. 1358 $sql = "SELECT * 1359 FROM $table_name"; 1360 $result = $db->sql_query($sql); 1361 1362 $i_num_fields = pg_num_fields($result); 1363 $seq = ''; 1364 1365 for ($i = 0; $i < $i_num_fields; $i++) 1366 { 1367 $ary_type[] = pg_field_type($result, $i); 1368 $ary_name[] = pg_field_name($result, $i); 1369 1370 $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault 1371 FROM pg_attrdef d, pg_class c 1372 WHERE (c.relname = '{$table_name}') 1373 AND (c.oid = d.adrelid) 1374 AND d.adnum = " . strval($i + 1); 1375 $result2 = $db->sql_query($sql); 1376 if ($row = $db->sql_fetchrow($result2)) 1377 { 1378 // Determine if we must reset the sequences 1379 if (strpos($row['rowdefault'], "nextval('") === 0) 1380 { 1381 $seq .= "SELECT SETVAL('{$table_name}_seq',(select case when max({$ary_name[$i]})>0 then max({$ary_name[$i]})+1 else 1 end FROM {$table_name}));\n"; 1382 } 1383 } 1384 } 1385 1386 $this->flush("COPY $table_name (" . implode(', ', $ary_name) . ') FROM stdin;' . "\n"); 1387 while ($row = $db->sql_fetchrow($result)) 1388 { 1389 $schema_vals = array(); 1390 1391 // Build the SQL statement to recreate the data. 1392 for ($i = 0; $i < $i_num_fields; $i++) 1393 { 1394 $str_val = $row[$ary_name[$i]]; 1395 1396 if (preg_match('#char|text|bool|bytea#i', $ary_type[$i])) 1397 { 1398 $str_val = str_replace(array("\n", "\t", "\r", "\b", "\f", "\v"), array('\n', '\t', '\r', '\b', '\f', '\v'), addslashes($str_val)); 1399 $str_empty = ''; 1400 } 1401 else 1402 { 1403 $str_empty = '\N'; 1404 } 1405 1406 if (empty($str_val) && $str_val !== '0') 1407 { 1408 $str_val = $str_empty; 1409 } 1410 1411 $schema_vals[] = $str_val; 1412 } 1413 1414 // Take the ordered fields and their associated data and build it 1415 // into a valid sql statement to recreate that field in the data. 1416 $this->flush(implode("\t", $schema_vals) . "\n"); 1417 } 1418 $db->sql_freeresult($result); 1419 $this->flush("\\.\n"); 1420 1421 // Write out the sequence statements 1422 $this->flush($seq); 1423 } 1424 1425 function write_end() 1426 { 1427 $this->flush("COMMIT;\n"); 1428 parent::write_end(); 1429 } 1430 } 1431 1432 class mssql_extractor extends base_extractor 1433 { 1434 function write_end() 1435 { 1436 $this->flush("COMMIT\nGO\n"); 1437 parent::write_end(); 1438 } 1439 1440 function write_start($prefix) 1441 { 1442 $sql_data = "--\n"; 1443 $sql_data .= "-- phpBB Backup Script\n"; 1444 $sql_data .= "-- Dump of tables for $prefix\n"; 1445 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; 1446 $sql_data .= "--\n"; 1447 $sql_data .= "BEGIN TRANSACTION\n"; 1448 $sql_data .= "GO\n"; 1449 $this->flush($sql_data); 1450 } 1451 1452 function write_table($table_name) 1453 { 1454 global $db; 1455 $sql_data = '-- Table: ' . $table_name . "\n"; 1456 $sql_data .= "IF OBJECT_ID(N'$table_name', N'U') IS NOT NULL\n"; 1457 $sql_data .= "DROP TABLE $table_name;\n"; 1458 $sql_data .= "GO\n"; 1459 $sql_data .= "\nCREATE TABLE [$table_name] (\n"; 1460 $rows = array(); 1461 1462 $text_flag = false; 1463 1464 $sql = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as IS_IDENTITY 1465 FROM INFORMATION_SCHEMA.COLUMNS 1466 WHERE TABLE_NAME = '$table_name'"; 1467 $result = $db->sql_query($sql); 1468 1469 while ($row = $db->sql_fetchrow($result)) 1470 { 1471 $line = "\t[{$row['COLUMN_NAME']}] [{$row['DATA_TYPE']}]"; 1472 1473 if ($row['DATA_TYPE'] == 'text') 1474 { 1475 $text_flag = true; 1476 } 1477 1478 if ($row['IS_IDENTITY']) 1479 { 1480 $line .= ' IDENTITY (1 , 1)'; 1481 } 1482 1483 if ($row['CHARACTER_MAXIMUM_LENGTH'] && $row['DATA_TYPE'] !== 'text') 1484 { 1485 $line .= ' (' . $row['CHARACTER_MAXIMUM_LENGTH'] . ')'; 1486 } 1487 1488 if ($row['IS_NULLABLE'] == 'YES') 1489 { 1490 $line .= ' NULL'; 1491 } 1492 else 1493 { 1494 $line .= ' NOT NULL'; 1495 } 1496 1497 if ($row['COLUMN_DEFAULT']) 1498 { 1499 $line .= ' DEFAULT ' . $row['COLUMN_DEFAULT']; 1500 } 1501 1502 $rows[] = $line; 1503 } 1504 $db->sql_freeresult($result); 1505 1506 $sql_data .= implode(",\n", $rows); 1507 $sql_data .= "\n) ON [PRIMARY]"; 1508 1509 if ($text_flag) 1510 { 1511 $sql_data .= " TEXTIMAGE_ON [PRIMARY]"; 1512 } 1513 1514 $sql_data .= "\nGO\n\n"; 1515 $rows = array(); 1516 1517 $sql = "SELECT CONSTRAINT_NAME, COLUMN_NAME 1518 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 1519 WHERE TABLE_NAME = '$table_name'"; 1520 $result = $db->sql_query($sql); 1521 while ($row = $db->sql_fetchrow($result)) 1522 { 1523 if (!sizeof($rows)) 1524 { 1525 $sql_data .= "ALTER TABLE [$table_name] WITH NOCHECK ADD\n"; 1526 $sql_data .= "\tCONSTRAINT [{$row['CONSTRAINT_NAME']}] PRIMARY KEY CLUSTERED \n\t(\n"; 1527 } 1528 $rows[] = "\t\t[{$row['COLUMN_NAME']}]"; 1529 } 1530 if (sizeof($rows)) 1531 { 1532 $sql_data .= implode(",\n", $rows); 1533 $sql_data .= "\n\t) ON [PRIMARY] \nGO\n"; 1534 } 1535 $db->sql_freeresult($result); 1536 1537 $index = array(); 1538 $sql = "EXEC sp_statistics '$table_name'"; 1539 $result = $db->sql_query($sql); 1540 while ($row = $db->sql_fetchrow($result)) 1541 { 1542 if ($row['TYPE'] == 3) 1543 { 1544 $index[$row['INDEX_NAME']][] = '[' . $row['COLUMN_NAME'] . ']'; 1545 } 1546 } 1547 $db->sql_freeresult($result); 1548 1549 foreach ($index as $index_name => $column_name) 1550 { 1551 $index[$index_name] = implode(', ', $column_name); 1552 } 1553 1554 foreach ($index as $index_name => $columns) 1555 { 1556 $sql_data .= "\nCREATE INDEX [$index_name] ON [$table_name]($columns) ON [PRIMARY]\nGO\n"; 1557 } 1558 $this->flush($sql_data); 1559 } 1560 1561 function write_data($table_name) 1562 { 1563 global $db; 1564 1565 if ($db->get_sql_layer() === 'mssql') 1566 { 1567 $this->write_data_mssql($table_name); 1568 } 1569 else if ($db->get_sql_layer() === 'mssqlnative') 1570 { 1571 $this->write_data_mssqlnative($table_name); 1572 } 1573 else 1574 { 1575 $this->write_data_odbc($table_name); 1576 } 1577 } 1578 1579 function write_data_mssql($table_name) 1580 { 1581 global $db; 1582 $ary_type = $ary_name = array(); 1583 $ident_set = false; 1584 $sql_data = ''; 1585 1586 // Grab all of the data from current table. 1587 $sql = "SELECT * 1588 FROM $table_name"; 1589 $result = $db->sql_query($sql); 1590 1591 $retrieved_data = mssql_num_rows($result); 1592 1593 $i_num_fields = mssql_num_fields($result); 1594 1595 for ($i = 0; $i < $i_num_fields; $i++) 1596 { 1597 $ary_type[$i] = mssql_field_type($result, $i); 1598 $ary_name[$i] = mssql_field_name($result, $i); 1599 } 1600 1601 if ($retrieved_data) 1602 { 1603 $sql = "SELECT 1 as has_identity 1604 FROM INFORMATION_SCHEMA.COLUMNS 1605 WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; 1606 $result2 = $db->sql_query($sql); 1607 $row2 = $db->sql_fetchrow($result2); 1608 if (!empty($row2['has_identity'])) 1609 { 1610 $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; 1611 $ident_set = true; 1612 } 1613 $db->sql_freeresult($result2); 1614 } 1615 1616 while ($row = $db->sql_fetchrow($result)) 1617 { 1618 $schema_vals = $schema_fields = array(); 1619 1620 // Build the SQL statement to recreate the data. 1621 for ($i = 0; $i < $i_num_fields; $i++) 1622 { 1623 $str_val = $row[$ary_name[$i]]; 1624 1625 if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) 1626 { 1627 $str_quote = ''; 1628 $str_empty = "''"; 1629 $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val)); 1630 } 1631 else if (preg_match('#date|timestamp#i', $ary_type[$i])) 1632 { 1633 if (empty($str_val)) 1634 { 1635 $str_quote = ''; 1636 } 1637 else 1638 { 1639 $str_quote = "'"; 1640 } 1641 } 1642 else 1643 { 1644 $str_quote = ''; 1645 $str_empty = 'NULL'; 1646 } 1647 1648 if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val))) 1649 { 1650 $str_val = $str_empty; 1651 } 1652 1653 $schema_vals[$i] = $str_quote . $str_val . $str_quote; 1654 $schema_fields[$i] = $ary_name[$i]; 1655 } 1656 1657 // Take the ordered fields and their associated data and build it 1658 // into a valid sql statement to recreate that field in the data. 1659 $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n"; 1660 1661 $this->flush($sql_data); 1662 $sql_data = ''; 1663 } 1664 $db->sql_freeresult($result); 1665 1666 if ($retrieved_data && $ident_set) 1667 { 1668 $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; 1669 } 1670 $this->flush($sql_data); 1671 } 1672 1673 function write_data_mssqlnative($table_name) 1674 { 1675 global $db; 1676 $ary_type = $ary_name = array(); 1677 $ident_set = false; 1678 $sql_data = ''; 1679 1680 // Grab all of the data from current table. 1681 $sql = "SELECT * FROM $table_name"; 1682 $db->mssqlnative_set_query_options(array('Scrollable' => SQLSRV_CURSOR_STATIC)); 1683 $result = $db->sql_query($sql); 1684 1685 $retrieved_data = $db->mssqlnative_num_rows($result); 1686 1687 if (!$retrieved_data) 1688 { 1689 $db->sql_freeresult($result); 1690 return; 1691 } 1692 1693 $sql = "SELECT COLUMN_NAME, DATA_TYPE 1694 FROM INFORMATION_SCHEMA.COLUMNS 1695 WHERE INFORMATION_SCHEMA.COLUMNS.TABLE_NAME = '" . $db->sql_escape($table_name) . "'"; 1696 $result_fields = $db->sql_query($sql); 1697 1698 $i_num_fields = 0; 1699 while ($row = $db->sql_fetchrow($result_fields)) 1700 { 1701 $ary_type[$i_num_fields] = $row['DATA_TYPE']; 1702 $ary_name[$i_num_fields] = $row['COLUMN_NAME']; 1703 $i_num_fields++; 1704 } 1705 $db->sql_freeresult($result_fields); 1706 1707 $sql = "SELECT 1 as has_identity 1708 FROM INFORMATION_SCHEMA.COLUMNS 1709 WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; 1710 $result2 = $db->sql_query($sql); 1711 $row2 = $db->sql_fetchrow($result2); 1712 1713 if (!empty($row2['has_identity'])) 1714 { 1715 $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; 1716 $ident_set = true; 1717 } 1718 $db->sql_freeresult($result2); 1719 1720 while ($row = $db->sql_fetchrow($result)) 1721 { 1722 $schema_vals = $schema_fields = array(); 1723 1724 // Build the SQL statement to recreate the data. 1725 for ($i = 0; $i < $i_num_fields; $i++) 1726 { 1727 $str_val = $row[$ary_name[$i]]; 1728 1729 // defaults to type number - better quote just to be safe, so check for is_int too 1730 if (is_int($ary_type[$i]) || preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) 1731 { 1732 $str_quote = ''; 1733 $str_empty = "''"; 1734 $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val)); 1735 } 1736 else if (preg_match('#date|timestamp#i', $ary_type[$i])) 1737 { 1738 if (empty($str_val)) 1739 { 1740 $str_quote = ''; 1741 } 1742 else 1743 { 1744 $str_quote = "'"; 1745 } 1746 } 1747 else 1748 { 1749 $str_quote = ''; 1750 $str_empty = 'NULL'; 1751 } 1752 1753 if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val))) 1754 { 1755 $str_val = $str_empty; 1756 } 1757 1758 $schema_vals[$i] = $str_quote . $str_val . $str_quote; 1759 $schema_fields[$i] = $ary_name[$i]; 1760 } 1761 1762 // Take the ordered fields and their associated data and build it 1763 // into a valid sql statement to recreate that field in the data. 1764 $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n"; 1765 1766 $this->flush($sql_data); 1767 $sql_data = ''; 1768 } 1769 $db->sql_freeresult($result); 1770 1771 if ($ident_set) 1772 { 1773 $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; 1774 } 1775 $this->flush($sql_data); 1776 } 1777 1778 function write_data_odbc($table_name) 1779 { 1780 global $db; 1781 $ary_type = $ary_name = array(); 1782 $ident_set = false; 1783 $sql_data = ''; 1784 1785 // Grab all of the data from current table. 1786 $sql = "SELECT * 1787 FROM $table_name"; 1788 $result = $db->sql_query($sql); 1789 1790 $retrieved_data = odbc_num_rows($result); 1791 1792 if ($retrieved_data) 1793 { 1794 $sql = "SELECT 1 as has_identity 1795 FROM INFORMATION_SCHEMA.COLUMNS 1796 WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; 1797 $result2 = $db->sql_query($sql); 1798 $row2 = $db->sql_fetchrow($result2); 1799 if (!empty($row2['has_identity'])) 1800 { 1801 $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; 1802 $ident_set = true; 1803 } 1804 $db->sql_freeresult($result2); 1805 } 1806 1807 $i_num_fields = odbc_num_fields($result); 1808 1809 for ($i = 0; $i < $i_num_fields; $i++) 1810 { 1811 $ary_type[$i] = odbc_field_type($result, $i + 1); 1812 $ary_name[$i] = odbc_field_name($result, $i + 1); 1813 } 1814 1815 while ($row = $db->sql_fetchrow($result)) 1816 { 1817 $schema_vals = $schema_fields = array(); 1818 1819 // Build the SQL statement to recreate the data. 1820 for ($i = 0; $i < $i_num_fields; $i++) 1821 { 1822 $str_val = $row[$ary_name[$i]]; 1823 1824 if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) 1825 { 1826 $str_quote = ''; 1827 $str_empty = "''"; 1828 $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val)); 1829 } 1830 else if (preg_match('#date|timestamp#i', $ary_type[$i])) 1831 { 1832 if (empty($str_val)) 1833 { 1834 $str_quote = ''; 1835 } 1836 else 1837 { 1838 $str_quote = "'"; 1839 } 1840 } 1841 else 1842 { 1843 $str_quote = ''; 1844 $str_empty = 'NULL'; 1845 } 1846 1847 if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val))) 1848 { 1849 $str_val = $str_empty; 1850 } 1851 1852 $schema_vals[$i] = $str_quote . $str_val . $str_quote; 1853 $schema_fields[$i] = $ary_name[$i]; 1854 } 1855 1856 // Take the ordered fields and their associated data and build it 1857 // into a valid sql statement to recreate that field in the data. 1858 $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n"; 1859 1860 $this->flush($sql_data); 1861 1862 $sql_data = ''; 1863 1864 } 1865 $db->sql_freeresult($result); 1866 1867 if ($retrieved_data && $ident_set) 1868 { 1869 $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; 1870 } 1871 $this->flush($sql_data); 1872 } 1873 1874 } 1875 1876 class oracle_extractor extends base_extractor 1877 { 1878 function write_table($table_name) 1879 { 1880 global $db; 1881 $sql_data = '-- Table: ' . $table_name . "\n"; 1882 $sql_data .= "DROP TABLE $table_name\n/\n"; 1883 $sql_data .= "\nCREATE TABLE $table_name (\n"; 1884 1885 $sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_PRECISION, DATA_LENGTH, NULLABLE, DATA_DEFAULT 1886 FROM ALL_TAB_COLS 1887 WHERE table_name = '{$table_name}'"; 1888 $result = $db->sql_query($sql); 1889 1890 $rows = array(); 1891 while ($row = $db->sql_fetchrow($result)) 1892 { 1893 $line = ' "' . $row['column_name'] . '" ' . $row['data_type']; 1894 1895 if ($row['data_type'] !== 'CLOB') 1896 { 1897 if ($row['data_type'] !== 'VARCHAR2' && $row['data_type'] !== 'CHAR') 1898 { 1899 $line .= '(' . $row['data_precision'] . ')'; 1900 } 1901 else 1902 { 1903 $line .= '(' . $row['data_length'] . ')'; 1904 } 1905 } 1906 1907 if (!empty($row['data_default'])) 1908 { 1909 $line .= ' DEFAULT ' . $row['data_default']; 1910 } 1911 1912 if ($row['nullable'] == 'N') 1913 { 1914 $line .= ' NOT NULL'; 1915 } 1916 $rows[] = $line; 1917 } 1918 $db->sql_freeresult($result); 1919 1920 $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME 1921 FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B 1922 WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME 1923 AND B.CONSTRAINT_TYPE = 'P' 1924 AND A.TABLE_NAME = '{$table_name}'"; 1925 $result = $db->sql_query($sql); 1926 1927 $primary_key = array(); 1928 $contraint_name = ''; 1929 while ($row = $db->sql_fetchrow($result)) 1930 { 1931 $constraint_name = '"' . $row['constraint_name'] . '"'; 1932 $primary_key[] = '"' . $row['column_name'] . '"'; 1933 } 1934 $db->sql_freeresult($result); 1935 1936 if (sizeof($primary_key)) 1937 { 1938 $rows[] = " CONSTRAINT {$constraint_name} PRIMARY KEY (" . implode(', ', $primary_key) . ')'; 1939 } 1940 1941 $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME 1942 FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B 1943 WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME 1944 AND B.CONSTRAINT_TYPE = 'U' 1945 AND A.TABLE_NAME = '{$table_name}'"; 1946 $result = $db->sql_query($sql); 1947 1948 $unique = array(); 1949 $contraint_name = ''; 1950 while ($row = $db->sql_fetchrow($result)) 1951 { 1952 $constraint_name = '"' . $row['constraint_name'] . '"'; 1953 $unique[] = '"' . $row['column_name'] . '"'; 1954 } 1955 $db->sql_freeresult($result); 1956 1957 if (sizeof($unique)) 1958 { 1959 $rows[] = " CONSTRAINT {$constraint_name} UNIQUE (" . implode(', ', $unique) . ')'; 1960 } 1961 1962 $sql_data .= implode(",\n", $rows); 1963 $sql_data .= "\n)\n/\n"; 1964 1965 $sql = "SELECT A.REFERENCED_NAME, C.* 1966 FROM USER_DEPENDENCIES A, USER_TRIGGERS B, USER_SEQUENCES C 1967 WHERE A.REFERENCED_TYPE = 'SEQUENCE' 1968 AND A.NAME = B.TRIGGER_NAME 1969 AND B.TABLE_NAME = '{$table_name}' 1970 AND C.SEQUENCE_NAME = A.REFERENCED_NAME"; 1971 $result = $db->sql_query($sql); 1972 1973 $type = request_var('type', ''); 1974 1975 while ($row = $db->sql_fetchrow($result)) 1976 { 1977 $sql_data .= "\nDROP SEQUENCE \"{$row['referenced_name']}\"\n/\n"; 1978 $sql_data .= "\nCREATE SEQUENCE \"{$row['referenced_name']}\""; 1979 1980 if ($type == 'full') 1981 { 1982 $sql_data .= ' START WITH ' . $row['last_number']; 1983 } 1984 1985 $sql_data .= "\n/\n"; 1986 } 1987 $db->sql_freeresult($result); 1988 1989 $sql = "SELECT DESCRIPTION, WHEN_CLAUSE, TRIGGER_BODY 1990 FROM USER_TRIGGERS 1991 WHERE TABLE_NAME = '{$table_name}'"; 1992 $result = $db->sql_query($sql); 1993 while ($row = $db->sql_fetchrow($result)) 1994 { 1995 $sql_data .= "\nCREATE OR REPLACE TRIGGER {$row['description']}WHEN ({$row['when_clause']})\n{$row['trigger_body']}\n/\n"; 1996 } 1997 $db->sql_freeresult($result); 1998 1999 $sql = "SELECT A.INDEX_NAME, B.COLUMN_NAME 2000 FROM USER_INDEXES A, USER_IND_COLUMNS B 2001 WHERE A.UNIQUENESS = 'NONUNIQUE' 2002 AND A.INDEX_NAME = B.INDEX_NAME 2003 AND B.TABLE_NAME = '{$table_name}'"; 2004 $result = $db->sql_query($sql); 2005 2006 $index = array(); 2007 2008 while ($row = $db->sql_fetchrow($result)) 2009 { 2010 $index[$row['index_name']][] = $row['column_name']; 2011 } 2012 2013 foreach ($index as $index_name => $column_names) 2014 { 2015 $sql_data .= "\nCREATE INDEX $index_name ON $table_name(" . implode(', ', $column_names) . ")\n/\n"; 2016 } 2017 $db->sql_freeresult($result); 2018 $this->flush($sql_data); 2019 } 2020 2021 function write_data($table_name) 2022 { 2023 global $db; 2024 $ary_type = $ary_name = array(); 2025 2026 // Grab all of the data from current table. 2027 $sql = "SELECT * 2028 FROM $table_name"; 2029 $result = $db->sql_query($sql); 2030 2031 $i_num_fields = ocinumcols($result); 2032 2033 for ($i = 0; $i < $i_num_fields; $i++) 2034 { 2035 $ary_type[$i] = ocicolumntype($result, $i + 1); 2036 $ary_name[$i] = ocicolumnname($result, $i + 1); 2037 } 2038 2039 $sql_data = ''; 2040 2041 while ($row = $db->sql_fetchrow($result)) 2042 { 2043 $schema_vals = $schema_fields = array(); 2044 2045 // Build the SQL statement to recreate the data. 2046 for ($i = 0; $i < $i_num_fields; $i++) 2047 { 2048 // Oracle uses uppercase - we use lowercase 2049 $str_val = $row[strtolower($ary_name[$i])]; 2050 2051 if (preg_match('#char|text|bool|raw|clob#i', $ary_type[$i])) 2052 { 2053 $str_quote = ''; 2054 $str_empty = "''"; 2055 $str_val = sanitize_data_oracle($str_val); 2056 } 2057 else if (preg_match('#date|timestamp#i', $ary_type[$i])) 2058 { 2059 if (empty($str_val)) 2060 { 2061 $str_quote = ''; 2062 } 2063 else 2064 { 2065 $str_quote = "'"; 2066 } 2067 } 2068 else 2069 { 2070 $str_quote = ''; 2071 $str_empty = 'NULL'; 2072 } 2073 2074 if (empty($str_val) && $str_val !== '0') 2075 { 2076 $str_val = $str_empty; 2077 } 2078 2079 $schema_vals[$i] = $str_quote . $str_val . $str_quote; 2080 $schema_fields[$i] = '"' . $ary_name[$i] . '"'; 2081 } 2082 2083 // Take the ordered fields and their associated data and build it 2084 // into a valid sql statement to recreate that field in the data. 2085 $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ")\n/\n"; 2086 2087 $this->flush($sql_data); 2088 } 2089 $db->sql_freeresult($result); 2090 } 2091 2092 function write_start($prefix) 2093 { 2094 $sql_data = "--\n"; 2095 $sql_data .= "-- phpBB Backup Script\n"; 2096 $sql_data .= "-- Dump of tables for $prefix\n"; 2097 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; 2098 $sql_data .= "--\n"; 2099 $this->flush($sql_data); 2100 } 2101 } 2102 2103 // get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P) 2104 function get_usable_memory() 2105 { 2106 $val = trim(@ini_get('memory_limit')); 2107 2108 if (preg_match('/(\\d+)([mkg]?)/i', $val, $regs)) 2109 { 2110 $memory_limit = (int) $regs[1]; 2111 switch ($regs[2]) 2112 { 2113 2114 case 'k': 2115 case 'K': 2116 $memory_limit *= 1024; 2117 break; 2118 2119 case 'm': 2120 case 'M': 2121 $memory_limit *= 1048576; 2122 break; 2123 2124 case 'g': 2125 case 'G': 2126 $memory_limit *= 1073741824; 2127 break; 2128 } 2129 2130 // how much memory PHP requires at the start of export (it is really a little less) 2131 if ($memory_limit > 6100000) 2132 { 2133 $memory_limit -= 6100000; 2134 } 2135 2136 // allow us to consume half of the total memory available 2137 $memory_limit /= 2; 2138 } 2139 else 2140 { 2141 // set the buffer to 1M if we have no clue how much memory PHP will give us :P 2142 $memory_limit = 1048576; 2143 } 2144 2145 return $memory_limit; 2146 } 2147 2148 function sanitize_data_mssql($text) 2149 { 2150 $data = preg_split('/[\n\t\r\b\f]/', $text); 2151 preg_match_all('/[\n\t\r\b\f]/', $text, $matches); 2152 2153 $val = array(); 2154 2155 foreach ($data as $value) 2156 { 2157 if (strlen($value)) 2158 { 2159 $val[] = "'" . $value . "'"; 2160 } 2161 if (sizeof($matches[0])) 2162 { 2163 $val[] = 'char(' . ord(array_shift($matches[0])) . ')'; 2164 } 2165 } 2166 2167 return implode('+', $val); 2168 } 2169 2170 function sanitize_data_oracle($text) 2171 { 2172 // $data = preg_split('/[\0\n\t\r\b\f\'"\/\\\]/', $text); 2173 // preg_match_all('/[\0\n\t\r\b\f\'"\/\\\]/', $text, $matches); 2174 $data = preg_split('/[\0\b\f\'\/]/', $text); 2175 preg_match_all('/[\0\r\b\f\'\/]/', $text, $matches); 2176 2177 $val = array(); 2178 2179 foreach ($data as $value) 2180 { 2181 if (strlen($value)) 2182 { 2183 $val[] = "'" . $value . "'"; 2184 } 2185 if (sizeof($matches[0])) 2186 { 2187 $val[] = 'chr(' . ord(array_shift($matches[0])) . ')'; 2188 } 2189 } 2190 2191 return implode('||', $val); 2192 } 2193 2194 function sanitize_data_generic($text) 2195 { 2196 $data = preg_split('/[\n\t\r\b\f]/', $text); 2197 preg_match_all('/[\n\t\r\b\f]/', $text, $matches); 2198 2199 $val = array(); 2200 2201 foreach ($data as $value) 2202 { 2203 if (strlen($value)) 2204 { 2205 $val[] = "'" . $value . "'"; 2206 } 2207 if (sizeof($matches[0])) 2208 { 2209 $val[] = "'" . array_shift($matches[0]) . "'"; 2210 } 2211 } 2212 2213 return implode('||', $val); 2214 } 2215 2216 // modified from PHP.net 2217 function fgetd(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) 2218 { 2219 $record = ''; 2220 $delim_len = strlen($delim); 2221 2222 while (!$eof($fp)) 2223 { 2224 $pos = strpos($record, $delim); 2225 if ($pos === false) 2226 { 2227 $record .= $read($fp, $buffer); 2228 if ($eof($fp) && ($pos = strpos($record, $delim)) !== false) 2229 { 2230 $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR); 2231 return substr($record, 0, $pos); 2232 } 2233 } 2234 else 2235 { 2236 $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR); 2237 return substr($record, 0, $pos); 2238 } 2239 } 2240 2241 return false; 2242 } 2243 2244 function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) 2245 { 2246 static $array = array(); 2247 static $record = ''; 2248 2249 if (!sizeof($array)) 2250 { 2251 while (!$eof($fp)) 2252 { 2253 if (strpos($record, $delim) !== false) 2254 { 2255 $array = explode($delim, $record); 2256 $record = array_pop($array); 2257 break; 2258 } 2259 else 2260 { 2261 $record .= $read($fp, $buffer); 2262 } 2263 } 2264 if ($eof($fp) && strpos($record, $delim) !== false) 2265 { 2266 $array = explode($delim, $record); 2267 $record = array_pop($array); 2268 } 2269 } 2270 2271 if (sizeof($array)) 2272 { 2273 return array_shift($array); 2274 } 2275 2276 return false; 2277 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |