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

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