PluginProbe
Redirection / 5.5.2
Redirection v5.5.2
5.10.0 5.9.0 5.8.1 5.8.0 3.7.2 3.7.3 4.0 4.0.1 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.3 4.3.1 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6.2 4.7.1 All 130 releases
redirection / database / database-status.php

database-status.php in Redirection 5.5.2, at database/database-status.php

392 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Red_Database_Status {
4 // Used in < 3.7 versions of Redirection, but since migrated to general settings
5 const OLD_DB_VERSION = 'redirection_version';
6 const DB_UPGRADE_STAGE = 'database_stage';
7
8 const RESULT_OK = 'ok';
9 const RESULT_ERROR = 'error';
10
11 const STATUS_OK = 'ok';
12 const STATUS_NEED_INSTALL = 'need-install';
13 const STATUS_NEED_UPDATING = 'need-update';
14 const STATUS_FINISHED_INSTALL = 'finish-install';
15 const STATUS_FINISHED_UPDATING = 'finish-update';
16
17 private $stage = false;
18 private $stages = [];
19
20 private $status = false;
21 private $result = false;
22 private $reason = false;
23 private $debug = [];
24
25 public function __construct() {
26 $this->status = self::STATUS_OK;
27
28 if ( $this->needs_installing() ) {
29 $this->status = self::STATUS_NEED_INSTALL;
30 }
31
32 $this->load_stage();
33
34 if ( $this->needs_updating() ) {
35 $this->status = self::STATUS_NEED_UPDATING;
36 }
37 }
38
39 public function load_stage() {
40 $settings = red_get_options();
41
42 if ( isset( $settings[ self::DB_UPGRADE_STAGE ] ) ) {
43 $this->stage = isset( $settings[ self::DB_UPGRADE_STAGE ]['stage'] ) ? $settings[ self::DB_UPGRADE_STAGE ]['stage'] : false;
44 $this->stages = isset( $settings[ self::DB_UPGRADE_STAGE ]['stages'] ) ? $settings[ self::DB_UPGRADE_STAGE ]['stages'] : [];
45 $this->status = isset( $settings[ self::DB_UPGRADE_STAGE ]['status'] ) ? $settings[ self::DB_UPGRADE_STAGE ]['status'] : false;
46 }
47 }
48
49 /**
50 * Does the database need install
51 *
52 * @return bool true if needs installing, false otherwise
53 */
54 public function needs_installing() {
55 $settings = red_get_options();
56
57 if ( $settings['database'] === '' && $this->get_old_version() === false ) {
58 return true;
59 }
60
61 return false;
62 }
63
64 /**
65 * Does the current database need updating to the target
66 *
67 * @return bool true if needs updating, false otherwise
68 */
69 public function needs_updating() {
70 // We need updating if we don't need to install, and the current version is less than target version
71 if ( $this->needs_installing() === false && version_compare( $this->get_current_version(), REDIRECTION_DB_VERSION, '<' ) ) {
72 return true;
73 }
74
75 // Also if we're still in the process of upgrading
76 if ( $this->get_current_stage() && $this->status !== self::STATUS_NEED_INSTALL ) {
77 return true;
78 }
79
80 return false;
81 }
82
83 /**
84 * Get current database version
85 *
86 * @return string Current database version
87 */
88 public function get_current_version() {
89 $settings = red_get_options();
90
91 if ( $settings['database'] !== '' && is_string( $settings['database'] ) ) {
92 if ( $settings['database'] === '+OK' ) {
93 return REDIRECTION_DB_VERSION;
94 }
95
96 return $settings['database'];
97 }
98
99 if ( $this->get_old_version() !== false ) {
100 $version = $this->get_old_version();
101
102 // Upgrade the old value
103 if ( $version ) {
104 red_set_options( array( 'database' => $version ) );
105 delete_option( self::OLD_DB_VERSION );
106 $this->clear_cache();
107 return $version;
108 }
109 }
110
111 return '';
112 }
113
114 private function get_old_version() {
115 return get_option( self::OLD_DB_VERSION );
116 }
117
118 public function check_tables_exist() {
119 $latest = Red_Database::get_latest_database();
120 $missing = $latest->get_missing_tables();
121
122 // No tables installed - do a fresh install
123 if ( count( $missing ) === count( $latest->get_all_tables() ) ) {
124 delete_option( Red_Database_Status::OLD_DB_VERSION );
125 red_set_options( [ 'database' => '' ] );
126 $this->clear_cache();
127
128 $this->status = self::STATUS_NEED_INSTALL;
129 $this->stop_update();
130 } elseif ( count( $missing ) > 0 && version_compare( $this->get_current_version(), '2.3.3', 'ge' ) ) {
131 // Some tables are missing - try and fill them in
132 $latest->install();
133 }
134 }
135
136 /**
137 * Does the current database support a particular version
138 *
139 * @param string $version Target version
140 * @return bool true if supported, false otherwise
141 */
142 public function does_support( $version ) {
143 return version_compare( $this->get_current_version(), $version, 'ge' );
144 }
145
146 public function is_error() {
147 return $this->result === self::RESULT_ERROR;
148 }
149
150 public function set_error( $error ) {
151 global $wpdb;
152
153 $this->result = self::RESULT_ERROR;
154 $this->reason = str_replace( "\t", ' ', $error );
155
156 if ( $wpdb->last_error ) {
157 $this->debug[] = $wpdb->last_error;
158
159 if ( strpos( $wpdb->last_error, 'command denied to user' ) !== false ) {
160 $this->reason .= ' - ' . __( 'Insufficient database permissions detected. Please give your database user appropriate permissions.', 'redirection' );
161 }
162 }
163
164 $latest = Red_Database::get_latest_database();
165 $this->debug = array_merge( $this->debug, $latest->get_table_schema() );
166 $this->debug[] = 'Stage: ' . $this->get_current_stage();
167 }
168
169 public function set_ok( $reason ) {
170 $this->reason = $reason;
171 $this->result = self::RESULT_OK;
172 $this->debug = [];
173 }
174
175 /**
176 * Stop current upgrade
177 */
178 public function stop_update() {
179 $this->stage = false;
180 $this->stages = [];
181 $this->debug = [];
182
183 red_set_options( [ self::DB_UPGRADE_STAGE => false ] );
184 $this->clear_cache();
185 }
186
187 public function finish() {
188 $this->stop_update();
189
190 if ( $this->status === self::STATUS_NEED_INSTALL ) {
191 $this->status = self::STATUS_FINISHED_INSTALL;
192 } elseif ( $this->status === self::STATUS_NEED_UPDATING ) {
193 $this->status = self::STATUS_FINISHED_UPDATING;
194 }
195 }
196
197 /**
198 * Get current upgrade stage
199 * @return string|bool Current stage name, or false if not upgrading
200 */
201 public function get_current_stage() {
202 return $this->stage;
203 }
204
205 /**
206 * Move current stage on to the next
207 */
208 public function set_next_stage() {
209 $this->debug = [];
210 $stage = $this->get_current_stage();
211
212 if ( $stage ) {
213 $stage = $this->get_next_stage( $stage );
214
215 // Save next position
216 if ( $stage ) {
217 $this->set_stage( $stage );
218 } else {
219 $this->finish();
220 }
221 }
222 }
223
224 /**
225 * Get current upgrade status
226 *
227 * @return array Database status array
228 */
229 public function get_json() {
230 // Base information
231 $result = [
232 'status' => $this->status,
233 'inProgress' => $this->stage !== false,
234 ];
235
236 // Add on version status
237 if ( $this->status === self::STATUS_NEED_INSTALL || $this->status === self::STATUS_NEED_UPDATING ) {
238 $result = array_merge(
239 $result,
240 $this->get_version_upgrade(),
241 [ 'manual' => $this->get_manual_upgrade() ]
242 );
243 }
244
245 // Add on upgrade status
246 if ( $this->is_error() ) {
247 $result = array_merge( $result, $this->get_version_upgrade(), $this->get_progress_status(), $this->get_error_status() );
248 } elseif ( $result['inProgress'] ) {
249 $result = array_merge( $result, $this->get_progress_status() );
250 } elseif ( $this->status === self::STATUS_FINISHED_INSTALL || $this->status === self::STATUS_FINISHED_UPDATING ) {
251 $result['complete'] = 100;
252 $result['reason'] = $this->reason;
253 }
254
255 return $result;
256 }
257
258 private function get_error_status() {
259 return [
260 'reason' => $this->reason,
261 'result' => self::RESULT_ERROR,
262 'debug' => $this->debug,
263 ];
264 }
265
266 private function get_progress_status() {
267 $complete = 0;
268
269 if ( $this->stage ) {
270 $complete = round( ( array_search( $this->stage, $this->stages, true ) / count( $this->stages ) ) * 100, 1 );
271 }
272
273 return [
274 'complete' => $complete,
275 'result' => self::RESULT_OK,
276 'reason' => $this->reason,
277 ];
278 }
279
280 private function get_version_upgrade() {
281 return [
282 'current' => $this->get_current_version() ? $this->get_current_version() : '-',
283 'next' => REDIRECTION_DB_VERSION,
284 'time' => microtime( true ),
285 ];
286 }
287
288 /**
289 * Set the status information for a database upgrade
290 */
291 public function start_install( array $upgrades ) {
292 $this->set_stages( $upgrades );
293 $this->status = self::STATUS_NEED_INSTALL;
294 }
295
296 public function start_upgrade( array $upgrades ) {
297 $this->set_stages( $upgrades );
298 $this->status = self::STATUS_NEED_UPDATING;
299 }
300
301 private function set_stages( array $upgrades ) {
302 $this->stages = [];
303
304 foreach ( $upgrades as $upgrade ) {
305 $upgrader = Red_Database_Upgrader::get( $upgrade );
306 $this->stages = array_merge( $this->stages, array_keys( $upgrader->get_stages() ) );
307 }
308
309 if ( count( $this->stages ) > 0 ) {
310 $this->set_stage( $this->stages[0] );
311 }
312 }
313
314 public function set_stage( $stage ) {
315 $this->stage = $stage;
316 $this->save_details();
317 }
318
319 private function save_details() {
320 $stages = [
321 self::DB_UPGRADE_STAGE => [
322 'stage' => $this->stage,
323 'stages' => $this->stages,
324 'status' => $this->status,
325 ],
326 ];
327
328 red_set_options( $stages );
329
330 $this->clear_cache();
331 }
332
333 private function get_manual_upgrade() {
334 $queries = [];
335 $database = new Red_Database();
336 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), false );
337
338 foreach ( $upgraders as $upgrade ) {
339 $upgrade = Red_Database_Upgrader::get( $upgrade );
340
341 $stages = $upgrade->get_stages();
342 foreach ( array_keys( $stages ) as $stage ) {
343 $queries = array_merge( $queries, $upgrade->get_queries_for_stage( $stage ) );
344 }
345 }
346
347 return $queries;
348 }
349
350 private function get_next_stage( $stage ) {
351 $database = new Red_Database();
352 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), $this->get_current_stage() );
353
354 if ( count( $upgraders ) === 0 ) {
355 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), false );
356 }
357
358 $upgrader = Red_Database_Upgrader::get( $upgraders[0] );
359
360 // Where are we in this?
361 $pos = array_search( $this->stage, $this->stages, true );
362
363 if ( $pos === count( $this->stages ) - 1 ) {
364 $this->save_db_version( REDIRECTION_DB_VERSION );
365 return false;
366 }
367
368 // Set current DB version
369 $current_stages = array_keys( $upgrader->get_stages() );
370
371 if ( array_search( $this->stage, $current_stages, true ) === count( $current_stages ) - 1 ) {
372 $this->save_db_version( $upgraders[1]['version'] );
373 }
374
375 // Move on to next in current version
376 return $this->stages[ $pos + 1 ];
377 }
378
379 public function save_db_version( $version ) {
380 red_set_options( array( 'database' => $version ) );
381 delete_option( self::OLD_DB_VERSION );
382
383 $this->clear_cache();
384 }
385
386 private function clear_cache() {
387 if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) && function_exists( 'wp_cache_flush' ) ) {
388 wp_cache_flush();
389 }
390 }
391 }
392