From 9cec38f916ae8678e0846109ac82a52ad1a7e714 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 28 Nov 2021 14:01:13 +0100 Subject: [PATCH] Make HTTPInputData dynamic - Removing DI:: dependency inside App class - Making testability easier & adapting tests --- index.php | 1 + src/App.php | 13 +++---- src/Util/HTTPInputData.php | 54 ++++++++++++++-------------- tests/Util/HTTPInputDataDouble.php | 34 +++++++----------- tests/src/Util/HTTPInputDataTest.php | 9 ++--- 5 files changed, 54 insertions(+), 57 deletions(-) diff --git a/index.php b/index.php index 95a1306b39..fa4c91aa36 100644 --- a/index.php +++ b/index.php @@ -45,5 +45,6 @@ $a->runFrontend( $dice->create(\Friendica\Core\PConfig\Capability\IManagePersonalConfigValues::class), $dice->create(\Friendica\Security\Authentication::class), $dice->create(\Friendica\App\Page::class), + new \Friendica\Util\HTTPInputData($_SERVER), $start_time ); diff --git a/src/App.php b/src/App.php index b8b7fb99fe..a17fb3ec38 100644 --- a/src/App.php +++ b/src/App.php @@ -44,7 +44,6 @@ use Friendica\Util\HTTPInputData; use Friendica\Util\HTTPSignature; use Friendica\Util\Profiler; use Friendica\Util\Strings; -use GuzzleHttp\Psr7\Response; use Psr\Log\LoggerInterface; /** @@ -563,13 +562,15 @@ class App * * @param App\Router $router * @param IManagePersonalConfigValues $pconfig - * @param Authentication $auth The Authentication backend of the node - * @param App\Page $page The Friendica page printing container + * @param Authentication $auth The Authentication backend of the node + * @param App\Page $page The Friendica page printing container + * @param HTTPInputData $httpInput A library for processing PHP input streams + * @param float $start_time The start time of the overall script execution * * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, float $start_time) + public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, HTTPInputData $httpInput, float $start_time) { $this->profiler->set($start_time, 'start'); $this->profiler->set(microtime(true), 'classinit'); @@ -704,8 +705,8 @@ class App } // Processes data from GET requests - $httpinput = HTTPInputData::process(); - $input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST); + $httpinput = $httpInput->process(); + $input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST); // Let the module run it's internal process (init, get, post, ...) $response = $module->run($input); diff --git a/src/Util/HTTPInputData.php b/src/Util/HTTPInputData.php index d22c3894d4..26d09c9772 100644 --- a/src/Util/HTTPInputData.php +++ b/src/Util/HTTPInputData.php @@ -27,9 +27,22 @@ namespace Friendica\Util; */ class HTTPInputData { - public static function process() + /** @var array The $_SERVER variable */ + protected $server; + + public function __construct(array $server) { - $content_parts = explode(';', static::getContentType()); + $this->server = $server; + } + + /** + * Process the PHP input stream and creates an array with its content + * + * @return array|array[] + */ + public function process(): array + { + $content_parts = explode(';', $this->server['CONTENT_TYPE'] ?? 'application/x-www-form-urlencoded'); $boundary = ''; $encoding = ''; @@ -54,7 +67,7 @@ class HTTPInputData } if ($content_type == 'multipart/form-data') { - return self::fetchFromMultipart($boundary); + return $this->fetchFromMultipart($boundary); } // can be handled by built in PHP functionality @@ -69,7 +82,7 @@ class HTTPInputData return ['variables' => $variables, 'files' => []]; } - private static function fetchFromMultipart(string $boundary) + private function fetchFromMultipart(string $boundary): array { $result = ['variables' => [], 'files' => []]; @@ -94,7 +107,7 @@ class HTTPInputData continue; } - $result = self::parseRawHeader($stream, $raw_headers, $boundary, $result); + $result = $this->parseRawHeader($stream, $raw_headers, $boundary, $result); $raw_headers = ''; } @@ -104,7 +117,7 @@ class HTTPInputData return $result; } - private static function parseRawHeader($stream, string $raw_headers, string $boundary, array $result) + private function parseRawHeader($stream, string $raw_headers, string $boundary, array $result) { $variables = $result['variables']; $files = $result['files']; @@ -115,7 +128,7 @@ class HTTPInputData if (strpos($header, ':') === false) { continue; } - list($name, $value) = explode(':', $header, 2); + [$name, $value] = explode(':', $header, 2); $headers[strtolower($name)] = ltrim($value, ' '); } @@ -135,13 +148,13 @@ class HTTPInputData $files[$name] = static::fetchFileData($stream, $boundary, $headers, $filename); return ['variables' => $variables, 'files' => $files]; } else { - $variables = self::fetchVariables($stream, $boundary, $headers, $name, $variables); + $variables = $this->fetchVariables($stream, $boundary, $headers, $name, $variables); } return ['variables' => $variables, 'files' => $files]; } - protected static function fetchFileData($stream, string $boundary, array $headers, string $filename) + protected function fetchFileData($stream, string $boundary, array $headers, string $filename) { $error = UPLOAD_ERR_OK; @@ -186,7 +199,7 @@ class HTTPInputData ]; } - private static function fetchVariables($stream, string $boundary, array $headers, string $name, array $variables) + private function fetchVariables($stream, string $boundary, array $headers, string $name, array $variables) { $fullValue = ''; $lastLine = null; @@ -229,10 +242,10 @@ class HTTPInputData $tmp = []; parse_str($fullValue, $tmp); - return self::expandVariables(explode('[', $name), $variables, $tmp); + return $this->expandVariables(explode('[', $name), $variables, $tmp); } - private static function expandVariables(array $names, $variables, array $values) + private function expandVariables(array $names, $variables, array $values) { if (!is_array($variables)) { return $values; @@ -252,7 +265,7 @@ class HTTPInputData if ($name === '') { $variables[] = reset($values); } elseif (isset($variables[$name]) && isset($values[$name])) { - $variables[$name] = self::expandVariables($names, $variables[$name], $values[$name]); + $variables[$name] = $this->expandVariables($names, $variables[$name], $values[$name]); } elseif (isset($values[$name])) { $variables[$name] = $values[$name]; } @@ -266,7 +279,7 @@ class HTTPInputData * * @return false|resource */ - protected static function getPhpInputStream() + protected function getPhpInputStream() { return fopen('php://input', 'rb'); } @@ -277,19 +290,8 @@ class HTTPInputData * * @return false|string */ - protected static function getPhpInputContent() + protected function getPhpInputContent() { return file_get_contents('php://input'); } - - /** - * Returns the content type string of the current call - * Mainly used for test doubling - * - * @return false|string - */ - protected static function getContentType() - { - return $_SERVER['CONTENT_TYPE'] ?? 'application/x-www-form-urlencoded'; - } } diff --git a/tests/Util/HTTPInputDataDouble.php b/tests/Util/HTTPInputDataDouble.php index 391b9c82bb..1675fa3923 100644 --- a/tests/Util/HTTPInputDataDouble.php +++ b/tests/Util/HTTPInputDataDouble.php @@ -30,20 +30,18 @@ use Friendica\Util\HTTPInputData; class HTTPInputDataDouble extends HTTPInputData { /** @var false|resource */ - protected static $injectedStream = false; + protected $injectedStream = false; /** @var false|string */ - protected static $injectedContent = false; - /** @var false|string */ - protected static $injectedContentType = false; + protected $injectedContent = false; /** * injects the PHP input stream for a test * * @param false|resource $stream */ - public static function setPhpInputStream($stream) + public function setPhpInputStream($stream) { - self::$injectedStream = $stream; + $this->injectedStream = $stream; } /** @@ -51,9 +49,9 @@ class HTTPInputDataDouble extends HTTPInputData * * @param false|string $content */ - public static function setPhpInputContent($content) + public function setPhpInputContent($content) { - self::$injectedContent = $content; + $this->injectedContent = $content; } /** @@ -61,30 +59,24 @@ class HTTPInputDataDouble extends HTTPInputData * * @param false|string $contentType */ - public static function setPhpInputContentType($contentType) + public function setPhpInputContentType($contentType) { - self::$injectedContentType = $contentType; + $this->injectedContentType = $contentType; } /** {@inheritDoc} */ - protected static function getPhpInputStream() + protected function getPhpInputStream() { - return static::$injectedStream; + return $this->injectedStream; } /** {@inheritDoc} */ - protected static function getPhpInputContent() + protected function getPhpInputContent() { - return static::$injectedContent; + return $this->injectedContent; } - /** {@inheritDoc} */ - protected static function getContentType() - { - return static::$injectedContentType; - } - - protected static function fetchFileData($stream, string $boundary, array $headers, string $filename) + protected function fetchFileData($stream, string $boundary, array $headers, string $filename) { $data = parent::fetchFileData($stream, $boundary, $headers, $filename); if (!empty($data['tmp_name'])) { diff --git a/tests/src/Util/HTTPInputDataTest.php b/tests/src/Util/HTTPInputDataTest.php index 5e8fd228fd..0d7c3938b5 100644 --- a/tests/src/Util/HTTPInputDataTest.php +++ b/tests/src/Util/HTTPInputDataTest.php @@ -139,14 +139,15 @@ class HTTPInputDataTest extends MockedTest */ public function testHttpInput(string $contentType, string $input, array $expected) { - HTTPInputDataDouble::setPhpInputContentType($contentType); - HTTPInputDataDouble::setPhpInputContent($input); + $httpInput = new HTTPInputDataDouble(['CONTENT_TYPE' => $contentType]); + $httpInput->setPhpInputContent($input); + $stream = fopen('php://memory', 'r+'); fwrite($stream, $input); rewind($stream); - HTTPInputDataDouble::setPhpInputStream($stream); - $output = HTTPInputDataDouble::process(); + $httpInput->setPhpInputStream($stream); + $output = $httpInput->process(); $this->assertEqualsCanonicalizing($expected, $output); } }