PluginProbe
Migrate to WordPress.com / trunk
Migrate to WordPress.com vtrunk
6.72 6.65 trunk 5.72 5.81 5.88
wpcom-migration / helper.php

helper.php in Migrate to WordPress.com trunk, at helper.php

411 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH') && !defined('MCDATAPATH') && !defined('PHP_ERR_MONIT_PATH')) exit;
3
4 if (!class_exists('WPCOMHelper')) :
5 class WPCOMHelper {
6 const MIN_SALT_LENGTH = 32;
7 const SALT_PLACEHOLDER = 'put your unique phrase here';
8 const SALT_CONSTANTS = array(
9 'AUTH_KEY', 'AUTH_SALT', 'SECURE_AUTH_KEY', 'SECURE_AUTH_SALT',
10 'LOGGED_IN_KEY', 'LOGGED_IN_SALT', 'NONCE_KEY', 'NONCE_SALT'
11 );
12
13 public static function configSalt($constant) {
14 if (!defined($constant)) {
15 return null;
16 }
17
18 $value = constant($constant);
19 if (!is_string($value) || strlen($value) < self::MIN_SALT_LENGTH) {
20 return null;
21 }
22
23 if (self::isSaltPlaceholder($value) || self::isSharedSalt($constant, $value)) {
24 return null;
25 }
26
27 return $value;
28 }
29
30 private static function isSaltPlaceholder($value) {
31 if ($value === self::SALT_PLACEHOLDER) {
32 return true;
33 }
34
35 #wp-config-sample.php is localized for some locales, so the placeholder is
36 #not always the English string. wp_salt() guards the translated form too.
37 // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
38 return function_exists('__') && $value === __('put your unique phrase here');
39 }
40
41 private static function isSharedSalt($constant, $value) {
42 foreach (self::SALT_CONSTANTS as $other) {
43 if ($other !== $constant && defined($other) && constant($other) === $value) {
44 return true;
45 }
46 }
47
48 return false;
49 }
50
51 public static function safePregMatch($pattern, $subject, &$matches = null, $flags = 0, $offset = 0) {
52 if (!is_string($pattern) || !is_string($subject)) {
53 return false;
54 }
55 return preg_match($pattern, $subject, $matches, $flags, $offset);
56 }
57
58 # XNOTE - The below function assumes valid input
59 # $array should be an array and $keys should be an array of string, or integer data
60 public static function filterArray($array, $keys) {
61 $filteredArray = array();
62 foreach ($keys as $key) {
63 if (array_key_exists($key, $array)) {
64 $filteredArray[$key] = $array[$key];
65 }
66 }
67 return $filteredArray;
68 }
69
70 # XNOTE - The below function assumes valid input
71 # $array should be an array and $keys should be an array of string, or integer data
72 public static function digArray($array, $keys) {
73 if (empty($keys)) {
74 return null;
75 }
76 $curr_array = $array;
77 foreach ($keys as $key) {
78 if (is_array($curr_array) && array_key_exists($key, $curr_array)) {
79 $curr_array = $curr_array[$key];
80 } else {
81 return null;
82 }
83 }
84 return $curr_array;
85 }
86
87 public static function arrayKeyFirst($array) {
88 if (!function_exists('array_key_first')) {
89 foreach ($array as $key => $value) {
90 return $key;
91 }
92 return null;
93 }
94
95 return array_key_first($array);
96 }
97
98 public static function safePregReplace($replace_regex, $replace_string, $element, $limit = -1) {
99 if (!is_string($replace_regex) || !is_string($replace_string) || !is_string($element) || !is_int($limit)) {
100 return $element;
101 }
102
103 $updated_element = preg_replace($replace_regex, $replace_string, $element, $limit);
104
105 if ($updated_element === null && preg_last_error() !== PREG_NO_ERROR) {
106 return $element;
107 }
108
109 return $updated_element;
110 }
111
112 public static function safeStrReplace($search, $replace, $subject) {
113 if (!is_string($search) || !is_string($replace) || !is_string($subject)) {
114 return $subject;
115 }
116 $updated_subject = str_replace($search, $replace, $subject);
117 if ($updated_subject === null) {
118 return $subject;
119 }
120 return $updated_subject;
121 }
122
123 public static function safeStrReplaceFirst($search, $replace, $subject) {
124 if (!is_string($search) || !is_string($replace) || !is_string($subject) || $search === '') {
125 return $subject;
126 }
127
128 $position = strpos($subject, $search);
129 if ($position === false) {
130 return $subject;
131 }
132
133 return substr_replace($subject, $replace, $position, strlen($search));
134 }
135
136 public static function preInitWPHook($hook_name, $function_name, $priority, $accepted_args) {
137 global $wp_filter;
138
139 // Check if $wp_filter is not initialized or not an array
140 if (!isset($wp_filter) || !is_array($wp_filter)) {
141 $wp_filter = array();
142 }
143
144 // Check if the hook exists in $wp_filter
145 if (!isset($wp_filter[$hook_name])) {
146 $wp_filter[$hook_name] = array();
147 }
148
149 // Check if the priority exists for the hook
150 if (!isset($wp_filter[$hook_name][$priority])) {
151 $wp_filter[$hook_name][$priority] = array();
152 }
153
154 // Add the filter function information to the $wp_filter array
155 $wp_filter[$hook_name][$priority][] = array(
156 'function' => $function_name,
157 'accepted_args' => $accepted_args,
158 );
159 }
160
161 public static function removePatternFromWpConfig($pattern) {
162 if (!defined('ABSPATH')) {
163 return;
164 }
165
166 $wp_conf_paths = array(
167 rtrim(ABSPATH, DIRECTORY_SEPARATOR) . "/wp-config.php",
168 rtrim(ABSPATH, DIRECTORY_SEPARATOR) . "../wp-config.php"
169 );
170
171 if (file_exists($wp_conf_paths[0])) {
172 $fname = $wp_conf_paths[0];
173 } elseif (file_exists($wp_conf_paths[1])) {
174 $fname = $wp_conf_paths[1];
175 } else {
176 return;
177 }
178
179 self::fileRemovePattern($fname, $pattern);
180 }
181
182 public static function fileRemovePattern($fname, $pattern, $is_regex = false) {
183 if (!is_string($fname) || !is_string($pattern)) {
184 return;
185 }
186
187 if (!WPCOMWPFileSystem::getInstance()->exists($fname)) {
188 return;
189 }
190
191 $content = WPCOMWPFileSystem::getInstance()->getContents($fname);
192 if ($content !== false) {
193 if ($is_regex !== false) {
194 $modified_content = preg_replace($pattern, "", $content);
195 } else {
196 $modified_content = str_replace($pattern, "", $content);
197 }
198
199 if (empty($modified_content)) {
200 return;
201 }
202
203 if ($content !== $modified_content) {
204 WPCOMWPFileSystem::getInstance()->putContents($fname, $modified_content,
205 WPCOMWPFileSystem::getInstance()->getchmodOctal($fname));
206 }
207 }
208 }
209
210 public static function opensslEncrypt($plain_text, $cipher_algo, $encryption_key, $iv = null) {
211 if (!function_exists('openssl_encrypt') || !function_exists('openssl_get_cipher_methods') ||
212 !function_exists('openssl_random_pseudo_bytes') || !function_exists('openssl_cipher_iv_length')) {
213 return array(false, "OpenSSL extension not found.");
214 }
215
216 if (empty($plain_text) || !is_string($plain_text) ||
217 empty($encryption_key) || !is_string($encryption_key)) {
218 return array(false, "Plain text or encryption key is not a valid string.");
219 }
220
221 if (!in_array($cipher_algo, openssl_get_cipher_methods(), true)) {
222 return array(false, "Invalid cipher algorithm - " . $cipher_algo);
223 }
224
225 if ($iv === null) {
226 $iv_length = openssl_cipher_iv_length($cipher_algo);
227 if ($iv_length === false) {
228 return array(false, "IV length not found.");
229 }
230 $iv = openssl_random_pseudo_bytes($iv_length);
231 if ($iv === false) {
232 return array(false, "IV generation failed.");
233 }
234 }
235
236 if (strlen($iv) !== $iv_length) {
237 return array(false, "Invalid IV length. Expected length is " . $iv_length . " bytes.");
238 }
239
240 $encrypted_data = openssl_encrypt($plain_text, $cipher_algo, $encryption_key, OPENSSL_RAW_DATA, $iv);
241 if ($encrypted_data === false) {
242 return array(false, "Encryption failed.");
243 }
244
245 return array(true, ($iv . $encrypted_data));
246 }
247
248 public static function opensslDecrypt($data, $cipher_algo, $encryption_key) {
249 if (!function_exists('openssl_decrypt') || !function_exists('openssl_get_cipher_methods') ||
250 !function_exists('openssl_cipher_iv_length')) {
251 return array(false, "OpenSSL extension not found.");
252 }
253
254 if (empty($data) || !is_string($data) || empty($encryption_key) || !is_string($encryption_key)) {
255 return array(false, "Encrypted secret or encryption key is not a valid string.");
256 }
257
258 if (!in_array($cipher_algo, openssl_get_cipher_methods(), true)) {
259 return array(false, "Invalid cipher algorithm - " . $cipher_algo);
260 }
261
262 $iv_length = openssl_cipher_iv_length($cipher_algo);
263 if ($iv_length === false) {
264 return array(false, "IV length not found.");
265 }
266
267 if (strlen($data) <= $iv_length) {
268 return array(false, "Data length is insufficient to contain IV.");
269 }
270
271 $iv = substr($data, 0, $iv_length);
272 $encrypted_data = substr($data, $iv_length);
273
274 if ($iv === false || $encrypted_data === false) {
275 return array(false, "IV or encrypted data not found.");
276 }
277
278 $decrypted_data = openssl_decrypt($encrypted_data, $cipher_algo, $encryption_key, OPENSSL_RAW_DATA, $iv);
279
280 if ($decrypted_data === false) {
281 return array(false, "Decryption failed.");
282 }
283
284 return array(true, $decrypted_data);
285 }
286
287 public static function get_direct_filesystem() {
288 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
289 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
290 return new WP_Filesystem_Direct(new StdClass());
291 }
292
293 /**
294 * Maybe unslash a value if WordPress is loaded
295 *
296 * @param string $value The value to potentially unslash
297 * @return string The unslashed value if WP is loaded, original value otherwise
298 */
299 public static function maybeUnslashValue($value) {
300 if (function_exists('wp_unslash')) {
301 return wp_unslash($value);
302 }
303 return $value;
304 }
305
306 /**
307 * Get and sanitize a string parameter from superglobal
308 *
309 * @param string $superglobal The superglobal type ('GET', 'POST', etc.)
310 * @param string $key The parameter key to retrieve
311 * @param string $context The sanitization context ('text', 'email', 'url')
312 * @return string|null Sanitized string value or null if invalid or unknown context
313 */
314 public static function getStringParamSanitized($superglobal, $key, $context) {
315 $raw_value = self::getRawParam($superglobal, $key);
316
317 if (!is_string($raw_value)) {
318 return null;
319 }
320
321 switch ($context) {
322 case 'text':
323 if (!function_exists('sanitize_text_field')) {
324 return null;
325 }
326 return sanitize_text_field($raw_value);
327 case 'email':
328 if (!function_exists('sanitize_email')) {
329 return null;
330 }
331 return sanitize_email($raw_value);
332 case 'url':
333 if (!function_exists('esc_url_raw')) {
334 return null;
335 }
336 return esc_url_raw($raw_value);
337 default:
338 return null;
339 }
340 }
341
342 /**
343 * Get and escape a string parameter from superglobal
344 *
345 * @param string $superglobal The superglobal type ('GET', 'POST', etc.)
346 * @param string $key The parameter key to retrieve
347 * @param string $context The escaping context ('attr', 'html', 'url')
348 * @return string|null Escaped string value or null if invalid or unknown context
349 */
350 public static function getStringParamEscaped($superglobal, $key, $context) {
351 $raw_value = self::getRawParam($superglobal, $key);
352
353 if (!is_string($raw_value)) {
354 return null;
355 }
356
357 switch ($context) {
358 case 'attr':
359 if (!function_exists('esc_attr')) {
360 return null;
361 }
362 return esc_attr($raw_value);
363 case 'html':
364 if (!function_exists('esc_html')) {
365 return null;
366 }
367 return esc_html($raw_value);
368 case 'url':
369 if (!function_exists('esc_url')) {
370 return null;
371 }
372 return esc_url($raw_value);
373 default:
374 return null;
375 }
376 }
377
378 // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
379 /**
380 * Get raw parameter value from superglobal
381 *
382 * @param string $superglobal The superglobal type ('GET', 'POST', etc.)
383 * @param string $key The parameter key to retrieve
384 * @return mixed Raw parameter value or null if not found
385 */
386 public static function getRawParam($superglobal, $key) {
387 $value = null;
388
389 switch (strtoupper($superglobal)) {
390 case 'GET':
391 $value = isset($_GET[$key]) ? $_GET[$key] : null;
392 break;
393 case 'POST':
394 $value = isset($_POST[$key]) ? $_POST[$key] : null;
395 break;
396 case 'COOKIE':
397 $value = isset($_COOKIE[$key]) ? $_COOKIE[$key] : null;
398 break;
399 case 'REQUEST':
400 $value = isset($_REQUEST[$key]) ? $_REQUEST[$key] : null;
401 break;
402 case 'SERVER':
403 $value = isset($_SERVER[$key]) ? $_SERVER[$key] : null;
404 break;
405 }
406
407 return $value !== null ? self::maybeUnslashValue($value) : null;
408 }
409 // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
410 }
411 endif;