PluginProbe
Redirection / 5.2
Redirection v5.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.2, at database/database-status.php

384 lines 9.8 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() ) {
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'] !== '' ) {
92 return $settings['database'];
93 } elseif ( $this->get_old_version() !== false ) {
94 $version = $this->get_old_version();
95
96 // Upgrade the old value
97 red_set_options( array( 'database' => $version ) );
98 delete_option( self::OLD_DB_VERSION );
99 $this->clear_cache();
100 return $version;
101 }
102
103 return '';
104 }
105
106 private function get_old_version() {
107 return get_option( self::OLD_DB_VERSION );
108 }
109
110 public function check_tables_exist() {
111 $latest = Red_Database::get_latest_database();
112 $missing = $latest->get_missing_tables();
113
114 // No tables installed - do a fresh install
115 if ( count( $missing ) === count( $latest->get_all_tables() ) ) {
116 delete_option( Red_Database_Status::OLD_DB_VERSION );
117 red_set_options( [ 'database' => '' ] );
118 $this->clear_cache();
119
120 $this->status = self::STATUS_NEED_INSTALL;
121 $this->stop_update();
122 } elseif ( count( $missing ) > 0 && version_compare( $this->get_current_version(), '2.3.3', 'ge' ) ) {
123 // Some tables are missing - try and fill them in
124 $latest->install();
125 }
126 }
127
128 /**
129 * Does the current database support a particular version
130 *
131 * @param string $version Target version
132 * @return bool true if supported, false otherwise
133 */
134 public function does_support( $version ) {
135 return version_compare( $this->get_current_version(), $version, 'ge' );
136 }
137
138 public function is_error() {
139 return $this->result === self::RESULT_ERROR;
140 }
141
142 public function set_error( $error ) {
143 global $wpdb;
144
145 $this->result = self::RESULT_ERROR;
146 $this->reason = str_replace( "\t", ' ', $error );
147
148 if ( $wpdb->last_error ) {
149 $this->debug[] = $wpdb->last_error;
150
151 if ( strpos( $wpdb->last_error, 'command denied to user' ) !== false ) {
152 $this->reason .= ' - ' . __( 'Insufficient database permissions detected. Please give your database user appropriate permissions.', 'redirection' );
153 }
154 }
155
156 $latest = Red_Database::get_latest_database();
157 $this->debug = array_merge( $this->debug, $latest->get_table_schema() );
158 $this->debug[] = 'Stage: ' . $this->get_current_stage();
159 }
160
161 public function set_ok( $reason ) {
162 $this->reason = $reason;
163 $this->result = self::RESULT_OK;
164 $this->debug = [];
165 }
166
167 /**
168 * Stop current upgrade
169 */
170 public function stop_update() {
171 $this->stage = false;
172 $this->stages = [];
173 $this->debug = [];
174
175 red_set_options( [ self::DB_UPGRADE_STAGE => false ] );
176 $this->clear_cache();
177 }
178
179 public function finish() {
180 $this->stop_update();
181
182 if ( $this->status === self::STATUS_NEED_INSTALL ) {
183 $this->status = self::STATUS_FINISHED_INSTALL;
184 } elseif ( $this->status === self::STATUS_NEED_UPDATING ) {
185 $this->status = self::STATUS_FINISHED_UPDATING;
186 }
187 }
188
189 /**
190 * Get current upgrade stage
191 * @return string|bool Current stage name, or false if not upgrading
192 */
193 public function get_current_stage() {
194 return $this->stage;
195 }
196
197 /**
198 * Move current stage on to the next
199 */
200 public function set_next_stage() {
201 $this->debug = [];
202 $stage = $this->get_current_stage();
203
204 if ( $stage ) {
205 $stage = $this->get_next_stage( $stage );
206
207 // Save next position
208 if ( $stage ) {
209 $this->set_stage( $stage );
210 } else {
211 $this->finish();
212 }
213 }
214 }
215
216 /**
217 * Get current upgrade status
218 *
219 * @return array Database status array
220 */
221 public function get_json() {
222 // Base information
223 $result = [
224 'status' => $this->status,
225 'inProgress' => $this->stage !== false,
226 ];
227
228 // Add on version status
229 if ( $this->status === self::STATUS_NEED_INSTALL || $this->status === self::STATUS_NEED_UPDATING ) {
230 $result = array_merge(
231 $result,
232 $this->get_version_upgrade(),
233 [ 'manual' => $this->get_manual_upgrade() ]
234 );
235 }
236
237 // Add on upgrade status
238 if ( $this->is_error() ) {
239 $result = array_merge( $result, $this->get_version_upgrade(), $this->get_progress_status(), $this->get_error_status() );
240 } elseif ( $result['inProgress'] ) {
241 $result = array_merge( $result, $this->get_progress_status() );
242 } elseif ( $this->status === self::STATUS_FINISHED_INSTALL || $this->status === self::STATUS_FINISHED_UPDATING ) {
243 $result['complete'] = 100;
244 $result['reason'] = $this->reason;
245 }
246
247 return $result;
248 }
249
250 private function get_error_status() {
251 return [
252 'reason' => $this->reason,
253 'result' => self::RESULT_ERROR,
254 'debug' => $this->debug,
255 ];
256 }
257
258 private function get_progress_status() {
259 $complete = 0;
260
261 if ( $this->stage ) {
262 $complete = round( ( array_search( $this->stage, $this->stages, true ) / count( $this->stages ) ) * 100, 1 );
263 }
264
265 return [
266 'complete' => $complete,
267 'result' => self::RESULT_OK,
268 'reason' => $this->reason,
269 ];
270 }
271
272 private function get_version_upgrade() {
273 return [
274 'current' => $this->get_current_version() ? $this->get_current_version() : '-',
275 'next' => REDIRECTION_DB_VERSION,
276 'time' => microtime( true ),
277 ];
278 }
279
280 /**
281 * Set the status information for a database upgrade
282 */
283 public function start_install( array $upgrades ) {
284 $this->set_stages( $upgrades );
285 $this->status = self::STATUS_NEED_INSTALL;
286 }
287
288 public function start_upgrade( array $upgrades ) {
289 $this->set_stages( $upgrades );
290 $this->status = self::STATUS_NEED_UPDATING;
291 }
292
293 private function set_stages( array $upgrades ) {
294 $this->stages = [];
295
296 foreach ( $upgrades as $upgrade ) {
297 $upgrader = Red_Database_Upgrader::get( $upgrade );
298 $this->stages = array_merge( $this->stages, array_keys( $upgrader->get_stages() ) );
299 }
300
301 if ( count( $this->stages ) > 0 ) {
302 $this->set_stage( $this->stages[0] );
303 }
304 }
305
306 public function set_stage( $stage ) {
307 $this->stage = $stage;
308 $this->save_details();
309 }
310
311 private function save_details() {
312 $stages = [
313 self::DB_UPGRADE_STAGE => [
314 'stage' => $this->stage,
315 'stages' => $this->stages,
316 'status' => $this->status,
317 ],
318 ];
319
320 red_set_options( $stages );
321
322 $this->clear_cache();
323 }
324
325 private function get_manual_upgrade() {
326 $queries = [];
327 $database = new Red_Database();
328 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), false );
329
330 foreach ( $upgraders as $upgrade ) {
331 $upgrade = Red_Database_Upgrader::get( $upgrade );
332
333 $stages = $upgrade->get_stages();
334 foreach ( array_keys( $stages ) as $stage ) {
335 $queries = array_merge( $queries, $upgrade->get_queries_for_stage( $stage ) );
336 }
337 }
338
339 return $queries;
340 }
341
342 private function get_next_stage( $stage ) {
343 $database = new Red_Database();
344 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), $this->get_current_stage() );
345
346 if ( count( $upgraders ) === 0 ) {
347 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), false );
348 }
349
350 $upgrader = Red_Database_Upgrader::get( $upgraders[0] );
351
352 // Where are we in this?
353 $pos = array_search( $this->stage, $this->stages, true );
354
355 if ( $pos === count( $this->stages ) - 1 ) {
356 $this->save_db_version( REDIRECTION_DB_VERSION );
357 return false;
358 }
359
360 // Set current DB version
361 $current_stages = array_keys( $upgrader->get_stages() );
362
363 if ( array_search( $this->stage, $current_stages, true ) === count( $current_stages ) - 1 ) {
364 $this->save_db_version( $upgraders[1]['version'] );
365 }
366
367 // Move on to next in current version
368 return $this->stages[ $pos + 1 ];
369 }
370
371 public function save_db_version( $version ) {
372 red_set_options( array( 'database' => $version ) );
373 delete_option( self::OLD_DB_VERSION );
374
375 $this->clear_cache();
376 }
377
378 private function clear_cache() {
379 if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) && function_exists( 'wp_cache_flush' ) ) {
380 wp_cache_flush();
381 }
382 }
383 }
384