bearsunday /
BEAR.Package
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace BEAR\Package\Provide\Router; |
||
| 6 | |||
| 7 | use BEAR\Package\Annotation\StdIn; |
||
| 8 | use BEAR\Package\Exception\InvalidRequestJsonException; |
||
| 9 | use BEAR\Package\Types; |
||
| 10 | use Override; |
||
| 11 | |||
| 12 | use function file_get_contents; |
||
| 13 | use function in_array; |
||
| 14 | use function json_decode; |
||
| 15 | use function json_last_error; |
||
| 16 | use function json_last_error_msg; |
||
| 17 | use function parse_str; |
||
| 18 | use function rtrim; |
||
| 19 | use function str_contains; |
||
| 20 | use function strtolower; |
||
| 21 | |||
| 22 | use const JSON_ERROR_NONE; |
||
| 23 | |||
| 24 | /** @psalm-import-type QueryParams from Types */ |
||
| 25 | final class HttpMethodParams implements HttpMethodParamsInterface |
||
| 26 | { |
||
| 27 | public const CONTENT_TYPE = 'CONTENT_TYPE'; |
||
| 28 | public const HTTP_CONTENT_TYPE = 'HTTP_CONTENT_TYPE'; |
||
| 29 | public const FORM_URL_ENCODE = 'application/x-www-form-urlencoded'; |
||
| 30 | public const APPLICATION_JSON = 'application/json'; |
||
| 31 | |||
| 32 | public function __construct( |
||
| 33 | #[StdIn] |
||
| 34 | private string $stdIn = 'php://input', |
||
| 35 | ) { |
||
| 36 | } |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @psalm-api |
||
| 40 | * @deprecated Use constructor injection |
||
| 41 | */ |
||
| 42 | public function setStdIn(string $stdIn): void |
||
| 43 | { |
||
| 44 | $this->stdIn = $stdIn; |
||
| 45 | } |
||
| 46 | |||
| 47 | /** |
||
| 48 | * {@inheritDoc} |
||
| 49 | */ |
||
| 50 | #[Override] |
||
| 51 | public function get(array $server, array $get, array $post) |
||
| 52 | { |
||
| 53 | // set the original value |
||
| 54 | $method = strtolower($server['REQUEST_METHOD']); |
||
| 55 | |||
| 56 | // early return on GET or HEAD |
||
| 57 | if ($method === 'get' || $method === 'head') { |
||
| 58 | return [$method, $get]; |
||
| 59 | } |
||
| 60 | |||
| 61 | return $this->unsafeMethod($method, $server, $post); |
||
| 62 | } |
||
| 63 | |||
| 64 | /** |
||
| 65 | * @param array{HTTP_X_HTTP_METHOD_OVERRIDE?: string, ...} $server |
||
| 66 | * @param QueryParams $post |
||
|
0 ignored issues
–
show
|
|||
| 67 | * |
||
| 68 | * @return array{0: string, 1: QueryParams} |
||
| 69 | */ |
||
| 70 | // phpcs:ignore Squiz.Commenting.FunctionComment.MissingParamName |
||
| 71 | private function unsafeMethod(string $method, array $server, array $post): array |
||
| 72 | { |
||
| 73 | /** @var array{_method?: string} $params */ |
||
| 74 | $params = $this->getParams($method, $server, $post); |
||
| 75 | |||
| 76 | if ($method === 'post') { |
||
| 77 | [$method, $params] = $this->getOverrideMethod($method, $server, $params); |
||
| 78 | } |
||
| 79 | |||
| 80 | return [$method, $params]; |
||
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * @param array{HTTP_X_HTTP_METHOD_OVERRIDE?: string, ...} $server |
||
| 85 | * @param array{_method?: string} $params |
||
| 86 | * |
||
| 87 | * @return array{0: string, 1: QueryParams} |
||
| 88 | */ |
||
| 89 | // phpcs:ignore Squiz.Commenting.FunctionComment.MissingParamName |
||
| 90 | private function getOverrideMethod(string $method, array $server, array $params): array |
||
| 91 | { |
||
| 92 | // must be a POST to do an override |
||
| 93 | |||
| 94 | // look for override in post data |
||
| 95 | if (isset($params['_method'])) { |
||
| 96 | $method = strtolower($params['_method']); |
||
| 97 | unset($params['_method']); |
||
| 98 | |||
| 99 | return [$method, $params]; |
||
| 100 | } |
||
| 101 | |||
| 102 | // look for override in headers |
||
| 103 | if (isset($server['HTTP_X_HTTP_METHOD_OVERRIDE'])) { |
||
| 104 | $method = strtolower($server['HTTP_X_HTTP_METHOD_OVERRIDE']); |
||
| 105 | } |
||
| 106 | |||
| 107 | return [$method, $params]; |
||
| 108 | } |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Return request parameters |
||
| 112 | * |
||
| 113 | * @param array{CONTENT_TYPE?: string, HTTP_CONTENT_TYPE?: string, ...} $server |
||
| 114 | * @param QueryParams $post |
||
| 115 | * |
||
| 116 | * @return QueryParams |
||
| 117 | */ |
||
| 118 | // phpcs:ignore Squiz.Commenting.FunctionComment.MissingParamName |
||
| 119 | private function getParams(string $method, array $server, array $post): array |
||
| 120 | { |
||
| 121 | // post data exists |
||
| 122 | if ($method === 'post' && ! empty($post)) { |
||
| 123 | return $post; |
||
|
0 ignored issues
–
show
|
|||
| 124 | } |
||
| 125 | |||
| 126 | if (in_array($method, ['post', 'put', 'patch', 'delete'], true)) { |
||
| 127 | return $this->phpInput($server); |
||
|
0 ignored issues
–
show
|
|||
| 128 | } |
||
| 129 | |||
| 130 | return $post; |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * Return request query by media-type |
||
| 135 | * |
||
| 136 | * @param array{CONTENT_TYPE?: string, HTTP_CONTENT_TYPE?: string, ...} $server $_SERVER |
||
| 137 | * |
||
| 138 | * @return QueryParams |
||
| 139 | */ |
||
| 140 | // phpcs:ignore Squiz.Commenting.FunctionComment.MissingParamName |
||
| 141 | private function phpInput(array $server): array |
||
| 142 | { |
||
| 143 | $contentType = $server[self::CONTENT_TYPE] ?? $server[self::HTTP_CONTENT_TYPE] ?? ''; |
||
| 144 | $isFormUrlEncoded = str_contains($contentType, self::FORM_URL_ENCODE); |
||
| 145 | if ($isFormUrlEncoded) { |
||
| 146 | parse_str(rtrim($this->getRawBody($server)), $put); |
||
| 147 | |||
| 148 | /** @var QueryParams $put */ |
||
| 149 | return $put; |
||
|
0 ignored issues
–
show
|
|||
| 150 | } |
||
| 151 | |||
| 152 | $isApplicationJson = str_contains($contentType, self::APPLICATION_JSON); |
||
| 153 | if (! $isApplicationJson) { |
||
| 154 | return []; |
||
|
0 ignored issues
–
show
|
|||
| 155 | } |
||
| 156 | |||
| 157 | /** @var QueryParams $content */ |
||
| 158 | $content = json_decode($this->getRawBody($server), true); |
||
| 159 | $error = json_last_error(); |
||
| 160 | if ($error !== JSON_ERROR_NONE) { |
||
| 161 | throw new InvalidRequestJsonException(json_last_error_msg()); |
||
| 162 | } |
||
| 163 | |||
| 164 | return $content; |
||
|
0 ignored issues
–
show
|
|||
| 165 | } |
||
| 166 | |||
| 167 | /** @param array{HTTP_RAW_POST_DATA?: string, ...} $server */ |
||
| 168 | // phpcs:ignore Squiz.Commenting.FunctionComment.MissingParamName |
||
| 169 | private function getRawBody(array $server): string |
||
| 170 | { |
||
| 171 | return $server['HTTP_RAW_POST_DATA'] ?? rtrim((string) file_get_contents($this->stdIn)); |
||
| 172 | } |
||
| 173 | } |
||
| 174 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths