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

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