PluginProbe
WP Reset / 1.70
WP Reset v1.70
trunk 1.0 1.1 1.11 1.20 1.25 1.30 1.35 1.40 1.45 1.50 1.55 1.60 1.65 1.70 1.75 1.77 1.80 1.81 1.82 1.83 1.84 1.85 1.86 1.90 All 42 releases
wp-reset / libs / dumper.php

dumper.php in WP Reset 1.70, at libs/dumper.php

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