PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260814
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260814
260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 All 189 releases
s2member / src / includes / classes / utils-strings.inc.php

utils-strings.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260814, at src/includes/classes/utils-strings.inc.php

733 lines 27.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * String utilities.
5 *
6 * Copyright: © 2009-2011
7 * {@link http://websharks-inc.com/ WebSharks, Inc.}
8 * (coded in the USA)
9 *
10 * Released under the terms of the GNU General Public License.
11 * You should have received a copy of the GNU General Public License,
12 * along with this software. In the main directory, see: /licensing/
13 * If not, see: {@link http://www.gnu.org/licenses/}.
14 *
15 * @package s2Member\Utilities
16 * @since 3.5
17 */
18 if(!defined('WPINC')) // MUST have WordPress.
19 exit('Do not access this file directly.');
20
21 if(!class_exists('c_ws_plugin__s2member_utils_strings'))
22 {
23 /**
24 * String utilities.
25 *
26 * @package s2Member\Utilities
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_utils_strings
30 {
31 /**
32 * Array of all ampersand entities.
33 *
34 * Array keys are actually regex patterns *(very useful)*.
35 *
36 * @package s2Member\Utilities
37 * @since 111106
38 *
39 * @var array
40 */
41 public static $ampersand_entities = array(
42 '&amp;' => '&amp;',
43 '&#0*38;' => '&#38;',
44 '&#[xX]0*26;' => '&#x26;'
45 );
46
47 /**
48 * Array of all quote entities *(and entities for quote variations)*.
49 *
50 * Array keys are actually regex patterns *(very useful)*.
51 *
52 * @package s2Member\Utilities
53 * @since 111106
54 *
55 * @var array
56 */
57 public static $quote_entities_w_variations = array(
58 '&apos;' => '&apos;',
59 '&#0*39;' => '&#39;',
60 '&#[xX]0*27;' => '&#x27;',
61 '&lsquo;' => '&lsquo;',
62 '&#0*8216;' => '&#8216;',
63 '&#[xX]0*2018;' => '&#x2018;',
64 '&rsquo;' => '&rsquo;',
65 '&#0*8217;' => '&#8217;',
66 '&#[xX]0*2019;' => '&#x2019;',
67 '&quot;' => '&quot;',
68 '&#0*34;' => '&#34;',
69 '&#[xX]0*22;' => '&#x22;',
70 '&ldquo;' => '&ldquo;',
71 '&#0*8220;' => '&#8220;',
72 '&#[xX]0*201[cC];' => '&#x201C;',
73 '&rdquo;' => '&rdquo;',
74 '&#0*8221;' => '&#8221;',
75 '&#[xX]0*201[dD];' => '&#x201D;'
76 );
77
78 /**
79 * Escapes double quotes.
80 *
81 * @package s2Member\Utilities
82 * @since 3.5
83 *
84 * @param string $string Input string.
85 * @param int $times Number of escapes. Defaults to 1.
86 * @param string $escape_char The character to be used in escapes.
87 *
88 * @return string Output string after double quotes are escaped.
89 */
90 public static function esc_dq($string = '', $times = NULL, $escape_char = '\\')
91 {
92 $times = (is_numeric($times) && $times >= 0) ? (int)$times : 1;
93
94 return str_replace('"', str_repeat($escape_char, $times).'"', (string)$string);
95 }
96
97 /**
98 * Escapes single quotes.
99 *
100 * @package s2Member\Utilities
101 * @since 3.5
102 *
103 * @param string $string Input string.
104 * @param int $times Number of escapes. Defaults to 1.
105 *
106 * @return string Output string after single quotes are escaped.
107 */
108 public static function esc_sq($string = '', $times = NULL)
109 {
110 $times = (is_numeric($times) && $times >= 0) ? (int)$times : 1;
111
112 return str_replace("'", str_repeat('\\', $times)."'", (string)$string);
113 }
114
115 /**
116 * Escapes JavaScript and single quotes.
117 *
118 * @package s2Member\Utilities
119 * @since 110901
120 *
121 * @param string $string Input string.
122 * @param int $times Number of escapes. Defaults to 1.
123 *
124 * @return string Output string after JavaScript and single quotes are escaped.
125 */
126 public static function esc_js_sq($string = '', $times = NULL)
127 {
128 $times = (is_numeric($times) && $times >= 0) ? (int)$times : 1;
129
130 return str_replace("'", str_repeat('\\', $times)."'", str_replace(array("\r", "\n"), array('', '\\n'), str_replace("\\'", "'", (string)$string)));
131 }
132
133 /**
134 * Escapes dollars signs (for regex patterns).
135 *
136 * @package s2Member\Utilities
137 * @since 3.5
138 *
139 * @param string $string Input string.
140 * @param int $times Number of escapes. Defaults to 1.
141 *
142 * @return string Output string after dollar signs are escaped.
143 *
144 * @deprecated Starting with s2Member v120103, please use:
145 * ``c_ws_plugin__s2member_utils_strings::esc_refs()``.
146 */
147 public static function esc_ds($string = '', $times = NULL)
148 {
149 $times = (is_numeric($times) && $times >= 0) ? (int)$times : 1;
150
151 return str_replace('$', str_repeat('\\', $times).'$', (string)$string);
152 }
153
154 /**
155 * Escapes backreferences (for regex patterns).
156 *
157 * @package s2Member\Utilities
158 * @since 120103
159 *
160 * @param string $string Input string.
161 * @param int $times Number of escapes. Defaults to 1.
162 *
163 * @return string Output string after backreferences are escaped.
164 */
165 public static function esc_refs($string = NULL, $times = NULL)
166 {
167 $times = (is_numeric($times) && $times >= 0) ? (int)$times : 1;
168
169 return str_replace(array('\\', '$'), array(str_repeat('\\', $times).'\\', str_repeat('\\', $times).'$'), (string)$string);
170 }
171
172 /**
173 * Sanitizes a string; by stripping characters NOT on a standard U.S. keyboard.
174 *
175 * @package s2Member\Utilities
176 * @since 111106
177 *
178 * @param string $string Input string.
179 *
180 * @return string Output string, after characters NOT on a standard U.S. keyboard have been stripped.
181 */
182 public static function strip_2_kb_chars($string = '')
183 {
184 return preg_replace('/[^0-9A-Z'."\r\n\t".'\s`\=\[\]\\\;\',\.\/~\!@#\$%\^&\*\(\)_\+\|\}\{\:"\?\>\<\-]/i', '', remove_accents((string)$string));
185 }
186
187 /**
188 * Sanitizes a string by breaking PHP opening tags (including encoded/mixed/double-encoded forms).
189 *
190 * @package s2Member\Utilities
191 * @since 241207
192 *
193 * @param string $input Input string to sanitize.
194 * @return string Original input when safe, otherwise decoded string with PHP opening tags removed.
195 */
196 public static function strip_php_tags($input = '') {
197 $copy = (string) $input;
198
199 //251002 Collapse mixed/double encodings (HTML entities + URL encodings).
200 $flags = ENT_QUOTES | (defined('ENT_HTML5') ? ENT_HTML5 : 0);
201 for ($i = 0; $i < 3; $i++) {
202 $copy = html_entity_decode($copy, $flags, 'UTF-8'); // &lt;, &#60;, &#x3C;, etc.
203 $copy = rawurldecode($copy); // %3C, %3F, %3E, etc.
204 }
205
206 // If no opener after normalization, return the original.
207 if (strpos($copy, '<?') === false) {
208 return $input;
209 }
210
211 // Break all openers by removing all occurrences of '<?'.
212 while (strpos($copy, '<?') !== false) {
213 $copy = str_replace('<?', 'NEUTERED_', $copy);
214 }
215
216 return $copy;
217 }
218
219 /**
220 * Recursively breaks PHP opening tags from strings in arrays/objects using strip_php_tags().
221 *
222 * @package s2Member\Utilities
223 * @since 251002
224 *
225 * @param mixed $input A scalar, array, or object to sanitize.
226 * @return mixed The sanitized value with PHP opening tags removed from all scalar leaves.
227 */
228 public static function strip_php_tags_deep($input) {
229 if (is_array($input)) {
230 foreach ($input as $k => $v)
231 $input[$k] = self::strip_php_tags_deep($v);
232 return $input;
233 }
234 if (is_object($input)) {
235 foreach (get_object_vars($input) as $k => $v)
236 $input->$k = self::strip_php_tags_deep($v);
237 return $input;
238 }
239 return self::strip_php_tags($input);
240 }
241
242 /**
243 * Trims deeply; alias of ``trim_deep``.
244 *
245 * @package s2Member\Utilities
246 * @since 111106
247 *
248 * @see s2Member\Utilities\c_ws_plugin__s2member_utils_strings::trim_deep()
249 * @see http://php.net/manual/en/function.trim.php
250 *
251 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
252 * @param string|bool $chars Optional. Defaults to false, indicating the default trim chars ` \t\n\r\0\x0B`. Or, set to a specific string of chars.
253 * @param string|bool $extra_chars Optional. This is NOT possible with PHP alone, but here you can specify extra chars; in addition to ``$chars``.
254 *
255 * @return string|array Either the input string, or the input array; after all data is trimmed up according to arguments passed in.
256 */
257 public static function trim($value = '', $chars = FALSE, $extra_chars = FALSE)
258 {
259 return c_ws_plugin__s2member_utils_strings::trim_deep($value, $chars, $extra_chars);
260 }
261
262 /**
263 * Trims deeply; or use {@link s2Member\Utilities\c_ws_plugin__s2member_utils_strings::trim()}.
264 *
265 * @package s2Member\Utilities
266 * @since 3.5
267 *
268 * @see s2Member\Utilities\c_ws_plugin__s2member_utils_strings::trim()
269 * @see http://php.net/manual/en/function.trim.php
270 *
271 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
272 * @param string|bool $chars Optional. Defaults to false, indicating the default trim chars ` \t\n\r\0\x0B`. Or, set to a specific string of chars.
273 * @param string|bool $extra_chars Optional. This is NOT possible with PHP alone, but here you can specify extra chars; in addition to ``$chars``.
274 *
275 * @return string|array Either the input string, or the input array; after all data is trimmed up according to arguments passed in.
276 */
277 public static function trim_deep($value = '', $chars = FALSE, $extra_chars = FALSE)
278 {
279 $chars = (is_string($chars)) ? $chars : " \t\n\r\0\x0B";
280 $chars = (is_string($extra_chars)) ? $chars.$extra_chars : $chars;
281
282 if(is_array($value)) /* Handles all types of arrays.
283 Note, we do NOT use ``array_map()`` here, because multiple args to ``array_map()`` causes a loss of string keys.
284 For further details, see: <http://php.net/manual/en/function.array-map.php>. */
285 {
286 foreach($value as &$r) // Reference.
287 $r = c_ws_plugin__s2member_utils_strings::trim_deep($r, $chars);
288 return $value; // Return modified array.
289 }
290 return trim((string)$value, $chars);
291 }
292
293 /**
294 * Trims double quotes deeply.
295 *
296 * @package s2Member\Utilities
297 * @since 3.5
298 *
299 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
300 *
301 * @return string|array Either the input string, or the input array; after all data is trimmed up.
302 */
303 public static function trim_dq_deep($value = '')
304 {
305 return c_ws_plugin__s2member_utils_strings::trim_deep($value, FALSE, '"');
306 }
307
308 /**
309 * Trims single quotes deeply.
310 *
311 * @package s2Member\Utilities
312 * @since 111106
313 *
314 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
315 *
316 * @return string|array Either the input string, or the input array; after all data is trimmed up.
317 */
318 public static function trim_sq_deep($value = '')
319 {
320 return c_ws_plugin__s2member_utils_strings::trim_deep($value, FALSE, "'");
321 }
322
323 /**
324 * Trims double and single quotes deeply.
325 *
326 * @package s2Member\Utilities
327 * @since 111106
328 *
329 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
330 *
331 * @return string|array Either the input string, or the input array; after all data is trimmed up.
332 */
333 public static function trim_dsq_deep($value = '')
334 {
335 return c_ws_plugin__s2member_utils_strings::trim_deep($value, FALSE, "'".'"');
336 }
337
338 /**
339 * Trims all single/double quote entity variations deeply.
340 *
341 * This is useful on Shortcode attributes mangled by a Visual Editor.
342 *
343 * @package s2Member\Utilities
344 * @since 111011
345 *
346 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
347 *
348 * @return string|array Either the input string, or the input array; after all data is trimmed up.
349 */
350 public static function trim_qts_deep($value = '')
351 {
352 $qts = implode('|', array_keys(c_ws_plugin__s2member_utils_strings::$quote_entities_w_variations));
353
354 return is_array($value) ? array_map('c_ws_plugin__s2member_utils_strings::trim_qts_deep', $value) : preg_replace('/^(?:'.$qts.')+|(?:'.$qts.')+$/', '', (string)$value);
355 }
356
357 /**
358 * Trims HTML whitespace.
359 *
360 * This is useful on Shortcode content.
361 *
362 * @package s2Member\Utilities
363 * @since 140124
364 *
365 * @param string $string Input string to trim.
366 *
367 * @return string Output string with all HTML whitespace trimmed away.
368 */
369 public static function trim_html($string = '')
370 {
371 $whitespace = '&nbsp;|\<br\>|\<br\s*\/\>|\<p\>(?:&nbsp;)*\<\/p\>';
372 return preg_replace('/^(?:'.$whitespace.')+|(?:'.$whitespace.')+$/', '', (string)$string);
373 }
374
375 /**
376 * Wraps a string with the characters provided.
377 *
378 * This is useful when preparing an input array for ``c_ws_plugin__s2member_utils_arrays::in_regex_array()``.
379 *
380 * @package s2Member\Utilities
381 * @since 3.5
382 *
383 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
384 * @param string $beg Optional. A string value to wrap at the beginning of each value.
385 * @param string $end Optional. A string value to wrap at the ending of each value.
386 * @param bool $wrap_e Optional. Defaults to false. Should empty strings be wrapped too?
387 *
388 * @return string|array Either the input string, or the input array; after all data is wrapped up.
389 */
390 public static function wrap_deep($value = '', $beg = '', $end = '', $wrap_e = FALSE)
391 {
392 if(is_array($value)) /* Handles all types of arrays.
393 Note, we do NOT use ``array_map()`` here, because multiple args to ``array_map()`` causes a loss of string keys.
394 For further details, see: <http://php.net/manual/en/function.array-map.php>. */
395 {
396 foreach($value as &$r) // Reference.
397 $r = c_ws_plugin__s2member_utils_strings::wrap_deep($r, $beg, $end, $wrap_e);
398 return $value; // Return modified array.
399 }
400 return (strlen((string)$value) || $wrap_e) ? (string)$beg.(string)$value.(string)$end : (string)$value;
401 }
402
403 /**
404 * Escapes meta characters with ``preg_quote()`` deeply.
405 *
406 * @package s2Member\Utilities
407 * @since 110926
408 *
409 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
410 * @param string $delimiter Optional. If a delimiting character is specified, it will also be escaped via ``preg_quote()``.
411 *
412 * @return string|array Either the input string, or the input array; after all data is escaped with ``preg_quote()``.
413 */
414 public static function preg_quote_deep($value = '', $delimiter = '')
415 {
416 if(is_array($value)) /* Handles all types of arrays.
417 Note, we do NOT use ``array_map()`` here, because multiple args to ``array_map()`` causes a loss of string keys.
418 For further details, see: <http://php.net/manual/en/function.array-map.php>. */
419 {
420 foreach($value as &$r) // Reference.
421 $r = c_ws_plugin__s2member_utils_strings::preg_quote_deep($r, $delimiter);
422 return $value; // Return modified array.
423 }
424 return preg_quote((string)$value, (string)$delimiter);
425 }
426
427 /**
428 * Generates a random string with letters/numbers/symbols.
429 *
430 * @package s2Member\Utilities
431 * @since 3.5
432 *
433 * @param int $length Optional. Defaults to `12`. Length of the random string.
434 * @param bool $special_chars Defaults to true. If false, special chars are NOT included.
435 * @param bool $extra_special_chars Defaults to false. If true, extra special chars are included.
436 *
437 * @return string A randomly generated string, based on parameter configuration.
438 */
439 public static function random_str_gen($length = 0, $special_chars = TRUE, $extra_special_chars = FALSE)
440 {
441 $length = (is_numeric($length) && $length >= 0) ? (int)$length : 12;
442
443 $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
444 $chars .= ($extra_special_chars) ? '-_ []{}<>~`+=,.;:/?|' : '';
445 $chars .= ($special_chars) ? '!@#$%^&*()' : '';
446
447 for($i = 0, $random_str = ''; $i < $length; $i++)
448 $random_str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
449
450 return $random_str;
451 }
452
453 /**
454 * Highlights PHP, and also Shortcodes.
455 *
456 * @package s2Member\Utilities
457 * @since 3.5
458 *
459 * @param string $string Input string to be highlighted.
460 *
461 * @return string The highlighted string.
462 */
463 public static function highlight_php($string = '')
464 {
465 $string = highlight_string(trim((string)$string), TRUE); // Start with PHP syntax, then Shortcodes.
466 $string = preg_replace('/\[\/?_*s2[a-z0-9_\-]+.*?\]/i', '<span style="color:#164A61;">$0</span>', $string);
467 return str_replace('<code>', '<code class="highlight-php">', $string);
468 }
469
470 /**
471 * Parses email addresses from a string or array.
472 *
473 * @package s2Member\Utilities
474 * @since 111009
475 *
476 * @param string|array $value Input string or an array is also fine.
477 *
478 * @return array Array of parsed email addresses.
479 */
480 public static function parse_emails($value = '')
481 {
482 if(is_array($value)) /* Handles all types of arrays.
483 Note, we do NOT use ``array_map()`` here, because multiple args to ``array_map()`` causes a loss of string keys.
484 For further details, see: <http://php.net/manual/en/function.array-map.php>. */
485 {
486 $emails = array(); // Initialize array.
487 foreach($value as $v) // Loop through array.
488 $emails = array_merge($emails, c_ws_plugin__s2member_utils_strings::parse_emails($v));
489 return $emails; // Return array.
490 }
491 $delimiter = (strpos((string)$value, ';') !== FALSE) ? ';' : ',';
492 foreach(c_ws_plugin__s2member_utils_strings::trim_deep(preg_split('/'.preg_quote($delimiter, '/').'+/', (string)$value)) as $section)
493 {
494 if(preg_match('/\<(.+?)\>/', $section, $m) && strpos($m[1], '@') !== FALSE)
495 $emails[] = $m[1]; // Email inside <brackets>.
496
497 else if(strpos($section, '@') !== FALSE)
498 $emails[] = $section;
499 }
500 return (!empty($emails)) ? $emails : array();
501 }
502
503 /**
504 * Base64 URL-safe encoding.
505 *
506 * @package s2Member\Utilities
507 * @since 110913
508 *
509 * @param string $string Input string to be base64 encoded.
510 * @param array $url_unsafe_chars Optional. An array of un-safe characters. Defaults to: ``array('+', '/')``.
511 * @param array $url_safe_chars Optional. An array of safe character replacements. Defaults to: ``array('-', '_')``.
512 * @param string $trim_padding_chars Optional. A string of padding chars to rtrim. Defaults to: `=~.`.
513 *
514 * @return string The base64 URL-safe encoded string.
515 */
516 public static function base64_url_safe_encode($string = '', $url_unsafe_chars = array('+', '/'), $url_safe_chars = array('-', '_'), $trim_padding_chars = '=~.')
517 {
518 $string = (string)$string; // Force string values here. String MUST be a string.
519 $trim_padding_chars = (string)$trim_padding_chars; // And force this one too.
520
521 $base64_url_safe = str_replace((array)$url_unsafe_chars, (array)$url_safe_chars, (string)base64_encode($string));
522 $base64_url_safe = (strlen($trim_padding_chars)) ? rtrim($base64_url_safe, $trim_padding_chars) : $base64_url_safe;
523
524 return $base64_url_safe; // Base64 encoded, with URL-safe replacements.
525 }
526
527 /**
528 * Base64 URL-safe decoding.
529 *
530 * Note, this function is backward compatible with routines supplied by s2Member in the past;
531 * where padding characters were replaced with `~` or `.`, instead of being stripped completely.
532 *
533 * @package s2Member\Utilities
534 * @since 110913
535 *
536 * @param string $base64_url_safe Input string to be base64 decoded.
537 * @param array $url_unsafe_chars Optional. An array of un-safe character replacements. Defaults to: ``array('+', '/')``.
538 * @param array $url_safe_chars Optional. An array of safe characters. Defaults to: ``array('-', '_')``.
539 * @param string $trim_padding_chars Optional. A string of padding chars to rtrim. Defaults to: `=~.`.
540 *
541 * @return string The decoded string.
542 */
543 public static function base64_url_safe_decode($base64_url_safe = '', $url_unsafe_chars = array('+', '/'), $url_safe_chars = array('-', '_'), $trim_padding_chars = '=~.')
544 {
545 $base64_url_safe = (string)$base64_url_safe; // Force string values here. This MUST be a string.
546 $trim_padding_chars = (string)$trim_padding_chars; // And force this one too.
547
548 $string = (strlen($trim_padding_chars)) ? rtrim($base64_url_safe, $trim_padding_chars) : $base64_url_safe;
549 $string = (strlen($trim_padding_chars)) ? str_pad($string, strlen($string) % 4, '=', STR_PAD_RIGHT) : $string;
550 $string = (string)base64_decode(str_replace((array)$url_safe_chars, (array)$url_unsafe_chars, $string));
551
552 return $string; // Base64 decoded, with URL-safe replacements.
553 }
554
555 /**
556 * Generates an RSA-SHA1 signature.
557 *
558 * @package s2Member\Utilities
559 * @since 111017
560 *
561 * @param string $string Input string/data, to be signed by this routine.
562 * @param string $key The secret key that will be used in this signature.
563 *
564 * @return string|bool An RSA-SHA1 signature string, or false on failure.
565 */
566 public static function rsa_sha1_sign($string = '', $key = '')
567 {
568 $key = c_ws_plugin__s2member_utils_strings::_rsa_sha1_key_fix_wrappers((string)$key);
569
570 $signature = c_ws_plugin__s2member_utils_strings::_rsa_sha1_shell_sign((string)$string, (string)$key);
571
572 if(empty($signature) && stripos(PHP_OS, 'win') === 0 && file_exists(($openssl = 'c:\\openssl-win32\\bin\\openssl.exe')))
573 $signature = c_ws_plugin__s2member_utils_strings::_rsa_sha1_shell_sign((string)$string, (string)$key, $openssl);
574
575 if(empty($signature) && stripos(PHP_OS, 'win') === 0 && file_exists(($openssl = 'c:\\openssl-win64\\bin\\openssl.exe')))
576 $signature = c_ws_plugin__s2member_utils_strings::_rsa_sha1_shell_sign((string)$string, (string)$key, $openssl);
577
578 if(empty($signature) && function_exists('openssl_get_privatekey') && function_exists('openssl_sign') && is_resource($private_key = openssl_get_privatekey((string)$key)))
579 openssl_sign((string)$string, $signature, $private_key, OPENSSL_ALGO_SHA1).openssl_free_key($private_key);
580
581 if(empty($signature)) // Now, if we're still empty, trigger an error here.
582 trigger_error('s2Member was unable to generate an RSA-SHA1 signature.'.
583 ' Please make sure your installation of PHP is compiled with OpenSSL: `openssl_sign()`.'.
584 ' See: http://php.net/manual/en/function.openssl-sign.php', E_USER_ERROR);
585
586 return (!empty($signature)) ? $signature : FALSE;
587 }
588
589 /**
590 * Generates an RSA-SHA1 signature from the command line.
591 *
592 * Used by {@link s2Member\Utilities\c_ws_plugin__s2member_utils_strings::rsa_sha1_sign()}.
593 *
594 * @package s2Member\Utilities
595 * @since 111017
596 *
597 * @param string $string Input string/data, to be signed by this routine.
598 * @param string $key The secret key that will be used in this signature.
599 * @param string $openssl Optional. Defaults to `openssl`. Path to OpenSSL executable.
600 *
601 * @return string|bool An RSA-SHA1 signature string, or false on failure.
602 */
603 public static function _rsa_sha1_shell_sign($string = '', $key = '', $openssl = '')
604 {
605 if(function_exists('shell_exec') && ($esa = 'escapeshellarg') && ($openssl = (($openssl && is_string($openssl)) ? $openssl : 'openssl')) && ($temp_dir = c_ws_plugin__s2member_utils_dirs::get_temp_dir()))
606 {
607 file_put_contents(($string_file = $temp_dir.'/'.md5(uniqid('', TRUE).'rsa-sha1-string').'.tmp'), (string)$string);
608 file_put_contents(($private_key_file = $temp_dir.'/'.md5(uniqid('', TRUE).'rsa-sha1-private-key').'.tmp'), (string)$key);
609 file_put_contents(($rsa_sha1_sig_file = $temp_dir.'/'.md5(uniqid('', TRUE).'rsa-sha1-sig').'.tmp'), '');
610
611 @shell_exec($esa($openssl).' sha1 -sign '.$esa($private_key_file).' -out '.$esa($rsa_sha1_sig_file).' '.$esa($string_file));
612 $signature = file_get_contents($rsa_sha1_sig_file); // Do NOT trim here. Was the signature was written?
613 unlink($rsa_sha1_sig_file).unlink($private_key_file).unlink($string_file); // Cleanup.
614 }
615 return (!empty($signature)) ? $signature : FALSE;
616 }
617
618 /**
619 * Fixes incomplete private key wrappers for RSA-SHA1 signing.
620 *
621 * Used by {@link s2Member\Utilities\c_ws_plugin__s2member_utils_strings::rsa_sha1_sign()}.
622 *
623 * @package s2Member\Utilities
624 * @since 111017
625 *
626 * @param string $key The secret key to be used in an RSA-SHA1 signature.
627 *
628 * @return string Key with incomplete wrappers corrected, when/if possible.
629 *
630 * @see http://www.faqs.org/qa/qa-14736.html
631 */
632 public static function _rsa_sha1_key_fix_wrappers($key = '')
633 {
634 if(($key = trim((string)$key)) && (strpos($key, '-----BEGIN RSA PRIVATE KEY-----') === FALSE || strpos($key, '-----END RSA PRIVATE KEY-----') === FALSE))
635 {
636 foreach(($lines = c_ws_plugin__s2member_utils_strings::trim_deep(preg_split('/['."\r\n".']+/', $key))) as $line => $value)
637 if(strpos($value, '-') === 0) // Begins with a boundary identifying character ( a hyphen `-` )?
638 {
639 $boundaries = (empty($boundaries)) ? 1 : $boundaries + 1; // Counter.
640 unset($lines[$line]); // Remove this boundary line. We'll fix these below.
641 }
642 if(empty($boundaries) || $boundaries <= 2) // Do NOT modify keys with more than 2 boundaries.
643 $key = '-----BEGIN RSA PRIVATE KEY-----'."\n".implode("\n", $lines)."\n".'-----END RSA PRIVATE KEY-----';
644 }
645 return $key; // Always a trimmed string here.
646 }
647
648 /**
649 * Generates an HMAC-SHA1 signature.
650 *
651 * @package s2Member\Utilities
652 * @since 111017
653 *
654 * @param string $string Input string/data, to be signed by this routine.
655 * @param string $key The secret key that will be used in this signature.
656 *
657 * @return string An HMAC-SHA1 signature string.
658 */
659 public static function hmac_sha1_sign($string = '', $key = '')
660 {
661 $key_64 = str_pad(((strlen((string)$key) > 64) ? pack('H*', sha1((string)$key)) : (string)$key), 64, chr(0x00));
662
663 return pack('H*', sha1(($key_64 ^ str_repeat(chr(0x5c), 64)).pack('H*', sha1(($key_64 ^ str_repeat(chr(0x36), 64)).(string)$string))));
664 }
665
666 /**
667 * Generates an HMAC-SHA256 signature.
668 *
669 * @package s2Member\Utilities
670 * @since 111017
671 *
672 * @param string $string Input string/data, to be signed by this routine.
673 * @param string $key The secret key that will be used in this signature.
674 * @param boolean $binary Return binary format?
675 *
676 * @return string An HMAC-SHA256 signature string.
677 */
678 public static function hmac_sha256_sign($string = '', $key = '', $binary = FALSE)
679 {
680 return hash_hmac('sha256', $string, $key, $binary);
681 }
682
683 /**
684 * Decodes unreserved chars encoded by PHP's ``urlencode()``, deeply.
685 *
686 * For further details regarding unreserved chars, see: {@link http://www.faqs.org/rfcs/rfc3986.html}.
687 *
688 * @package s2Member\Utilities
689 * @since 111017
690 *
691 * @see http://www.faqs.org/rfcs/rfc3986.html
692 *
693 * @param string|array $value Either a string, an array, or a multi-dimensional array, filled with integer and/or string values.
694 *
695 * @return string|array Either the input string, or the input array; after all unreserved chars are decoded properly.
696 */
697 public static function urldecode_ur_chars_deep($value = array())
698 {
699 if(is_array($value)) /* Handles all types of arrays.
700 Note, we do NOT use ``array_map()`` here, because multiple args to ``array_map()`` causes a loss of string keys.
701 For further details, see: <http://php.net/manual/en/function.array-map.php>. */
702 {
703 foreach($value as &$r) // Reference.
704 $r = c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep($r);
705 return $value; // Return modified array.
706 }
707 return str_replace(array('%2D', '%2E', '%5F', '%7E'), array('-', '.', '_', '~'), (string)$value);
708 }
709
710 public static function like_escape($string)
711 {
712 global $wpdb; // Global DB object reference.
713
714 if(method_exists($wpdb, 'esc_like'))
715 return $wpdb->esc_like($string);
716
717 return like_escape($string); // Deprecated in WP v4.0.
718 }
719
720 public static function fill_cvs($string, $custom, $urlencode = false)
721 {
722 $string = (string)$string;
723 $custom = (string)$custom;
724
725 foreach (preg_split('/\|/', $custom) as $_key => $_value) {
726 $string = str_ireplace('%%cv'.$_key.'%%', $urlencode ? urlencode(trim($_value)) : trim($_value), $string);
727 } // unset($_key, $_value); // Housekeeping.
728
729 return $string;
730 }
731 }
732 }
733