PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/phpBB/includes/acp/acp_database.php

https://github.com/naderman/phpbb-orchestra
PHP | 2074 lines | 1819 code | 204 blank | 51 comment | 195 complexity | ba64cb02e2f8205207cbc3b7ad43a5b2 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * @package acp
  5. * @version $Id$
  6. * @copyright (c) 2005 phpBB Group
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. */
  10. /**
  11. * @ignore
  12. */
  13. if (!defined('IN_PHPBB'))
  14. {
  15. exit;
  16. }
  17. /**
  18. * @package acp
  19. */
  20. class acp_database
  21. {
  22. var $u_action;
  23. function main($id, $mode)
  24. {
  25. global $cache, $db, $user, $auth, $template, $table_prefix;
  26. global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
  27. $user->add_lang('acp/database');
  28. $this->tpl_name = 'acp_database';
  29. $this->page_title = 'ACP_DATABASE';
  30. $action = request_var('action', '');
  31. $submit = (isset($_POST['submit'])) ? true : false;
  32. $template->assign_vars(array(
  33. 'MODE' => $mode
  34. ));
  35. switch ($mode)
  36. {
  37. case 'backup':
  38. $this->page_title = 'ACP_BACKUP';
  39. switch ($action)
  40. {
  41. case 'download':
  42. $type = request_var('type', '');
  43. $table = request_var('table', array(''));
  44. $format = request_var('method', '');
  45. $where = request_var('where', '');
  46. if (!sizeof($table))
  47. {
  48. trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
  49. }
  50. $store = $download = $structure = $schema_data = false;
  51. if ($where == 'store_and_download' || $where == 'store')
  52. {
  53. $store = true;
  54. }
  55. if ($where == 'store_and_download' || $where == 'download')
  56. {
  57. $download = true;
  58. }
  59. if ($type == 'full' || $type == 'structure')
  60. {
  61. $structure = true;
  62. }
  63. if ($type == 'full' || $type == 'data')
  64. {
  65. $schema_data = true;
  66. }
  67. @set_time_limit(1200);
  68. @set_time_limit(0);
  69. $time = time();
  70. $filename = 'backup_' . $time . '_' . unique_id();
  71. switch ($db->sql_layer)
  72. {
  73. case 'mysqli':
  74. case 'mysql4':
  75. case 'mysql':
  76. $extractor = new mysql_extractor($download, $store, $format, $filename, $time);
  77. break;
  78. case 'sqlite':
  79. $extractor = new sqlite_extractor($download, $store, $format, $filename, $time);
  80. break;
  81. case 'postgres':
  82. $extractor = new postgres_extractor($download, $store, $format, $filename, $time);
  83. break;
  84. case 'oracle':
  85. $extractor = new oracle_extractor($download, $store, $format, $filename, $time);
  86. break;
  87. case 'mssql':
  88. case 'mssql_odbc':
  89. case 'mssqlnative':
  90. $extractor = new mssql_extractor($download, $store, $format, $filename, $time);
  91. break;
  92. case 'firebird':
  93. $extractor = new firebird_extractor($download, $store, $format, $filename, $time);
  94. break;
  95. }
  96. $extractor->write_start($table_prefix);
  97. foreach ($table as $table_name)
  98. {
  99. // Get the table structure
  100. if ($structure)
  101. {
  102. $extractor->write_table($table_name);
  103. }
  104. else
  105. {
  106. // We might wanna empty out all that junk :D
  107. switch ($db->sql_layer)
  108. {
  109. case 'sqlite':
  110. case 'firebird':
  111. $extractor->flush('DELETE FROM ' . $table_name . ";\n");
  112. break;
  113. case 'mssql':
  114. case 'mssql_odbc':
  115. case 'mssqlnative':
  116. $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n");
  117. break;
  118. case 'oracle':
  119. $extractor->flush('TRUNCATE TABLE ' . $table_name . "/\n");
  120. break;
  121. default:
  122. $extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n");
  123. break;
  124. }
  125. }
  126. // Data
  127. if ($schema_data)
  128. {
  129. $extractor->write_data($table_name);
  130. }
  131. }
  132. $extractor->write_end();
  133. add_log('admin', 'LOG_DB_BACKUP');
  134. if ($download == true)
  135. {
  136. exit;
  137. }
  138. trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action));
  139. break;
  140. default:
  141. include($phpbb_root_path . 'includes/functions_install.' . $phpEx);
  142. $tables = get_tables($db);
  143. asort($tables);
  144. foreach ($tables as $table_name)
  145. {
  146. if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0)
  147. {
  148. $template->assign_block_vars('tables', array(
  149. 'TABLE' => $table_name
  150. ));
  151. }
  152. }
  153. unset($tables);
  154. $template->assign_vars(array(
  155. 'U_ACTION' => $this->u_action . '&amp;action=download'
  156. ));
  157. $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2');
  158. foreach ($available_methods as $type => $module)
  159. {
  160. if (!@extension_loaded($module))
  161. {
  162. continue;
  163. }
  164. $template->assign_block_vars('methods', array(
  165. 'TYPE' => $type
  166. ));
  167. }
  168. $template->assign_block_vars('methods', array(
  169. 'TYPE' => 'text'
  170. ));
  171. break;
  172. }
  173. break;
  174. case 'restore':
  175. $this->page_title = 'ACP_RESTORE';
  176. switch ($action)
  177. {
  178. case 'submit':
  179. $delete = request_var('delete', '');
  180. $file = request_var('file', '');
  181. if (!preg_match('#^backup_\d{10,}_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
  182. {
  183. trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
  184. }
  185. $file_name = $phpbb_root_path . 'store/' . $matches[0];
  186. if (!file_exists($file_name) || !is_readable($file_name))
  187. {
  188. trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
  189. }
  190. if ($delete)
  191. {
  192. if (confirm_box(true))
  193. {
  194. unlink($file_name);
  195. add_log('admin', 'LOG_DB_DELETE');
  196. trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action));
  197. }
  198. else
  199. {
  200. confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file)));
  201. }
  202. }
  203. else
  204. {
  205. $download = request_var('download', '');
  206. if ($download)
  207. {
  208. $name = $matches[0];
  209. switch ($matches[1])
  210. {
  211. case 'sql':
  212. $mimetype = 'text/x-sql';
  213. break;
  214. case 'sql.bz2':
  215. $mimetype = 'application/x-bzip2';
  216. break;
  217. case 'sql.gz':
  218. $mimetype = 'application/x-gzip';
  219. break;
  220. }
  221. header('Pragma: no-cache');
  222. header("Content-Type: $mimetype; name=\"$name\"");
  223. header("Content-disposition: attachment; filename=$name");
  224. @set_time_limit(0);
  225. $fp = @fopen($file_name, 'rb');
  226. if ($fp !== false)
  227. {
  228. while (!feof($fp))
  229. {
  230. echo fread($fp, 8192);
  231. }
  232. fclose($fp);
  233. }
  234. flush();
  235. exit;
  236. }
  237. switch ($matches[1])
  238. {
  239. case 'sql':
  240. $fp = fopen($file_name, 'rb');
  241. $read = 'fread';
  242. $seek = 'fseek';
  243. $eof = 'feof';
  244. $close = 'fclose';
  245. $fgetd = 'fgetd';
  246. break;
  247. case 'sql.bz2':
  248. $fp = bzopen($file_name, 'r');
  249. $read = 'bzread';
  250. $seek = '';
  251. $eof = 'feof';
  252. $close = 'bzclose';
  253. $fgetd = 'fgetd_seekless';
  254. break;
  255. case 'sql.gz':
  256. $fp = gzopen($file_name, 'rb');
  257. $read = 'gzread';
  258. $seek = 'gzseek';
  259. $eof = 'gzeof';
  260. $close = 'gzclose';
  261. $fgetd = 'fgetd';
  262. break;
  263. }
  264. switch ($db->sql_layer)
  265. {
  266. case 'mysql':
  267. case 'mysql4':
  268. case 'mysqli':
  269. case 'sqlite':
  270. while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false)
  271. {
  272. $db->sql_query($sql);
  273. }
  274. break;
  275. case 'firebird':
  276. $delim = ";\n";
  277. while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false)
  278. {
  279. $query = trim($sql);
  280. if (substr($query, 0, 8) === 'SET TERM')
  281. {
  282. $delim = $query[9] . "\n";
  283. continue;
  284. }
  285. $db->sql_query($query);
  286. }
  287. break;
  288. case 'postgres':
  289. $delim = ";\n";
  290. while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false)
  291. {
  292. $query = trim($sql);
  293. if (substr($query, 0, 13) == 'CREATE DOMAIN')
  294. {
  295. list(, , $domain) = explode(' ', $query);
  296. $sql = "SELECT domain_name
  297. FROM information_schema.domains
  298. WHERE domain_name = '$domain';";
  299. $result = $db->sql_query($sql);
  300. if (!$db->sql_fetchrow($result))
  301. {
  302. $db->sql_query($query);
  303. }
  304. $db->sql_freeresult($result);
  305. }
  306. else
  307. {
  308. $db->sql_query($query);
  309. }
  310. if (substr($query, 0, 4) == 'COPY')
  311. {
  312. while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.')
  313. {
  314. if ($sub === false)
  315. {
  316. trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING);
  317. }
  318. pg_put_line($db->db_connect_id, $sub . "\n");
  319. }
  320. pg_put_line($db->db_connect_id, "\\.\n");
  321. pg_end_copy($db->db_connect_id);
  322. }
  323. }
  324. break;
  325. case 'oracle':
  326. while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false)
  327. {
  328. $db->sql_query($sql);
  329. }
  330. break;
  331. case 'mssql':
  332. case 'mssql_odbc':
  333. case 'mssqlnative':
  334. while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false)
  335. {
  336. $db->sql_query($sql);
  337. }
  338. break;
  339. }
  340. $close($fp);
  341. // Purge the cache due to updated data
  342. $cache->purge();
  343. add_log('admin', 'LOG_DB_RESTORE');
  344. trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action));
  345. break;
  346. }
  347. default:
  348. $methods = array('sql');
  349. $available_methods = array('sql.gz' => 'zlib', 'sql.bz2' => 'bz2');
  350. foreach ($available_methods as $type => $module)
  351. {
  352. if (!@extension_loaded($module))
  353. {
  354. continue;
  355. }
  356. $methods[] = $type;
  357. }
  358. $dir = $phpbb_root_path . 'store/';
  359. $dh = @opendir($dir);
  360. $backup_files = array();
  361. if ($dh)
  362. {
  363. while (($file = readdir($dh)) !== false)
  364. {
  365. if (preg_match('#^backup_(\d{10,})_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
  366. {
  367. if (in_array($matches[2], $methods))
  368. {
  369. $backup_files[(int) $matches[1]] = $file;
  370. }
  371. }
  372. }
  373. closedir($dh);
  374. }
  375. if (!empty($backup_files))
  376. {
  377. krsort($backup_files);
  378. foreach ($backup_files as $name => $file)
  379. {
  380. $template->assign_block_vars('files', array(
  381. 'FILE' => $file,
  382. 'NAME' => $user->format_date($name, 'd-m-Y H:i:s', true),
  383. 'SUPPORTED' => true,
  384. ));
  385. }
  386. }
  387. $template->assign_vars(array(
  388. 'U_ACTION' => $this->u_action . '&amp;action=submit'
  389. ));
  390. break;
  391. }
  392. break;
  393. }
  394. }
  395. }
  396. /**
  397. * @package acp
  398. */
  399. class base_extractor
  400. {
  401. var $fh;
  402. var $fp;
  403. var $write;
  404. var $close;
  405. var $store;
  406. var $download;
  407. var $time;
  408. var $format;
  409. var $run_comp = false;
  410. function base_extractor($download = false, $store = false, $format, $filename, $time)
  411. {
  412. $this->download = $download;
  413. $this->store = $store;
  414. $this->time = $time;
  415. $this->format = $format;
  416. switch ($format)
  417. {
  418. case 'text':
  419. $ext = '.sql';
  420. $open = 'fopen';
  421. $this->write = 'fwrite';
  422. $this->close = 'fclose';
  423. $mimetype = 'text/x-sql';
  424. break;
  425. case 'bzip2':
  426. $ext = '.sql.bz2';
  427. $open = 'bzopen';
  428. $this->write = 'bzwrite';
  429. $this->close = 'bzclose';
  430. $mimetype = 'application/x-bzip2';
  431. break;
  432. case 'gzip':
  433. $ext = '.sql.gz';
  434. $open = 'gzopen';
  435. $this->write = 'gzwrite';
  436. $this->close = 'gzclose';
  437. $mimetype = 'application/x-gzip';
  438. break;
  439. }
  440. if ($download == true)
  441. {
  442. $name = $filename . $ext;
  443. header('Pragma: no-cache');
  444. header("Content-Type: $mimetype; name=\"$name\"");
  445. header("Content-disposition: attachment; filename=$name");
  446. switch ($format)
  447. {
  448. case 'bzip2':
  449. ob_start();
  450. break;
  451. case 'gzip':
  452. if ((isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'msie') === false)
  453. {
  454. ob_start('ob_gzhandler');
  455. }
  456. else
  457. {
  458. $this->run_comp = true;
  459. }
  460. break;
  461. }
  462. }
  463. if ($store == true)
  464. {
  465. global $phpbb_root_path;
  466. $file = $phpbb_root_path . 'store/' . $filename . $ext;
  467. $this->fp = $open($file, 'w');
  468. if (!$this->fp)
  469. {
  470. trigger_error('FILE_WRITE_FAIL', E_USER_ERROR);
  471. }
  472. }
  473. }
  474. function write_end()
  475. {
  476. static $close;
  477. if ($this->store)
  478. {
  479. if ($close === null)
  480. {
  481. $close = $this->close;
  482. }
  483. $close($this->fp);
  484. }
  485. // bzip2 must be written all the way at the end
  486. if ($this->download && $this->format === 'bzip2')
  487. {
  488. $c = ob_get_clean();
  489. echo bzcompress($c);
  490. }
  491. }
  492. function flush($data)
  493. {
  494. static $write;
  495. if ($this->store === true)
  496. {
  497. if ($write === null)
  498. {
  499. $write = $this->write;
  500. }
  501. $write($this->fp, $data);
  502. }
  503. if ($this->download === true)
  504. {
  505. if ($this->format === 'bzip2' || $this->format === 'text' || ($this->format === 'gzip' && !$this->run_comp))
  506. {
  507. echo $data;
  508. }
  509. // we can write the gzip data as soon as we get it
  510. if ($this->format === 'gzip')
  511. {
  512. if ($this->run_comp)
  513. {
  514. echo gzencode($data);
  515. }
  516. else
  517. {
  518. ob_flush();
  519. flush();
  520. }
  521. }
  522. }
  523. }
  524. }
  525. /**
  526. * @package acp
  527. */
  528. class mysql_extractor extends base_extractor
  529. {
  530. function write_start($table_prefix)
  531. {
  532. $sql_data = "#\n";
  533. $sql_data .= "# phpBB Backup Script\n";
  534. $sql_data .= "# Dump of tables for $table_prefix\n";
  535. $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  536. $sql_data .= "#\n";
  537. $this->flush($sql_data);
  538. }
  539. function write_table($table_name)
  540. {
  541. global $db;
  542. static $new_extract;
  543. if ($new_extract === null)
  544. {
  545. if ($db->sql_layer === 'mysqli' || version_compare($db->sql_server_info(true), '3.23.20', '>='))
  546. {
  547. $new_extract = true;
  548. }
  549. else
  550. {
  551. $new_extract = false;
  552. }
  553. }
  554. if ($new_extract)
  555. {
  556. $this->new_write_table($table_name);
  557. }
  558. else
  559. {
  560. $this->old_write_table($table_name);
  561. }
  562. }
  563. function write_data($table_name)
  564. {
  565. global $db;
  566. if ($db->sql_layer === 'mysqli')
  567. {
  568. $this->write_data_mysqli($table_name);
  569. }
  570. else
  571. {
  572. $this->write_data_mysql($table_name);
  573. }
  574. }
  575. function write_data_mysqli($table_name)
  576. {
  577. global $db;
  578. $sql = "SELECT *
  579. FROM $table_name";
  580. $result = mysqli_query($db->db_connect_id, $sql, MYSQLI_USE_RESULT);
  581. if ($result != false)
  582. {
  583. $fields_cnt = mysqli_num_fields($result);
  584. // Get field information
  585. $field = mysqli_fetch_fields($result);
  586. $field_set = array();
  587. for ($j = 0; $j < $fields_cnt; $j++)
  588. {
  589. $field_set[] = $field[$j]->name;
  590. }
  591. $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
  592. $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
  593. $fields = implode(', ', $field_set);
  594. $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
  595. $first_set = true;
  596. $query_len = 0;
  597. $max_len = get_usable_memory();
  598. while ($row = mysqli_fetch_row($result))
  599. {
  600. $values = array();
  601. if ($first_set)
  602. {
  603. $query = $sql_data . '(';
  604. }
  605. else
  606. {
  607. $query .= ',(';
  608. }
  609. for ($j = 0; $j < $fields_cnt; $j++)
  610. {
  611. if (!isset($row[$j]) || is_null($row[$j]))
  612. {
  613. $values[$j] = 'NULL';
  614. }
  615. else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024))
  616. {
  617. $values[$j] = $row[$j];
  618. }
  619. else
  620. {
  621. $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
  622. }
  623. }
  624. $query .= implode(', ', $values) . ')';
  625. $query_len += strlen($query);
  626. if ($query_len > $max_len)
  627. {
  628. $this->flush($query . ";\n\n");
  629. $query = '';
  630. $query_len = 0;
  631. $first_set = true;
  632. }
  633. else
  634. {
  635. $first_set = false;
  636. }
  637. }
  638. mysqli_free_result($result);
  639. // check to make sure we have nothing left to flush
  640. if (!$first_set && $query)
  641. {
  642. $this->flush($query . ";\n\n");
  643. }
  644. }
  645. }
  646. function write_data_mysql($table_name)
  647. {
  648. global $db;
  649. $sql = "SELECT *
  650. FROM $table_name";
  651. $result = mysql_unbuffered_query($sql, $db->db_connect_id);
  652. if ($result != false)
  653. {
  654. $fields_cnt = mysql_num_fields($result);
  655. // Get field information
  656. $field = array();
  657. for ($i = 0; $i < $fields_cnt; $i++)
  658. {
  659. $field[] = mysql_fetch_field($result, $i);
  660. }
  661. $field_set = array();
  662. for ($j = 0; $j < $fields_cnt; $j++)
  663. {
  664. $field_set[] = $field[$j]->name;
  665. }
  666. $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
  667. $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
  668. $fields = implode(', ', $field_set);
  669. $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
  670. $first_set = true;
  671. $query_len = 0;
  672. $max_len = get_usable_memory();
  673. while ($row = mysql_fetch_row($result))
  674. {
  675. $values = array();
  676. if ($first_set)
  677. {
  678. $query = $sql_data . '(';
  679. }
  680. else
  681. {
  682. $query .= ',(';
  683. }
  684. for ($j = 0; $j < $fields_cnt; $j++)
  685. {
  686. if (!isset($row[$j]) || is_null($row[$j]))
  687. {
  688. $values[$j] = 'NULL';
  689. }
  690. else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp'))
  691. {
  692. $values[$j] = $row[$j];
  693. }
  694. else
  695. {
  696. $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
  697. }
  698. }
  699. $query .= implode(', ', $values) . ')';
  700. $query_len += strlen($query);
  701. if ($query_len > $max_len)
  702. {
  703. $this->flush($query . ";\n\n");
  704. $query = '';
  705. $query_len = 0;
  706. $first_set = true;
  707. }
  708. else
  709. {
  710. $first_set = false;
  711. }
  712. }
  713. mysql_free_result($result);
  714. // check to make sure we have nothing left to flush
  715. if (!$first_set && $query)
  716. {
  717. $this->flush($query . ";\n\n");
  718. }
  719. }
  720. }
  721. function new_write_table($table_name)
  722. {
  723. global $db;
  724. $sql = 'SHOW CREATE TABLE ' . $table_name;
  725. $result = $db->sql_query($sql);
  726. $row = $db->sql_fetchrow($result);
  727. $sql_data = '# Table: ' . $table_name . "\n";
  728. $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
  729. $this->flush($sql_data . $row['Create Table'] . ";\n\n");
  730. $db->sql_freeresult($result);
  731. }
  732. function old_write_table($table_name)
  733. {
  734. global $db;
  735. $sql_data = '# Table: ' . $table_name . "\n";
  736. $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
  737. $sql_data .= "CREATE TABLE $table_name(\n";
  738. $rows = array();
  739. $sql = "SHOW FIELDS
  740. FROM $table_name";
  741. $result = $db->sql_query($sql);
  742. while ($row = $db->sql_fetchrow($result))
  743. {
  744. $line = ' ' . $row['Field'] . ' ' . $row['Type'];
  745. if (!is_null($row['Default']))
  746. {
  747. $line .= " DEFAULT '{$row['Default']}'";
  748. }
  749. if ($row['Null'] != 'YES')
  750. {
  751. $line .= ' NOT NULL';
  752. }
  753. if ($row['Extra'] != '')
  754. {
  755. $line .= ' ' . $row['Extra'];
  756. }
  757. $rows[] = $line;
  758. }
  759. $db->sql_freeresult($result);
  760. $sql = "SHOW KEYS
  761. FROM $table_name";
  762. $result = $db->sql_query($sql);
  763. $index = array();
  764. while ($row = $db->sql_fetchrow($result))
  765. {
  766. $kname = $row['Key_name'];
  767. if ($kname != 'PRIMARY')
  768. {
  769. if ($row['Non_unique'] == 0)
  770. {
  771. $kname = "UNIQUE|$kname";
  772. }
  773. }
  774. if ($row['Sub_part'])
  775. {
  776. $row['Column_name'] .= '(' . $row['Sub_part'] . ')';
  777. }
  778. $index[$kname][] = $row['Column_name'];
  779. }
  780. $db->sql_freeresult($result);
  781. foreach ($index as $key => $columns)
  782. {
  783. $line = ' ';
  784. if ($key == 'PRIMARY')
  785. {
  786. $line .= 'PRIMARY KEY (' . implode(', ', $columns) . ')';
  787. }
  788. else if (strpos($key, 'UNIQUE') === 0)
  789. {
  790. $line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')';
  791. }
  792. else if (strpos($key, 'FULLTEXT') === 0)
  793. {
  794. $line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')';
  795. }
  796. else
  797. {
  798. $line .= "KEY $key (" . implode(', ', $columns) . ')';
  799. }
  800. $rows[] = $line;
  801. }
  802. $sql_data .= implode(",\n", $rows);
  803. $sql_data .= "\n);\n\n";
  804. $this->flush($sql_data);
  805. }
  806. }
  807. /**
  808. * @package acp
  809. */
  810. class sqlite_extractor extends base_extractor
  811. {
  812. function write_start($prefix)
  813. {
  814. $sql_data = "--\n";
  815. $sql_data .= "-- phpBB Backup Script\n";
  816. $sql_data .= "-- Dump of tables for $prefix\n";
  817. $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  818. $sql_data .= "--\n";
  819. $sql_data .= "BEGIN TRANSACTION;\n";
  820. $this->flush($sql_data);
  821. }
  822. function write_table($table_name)
  823. {
  824. global $db;
  825. $sql_data = '-- Table: ' . $table_name . "\n";
  826. $sql_data .= "DROP TABLE $table_name;\n";
  827. $sql = "SELECT sql
  828. FROM sqlite_master
  829. WHERE type = 'table'
  830. AND name = '" . $db->sql_escape($table_name) . "'
  831. ORDER BY type DESC, name;";
  832. $result = $db->sql_query($sql);
  833. $row = $db->sql_fetchrow($result);
  834. $db->sql_freeresult($result);
  835. // Create Table
  836. $sql_data .= $row['sql'] . ";\n";
  837. $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');");
  838. $ar = array();
  839. while ($row = $db->sql_fetchrow($result))
  840. {
  841. $ar[] = $row;
  842. }
  843. $db->sql_freeresult($result);
  844. foreach ($ar as $value)
  845. {
  846. if (strpos($value['name'], 'autoindex') !== false)
  847. {
  848. continue;
  849. }
  850. $result = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($value['name']) . "');");
  851. $fields = array();
  852. while ($row = $db->sql_fetchrow($result))
  853. {
  854. $fields[] = $row['name'];
  855. }
  856. $db->sql_freeresult($result);
  857. $sql_data .= 'CREATE ' . ($value['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $value['name'] . ' on ' . $table_name . ' (' . implode(', ', $fields) . ");\n";
  858. }
  859. $this->flush($sql_data . "\n");
  860. }
  861. function write_data($table_name)
  862. {
  863. global $db;
  864. static $proper;
  865. if (is_null($proper))
  866. {
  867. $proper = version_compare(PHP_VERSION, '5.1.3', '>=');
  868. }
  869. if ($proper)
  870. {
  871. $col_types = sqlite_fetch_column_types($db->db_connect_id, $table_name);
  872. }
  873. else
  874. {
  875. $sql = "SELECT sql
  876. FROM sqlite_master
  877. WHERE type = 'table'
  878. AND name = '" . $table_name . "'";
  879. $table_data = sqlite_single_query($db->db_connect_id, $sql);
  880. $table_data = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', '', $table_data);
  881. $table_data = trim($table_data);
  882. preg_match('#\((.*)\)#s', $table_data, $matches);
  883. $table_cols = explode(',', trim($matches[1]));
  884. foreach ($table_cols as $declaration)
  885. {
  886. $entities = preg_split('#\s+#', trim($declaration));
  887. $column_name = preg_replace('/"?([^"]+)"?/', '\1', $entities[0]);
  888. // Hit a primary key, those are not what we need :D
  889. if (empty($entities[1]) || (strtolower($entities[0]) === 'primary' && strtolower($entities[1]) === 'key'))
  890. {
  891. continue;
  892. }
  893. $col_types[$column_name] = $entities[1];
  894. }
  895. }
  896. $sql = "SELECT *
  897. FROM $table_name";
  898. $result = sqlite_unbuffered_query($db->db_connect_id, $sql);
  899. $rows = sqlite_fetch_all($result, SQLITE_ASSOC);
  900. $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES (';
  901. foreach ($rows as $row)
  902. {
  903. foreach ($row as $column_name => $column_data)
  904. {
  905. if (is_null($column_data))
  906. {
  907. $row[$column_name] = 'NULL';
  908. }
  909. else if ($column_data == '')
  910. {
  911. $row[$column_name] = "''";
  912. }
  913. else if (strpos($col_types[$column_name], 'text') !== false || strpos($col_types[$column_name], 'char') !== false || strpos($col_types[$column_name], 'blob') !== false)
  914. {
  915. $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data));
  916. }
  917. }
  918. $this->flush($sql_insert . implode(', ', $row) . ");\n");
  919. }
  920. }
  921. function write_end()
  922. {
  923. $this->flush("COMMIT;\n");
  924. parent::write_end();
  925. }
  926. }
  927. /**
  928. * @package acp
  929. */
  930. class postgres_extractor extends base_extractor
  931. {
  932. function write_start($prefix)
  933. {
  934. $sql_data = "--\n";
  935. $sql_data .= "-- phpBB Backup Script\n";
  936. $sql_data .= "-- Dump of tables for $prefix\n";
  937. $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  938. $sql_data .= "--\n";
  939. $sql_data .= "BEGIN TRANSACTION;\n";
  940. $this->flush($sql_data);
  941. }
  942. function write_table($table_name)
  943. {
  944. global $db;
  945. static $domains_created = array();
  946. $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default
  947. FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b
  948. WHERE a.domain_name = b.domain_name
  949. AND b.table_name = '{$table_name}'";
  950. $result = $db->sql_query($sql);
  951. while ($row = $db->sql_fetchrow($result))
  952. {
  953. if (empty($domains_created[$row['domain_name']]))
  954. {
  955. $domains_created[$row['domain_name']] = true;
  956. //$sql_data = "DROP DOMAIN {$row['domain_name']};\n";
  957. $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}";
  958. if (!empty($row['character_maximum_length']))
  959. {
  960. $sql_data .= '(' . $row['character_maximum_length'] . ')';
  961. }
  962. $sql_data .= ' NOT NULL';
  963. if (!empty($row['domain_default']))
  964. {
  965. $sql_data .= ' DEFAULT ' . $row['domain_default'];
  966. }
  967. $this->flush($sql_data . ";\n");
  968. }
  969. }
  970. $sql_data = '-- Table: ' . $table_name . "\n";
  971. $sql_data .= "DROP TABLE $table_name;\n";
  972. // PGSQL does not "tightly" bind sequences and tables, we must guess...
  973. $sql = "SELECT relname
  974. FROM pg_class
  975. WHERE relkind = 'S'
  976. AND relname = '{$table_name}_seq'";
  977. $result = $db->sql_query($sql);
  978. // We don't even care about storing the results. We already know the answer if we get rows back.
  979. if ($db->sql_fetchrow($result))
  980. {
  981. $sql_data .= "DROP SEQUENCE {$table_name}_seq;\n";
  982. $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n";
  983. }
  984. $db->sql_freeresult($result);
  985. $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
  986. FROM pg_class c, pg_attribute a, pg_type t
  987. WHERE c.relname = '" . $db->sql_escape($table_name) . "'
  988. AND a.attnum > 0
  989. AND a.attrelid = c.oid
  990. AND a.atttypid = t.oid
  991. ORDER BY a.attnum";
  992. $result = $db->sql_query($field_query);
  993. $sql_data .= "CREATE TABLE $table_name(\n";
  994. $lines = array();
  995. while ($row = $db->sql_fetchrow($result))
  996. {
  997. // Get the data from the table
  998. $sql_get_default = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
  999. FROM pg_attrdef d, pg_class c
  1000. WHERE (c.relname = '" . $db->sql_escape($table_name) . "')
  1001. AND (c.oid = d.adrelid)
  1002. AND d.adnum = " . $row['attnum'];
  1003. $def_res = $db->sql_query($sql_get_default);
  1004. $def_row = $db->sql_fetchrow($def_res);
  1005. $db->sql_freeresult($def_res);
  1006. if (empty($def_row))
  1007. {
  1008. unset($row['rowdefault']);
  1009. }
  1010. else
  1011. {
  1012. $row['rowdefault'] = $def_row['rowdefault'];
  1013. }
  1014. if ($row['type'] == 'bpchar')
  1015. {
  1016. // Internally stored as bpchar, but isn't accepted in a CREATE TABLE statement.
  1017. $row['type'] = 'char';
  1018. }
  1019. $line = ' ' . $row['field'] . ' ' . $row['type'];
  1020. if (strpos($row['type'], 'char') !== false)
  1021. {
  1022. if ($row['lengthvar'] > 0)
  1023. {
  1024. $line .= '(' . ($row['lengthvar'] - 4) . ')';
  1025. }
  1026. }
  1027. if (strpos($row['type'], 'numeric') !== false)
  1028. {
  1029. $line .= '(';
  1030. $line .= sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff));
  1031. $line .= ')';
  1032. }
  1033. if (isset($row['rowdefault']))
  1034. {
  1035. $line .= ' DEFAULT ' . $row['rowdefault'];
  1036. }
  1037. if ($row['notnull'] == 't')
  1038. {
  1039. $line .= ' NOT NULL';
  1040. }
  1041. $lines[] = $line;
  1042. }
  1043. $db->sql_freeresult($result);
  1044. // Get the listing of primary keys.
  1045. $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
  1046. FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia
  1047. WHERE (bc.oid = i.indrelid)
  1048. AND (ic.oid = i.indexrelid)
  1049. AND (ia.attrelid = i.indexrelid)
  1050. AND (ta.attrelid = bc.oid)
  1051. AND (bc.relname = '" . $db->sql_escape($table_name) . "')
  1052. AND (ta.attrelid = i.indrelid)
  1053. AND (ta.attnum = i.indkey[ia.attnum-1])
  1054. ORDER BY index_name, tab_name, column_name";
  1055. $result = $db->sql_query($sql_pri_keys);
  1056. $index_create = $index_rows = $primary_key = array();
  1057. // We do this in two steps. It makes placing the comma easier
  1058. while ($row = $db->sql_fetchrow($result))
  1059. {
  1060. if ($row['primary_key'] == 't')
  1061. {
  1062. $primary_key[] = $row['column_name'];
  1063. $primary_key_name = $row['index_name'];
  1064. }
  1065. else
  1066. {
  1067. // We have to store this all this info because it is possible to have a multi-column key...
  1068. // we can loop through it again and build the statement
  1069. $index_rows[$row['index_name']]['table'] = $table_name;
  1070. $index_rows[$row['index_name']]['unique'] = ($row['unique_key'] == 't') ? true : false;
  1071. $index_rows[$row['index_name']]['column_names'][] = $row['column_name'];
  1072. }
  1073. }
  1074. $db->sql_freeresult($result);
  1075. if (!empty($index_rows))
  1076. {
  1077. foreach ($index_rows as $idx_name => $props)
  1078. {
  1079. $index_create[] = 'CREATE ' . ($props['unique'] ? 'UNIQUE ' : '') . "INDEX $idx_name ON $table_name (" . implode(', ', $props['column_names']) . ");";
  1080. }
  1081. }
  1082. if (!empty($primary_key))
  1083. {
  1084. $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (" . implode(', ', $primary_key) . ")";
  1085. }
  1086. // Generate constraint clauses for CHECK constraints
  1087. $sql_checks = "SELECT conname as index_name, consrc
  1088. FROM pg_constraint, pg_class bc
  1089. WHERE conrelid = bc.oid
  1090. AND bc.relname = '" . $db->sql_escape($table_name) . "'
  1091. AND NOT EXISTS (
  1092. SELECT *
  1093. FROM pg_constraint as c, pg_inherits as i
  1094. WHERE i.inhrelid = pg_constraint.conrelid
  1095. AND c.conname = pg_constraint.conname
  1096. AND c.consrc = pg_constraint.consrc
  1097. AND c.conrelid = i.inhparent
  1098. )";
  1099. $result = $db->sql_query($sql_checks);
  1100. // Add the constraints to the sql file.
  1101. while ($row = $db->sql_fetchrow($result))
  1102. {
  1103. if (!is_null($row['consrc']))
  1104. {
  1105. $lines[] = ' CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['consrc'];
  1106. }
  1107. }
  1108. $db->sql_freeresult($result);
  1109. $sql_data .= implode(", \n", $lines);
  1110. $sql_data .= "\n);\n";
  1111. if (!empty($index_create))
  1112. {
  1113. $sql_data .= implode("\n", $index_create) . "\n\n";
  1114. }
  1115. $this->flush($sql_data);
  1116. }
  1117. function write_data($table_name)
  1118. {
  1119. global $db;
  1120. // Grab all of the data from current table.
  1121. $sql = "SELECT *
  1122. FROM $table_name";
  1123. $result = $db->sql_query($sql);
  1124. $i_num_fields = pg_num_fields($result);
  1125. $seq = '';
  1126. for ($i = 0; $i < $i_num_fields; $i++)
  1127. {
  1128. $ary_type[] = pg_field_type($result, $i);
  1129. $ary_name[] = pg_field_name($result, $i);
  1130. $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
  1131. FROM pg_attrdef d, pg_class c
  1132. WHERE (c.relname = '{$table_name}')
  1133. AND (c.oid = d.adrelid)
  1134. AND d.adnum = " . strval($i + 1);
  1135. $result2 = $db->sql_query($sql);
  1136. if ($row = $db->sql_fetchrow($result2))
  1137. {
  1138. // Determine if we must reset the sequences
  1139. if (strpos($row['rowdefault'], "nextval('") === 0)
  1140. {
  1141. $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";
  1142. }
  1143. }
  1144. }
  1145. $this->flush("COPY $table_name (" . implode(', ', $ary_name) . ') FROM stdin;' . "\n");
  1146. while ($row = $db->sql_fetchrow($result))
  1147. {
  1148. $schema_vals = array();
  1149. // Build the SQL statement to recreate the data.
  1150. for ($i = 0; $i < $i_num_fields; $i++)
  1151. {
  1152. $str_val = $row[$ary_name[$i]];
  1153. if (preg_match('#char|text|bool|bytea#i', $ary_type[$i]))
  1154. {
  1155. $str_val = str_replace(array("\n", "\t", "\r", "\b", "\f", "\v"), array('\n', '\t', '\r', '\b', '\f', '\v'), addslashes($str_val));
  1156. $str_empty = '';
  1157. }
  1158. else
  1159. {
  1160. $str_empty = '\N';
  1161. }
  1162. if (empty($str_val) && $str_val !== '0')
  1163. {
  1164. $str_val = $str_empty;
  1165. }
  1166. $schema_vals[] = $str_val;
  1167. }
  1168. // Take the ordered fields and their associated data and build it
  1169. // into a valid sql statement to recreate that field in the data.
  1170. $this->flush(implode("\t", $schema_vals) . "\n");
  1171. }
  1172. $db->sql_freeresult($result);
  1173. $this->flush("\\.\n");
  1174. // Write out the sequence statements
  1175. $this->flush($seq);
  1176. }
  1177. function write_end()
  1178. {
  1179. $this->flush("COMMIT;\n");
  1180. parent::write_end();
  1181. }
  1182. }
  1183. /**
  1184. * @package acp
  1185. */
  1186. class mssql_extractor extends base_extractor
  1187. {
  1188. function write_end()
  1189. {
  1190. $this->flush("COMMIT\nGO\n");
  1191. parent::write_end();
  1192. }
  1193. function write_start($prefix)
  1194. {
  1195. $sql_data = "--\n";
  1196. $sql_data .= "-- phpBB Backup Script\n";
  1197. $sql_data .= "-- Dump of tables for $prefix\n";
  1198. $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  1199. $sql_data .= "--\n";
  1200. $sql_data .= "BEGIN TRANSACTION\n";
  1201. $sql_data .= "GO\n";
  1202. $this->flush($sql_data);
  1203. }
  1204. function write_table($table_name)
  1205. {
  1206. global $db;
  1207. $sql_data = '-- Table: ' . $table_name . "\n";
  1208. $sql_data .= "IF OBJECT_ID(N'$table_name', N'U') IS NOT NULL\n";
  1209. $sql_data .= "DROP TABLE $table_name;\n";
  1210. $sql_data .= "GO\n";
  1211. $sql_data .= "\nCREATE TABLE [$table_name] (\n";
  1212. $rows = array();
  1213. $text_flag = false;
  1214. $sql = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as IS_IDENTITY
  1215. FROM INFORMATION_SCHEMA.COLUMNS
  1216. WHERE TABLE_NAME = '$table_name'";
  1217. $result = $db->sql_query($sql);
  1218. while ($row = $db->sql_fetchrow($result))
  1219. {
  1220. $line = "\t[{$row['COLUMN_NAME']}] [{$row['DATA_TYPE']}]";
  1221. if ($row['DATA_TYPE'] == 'text')
  1222. {
  1223. $text_flag = true;
  1224. }
  1225. if ($row['IS_IDENTITY'])
  1226. {
  1227. $line .= ' IDENTITY (1 , 1)';
  1228. }
  1229. if ($row['CHARACTER_MAXIMUM_LENGTH'] && $row['DATA_TYPE'] !== 'text')
  1230. {
  1231. $line .= ' (' . $row['CHARACTER_MAXIMUM_LENGTH'] . ')';
  1232. }
  1233. if ($row['IS_NULLABLE'] == 'YES')
  1234. {
  1235. $line .= ' NULL';
  1236. }
  1237. else
  1238. {
  1239. $line .= ' NOT NULL';
  1240. }
  1241. if ($row['COLUMN_DEFAULT'])
  1242. {
  1243. $line .= ' DEFAULT ' . $row['COLUMN_DEFAULT'];
  1244. }
  1245. $rows[] = $line;
  1246. }
  1247. $db->sql_freeresult($result);
  1248. $sql_data .= implode(",\n", $rows);
  1249. $sql_data .= "\n) ON [PRIMARY]";
  1250. if ($text_flag)
  1251. {
  1252. $sql_data .= " TEXTIMAGE_ON [PRIMARY]";
  1253. }
  1254. $sql_data .= "\nGO\n\n";
  1255. $rows = array();
  1256. $sql = "SELECT CONSTRAINT_NAME, COLUMN_NAME
  1257. FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
  1258. WHERE TABLE_NAME = '$table_name'";
  1259. $result = $db->sql_query($sql);
  1260. while ($row = $db->sql_fetchrow($result))
  1261. {
  1262. if (!sizeof($rows))
  1263. {
  1264. $sql_data .= "ALTER TABLE [$table_name] WITH NOCHECK ADD\n";
  1265. $sql_data .= "\tCONSTRAINT [{$row['CONSTRAINT_NAME']}] PRIMARY KEY CLUSTERED \n\t(\n";
  1266. }
  1267. $rows[] = "\t\t[{$row['COLUMN_NAME']}]";
  1268. }
  1269. if (sizeof($rows))
  1270. {
  1271. $sql_data .= implode(",\n", $rows);
  1272. $sql_data .= "\n\t) ON [PRIMARY] \nGO\n";
  1273. }
  1274. $db->sql_freeresult($result);
  1275. $index = array();
  1276. $sql = "EXEC sp_statistics '$table_name'";
  1277. $result = $db->sql_query($sql);
  1278. while ($row = $db->sql_fetchrow($result))
  1279. {
  1280. if ($row['TYPE'] == 3)
  1281. {
  1282. $index[$row['INDEX_NAME']][] = '[' . $row['COLUMN_NAME'] . ']';
  1283. }
  1284. }
  1285. $db->sql_freeresult($result);
  1286. foreach ($index as $index_name => $column_name)
  1287. {
  1288. $index[$index_name] = implode(', ', $column_name);
  1289. }
  1290. foreach ($index as $index_name => $columns)
  1291. {
  1292. $sql_data .= "\nCREATE INDEX [$index_name] ON [$table_name]($columns) ON [PRIMARY]\nGO\n";
  1293. }
  1294. $this->flush($sql_data);
  1295. }
  1296. function write_data($table_name)
  1297. {
  1298. global $db;
  1299. if ($db->sql_layer === 'mssql')
  1300. {
  1301. $this->write_data_mssql($table_name);
  1302. }
  1303. else if($db->sql_layer === 'mssqlnative')
  1304. {
  1305. $this->write_data_mssqlnative($table_name);
  1306. }
  1307. else
  1308. {
  1309. $this->write_data_odbc($table_name);
  1310. }
  1311. }
  1312. function write_data_mssql($table_name)
  1313. {
  1314. global $db;
  1315. $ary_type = $ary_name = array();
  1316. $ident_set = false;
  1317. $sql_data = '';
  1318. // Grab all of the data from current table.
  1319. $sql = "SELECT *
  1320. FROM $table_name";
  1321. $result = $db->sql_query($sql);
  1322. $retrieved_data = mssql_num_rows($result);
  1323. $i_num_fields = mssql_num_fields($result);
  1324. for ($i = 0; $i < $i_num_fields; $i++)
  1325. {
  1326. $ary_type[$i] = mssql_field_type($result, $i);
  1327. $ary_name[$i] = mssql_field_name($result, $i);
  1328. }
  1329. if ($retrieved_data)
  1330. {
  1331. $sql = "SELECT 1 as has_identity
  1332. FROM INFORMATION_SCHEMA.COLUMNS
  1333. WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
  1334. $result2 = $db->sql_query($sql);
  1335. $row2 = $db->sql_fetchrow($result2);
  1336. if (!empty($row2['has_identity']))
  1337. {
  1338. $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
  1339. $ident_set = true;
  1340. }
  1341. $db->sql_freeresult($result2);
  1342. }
  1343. while ($row = $db->sql_fetchrow($result))
  1344. {
  1345. $schema_vals = $schema_fields = array();
  1346. // Build the SQL statement to recreate the data.
  1347. for ($i = 0; $i < $i_num_fields; $i++)
  1348. {
  1349. $str_val = $row[$ary_name[$i]];
  1350. if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
  1351. {
  1352. $str_quote = '';
  1353. $str_empty = "''";
  1354. $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
  1355. }
  1356. else if (preg_match('#date|timestamp#i', $ary_type[$i]))
  1357. {
  1358. if (empty($str_val))
  1359. {
  1360. $str_quote = '';
  1361. }
  1362. else
  1363. {
  1364. $str_quote = "'";
  1365. }
  1366. }
  1367. else
  1368. {
  1369. $str_quote = '';
  1370. $str_empty = 'NULL';
  1371. }
  1372. if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
  1373. {
  1374. $str_val = $str_empty;
  1375. }
  1376. $schema_vals[$i] = $str_quote . $str_val . $str_quote;
  1377. $schema_fields[$i] = $ary_name[$i];
  1378. }
  1379. // Take the ordered fields and their associated data and build it
  1380. // into a valid sql statement to recreate that field in the data.
  1381. $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
  1382. $this->flush($sql_data);
  1383. $sql_data = '';
  1384. }
  1385. $db->sql_freeresult($result);
  1386. if ($retrieved_data && $ident_set)
  1387. {
  1388. $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
  1389. }
  1390. $this->flush($sql_data);
  1391. }
  1392. function write_data_mssqlnative($table_name)
  1393. {
  1394. global $db;
  1395. $ary_type = $ary_name = array();
  1396. $ident_set = false;
  1397. $sql_data = '';
  1398. // Grab all of the data from current table.
  1399. $sql = "SELECT * FROM $table_name";
  1400. $db->mssqlnative_set_query_options(array('Scrollable' => SQLSRV_CURSOR_STATIC));
  1401. $result = $db->sql_query($sql);
  1402. $retrieved_data = $db->mssqlnative_num_rows($result);
  1403. if (!$retrieved_data)
  1404. {
  1405. $db->sql_freeresult($result);
  1406. return;
  1407. }
  1408. $sql = "SELECT * FROM $table_name";
  1409. $result_fields = $db->sql_query_limit($sql, 1);
  1410. $row = new result_mssqlnative($result_fields);
  1411. $i_num_fields = $row->num_fields();
  1412. for ($i = 0; $i < $i_num_fields; $i++)
  1413. {
  1414. $ary_type[$i] = $row->field_type($i);
  1415. $ary_name[$i] = $row->field_name($i);
  1416. }
  1417. $db->sql_freeresult($result_fields);
  1418. $sql = "SELECT 1 as has_identity
  1419. FROM INFORMATION_SCHEMA.COLUMNS
  1420. WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
  1421. $result2 = $db->sql_query($sql);
  1422. $row2 = $db->sql_fetchrow($result2);
  1423. if (!empty($row2['has_identity']))
  1424. {
  1425. $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
  1426. $ident_set = true;
  1427. }
  1428. $db->sql_freeresult($result2);
  1429. while ($row = $db->sql_fetchrow($result))
  1430. {
  1431. $schema_vals = $schema_fields = array();
  1432. // Build the SQL statement to recreate the data.
  1433. for ($i = 0; $i < $i_num_fields; $i++)
  1434. {
  1435. $str_val = $row[$ary_name[$i]];
  1436. // defaults to type number - better quote just to be safe, so check for is_int too
  1437. if (is_int($ary_type[$i]) || preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
  1438. {
  1439. $str_quote = '';
  1440. $str_empty = "''";
  1441. $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
  1442. }
  1443. else if (preg_match('#date|timestamp#i', $ary_type[$i]))
  1444. {
  1445. if (empty($str_val))
  1446. {
  1447. $str_quote = '';
  1448. }
  1449. else
  1450. {
  1451. $str_quote = "'";
  1452. }
  1453. }
  1454. else
  1455. {
  1456. $str_quote = '';
  1457. $str_empty = 'NULL';
  1458. }
  1459. if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
  1460. {
  1461. $str_val = $str_empty;
  1462. }
  1463. $schema_vals[$i] = $str_quote . $str_val . $str_quote;
  1464. $schema_fields[$i] = $ary_name[$i];
  1465. }
  1466. // Take the ordered fields and their associated data and build it
  1467. // into a valid sql statement to recreate that field in the data.
  1468. $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
  1469. $this->flush($sql_data);
  1470. $sql_data = '';
  1471. }
  1472. $db->sql_freeresult($result);
  1473. if ($ident_set)
  1474. {
  1475. $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
  1476. }
  1477. $this->flush($sql_data);
  1478. }
  1479. function write_data_odbc($table_name)
  1480. {
  1481. global $db;
  1482. $ary_type = $ary_name = array();
  1483. $ident_set = false;
  1484. $sql_data = '';
  1485. // Grab all of the data from current table.
  1486. $sql = "SELECT *
  1487. FROM $table_name";
  1488. $result = $db->sql_query($sql);
  1489. $retrieved_data = odbc_num_rows($result);
  1490. if ($retrieved_data)
  1491. {
  1492. $sql = "SELECT 1 as has_identity
  1493. FROM INFORMATION_SCHEMA.COLUMNS
  1494. WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
  1495. $result2 = $db->sql_query($sql);
  1496. $row2 = $db->sql_fetchrow($result2);
  1497. if (!empty($row2['has_identity']))
  1498. {
  1499. $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
  1500. $ident_set = true;
  1501. }
  1502. $db->sql_freeresult($result2);
  1503. }
  1504. $i_num_fields = odbc_num_fields($result);
  1505. for ($i = 0; $i < $i_num_fields; $i++)
  1506. {
  1507. $ary_type[$i] = odbc_field_type($result, $i + 1);
  1508. $ary_name[$i] = odbc_field_name($result, $i + 1);
  1509. }
  1510. while ($row = $db->sql_fetchrow($result))
  1511. {
  1512. $schema_vals = $schema_fields = array();
  1513. // Build the SQL statement to recreate the data.
  1514. for ($i = 0; $i < $i_num_fields; $i++)
  1515. {
  1516. $str_val = $row[$ary_name[$i]];
  1517. if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
  1518. {
  1519. $str_quote = '';
  1520. $str_empty = "''";
  1521. $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
  1522. }
  1523. else if (preg_match('#date|timestamp#i', $ary_type[$i]))
  1524. {
  1525. if (empty($str_val))
  1526. {
  1527. $str_quote = '';
  1528. }
  1529. else
  1530. {
  1531. $str_quote = "'";
  1532. }
  1533. }
  1534. else
  1535. {
  1536. $str_quote = '';
  1537. $str_empty = 'NULL';
  1538. }
  1539. if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
  1540. {
  1541. $str_val = $str_empty;
  1542. }
  1543. $schema_vals[$i] = $str_quote . $str_val . $str_quote;
  1544. $schema_fields[$i] = $ary_name[$i];
  1545. }
  1546. // Take the ordered fields and their associated data and build it
  1547. // into a valid sql statement to recreate that field in the data.
  1548. $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
  1549. $this->flush($sql_data);
  1550. $sql_data = '';
  1551. }
  1552. $db->sql_freeresult($result);
  1553. if ($retrieved_data && $ident_set)
  1554. {
  1555. $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
  1556. }
  1557. $this->flush($sql_data);
  1558. }
  1559. }
  1560. /**
  1561. * @package acp
  1562. */
  1563. class oracle_extractor extends base_extractor
  1564. {
  1565. function write_table($table_name)
  1566. {
  1567. global $db;
  1568. $sql_data = '-- Table: ' . $table_name . "\n";
  1569. $sql_data .= "DROP TABLE $table_name\n/\n";
  1570. $sql_data .= "\nCREATE TABLE $table_name (\n";
  1571. $sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_PRECISION, DATA_LENGTH, NULLABLE, DATA_DEFAULT
  1572. FROM ALL_TAB_COLS
  1573. WHERE table_name = '{$table_name}'";
  1574. $result = $db->sql_query($sql);
  1575. $rows = array();
  1576. while ($row = $db->sql_fetchrow($result))
  1577. {
  1578. $line = ' "' . $row['column_name'] . '" ' . $row['data_type'];
  1579. if ($row['data_type'] !== 'CLOB')
  1580. {
  1581. if ($row['data_type'] !== 'VARCHAR2' && $row['data_type'] !== 'CHAR')
  1582. {
  1583. $line .= '(' . $row['data_precision'] . ')';
  1584. }
  1585. else
  1586. {
  1587. $line .= '(' . $row['data_length'] . ')';
  1588. }
  1589. }
  1590. if (!empty($row['data_default']))
  1591. {
  1592. $line .= ' DEFAULT ' . $row['data_default'];
  1593. }
  1594. if ($row['nullable'] == 'N')
  1595. {
  1596. $line .= ' NOT NULL';
  1597. }
  1598. $rows[] = $line;
  1599. }
  1600. $db->sql_freeresult($result);
  1601. $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
  1602. FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
  1603. WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
  1604. AND B.CONSTRAINT_TYPE = 'P'
  1605. AND A.TABLE_NAME = '{$table_name}'";
  1606. $result = $db->sql_query($sql);
  1607. $primary_key = array();
  1608. $contraint_name = '';
  1609. while ($row = $db->sql_fetchrow($result))
  1610. {
  1611. $constraint_name = '"' . $row['constraint_name'] . '"';
  1612. $primary_key[] = '"' . $row['column_name'] . '"';
  1613. }
  1614. $db->sql_freeresult($result);
  1615. if (sizeof($primary_key))
  1616. {
  1617. $rows[] = " CONSTRAINT {$constraint_name} PRIMARY KEY (" . implode(', ', $primary_key) . ')';
  1618. }
  1619. $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
  1620. FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
  1621. WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
  1622. AND B.CONSTRAINT_TYPE = 'U'
  1623. AND A.TABLE_NAME = '{$table_name}'";
  1624. $result = $db->sql_query($sql);
  1625. $unique = array();
  1626. $contraint_name = '';
  1627. while ($row = $db->sql_fetchrow($result))
  1628. {
  1629. $constraint_name = '"' . $row['constraint_name'] . '"';
  1630. $unique[] = '"' . $row['column_name'] . '"';
  1631. }
  1632. $db->sql_freeresult($result);
  1633. if (sizeof($unique))
  1634. {
  1635. $rows[] = " CONSTRAINT {$constraint_name} UNIQUE (" . implode(', ', $unique) . ')';
  1636. }
  1637. $sql_data .= implode(",\n", $rows);
  1638. $sql_data .= "\n)\n/\n";
  1639. $sql = "SELECT A.REFERENCED_NAME, C.*
  1640. FROM USER_DEPENDENCIES A, USER_TRIGGERS B, USER_SEQUENCES C
  1641. WHERE A.REFERENCED_TYPE = 'SEQUENCE'
  1642. AND A.NAME = B.TRIGGER_NAME
  1643. AND B.TABLE_NAME = '{$table_name}'
  1644. AND C.SEQUENCE_NAME = A.REFERENCED_NAME";
  1645. $result = $db->sql_query($sql);
  1646. $type = request_var('type', '');
  1647. while ($row = $db->sql_fetchrow($result))
  1648. {
  1649. $sql_data .= "\nDROP SEQUENCE \"{$row['referenced_name']}\"\n/\n";
  1650. $sql_data .= "\nCREATE SEQUENCE \"{$row['referenced_name']}\"";
  1651. if ($type == 'full')
  1652. {
  1653. $sql_data .= ' START WITH ' . $row['last_number'];
  1654. }
  1655. $sql_data .= "\n/\n";
  1656. }
  1657. $db->sql_freeresult($result);
  1658. $sql = "SELECT DESCRIPTION, WHEN_CLAUSE, TRIGGER_BODY
  1659. FROM USER_TRIGGERS
  1660. WHERE TABLE_NAME = '{$table_name}'";
  1661. $result = $db->sql_query($sql);
  1662. while ($row = $db->sql_fetchrow($result))
  1663. {
  1664. $sql_data .= "\nCREATE OR REPLACE TRIGGER {$row['description']}WHEN ({$row['when_clause']})\n{$row['trigger_body']}\n/\n";
  1665. }
  1666. $db->sql_freeresult($result);
  1667. $sql = "SELECT A.INDEX_NAME, B.COLUMN_NAME
  1668. FROM USER_INDEXES A, USER_IND_COLUMNS B
  1669. WHERE A.UNIQUENESS = 'NONUNIQUE'
  1670. AND A.INDEX_NAME = B.INDEX_NAME
  1671. AND B.TABLE_NAME = '{$table_name}'";
  1672. $result = $db->sql_query($sql);
  1673. $index = array();
  1674. while ($row = $db->sql_fetchrow($result))
  1675. {
  1676. $index[$row['index_name']][] = $row['column_name'];
  1677. }
  1678. foreach ($index as $index_name => $column_names)
  1679. {
  1680. $sql_data .= "\nCREATE INDEX $index_name ON $table_name(" . implode(', ', $column_names) . ")\n/\n";
  1681. }
  1682. $db->sql_freeresult($result);
  1683. $this->flush($sql_data);
  1684. }
  1685. function write_data($table_name)
  1686. {
  1687. global $db;
  1688. $ary_type = $ary_name = array();
  1689. // Grab all of the data from current table.
  1690. $sql = "SELECT *
  1691. FROM $table_name";
  1692. $result = $db->sql_query($sql);
  1693. $i_num_fields = ocinumcols($result);
  1694. for ($i = 0; $i < $i_num_fields; $i++)
  1695. {
  1696. $ary_type[$i] = ocicolumntype($result, $i + 1);
  1697. $ary_name[$i] = ocicolumnname($result, $i + 1);
  1698. }
  1699. $sql_data = '';
  1700. while ($row = $db->sql_fetchrow($result))
  1701. {
  1702. $schema_vals = $schema_fields = array();
  1703. // Build the SQL statement to recreate the data.
  1704. for ($i = 0; $i < $i_num_fields; $i++)
  1705. {
  1706. // Oracle uses uppercase - we use lowercase
  1707. $str_val = $row[strtolower($ary_name[$i])];
  1708. if (preg_match('#char|text|bool|raw|clob#i', $ary_type[$i]))
  1709. {
  1710. $str_quote = '';
  1711. $str_empty = "''";
  1712. $str_val = sanitize_data_oracle($str_val);
  1713. }
  1714. else if (preg_match('#date|timestamp#i', $ary_type[$i]))
  1715. {
  1716. if (empty($str_val))
  1717. {
  1718. $str_quote = '';
  1719. }
  1720. else
  1721. {
  1722. $str_quote = "'";
  1723. }
  1724. }
  1725. else
  1726. {
  1727. $str_quote = '';
  1728. $str_empty = 'NULL';
  1729. }
  1730. if (empty($str_val) && $str_val !== '0')
  1731. {
  1732. $str_val = $str_empty;
  1733. }
  1734. $schema_vals[$i] = $str_quote . $str_val . $str_quote;
  1735. $schema_fields[$i] = '"' . $ary_name[$i] . '"';
  1736. }
  1737. // Take the ordered fields and their associated data and build it
  1738. // into a valid sql statement to recreate that field in the data.
  1739. $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ")\n/\n";
  1740. $this->flush($sql_data);
  1741. }
  1742. $db->sql_freeresult($result);
  1743. }
  1744. function write_start($prefix)
  1745. {
  1746. $sql_data = "--\n";
  1747. $sql_data .= "-- phpBB Backup Script\n";
  1748. $sql_data .= "-- Dump of tables for $prefix\n";
  1749. $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  1750. $sql_data .= "--\n";
  1751. $this->flush($sql_data);
  1752. }
  1753. }
  1754. /**
  1755. * @package acp
  1756. */
  1757. class firebird_extractor extends base_extractor
  1758. {
  1759. function write_start($prefix)
  1760. {
  1761. $sql_data = "--\n";
  1762. $sql_data .= "-- phpBB Backup Script\n";
  1763. $sql_data .= "-- Dump of tables for $prefix\n";
  1764. $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  1765. $sql_data .= "--\n";
  1766. $this->flush($sql_data);
  1767. }
  1768. function write_data($table_name)
  1769. {
  1770. global $db;
  1771. $ary_type = $ary_name = array();
  1772. // Grab all of the data from current table.
  1773. $sql = "SELECT *
  1774. FROM $table_name";
  1775. $result = $db->sql_query($sq