From eebace5030fb313ff854264fdcefba797e4332c8 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 24 Jul 2018 19:30:15 +0200 Subject: [PATCH] console app draft --- Log/FileLogger.php | 8 +- Message/Console/Header.php | 270 +++++++++++++++++++++++++++++ Message/Console/Request.php | 10 +- Message/Console/Response.php | 193 +++++++++++++++++++++ Message/Http/Header.php | 10 +- Message/Http/Request.php | 8 +- Uri/Argument.php | 321 +++++++++++++++++++++++++++++++++++ Uri/Http.php | 10 +- 8 files changed, 806 insertions(+), 24 deletions(-) create mode 100644 Uri/Argument.php diff --git a/Log/FileLogger.php b/Log/FileLogger.php index ce84e89c4..d295f7eea 100644 --- a/Log/FileLogger.php +++ b/Log/FileLogger.php @@ -266,6 +266,10 @@ final class FileLogger implements LoggerInterface */ private function write(string $message) : void { + if ($this->verbose) { + echo $message, "\n"; + } + $this->createFile(); if (!\is_writable($this->path)) { return; @@ -280,10 +284,6 @@ final class FileLogger implements LoggerInterface \fclose($this->fp); $this->fp = false; } - - if ($this->verbose) { - echo $message, "\n"; - } } /** diff --git a/Message/Console/Header.php b/Message/Console/Header.php index e69de29bb..7b7d56c01 100644 --- a/Message/Console/Header.php +++ b/Message/Console/Header.php @@ -0,0 +1,270 @@ +set('Content-Type', 'text/html; charset=utf-8'); + parent::__construct(); + } + + /** + * Set header. + * + * @param string $key Header key (case insensitive) + * @param string $header Header value + * @param bool $overwrite Overwrite if already existing + * + * @return bool + * + * @since 1.0.0 + */ + public function set(string $key, string $header, bool $overwrite = false) : bool + { + if (self::$isLocked) { + return false; + } + + if (self::isSecurityHeader($key) && isset($this->header[$key])) { + return false; + } + + $key = strtolower($key); + + if (!$overwrite && isset($this->header[$key])) { + return false; + } + + unset($this->header[$key]); + + if (!isset($this->header[$key])) { + $this->header[$key] = []; + } + + $this->header[$key][] = $header; + + return true; + } + + /** + * Is security header. + * + * @param string $key Header key + * + * @return bool + * + * @since 1.0.0 + */ + public static function isSecurityHeader(string $key) : bool + { + $key = strtolower($key); + + return $key === 'content-security-policy' + || $key === 'x-xss-protection' + || $key === 'x-content-type-options' + || $key === 'x-frame-options'; + } + + /** + * {@inheritdoc} + */ + public function getProtocolVersion() : string + { + return self::VERSION; + } + + /** + * Get status code. + * + * @return int + * + * @since 1.0.0 + */ + public function getStatusCode() : int + { + if ($this->status === 0) { + $this->status = (int) \http_response_code(); + } + + return parent::getStatusCode(); + } + + /** + * Get all headers for apache and nginx + * + * @return array + * + * @since 1.0.0 + */ + public static function getAllHeaders() : array + { + if (function_exists('getallheaders')) { + // @codeCoverageIgnoreStart + return getallheaders(); + // @codeCoverageIgnoreEnd + } + + $headers = []; + foreach ($_SERVER as $name => $value) { + $part = \substr($name, 5); + if ($part === 'HTTP_') { + $headers[\str_replace(' ', '-', \ucwords(\strtolower(\str_replace('_', ' ', $part))))] = $value; + } + } + + return $headers; + } + + /** + * Remove header by ID. + * + * @param mixed $key Header key + * + * @return bool + * + * @since 1.0.0 + */ + public function remove($key) : bool + { + if (self::$isLocked) { + return false; + } + + if (isset($this->header[$key])) { + unset($this->header[$key]); + + return true; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function getReasonPhrase() : string + { + $phrases = $this->get('Status'); + + return empty($phrases) ? '' : $phrases[0]; + } + + /** + * Get header by name. + * + * @param string $key Header key + * + * @return array + * + * @since 1.0.0 + */ + public function get(string $key) : array + { + return $this->header[strtolower($key)] ?? []; + } + + /** + * Check if header is defined. + * + * @param string $key Header key + * + * @return bool + * + * @since 1.0.0 + */ + public function has(string $key) : bool + { + return isset($this->header[$key]); + } + + /** + * Push all headers. + * + * @return void + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function push() : void + { + if (self::$isLocked) { + throw new \Exception('Already locked'); + } + + foreach ($this->header as $name => $arr) { + foreach ($arr as $ele => $value) { + header($name . ': ' . $value); + } + } + } + + /** + * {@inheritdoc} + */ + public function generate(int $code) : void + { + switch ($code) { + default: + $this->generate500(); + } + } + + /** + * Generate predefined header. + * + * @return void + * + * @since 1.0.0 + */ + private function generate500() : void + { + } +} diff --git a/Message/Console/Request.php b/Message/Console/Request.php index a2d074f91..13777552b 100644 --- a/Message/Console/Request.php +++ b/Message/Console/Request.php @@ -18,6 +18,7 @@ use phpOMS\Localization\Localization; use phpOMS\Message\RequestAbstract; use phpOMS\Message\RequestSource; use phpOMS\Router\RouteVerb; +use phpOMS\Uri\UriInterface; /** * Request class. @@ -50,12 +51,9 @@ final class Request extends RequestAbstract public function __construct(UriInterface $uri, Localization $l11n = null) { $this->header = new Header(); + $this->header->setL11n($l11n ?? new Localization()); - if ($l11n === null) { - $l11n = $l11n ?? new Localization(); - } - - $this->header->setL11n($l11n); + $this->uri = $uri; } /** @@ -80,7 +78,7 @@ final class Request extends RequestAbstract $paths[] = $pathArray[$i]; } - $this->hash[] = sha1(implode('', $paths)); + $this->hash[] = sha1(\implode('', $paths)); } } diff --git a/Message/Console/Response.php b/Message/Console/Response.php index e69de29bb..94f26195b 100644 --- a/Message/Console/Response.php +++ b/Message/Console/Response.php @@ -0,0 +1,193 @@ +header = new Header(); + $this->header->setL11n($l11n ?? new Localization()); + } + + /** + * Set response. + * + * @param array $response Response to set + * + * @return void + * + * @since 1.0.0 + */ + public function setResponse(array $response) : void + { + $this->response = $response; + } + + /** + * Remove response by ID. + * + * @param mixed $id Response ID + * + * @return bool + * + * @since 1.0.0 + */ + public function remove($id) : bool + { + if (isset($this->response[$id])) { + unset($this->response[$id]); + + return true; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function getBody() : string + { + return $this->render(); + } + + /** + * Generate response based on header. + * + * @return string + * + * @since 1.0.0 + */ + public function render() : string + { + $types = $this->header->get('Content-Type'); + + foreach ($types as $type) { + if (\stripos($type, MimeType::M_JSON) !== false) { + return (string) \json_encode($this->jsonSerialize()); + } + } + + return $this->getRaw(); + } + + /** + * Generate raw response. + * + * @return string + * + * @throws \Exception + * + * @since 1.0.0 + */ + private function getRaw() : string + { + $render = ''; + + foreach ($this->response as $key => $response) { + if ($response instanceOf \Serializable) { + $render .= $response->serialize(); + } elseif (\is_string($response) || \is_numeric($response)) { + $render .= $response; + } else { + throw new \Exception('Wrong response type'); + } + } + + return $this->removeWhitespaceAndLineBreak($render); + } + + /** + * Remove whitespace and line break from render + * + * @param string $render Rendered string + * + * @return string + * + * @since 1.0.0 + */ + private function removeWhitespaceAndLineBreak(string $render) : string + { + $types = $this->header->get('Content-Type'); + if (\stripos($types[0], MimeType::M_HTML) !== false) { + return \trim(\preg_replace('/(\s{2,}|\n|\t)(?![^<>]*<\/pre>)/', ' ', $render)); + } + + return $render; + } + + /** + * {@inheritdoc} + */ + public function toArray() : array + { + $result = []; + + try { + foreach ($this->response as $key => $response) { + if ($response instanceof View) { + $result += $response->toArray(); + } elseif (\is_array($response)) { + $result += $response; + } elseif (\is_scalar($response)) { + $result[] = $response; + } elseif ($response instanceof \JsonSerializable) { + $result[] = $response->jsonSerialize(); + } elseif ($response === null) { + continue; + } else { + throw new \Exception('Wrong response type'); + } + } + } catch (\Exception $e) { + // todo: handle exception + // need to to try catch for logging. otherwise the json_encode in the logger will have a problem with this + $result = []; + } finally { + return $result; + } + } +} diff --git a/Message/Http/Header.php b/Message/Http/Header.php index 62d4fe803..69ea4ae11 100644 --- a/Message/Http/Header.php +++ b/Message/Http/Header.php @@ -70,7 +70,7 @@ final class Header extends HeaderAbstract return false; } - $key = strtolower($key); + $key = \strtolower($key); if (!$overwrite && isset($this->header[$key])) { return false; @@ -98,7 +98,7 @@ final class Header extends HeaderAbstract */ public static function isSecurityHeader(string $key) : bool { - $key = strtolower($key); + $key = \strtolower($key); return $key === 'content-security-policy' || $key === 'x-xss-protection' @@ -139,9 +139,9 @@ final class Header extends HeaderAbstract */ public static function getAllHeaders() : array { - if (function_exists('getallheaders')) { + if (\function_exists('getallheaders')) { // @codeCoverageIgnoreStart - return getallheaders(); + return \getallheaders(); // @codeCoverageIgnoreEnd } @@ -201,7 +201,7 @@ final class Header extends HeaderAbstract */ public function get(string $key) : array { - return $this->header[strtolower($key)] ?? []; + return $this->header[\strtolower($key)] ?? []; } /** diff --git a/Message/Http/Request.php b/Message/Http/Request.php index 8101a5efb..61114fd37 100644 --- a/Message/Http/Request.php +++ b/Message/Http/Request.php @@ -105,7 +105,7 @@ final class Request extends RequestAbstract $this->setupUriBuilder(); } - $this->data = array_change_key_case($this->data, CASE_LOWER); + $this->data = \array_change_key_case($this->data, CASE_LOWER); } /** @@ -249,7 +249,7 @@ final class Request extends RequestAbstract $paths[] = $pathArray[$i]; } - $this->hash[] = sha1(implode('', $paths)); + $this->hash[] = sha1(\implode('', $paths)); } } @@ -298,7 +298,7 @@ final class Request extends RequestAbstract $httpUserAgent = \strtolower($_SERVER['HTTP_USER_AGENT']); foreach ($arr as $key => $val) { - if (stripos($httpUserAgent, $val)) { + if (\stripos($httpUserAgent, $val)) { $this->browser = $val; return $this->browser; @@ -466,7 +466,7 @@ final class Request extends RequestAbstract { if ($this->getMethod() === RequestMethod::GET && !empty($this->data)) { return $this->uri->__toString() - . (parse_url($this->uri->__toString(), PHP_URL_QUERY) ? '&' : '?') + . (\parse_url($this->uri->__toString(), PHP_URL_QUERY) ? '&' : '?') . http_build_query($this->data); } diff --git a/Uri/Argument.php b/Uri/Argument.php new file mode 100644 index 000000000..bbd50c006 --- /dev/null +++ b/Uri/Argument.php @@ -0,0 +1,321 @@ +set($uri); + } + + /** + * {@inheritdoc} + */ + public function set(string $uri) : void + { + $this->uri = $uri; + } + + /** + * {@inheritdoc} + */ + public static function isValid(string $uri) : bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getRootPath() : string + { + return $this->rootPath; + } + + /** + * {@inheritdoc} + */ + public function setRootPath(string $root) : void + { + $this->rootPath = $root; + $this->set($this->uri); + } + + /** + * {@inheritdoc} + */ + public function getScheme() : string + { + return $this->scheme; + } + + /** + * {@inheritdoc} + */ + public function getHost() : string + { + return $this->host; + } + + /** + * {@inheritdoc} + */ + public function getPort() : int + { + return $this->port; + } + + /** + * {@inheritdoc} + */ + public function getPass() : string + { + return $this->pass; + } + + /** + * {@inheritdoc} + */ + public function getPath() : string + { + return $this->path; + } + + /** + * Get path offset. + * + * @return int + * + * @since 1.0.0 + */ + public function getPathOffset() : int + { + return \substr_count($this->rootPath, '/') - 1; + } + + /** + * {@inheritdoc} + */ + public function getRoute() : string + { + $query = $this->getQuery(); + return $this->path . (!empty($query) ? '?' . $this->getQuery() : ''); + } + + /** + * {@inheritdoc} + */ + public function getQuery(string $key = null) : string + { + if ($key !== null) { + $key = \strtolower($key); + + return $this->query[$key] ?? ''; + } + + return $this->queryString; + } + + /** + * {@inheritdoc} + */ + public function getPathElement(int $pos = null) : string + { + return explode('/', $this->path)[$pos] ?? ''; + } + + /** + * {@inheritdoc} + */ + public function getPathElements() : array + { + return explode('/', $this->path); + } + + /** + * {@inheritdoc} + */ + public function getQueryArray() : array + { + return $this->query; + } + + /** + * {@inheritdoc} + */ + public function getFragment() : string + { + return $this->fragment; + } + + /** + * {@inheritdoc} + */ + public function getBase() : string + { + return $this->base; + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return $this->uri; + } + + /** + * {@inheritdoc} + */ + public function getAuthority() : string + { + return ''; + } + + /** + * {@inheritdoc} + */ + public function getUser() : string + { + return $this->user; + } + + /** + * {@inheritdoc} + */ + public function getUserInfo() : string + { + return ''; + } +} diff --git a/Uri/Http.php b/Uri/Http.php index 79b47cccd..b9803d16f 100644 --- a/Uri/Http.php +++ b/Uri/Http.php @@ -195,7 +195,7 @@ final class Http implements UriInterface */ public static function isValid(string $uri) : bool { - return (bool) filter_var($uri, FILTER_VALIDATE_URL); + return (bool) \filter_var($uri, FILTER_VALIDATE_URL); } /** @@ -264,7 +264,7 @@ final class Http implements UriInterface */ public function getPathOffset() : int { - return substr_count($this->rootPath, '/') - 1; + return \substr_count($this->rootPath, '/') - 1; } /** @@ -282,7 +282,7 @@ final class Http implements UriInterface public function getQuery(string $key = null) : string { if ($key !== null) { - $key = strtolower($key); + $key = \strtolower($key); return $this->query[$key] ?? ''; } @@ -295,7 +295,7 @@ final class Http implements UriInterface */ public function getPathElement(int $pos = null) : string { - return explode('/', $this->path)[$pos] ?? ''; + return \explode('/', $this->path)[$pos] ?? ''; } /** @@ -303,7 +303,7 @@ final class Http implements UriInterface */ public function getPathElements() : array { - return explode('/', $this->path); + return \explode('/', $this->path); } /**