WP Staging – DB & File Duplicator & Migration - Version 2.7.0

Version Description

  • HotFix: Fix fatal error in step 6 after updating to WordPress 5.4
Download this release

Release Info

Developer ReneHermi
Plugin Icon 128x128 WP Staging – DB & File Duplicator & Migration
Version 2.7.0
Comparing to
See all releases

Code changes from version 2.6.9 to 2.7.0

Manager/Database/Mysqldump/Mysqldump.php ADDED
@@ -0,0 +1,2318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PHP version of mysqldump cli that comes with MySQL.
5
+ *
6
+ * Tags: mysql mysqldump pdo php7 php5 database php sql hhvm mariadb mysql-backup.
7
+ *
8
+ * @category Library
9
+ * @package Ifsnop\Mysqldump
10
+ * @author Diego Torres <ifsnop@github.com>
11
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
12
+ * @link https://github.com/ifsnop/mysqldump-php
13
+ *
14
+ */
15
+
16
+ namespace WPStaging\Manager\Database\Mysqldump;
17
+
18
+ use Exception;
19
+ use PDO;
20
+ use PDOException;
21
+
22
+ /**
23
+ * Class Mysqldump.
24
+ *
25
+ * @category Library
26
+ * @author Diego Torres <ifsnop@github.com>
27
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
28
+ * @link https://github.com/ifsnop/mysqldump-php
29
+ *
30
+ */
31
+ class Mysqldump
32
+ {
33
+
34
+ // Same as mysqldump.
35
+ const MAXLINESIZE = 1000000;
36
+
37
+ // List of available compression methods as constants.
38
+ const GZIP = 'Gzip';
39
+ const BZIP2 = 'Bzip2';
40
+ const NONE = 'None';
41
+ const GZIPSTREAM = 'Gzipstream';
42
+
43
+ // List of available connection strings.
44
+ const UTF8 = 'utf8';
45
+ const UTF8MB4 = 'utf8mb4';
46
+
47
+ /**
48
+ * Database username.
49
+ * @var string
50
+ */
51
+ public $user;
52
+
53
+ /**
54
+ * Database password.
55
+ * @var string
56
+ */
57
+ public $pass;
58
+
59
+ /**
60
+ * Connection string for PDO.
61
+ * @var string
62
+ */
63
+ public $dsn;
64
+
65
+ /**
66
+ * Destination filename, defaults to stdout.
67
+ * @var string
68
+ */
69
+ public $fileName = 'php://stdout';
70
+
71
+ // Internal stuff.
72
+ private $tables = array();
73
+ private $views = array();
74
+ private $triggers = array();
75
+ private $procedures = array();
76
+ private $functions = array();
77
+ private $events = array();
78
+ private $dbHandler = null;
79
+ private $dbType = "";
80
+ private $compressManager;
81
+ private $typeAdapter;
82
+ private $dumpSettings = array();
83
+ private $pdoSettings = array();
84
+ private $version;
85
+ private $tableColumnTypes = array();
86
+ private $transformColumnValueCallable;
87
+
88
+ /**
89
+ * Database name, parsed from dsn.
90
+ * @var string
91
+ */
92
+ private $dbName;
93
+
94
+ /**
95
+ * Host name, parsed from dsn.
96
+ * @var string
97
+ */
98
+ private $host;
99
+
100
+ /**
101
+ * Dsn string parsed as an array.
102
+ * @var array
103
+ */
104
+ private $dsnArray = array();
105
+
106
+ /**
107
+ * Keyed on table name, with the value as the conditions.
108
+ * e.g. - 'users' => 'date_registered > NOW() - INTERVAL 6 MONTH'
109
+ *
110
+ * @var array
111
+ */
112
+ private $tableWheres = array();
113
+ private $tableLimits = array();
114
+
115
+ /**
116
+ * Constructor of Mysqldump. Note that in the case of an SQLite database
117
+ * connection, the filename must be in the $db parameter.
118
+ *
119
+ * @param string $dsn PDO DSN connection string
120
+ * @param string $user SQL account username
121
+ * @param string $pass SQL account password
122
+ * @param array $dumpSettings SQL database settings
123
+ * @param array $pdoSettings PDO configured attributes
124
+ */
125
+ public function __construct(
126
+ $dsn = '',
127
+ $user = '',
128
+ $pass = '',
129
+ $dumpSettings = array(),
130
+ $pdoSettings = array()
131
+ ) {
132
+ $dumpSettingsDefault = array(
133
+ 'include-tables' => array(),
134
+ 'exclude-tables' => array(),
135
+ 'compress' => Mysqldump::NONE,
136
+ 'init_commands' => array(),
137
+ 'no-data' => array(),
138
+ 'reset-auto-increment' => false,
139
+ 'add-drop-database' => false,
140
+ 'add-drop-table' => false,
141
+ 'add-drop-trigger' => true,
142
+ 'add-locks' => true,
143
+ 'complete-insert' => false,
144
+ 'databases' => false,
145
+ 'default-character-set' => Mysqldump::UTF8,
146
+ 'disable-keys' => true,
147
+ 'extended-insert' => true,
148
+ 'events' => false,
149
+ 'hex-blob' => true, /* faster than escaped content */
150
+ 'insert-ignore' => false,
151
+ 'net_buffer_length' => self::MAXLINESIZE,
152
+ 'no-autocommit' => true,
153
+ 'no-create-info' => false,
154
+ 'lock-tables' => true,
155
+ 'routines' => false,
156
+ 'single-transaction' => true,
157
+ 'skip-triggers' => false,
158
+ 'skip-tz-utc' => false,
159
+ 'skip-comments' => false,
160
+ 'skip-dump-date' => false,
161
+ 'skip-definer' => false,
162
+ 'where' => '',
163
+ 'version' => '',
164
+ /* deprecated */
165
+ 'disable-foreign-keys-check' => true
166
+ );
167
+
168
+ $pdoSettingsDefault = array(
169
+ PDO::ATTR_PERSISTENT => true,
170
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
171
+ );
172
+
173
+ $this->user = $user;
174
+ $this->pass = $pass;
175
+ $this->parseDsn($dsn);
176
+
177
+ // This drops MYSQL dependency, only use the constant if it's defined.
178
+ if ("mysql" === $this->dbType) {
179
+ $pdoSettingsDefault[PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = false;
180
+ }
181
+
182
+ $this->pdoSettings = self::array_replace_recursive($pdoSettingsDefault, $pdoSettings);
183
+ $this->dumpSettings = self::array_replace_recursive($dumpSettingsDefault, $dumpSettings);
184
+ $this->dumpSettings['init_commands'][] = "SET NAMES ".$this->dumpSettings['default-character-set'];
185
+
186
+ if (false === $this->dumpSettings['skip-tz-utc']) {
187
+ $this->dumpSettings['init_commands'][] = "SET TIME_ZONE='+00:00'";
188
+ }
189
+
190
+ $diff = array_diff(array_keys($this->dumpSettings), array_keys($dumpSettingsDefault));
191
+ if (count($diff) > 0) {
192
+ throw new Exception("Unexpected value in dumpSettings: (".implode(",", $diff).")");
193
+ }
194
+
195
+ if (!is_array($this->dumpSettings['include-tables']) ||
196
+ !is_array($this->dumpSettings['exclude-tables'])) {
197
+ throw new Exception("Include-tables and exclude-tables should be arrays");
198
+ }
199
+
200
+ // Dump the same views as tables, mimic mysqldump behaviour
201
+ $this->dumpSettings['include-views'] = $this->dumpSettings['include-tables'];
202
+
203
+ // Create a new compressManager to manage compressed output
204
+ $this->compressManager = CompressManagerFactory::create($this->dumpSettings['compress']);
205
+ }
206
+
207
+ /**
208
+ * Destructor of Mysqldump. Unsets dbHandlers and database objects.
209
+ */
210
+ public function __destruct()
211
+ {
212
+ $this->dbHandler = null;
213
+ }
214
+
215
+ /**
216
+ * Custom array_replace_recursive to be used if PHP < 5.3
217
+ * Replaces elements from passed arrays into the first array recursively.
218
+ *
219
+ * @param array $array1 The array in which elements are replaced
220
+ * @param array $array2 The array from which elements will be extracted
221
+ *
222
+ * @return array Returns an array, or NULL if an error occurs.
223
+ */
224
+ public static function array_replace_recursive($array1, $array2)
225
+ {
226
+ if (function_exists('array_replace_recursive')) {
227
+ return array_replace_recursive($array1, $array2);
228
+ }
229
+
230
+ foreach ($array2 as $key => $value) {
231
+ if (is_array($value)) {
232
+ $array1[$key] = self::array_replace_recursive($array1[$key], $value);
233
+ } else {
234
+ $array1[$key] = $value;
235
+ }
236
+ }
237
+ return $array1;
238
+ }
239
+
240
+ /**
241
+ * Keyed by table name, with the value as the conditions:
242
+ * e.g. 'users' => 'date_registered > NOW() - INTERVAL 6 MONTH AND deleted=0'
243
+ *
244
+ * @param array $tableWheres
245
+ */
246
+ public function setTableWheres(array $tableWheres)
247
+ {
248
+ $this->tableWheres = $tableWheres;
249
+ }
250
+
251
+ /**
252
+ * @param $tableName
253
+ *
254
+ * @return boolean|mixed
255
+ */
256
+ public function getTableWhere($tableName)
257
+ {
258
+ if (!empty($this->tableWheres[$tableName])) {
259
+ return $this->tableWheres[$tableName];
260
+ } elseif ($this->dumpSettings['where']) {
261
+ return $this->dumpSettings['where'];
262
+ }
263
+
264
+ return false;
265
+ }
266
+
267
+ /**
268
+ * Keyed by table name, with the value as the numeric limit:
269
+ * e.g. 'users' => 3000
270
+ *
271
+ * @param array $tableLimits
272
+ */
273
+ public function setTableLimits(array $tableLimits)
274
+ {
275
+ $this->tableLimits = $tableLimits;
276
+ }
277
+
278
+ /**
279
+ * Returns the LIMIT for the table. Must be numeric to be returned.
280
+ * @param $tableName
281
+ * @return boolean
282
+ */
283
+ public function getTableLimit($tableName)
284
+ {
285
+ if (empty($this->tableLimits[$tableName])) {
286
+ return false;
287
+ }
288
+
289
+ $limit = $this->tableLimits[$tableName];
290
+ if (!is_numeric($limit)) {
291
+ return false;
292
+ }
293
+
294
+ return $limit;
295
+ }
296
+
297
+ /**
298
+ * Parse DSN string and extract dbname value
299
+ * Several examples of a DSN string
300
+ * mysql:host=localhost;dbname=testdb
301
+ * mysql:host=localhost;port=3307;dbname=testdb
302
+ * mysql:unix_socket=/tmp/mysql.sock;dbname=testdb
303
+ *
304
+ * @param string $dsn dsn string to parse
305
+ * @return boolean
306
+ */
307
+ private function parseDsn($dsn)
308
+ {
309
+ if (empty($dsn) || (false === ($pos = strpos($dsn, ":")))) {
310
+ throw new Exception("Empty DSN string");
311
+ }
312
+
313
+ $this->dsn = $dsn;
314
+ $this->dbType = strtolower(substr($dsn, 0, $pos)); // always returns a string
315
+
316
+ if (empty($this->dbType)) {
317
+ throw new Exception("Missing database type from DSN string");
318
+ }
319
+
320
+ $dsn = substr($dsn, $pos + 1);
321
+
322
+ foreach (explode(";", $dsn) as $kvp) {
323
+ $kvpArr = explode("=", $kvp);
324
+ $this->dsnArray[strtolower($kvpArr[0])] = $kvpArr[1];
325
+ }
326
+
327
+ if (empty($this->dsnArray['host']) &&
328
+ empty($this->dsnArray['unix_socket'])) {
329
+ throw new Exception("Missing host from DSN string");
330
+ }
331
+ $this->host = (!empty($this->dsnArray['host'])) ?
332
+ $this->dsnArray['host'] : $this->dsnArray['unix_socket'];
333
+
334
+ if (empty($this->dsnArray['dbname'])) {
335
+ throw new Exception("Missing database name from DSN string");
336
+ }
337
+
338
+ $this->dbName = $this->dsnArray['dbname'];
339
+
340
+ return true;
341
+ }
342
+
343
+ /**
344
+ * Connect with PDO.
345
+ *
346
+ * @return null
347
+ */
348
+ private function connect()
349
+ {
350
+ // Connecting with PDO.
351
+ try {
352
+ switch ($this->dbType) {
353
+ case 'sqlite':
354
+ $this->dbHandler = @new PDO("sqlite:".$this->dbName, null, null, $this->pdoSettings);
355
+ break;
356
+ case 'mysql':
357
+ case 'pgsql':
358
+ case 'dblib':
359
+ $this->dbHandler = @new PDO(
360
+ $this->dsn,
361
+ $this->user,
362
+ $this->pass,
363
+ $this->pdoSettings
364
+ );
365
+ // Execute init commands once connected
366
+ foreach ($this->dumpSettings['init_commands'] as $stmt) {
367
+ $this->dbHandler->exec($stmt);
368
+ }
369
+ // Store server version
370
+ $this->version = $this->dbHandler->getAttribute(PDO::ATTR_SERVER_VERSION);
371
+ break;
372
+ default:
373
+ throw new Exception("Unsupported database type (".$this->dbType.")");
374
+ }
375
+ } catch (PDOException $e) {
376
+ throw new Exception(
377
+ "Connection to ".$this->dbType." failed with message: ".
378
+ $e->getMessage()
379
+ );
380
+ }
381
+
382
+ if (is_null($this->dbHandler)) {
383
+ throw new Exception("Connection to ".$this->dbType."failed");
384
+ }
385
+
386
+ $this->dbHandler->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL);
387
+ $this->typeAdapter = TypeAdapterFactory::create($this->dbType, $this->dbHandler, $this->dumpSettings);
388
+ }
389
+
390
+ /**
391
+ * Primary function, triggers dumping.
392
+ *
393
+ * @param string $filename Name of file to write sql dump to
394
+ * @return null
395
+ * @throws \Exception
396
+ */
397
+ public function start($filename = '')
398
+ {
399
+ // Output file can be redefined here
400
+ if (!empty($filename)) {
401
+ $this->fileName = $filename;
402
+ }
403
+
404
+ // Connect to database
405
+ $this->connect();
406
+
407
+ // Create output file
408
+ $this->compressManager->open($this->fileName);
409
+
410
+ // Write some basic info to output file
411
+ $this->compressManager->write($this->getDumpFileHeader());
412
+
413
+ // Store server settings and use sanner defaults to dump
414
+ $this->compressManager->write(
415
+ $this->typeAdapter->backup_parameters()
416
+ );
417
+
418
+ if ($this->dumpSettings['databases']) {
419
+ $this->compressManager->write(
420
+ $this->typeAdapter->getDatabaseHeader($this->dbName)
421
+ );
422
+ if ($this->dumpSettings['add-drop-database']) {
423
+ $this->compressManager->write(
424
+ $this->typeAdapter->add_drop_database($this->dbName)
425
+ );
426
+ }
427
+ }
428
+
429
+ // Get table, view, trigger, procedures, functions and events structures from
430
+ // database.
431
+ $this->getDatabaseStructureTables();
432
+ $this->getDatabaseStructureViews();
433
+ $this->getDatabaseStructureTriggers();
434
+ $this->getDatabaseStructureProcedures();
435
+ $this->getDatabaseStructureFunctions();
436
+ $this->getDatabaseStructureEvents();
437
+
438
+ if ($this->dumpSettings['databases']) {
439
+ $this->compressManager->write(
440
+ $this->typeAdapter->databases($this->dbName)
441
+ );
442
+ }
443
+
444
+ // If there still are some tables/views in include-tables array,
445
+ // that means that some tables or views weren't found.
446
+ // Give proper error and exit.
447
+ // This check will be removed once include-tables supports regexps.
448
+ if (0 < count($this->dumpSettings['include-tables'])) {
449
+ $name = implode(",", $this->dumpSettings['include-tables']);
450
+ throw new Exception("Table (".$name.") not found in database");
451
+ }
452
+
453
+ $this->exportTables();
454
+ $this->exportTriggers();
455
+ $this->exportFunctions();
456
+ $this->exportProcedures();
457
+ $this->exportViews();
458
+ $this->exportEvents();
459
+
460
+ // Restore saved parameters.
461
+ $this->compressManager->write(
462
+ $this->typeAdapter->restore_parameters()
463
+ );
464
+ // Write some stats to output file.
465
+ $this->compressManager->write($this->getDumpFileFooter());
466
+ // Close output file.
467
+ $this->compressManager->close();
468
+
469
+ return;
470
+ }
471
+
472
+ /**
473
+ * Returns header for dump file.
474
+ *
475
+ * @return string
476
+ */
477
+ private function getDumpFileHeader()
478
+ {
479
+ $header = '';
480
+ if (!$this->dumpSettings['skip-comments']) {
481
+ // Some info about software, source and time
482
+ $header = "-- MySql dump created by WP Staging Pro v" . $this->dumpSettings['version'] . PHP_EOL.
483
+ "--".PHP_EOL.
484
+ "-- Host: {$this->host}\tDatabase: {$this->dbName}".PHP_EOL.
485
+ "-- ------------------------------------------------------".PHP_EOL;
486
+
487
+ if (!empty($this->version)) {
488
+ $header .= "-- Server version \t".$this->version.PHP_EOL;
489
+ }
490
+
491
+ if (!$this->dumpSettings['skip-dump-date']) {
492
+ $header .= "-- Date: ".date('r').PHP_EOL.PHP_EOL;
493
+ }
494
+ }
495
+ return $header;
496
+ }
497
+
498
+ /**
499
+ * Returns footer for dump file.
500
+ *
501
+ * @return string
502
+ */
503
+ private function getDumpFileFooter()
504
+ {
505
+ $footer = '';
506
+ if (!$this->dumpSettings['skip-comments']) {
507
+ $footer .= '-- Dump completed';
508
+ if (!$this->dumpSettings['skip-dump-date']) {
509
+ $footer .= ' on: '.date('r');
510
+ }
511
+ $footer .= PHP_EOL;
512
+ }
513
+
514
+ return $footer;
515
+ }
516
+
517
+ /**
518
+ * Reads table names from database.
519
+ * Fills $this->tables array so they will be dumped later.
520
+ *
521
+ * @return null
522
+ */
523
+ private function getDatabaseStructureTables()
524
+ {
525
+ // Listing all tables from database
526
+ if (empty($this->dumpSettings['include-tables'])) {
527
+ // include all tables for now, blacklisting happens later
528
+ foreach ($this->dbHandler->query($this->typeAdapter->show_tables($this->dbName)) as $row) {
529
+ array_push($this->tables, current($row));
530
+ }
531
+ } else {
532
+ // include only the tables mentioned in include-tables
533
+ foreach ($this->dbHandler->query($this->typeAdapter->show_tables($this->dbName)) as $row) {
534
+ if (in_array(current($row), $this->dumpSettings['include-tables'], true)) {
535
+ array_push($this->tables, current($row));
536
+ $elem = array_search(
537
+ current($row),
538
+ $this->dumpSettings['include-tables']
539
+ );
540
+ unset($this->dumpSettings['include-tables'][$elem]);
541
+ }
542
+ }
543
+ }
544
+ return;
545
+ }
546
+
547
+ /**
548
+ * Reads view names from database.
549
+ * Fills $this->tables array so they will be dumped later.
550
+ *
551
+ * @return null
552
+ */
553
+ private function getDatabaseStructureViews()
554
+ {
555
+ // Listing all views from database
556
+ if (empty($this->dumpSettings['include-views'])) {
557
+ // include all views for now, blacklisting happens later
558
+ foreach ($this->dbHandler->query($this->typeAdapter->show_views($this->dbName)) as $row) {
559
+ array_push($this->views, current($row));
560
+ }
561
+ } else {
562
+ // include only the tables mentioned in include-tables
563
+ foreach ($this->dbHandler->query($this->typeAdapter->show_views($this->dbName)) as $row) {
564
+ if (in_array(current($row), $this->dumpSettings['include-views'], true)) {
565
+ array_push($this->views, current($row));
566
+ $elem = array_search(
567
+ current($row),
568
+ $this->dumpSettings['include-views']
569
+ );
570
+ unset($this->dumpSettings['include-views'][$elem]);
571
+ }
572
+ }
573
+ }
574
+ return;
575
+ }
576
+
577
+ /**
578
+ * Reads trigger names from database.
579
+ * Fills $this->tables array so they will be dumped later.
580
+ *
581
+ * @return null
582
+ */
583
+ private function getDatabaseStructureTriggers()
584
+ {
585
+ // Listing all triggers from database
586
+ if (false === $this->dumpSettings['skip-triggers']) {
587
+ foreach ($this->dbHandler->query($this->typeAdapter->show_triggers($this->dbName)) as $row) {
588
+ array_push($this->triggers, $row['Trigger']);
589
+ }
590
+ }
591
+ return;
592
+ }
593
+
594
+ /**
595
+ * Reads procedure names from database.
596
+ * Fills $this->tables array so they will be dumped later.
597
+ *
598
+ * @return null
599
+ */
600
+ private function getDatabaseStructureProcedures()
601
+ {
602
+ // Listing all procedures from database
603
+ if ($this->dumpSettings['routines']) {
604
+ foreach ($this->dbHandler->query($this->typeAdapter->show_procedures($this->dbName)) as $row) {
605
+ array_push($this->procedures, $row['procedure_name']);
606
+ }
607
+ }
608
+ return;
609
+ }
610
+
611
+ /**
612
+ * Reads functions names from database.
613
+ * Fills $this->tables array so they will be dumped later.
614
+ *
615
+ * @return null
616
+ */
617
+ private function getDatabaseStructureFunctions()
618
+ {
619
+ // Listing all functions from database
620
+ if ($this->dumpSettings['routines']) {
621
+ foreach ($this->dbHandler->query($this->typeAdapter->show_functions($this->dbName)) as $row) {
622
+ array_push($this->functions, $row['function_name']);
623
+ }
624
+ }
625
+ return;
626
+ }
627
+
628
+ /**
629
+ * Reads event names from database.
630
+ * Fills $this->tables array so they will be dumped later.
631
+ *
632
+ * @return null
633
+ */
634
+ private function getDatabaseStructureEvents()
635
+ {
636
+ // Listing all events from database
637
+ if ($this->dumpSettings['events']) {
638
+ foreach ($this->dbHandler->query($this->typeAdapter->show_events($this->dbName)) as $row) {
639
+ array_push($this->events, $row['event_name']);
640
+ }
641
+ }
642
+ return;
643
+ }
644
+
645
+ /**
646
+ * Compare if $table name matches with a definition inside $arr
647
+ * @param $table string
648
+ * @param $arr array with strings or patterns
649
+ * @return boolean
650
+ */
651
+ private function matches($table, $arr)
652
+ {
653
+ $match = false;
654
+
655
+ foreach ($arr as $pattern) {
656
+ if ('/' != $pattern[0]) {
657
+ continue;
658
+ }
659
+ if (1 == preg_match($pattern, $table)) {
660
+ $match = true;
661
+ }
662
+ }
663
+
664
+ return in_array($table, $arr) || $match;
665
+ }
666
+
667
+ /**
668
+ * Exports all the tables selected from database
669
+ *
670
+ * @return null
671
+ */
672
+ private function exportTables()
673
+ {
674
+ // Exporting tables one by one
675
+ foreach ($this->tables as $table) {
676
+ if ($this->matches($table, $this->dumpSettings['exclude-tables'])) {
677
+ continue;
678
+ }
679
+ $this->getTableStructure($table);
680
+ if (false === $this->dumpSettings['no-data']) { // don't break compatibility with old trigger
681
+ $this->listValues($table);
682
+ } elseif (true === $this->dumpSettings['no-data']
683
+ || $this->matches($table, $this->dumpSettings['no-data'])) {
684
+ continue;
685
+ } else {
686
+ $this->listValues($table);
687
+ }
688
+ }
689
+ }
690
+
691
+ /**
692
+ * Exports all the views found in database
693
+ *
694
+ * @return null
695
+ */
696
+ private function exportViews()
697
+ {
698
+ if (false === $this->dumpSettings['no-create-info']) {
699
+ // Exporting views one by one
700
+ foreach ($this->views as $view) {
701
+ if ($this->matches($view, $this->dumpSettings['exclude-tables'])) {
702
+ continue;
703
+ }
704
+ $this->tableColumnTypes[$view] = $this->getTableColumnTypes($view);
705
+ $this->getViewStructureTable($view);
706
+ }
707
+ foreach ($this->views as $view) {
708
+ if ($this->matches($view, $this->dumpSettings['exclude-tables'])) {
709
+ continue;
710
+ }
711
+ $this->getViewStructureView($view);
712
+ }
713
+ }
714
+ }
715
+
716
+ /**
717
+ * Exports all the triggers found in database
718
+ *
719
+ * @return null
720
+ */
721
+ private function exportTriggers()
722
+ {
723
+ // Exporting triggers one by one
724
+ foreach ($this->triggers as $trigger) {
725
+ $this->getTriggerStructure($trigger);
726
+ }
727
+ }
728
+
729
+ /**
730
+ * Exports all the procedures found in database
731
+ *
732
+ * @return null
733
+ */
734
+ private function exportProcedures()
735
+ {
736
+ // Exporting triggers one by one
737
+ foreach ($this->procedures as $procedure) {
738
+ $this->getProcedureStructure($procedure);
739
+ }
740
+ }
741
+
742
+ /**
743
+ * Exports all the functions found in database
744
+ *
745
+ * @return null
746
+ */
747
+ private function exportFunctions()
748
+ {
749
+ // Exporting triggers one by one
750
+ foreach ($this->functions as $function) {
751
+ $this->getFunctionStructure($function);
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Exports all the events found in database
757
+ *
758
+ * @return null
759
+ */
760
+ private function exportEvents()
761
+ {
762
+ // Exporting triggers one by one
763
+ foreach ($this->events as $event) {
764
+ $this->getEventStructure($event);
765
+ }
766
+ }
767
+
768
+ /**
769
+ * Table structure extractor
770
+ *
771
+ * @todo move specific mysql code to typeAdapter
772
+ * @param string $tableName Name of table to export
773
+ * @return null
774
+ */
775
+ private function getTableStructure($tableName)
776
+ {
777
+ if (!$this->dumpSettings['no-create-info']) {
778
+ $ret = '';
779
+ if (!$this->dumpSettings['skip-comments']) {
780
+ $ret = "--".PHP_EOL.
781
+ "-- Table structure for table `$tableName`".PHP_EOL.
782
+ "--".PHP_EOL.PHP_EOL;
783
+ }
784
+ $stmt = $this->typeAdapter->show_create_table($tableName);
785
+ foreach ($this->dbHandler->query($stmt) as $r) {
786
+ $this->compressManager->write($ret);
787
+ if ($this->dumpSettings['add-drop-table']) {
788
+ $this->compressManager->write(
789
+ $this->typeAdapter->drop_table($tableName)
790
+ );
791
+ }
792
+ $this->compressManager->write(
793
+ $this->typeAdapter->create_table($r)
794
+ );
795
+ break;
796
+ }
797
+ }
798
+ $this->tableColumnTypes[$tableName] = $this->getTableColumnTypes($tableName);
799
+ return;
800
+ }
801
+
802
+ /**
803
+ * Store column types to create data dumps and for Stand-In tables
804
+ *
805
+ * @param string $tableName Name of table to export
806
+ * @return array type column types detailed
807
+ */
808
+
809
+ private function getTableColumnTypes($tableName)
810
+ {
811
+ $columnTypes = array();
812
+ $columns = $this->dbHandler->query(
813
+ $this->typeAdapter->show_columns($tableName)
814
+ );
815
+ $columns->setFetchMode(PDO::FETCH_ASSOC);
816
+
817
+ foreach ($columns as $key => $col) {
818
+ $types = $this->typeAdapter->parseColumnType($col);
819
+ $columnTypes[$col['Field']] = array(
820
+ 'is_numeric'=> $types['is_numeric'],
821
+ 'is_blob' => $types['is_blob'],
822
+ 'type' => $types['type'],
823
+ 'type_sql' => $col['Type'],
824
+ 'is_virtual' => $types['is_virtual']
825
+ );
826
+ }
827
+
828
+ return $columnTypes;
829
+ }
830
+
831
+ /**
832
+ * View structure extractor, create table (avoids cyclic references)
833
+ *
834
+ * @todo move mysql specific code to typeAdapter
835
+ * @param string $viewName Name of view to export
836
+ * @return null
837
+ */
838
+ private function getViewStructureTable($viewName)
839
+ {
840
+ if (!$this->dumpSettings['skip-comments']) {
841
+ $ret = "--".PHP_EOL.
842
+ "-- Stand-In structure for view `${viewName}`".PHP_EOL.
843
+ "--".PHP_EOL.PHP_EOL;
844
+ $this->compressManager->write($ret);
845
+ }
846
+ $stmt = $this->typeAdapter->show_create_view($viewName);
847
+
848
+ // create views as tables, to resolve dependencies
849
+ foreach ($this->dbHandler->query($stmt) as $r) {
850
+ if ($this->dumpSettings['add-drop-table']) {
851
+ $this->compressManager->write(
852
+ $this->typeAdapter->drop_view($viewName)
853
+ );
854
+ }
855
+
856
+ $this->compressManager->write(
857
+ $this->createStandInTable($viewName)
858
+ );
859
+ break;
860
+ }
861
+ }
862
+
863
+ /**
864
+ * Write a create table statement for the table Stand-In, show create
865
+ * table would return a create algorithm when used on a view
866
+ *
867
+ * @param string $viewName Name of view to export
868
+ * @return string create statement
869
+ */
870
+ public function createStandInTable($viewName)
871
+ {
872
+ $ret = array();
873
+ foreach ($this->tableColumnTypes[$viewName] as $k => $v) {
874
+ $ret[] = "`${k}` ${v['type_sql']}";
875
+ }
876
+ $ret = implode(PHP_EOL.",", $ret);
877
+
878
+ $ret = "CREATE TABLE IF NOT EXISTS `$viewName` (".
879
+ PHP_EOL.$ret.PHP_EOL.");".PHP_EOL;
880
+
881
+ return $ret;
882
+ }
883
+
884
+ /**
885
+ * View structure extractor, create view
886
+ *
887
+ * @todo move mysql specific code to typeAdapter
888
+ * @param string $viewName Name of view to export
889
+ * @return null
890
+ */
891
+ private function getViewStructureView($viewName)
892
+ {
893
+ if (!$this->dumpSettings['skip-comments']) {
894
+ $ret = "--".PHP_EOL.
895
+ "-- View structure for view `${viewName}`".PHP_EOL.
896
+ "--".PHP_EOL.PHP_EOL;
897
+ $this->compressManager->write($ret);
898
+ }
899
+ $stmt = $this->typeAdapter->show_create_view($viewName);
900
+
901
+ // create views, to resolve dependencies
902
+ // replacing tables with views
903
+ foreach ($this->dbHandler->query($stmt) as $r) {
904
+ // because we must replace table with view, we should delete it
905
+ $this->compressManager->write(
906
+ $this->typeAdapter->drop_view($viewName)
907
+ );
908
+ $this->compressManager->write(
909
+ $this->typeAdapter->create_view($r)
910
+ );
911
+ break;
912
+ }
913
+ }
914
+
915
+ /**
916
+ * Trigger structure extractor
917
+ *
918
+ * @param string $triggerName Name of trigger to export
919
+ * @return null
920
+ */
921
+ private function getTriggerStructure($triggerName)
922
+ {
923
+ $stmt = $this->typeAdapter->show_create_trigger($triggerName);
924
+ foreach ($this->dbHandler->query($stmt) as $r) {
925
+ if ($this->dumpSettings['add-drop-trigger']) {
926
+ $this->compressManager->write(
927
+ $this->typeAdapter->add_drop_trigger($triggerName)
928
+ );
929
+ }
930
+ $this->compressManager->write(
931
+ $this->typeAdapter->create_trigger($r)
932
+ );
933
+ return;
934
+ }
935
+ }
936
+
937
+ /**
938
+ * Procedure structure extractor
939
+ *
940
+ * @param string $procedureName Name of procedure to export
941
+ * @return null
942
+ */
943
+ private function getProcedureStructure($procedureName)
944
+ {
945
+ if (!$this->dumpSettings['skip-comments']) {
946
+ $ret = "--".PHP_EOL.
947
+ "-- Dumping routines for database '".$this->dbName."'".PHP_EOL.
948
+ "--".PHP_EOL.PHP_EOL;
949
+ $this->compressManager->write($ret);
950
+ }
951
+ $stmt = $this->typeAdapter->show_create_procedure($procedureName);
952
+ foreach ($this->dbHandler->query($stmt) as $r) {
953
+ $this->compressManager->write(
954
+ $this->typeAdapter->create_procedure($r)
955
+ );
956
+ return;
957
+ }
958
+ }
959
+
960
+ /**
961
+ * Function structure extractor
962
+ *
963
+ * @param string $functionName Name of function to export
964
+ * @return null
965
+ */
966
+ private function getFunctionStructure($functionName)
967
+ {
968
+ if (!$this->dumpSettings['skip-comments']) {
969
+ $ret = "--".PHP_EOL.
970
+ "-- Dumping routines for database '".$this->dbName."'".PHP_EOL.
971
+ "--".PHP_EOL.PHP_EOL;
972
+ $this->compressManager->write($ret);
973
+ }
974
+ $stmt = $this->typeAdapter->show_create_function($functionName);
975
+ foreach ($this->dbHandler->query($stmt) as $r) {
976
+ $this->compressManager->write(
977
+ $this->typeAdapter->create_function($r)
978
+ );
979
+ return;
980
+ }
981
+ }
982
+
983
+ /**
984
+ * Event structure extractor
985
+ *
986
+ * @param string $eventName Name of event to export
987
+ * @return null
988
+ */
989
+ private function getEventStructure($eventName)
990
+ {
991
+ if (!$this->dumpSettings['skip-comments']) {
992
+ $ret = "--".PHP_EOL.
993
+ "-- Dumping events for database '".$this->dbName."'".PHP_EOL.
994
+ "--".PHP_EOL.PHP_EOL;
995
+ $this->compressManager->write($ret);
996
+ }
997
+ $stmt = $this->typeAdapter->show_create_event($eventName);
998
+ foreach ($this->dbHandler->query($stmt) as $r) {
999
+ $this->compressManager->write(
1000
+ $this->typeAdapter->create_event($r)
1001
+ );
1002
+ return;
1003
+ }
1004
+ }
1005
+
1006
+ /**
1007
+ * Prepare values for output
1008
+ *
1009
+ * @param string $tableName Name of table which contains rows
1010
+ * @param array $row Associative array of column names and values to be
1011
+ * quoted
1012
+ *
1013
+ * @return array
1014
+ */
1015
+ private function prepareColumnValues($tableName, $row)
1016
+ {
1017
+ $ret = array();
1018
+ $columnTypes = $this->tableColumnTypes[$tableName];
1019
+ foreach ($row as $colName => $colValue) {
1020
+ $colValue = $this->hookTransformColumnValue($tableName, $colName, $colValue, $row);
1021
+ $ret[] = $this->escape($colValue, $columnTypes[$colName]);
1022
+ }
1023
+
1024
+ return $ret;
1025
+ }
1026
+
1027
+ /**
1028
+ * Escape values with quotes when needed
1029
+ *
1030
+ * @param string $tableName Name of table which contains rows
1031
+ * @param array $row Associative array of column names and values to be quoted
1032
+ *
1033
+ * @return string
1034
+ */
1035
+ private function escape($colValue, $colType)
1036
+ {
1037
+ if (is_null($colValue)) {
1038
+ return "NULL";
1039
+ } elseif ($this->dumpSettings['hex-blob'] && $colType['is_blob']) {
1040
+ if ($colType['type'] == 'bit' || !empty($colValue)) {
1041
+ return "0x${colValue}";
1042
+ } else {
1043
+ return "''";
1044
+ }
1045
+ } elseif ($colType['is_numeric']) {
1046
+ return $colValue;
1047
+ }
1048
+
1049
+ return $this->dbHandler->quote($colValue);
1050
+ }
1051
+
1052
+ /**
1053
+ * Set a callable that will will be used to transform column values.
1054
+ *
1055
+ * @param callable $callable
1056
+ *
1057
+ * @return void
1058
+ */
1059
+ public function setTransformColumnValueHook($callable)
1060
+ {
1061
+ $this->transformColumnValueCallable = $callable;
1062
+ }
1063
+
1064
+ /**
1065
+ * Give extending classes an opportunity to transform column values
1066
+ *
1067
+ * @param string $tableName Name of table which contains rows
1068
+ * @param string $colName Name of the column in question
1069
+ * @param string $colValue Value of the column in question
1070
+ *
1071
+ * @return string
1072
+ */
1073
+ protected function hookTransformColumnValue($tableName, $colName, $colValue, $row)
1074
+ {
1075
+ if (!$this->transformColumnValueCallable) {
1076
+ return $colValue;
1077
+ }
1078
+
1079
+ return call_user_func_array($this->transformColumnValueCallable, array(
1080
+ $tableName,
1081
+ $colName,
1082
+ $colValue,
1083
+ $row
1084
+ ));
1085
+ }
1086
+
1087
+ /**
1088
+ * Table rows extractor
1089
+ *
1090
+ * @param string $tableName Name of table to export
1091
+ *
1092
+ * @return null
1093
+ */
1094
+ private function listValues($tableName)
1095
+ {
1096
+ $this->prepareListValues($tableName);
1097
+
1098
+ $onlyOnce = true;
1099
+ $lineSize = 0;
1100
+
1101
+ // colStmt is used to form a query to obtain row values
1102
+ $colStmt = $this->getColumnStmt($tableName);
1103
+ // colNames is used to get the name of the columns when using complete-insert
1104
+ if ($this->dumpSettings['complete-insert']) {
1105
+ $colNames = $this->getColumnNames($tableName);
1106
+ }
1107
+
1108
+ $stmt = "SELECT ".implode(",", $colStmt)." FROM `$tableName`";
1109
+
1110
+ // Table specific conditions override the default 'where'
1111
+ $condition = $this->getTableWhere($tableName);
1112
+
1113
+ if ($condition) {
1114
+ $stmt .= " WHERE {$condition}";
1115
+ }
1116
+
1117
+ $limit = $this->getTableLimit($tableName);
1118
+
1119
+ if ($limit) {
1120
+ $stmt .= " LIMIT {$limit}";
1121
+ }
1122
+
1123
+ $resultSet = $this->dbHandler->query($stmt);
1124
+ $resultSet->setFetchMode(PDO::FETCH_ASSOC);
1125
+
1126
+ $ignore = $this->dumpSettings['insert-ignore'] ? ' IGNORE' : '';
1127
+
1128
+ $count = 0;
1129
+ foreach ($resultSet as $row) {
1130
+ $count++;
1131
+ $vals = $this->prepareColumnValues($tableName, $row);
1132
+ if ($onlyOnce || !$this->dumpSettings['extended-insert']) {
1133
+ if ($this->dumpSettings['complete-insert']) {
1134
+ $lineSize += $this->compressManager->write(
1135
+ "INSERT$ignore INTO `$tableName` (".
1136
+ implode(", ", $colNames).
1137
+ ") VALUES (".implode(",", $vals).")"
1138
+ );
1139
+ } else {
1140
+ $lineSize += $this->compressManager->write(
1141
+ "INSERT$ignore INTO `$tableName` VALUES (".implode(",", $vals).")"
1142
+ );
1143
+ }
1144
+ $onlyOnce = false;
1145
+ } else {
1146
+ $lineSize += $this->compressManager->write(",(".implode(",", $vals).")");
1147
+ }
1148
+ if (($lineSize > $this->dumpSettings['net_buffer_length']) ||
1149
+ !$this->dumpSettings['extended-insert']) {
1150
+ $onlyOnce = true;
1151
+ $lineSize = $this->compressManager->write(";".PHP_EOL);
1152
+ }
1153
+ }
1154
+ $resultSet->closeCursor();
1155
+
1156
+ if (!$onlyOnce) {
1157
+ $this->compressManager->write(";".PHP_EOL);
1158
+ }
1159
+
1160
+ $this->endListValues($tableName, $count);
1161
+ }
1162
+
1163
+ /**
1164
+ * Table rows extractor, append information prior to dump
1165
+ *
1166
+ * @param string $tableName Name of table to export
1167
+ *
1168
+ * @return null
1169
+ */
1170
+ public function prepareListValues($tableName)
1171
+ {
1172
+ if (!$this->dumpSettings['skip-comments']) {
1173
+ $this->compressManager->write(
1174
+ "--".PHP_EOL.
1175
+ "-- Dumping data for table `$tableName`".PHP_EOL.
1176
+ "--".PHP_EOL.PHP_EOL
1177
+ );
1178
+ }
1179
+
1180
+ if ($this->dumpSettings['single-transaction']) {
1181
+ $this->dbHandler->exec($this->typeAdapter->setup_transaction());
1182
+ $this->dbHandler->exec($this->typeAdapter->start_transaction());
1183
+ }
1184
+
1185
+ if ($this->dumpSettings['lock-tables'] && !$this->dumpSettings['single-transaction']) {
1186
+ $this->typeAdapter->lock_table($tableName);
1187
+ }
1188
+
1189
+ if ($this->dumpSettings['add-locks']) {
1190
+ $this->compressManager->write(
1191
+ $this->typeAdapter->start_add_lock_table($tableName)
1192
+ );
1193
+ }
1194
+
1195
+ if ($this->dumpSettings['disable-keys']) {
1196
+ $this->compressManager->write(
1197
+ $this->typeAdapter->start_add_disable_keys($tableName)
1198
+ );
1199
+ }
1200
+
1201
+ // Disable autocommit for faster reload
1202
+ if ($this->dumpSettings['no-autocommit']) {
1203
+ $this->compressManager->write(
1204
+ $this->typeAdapter->start_disable_autocommit()
1205
+ );
1206
+ }
1207
+
1208
+ return;
1209
+ }
1210
+
1211
+ /**
1212
+ * Table rows extractor, close locks and commits after dump
1213
+ *
1214
+ * @param string $tableName Name of table to export.
1215
+ * @param integer $count Number of rows inserted.
1216
+ *
1217
+ * @return void
1218
+ */
1219
+ public function endListValues($tableName, $count = 0)
1220
+ {
1221
+ if ($this->dumpSettings['disable-keys']) {
1222
+ $this->compressManager->write(
1223
+ $this->typeAdapter->end_add_disable_keys($tableName)
1224
+ );
1225
+ }
1226
+
1227
+ if ($this->dumpSettings['add-locks']) {
1228
+ $this->compressManager->write(
1229
+ $this->typeAdapter->end_add_lock_table($tableName)
1230
+ );
1231
+ }
1232
+
1233
+ if ($this->dumpSettings['single-transaction']) {
1234
+ $this->dbHandler->exec($this->typeAdapter->commit_transaction());
1235
+ }
1236
+
1237
+ if ($this->dumpSettings['lock-tables'] && !$this->dumpSettings['single-transaction']) {
1238
+ $this->typeAdapter->unlock_table($tableName);
1239
+ }
1240
+
1241
+ // Commit to enable autocommit
1242
+ if ($this->dumpSettings['no-autocommit']) {
1243
+ $this->compressManager->write(
1244
+ $this->typeAdapter->end_disable_autocommit()
1245
+ );
1246
+ }
1247
+
1248
+ $this->compressManager->write(PHP_EOL);
1249
+
1250
+ if (!$this->dumpSettings['skip-comments']) {
1251
+ $this->compressManager->write(
1252
+ "-- Dumped table `".$tableName."` with $count row(s)".PHP_EOL.
1253
+ '--'.PHP_EOL.PHP_EOL
1254
+ );
1255
+ }
1256
+
1257
+ return;
1258
+ }
1259
+
1260
+ /**
1261
+ * Build SQL List of all columns on current table which will be used for selecting
1262
+ *
1263
+ * @param string $tableName Name of table to get columns
1264
+ *
1265
+ * @return array SQL sentence with columns for select
1266
+ */
1267
+ public function getColumnStmt($tableName)
1268
+ {
1269
+ $colStmt = array();
1270
+ foreach ($this->tableColumnTypes[$tableName] as $colName => $colType) {
1271
+ if ($colType['type'] == 'bit' && $this->dumpSettings['hex-blob']) {
1272
+ $colStmt[] = "LPAD(HEX(`${colName}`),2,'0') AS `${colName}`";
1273
+ } elseif ($colType['is_blob'] && $this->dumpSettings['hex-blob']) {
1274
+ $colStmt[] = "HEX(`${colName}`) AS `${colName}`";
1275
+ } elseif ($colType['is_virtual']) {
1276
+ $this->dumpSettings['complete-insert'] = true;
1277
+ continue;
1278
+ } else {
1279
+ $colStmt[] = "`${colName}`";
1280
+ }
1281
+ }
1282
+
1283
+ return $colStmt;
1284
+ }
1285
+
1286
+ /**
1287
+ * Build SQL List of all columns on current table which will be used for inserting
1288
+ *
1289
+ * @param string $tableName Name of table to get columns
1290
+ *
1291
+ * @return array columns for sql sentence for insert
1292
+ */
1293
+ public function getColumnNames($tableName)
1294
+ {
1295
+ $colNames = array();
1296
+ foreach ($this->tableColumnTypes[$tableName] as $colName => $colType) {
1297
+ if ($colType['is_virtual']) {
1298
+ $this->dumpSettings['complete-insert'] = true;
1299
+ continue;
1300
+ } else {
1301
+ $colNames[] = "`${colName}`";
1302
+ }
1303
+ }
1304
+ return $colNames;
1305
+ }
1306
+ }
1307
+
1308
+ /**
1309
+ * Enum with all available compression methods
1310
+ *
1311
+ */
1312
+ abstract class CompressMethod
1313
+ {
1314
+ public static $enums = array(
1315
+ Mysqldump::NONE,
1316
+ Mysqldump::GZIP,
1317
+ Mysqldump::BZIP2,
1318
+ Mysqldump::GZIPSTREAM,
1319
+ );
1320
+
1321
+ /**
1322
+ * @param string $c
1323
+ * @return boolean
1324
+ */
1325
+ public static function isValid($c)
1326
+ {
1327
+ return in_array($c, self::$enums);
1328
+ }
1329
+ }
1330
+
1331
+ abstract class CompressManagerFactory
1332
+ {
1333
+ /**
1334
+ * @param string $c
1335
+ * @return CompressBzip2|CompressGzip|CompressNone
1336
+ */
1337
+ public static function create($c)
1338
+ {
1339
+ $c = ucfirst(strtolower($c));
1340
+ if (!CompressMethod::isValid($c)) {
1341
+ throw new Exception("Compression method ($c) is not defined yet");
1342
+ }
1343
+
1344
+ $method = __NAMESPACE__."\\"."Compress".$c;
1345
+
1346
+ return new $method;
1347
+ }
1348
+ }
1349
+
1350
+ class CompressBzip2 extends CompressManagerFactory
1351
+ {
1352
+ private $fileHandler = null;
1353
+
1354
+ public function __construct()
1355
+ {
1356
+ if (!function_exists("bzopen")) {
1357
+ throw new Exception("Compression is enabled, but bzip2 lib is not installed or configured properly");
1358
+ }
1359
+ }
1360
+
1361
+ /**
1362
+ * @param string $filename
1363
+ */
1364
+ public function open($filename)
1365
+ {
1366
+ $this->fileHandler = bzopen($filename, "w");
1367
+ if (false === $this->fileHandler) {
1368
+ throw new Exception("Output file is not writable");
1369
+ }
1370
+
1371
+ return true;
1372
+ }
1373
+
1374
+ public function write($str)
1375
+ {
1376
+ $bytesWritten = bzwrite($this->fileHandler, $str);
1377
+ if (false === $bytesWritten) {
1378
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
1379
+ }
1380
+ return $bytesWritten;
1381
+ }
1382
+
1383
+ public function close()
1384
+ {
1385
+ return bzclose($this->fileHandler);
1386
+ }
1387
+ }
1388
+
1389
+ class CompressGzip extends CompressManagerFactory
1390
+ {
1391
+ private $fileHandler = null;
1392
+
1393
+ public function __construct()
1394
+ {
1395
+ if (!function_exists("gzopen")) {
1396
+ throw new Exception("Compression is enabled, but gzip lib is not installed or configured properly");
1397
+ }
1398
+ }
1399
+
1400
+ /**
1401
+ * @param string $filename
1402
+ */
1403
+ public function open($filename)
1404
+ {
1405
+ $this->fileHandler = gzopen($filename, "wb");
1406
+ if (false === $this->fileHandler) {
1407
+ throw new Exception("Output file is not writable");
1408
+ }
1409
+
1410
+ return true;
1411
+ }
1412
+
1413
+ public function write($str)
1414
+ {
1415
+ $bytesWritten = gzwrite($this->fileHandler, $str);
1416
+ if (false === $bytesWritten) {
1417
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
1418
+ }
1419
+ return $bytesWritten;
1420
+ }
1421
+
1422
+ public function close()
1423
+ {
1424
+ return gzclose($this->fileHandler);
1425
+ }
1426
+ }
1427
+
1428
+ class CompressNone extends CompressManagerFactory
1429
+ {
1430
+ private $fileHandler = null;
1431
+
1432
+ /**
1433
+ * @param string $filename
1434
+ */
1435
+ public function open($filename)
1436
+ {
1437
+ $this->fileHandler = fopen($filename, "wb");
1438
+ if (false === $this->fileHandler) {
1439
+ throw new Exception("Output file is not writable");
1440
+ }
1441
+
1442
+ return true;
1443
+ }
1444
+
1445
+ public function write($str)
1446
+ {
1447
+ $bytesWritten = fwrite($this->fileHandler, $str);
1448
+ if (false === $bytesWritten) {
1449
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
1450
+ }
1451
+ return $bytesWritten;
1452
+ }
1453
+
1454
+ public function close()
1455
+ {
1456
+ return fclose($this->fileHandler);
1457
+ }
1458
+ }
1459
+
1460
+ class CompressGzipstream extends CompressManagerFactory
1461
+ {
1462
+ private $fileHandler = null;
1463
+
1464
+ private $compressContext;
1465
+
1466
+ /**
1467
+ * @param string $filename
1468
+ */
1469
+ public function open($filename)
1470
+ {
1471
+ $this->fileHandler = fopen($filename, "wb");
1472
+ if (false === $this->fileHandler) {
1473
+ throw new Exception("Output file is not writable");
1474
+ }
1475
+
1476
+ $this->compressContext = deflate_init(ZLIB_ENCODING_GZIP, array('level' => 9));
1477
+ return true;
1478
+ }
1479
+
1480
+ public function write($str)
1481
+ {
1482
+
1483
+ $bytesWritten = fwrite($this->fileHandler, deflate_add($this->compressContext, $str, ZLIB_NO_FLUSH));
1484
+ if (false === $bytesWritten) {
1485
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
1486
+ }
1487
+ return $bytesWritten;
1488
+ }
1489
+
1490
+ public function close()
1491
+ {
1492
+ fwrite($this->fileHandler, deflate_add($this->compressContext, '', ZLIB_FINISH));
1493
+ return fclose($this->fileHandler);
1494
+ }
1495
+ }
1496
+
1497
+ /**
1498
+ * Enum with all available TypeAdapter implementations
1499
+ *
1500
+ */
1501
+ abstract class TypeAdapter
1502
+ {
1503
+ public static $enums = array(
1504
+ "Sqlite",
1505
+ "Mysql"
1506
+ );
1507
+
1508
+ /**
1509
+ * @param string $c
1510
+ * @return boolean
1511
+ */
1512
+ public static function isValid($c)
1513
+ {
1514
+ return in_array($c, self::$enums);
1515
+ }
1516
+ }
1517
+
1518
+ /**
1519
+ * TypeAdapter Factory
1520
+ *
1521
+ */
1522
+ abstract class TypeAdapterFactory
1523
+ {
1524
+ protected $dbHandler = null;
1525
+ protected $dumpSettings = array();
1526
+
1527
+ /**
1528
+ * @param string $c Type of database factory to create (Mysql, Sqlite,...)
1529
+ * @param PDO $dbHandler
1530
+ */
1531
+ public static function create($c, $dbHandler = null, $dumpSettings = array())
1532
+ {
1533
+ $c = ucfirst(strtolower($c));
1534
+ if (!TypeAdapter::isValid($c)) {
1535
+ throw new Exception("Database type support for ($c) not yet available");
1536
+ }
1537
+ $method = __NAMESPACE__."\\"."TypeAdapter".$c;
1538
+ return new $method($dbHandler, $dumpSettings);
1539
+ }
1540
+
1541
+ public function __construct($dbHandler = null, $dumpSettings = array())
1542
+ {
1543
+ $this->dbHandler = $dbHandler;
1544
+ $this->dumpSettings = $dumpSettings;
1545
+ }
1546
+
1547
+ /**
1548
+ * function databases Add sql to create and use database
1549
+ * @todo make it do something with sqlite
1550
+ */
1551
+ public function databases()
1552
+ {
1553
+ return "";
1554
+ }
1555
+
1556
+ public function show_create_table($tableName)
1557
+ {
1558
+ return "SELECT tbl_name as 'Table', sql as 'Create Table' ".
1559
+ "FROM sqlite_master ".
1560
+ "WHERE type='table' AND tbl_name='$tableName'";
1561
+ }
1562
+
1563
+ /**
1564
+ * function create_table Get table creation code from database
1565
+ * @todo make it do something with sqlite
1566
+ */
1567
+ public function create_table($row)
1568
+ {
1569
+ return "";
1570
+ }
1571
+
1572
+ public function show_create_view($viewName)
1573
+ {
1574
+ return "SELECT tbl_name as 'View', sql as 'Create View' ".
1575
+ "FROM sqlite_master ".
1576
+ "WHERE type='view' AND tbl_name='$viewName'";
1577
+ }
1578
+
1579
+ /**
1580
+ * function create_view Get view creation code from database
1581
+ * @todo make it do something with sqlite
1582
+ */
1583
+ public function create_view($row)
1584
+ {
1585
+ return "";
1586
+ }
1587
+
1588
+ /**
1589
+ * function show_create_trigger Get trigger creation code from database
1590
+ * @todo make it do something with sqlite
1591
+ */
1592
+ public function show_create_trigger($triggerName)
1593
+ {
1594
+ return "";
1595
+ }
1596
+
1597
+ /**
1598
+ * function create_trigger Modify trigger code, add delimiters, etc
1599
+ * @todo make it do something with sqlite
1600
+ */
1601
+ public function create_trigger($triggerName)
1602
+ {
1603
+ return "";
1604
+ }
1605
+
1606
+ /**
1607
+ * function create_procedure Modify procedure code, add delimiters, etc
1608
+ * @todo make it do something with sqlite
1609
+ */
1610
+ public function create_procedure($procedureName)
1611
+ {
1612
+ return "";
1613
+ }
1614
+
1615
+ /**
1616
+ * function create_function Modify function code, add delimiters, etc
1617
+ * @todo make it do something with sqlite
1618
+ */
1619
+ public function create_function($functionName)
1620
+ {
1621
+ return "";
1622
+ }
1623
+
1624
+ public function show_tables()
1625
+ {
1626
+ return "SELECT tbl_name FROM sqlite_master WHERE type='table'";
1627
+ }
1628
+
1629
+ public function show_views()
1630
+ {
1631
+ return "SELECT tbl_name FROM sqlite_master WHERE type='view'";
1632
+ }
1633
+
1634
+ public function show_triggers()
1635
+ {
1636
+ return "SELECT name FROM sqlite_master WHERE type='trigger'";
1637
+ }
1638
+
1639
+ public function show_columns()
1640
+ {
1641
+ if (func_num_args() != 1) {
1642
+ return "";
1643
+ }
1644
+
1645
+ $args = func_get_args();
1646
+
1647
+ return "pragma table_info(${args[0]})";
1648
+ }
1649
+
1650
+ public function show_procedures()
1651
+ {
1652
+ return "";
1653
+ }
1654
+
1655
+ public function show_functions()
1656
+ {
1657
+ return "";
1658
+ }
1659
+
1660
+ public function show_events()
1661
+ {
1662
+ return "";
1663
+ }
1664
+
1665
+ public function setup_transaction()
1666
+ {
1667
+ return "";
1668
+ }
1669
+
1670
+ public function start_transaction()
1671
+ {
1672
+ return "BEGIN EXCLUSIVE";
1673
+ }
1674
+
1675
+ public function commit_transaction()
1676
+ {
1677
+ return "COMMIT";
1678
+ }
1679
+
1680
+ public function lock_table()
1681
+ {
1682
+ return "";
1683
+ }
1684
+
1685
+ public function unlock_table()
1686
+ {
1687
+ return "";
1688
+ }
1689
+
1690
+ public function start_add_lock_table()
1691
+ {
1692
+ return PHP_EOL;
1693
+ }
1694
+
1695
+ public function end_add_lock_table()
1696
+ {
1697
+ return PHP_EOL;
1698
+ }
1699
+
1700
+ public function start_add_disable_keys()
1701
+ {
1702
+ return PHP_EOL;
1703
+ }
1704
+
1705
+ public function end_add_disable_keys()
1706
+ {
1707
+ return PHP_EOL;
1708
+ }
1709
+
1710
+ public function start_disable_foreign_keys_check()
1711
+ {
1712
+ return PHP_EOL;
1713
+ }
1714
+
1715
+ public function end_disable_foreign_keys_check()
1716
+ {
1717
+ return PHP_EOL;
1718
+ }
1719
+
1720
+ public function add_drop_database()
1721
+ {
1722
+ return PHP_EOL;
1723
+ }
1724
+
1725
+ public function add_drop_trigger()
1726
+ {
1727
+ return PHP_EOL;
1728
+ }
1729
+
1730
+ public function drop_table()
1731
+ {
1732
+ return PHP_EOL;
1733
+ }
1734
+
1735
+ public function drop_view()
1736
+ {
1737
+ return PHP_EOL;
1738
+ }
1739
+
1740
+ /**
1741
+ * Decode column metadata and fill info structure.
1742
+ * type, is_numeric and is_blob will always be available.
1743
+ *
1744
+ * @param array $colType Array returned from "SHOW COLUMNS FROM tableName"
1745
+ * @return array
1746
+ */
1747
+ public function parseColumnType($colType)
1748
+ {
1749
+ return array();
1750
+ }
1751
+
1752
+ public function backup_parameters()
1753
+ {
1754
+ return PHP_EOL;
1755
+ }
1756
+
1757
+ public function restore_parameters()
1758
+ {
1759
+ return PHP_EOL;
1760
+ }
1761
+ }
1762
+
1763
+ class TypeAdapterPgsql extends TypeAdapterFactory
1764
+ {
1765
+ }
1766
+
1767
+ class TypeAdapterDblib extends TypeAdapterFactory
1768
+ {
1769
+ }
1770
+
1771
+ class TypeAdapterSqlite extends TypeAdapterFactory
1772
+ {
1773
+ }
1774
+
1775
+ class TypeAdapterMysql extends TypeAdapterFactory
1776
+ {
1777
+ const DEFINER_RE = 'DEFINER=`(?:[^`]|``)*`@`(?:[^`]|``)*`';
1778
+
1779
+
1780
+ // Numerical Mysql types
1781
+ public $mysqlTypes = array(
1782
+ 'numerical' => array(
1783
+ 'bit',
1784
+ 'tinyint',
1785
+ 'smallint',
1786
+ 'mediumint',
1787
+ 'int',
1788
+ 'integer',
1789
+ 'bigint',
1790
+ 'real',
1791
+ 'double',
1792
+ 'float',
1793
+ 'decimal',
1794
+ 'numeric'
1795
+ ),
1796
+ 'blob' => array(
1797
+ 'tinyblob',
1798
+ 'blob',
1799
+ 'mediumblob',
1800
+ 'longblob',
1801
+ 'binary',
1802
+ 'varbinary',
1803
+ 'bit',
1804
+ 'geometry', /* http://bugs.mysql.com/bug.php?id=43544 */
1805
+ 'point',
1806
+ 'linestring',
1807
+ 'polygon',
1808
+ 'multipoint',
1809
+ 'multilinestring',
1810
+ 'multipolygon',
1811
+ 'geometrycollection',
1812
+ )
1813
+ );
1814
+
1815
+ public function databases()
1816
+ {
1817
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
1818
+ $args = func_get_args();
1819
+ $databaseName = $args[0];
1820
+
1821
+ $resultSet = $this->dbHandler->query("SHOW VARIABLES LIKE 'character_set_database';");
1822
+ $characterSet = $resultSet->fetchColumn(1);
1823
+ $resultSet->closeCursor();
1824
+
1825
+ $resultSet = $this->dbHandler->query("SHOW VARIABLES LIKE 'collation_database';");
1826
+ $collationDb = $resultSet->fetchColumn(1);
1827
+ $resultSet->closeCursor();
1828
+ $ret = "";
1829
+
1830
+ $ret .= "CREATE DATABASE /*!32312 IF NOT EXISTS*/ `${databaseName}`".
1831
+ " /*!40100 DEFAULT CHARACTER SET ${characterSet} ".
1832
+ " COLLATE ${collationDb} */;".PHP_EOL.PHP_EOL.
1833
+ "USE `${databaseName}`;".PHP_EOL.PHP_EOL;
1834
+
1835
+ return $ret;
1836
+ }
1837
+
1838
+ public function show_create_table($tableName)
1839
+ {
1840
+ return "SHOW CREATE TABLE `$tableName`";
1841
+ }
1842
+
1843
+ public function show_create_view($viewName)
1844
+ {
1845
+ return "SHOW CREATE VIEW `$viewName`";
1846
+ }
1847
+
1848
+ public function show_create_trigger($triggerName)
1849
+ {
1850
+ return "SHOW CREATE TRIGGER `$triggerName`";
1851
+ }
1852
+
1853
+ public function show_create_procedure($procedureName)
1854
+ {
1855
+ return "SHOW CREATE PROCEDURE `$procedureName`";
1856
+ }
1857
+
1858
+ public function show_create_function($functionName)
1859
+ {
1860
+ return "SHOW CREATE FUNCTION `$functionName`";
1861
+ }
1862
+
1863
+ public function show_create_event($eventName)
1864
+ {
1865
+ return "SHOW CREATE EVENT `$eventName`";
1866
+ }
1867
+
1868
+ public function create_table($row)
1869
+ {
1870
+ if (!isset($row['Create Table'])) {
1871
+ throw new Exception("Error getting table code, unknown output");
1872
+ }
1873
+
1874
+ $createTable = $row['Create Table'];
1875
+ if ($this->dumpSettings['reset-auto-increment']) {
1876
+ $match = "/AUTO_INCREMENT=[0-9]+/s";
1877
+ $replace = "";
1878
+ $createTable = preg_replace($match, $replace, $createTable);
1879
+ }
1880
+
1881
+ $ret = "/*!40101 SET @saved_cs_client = @@character_set_client */;".PHP_EOL.
1882
+ "/*!40101 SET character_set_client = ".$this->dumpSettings['default-character-set']." */;".PHP_EOL.
1883
+ $createTable.";".PHP_EOL.
1884
+ "/*!40101 SET character_set_client = @saved_cs_client */;".PHP_EOL.
1885
+ PHP_EOL;
1886
+ return $ret;
1887
+ }
1888
+
1889
+ public function create_view($row)
1890
+ {
1891
+ $ret = "";
1892
+ if (!isset($row['Create View'])) {
1893
+ throw new Exception("Error getting view structure, unknown output");
1894
+ }
1895
+
1896
+ $viewStmt = $row['Create View'];
1897
+
1898
+ $definerStr = $this->dumpSettings['skip-definer'] ? '' : '/*!50013 \2 */'.PHP_EOL;
1899
+
1900
+ if ($viewStmtReplaced = preg_replace(
1901
+ '/^(CREATE(?:\s+ALGORITHM=(?:UNDEFINED|MERGE|TEMPTABLE))?)\s+('
1902
+ .self::DEFINER_RE.'(?:\s+SQL SECURITY DEFINER|INVOKER)?)?\s+(VIEW .+)$/',
1903
+ '/*!50001 \1 */'.PHP_EOL.$definerStr.'/*!50001 \3 */',
1904
+ $viewStmt,
1905
+ 1
1906
+ )) {
1907
+ $viewStmt = $viewStmtReplaced;
1908
+ };
1909
+
1910
+ $ret .= $viewStmt.';'.PHP_EOL.PHP_EOL;
1911
+ return $ret;
1912
+ }
1913
+
1914
+ public function create_trigger($row)
1915
+ {
1916
+ $ret = "";
1917
+ if (!isset($row['SQL Original Statement'])) {
1918
+ throw new Exception("Error getting trigger code, unknown output");
1919
+ }
1920
+
1921
+ $triggerStmt = $row['SQL Original Statement'];
1922
+ $definerStr = $this->dumpSettings['skip-definer'] ? '' : '/*!50017 \2*/ ';
1923
+ if ($triggerStmtReplaced = preg_replace(
1924
+ '/^(CREATE)\s+('.self::DEFINER_RE.')?\s+(TRIGGER\s.*)$/s',
1925
+ '/*!50003 \1*/ '.$definerStr.'/*!50003 \3 */',
1926
+ $triggerStmt,
1927
+ 1
1928
+ )) {
1929
+ $triggerStmt = $triggerStmtReplaced;
1930
+ }
1931
+
1932
+ $ret .= "DELIMITER ;;".PHP_EOL.
1933
+ $triggerStmt.";;".PHP_EOL.
1934
+ "DELIMITER ;".PHP_EOL.PHP_EOL;
1935
+ return $ret;
1936
+ }
1937
+
1938
+ public function create_procedure($row)
1939
+ {
1940
+ $ret = "";
1941
+ if (!isset($row['Create Procedure'])) {
1942
+ throw new Exception("Error getting procedure code, unknown output. ".
1943
+ "Please check 'https://bugs.mysql.com/bug.php?id=14564'");
1944
+ }
1945
+ $procedureStmt = $row['Create Procedure'];
1946
+ if ( $this->dumpSettings['skip-definer'] ) {
1947
+ if ($procedureStmtReplaced = preg_replace(
1948
+ '/^(CREATE)\s+('.self::DEFINER_RE.')?\s+(PROCEDURE\s.*)$/s',
1949
+ '\1 \3',
1950
+ $procedureStmt,
1951
+ 1
1952
+ )) {
1953
+ $procedureStmt = $procedureStmtReplaced;
1954
+ }
1955
+ }
1956
+
1957
+ $ret .= "/*!50003 DROP PROCEDURE IF EXISTS `".
1958
+ $row['Procedure']."` */;".PHP_EOL.
1959
+ "/*!40101 SET @saved_cs_client = @@character_set_client */;".PHP_EOL.
1960
+ "/*!40101 SET character_set_client = ".$this->dumpSettings['default-character-set']." */;".PHP_EOL.
1961
+ "DELIMITER ;;".PHP_EOL.
1962
+ $procedureStmt." ;;".PHP_EOL.
1963
+ "DELIMITER ;".PHP_EOL.
1964
+ "/*!40101 SET character_set_client = @saved_cs_client */;".PHP_EOL.PHP_EOL;
1965
+
1966
+ return $ret;
1967
+ }
1968
+
1969
+ public function create_function($row)
1970
+ {
1971
+ $ret = "";
1972
+ if (!isset($row['Create Function'])) {
1973
+ throw new Exception("Error getting function code, unknown output. ".
1974
+ "Please check 'https://bugs.mysql.com/bug.php?id=14564'");
1975
+ }
1976
+ $functionStmt = $row['Create Function'];
1977
+ $characterSetClient = $row['character_set_client'];
1978
+ $collationConnection = $row['collation_connection'];
1979
+ $sqlMode = $row['sql_mode'];
1980
+ if ( $this->dumpSettings['skip-definer'] ) {
1981
+ if ($functionStmtReplaced = preg_replace(
1982
+ '/^(CREATE)\s+('.self::DEFINER_RE.')?\s+(FUNCTION\s.*)$/s',
1983
+ '\1 \3',
1984
+ $functionStmt,
1985
+ 1
1986
+ )) {
1987
+ $functionStmt = $functionStmtReplaced;
1988
+ }
1989
+ }
1990
+
1991
+ $ret .= "/*!50003 DROP FUNCTION IF EXISTS `".
1992
+ $row['Function']."` */;".PHP_EOL.
1993
+ "/*!40101 SET @saved_cs_client = @@character_set_client */;".PHP_EOL.
1994
+ "/*!50003 SET @saved_cs_results = @@character_set_results */ ;".PHP_EOL.
1995
+ "/*!50003 SET @saved_col_connection = @@collation_connection */ ;".PHP_EOL.
1996
+ "/*!40101 SET character_set_client = ".$characterSetClient." */;".PHP_EOL.
1997
+ "/*!40101 SET character_set_results = ".$characterSetClient." */;".PHP_EOL.
1998
+ "/*!50003 SET collation_connection = ".$collationConnection." */ ;".PHP_EOL.
1999
+ "/*!50003 SET @saved_sql_mode = @@sql_mode */ ;;".PHP_EOL.
2000
+ "/*!50003 SET sql_mode = '".$sqlMode."' */ ;;".PHP_EOL.
2001
+ "/*!50003 SET @saved_time_zone = @@time_zone */ ;;".PHP_EOL.
2002
+ "/*!50003 SET time_zone = 'SYSTEM' */ ;;".PHP_EOL.
2003
+ "DELIMITER ;;".PHP_EOL.
2004
+ $functionStmt." ;;".PHP_EOL.
2005
+ "DELIMITER ;".PHP_EOL.
2006
+ "/*!50003 SET sql_mode = @saved_sql_mode */ ;".PHP_EOL.
2007
+ "/*!50003 SET character_set_client = @saved_cs_client */ ;".PHP_EOL.
2008
+ "/*!50003 SET character_set_results = @saved_cs_results */ ;".PHP_EOL.
2009
+ "/*!50003 SET collation_connection = @saved_col_connection */ ;".PHP_EOL.
2010
+ "/*!50106 SET TIME_ZONE= @saved_time_zone */ ;".PHP_EOL.PHP_EOL;
2011
+
2012
+
2013
+ return $ret;
2014
+ }
2015
+
2016
+ public function create_event($row)
2017
+ {
2018
+ $ret = "";
2019
+ if (!isset($row['Create Event'])) {
2020
+ throw new Exception("Error getting event code, unknown output. ".
2021
+ "Please check 'http://stackoverflow.com/questions/10853826/mysql-5-5-create-event-gives-syntax-error'");
2022
+ }
2023
+ $eventName = $row['Event'];
2024
+ $eventStmt = $row['Create Event'];
2025
+ $sqlMode = $row['sql_mode'];
2026
+ $definerStr = $this->dumpSettings['skip-definer'] ? '' : '/*!50117 \2*/ ';
2027
+
2028
+ if ($eventStmtReplaced = preg_replace(
2029
+ '/^(CREATE)\s+('.self::DEFINER_RE.')?\s+(EVENT .*)$/',
2030
+ '/*!50106 \1*/ '.$definerStr.'/*!50106 \3 */',
2031
+ $eventStmt,
2032
+ 1
2033
+ )) {
2034
+ $eventStmt = $eventStmtReplaced;
2035
+ }
2036
+
2037
+ $ret .= "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;".PHP_EOL.
2038
+ "/*!50106 DROP EVENT IF EXISTS `".$eventName."` */;".PHP_EOL.
2039
+ "DELIMITER ;;".PHP_EOL.
2040
+ "/*!50003 SET @saved_cs_client = @@character_set_client */ ;;".PHP_EOL.
2041
+ "/*!50003 SET @saved_cs_results = @@character_set_results */ ;;".PHP_EOL.
2042
+ "/*!50003 SET @saved_col_connection = @@collation_connection */ ;;".PHP_EOL.
2043
+ "/*!50003 SET character_set_client = utf8 */ ;;".PHP_EOL.
2044
+ "/*!50003 SET character_set_results = utf8 */ ;;".PHP_EOL.
2045
+ "/*!50003 SET collation_connection = utf8_general_ci */ ;;".PHP_EOL.
2046
+ "/*!50003 SET @saved_sql_mode = @@sql_mode */ ;;".PHP_EOL.
2047
+ "/*!50003 SET sql_mode = '".$sqlMode."' */ ;;".PHP_EOL.
2048
+ "/*!50003 SET @saved_time_zone = @@time_zone */ ;;".PHP_EOL.
2049
+ "/*!50003 SET time_zone = 'SYSTEM' */ ;;".PHP_EOL.
2050
+ $eventStmt." ;;".PHP_EOL.
2051
+ "/*!50003 SET time_zone = @saved_time_zone */ ;;".PHP_EOL.
2052
+ "/*!50003 SET sql_mode = @saved_sql_mode */ ;;".PHP_EOL.
2053
+ "/*!50003 SET character_set_client = @saved_cs_client */ ;;".PHP_EOL.
2054
+ "/*!50003 SET character_set_results = @saved_cs_results */ ;;".PHP_EOL.
2055
+ "/*!50003 SET collation_connection = @saved_col_connection */ ;;".PHP_EOL.
2056
+ "DELIMITER ;".PHP_EOL.
2057
+ "/*!50106 SET TIME_ZONE= @save_time_zone */ ;".PHP_EOL.PHP_EOL;
2058
+ // Commented because we are doing this in restore_parameters()
2059
+ // "/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;" . PHP_EOL . PHP_EOL;
2060
+
2061
+ return $ret;
2062
+ }
2063
+
2064
+ public function show_tables()
2065
+ {
2066
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2067
+ $args = func_get_args();
2068
+ return "SELECT TABLE_NAME AS tbl_name ".
2069
+ "FROM INFORMATION_SCHEMA.TABLES ".
2070
+ "WHERE TABLE_TYPE='BASE TABLE' AND TABLE_SCHEMA='${args[0]}'";
2071
+ }
2072
+
2073
+ public function show_views()
2074
+ {
2075
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2076
+ $args = func_get_args();
2077
+ return "SELECT TABLE_NAME AS tbl_name ".
2078
+ "FROM INFORMATION_SCHEMA.TABLES ".
2079
+ "WHERE TABLE_TYPE='VIEW' AND TABLE_SCHEMA='${args[0]}'";
2080
+ }
2081
+
2082
+ public function show_triggers()
2083
+ {
2084
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2085
+ $args = func_get_args();
2086
+ return "SHOW TRIGGERS FROM `${args[0]}`;";
2087
+ }
2088
+
2089
+ public function show_columns()
2090
+ {
2091
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2092
+ $args = func_get_args();
2093
+ return "SHOW COLUMNS FROM `${args[0]}`;";
2094
+ }
2095
+
2096
+ public function show_procedures()
2097
+ {
2098
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2099
+ $args = func_get_args();
2100
+ return "SELECT SPECIFIC_NAME AS procedure_name ".
2101
+ "FROM INFORMATION_SCHEMA.ROUTINES ".
2102
+ "WHERE ROUTINE_TYPE='PROCEDURE' AND ROUTINE_SCHEMA='${args[0]}'";
2103
+ }
2104
+
2105
+ public function show_functions()
2106
+ {
2107
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2108
+ $args = func_get_args();
2109
+ return "SELECT SPECIFIC_NAME AS function_name ".
2110
+ "FROM INFORMATION_SCHEMA.ROUTINES ".
2111
+ "WHERE ROUTINE_TYPE='FUNCTION' AND ROUTINE_SCHEMA='${args[0]}'";
2112
+ }
2113
+
2114
+ /**
2115
+ * Get query string to ask for names of events from current database.
2116
+ *
2117
+ * @param string Name of database
2118
+ * @return string
2119
+ */
2120
+ public function show_events()
2121
+ {
2122
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2123
+ $args = func_get_args();
2124
+ return "SELECT EVENT_NAME AS event_name ".
2125
+ "FROM INFORMATION_SCHEMA.EVENTS ".
2126
+ "WHERE EVENT_SCHEMA='${args[0]}'";
2127
+ }
2128
+
2129
+ public function setup_transaction()
2130
+ {
2131
+ return "SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ";
2132
+ }
2133
+
2134
+ public function start_transaction()
2135
+ {
2136
+ return "START TRANSACTION " .
2137
+ "/*!40100 WITH CONSISTENT SNAPSHOT */";
2138
+ }
2139
+
2140
+
2141
+ public function commit_transaction()
2142
+ {
2143
+ return "COMMIT";
2144
+ }
2145
+
2146
+ public function lock_table()
2147
+ {
2148
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2149
+ $args = func_get_args();
2150
+ return $this->dbHandler->exec("LOCK TABLES `${args[0]}` READ LOCAL");
2151
+ }
2152
+
2153
+ public function unlock_table()
2154
+ {
2155
+ return $this->dbHandler->exec("UNLOCK TABLES");
2156
+ }
2157
+
2158
+ public function start_add_lock_table()
2159
+ {
2160
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2161
+ $args = func_get_args();
2162
+ return "LOCK TABLES `${args[0]}` WRITE;".PHP_EOL;
2163
+ }
2164
+
2165
+ public function end_add_lock_table()
2166
+ {
2167
+ return "UNLOCK TABLES;".PHP_EOL;
2168
+ }
2169
+
2170
+ public function start_add_disable_keys()
2171
+ {
2172
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2173
+ $args = func_get_args();
2174
+ return "/*!40000 ALTER TABLE `${args[0]}` DISABLE KEYS */;".
2175
+ PHP_EOL;
2176
+ }
2177
+
2178
+ public function end_add_disable_keys()
2179
+ {
2180
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2181
+ $args = func_get_args();
2182
+ return "/*!40000 ALTER TABLE `${args[0]}` ENABLE KEYS */;".
2183
+ PHP_EOL;
2184
+ }
2185
+
2186
+ public function start_disable_autocommit()
2187
+ {
2188
+ return "SET autocommit=0;".PHP_EOL;
2189
+ }
2190
+
2191
+ public function end_disable_autocommit()
2192
+ {
2193
+ return "COMMIT;".PHP_EOL;
2194
+ }
2195
+
2196
+ public function add_drop_database()
2197
+ {
2198
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2199
+ $args = func_get_args();
2200
+ return "/*!40000 DROP DATABASE IF EXISTS `${args[0]}`*/;".
2201
+ PHP_EOL.PHP_EOL;
2202
+ }
2203
+
2204
+ public function add_drop_trigger()
2205
+ {
2206
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2207
+ $args = func_get_args();
2208
+ return "DROP TRIGGER IF EXISTS `${args[0]}`;".PHP_EOL;
2209
+ }
2210
+
2211
+ public function drop_table()
2212
+ {
2213
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2214
+ $args = func_get_args();
2215
+ return "DROP TABLE IF EXISTS `${args[0]}`;".PHP_EOL;
2216
+ }
2217
+
2218
+ public function drop_view()
2219
+ {
2220
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2221
+ $args = func_get_args();
2222
+ return "DROP TABLE IF EXISTS `${args[0]}`;".PHP_EOL.
2223
+ "/*!50001 DROP VIEW IF EXISTS `${args[0]}`*/;".PHP_EOL;
2224
+ }
2225
+
2226
+ public function getDatabaseHeader()
2227
+ {
2228
+ $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
2229
+ $args = func_get_args();
2230
+ return "--".PHP_EOL.
2231
+ "-- Current Database: `${args[0]}`".PHP_EOL.
2232
+ "--".PHP_EOL.PHP_EOL;
2233
+ }
2234
+
2235
+ /**
2236
+ * Decode column metadata and fill info structure.
2237
+ * type, is_numeric and is_blob will always be available.
2238
+ *
2239
+ * @param array $colType Array returned from "SHOW COLUMNS FROM tableName"
2240
+ * @return array
2241
+ */
2242
+ public function parseColumnType($colType)
2243
+ {
2244
+ $colInfo = array();
2245
+ $colParts = explode(" ", $colType['Type']);
2246
+
2247
+ if ($fparen = strpos($colParts[0], "(")) {
2248
+ $colInfo['type'] = substr($colParts[0], 0, $fparen);
2249
+ $colInfo['length'] = str_replace(")", "", substr($colParts[0], $fparen + 1));
2250
+ $colInfo['attributes'] = isset($colParts[1]) ? $colParts[1] : null;
2251
+ } else {
2252
+ $colInfo['type'] = $colParts[0];
2253
+ }
2254
+ $colInfo['is_numeric'] = in_array($colInfo['type'], $this->mysqlTypes['numerical']);
2255
+ $colInfo['is_blob'] = in_array($colInfo['type'], $this->mysqlTypes['blob']);
2256
+ // for virtual columns that are of type 'Extra', column type
2257
+ // could by "STORED GENERATED" or "VIRTUAL GENERATED"
2258
+ // MySQL reference: https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
2259
+ $colInfo['is_virtual'] = strpos($colType['Extra'], "VIRTUAL GENERATED") !== false || strpos($colType['Extra'], "STORED GENERATED") !== false;
2260
+
2261
+ return $colInfo;
2262
+ }
2263
+
2264
+ public function backup_parameters()
2265
+ {
2266
+ $ret = "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;".PHP_EOL.
2267
+ "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;".PHP_EOL.
2268
+ "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;".PHP_EOL.
2269
+ "/*!40101 SET NAMES ".$this->dumpSettings['default-character-set']." */;".PHP_EOL;
2270
+
2271
+ if (false === $this->dumpSettings['skip-tz-utc']) {
2272
+ $ret .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;".PHP_EOL.
2273
+ "/*!40103 SET TIME_ZONE='+00:00' */;".PHP_EOL;
2274
+ }
2275
+
2276
+ $ret .= "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;".PHP_EOL.
2277
+ "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;".PHP_EOL.
2278
+ "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;".PHP_EOL.
2279
+ "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;".PHP_EOL.PHP_EOL;
2280
+
2281
+ return $ret;
2282
+ }
2283
+
2284
+ public function restore_parameters()
2285
+ {
2286
+ $ret = "";
2287
+
2288
+ if (false === $this->dumpSettings['skip-tz-utc']) {
2289
+ $ret .= "/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;".PHP_EOL;
2290
+ }
2291
+
2292
+ $ret .= "/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;".PHP_EOL.
2293
+ "/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;".PHP_EOL.
2294
+ "/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;".PHP_EOL.
2295
+ "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;".PHP_EOL.
2296
+ "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;".PHP_EOL.
2297
+ "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;".PHP_EOL.
2298
+ "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;".PHP_EOL.PHP_EOL;
2299
+
2300
+ return $ret;
2301
+ }
2302
+
2303
+ /**
2304
+ * Check number of parameters passed to function, useful when inheriting.
2305
+ * Raise exception if unexpected.
2306
+ *
2307
+ * @param integer $num_args
2308
+ * @param integer $expected_num_args
2309
+ * @param string $method_name
2310
+ */
2311
+ private function check_parameters($num_args, $expected_num_args, $method_name)
2312
+ {
2313
+ if ($num_args != $expected_num_args) {
2314
+ throw new Exception("Unexpected parameter passed to $method_name");
2315
+ }
2316
+ return;
2317
+ }
2318
+ }
Manager/FileSystem/DirectoryManager.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // TODO PHP7.x; declare(strict_types=1);
4
+ // TODO PHP7.x; return types & type-hint
5
+
6
+ namespace WPStaging\Manager\FileSystem;
7
+
8
+ use RuntimeException;
9
+ use WPStaging\Service\Adapter\Directory;
10
+
11
+ class DirectoryManager
12
+ {
13
+ /** @var Directory */
14
+ private $adapter;
15
+
16
+ public function __construct(Directory $adapter)
17
+ {
18
+ $this->adapter = $adapter;
19
+ }
20
+
21
+ /**
22
+ * @noinspection PhpUnused
23
+ * @return string
24
+ */
25
+ public function getRelativeUploadsDirectory()
26
+ {
27
+ return str_replace(ABSPATH, null, $this->adapter->getUploadsDirectory());
28
+ }
29
+
30
+ /**
31
+ * @param string $dirname
32
+ * @return string
33
+ */
34
+ public function provideCustomUploadsDirectory($dirname)
35
+ {
36
+ $fullPath = trailingslashit($this->adapter->getUploadsDirectory()) . trim($dirname, '/\\');
37
+
38
+ // TODO RPoC
39
+ if (!wp_mkdir_p($fullPath)) {
40
+ throw new RuntimeException('Failed to create directory ' . $fullPath);
41
+ }
42
+
43
+ return trailingslashit($fullPath);
44
+ }
45
+ }
Service/Adapter/DateTimeAdapter.php CHANGED
@@ -1,17 +1,52 @@
1
  <?php
2
 
3
  //TODO PHP7.x; declare(strict_types=1);
 
4
 
5
  namespace WPStaging\Service\Adapter;
6
 
7
- use DateTime as CoreDateTime;
 
8
 
9
  class DateTimeAdapter
10
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  public function getDateTimeFormat()
12
  {
13
- $dateFormat = get_option('date_format');
14
- $timeFormat = 'H:i:s';
15
 
16
  if (!$dateFormat) {
17
  $dateFormat = 'Y/m/d';
@@ -22,13 +57,45 @@ class DateTimeAdapter
22
  return $dateFormat . ' ' . $timeFormat;
23
  }
24
 
25
- // TODO PHP7.0; public function transformWpDateTimeFormat(DateTime $dateTime): string
26
  /**
27
- * @param CoreDateTime $dateTime
28
  * @return string
29
  */
30
- public function transformToWpFormat(CoreDateTime $dateTime)
31
  {
32
  return $dateTime->format($this->getDateTimeFormat());
33
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
1
  <?php
2
 
3
  //TODO PHP7.x; declare(strict_types=1);
4
+ //TODO PHP7.x; type hinting & return types
5
 
6
  namespace WPStaging\Service\Adapter;
7
 
8
+ use DateTime;
9
+ use RuntimeException;
10
 
11
  class DateTimeAdapter
12
  {
13
+ const DEFAULT_TIME_FORMAT = 'H:i:s';
14
+
15
+ /** @var string */
16
+ private $dateFormat;
17
+
18
+ /** @var string */
19
+ private $timeFormat;
20
+
21
+ // TODO PHP5.6 constant
22
+ private $genericDateFormats = [
23
+ // WP Suggested formats
24
+ 'F j, Y',
25
+ 'Y-m-d',
26
+ 'm/d/Y',
27
+ 'd/m/Y',
28
+ // Commonly used formats
29
+ 'd-m-Y',
30
+ 'm-d-Y',
31
+ 'Y-m-d',
32
+ 'Y/m/d',
33
+ ];
34
+
35
+ public function __construct()
36
+ {
37
+ $this->dateFormat = get_option('date_format');
38
+ $this->timeFormat = get_option('time_format');
39
+ }
40
+
41
+ public function getWPDateTimeFormat()
42
+ {
43
+ return $this->dateFormat . ' ' . $this->timeFormat;
44
+ }
45
+
46
  public function getDateTimeFormat()
47
  {
48
+ $dateFormat = $this->dateFormat;
49
+ $timeFormat = self::DEFAULT_TIME_FORMAT;
50
 
51
  if (!$dateFormat) {
52
  $dateFormat = 'Y/m/d';
57
  return $dateFormat . ' ' . $timeFormat;
58
  }
59
 
 
60
  /**
61
+ * @param DateTime $dateTime
62
  * @return string
63
  */
64
+ public function transformToWpFormat(DateTime $dateTime)
65
  {
66
  return $dateTime->format($this->getDateTimeFormat());
67
  }
68
+
69
+ /**
70
+ * @param string $value
71
+ * @return DateTime|null
72
+ */
73
+ public function getDateTime($value)
74
+ {
75
+ $date = null;
76
+ foreach ($this->generateDefaultDateFormats() as $format) {
77
+ $date = DateTime::createFromFormat($format, $value);
78
+ if ($date) {
79
+ break;
80
+ }
81
+ }
82
+
83
+ return $date?: null;
84
+ }
85
+
86
+ // TODO
87
+ private function generateDefaultDateFormats()
88
+ {
89
+ $formats = [
90
+ 'U', // Timestamp
91
+ $this->getDateTimeFormat(),
92
+ $this->getWPDateTimeFormat(),
93
+ ];
94
+
95
+ foreach ($this->genericDateFormats as $format) {
96
+ $formats[] = $format . ' ' . self::DEFAULT_TIME_FORMAT;
97
+ }
98
+
99
+ return $formats;
100
+ }
101
  }
Service/Traits/ArrayableTrait.php CHANGED
@@ -7,7 +7,6 @@ namespace WPStaging\Service\Traits;
7
  use DateTime;
8
  use ReflectionClass;
9
  use ReflectionProperty;
10
- use WPStaging\Service\Adapter\DateTimeAdapter;
11
 
12
  trait ArrayableTrait
13
  {
@@ -30,7 +29,7 @@ trait ArrayableTrait
30
  $value = $prop->getValue($this);
31
 
32
  if ($value instanceof DateTime) {
33
- $value = (new DateTimeAdapter)->transformToWpFormat($value);
34
  }
35
 
36
  $data[$prop->getName()] = $value;
7
  use DateTime;
8
  use ReflectionClass;
9
  use ReflectionProperty;
 
10
 
11
  trait ArrayableTrait
12
  {
29
  $value = $prop->getValue($this);
30
 
31
  if ($value instanceof DateTime) {
32
+ $value = $value->format('U');
33
  }
34
 
35
  $data[$prop->getName()] = $value;
Service/Traits/HydrateTrait.php CHANGED
@@ -8,6 +8,7 @@ namespace WPStaging\Service\Traits;
8
  use DateTime;
9
  use ReflectionException;
10
  use ReflectionMethod;
 
11
  use WPStaging\Service\Entity\EntityException;
12
 
13
  trait HydrateTrait
@@ -56,8 +57,7 @@ trait HydrateTrait
56
  $param = $params[0];
57
 
58
  if ($value && !$value instanceof DateTime && $param->getClass() && 'DateTime' === $param->getClass()->getName()) {
59
- /** @noinspection PhpUnhandledExceptionInspection */
60
- $value = new DateTime(str_replace(',', null, $value));
61
  }
62
 
63
  $method->invoke($this, $value);
8
  use DateTime;
9
  use ReflectionException;
10
  use ReflectionMethod;
11
+ use WPStaging\Service\Adapter\DateTimeAdapter;
12
  use WPStaging\Service\Entity\EntityException;
13
 
14
  trait HydrateTrait
57
  $param = $params[0];
58
 
59
  if ($value && !$value instanceof DateTime && $param->getClass() && 'DateTime' === $param->getClass()->getName()) {
60
+ $value = (new DateTimeAdapter)->getDateTime($value);
 
61
  }
62
 
63
  $method->invoke($this, $value);
readme.txt CHANGED
@@ -9,7 +9,7 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
10
  Requires at least: 3.6+
11
  Tested up to: 5.3
12
- Stable tag: 2.6.9
13
  Requires PHP: 5.3
14
 
15
  A duplicator plugin - clone/move, duplicate & migrate live websites to independent staging and development sites that are accessible​ by authorized users only.
@@ -153,6 +153,9 @@ https://wp-staging.com
153
 
154
  == Changelog ==
155
 
 
 
 
156
  = 2.6.9 =
157
  * Fix: Can not login to staging site under certain circumstances
158
  * Fix: Use user selected language setting instead global site based one
9
  Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
10
  Requires at least: 3.6+
11
  Tested up to: 5.3
12
+ Stable tag: 2.7.0
13
  Requires PHP: 5.3
14
 
15
  A duplicator plugin - clone/move, duplicate & migrate live websites to independent staging and development sites that are accessible​ by authorized users only.
153
 
154
  == Changelog ==
155
 
156
+ = 2.7.0 =
157
+ * HotFix: Fix fatal error in step 6 after updating to WordPress 5.4
158
+
159
  = 2.6.9 =
160
  * Fix: Can not login to staging site under certain circumstances
161
  * Fix: Use user selected language setting instead global site based one
vendor/composer/autoload_static.php CHANGED
@@ -9,6 +9,7 @@ class ComposerStaticInitc2c8fce0bd7d21d1b2bc76515b028e91
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
11
  array (
 
12
  'WPStaging\\' => 10,
13
  ),
14
  'P' =>
@@ -18,11 +19,11 @@ class ComposerStaticInitc2c8fce0bd7d21d1b2bc76515b028e91
18
  );
19
 
20
  public static $prefixDirsPsr4 = array (
21
- 'WPStaging\\Test\\' =>
22
  array (
23
  0 => __DIR__ . '/../..' . '/../tests/unit',
24
  ),
25
- 'WPStaging\\' =>
26
  array (
27
  0 => __DIR__ . '/../..' . '/',
28
  ),
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
11
  array (
12
+ 'WPStaging\\Test\\' => 15,
13
  'WPStaging\\' => 10,
14
  ),
15
  'P' =>
19
  );
20
 
21
  public static $prefixDirsPsr4 = array (
22
+ 'WPStaging\\Test\\' =>
23
  array (
24
  0 => __DIR__ . '/../..' . '/../tests/unit',
25
  ),
26
+ 'WPStaging\\' =>
27
  array (
28
  0 => __DIR__ . '/../..' . '/',
29
  ),
vendor/composer/installed.json CHANGED
@@ -1,23 +1,23 @@
1
  [
2
  {
3
  "name": "psr/log",
4
- "version": "1.1.2",
5
- "version_normalized": "1.1.2.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/php-fig/log.git",
9
- "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
14
- "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
15
  "shasum": ""
16
  },
17
  "require": {
18
  "php": ">=5.3.0"
19
  },
20
- "time": "2019-11-01T11:05:21+00:00",
21
  "type": "library",
22
  "extra": {
23
  "branch-alias": {
1
  [
2
  {
3
  "name": "psr/log",
4
+ "version": "1.1.3",
5
+ "version_normalized": "1.1.3.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/php-fig/log.git",
9
+ "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
14
+ "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
15
  "shasum": ""
16
  },
17
  "require": {
18
  "php": ">=5.3.0"
19
  },
20
+ "time": "2020-03-23T09:12:05+00:00",
21
  "type": "library",
22
  "extra": {
23
  "branch-alias": {
vendor/psr/log/Psr/Log/LoggerInterface.php CHANGED
@@ -22,8 +22,8 @@ interface LoggerInterface
22
  /**
23
  * System is unusable.
24
  *
25
- * @param string $message
26
- * @param array $context
27
  *
28
  * @return void
29
  */
@@ -35,8 +35,8 @@ interface LoggerInterface
35
  * Example: Entire website down, database unavailable, etc. This should
36
  * trigger the SMS alerts and wake you up.
37
  *
38
- * @param string $message
39
- * @param array $context
40
  *
41
  * @return void
42
  */
@@ -47,8 +47,8 @@ interface LoggerInterface
47
  *
48
  * Example: Application component unavailable, unexpected exception.
49
  *
50
- * @param string $message
51
- * @param array $context
52
  *
53
  * @return void
54
  */
@@ -58,8 +58,8 @@ interface LoggerInterface
58
  * Runtime errors that do not require immediate action but should typically
59
  * be logged and monitored.
60
  *
61
- * @param string $message
62
- * @param array $context
63
  *
64
  * @return void
65
  */
@@ -71,8 +71,8 @@ interface LoggerInterface
71
  * Example: Use of deprecated APIs, poor use of an API, undesirable things
72
  * that are not necessarily wrong.
73
  *
74
- * @param string $message
75
- * @param array $context
76
  *
77
  * @return void
78
  */
@@ -81,8 +81,8 @@ interface LoggerInterface
81
  /**
82
  * Normal but significant events.
83
  *
84
- * @param string $message
85
- * @param array $context
86
  *
87
  * @return void
88
  */
@@ -93,8 +93,8 @@ interface LoggerInterface
93
  *
94
  * Example: User logs in, SQL logs.
95
  *
96
- * @param string $message
97
- * @param array $context
98
  *
99
  * @return void
100
  */
@@ -103,8 +103,8 @@ interface LoggerInterface
103
  /**
104
  * Detailed debug information.
105
  *
106
- * @param string $message
107
- * @param array $context
108
  *
109
  * @return void
110
  */
@@ -113,9 +113,9 @@ interface LoggerInterface
113
  /**
114
  * Logs with an arbitrary level.
115
  *
116
- * @param mixed $level
117
- * @param string $message
118
- * @param array $context
119
  *
120
  * @return void
121
  *
22
  /**
23
  * System is unusable.
24
  *
25
+ * @param string $message
26
+ * @param mixed[] $context
27
  *
28
  * @return void
29
  */
35
  * Example: Entire website down, database unavailable, etc. This should
36
  * trigger the SMS alerts and wake you up.
37
  *
38
+ * @param string $message
39
+ * @param mixed[] $context
40
  *
41
  * @return void
42
  */
47
  *
48
  * Example: Application component unavailable, unexpected exception.
49
  *
50
+ * @param string $message
51
+ * @param mixed[] $context
52
  *
53
  * @return void
54
  */
58
  * Runtime errors that do not require immediate action but should typically
59
  * be logged and monitored.
60
  *
61
+ * @param string $message
62
+ * @param mixed[] $context
63
  *
64
  * @return void
65
  */
71
  * Example: Use of deprecated APIs, poor use of an API, undesirable things
72
  * that are not necessarily wrong.
73
  *
74
+ * @param string $message
75
+ * @param mixed[] $context
76
  *
77
  * @return void
78
  */
81
  /**
82
  * Normal but significant events.
83
  *
84
+ * @param string $message
85
+ * @param mixed[] $context
86
  *
87
  * @return void
88
  */
93
  *
94
  * Example: User logs in, SQL logs.
95
  *
96
+ * @param string $message
97
+ * @param mixed[] $context
98
  *
99
  * @return void
100
  */
103
  /**
104
  * Detailed debug information.
105
  *
106
+ * @param string $message
107
+ * @param mixed[] $context
108
  *
109
  * @return void
110
  */
113
  /**
114
  * Logs with an arbitrary level.
115
  *
116
+ * @param mixed $level
117
+ * @param string $message
118
+ * @param mixed[] $context
119
  *
120
  * @return void
121
  *
vendor/psr/log/Psr/Log/Test/DummyTest.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Log\Test;
4
+
5
+ /**
6
+ * This class is internal and does not follow the BC promise.
7
+ *
8
+ * Do NOT use this class in any way.
9
+ *
10
+ * @internal
11
+ */
12
+ class DummyTest
13
+ {
14
+ public function __toString()
15
+ {
16
+ return 'DummyTest';
17
+ }
18
+ }
vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php CHANGED
@@ -136,11 +136,3 @@ abstract class LoggerInterfaceTest extends TestCase
136
  $this->assertEquals($expected, $this->getLogs());
137
  }
138
  }
139
-
140
- class DummyTest
141
- {
142
- public function __toString()
143
- {
144
- return 'DummyTest';
145
- }
146
- }
136
  $this->assertEquals($expected, $this->getLogs());
137
  }
138
  }
 
 
 
 
 
 
 
 
wp-staging.php CHANGED
@@ -7,7 +7,7 @@
7
  * Author: WP-Staging
8
  * Author URI: https://wp-staging.com
9
  * Contributors: ReneHermi, ilgityildirim
10
- * Version: 2.6.9
11
  * Text Domain: wp-staging
12
  * Domain Path: /languages/
13
  *
@@ -39,7 +39,7 @@ if (!defined('WPSTG_PLUGIN_SLUG')) {
39
 
40
  // Plugin Version
41
  if (!defined('WPSTG_VERSION')) {
42
- define('WPSTG_VERSION', '2.6.9');
43
  }
44
 
45
  // Compatible up to WordPress Version
7
  * Author: WP-Staging
8
  * Author URI: https://wp-staging.com
9
  * Contributors: ReneHermi, ilgityildirim
10
+ * Version: 2.7.0
11
  * Text Domain: wp-staging
12
  * Domain Path: /languages/
13
  *
39
 
40
  // Plugin Version
41
  if (!defined('WPSTG_VERSION')) {
42
+ define('WPSTG_VERSION', '2.7.0');
43
  }
44
 
45
  // Compatible up to WordPress Version