str_ends_with()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 0
cts 0
cp 0
crap 6
rs 10
1
<?php
2
3
namespace kalanis\kw_input\Parsers;
4
5
6
/**
7
 * Class FixServer
8
 * @package kalanis\kw_input\Parsers
9
 * Fixes `$_SERVER` variables for various setups.
10
 * Got from Wordpress
11
 */
12
class FixServer
13
{
14
    /**
15
     * @param array<string|int, string|int|bool|null> $in
16
     * @return array<string|int, string|int|bool|null>
17
     */
18 18
    public static function updateVars(array $in): array
19
    {
20 18
        $default_server_values = array(
21 18
            'SERVER_SOFTWARE' => '',
22 18
            'REQUEST_URI' => '',
23 18
            'PATH_TRANSLATED' => '',
24 18
        );
25
26 18
        $in = array_merge($default_server_values, $in);
27
28
        // Fix for IIS when running with PHP ISAPI.
29
        if (
30 18
            empty($in['REQUEST_URI'])
31 18
            || ('cgi-fcgi' !== PHP_SAPI && preg_match('/^Microsoft-IIS\//', strval($in['SERVER_SOFTWARE'])))
32
        ) {
33
34 16
            if (isset($in['HTTP_X_ORIGINAL_URL'])) {
35
                // IIS Mod-Rewrite.
36 1
                $in['REQUEST_URI'] = $in['HTTP_X_ORIGINAL_URL'];
37 15
            } elseif (isset($in['HTTP_X_REWRITE_URL'])) {
38
                // IIS Isapi_Rewrite.
39 1
                $in['REQUEST_URI'] = $in['HTTP_X_REWRITE_URL'];
40
            } else {
41
                // Use ORIG_PATH_INFO if there is no PATH_INFO.
42 14
                if (!isset($in['PATH_INFO']) && isset($in['ORIG_PATH_INFO'])) {
43 1
                    $in['PATH_INFO'] = $in['ORIG_PATH_INFO'];
44
                }
45
46
                // Some IIS + PHP configurations put the script-name in the path-info (no need to append it twice).
47 14
                if (isset($in['PATH_INFO'])) {
48 7
                    if (isset($in['SCRIPT_NAME'])) {
49 4
                        if ($in['PATH_INFO'] === $in['SCRIPT_NAME']) {
50 1
                            $in['REQUEST_URI'] = $in['PATH_INFO'];
51
                        } else {
52 4
                            $in['REQUEST_URI'] = $in['SCRIPT_NAME'] . $in['PATH_INFO'];
53
                        }
54
                    } else {
55 3
                        $in['REQUEST_URI'] = $in['PATH_INFO'];
56
                    }
57
                }
58
59
                // Append the query string if it exists and isn't null.
60 14
                if (!empty($in['QUERY_STRING'])) {
61 1
                    $in['REQUEST_URI'] .= '?' . $in['QUERY_STRING'];
62
                }
63
            }
64
        }
65
66
        // Fix for PHP as CGI hosts that set SCRIPT_FILENAME to something ending in php.cgi for all requests.
67 18
        if (isset($in['SCRIPT_FILENAME']) && str_ends_with(strval($in['SCRIPT_FILENAME']), 'php.cgi')) {
68 1
            $in['SCRIPT_FILENAME'] = $in['PATH_TRANSLATED'];
69
        }
70
71
        // Fix for Dreamhost and other PHP as CGI hosts.
72 18
        if (isset($in['SCRIPT_NAME']) && str_contains(strval($in['SCRIPT_NAME']), 'php.cgi')) {
73 1
            unset($in['PATH_INFO']);
74
        }
75
76
        // Fix empty PHP_SELF.
77 18
        if (empty($in['PHP_SELF'])) {
78 12
            $in['PHP_SELF'] = preg_replace('/(\?.*)?$/', '', strval($in['REQUEST_URI']));
79
        }
80
81 18
        return $in;
82
    }
83
84
    /**
85
     * @param array<string|int, string|int|bool|null> $in
86
     * @return array<string|int, string|int|bool|null>
87
     */
88 10
    public static function updateAuth(array $in): array
89
    {
90
        // If we don't have anything to pull from, return early.
91 10
        if (!isset($in['HTTP_AUTHORIZATION']) && !isset($in['REDIRECT_HTTP_AUTHORIZATION'])) {
92 5
            return $in;
93
        }
94
95
        // If either PHP_AUTH key is already set, do nothing.
96 5
        if (isset($in['PHP_AUTH_USER']) || isset($in['PHP_AUTH_PW'])) {
97 1
            return $in;
98
        }
99
100
        // From our prior conditional, one of these must be set.
101 4
        $header = isset($in['HTTP_AUTHORIZATION'])
102 3
            ? $in['HTTP_AUTHORIZATION']
103 4
            : (isset($in['REDIRECT_HTTP_AUTHORIZATION']) ? $in['REDIRECT_HTTP_AUTHORIZATION'] : '');
104
105
        // Test to make sure the pattern matches expected.
106 4
        if (!preg_match('%^Basic [a-z\d/+]*={0,2}$%i', strval($header))) {
107 2
            return $in;
108
        }
109
110
        // Removing `Basic ` the token would start six characters in.
111 2
        $token = substr(strval($header), 6);
112 2
        $userpass = base64_decode($token);
113
114
        // There must be at least one colon in the string.
115 2
        if (!str_contains($userpass, ':')) {
116 1
            return $in;
117
        }
118
119 1
        list($user, $pass) = explode(':', $userpass, 2);
120
121
        // Now shove them in the proper keys where we're expecting later on.
122 1
        $in['PHP_AUTH_USER'] = $user;
123 1
        $in['PHP_AUTH_PW'] = $pass;
124
125 1
        return $in;
126
    }
127
}
128
129
130 1
if (!function_exists('str_contains')) {
131
    /**
132
     * Polyfill for `str_contains()` function added in PHP 8.0.
133
     *
134
     * Performs a case-sensitive check indicating if needle is
135
     * contained in haystack.
136
     *
137
     * @param string $haystack The string to search in.
138
     * @param string $needle The substring to search for in the `$haystack`.
139
     * @return bool True if `$needle` is in `$haystack`, otherwise false.
140
     * @codeCoverageIgnore php dependency
141
     */
142
    function str_contains($haystack, $needle)
143
    {
144
        if ('' === $needle) {
145
            return true;
146
        }
147
148
        return false !== strpos($haystack, $needle);
149
    }
150
}
151
152 1
if (!function_exists('str_starts_with')) {
153
    /**
154
     * Polyfill for `str_starts_with()` function added in PHP 8.0.
155
     *
156
     * Performs a case-sensitive check indicating if
157
     * the haystack begins with needle.
158
     *
159
     * @param string $haystack The string to search in.
160
     * @param string $needle The substring to search for in the `$haystack`.
161
     * @return bool True if `$haystack` starts with `$needle`, otherwise false.
162
     * @codeCoverageIgnore php dependency
163
     */
164
    function str_starts_with($haystack, $needle)
165
    {
166
        if ('' === $needle) {
167
            return true;
168
        }
169
170
        return 0 === strpos($haystack, $needle);
171
    }
172
}
173
174 1
if (!function_exists('str_ends_with')) {
175
    /**
176
     * Polyfill for `str_ends_with()` function added in PHP 8.0.
177
     *
178
     * Performs a case-sensitive check indicating if
179
     * the haystack ends with needle.
180
     *
181
     * @param string $haystack The string to search in.
182
     * @param string $needle The substring to search for in the `$haystack`.
183
     * @return bool True if `$haystack` ends with `$needle`, otherwise false.
184
     * @codeCoverageIgnore php dependency
185
     */
186
    function str_ends_with($haystack, $needle)
187
    {
188
        if ('' === $haystack) {
189
            return '' === $needle;
190
        }
191
192
        $len = strlen($needle);
193
194
        return substr($haystack, -$len, $len) === $needle;
195
    }
196
}
197