PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3-beta 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 All 507 releases
← All changes | jetpack_vendor/automattic/jetpack-waf/src/functions.php +120 -0 16.2-beta → 16.3-beta View file →
@@ -1,0 +1,120 @@
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 +}