PluginProbe
The WP Remote WordPress Plugin / 6.76
The WP Remote WordPress Plugin v6.76
6.76 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 All 54 releases
wpremote / helper.php

helper.php in The WP Remote WordPress Plugin 6.76, at helper.php

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