PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.6.0
WP 2FA – Two-factor authentication for WordPress v2.6.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 2 years ago class-date-time-utils.php 2 years ago class-debugging.php 2 years ago class-generate-modal.php 2 years ago class-migration.php 2 years ago class-request-utils.php 2 years ago class-settings-utils.php 2 years ago class-user-utils.php 2 years ago index.php 5 years ago
class-abstract-migration.php
214 lines
1 <?php
2 /**
3 * Abstract migration class.
4 *
5 * @package wp2fa
6 * @subpackage utils
7 * @copyright %%YEAR%% 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 * @since 1.6
48 */
49 class Abstract_Migration {
50
51 /**
52 * Extracted version from the DB (WP option)
53 *
54 * @var string
55 */
56 protected static $stored_version = '';
57
58 /**
59 * The name of the option from which we should extract version
60 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
61 * Note: only numbers will be processed
62 *
63 * @var string
64 */
65 protected static $version_option_name = '';
66
67 /**
68 * The constant name where the plugin version is stored
69 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
70 * Note: only numbers will be processed
71 *
72 * @var string
73 *
74 * @since 2.2.0
75 */
76 protected static $const_name_of_plugin_version = '';
77
78 /**
79 * Used for adding proper pads for the missing numbers
80 * Version number format used here depends on selection for how many numbers will be used for representing version
81 *
82 * For X.X use 2;
83 * For X.X.X use 3;
84 * For X.X.X.X use 4;
85 *
86 * etc.
87 *
88 * Example: if selected version format is X.X.X that means that 3 digits are used for versioning.
89 * And current version is stored as 2 (no suffix 0.0) that means that it will be normalized as 200.
90 *
91 * @var integer
92 */
93 protected static $pad_length = 3;
94
95 /**
96 * Collects all the migration methods which needs to be executed in order and executes them
97 *
98 * @return void
99 */
100 public static function migrate() {
101
102 if ( version_compare( static::get_stored_version(), \constant( static::$const_name_of_plugin_version ), '<' ) ) {
103
104 $stored_version_as_number = static::normalize_version( static::get_stored_version() );
105 $target_version_as_number = static::normalize_version( \constant( static::$const_name_of_plugin_version ) );
106 $method_as_version_numbers = static::get_all_migration_methods_as_numbers();
107
108 $migrate_methods = array_filter(
109 $method_as_version_numbers,
110 function ( $method, $key ) use ( &$stored_version_as_number, &$target_version_as_number ) {
111 if ( $target_version_as_number > $stored_version_as_number ) {
112 return ( in_array( $key, range( $stored_version_as_number, $target_version_as_number ), true ) );
113 }
114
115 return false;
116 },
117 ARRAY_FILTER_USE_BOTH
118 );
119
120 if ( ! empty( $migrate_methods ) ) {
121 \ksort( $migrate_methods );
122 foreach ( $migrate_methods as $method ) {
123 static::{$method}();
124 }
125 }
126
127 self::store_updated_version();
128 }
129
130 /**
131 * Downgrading the plugin? Set the version number.
132 * Leave the rest as is.
133 *
134 * @return void
135 *
136 * @since 2.2.0
137 */
138 if ( version_compare( static::get_stored_version(), \constant( static::$const_name_of_plugin_version ), '>' ) ) {
139 self::store_updated_version();
140 }
141 }
142
143 /**
144 * Extracts currently stored version from the DB
145 *
146 * @return string
147 */
148 private static function get_stored_version() {
149
150 if ( '' === trim( (string) static::$stored_version ) ) {
151 static::$stored_version = (string) Settings_Utils::get_option( static::$version_option_name, '0.0.0' );
152 }
153
154 return static::$stored_version;
155 }
156
157 /**
158 * Stores the version to which we migrated
159 *
160 * @return void
161 */
162 private static function store_updated_version() {
163 Settings_Utils::update_option( static::$version_option_name, \constant( static::$const_name_of_plugin_version ) );
164 }
165
166 /**
167 * Normalized the version numbers to numbers
168 *
169 * Version format is expected to be as follows:
170 * X.X.X
171 *
172 * All non numeric values will be removed from the version string
173 *
174 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
175 * Note: only numbers will be processed
176 *
177 * @param string $version - The version string we have to use.
178 *
179 * @return string
180 */
181 private static function normalize_version( string $version ) {
182 $version_as_number = (int) filter_var( $version, FILTER_SANITIZE_NUMBER_INT );
183
184 if ( self::$pad_length > strlen( (string) $version_as_number ) ) {
185 $version_as_number = str_pad( (string) $version_as_number, static::$pad_length, '0', STR_PAD_RIGHT );
186 }
187
188 return $version_as_number;
189 }
190
191 /**
192 * Collects all the migration methods from the class and stores them in the array
193 * Array is in following format:
194 * key - number of the version
195 * value - name of the method
196 *
197 * @return array
198 */
199 private static function get_all_migration_methods_as_numbers() {
200 $class_methods = \get_class_methods( get_called_class() );
201
202 $method_as_version_numbers = array();
203 foreach ( $class_methods as $method ) {
204 if ( false !== \strpos( $method, 'migrate_up_to_' ) ) {
205 $ver = \substr( $method, \strrpos( $method, '_' ) + 1, \strlen( $method ) );
206 $method_as_version_numbers[ $ver ] = $method;
207 }
208 }
209
210 return $method_as_version_numbers;
211 }
212 }
213 }
214