PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 1.6.0
WP 2FA – Two-factor authentication for WordPress v1.6.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 / AbstractMigration.php
wp-2fa / includes / classes / Utils Last commit date
AbstractMigration.php 5 years ago DateTimeUtils.php 5 years ago Debugging.php 5 years ago GenerateModal.php 5 years ago Migration.php 5 years ago UserUtils.php 5 years ago
AbstractMigration.php
199 lines
1 <?php
2 namespace WP2FA\Utils;
3
4 defined( 'ABSPATH' ) || exit; // Exit if accessed directly
5
6 /**
7 * Abstract AMigration class
8 */
9 if ( ! class_exists( '\WP2FA\Utils\AbstractMigration' ) ) {
10
11 /**
12 * Utility class to ease the migration process.
13 *
14 * Every migration must go in its own method
15 * The naming convention is migrateUpTo_XXX where XXX is the number of the version,
16 * format is numbers only.
17 * Example: migration for version upto 1.4 must be in migrateUpTo_14 method
18 *
19 * The numbers in the names of the methods must have exact numbers count as in the selected
20 * 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)
21 * Example:
22 * - if X.X.X is selected for version number, then for version 1.1 method must have "...migrateUpTo_110..." in its name
23 * - if X.X is selected for version number, then for version 1, method must have "...migrateUpTo_10..." in its name
24 *
25 * Note: you can add prefix to the migration method, if that is necessary, but "migrateUpTo_" is a must -
26 * the name must contain that @see getAllMigrationMethodsAsNumbers of that class.
27 * For version extraction the number following the last '_' will be used
28 * TODO: the mandatory part of the method name can be a setting in the class, but is that a good idea?
29 *
30 * Note: order of the methods is not preserved - version numbers will be used for ordering
31 *
32 * @package WP2FA\Utils
33 * @since 1.6
34 */
35 class AbstractMigration {
36
37 /**
38 * Extracted version from the DB (WP option)
39 */
40 protected static $storedVersion = '';
41
42 /**
43 * The name of the option from which we should extact version
44 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
45 * Note: only numbers will be processed
46 */
47 protected static $versionOptionName = '';
48
49 /**
50 * The constant name where the plugin version is stored
51 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
52 * Note: only numbers will be processed
53 */
54 protected static $constNameOfPluginVersion = '';
55
56 /**
57 * Used for adding proper pads for the missing numbers
58 * Version number format used here depends on selection for how many numbers will be used for representing version
59 *
60 * for X.X use 2;
61 * for X.X.X use 3;
62 * for X.X.X.X use 4;
63 *
64 * etc.
65 *
66 * Example: if selected version format is X.X.X that means that 3 digits are used for versioning.
67 * And current version is stored as 2 (no suffix 0.0) that means that it will be normalized as 200.
68 */
69 protected static $padLength = 3;
70
71 /**
72 * Collects all the migration methods which needs to be executed in order and executes them
73 *
74 * @return void
75 */
76 public static function migrate() {
77
78 if ( version_compare( static::getStoredVersion(), \constant( static::$constNameOfPluginVersion ), '<' ) ) {
79
80 $storedVersionAsNumber = static::normalizeVersion( static::getStoredVersion() );
81 $targetVersionAsNumber = static::normalizeVersion( \constant( static::$constNameOfPluginVersion ) );
82 $methodAsVersionNumbers = static::getAllMigrationMethodsAsNumbers();
83
84 $migrateMethods = array_filter(
85 $methodAsVersionNumbers,
86 function( $method, $key ) use ( &$storedVersionAsNumber, &$targetVersionAsNumber ) {
87 if ( $targetVersionAsNumber > $storedVersionAsNumber ) {
88 return ( in_array( $key, range( $storedVersionAsNumber, $targetVersionAsNumber ) ) );
89 }
90
91 return false;
92 },
93 ARRAY_FILTER_USE_BOTH
94 );
95
96 if ( ! empty( $migrateMethods ) ) {
97 \ksort( $migrateMethods );
98 foreach ( $migrateMethods as $method ) {
99 static::{$method}();
100 }
101 }
102
103 self::storeUpdatedVersion();
104 }
105 }
106
107 /**
108 * Extracts currently stored version from the DB
109 *
110 * @return string
111 */
112 private static function getStoredVersion() {
113
114 if ( '' === trim( static::$storedVersion ) ) {
115
116 // Add plugin version to wp_options.
117 if ( self::isMultisite() ) {
118 static::$storedVersion = get_network_option( null, static::$versionOptionName, '0.0.0' );
119 } else {
120 static::$storedVersion = get_option( static::$versionOptionName, '0.0.0' );
121 }
122 }
123
124 return static::$storedVersion;
125 }
126
127 /**
128 * Stores the version to which we migrated
129 *
130 * @return void
131 */
132 private static function storeUpdatedVersion() {
133
134 // Add plugin version to wp_options.
135 if ( self::isMultisite() ) {
136 update_network_option( null, static::$versionOptionName, \constant( static::$constNameOfPluginVersion ) );
137 } else {
138 update_option( static::$versionOptionName, \constant( static::$constNameOfPluginVersion ) );
139 }
140 }
141
142 /**
143 * Normalized the version numbers to numbers
144 *
145 * Version format is expected to be as follows:
146 * X.X.X
147 *
148 * All non numeric values will be removed from the version string
149 *
150 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
151 * Note: only numbers will be processed
152 *
153 * @param string $version
154 *
155 * @return string
156 */
157 private static function normalizeVersion( string $version ) {
158 $versionAsNumber = (int) filter_var( $version, FILTER_SANITIZE_NUMBER_INT );
159
160 if ( self::$padLength > strlen( $versionAsNumber ) ) {
161 $versionAsNumber = str_pad( $versionAsNumber, static::$padLength, '0', STR_PAD_RIGHT );
162 }
163
164 return $versionAsNumber;
165 }
166
167 /**
168 * Collects all the migration methods from the class and stores them in the array
169 * Array is in following format:
170 * key - number of the version
171 * value - name of the method
172 *
173 * @return array
174 */
175 private static function getAllMigrationMethodsAsNumbers() {
176 $classMethods = \get_class_methods( get_called_class() );
177
178 $methodAsVersionNumbers = [];
179 foreach ( $classMethods as $method ) {
180 if ( false !== \strpos( $method, 'migrateUpTo_' ) ) {
181 $ver = \substr( $method, \strrpos( $method, '_' ) + 1, \strlen( $method ) );
182 $methodAsVersionNumbers[ $ver ] = $method;
183 }
184 }
185
186 return $methodAsVersionNumbers;
187 }
188
189 /**
190 * Checks if the current installation of the WP is multisite
191 *
192 * @return boolean
193 */
194 private static function isMultisite() {
195 return function_exists( 'is_multisite' ) && is_multisite();
196 }
197 }
198 }
199