Advertisement
Guest User

Untitled

a guest
Jul 2nd, 2017
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.93 KB | None | 0 0
  1. <?php
  2. //bold("<br><br>Shuttle Dumper included");
  3. /**
  4. * Abstract dump file: provides common interface for writing
  5. * data to dump files.
  6. */
  7. abstract class Shuttle_Dump_File {
  8. /**
  9. * File Handle
  10. */
  11. protected $fh;
  12.  
  13. /**
  14. * Location of the dump file on the disk
  15. */
  16. protected $file_location;
  17.  
  18. abstract function write($string);
  19. abstract function end();
  20.  
  21. static function create($filename) {
  22. if (self::is_gzip($filename)) {
  23. return new Shuttle_Dump_File_Gzip($filename);
  24. }
  25. return new Shuttle_Dump_File_Plaintext($filename);
  26. }
  27. function __construct($file) {
  28. $this->file_location = $file;
  29. $this->fh = $this->open();
  30.  
  31. if (!$this->fh) {
  32. throw new Shuttle_Exception("Couldn't create gz file");
  33. }
  34. }
  35.  
  36. public static function is_gzip($filename) {
  37. return preg_match('~gz$~i', $filename);
  38. }
  39. }
  40.  
  41. /**
  42. * Plain text implementation. Uses standard file functions in PHP.
  43. */
  44. class Shuttle_Dump_File_Plaintext extends Shuttle_Dump_File {
  45. function open() {
  46. return fopen($this->file_location, 'w');
  47. }
  48. function write($string) {
  49. return fwrite($this->fh, $string);
  50. }
  51. function end() {
  52. return fclose($this->fh);
  53. }
  54. }
  55.  
  56. /**
  57. * Gzip implementation. Uses gz* functions.
  58. */
  59. class Shuttle_Dump_File_Gzip extends Shuttle_Dump_File {
  60. function open() {
  61. return gzopen($this->file_location, 'wb9');
  62. }
  63. function write($string) {
  64. return gzwrite($this->fh, $string);
  65. }
  66. function end() {
  67. return gzclose($this->fh);
  68. }
  69. }
  70.  
  71. /**
  72. * MySQL insert statement builder.
  73. */
  74. class Shuttle_Insert_Statement {
  75. private $rows = array();
  76. private $length = 0;
  77. private $table;
  78.  
  79. function __construct($table) {
  80. $this->table = $table;
  81. }
  82.  
  83. function reset() {
  84. $this->rows = array();
  85. $this->length = 0;
  86. }
  87.  
  88. function add_row($row) {
  89. $row = '(' . implode(",", $row) . ')';
  90. $this->rows[] = $row;
  91. $this->length += strlen($row);
  92. }
  93.  
  94. function get_sql() {
  95. if (empty($this->rows)) {
  96. return false;
  97. }
  98.  
  99. return 'INSERT INTO `' . $this->table . '` VALUES ' .
  100. implode(",\n", $this->rows) . '; ';
  101. }
  102.  
  103. function get_length() {
  104. return $this->length;
  105. }
  106. }
  107.  
  108. /**
  109. * Main facade
  110. */
  111. abstract class Shuttle_Dumper {
  112. /**
  113. * Maximum length of single insert statement
  114. */
  115. const INSERT_THRESHOLD = 838860;
  116.  
  117. /**
  118. * @var Shuttle_DBConn
  119. */
  120. public $db;
  121.  
  122. /**
  123. * @var Shuttle_Dump_File
  124. */
  125. public $dump_file;
  126.  
  127. /**
  128. * End of line style used in the dump
  129. */
  130. public $eol = "\r\n";
  131.  
  132. /**
  133. * Specificed tables to include
  134. */
  135. public $include_tables;
  136.  
  137. /**
  138. * Specified tables to exclude
  139. */
  140. public $exclude_tables = array();
  141.  
  142. /**
  143. * Factory method for dumper on current hosts's configuration.
  144. */
  145. static function create($db_options) {
  146. $db = Shuttle_DBConn::create($db_options);
  147.  
  148. $db->connect();
  149.  
  150. if (self::has_shell_access()
  151. && self::is_shell_command_available('mysqldump')
  152. && self::is_shell_command_available('gzip')
  153. ) {
  154. $dumper = new Shuttle_Dumper_ShellCommand($db);
  155. } else {
  156. $dumper = new Shuttle_Dumper_Native($db);
  157. }
  158.  
  159. if (isset($db_options['include_tables'])) {
  160. $dumper->include_tables = $db_options['include_tables'];
  161. }
  162. if (isset($db_options['exclude_tables'])) {
  163. $dumper->exclude_tables = $db_options['exclude_tables'];
  164. }
  165.  
  166. return $dumper;
  167. }
  168.  
  169. function __construct(Shuttle_DBConn $db) {
  170. $this->db = $db;
  171. }
  172.  
  173. public static function has_shell_access() {
  174. if (!is_callable('shell_exec')) {
  175. return false;
  176. }
  177. $disabled_functions = ini_get('disable_functions');
  178. return stripos($disabled_functions, 'shell_exec') === false;
  179. }
  180.  
  181. public static function is_shell_command_available($command) {
  182. if (preg_match('~win~i', PHP_OS)) {
  183. /*
  184. On Windows, the `where` command checks for availabilty in PATH. According
  185. to the manual(`where /?`), there is quiet mode:
  186. ....
  187. /Q Returns only the exit code, without displaying the list
  188. of matched files. (Quiet mode)
  189. ....
  190. */
  191. $output = array();
  192. exec('where /Q ' . $command, $output, $return_val);
  193.  
  194. if (intval($return_val) === 1) {
  195. return false;
  196. } else {
  197. return true;
  198. }
  199.  
  200. } else {
  201. $last_line = exec('which ' . $command);
  202. $last_line = trim($last_line);
  203.  
  204. // Whenever there is at least one line in the output,
  205. // it should be the path to the executable
  206. if (empty($last_line)) {
  207. return false;
  208. } else {
  209. return true;
  210. }
  211. }
  212.  
  213. }
  214.  
  215. /**
  216. * Create an export file from the tables with that prefix.
  217. * @param string $export_file_location the file to put the dump to.
  218. * Note that whenever the file has .gz extension the dump will be comporessed with gzip
  219. * @param string $table_prefix Allow to export only tables with particular prefix
  220. * @return void
  221. */
  222. abstract public function dump($export_file_location, $table_prefix='');
  223.  
  224. protected function get_tables($table_prefix) {
  225. if (!empty($this->include_tables)) {
  226. return $this->include_tables;
  227. }
  228.  
  229. // $tables will only include the tables and not views.
  230. // TODO - Handle views also, edits to be made in function 'get_create_table_sql' line 336
  231. $tables = $this->db->fetch_numeric('
  232. SHOW FULL TABLES WHERE Table_Type = "BASE TABLE" AND Tables_in_'.$this->db->name.' LIKE "' . $this->db->escape_like($table_prefix) . '%"
  233. ');
  234.  
  235. $tables_list = array();
  236. foreach ($tables as $table_row) {
  237. $table_name = $table_row[0];
  238. if (!in_array($table_name, $this->exclude_tables)) {
  239. $tables_list[] = $table_name;
  240. }
  241. }
  242. return $tables_list;
  243. }
  244. }
  245.  
  246. class Shuttle_Dumper_ShellCommand extends Shuttle_Dumper {
  247. function dump($export_file_location, $table_prefix='') {
  248. $command = 'mysqldump -h ' . escapeshellarg($this->db->host) .
  249. ' -u ' . escapeshellarg($this->db->username) .
  250. ' --password=' . escapeshellarg($this->db->password) .
  251. ' ' . escapeshellarg($this->db->name);
  252.  
  253. $include_all_tables = empty($table_prefix) &&
  254. empty($this->include_tables) &&
  255. empty($this->exclude_tables);
  256.  
  257. if (!$include_all_tables) {
  258. $tables = $this->get_tables($table_prefix);
  259. $command .= ' ' . implode(' ', array_map('escapeshellarg', $tables));
  260. }
  261.  
  262. $error_file = tempnam(sys_get_temp_dir(), 'err');
  263.  
  264. $command .= ' 2> ' . escapeshellarg($error_file);
  265.  
  266. if (Shuttle_Dump_File::is_gzip($export_file_location)) {
  267. $command .= ' | gzip';
  268. }
  269.  
  270. $command .= ' > ' . escapeshellarg($export_file_location);
  271.  
  272. exec($command, $output, $return_val);
  273.  
  274. if ($return_val !== 0) {
  275. $error_text = file_get_contents($error_file);
  276. unlink($error_file);
  277. throw new Shuttle_Exception('Couldn\'t export database: ' . $error_text);
  278. }
  279.  
  280. unlink($error_file);
  281. }
  282. }
  283.  
  284. class Shuttle_Dumper_Native extends Shuttle_Dumper {
  285. public function dump($export_file_location, $table_prefix='') {
  286. $eol = $this->eol;
  287.  
  288. $this->dump_file = Shuttle_Dump_File::create($export_file_location);
  289.  
  290. $this->dump_file->write("-- Generation time: " . date('r') . $eol);
  291. $this->dump_file->write("-- Host: " . $this->db->host . $eol);
  292. $this->dump_file->write("-- DB name: " . $this->db->name . $eol);
  293. $this->dump_file->write("/*!40030 SET NAMES UTF8 */;$eol");
  294.  
  295. $this->dump_file->write("/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;$eol");
  296. $this->dump_file->write("/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;$eol");
  297. $this->dump_file->write("/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;$eol");
  298. $this->dump_file->write("/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;$eol");
  299. $this->dump_file->write("/*!40103 SET TIME_ZONE='+00:00' */;$eol");
  300. $this->dump_file->write("/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;$eol");
  301. $this->dump_file->write("/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;$eol");
  302. $this->dump_file->write("/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;$eol");
  303. $this->dump_file->write("/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;$eol$eol");
  304.  
  305.  
  306. $tables = $this->get_tables($table_prefix);
  307. foreach ($tables as $table) {
  308. $this->dump_table($table);
  309. }
  310.  
  311. $this->dump_file->write("$eol$eol");
  312. $this->dump_file->write("/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;$eol");
  313. $this->dump_file->write("/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;$eol");
  314. $this->dump_file->write("/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;$eol");
  315. $this->dump_file->write("/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;$eol");
  316. $this->dump_file->write("/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;$eol");
  317. $this->dump_file->write("/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;$eol");
  318. $this->dump_file->write("/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;$eol$eol");
  319.  
  320. unset($this->dump_file);
  321. }
  322.  
  323. protected function dump_table($table) {
  324. $eol = $this->eol;
  325.  
  326. $this->dump_file->write("DROP TABLE IF EXISTS `$table`;$eol");
  327.  
  328. $create_table_sql = $this->get_create_table_sql($table);
  329. $this->dump_file->write($create_table_sql . $eol . $eol);
  330.  
  331. $data = $this->db->query("SELECT * FROM `$table`");
  332.  
  333. $insert = new Shuttle_Insert_Statement($table);
  334.  
  335. while ($row = $this->db->fetch_row($data)) {
  336. $row_values = array();
  337. foreach ($row as $value) {
  338. $row_values[] = $this->db->escape($value);
  339. }
  340. $insert->add_row( $row_values );
  341.  
  342. if ($insert->get_length() > self::INSERT_THRESHOLD) {
  343. // The insert got too big: write the SQL and create
  344. // new insert statement
  345. $this->dump_file->write($insert->get_sql() . $eol);
  346. $insert->reset();
  347. }
  348. }
  349.  
  350. $sql = $insert->get_sql();
  351. if ($sql) {
  352. $this->dump_file->write($insert->get_sql() . $eol);
  353. }
  354. $this->dump_file->write($eol . $eol);
  355. }
  356.  
  357. public function get_create_table_sql($table) {
  358. $create_table_sql = $this->db->fetch('SHOW CREATE TABLE `' . $table . '`');
  359. return $create_table_sql[0]['Create Table'] . ';';
  360. }
  361. }
  362.  
  363. class Shuttle_DBConn {
  364. public $host;
  365. public $username;
  366. public $password;
  367. public $name;
  368.  
  369. protected $connection;
  370.  
  371. function __construct($options) {
  372. $this->host = $options['host'];
  373. if (empty($this->host)) {
  374. $this->host = '127.0.0.1';
  375. }
  376. $this->username = $options['username'];
  377. $this->password = $options['password'];
  378. $this->name = $options['db_name'];
  379. }
  380.  
  381. static function create($options) {
  382. if (class_exists('mysqli')) {
  383. $class_name = "Shuttle_DBConn_Mysqli";
  384. } else {
  385. $class_name = "Shuttle_DBConn_Mysql";
  386. }
  387.  
  388. return new $class_name($options);
  389. }
  390. }
  391.  
  392. class Shuttle_DBConn_Mysql extends Shuttle_DBConn {
  393. function connect() {
  394. $this->connection = @mysql_connect($this->host, $this->username, $this->password);
  395. if (!$this->connection) {
  396. throw new Shuttle_Exception("Couldn't connect to the database: " . mysql_error());
  397. }
  398.  
  399. $select_db_res = mysql_select_db($this->name, $this->connection);
  400. if (!$select_db_res) {
  401. throw new Shuttle_Exception("Couldn't select database: " . mysql_error($this->connection));
  402. }
  403.  
  404. return true;
  405. }
  406.  
  407. function query($q) {
  408. if (!$this->connection) {
  409. $this->connect();
  410. }
  411. $res = mysql_query($q);
  412. if (!$res) {
  413. throw new Shuttle_Exception("SQL error: " . mysql_error($this->connection));
  414. }
  415. return $res;
  416. }
  417.  
  418. function fetch_numeric($query) {
  419. return $this->fetch($query, MYSQL_NUM);
  420. }
  421.  
  422. function fetch($query, $result_type=MYSQL_ASSOC) {
  423. $result = $this->query($query, $this->connection);
  424. $return = array();
  425. while ( $row = mysql_fetch_array($result, $result_type) ) {
  426. $return[] = $row;
  427. }
  428. return $return;
  429. }
  430.  
  431. function escape($value) {
  432. if (is_null($value)) {
  433. return "NULL";
  434. }
  435. return "'" . mysql_real_escape_string($value) . "'";
  436. }
  437.  
  438. function escape_like($search) {
  439. return str_replace(array('_', '%'), array('\_', '\%'), $search);
  440. }
  441.  
  442. function get_var($sql) {
  443. $result = $this->query($sql);
  444. $row = mysql_fetch_array($result);
  445. return $row[0];
  446. }
  447.  
  448. function fetch_row($data) {
  449. return mysql_fetch_assoc($data);
  450. }
  451. }
  452.  
  453.  
  454. class Shuttle_DBConn_Mysqli extends Shuttle_DBConn {
  455. function connect() {
  456. $this->connection = @new MySQLi($this->host, $this->username, $this->password, $this->name);
  457.  
  458. if ($this->connection->connect_error) {
  459. throw new Shuttle_Exception("Couldn't connect to the database: " . $this->connection->connect_error);
  460. }
  461.  
  462. return true;
  463. }
  464.  
  465. function query($q) {
  466. if (!$this->connection) {
  467. $this->connect();
  468. }
  469. $res = $this->connection->query($q);
  470.  
  471. if (!$res) {
  472. throw new Shuttle_Exception("SQL error: " . $this->connection->error);
  473. }
  474.  
  475. return $res;
  476. }
  477.  
  478. function fetch_numeric($query) {
  479. return $this->fetch($query, MYSQLI_NUM);
  480. }
  481.  
  482. function fetch($query, $result_type=MYSQLI_ASSOC) {
  483. $result = $this->query($query, $this->connection);
  484. $return = array();
  485. while ( $row = $result->fetch_array($result_type) ) {
  486. $return[] = $row;
  487. }
  488. return $return;
  489. }
  490.  
  491. function escape($value) {
  492. if (is_null($value)) {
  493. return "NULL";
  494. }
  495. return "'" . $this->connection->real_escape_string($value) . "'";
  496. }
  497.  
  498. function escape_like($search) {
  499. return str_replace(array('_', '%'), array('\_', '\%'), $search);
  500. }
  501.  
  502. function get_var($sql) {
  503. $result = $this->query($sql);
  504. $row = $result->fetch_array($result, MYSQLI_NUM);
  505. return $row[0];
  506. }
  507.  
  508. function fetch_row($data) {
  509. return $data->fetch_array(MYSQLI_ASSOC);
  510. }
  511. }
  512.  
  513. class Shuttle_Exception extends Exception {};
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement