PluginProbe
The WP Remote WordPress Plugin / trunk
The WP Remote WordPress Plugin vtrunk
6.72 6.69 6.65 6.62 6.48 6.47 4.87 4.97 5.05 5.09 5.16 5.22 5.24 5.25 5.38 5.41 5.42 5.45 5.47 5.53 5.56 5.65 5.68 5.72 5.73 All 53 releases
← All changes | helper.php +399 -0 5.09trunk View file →
@@ -1,8 +1,54 @@
1 1 <?php
2 +if (!defined('ABSPATH') && !defined('MCDATAPATH') && !defined('PHP_ERR_MONIT_PATH')) exit;
2 3
3 4 if (!class_exists('WPRHelper')) :
4 5 class WPRHelper {
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 +
5 51 public static function safePregMatch($pattern, $subject, &$matches = null, $flags = 0, $offset = 0) {
6 52 if (!is_string($pattern) || !is_string($subject)) {
7 53 return false;
8 54 }
@@ -7,6 +53,359 @@
7 53 return false;
8 54 }
9 55 return preg_match($pattern, $subject, $matches, $flags, $offset);
10 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 (!WPRWPFileSystem::getInstance()->exists($fname)) {
188 + return;
189 + }
190 +
191 + $content = WPRWPFileSystem::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 + WPRWPFileSystem::getInstance()->putContents($fname, $modified_content,
205 + WPRWPFileSystem::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
11 410 }
12 411 endif;