PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.8.0
WP 2FA – Two-factor authentication for WordPress v2.8.0
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / Utils / class-abstract-migration.php
wp-2fa / includes / classes / Utils Last commit date
class-abstract-migration.php 1 year ago class-date-time-utils.php 1 year ago class-debugging.php 1 year ago class-generate-modal.php 1 year ago class-migration.php 1 year ago class-request-utils.php 1 year ago class-settings-utils.php 1 year ago class-user-utils.php 1 year ago class-white-label.php 1 year ago index.php 1 year ago
class-abstract-migration.php
236 lines
1 <?php
2 /**
3 * Abstract migration class.
4 *
5 * @package wp2fa
6 * @subpackage utils
7 * @copyright 2024 Melapress
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 */
11
12 declare(strict_types=1);
13
14 namespace WP2FA\Utils;
15
16 use WP2FA\Utils\Settings_Utils;
17
18 defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
19
20 /**
21 * Abstract AMigration class
22 */
23 if ( ! class_exists( '\WP2FA\Utils\Abstract_Migration' ) ) {
24
25 /**
26 * Utility class to ease the migration process.
27 *
28 * Every migration must go in its own method
29 * The naming convention is migrateUpTo_XXX where XXX is the number of the version,
30 * format is numbers only.
31 * Example: migration for version upto 1.4 must be in migrateUpTo_14 method
32 *
33 * The numbers in the names of the methods must have exact numbers count as in the selected
34 * version in use, even if there are silent numbers for some of the major versions as 1, 2, 3 etc. (the .0.0 is skipped / silent)
35 * Example:
36 * - if X.X.X is selected for version number, then for version 1.1 method must have "...migrateUpTo_110..." in its name
37 * - if X.X is selected for version number, then for version 1, method must have "...migrateUpTo_10..." in its name
38 *
39 * Note: you can add prefix to the migration method, if that is necessary, but "migrateUpTo_" is a must -
40 * the name must contain that @see getAllMigrationMethodsAsNumbers of that class.
41 * For version extraction the number following the last '_' will be used
42 * TODO: the mandatory part of the method name can be a setting in the class, but is that a good idea?
43 *
44 * Note: order of the methods is not preserved - version numbers will be used for ordering
45 *
46 * @package WP2FA\Utils
47 *
48 * @since 1.6
49 */
50 class Abstract_Migration {
51
52 /**
53 * Extracted version from the DB (WP option)
54 *
55 * @var string
56 *
57 * @since 1.6.0
58 */
59 protected static $stored_version = '';
60
61 /**
62 * The name of the option from which we should extract version
63 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
64 * Note: only numbers will be processed
65 *
66 * @var string
67 *
68 * @since 1.6.0
69 */
70 protected static $version_option_name = '';
71
72 /**
73 * The constant name where the plugin version is stored
74 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
75 * Note: only numbers will be processed
76 *
77 * @var string
78 *
79 * @since 2.2.0
80 */
81 protected static $const_name_of_plugin_version = '';
82
83 /**
84 * Used for adding proper pads for the missing numbers
85 * Version number format used here depends on selection for how many numbers will be used for representing version
86 *
87 * For X.X use 2;
88 * For X.X.X use 3;
89 * For X.X.X.X use 4;
90 *
91 * etc.
92 *
93 * Example: if selected version format is X.X.X that means that 3 digits are used for versioning.
94 * And current version is stored as 2 (no suffix 0.0) that means that it will be normalized as 200.
95 *
96 * @var integer
97 *
98 * @since 1.6.0
99 */
100 protected static $pad_length = 3;
101
102 /**
103 * Collects all the migration methods which needs to be executed in order and executes them
104 *
105 * @return void
106 *
107 * @since 1.6.0
108 */
109 public static function migrate() {
110
111 if ( version_compare( static::get_stored_version(), \constant( static::$const_name_of_plugin_version ), '<' ) ) {
112
113 $stored_version_as_number = static::normalize_version( static::get_stored_version() );
114 $target_version_as_number = static::normalize_version( \constant( static::$const_name_of_plugin_version ) );
115 $method_as_version_numbers = static::get_all_migration_methods_as_numbers();
116
117 $migrate_methods = array_filter(
118 $method_as_version_numbers,
119 function ( $method, $key ) use ( &$stored_version_as_number, &$target_version_as_number ) {
120 if ( $target_version_as_number > $stored_version_as_number ) {
121 return ( in_array( $key, range( $stored_version_as_number, $target_version_as_number ), true ) );
122 }
123
124 return false;
125 },
126 ARRAY_FILTER_USE_BOTH
127 );
128
129 if ( ! empty( $migrate_methods ) ) {
130 \ksort( $migrate_methods );
131 foreach ( $migrate_methods as $method ) {
132 static::{$method}();
133 }
134 }
135
136 // If we have a previous version, its an update so flag notice.
137 if ( ! empty( Settings_Utils::get_option( static::$version_option_name ) ) ) {
138 Settings_Utils::update_option( 'wp_2fa_update_redirection_needed', true );
139 }
140
141 self::store_updated_version();
142 }
143
144 /**
145 * Downgrading the plugin? Set the version number.
146 * Leave the rest as is.
147 *
148 * @return void
149 *
150 * @since 2.2.0
151 */
152 if ( version_compare( static::get_stored_version(), \constant( static::$const_name_of_plugin_version ), '>' ) ) {
153 self::store_updated_version();
154 }
155 }
156
157 /**
158 * Extracts currently stored version from the DB
159 *
160 * @return string
161 *
162 * @since 1.6.0
163 */
164 private static function get_stored_version() {
165
166 if ( '' === trim( (string) static::$stored_version ) ) {
167 static::$stored_version = (string) Settings_Utils::get_option( static::$version_option_name, '0.0.0' );
168 }
169
170 return static::$stored_version;
171 }
172
173 /**
174 * Stores the version to which we migrated
175 *
176 * @return void
177 *
178 * @since 1.6.0
179 */
180 private static function store_updated_version() {
181 Settings_Utils::update_option( static::$version_option_name, \constant( static::$const_name_of_plugin_version ) );
182 }
183
184 /**
185 * Normalized the version numbers to numbers
186 *
187 * Version format is expected to be as follows:
188 * X.X.X
189 *
190 * All non numeric values will be removed from the version string
191 *
192 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
193 * Note: only numbers will be processed
194 *
195 * @param string $version - The version string we have to use.
196 *
197 * @return string
198 *
199 * @since 1.6.0
200 */
201 private static function normalize_version( string $version ) {
202 $version_as_number = (int) filter_var( $version, FILTER_SANITIZE_NUMBER_INT );
203
204 if ( self::$pad_length > strlen( (string) $version_as_number ) ) {
205 $version_as_number = str_pad( (string) $version_as_number, static::$pad_length, '0', STR_PAD_RIGHT );
206 }
207
208 return $version_as_number;
209 }
210
211 /**
212 * Collects all the migration methods from the class and stores them in the array
213 * Array is in following format:
214 * key - number of the version
215 * value - name of the method
216 *
217 * @return array
218 *
219 * @since 1.6.0
220 */
221 private static function get_all_migration_methods_as_numbers() {
222 $class_methods = \get_class_methods( get_called_class() );
223
224 $method_as_version_numbers = array();
225 foreach ( $class_methods as $method ) {
226 if ( false !== \strpos( $method, 'migrate_up_to_' ) ) {
227 $ver = \substr( $method, \strrpos( $method, '_' ) + 1, \strlen( $method ) );
228 $method_as_version_numbers[ $ver ] = $method;
229 }
230 }
231
232 return $method_as_version_numbers;
233 }
234 }
235 }
236