PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-waf / src / functions.php

functions.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-waf/src/functions.php

121 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Utility functions for WAF.
4 *
5 * @package automattic/jetpack-waf
6 */
7
8 namespace Automattic\Jetpack\Waf;
9
10 /**
11 * A wrapper for WordPress's `wp_unslash()`.
12 *
13 * Even though PHP itself dropped the option to add slashes to superglobals a decade ago,
14 * WordPress still does it through some misguided extreme backwards compatibility. 🙄
15 *
16 * If WordPress's function exists, assume it needs to be called. If not, assume it doesn't.
17 *
18 * @param string|array $value String or array of data to unslash.
19 * @return string|array Possibly unslashed $value.
20 */
21 function wp_unslash( $value ) {
22 if ( function_exists( '\\wp_unslash' ) ) {
23 return \wp_unslash( $value );
24 } else {
25 return $value;
26 }
27 }
28
29 /**
30 * PHP helpfully parses request data into nested arrays in superglobals like $_GET and $_POST,
31 * and as part of that parsing turns field names like "myfield[x][y]" into a nested array
32 * that looks like [ "myfield" => [ "x" => [ "y" => "..." ] ] ]
33 * However, modsecurity (and thus our WAF rules) expect the original (non-nested) names.
34 *
35 * Therefore, this method takes an array of any depth and returns a single-depth array with nested
36 * keys translated back to a single string with brackets.
37 *
38 * Because there might be multiple items with the same name, this function will return an array of tuples,
39 * with the first item in the tuple the re-created original field name, and the second item the value.
40 *
41 * @example
42 * flatten_array( [ "field1" => "abc", "field2" => [ "d", "e", "f" ] ] )
43 * => [
44 * [ "field1", "abc" ],
45 * [ "field2[0]", "d" ],
46 * [ "field2[1]", "e" ],
47 * [ "field2[2]", "f" ],
48 * ]
49 *
50 * @param array $array An array that resembles one of the PHP superglobals like $_GET or $_POST.
51 * @param string $key_prefix String that should be prepended to the keys output by this function.
52 * Usually only used internally as part of recursion when flattening a nested array.
53 * @param bool|null $dot_notation Whether to use dot notation instead of bracket notation.
54 *
55 * @return array{0: string, 1: scalar}[] $key_prefix An array of key/value tuples, one for each distinct value in the input array.
56 */
57 function flatten_array( $array, $key_prefix = '', $dot_notation = null ) {
58 $return = array();
59 foreach ( $array as $source_key => $source_value ) {
60 $key = $source_key;
61 if ( ! empty( $key_prefix ) ) {
62 $key = $dot_notation ? "$key_prefix.$source_key" : $key_prefix . "[$source_key]";
63 }
64
65 if ( ! is_array( $source_value ) ) {
66 $return[] = array( $key, $source_value );
67 } else {
68 $return = array_merge( $return, flatten_array( $source_value, $key, $dot_notation ) );
69 }
70 }
71 return $return;
72 }
73
74 /**
75 * Polyfill for getallheaders, which is not available in all PHP environments.
76 *
77 * @link https://github.com/ralouphie/getallheaders
78 */
79 if ( ! function_exists( 'getallheaders' ) ) {
80 /**
81 * Get all HTTP header key/values as an associative array for the current request.
82 *
83 * @return array The HTTP header key/value pairs.
84 */
85 function getallheaders() {
86 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
87 $headers = array();
88
89 $copy_server = array(
90 'CONTENT_TYPE' => 'Content-Type',
91 'CONTENT_LENGTH' => 'Content-Length',
92 'CONTENT_MD5' => 'Content-Md5',
93 );
94
95 foreach ( $_SERVER as $key => $value ) {
96 if ( substr( $key, 0, 5 ) === 'HTTP_' ) {
97 $key = substr( $key, 5 );
98 if ( ! isset( $copy_server[ $key ] ) || ! isset( $_SERVER[ $key ] ) ) {
99 $key = str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', $key ) ) ) );
100 $headers[ $key ] = $value;
101 }
102 } elseif ( isset( $copy_server[ $key ] ) ) {
103 $headers[ $copy_server[ $key ] ] = $value;
104 }
105 }
106
107 if ( ! isset( $headers['Authorization'] ) ) {
108 if ( isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) {
109 $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
110 } elseif ( isset( $_SERVER['PHP_AUTH_USER'] ) ) {
111 $basic_pass = $_SERVER['PHP_AUTH_PW'] ?? '';
112 $headers['Authorization'] = 'Basic ' . base64_encode( $_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass );
113 } elseif ( isset( $_SERVER['PHP_AUTH_DIGEST'] ) ) {
114 $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
115 }
116 }
117
118 return $headers;
119 }
120 }
121