From e94ba22e05c804e793c808cb1d2a8401564f3888 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Mon, 18 Mar 2019 11:37:28 -0400 Subject: [PATCH 01/14] [4.0.x] - Corrected return value for get --- phalcon/collection.zep | 2 +- phalcon/registry.zep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phalcon/collection.zep b/phalcon/collection.zep index d78a9a418f4..84026617276 100644 --- a/phalcon/collection.zep +++ b/phalcon/collection.zep @@ -91,7 +91,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS /** * Get the element from the collection */ - public function get(string! element, var defaultValue = null, bool insensitive = true) -> var | bool + public function get(string! element, var defaultValue = null, bool insensitive = true) -> var { var value; diff --git a/phalcon/registry.zep b/phalcon/registry.zep index 43154054025..1fc6bd0451b 100644 --- a/phalcon/registry.zep +++ b/phalcon/registry.zep @@ -125,7 +125,7 @@ final class Registry extends Collection /** * Get the element from the collection */ - public final function get(string! element, var defaultValue = null, bool insensitive = true) -> var | bool + public final function get(string! element, var defaultValue = null, bool insensitive = true) -> var { return parent::get(element, defaultValue, insensitive); } From db1cc032d6d870aed3418dfede9f6917e7b440a0 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Tue, 19 Mar 2019 20:25:36 -0400 Subject: [PATCH 02/14] [4.0.x] - Changed the constructor to use memory instead of temp --- phalcon/http/message/request.zep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index 0594a65cb37..bf55bcaa2ae 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -93,7 +93,7 @@ class Request implements RequestInterface /** * Constructor */ - public function __construct(string method = "GET", var uri = null, var body = "php://temp", array headers = []) + public function __construct(string method = "GET", var uri = null, var body = "php://memory", array headers = []) { if "php://input" === body { let body = new Input(); From 7afb7b27b32be0f9f7b3bffdca520156f4ccdd18 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Wed, 20 Mar 2019 18:28:47 -0400 Subject: [PATCH 03/14] [#13907] - Incorporated Collection to the Request --- phalcon/collection.zep | 8 +- phalcon/http/message/request.zep | 223 +++++++++++++------------------ 2 files changed, 98 insertions(+), 133 deletions(-) diff --git a/phalcon/collection.zep b/phalcon/collection.zep index 84026617276..a04e5cdab83 100644 --- a/phalcon/collection.zep +++ b/phalcon/collection.zep @@ -96,7 +96,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS var value; if likely insensitive { - let element = strtolower(element); + let element = element->lower(); } if likely fetch value, this->lowerKeys[element] { @@ -120,7 +120,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS public function has(string! element, bool insensitive = true) -> bool { if likely insensitive { - let element = strtolower(element); + let element = element->lower(); } return isset this->lowerKeys[element]; @@ -209,7 +209,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS if this->has(element) { if likely insensitive { - let element = strtolower(element); + let element = element->lower(); } let value = lowerKeys[element]; @@ -239,7 +239,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS { var key; - let key = strtolower(element); + let key = element->lower(); let this->data[element] = value, this->lowerKeys[key] = element; diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index bf55bcaa2ae..163c4684baf 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -14,6 +14,7 @@ namespace Phalcon\Http\Message; +use Phalcon\Collection; use Phalcon\Helper\Arr; use Phalcon\Http\Message\Stream\Input; use Phalcon\Http\Message\Uri; @@ -50,9 +51,9 @@ class Request implements RequestInterface private body { get }; /** - * @var array + * @var */ - private headers = []; + private headers; /** * Retrieves the HTTP method of the request. @@ -99,15 +100,10 @@ class Request implements RequestInterface let body = new Input(); } - this - ->processHeaders(headers) - ->processUri(uri); - - this->checkMethod(method); - - let - this->method = method, - this->body = this->processBody(body, "w+b"); + let this->headers = this->processHeaders(headers), + this->uri = this->processUri(uri), + this->method = this->processMethod(method), + this->body = this->processBody(body, "w+b"); } /** @@ -121,12 +117,7 @@ class Request implements RequestInterface */ public function getHeader(var name) -> array { - var element, key; - - let key = strtolower(name), - element = Arr::get(this->headers, key, []); - - return Arr::get(element, "value", []); + return this->headers->get(name, []); } /** @@ -179,16 +170,7 @@ class Request implements RequestInterface */ public function getHeaders() -> array { - var element, headers; - array headerData; - - let headers = this->headers, - headerData = []; - for element in headers { - let headerData[element["name"]] = element["value"]; - } - - return headerData; + return this->headers->toArray(); } /** @@ -227,7 +209,7 @@ class Request implements RequestInterface */ public function hasHeader(var name) -> bool { - return isset this->headers[strtolower(name)]; + return this->headers->has(name); } /** @@ -243,21 +225,16 @@ class Request implements RequestInterface */ public function withAddedHeader(var name, var value) -> { - var existing, headers, key; + var existing, headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, - existing = Arr::get(headers, key, []), - existing = Arr::get(existing, "value", []), + let headers = clone this->headers, + existing = headers->get(name, []), value = this->getHeaderValue(value), - existing = array_merge(existing, value); + value = array_merge(existing, value); - let headers[key] = [ - "name" : name, - "value" : existing - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -296,18 +273,14 @@ class Request implements RequestInterface */ public function withHeader(var name, var value) -> { - var headers, key; + var headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, + let headers = clone this->headers, value = this->getHeaderValue(value); - let headers[key] = [ - "name" : name, - "value" : value - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -327,7 +300,7 @@ class Request implements RequestInterface */ public function withMethod(var method) -> { - this->checkMethod(method); + this->processMethod(method); return this->cloneInstance(method, "method"); } @@ -344,7 +317,7 @@ class Request implements RequestInterface */ public function withProtocolVersion(var version) -> { - this->checkProtocol(version); + this->processProtocol(version); return this->cloneInstance(version, "protocolVersion"); } @@ -407,20 +380,17 @@ class Request implements RequestInterface var headers, host, newInstance; let preserveHost = (bool) preserveHost, - headers = this->headers, + headers = clone this->headers, newInstance = clone this, newInstance->uri = uri; if !(true === preserveHost && - true === this->hasHeader("Host") && + true === headers->has("Host") && "" !== uri->getHost()) { let host = this->getUriHost(uri); - let headers["host"] = [ - "name" : "Host", - "value" : [host] - ]; + headers->set("Host", [host]); let newInstance->headers = headers; } @@ -439,12 +409,11 @@ class Request implements RequestInterface */ public function withoutHeader(var name) -> { - var headers, key; + var headers; - let key = strtolower(name), - headers = this->headers; + let headers = clone this->headers; - unset headers[key]; + headers->remove(name); return this->cloneInstance(headers, "headers"); } @@ -454,7 +423,7 @@ class Request implements RequestInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - private function checkHeaderName(var name) -> void + internal function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -506,7 +475,7 @@ class Request implements RequestInterface * * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 */ - private function checkHeaderValue(var value) -> void + internal function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -520,61 +489,10 @@ class Request implements RequestInterface } } - /** - * Check the method - */ - private function checkMethod(var method = "") -> - { - array methods; - - let methods = [ - "GET" : 1, - "CONNECT" : 1, - "DELETE" : 1, - "HEAD" : 1, - "OPTIONS" : 1, - "PATCH" : 1, - "POST" : 1, - "PUT" : 1, - "TRACE" : 1 - ]; - - if !(!empty(method) && typeof method === "string" && isset methods[method]) { - throw new \InvalidArgumentException("Invalid or unsupported method " . method); - } - - return this; - } - - /** - * Checks the protocol - */ - private function checkProtocol(var protocol = "") -> - { - array protocols; - - let protocols = [ - "1.0" : 1, - "1.1" : 1, - "2.0" : 1, - "3.0" : 1 - ]; - - if (empty(protocol)) || typeof protocol !== "string" { - throw new \InvalidArgumentException("Invalid protocol value"); - } - - if !isset protocols[protocol] { - throw new \InvalidArgumentException("Unsupported protocol " . protocol); - } - - return this; - } - /** * Returns a new instance having set the parameter */ - private function cloneInstance(var element, string property) -> + internal function cloneInstance(var element, string property) -> { var newInstance; @@ -589,7 +507,7 @@ class Request implements RequestInterface /** * Returns the header values checked for validity */ - private function getHeaderValue(var values) -> array + internal function getHeaderValue(var values) -> array { var value; array valueData; @@ -616,7 +534,7 @@ class Request implements RequestInterface /** * Return the host and if applicable the port */ - private function getUriHost( uri) -> string + internal function getUriHost( uri) -> string { var host; @@ -631,7 +549,7 @@ class Request implements RequestInterface /** * Set a valid stream */ - private function processBody(var body = "php://memory", string mode = "r+b") -> + internal function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -647,43 +565,90 @@ class Request implements RequestInterface /** * Sets the headers */ - private function processHeaders(array headers) -> + internal function processHeaders(array headers) -> { - var key, name, value; - array headerData; + var collection, name, value; - let headerData = []; + let collection = new Collection(); for name, value in headers { this->checkHeaderName(name); - let key = strtolower(name), + let name = (string) name, value = this->getHeaderValue(value); - let headerData[key] = [ - "name" : name, - "value" : value - ]; + collection->set(name, value); } - let this->headers = headerData; + return collection; + } + + /** + * Check the method + */ + internal function processMethod(var method = "") -> string + { + array methods; + + let methods = [ + "GET" : 1, + "CONNECT" : 1, + "DELETE" : 1, + "HEAD" : 1, + "OPTIONS" : 1, + "PATCH" : 1, + "POST" : 1, + "PUT" : 1, + "TRACE" : 1 + ]; - return this; + if !(!empty(method) && typeof method === "string" && isset methods[method]) { + throw new \InvalidArgumentException("Invalid or unsupported method " . method); + } + + return method; + } + + /** + * Checks the protocol + */ + internal function processProtocol(var protocol = "") -> string + { + array protocols; + + let protocols = [ + "1.0" : 1, + "1.1" : 1, + "2.0" : 1, + "3.0" : 1 + ]; + + if (empty(protocol)) || typeof protocol !== "string" { + throw new \InvalidArgumentException("Invalid protocol value"); + } + + if !isset protocols[protocol] { + throw new \InvalidArgumentException("Unsupported protocol " . protocol); + } + + return protocol; } /** * Sets a valid Uri */ - private function processUri(var uri) -> + internal function processUri(var uri) -> { + var localUri; + if uri instanceof UriInterface { - let this->uri = uri; + let localUri = uri; } elseif typeof uri === "string" || null === uri { - let this->uri = new Uri(uri); + let localUri = new Uri(uri); } else { throw new \InvalidArgumentException("Invalid uri passed as a parameter"); } - return this; + return localUri; } } From 14f8fbaece9cf1a46f20d13965dfb58729673015 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Wed, 20 Mar 2019 19:41:12 -0400 Subject: [PATCH 04/14] [#13907] - Refactoring response --- phalcon/http/message/request.zep | 15 +-- phalcon/http/message/response.zep | 149 ++++++++++++------------------ 2 files changed, 66 insertions(+), 98 deletions(-) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index 163c4684baf..dea08e48ab2 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -15,7 +15,6 @@ namespace Phalcon\Http\Message; use Phalcon\Collection; -use Phalcon\Helper\Arr; use Phalcon\Http\Message\Stream\Input; use Phalcon\Http\Message\Uri; use Psr\Http\Message\RequestInterface; @@ -117,6 +116,8 @@ class Request implements RequestInterface */ public function getHeader(var name) -> array { + let name = (string) name; + return this->headers->get(name, []); } @@ -494,14 +495,14 @@ class Request implements RequestInterface */ internal function cloneInstance(var element, string property) -> { - var newInstance; + var newInstance; - let newInstance = clone this; + let newInstance = clone this; if element !== this->{property} { - let newInstance->{property} = element; - } + let newInstance->{property} = element; + } - return newInstance; + return newInstance; } /** @@ -623,7 +624,7 @@ class Request implements RequestInterface "3.0" : 1 ]; - if (empty(protocol)) || typeof protocol !== "string" { + if (empty(protocol)) || typeof protocol !== "string" { throw new \InvalidArgumentException("Invalid protocol value"); } diff --git a/phalcon/http/message/response.zep b/phalcon/http/message/response.zep index bdfce43a35d..0806470f191 100644 --- a/phalcon/http/message/response.zep +++ b/phalcon/http/message/response.zep @@ -14,7 +14,7 @@ namespace Phalcon\Http\Message; -use Phalcon\Helper\Arr; +use Phalcon\Collection; use Phalcon\Http\Message\Stream; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; @@ -44,9 +44,9 @@ class Response implements ResponseInterface private body { get }; /** - * @var array + * @var */ - private headers = []; + private headers; /** * Retrieves the HTTP protocol version as a string. @@ -88,11 +88,10 @@ class Response implements ResponseInterface */ public function __construct(var body = "php://memory", int code = 200, array headers = []) { - this - ->processHeaders(headers) - ->processCode(code); + this->processCode(code); - let this->body = this->processBody(body, "w+b"); + let this->headers = this->processHeaders(headers), + this->body = this->processBody(body, "w+b"); } /** @@ -106,12 +105,9 @@ class Response implements ResponseInterface */ public function getHeader(var name) -> array { - var element, key; + let name = (string) name; - let key = strtolower(name), - element = Arr::get(this->headers, key, []); - - return Arr::get(element, "value", []); + return this->headers->get(name, []); } /** @@ -164,16 +160,7 @@ class Response implements ResponseInterface */ public function getHeaders() -> array { - var element, headers; - array headerData; - - let headers = this->headers, - headerData = []; - for element in headers { - let headerData[element["name"]] = element["value"]; - } - - return headerData; + return this->headers->toArray(); } /** @@ -181,7 +168,7 @@ class Response implements ResponseInterface */ public function hasHeader(var name) -> bool { - return isset this->headers[strtolower(name)]; + return this->headers->has(name); } /** @@ -197,21 +184,16 @@ class Response implements ResponseInterface */ public function withAddedHeader(var name, var value) -> { - var existing, headers, key; + var existing, headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, - existing = Arr::get(headers, key, []), - existing = Arr::get(existing, "value", []), + let headers = clone this->headers, + existing = headers->get(name, []), value = this->getHeaderValue(value), - existing = array_merge(existing, value); + value = array_merge(existing, value); - let headers[key] = [ - "name" : name, - "value" : existing - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -250,18 +232,14 @@ class Response implements ResponseInterface */ public function withHeader(var name, var value) -> { - var headers, key; + var headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, + let headers = clone this->headers, value = this->getHeaderValue(value); - let headers[key] = [ - "name" : name, - "value" : value - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -278,7 +256,7 @@ class Response implements ResponseInterface */ public function withProtocolVersion(var version) -> { - this->checkProtocol(version); + this->processProtocol(version); return this->cloneInstance(version, "protocolVersion"); } @@ -301,10 +279,6 @@ class Response implements ResponseInterface { var newInstance; - if code === this->statusCode { - return this; - } - /** * Immutable - need to send a new object back */ @@ -326,12 +300,11 @@ class Response implements ResponseInterface */ public function withoutHeader(var name) -> { - var headers, key; + var headers; - let key = strtolower(name), - headers = this->headers; + let headers = clone this->headers; - unset headers[key]; + headers->remove(name); return this->cloneInstance(headers, "headers"); } @@ -341,7 +314,7 @@ class Response implements ResponseInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - private function checkHeaderName(var name) -> void + internal function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -391,7 +364,7 @@ class Response implements ResponseInterface * except where necessary to quote parentheses ["(" and ")"] and * backslash octets occurring within that comment. */ - private function checkHeaderValue(var value) -> void + internal function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -405,35 +378,10 @@ class Response implements ResponseInterface } } - /** - * Checks the protocol - */ - private function checkProtocol(var protocol = "") -> - { - array protocols; - - let protocols = [ - "1.0" : 1, - "1.1" : 1, - "2.0" : 1, - "3.0" : 1 - ]; - - if (empty(protocol)) || typeof protocol !== "string" { - throw new \InvalidArgumentException("Invalid protocol value"); - } - - if !isset protocols[protocol] { - throw new \InvalidArgumentException("Unsupported protocol " . protocol); - } - - return this; - } - /** * Returns a new instance having set the parameter */ - private function cloneInstance(var element, string property) -> + internal function cloneInstance(var element, string property) -> { var newInstance; @@ -448,7 +396,7 @@ class Response implements ResponseInterface /** * Returns the header values checked for validity */ - private function getHeaderValue(var values) -> array + internal function getHeaderValue(var values) -> array { var value; array valueData; @@ -475,7 +423,7 @@ class Response implements ResponseInterface /** * Returns the list of status codes available */ - private function getPhrases() -> array + internal function getPhrases() -> array { return [ 100 : "Continue", // Information - RFC 7231, 6.2.1 @@ -575,7 +523,7 @@ class Response implements ResponseInterface /** * Set a valid stream */ - private function processBody(var body = "php://memory", string mode = "r+b") -> + internal function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -621,27 +569,46 @@ class Response implements ResponseInterface /** * Sets the headers */ - private function processHeaders(array headers) -> + internal function processHeaders(array headers) -> { - var key, name, value; - array headerData; + var collection, name, value; - let headerData = []; + let collection = new Collection(); for name, value in headers { this->checkHeaderName(name); - let key = strtolower(name), + let name = (string) name, value = this->getHeaderValue(value); - let headerData[key] = [ - "name" : name, - "value" : value - ]; + collection->set(name, value); } - let this->headers = headerData; + return collection; + } + + /** + * Checks the protocol + */ + internal function processProtocol(var protocol = "") -> string + { + array protocols; + + let protocols = [ + "1.0" : 1, + "1.1" : 1, + "2.0" : 1, + "3.0" : 1 + ]; + + if (empty(protocol)) || typeof protocol !== "string" { + throw new \InvalidArgumentException("Invalid protocol value"); + } + + if !isset protocols[protocol] { + throw new \InvalidArgumentException("Unsupported protocol " . protocol); + } - return this; + return protocol; } } From a1fcbf72724b731ebd3e816b5b52ee4d478772ec Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 22 Mar 2019 13:06:29 -0400 Subject: [PATCH 05/14] [#13907] - Added Collection for headers and attributes --- phalcon/http/message/serverrequest.zep | 285 +++++++++++-------------- 1 file changed, 128 insertions(+), 157 deletions(-) diff --git a/phalcon/http/message/serverrequest.zep b/phalcon/http/message/serverrequest.zep index 42a3671daef..f96a44d703e 100644 --- a/phalcon/http/message/serverrequest.zep +++ b/phalcon/http/message/serverrequest.zep @@ -14,7 +14,7 @@ namespace Phalcon\Http\Message; -use Phalcon\Helper\Arr; +use Phalcon\Collection; use Phalcon\Http\Message\Stream\Input; use Phalcon\Http\Message\Uri; use Psr\Http\Message\MessageInterface; @@ -65,17 +65,9 @@ use Psr\Http\Message\UriInterface; class ServerRequest implements ServerRequestInterface { /** - * Retrieve attributes derived from the request. - * - * The request "attributes" may be used to allow injection of any - * parameters derived from the request: e.g., the results of path - * match operations; the results of decrypting cookies; the results of - * deserializing non-form-encoded message bodies; etc. Attributes - * will be application and request specific, and CAN be mutable. - * - * @var array + * @var */ - private attributes = [] { get }; + private attributes; /** * Gets the body of the message. @@ -97,9 +89,9 @@ class ServerRequest implements ServerRequestInterface private cookieParams = [] { get }; /** - * @var array + * @var */ - private headers = []; + private headers; /** * Retrieves the HTTP method of the request. @@ -211,24 +203,20 @@ class ServerRequest implements ServerRequestInterface let body = new Input(); } - this - ->processHeaders(headers) - ->processUri(uri); - - this - ->checkProtocol(protocol) - ->checkMethod(method) - ->checkUploadedFiles(uploadFiles); + this->checkUploadedFiles(uploadFiles); - let - this->protocolVersion = protocol, - this->method = method, - this->uploadedFiles = uploadFiles, + let this->protocolVersion = this->processProtocol(protocol), + this->method = this->processMethod(method), + this->headers = this->processHeaders(headers), + this->uri = this->processUri(uri), this->body = this->processBody(body, "w+b"), + this->uploadedFiles = uploadFiles, this->parsedBody = parsedBody, this->serverParams = serverParams, this->cookieParams = cookies, - this->queryParams = queryParams; + this->queryParams = queryParams, + this->attributes = new Collection() + ; } /** @@ -243,7 +231,21 @@ class ServerRequest implements ServerRequestInterface */ public function getAttribute(var name, var defaultValue = null) -> var { - return Arr::get(this->attributes, name, defaultValue); + return this->attributes->get(name, defaultValue); + } + + /** + * Retrieve attributes derived from the request. + * + * The request "attributes" may be used to allow injection of any + * parameters derived from the request: e.g., the results of path + * match operations; the results of decrypting cookies; the results of + * deserializing non-form-encoded message bodies; etc. Attributes + * will be application and request specific, and CAN be mutable. + */ + public function getAttributes() -> array + { + return this->attributes->toArray(); } /** @@ -257,12 +259,9 @@ class ServerRequest implements ServerRequestInterface */ public function getHeader(var name) -> array { - var element, key; - - let key = strtolower(name), - element = Arr::get(this->headers, key, []); + let name = (string) name; - return Arr::get(element, "value", []); + return this->headers->get(name, []); } /** @@ -315,16 +314,7 @@ class ServerRequest implements ServerRequestInterface */ public function getHeaders() -> array { - var element, headers; - array headerData; - - let headers = this->headers, - headerData = []; - for element in headers { - let headerData[element["name"]] = element["value"]; - } - - return headerData; + return this->headers->toArray(); } /** @@ -363,7 +353,7 @@ class ServerRequest implements ServerRequestInterface */ public function hasHeader(var name) -> bool { - return isset this->headers[strtolower(name)]; + return this->headers->has(name); } /** @@ -379,24 +369,18 @@ class ServerRequest implements ServerRequestInterface */ public function withAddedHeader(var name, var value) -> { - var existing, headers, key; + var existing, headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, - existing = Arr::get(headers, key, []), - existing = Arr::get(existing, "value", []), + let headers = clone this->headers, + existing = headers->get(name, []), value = this->getHeaderValue(value), - existing = array_merge(existing, value); + value = array_merge(existing, value); - let headers[key] = [ - "name" : name, - "value" : existing - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); - } /** @@ -413,8 +397,9 @@ class ServerRequest implements ServerRequestInterface { var attributes; - let attributes = this->attributes, - attributes[name] = value; + let attributes = clone this->attributes; + + attributes->set(name, value); return this->cloneInstance(attributes, "attributes"); } @@ -472,18 +457,14 @@ class ServerRequest implements ServerRequestInterface */ public function withHeader(var name, var value) -> { - var headers, key; + var headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, + let headers = clone this->headers, value = this->getHeaderValue(value); - let headers[key] = [ - "name" : name, - "value" : value - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -503,7 +484,7 @@ class ServerRequest implements ServerRequestInterface */ public function withMethod(var method) -> { - this->checkMethod(method); + this->processMethod(method); return this->cloneInstance(method, "method"); } @@ -550,7 +531,7 @@ class ServerRequest implements ServerRequestInterface */ public function withProtocolVersion(var version) -> { - this->checkProtocol(version); + this->processProtocol(version); return this->cloneInstance(version, "protocolVersion"); } @@ -652,17 +633,17 @@ class ServerRequest implements ServerRequestInterface var headers, host, newInstance; let preserveHost = (bool) preserveHost, - headers = this->headers, + headers = clone this->headers, newInstance = clone this, newInstance->uri = uri; - if !(preserveHost && true === this->hasHeader("Host") && "" !== uri->getHost()) { + if !(true === preserveHost && + true === headers->has("Host") && + "" !== uri->getHost()) { + let host = this->getUriHost(uri); - let headers["host"] = [ - "name" : "Host", - "value" : [host] - ]; + headers->set("Host", [host]); let newInstance->headers = headers; } @@ -684,9 +665,9 @@ class ServerRequest implements ServerRequestInterface { var attributes; - let attributes = this->attributes; + let attributes = clone this->attributes; - unset attributes[name]; + attributes->remove(name); return this->cloneInstance(attributes, "attributes"); } @@ -702,12 +683,11 @@ class ServerRequest implements ServerRequestInterface */ public function withoutHeader(var name) -> { - var headers, key; + var headers; - let key = strtolower(name), - headers = this->headers; + let headers = clone this->headers; - unset headers[key]; + headers->remove(name); return this->cloneInstance(headers, "headers"); } @@ -717,7 +697,7 @@ class ServerRequest implements ServerRequestInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - private function checkHeaderName(var name) -> void + internal function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -769,7 +749,7 @@ class ServerRequest implements ServerRequestInterface * * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 */ - private function checkHeaderValue(var value) -> void + internal function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -783,61 +763,10 @@ class ServerRequest implements ServerRequestInterface } } - /** - * Check the method - */ - private function checkMethod(var method = "") -> - { - array methods; - - let methods = [ - "GET" : 1, - "CONNECT" : 1, - "DELETE" : 1, - "HEAD" : 1, - "OPTIONS" : 1, - "PATCH" : 1, - "POST" : 1, - "PUT" : 1, - "TRACE" : 1 - ]; - - if !(!empty(method) && typeof method === "string" && isset methods[method]) { - throw new \InvalidArgumentException("Invalid or unsupported method " . method); - } - - return this; - } - - /** - * Checks the protocol - */ - private function checkProtocol(var protocol = "") -> - { - array protocols; - - let protocols = [ - "1.0" : 1, - "1.1" : 1, - "2.0" : 1, - "3.0" : 1 - ]; - - if (empty(protocol)) || typeof protocol !== "string" { - throw new \InvalidArgumentException("Invalid protocol value"); - } - - if !isset protocols[protocol] { - throw new \InvalidArgumentException("Unsupported protocol " . protocol); - } - - return this; - } - /** * Checks the uploaded files */ - private function checkUploadedFiles(array files) -> + internal function checkUploadedFiles(array files) -> void { var file; @@ -851,14 +780,12 @@ class ServerRequest implements ServerRequestInterface } } - - return this; } /** * Returns a new instance having set the parameter */ - private function cloneInstance(var element, string property) -> + internal function cloneInstance(var element, string property) -> { var newInstance; @@ -873,7 +800,7 @@ class ServerRequest implements ServerRequestInterface /** * Returns the header values checked for validity */ - private function getHeaderValue(var values) -> array + internal function getHeaderValue(var values) -> array { var value; array valueData; @@ -900,7 +827,7 @@ class ServerRequest implements ServerRequestInterface /** * Return the host and if applicable the port */ - private function getUriHost( uri) -> string + internal function getUriHost( uri) -> string { var host; @@ -915,7 +842,7 @@ class ServerRequest implements ServerRequestInterface /** * Set a valid stream */ - private function processBody(var body = "php://memory", string mode = "r+b") -> + internal function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -931,52 +858,96 @@ class ServerRequest implements ServerRequestInterface /** * Sets the headers */ - private function processHeaders(array headers) -> + internal function processHeaders(array headers) -> { - var host, key, name, value; - array headerData; + var collection, host, name, value; - let headerData = []; + let collection = new Collection(); for name, value in headers { this->checkHeaderName(name); - let key = strtolower(name), + let name = (string) name, value = this->getHeaderValue(value); - let headerData[key] = [ - "name" : name, - "value" : value - ]; + collection->set(name, value); } - if isset headerData["host"] && "" !== this->uri->getHost() { + if true === collection->has("host") && "" !== this->uri->getHost() { let host = this->getUriHost(this->uri); - let headerData["host"] = [ - "name" : "Host", - "value" : [host] - ]; + collection->set("Host", [host]); + } + + return collection; + } + + /** + * Check the method + */ + internal function processMethod(var method = "") -> string + { + array methods; + + let methods = [ + "GET" : 1, + "CONNECT" : 1, + "DELETE" : 1, + "HEAD" : 1, + "OPTIONS" : 1, + "PATCH" : 1, + "POST" : 1, + "PUT" : 1, + "TRACE" : 1 + ]; + + if !(!empty(method) && typeof method === "string" && isset methods[method]) { + throw new \InvalidArgumentException("Invalid or unsupported method " . method); + } + + return method; + } + + /** + * Checks the protocol + */ + internal function processProtocol(var protocol = "") -> string + { + array protocols; + + let protocols = [ + "1.0" : 1, + "1.1" : 1, + "2.0" : 1, + "3.0" : 1 + ]; + + if (empty(protocol)) || typeof protocol !== "string" { + throw new \InvalidArgumentException("Invalid protocol value"); } - let this->headers = headerData; + if !isset protocols[protocol] { + throw new \InvalidArgumentException("Unsupported protocol " . protocol); + } - return this; + return protocol; } /** * Sets a valid Uri */ - private function processUri(var uri) -> + internal function processUri(var uri) -> { + var localUri; + if uri instanceof UriInterface { - let this->uri = uri; + let localUri = uri; } elseif typeof uri === "string" || null === uri { - let this->uri = new Uri(uri); + let localUri = new Uri(uri); } else { throw new \InvalidArgumentException("Invalid uri passed as a parameter"); } - return this; + return localUri; } } From b3c2af4a8261fd3868eb4724c29cced57aab9640 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 22 Mar 2019 16:48:22 -0400 Subject: [PATCH 06/14] [#13907] - Added the ability to pass a collection object and array --- CHANGELOG-4.0.md | 1 + phalcon/http/message/request.zep | 34 +++++++++++++++++++------- phalcon/http/message/serverrequest.zep | 34 +++++++++++++++++--------- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/CHANGELOG-4.0.md b/CHANGELOG-4.0.md index 43dc16c6f12..b050efb57bd 100644 --- a/CHANGELOG-4.0.md +++ b/CHANGELOG-4.0.md @@ -23,6 +23,7 @@ The implementation offers PSR-7/PSR-17 compatible components in a different name - `Phalcon\Helper\Number` [#13889](https://github.com/phalcon/cphalcon/pull/13889) - Added `Phalcon\Collection`, an object implementing `ArrayAccess`, `Countable`, `IteratorAggregate`, `JsonSerializable`, `Serializable`, offering an easy way to handle collections of data such as arrays, superglobals etc. [#13886](https://github.com/phalcon/cphalcon/issues/13886) +- Added `Phalcon\Collection`, in `Phalcon\Http\Message\Request` and `Phalcon\Http\Message\ServerRequest` to handle the headers [#13907](https://github.com/phalcon/cphalcon/issues/13907) ## Fixed - Fixed Assets Manager hard reference to \Phalcon\Tag, should use DI [#12261](https://github.com/phalcon/cphalcon/issues/12261) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index dea08e48ab2..91ba0e57dfc 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -93,7 +93,7 @@ class Request implements RequestInterface /** * Constructor */ - public function __construct(string method = "GET", var uri = null, var body = "php://memory", array headers = []) + public function __construct(string method = "GET", var uri = null, var body = "php://memory", var headers = []) { if "php://input" === body { let body = new Input(); @@ -566,19 +566,35 @@ class Request implements RequestInterface /** * Sets the headers */ - internal function processHeaders(array headers) -> + internal function processHeaders(var headers) -> { - var collection, name, value; + var collection, host, name, value; - let collection = new Collection(); - for name, value in headers { + if typeof headers === "array" { + let collection = new Collection(); + for name, value in headers { - this->checkHeaderName(name); + this->checkHeaderName(name); - let name = (string) name, - value = this->getHeaderValue(value); + let name = (string) name, + value = this->getHeaderValue(value); - collection->set(name, value); + collection->set(name, value); + } + + if true === collection->has("host") && "" !== this->uri->getHost() { + let host = this->getUriHost(this->uri); + + collection->set("Host", [host]); + } + } else { + if headers instanceof Collection { + let collection = headers; + } else { + throw new \InvalidArgumentException( + "Headers needs to be either an array or instance of Phalcon\Collection" + ); + } } return collection; diff --git a/phalcon/http/message/serverrequest.zep b/phalcon/http/message/serverrequest.zep index f96a44d703e..7dbbaf59d92 100644 --- a/phalcon/http/message/serverrequest.zep +++ b/phalcon/http/message/serverrequest.zep @@ -191,7 +191,7 @@ class ServerRequest implements ServerRequestInterface var uri = null, array serverParams = [], var body = "php://input", - array headers = [], + var headers = [], array cookies = [], array queryParams = [], array uploadFiles = [], @@ -858,25 +858,35 @@ class ServerRequest implements ServerRequestInterface /** * Sets the headers */ - internal function processHeaders(array headers) -> + internal function processHeaders(var headers) -> { var collection, host, name, value; - let collection = new Collection(); - for name, value in headers { + if typeof headers === "array" { + let collection = new Collection(); + for name, value in headers { - this->checkHeaderName(name); + this->checkHeaderName(name); - let name = (string) name, - value = this->getHeaderValue(value); + let name = (string) name, + value = this->getHeaderValue(value); - collection->set(name, value); - } + collection->set(name, value); + } - if true === collection->has("host") && "" !== this->uri->getHost() { - let host = this->getUriHost(this->uri); + if true === collection->has("host") && "" !== this->uri->getHost() { + let host = this->getUriHost(this->uri); - collection->set("Host", [host]); + collection->set("Host", [host]); + } + } else { + if headers instanceof Collection { + let collection = headers; + } else { + throw new \InvalidArgumentException( + "Headers needs to be either an array or instance of Phalcon\Collection" + ); + } } return collection; From 45473a7944b39529c41552c8ce1250a4b1fd2fa4 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Mon, 18 Mar 2019 11:37:28 -0400 Subject: [PATCH 07/14] [4.0.x] - Corrected return value for get --- phalcon/collection.zep | 2 +- phalcon/registry.zep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phalcon/collection.zep b/phalcon/collection.zep index d78a9a418f4..84026617276 100644 --- a/phalcon/collection.zep +++ b/phalcon/collection.zep @@ -91,7 +91,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS /** * Get the element from the collection */ - public function get(string! element, var defaultValue = null, bool insensitive = true) -> var | bool + public function get(string! element, var defaultValue = null, bool insensitive = true) -> var { var value; diff --git a/phalcon/registry.zep b/phalcon/registry.zep index 43154054025..1fc6bd0451b 100644 --- a/phalcon/registry.zep +++ b/phalcon/registry.zep @@ -125,7 +125,7 @@ final class Registry extends Collection /** * Get the element from the collection */ - public final function get(string! element, var defaultValue = null, bool insensitive = true) -> var | bool + public final function get(string! element, var defaultValue = null, bool insensitive = true) -> var { return parent::get(element, defaultValue, insensitive); } From 5db486783f2eede53ff13f1410270c6c2d12fc00 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Tue, 19 Mar 2019 20:25:36 -0400 Subject: [PATCH 08/14] [4.0.x] - Changed the constructor to use memory instead of temp --- phalcon/http/message/request.zep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index 0594a65cb37..bf55bcaa2ae 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -93,7 +93,7 @@ class Request implements RequestInterface /** * Constructor */ - public function __construct(string method = "GET", var uri = null, var body = "php://temp", array headers = []) + public function __construct(string method = "GET", var uri = null, var body = "php://memory", array headers = []) { if "php://input" === body { let body = new Input(); From abca4ef378a6b3af1ac86b6dc90a51861d7b896d Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Wed, 20 Mar 2019 18:28:47 -0400 Subject: [PATCH 09/14] [#13907] - Incorporated Collection to the Request --- phalcon/collection.zep | 8 +- phalcon/http/message/request.zep | 223 +++++++++++++------------------ 2 files changed, 98 insertions(+), 133 deletions(-) diff --git a/phalcon/collection.zep b/phalcon/collection.zep index 84026617276..a04e5cdab83 100644 --- a/phalcon/collection.zep +++ b/phalcon/collection.zep @@ -96,7 +96,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS var value; if likely insensitive { - let element = strtolower(element); + let element = element->lower(); } if likely fetch value, this->lowerKeys[element] { @@ -120,7 +120,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS public function has(string! element, bool insensitive = true) -> bool { if likely insensitive { - let element = strtolower(element); + let element = element->lower(); } return isset this->lowerKeys[element]; @@ -209,7 +209,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS if this->has(element) { if likely insensitive { - let element = strtolower(element); + let element = element->lower(); } let value = lowerKeys[element]; @@ -239,7 +239,7 @@ class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonS { var key; - let key = strtolower(element); + let key = element->lower(); let this->data[element] = value, this->lowerKeys[key] = element; diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index bf55bcaa2ae..163c4684baf 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -14,6 +14,7 @@ namespace Phalcon\Http\Message; +use Phalcon\Collection; use Phalcon\Helper\Arr; use Phalcon\Http\Message\Stream\Input; use Phalcon\Http\Message\Uri; @@ -50,9 +51,9 @@ class Request implements RequestInterface private body { get }; /** - * @var array + * @var */ - private headers = []; + private headers; /** * Retrieves the HTTP method of the request. @@ -99,15 +100,10 @@ class Request implements RequestInterface let body = new Input(); } - this - ->processHeaders(headers) - ->processUri(uri); - - this->checkMethod(method); - - let - this->method = method, - this->body = this->processBody(body, "w+b"); + let this->headers = this->processHeaders(headers), + this->uri = this->processUri(uri), + this->method = this->processMethod(method), + this->body = this->processBody(body, "w+b"); } /** @@ -121,12 +117,7 @@ class Request implements RequestInterface */ public function getHeader(var name) -> array { - var element, key; - - let key = strtolower(name), - element = Arr::get(this->headers, key, []); - - return Arr::get(element, "value", []); + return this->headers->get(name, []); } /** @@ -179,16 +170,7 @@ class Request implements RequestInterface */ public function getHeaders() -> array { - var element, headers; - array headerData; - - let headers = this->headers, - headerData = []; - for element in headers { - let headerData[element["name"]] = element["value"]; - } - - return headerData; + return this->headers->toArray(); } /** @@ -227,7 +209,7 @@ class Request implements RequestInterface */ public function hasHeader(var name) -> bool { - return isset this->headers[strtolower(name)]; + return this->headers->has(name); } /** @@ -243,21 +225,16 @@ class Request implements RequestInterface */ public function withAddedHeader(var name, var value) -> { - var existing, headers, key; + var existing, headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, - existing = Arr::get(headers, key, []), - existing = Arr::get(existing, "value", []), + let headers = clone this->headers, + existing = headers->get(name, []), value = this->getHeaderValue(value), - existing = array_merge(existing, value); + value = array_merge(existing, value); - let headers[key] = [ - "name" : name, - "value" : existing - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -296,18 +273,14 @@ class Request implements RequestInterface */ public function withHeader(var name, var value) -> { - var headers, key; + var headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, + let headers = clone this->headers, value = this->getHeaderValue(value); - let headers[key] = [ - "name" : name, - "value" : value - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -327,7 +300,7 @@ class Request implements RequestInterface */ public function withMethod(var method) -> { - this->checkMethod(method); + this->processMethod(method); return this->cloneInstance(method, "method"); } @@ -344,7 +317,7 @@ class Request implements RequestInterface */ public function withProtocolVersion(var version) -> { - this->checkProtocol(version); + this->processProtocol(version); return this->cloneInstance(version, "protocolVersion"); } @@ -407,20 +380,17 @@ class Request implements RequestInterface var headers, host, newInstance; let preserveHost = (bool) preserveHost, - headers = this->headers, + headers = clone this->headers, newInstance = clone this, newInstance->uri = uri; if !(true === preserveHost && - true === this->hasHeader("Host") && + true === headers->has("Host") && "" !== uri->getHost()) { let host = this->getUriHost(uri); - let headers["host"] = [ - "name" : "Host", - "value" : [host] - ]; + headers->set("Host", [host]); let newInstance->headers = headers; } @@ -439,12 +409,11 @@ class Request implements RequestInterface */ public function withoutHeader(var name) -> { - var headers, key; + var headers; - let key = strtolower(name), - headers = this->headers; + let headers = clone this->headers; - unset headers[key]; + headers->remove(name); return this->cloneInstance(headers, "headers"); } @@ -454,7 +423,7 @@ class Request implements RequestInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - private function checkHeaderName(var name) -> void + internal function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -506,7 +475,7 @@ class Request implements RequestInterface * * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 */ - private function checkHeaderValue(var value) -> void + internal function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -520,61 +489,10 @@ class Request implements RequestInterface } } - /** - * Check the method - */ - private function checkMethod(var method = "") -> - { - array methods; - - let methods = [ - "GET" : 1, - "CONNECT" : 1, - "DELETE" : 1, - "HEAD" : 1, - "OPTIONS" : 1, - "PATCH" : 1, - "POST" : 1, - "PUT" : 1, - "TRACE" : 1 - ]; - - if !(!empty(method) && typeof method === "string" && isset methods[method]) { - throw new \InvalidArgumentException("Invalid or unsupported method " . method); - } - - return this; - } - - /** - * Checks the protocol - */ - private function checkProtocol(var protocol = "") -> - { - array protocols; - - let protocols = [ - "1.0" : 1, - "1.1" : 1, - "2.0" : 1, - "3.0" : 1 - ]; - - if (empty(protocol)) || typeof protocol !== "string" { - throw new \InvalidArgumentException("Invalid protocol value"); - } - - if !isset protocols[protocol] { - throw new \InvalidArgumentException("Unsupported protocol " . protocol); - } - - return this; - } - /** * Returns a new instance having set the parameter */ - private function cloneInstance(var element, string property) -> + internal function cloneInstance(var element, string property) -> { var newInstance; @@ -589,7 +507,7 @@ class Request implements RequestInterface /** * Returns the header values checked for validity */ - private function getHeaderValue(var values) -> array + internal function getHeaderValue(var values) -> array { var value; array valueData; @@ -616,7 +534,7 @@ class Request implements RequestInterface /** * Return the host and if applicable the port */ - private function getUriHost( uri) -> string + internal function getUriHost( uri) -> string { var host; @@ -631,7 +549,7 @@ class Request implements RequestInterface /** * Set a valid stream */ - private function processBody(var body = "php://memory", string mode = "r+b") -> + internal function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -647,43 +565,90 @@ class Request implements RequestInterface /** * Sets the headers */ - private function processHeaders(array headers) -> + internal function processHeaders(array headers) -> { - var key, name, value; - array headerData; + var collection, name, value; - let headerData = []; + let collection = new Collection(); for name, value in headers { this->checkHeaderName(name); - let key = strtolower(name), + let name = (string) name, value = this->getHeaderValue(value); - let headerData[key] = [ - "name" : name, - "value" : value - ]; + collection->set(name, value); } - let this->headers = headerData; + return collection; + } + + /** + * Check the method + */ + internal function processMethod(var method = "") -> string + { + array methods; + + let methods = [ + "GET" : 1, + "CONNECT" : 1, + "DELETE" : 1, + "HEAD" : 1, + "OPTIONS" : 1, + "PATCH" : 1, + "POST" : 1, + "PUT" : 1, + "TRACE" : 1 + ]; - return this; + if !(!empty(method) && typeof method === "string" && isset methods[method]) { + throw new \InvalidArgumentException("Invalid or unsupported method " . method); + } + + return method; + } + + /** + * Checks the protocol + */ + internal function processProtocol(var protocol = "") -> string + { + array protocols; + + let protocols = [ + "1.0" : 1, + "1.1" : 1, + "2.0" : 1, + "3.0" : 1 + ]; + + if (empty(protocol)) || typeof protocol !== "string" { + throw new \InvalidArgumentException("Invalid protocol value"); + } + + if !isset protocols[protocol] { + throw new \InvalidArgumentException("Unsupported protocol " . protocol); + } + + return protocol; } /** * Sets a valid Uri */ - private function processUri(var uri) -> + internal function processUri(var uri) -> { + var localUri; + if uri instanceof UriInterface { - let this->uri = uri; + let localUri = uri; } elseif typeof uri === "string" || null === uri { - let this->uri = new Uri(uri); + let localUri = new Uri(uri); } else { throw new \InvalidArgumentException("Invalid uri passed as a parameter"); } - return this; + return localUri; } } From 2a47231566538dbaaafa6291f3f75e2ab8c44429 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Wed, 20 Mar 2019 19:41:12 -0400 Subject: [PATCH 10/14] [#13907] - Refactoring response --- phalcon/http/message/request.zep | 15 +-- phalcon/http/message/response.zep | 149 ++++++++++++------------------ 2 files changed, 66 insertions(+), 98 deletions(-) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index 163c4684baf..dea08e48ab2 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -15,7 +15,6 @@ namespace Phalcon\Http\Message; use Phalcon\Collection; -use Phalcon\Helper\Arr; use Phalcon\Http\Message\Stream\Input; use Phalcon\Http\Message\Uri; use Psr\Http\Message\RequestInterface; @@ -117,6 +116,8 @@ class Request implements RequestInterface */ public function getHeader(var name) -> array { + let name = (string) name; + return this->headers->get(name, []); } @@ -494,14 +495,14 @@ class Request implements RequestInterface */ internal function cloneInstance(var element, string property) -> { - var newInstance; + var newInstance; - let newInstance = clone this; + let newInstance = clone this; if element !== this->{property} { - let newInstance->{property} = element; - } + let newInstance->{property} = element; + } - return newInstance; + return newInstance; } /** @@ -623,7 +624,7 @@ class Request implements RequestInterface "3.0" : 1 ]; - if (empty(protocol)) || typeof protocol !== "string" { + if (empty(protocol)) || typeof protocol !== "string" { throw new \InvalidArgumentException("Invalid protocol value"); } diff --git a/phalcon/http/message/response.zep b/phalcon/http/message/response.zep index bdfce43a35d..0806470f191 100644 --- a/phalcon/http/message/response.zep +++ b/phalcon/http/message/response.zep @@ -14,7 +14,7 @@ namespace Phalcon\Http\Message; -use Phalcon\Helper\Arr; +use Phalcon\Collection; use Phalcon\Http\Message\Stream; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; @@ -44,9 +44,9 @@ class Response implements ResponseInterface private body { get }; /** - * @var array + * @var */ - private headers = []; + private headers; /** * Retrieves the HTTP protocol version as a string. @@ -88,11 +88,10 @@ class Response implements ResponseInterface */ public function __construct(var body = "php://memory", int code = 200, array headers = []) { - this - ->processHeaders(headers) - ->processCode(code); + this->processCode(code); - let this->body = this->processBody(body, "w+b"); + let this->headers = this->processHeaders(headers), + this->body = this->processBody(body, "w+b"); } /** @@ -106,12 +105,9 @@ class Response implements ResponseInterface */ public function getHeader(var name) -> array { - var element, key; + let name = (string) name; - let key = strtolower(name), - element = Arr::get(this->headers, key, []); - - return Arr::get(element, "value", []); + return this->headers->get(name, []); } /** @@ -164,16 +160,7 @@ class Response implements ResponseInterface */ public function getHeaders() -> array { - var element, headers; - array headerData; - - let headers = this->headers, - headerData = []; - for element in headers { - let headerData[element["name"]] = element["value"]; - } - - return headerData; + return this->headers->toArray(); } /** @@ -181,7 +168,7 @@ class Response implements ResponseInterface */ public function hasHeader(var name) -> bool { - return isset this->headers[strtolower(name)]; + return this->headers->has(name); } /** @@ -197,21 +184,16 @@ class Response implements ResponseInterface */ public function withAddedHeader(var name, var value) -> { - var existing, headers, key; + var existing, headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, - existing = Arr::get(headers, key, []), - existing = Arr::get(existing, "value", []), + let headers = clone this->headers, + existing = headers->get(name, []), value = this->getHeaderValue(value), - existing = array_merge(existing, value); + value = array_merge(existing, value); - let headers[key] = [ - "name" : name, - "value" : existing - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -250,18 +232,14 @@ class Response implements ResponseInterface */ public function withHeader(var name, var value) -> { - var headers, key; + var headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, + let headers = clone this->headers, value = this->getHeaderValue(value); - let headers[key] = [ - "name" : name, - "value" : value - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -278,7 +256,7 @@ class Response implements ResponseInterface */ public function withProtocolVersion(var version) -> { - this->checkProtocol(version); + this->processProtocol(version); return this->cloneInstance(version, "protocolVersion"); } @@ -301,10 +279,6 @@ class Response implements ResponseInterface { var newInstance; - if code === this->statusCode { - return this; - } - /** * Immutable - need to send a new object back */ @@ -326,12 +300,11 @@ class Response implements ResponseInterface */ public function withoutHeader(var name) -> { - var headers, key; + var headers; - let key = strtolower(name), - headers = this->headers; + let headers = clone this->headers; - unset headers[key]; + headers->remove(name); return this->cloneInstance(headers, "headers"); } @@ -341,7 +314,7 @@ class Response implements ResponseInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - private function checkHeaderName(var name) -> void + internal function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -391,7 +364,7 @@ class Response implements ResponseInterface * except where necessary to quote parentheses ["(" and ")"] and * backslash octets occurring within that comment. */ - private function checkHeaderValue(var value) -> void + internal function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -405,35 +378,10 @@ class Response implements ResponseInterface } } - /** - * Checks the protocol - */ - private function checkProtocol(var protocol = "") -> - { - array protocols; - - let protocols = [ - "1.0" : 1, - "1.1" : 1, - "2.0" : 1, - "3.0" : 1 - ]; - - if (empty(protocol)) || typeof protocol !== "string" { - throw new \InvalidArgumentException("Invalid protocol value"); - } - - if !isset protocols[protocol] { - throw new \InvalidArgumentException("Unsupported protocol " . protocol); - } - - return this; - } - /** * Returns a new instance having set the parameter */ - private function cloneInstance(var element, string property) -> + internal function cloneInstance(var element, string property) -> { var newInstance; @@ -448,7 +396,7 @@ class Response implements ResponseInterface /** * Returns the header values checked for validity */ - private function getHeaderValue(var values) -> array + internal function getHeaderValue(var values) -> array { var value; array valueData; @@ -475,7 +423,7 @@ class Response implements ResponseInterface /** * Returns the list of status codes available */ - private function getPhrases() -> array + internal function getPhrases() -> array { return [ 100 : "Continue", // Information - RFC 7231, 6.2.1 @@ -575,7 +523,7 @@ class Response implements ResponseInterface /** * Set a valid stream */ - private function processBody(var body = "php://memory", string mode = "r+b") -> + internal function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -621,27 +569,46 @@ class Response implements ResponseInterface /** * Sets the headers */ - private function processHeaders(array headers) -> + internal function processHeaders(array headers) -> { - var key, name, value; - array headerData; + var collection, name, value; - let headerData = []; + let collection = new Collection(); for name, value in headers { this->checkHeaderName(name); - let key = strtolower(name), + let name = (string) name, value = this->getHeaderValue(value); - let headerData[key] = [ - "name" : name, - "value" : value - ]; + collection->set(name, value); } - let this->headers = headerData; + return collection; + } + + /** + * Checks the protocol + */ + internal function processProtocol(var protocol = "") -> string + { + array protocols; + + let protocols = [ + "1.0" : 1, + "1.1" : 1, + "2.0" : 1, + "3.0" : 1 + ]; + + if (empty(protocol)) || typeof protocol !== "string" { + throw new \InvalidArgumentException("Invalid protocol value"); + } + + if !isset protocols[protocol] { + throw new \InvalidArgumentException("Unsupported protocol " . protocol); + } - return this; + return protocol; } } From ae10bbfbee3e0b5cbdc56e100242a8488330c205 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 22 Mar 2019 13:06:29 -0400 Subject: [PATCH 11/14] [#13907] - Added Collection for headers and attributes --- phalcon/http/message/serverrequest.zep | 285 +++++++++++-------------- 1 file changed, 128 insertions(+), 157 deletions(-) diff --git a/phalcon/http/message/serverrequest.zep b/phalcon/http/message/serverrequest.zep index 42a3671daef..f96a44d703e 100644 --- a/phalcon/http/message/serverrequest.zep +++ b/phalcon/http/message/serverrequest.zep @@ -14,7 +14,7 @@ namespace Phalcon\Http\Message; -use Phalcon\Helper\Arr; +use Phalcon\Collection; use Phalcon\Http\Message\Stream\Input; use Phalcon\Http\Message\Uri; use Psr\Http\Message\MessageInterface; @@ -65,17 +65,9 @@ use Psr\Http\Message\UriInterface; class ServerRequest implements ServerRequestInterface { /** - * Retrieve attributes derived from the request. - * - * The request "attributes" may be used to allow injection of any - * parameters derived from the request: e.g., the results of path - * match operations; the results of decrypting cookies; the results of - * deserializing non-form-encoded message bodies; etc. Attributes - * will be application and request specific, and CAN be mutable. - * - * @var array + * @var */ - private attributes = [] { get }; + private attributes; /** * Gets the body of the message. @@ -97,9 +89,9 @@ class ServerRequest implements ServerRequestInterface private cookieParams = [] { get }; /** - * @var array + * @var */ - private headers = []; + private headers; /** * Retrieves the HTTP method of the request. @@ -211,24 +203,20 @@ class ServerRequest implements ServerRequestInterface let body = new Input(); } - this - ->processHeaders(headers) - ->processUri(uri); - - this - ->checkProtocol(protocol) - ->checkMethod(method) - ->checkUploadedFiles(uploadFiles); + this->checkUploadedFiles(uploadFiles); - let - this->protocolVersion = protocol, - this->method = method, - this->uploadedFiles = uploadFiles, + let this->protocolVersion = this->processProtocol(protocol), + this->method = this->processMethod(method), + this->headers = this->processHeaders(headers), + this->uri = this->processUri(uri), this->body = this->processBody(body, "w+b"), + this->uploadedFiles = uploadFiles, this->parsedBody = parsedBody, this->serverParams = serverParams, this->cookieParams = cookies, - this->queryParams = queryParams; + this->queryParams = queryParams, + this->attributes = new Collection() + ; } /** @@ -243,7 +231,21 @@ class ServerRequest implements ServerRequestInterface */ public function getAttribute(var name, var defaultValue = null) -> var { - return Arr::get(this->attributes, name, defaultValue); + return this->attributes->get(name, defaultValue); + } + + /** + * Retrieve attributes derived from the request. + * + * The request "attributes" may be used to allow injection of any + * parameters derived from the request: e.g., the results of path + * match operations; the results of decrypting cookies; the results of + * deserializing non-form-encoded message bodies; etc. Attributes + * will be application and request specific, and CAN be mutable. + */ + public function getAttributes() -> array + { + return this->attributes->toArray(); } /** @@ -257,12 +259,9 @@ class ServerRequest implements ServerRequestInterface */ public function getHeader(var name) -> array { - var element, key; - - let key = strtolower(name), - element = Arr::get(this->headers, key, []); + let name = (string) name; - return Arr::get(element, "value", []); + return this->headers->get(name, []); } /** @@ -315,16 +314,7 @@ class ServerRequest implements ServerRequestInterface */ public function getHeaders() -> array { - var element, headers; - array headerData; - - let headers = this->headers, - headerData = []; - for element in headers { - let headerData[element["name"]] = element["value"]; - } - - return headerData; + return this->headers->toArray(); } /** @@ -363,7 +353,7 @@ class ServerRequest implements ServerRequestInterface */ public function hasHeader(var name) -> bool { - return isset this->headers[strtolower(name)]; + return this->headers->has(name); } /** @@ -379,24 +369,18 @@ class ServerRequest implements ServerRequestInterface */ public function withAddedHeader(var name, var value) -> { - var existing, headers, key; + var existing, headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, - existing = Arr::get(headers, key, []), - existing = Arr::get(existing, "value", []), + let headers = clone this->headers, + existing = headers->get(name, []), value = this->getHeaderValue(value), - existing = array_merge(existing, value); + value = array_merge(existing, value); - let headers[key] = [ - "name" : name, - "value" : existing - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); - } /** @@ -413,8 +397,9 @@ class ServerRequest implements ServerRequestInterface { var attributes; - let attributes = this->attributes, - attributes[name] = value; + let attributes = clone this->attributes; + + attributes->set(name, value); return this->cloneInstance(attributes, "attributes"); } @@ -472,18 +457,14 @@ class ServerRequest implements ServerRequestInterface */ public function withHeader(var name, var value) -> { - var headers, key; + var headers; this->checkHeaderName(name); - let key = strtolower(name), - headers = this->headers, + let headers = clone this->headers, value = this->getHeaderValue(value); - let headers[key] = [ - "name" : name, - "value" : value - ]; + headers->set(name, value); return this->cloneInstance(headers, "headers"); } @@ -503,7 +484,7 @@ class ServerRequest implements ServerRequestInterface */ public function withMethod(var method) -> { - this->checkMethod(method); + this->processMethod(method); return this->cloneInstance(method, "method"); } @@ -550,7 +531,7 @@ class ServerRequest implements ServerRequestInterface */ public function withProtocolVersion(var version) -> { - this->checkProtocol(version); + this->processProtocol(version); return this->cloneInstance(version, "protocolVersion"); } @@ -652,17 +633,17 @@ class ServerRequest implements ServerRequestInterface var headers, host, newInstance; let preserveHost = (bool) preserveHost, - headers = this->headers, + headers = clone this->headers, newInstance = clone this, newInstance->uri = uri; - if !(preserveHost && true === this->hasHeader("Host") && "" !== uri->getHost()) { + if !(true === preserveHost && + true === headers->has("Host") && + "" !== uri->getHost()) { + let host = this->getUriHost(uri); - let headers["host"] = [ - "name" : "Host", - "value" : [host] - ]; + headers->set("Host", [host]); let newInstance->headers = headers; } @@ -684,9 +665,9 @@ class ServerRequest implements ServerRequestInterface { var attributes; - let attributes = this->attributes; + let attributes = clone this->attributes; - unset attributes[name]; + attributes->remove(name); return this->cloneInstance(attributes, "attributes"); } @@ -702,12 +683,11 @@ class ServerRequest implements ServerRequestInterface */ public function withoutHeader(var name) -> { - var headers, key; + var headers; - let key = strtolower(name), - headers = this->headers; + let headers = clone this->headers; - unset headers[key]; + headers->remove(name); return this->cloneInstance(headers, "headers"); } @@ -717,7 +697,7 @@ class ServerRequest implements ServerRequestInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - private function checkHeaderName(var name) -> void + internal function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -769,7 +749,7 @@ class ServerRequest implements ServerRequestInterface * * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 */ - private function checkHeaderValue(var value) -> void + internal function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -783,61 +763,10 @@ class ServerRequest implements ServerRequestInterface } } - /** - * Check the method - */ - private function checkMethod(var method = "") -> - { - array methods; - - let methods = [ - "GET" : 1, - "CONNECT" : 1, - "DELETE" : 1, - "HEAD" : 1, - "OPTIONS" : 1, - "PATCH" : 1, - "POST" : 1, - "PUT" : 1, - "TRACE" : 1 - ]; - - if !(!empty(method) && typeof method === "string" && isset methods[method]) { - throw new \InvalidArgumentException("Invalid or unsupported method " . method); - } - - return this; - } - - /** - * Checks the protocol - */ - private function checkProtocol(var protocol = "") -> - { - array protocols; - - let protocols = [ - "1.0" : 1, - "1.1" : 1, - "2.0" : 1, - "3.0" : 1 - ]; - - if (empty(protocol)) || typeof protocol !== "string" { - throw new \InvalidArgumentException("Invalid protocol value"); - } - - if !isset protocols[protocol] { - throw new \InvalidArgumentException("Unsupported protocol " . protocol); - } - - return this; - } - /** * Checks the uploaded files */ - private function checkUploadedFiles(array files) -> + internal function checkUploadedFiles(array files) -> void { var file; @@ -851,14 +780,12 @@ class ServerRequest implements ServerRequestInterface } } - - return this; } /** * Returns a new instance having set the parameter */ - private function cloneInstance(var element, string property) -> + internal function cloneInstance(var element, string property) -> { var newInstance; @@ -873,7 +800,7 @@ class ServerRequest implements ServerRequestInterface /** * Returns the header values checked for validity */ - private function getHeaderValue(var values) -> array + internal function getHeaderValue(var values) -> array { var value; array valueData; @@ -900,7 +827,7 @@ class ServerRequest implements ServerRequestInterface /** * Return the host and if applicable the port */ - private function getUriHost( uri) -> string + internal function getUriHost( uri) -> string { var host; @@ -915,7 +842,7 @@ class ServerRequest implements ServerRequestInterface /** * Set a valid stream */ - private function processBody(var body = "php://memory", string mode = "r+b") -> + internal function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -931,52 +858,96 @@ class ServerRequest implements ServerRequestInterface /** * Sets the headers */ - private function processHeaders(array headers) -> + internal function processHeaders(array headers) -> { - var host, key, name, value; - array headerData; + var collection, host, name, value; - let headerData = []; + let collection = new Collection(); for name, value in headers { this->checkHeaderName(name); - let key = strtolower(name), + let name = (string) name, value = this->getHeaderValue(value); - let headerData[key] = [ - "name" : name, - "value" : value - ]; + collection->set(name, value); } - if isset headerData["host"] && "" !== this->uri->getHost() { + if true === collection->has("host") && "" !== this->uri->getHost() { let host = this->getUriHost(this->uri); - let headerData["host"] = [ - "name" : "Host", - "value" : [host] - ]; + collection->set("Host", [host]); + } + + return collection; + } + + /** + * Check the method + */ + internal function processMethod(var method = "") -> string + { + array methods; + + let methods = [ + "GET" : 1, + "CONNECT" : 1, + "DELETE" : 1, + "HEAD" : 1, + "OPTIONS" : 1, + "PATCH" : 1, + "POST" : 1, + "PUT" : 1, + "TRACE" : 1 + ]; + + if !(!empty(method) && typeof method === "string" && isset methods[method]) { + throw new \InvalidArgumentException("Invalid or unsupported method " . method); + } + + return method; + } + + /** + * Checks the protocol + */ + internal function processProtocol(var protocol = "") -> string + { + array protocols; + + let protocols = [ + "1.0" : 1, + "1.1" : 1, + "2.0" : 1, + "3.0" : 1 + ]; + + if (empty(protocol)) || typeof protocol !== "string" { + throw new \InvalidArgumentException("Invalid protocol value"); } - let this->headers = headerData; + if !isset protocols[protocol] { + throw new \InvalidArgumentException("Unsupported protocol " . protocol); + } - return this; + return protocol; } /** * Sets a valid Uri */ - private function processUri(var uri) -> + internal function processUri(var uri) -> { + var localUri; + if uri instanceof UriInterface { - let this->uri = uri; + let localUri = uri; } elseif typeof uri === "string" || null === uri { - let this->uri = new Uri(uri); + let localUri = new Uri(uri); } else { throw new \InvalidArgumentException("Invalid uri passed as a parameter"); } - return this; + return localUri; } } From 18d88985520e634dc358709f0c2a17b9383526e7 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 22 Mar 2019 16:48:22 -0400 Subject: [PATCH 12/14] [#13907] - Added the ability to pass a collection object and array --- CHANGELOG-4.0.md | 1 + phalcon/http/message/request.zep | 34 +++++++++++++++++++------- phalcon/http/message/serverrequest.zep | 34 +++++++++++++++++--------- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/CHANGELOG-4.0.md b/CHANGELOG-4.0.md index 7f299f3c1de..ce547632104 100644 --- a/CHANGELOG-4.0.md +++ b/CHANGELOG-4.0.md @@ -23,6 +23,7 @@ The implementation offers PSR-7/PSR-17 compatible components in a different name - `Phalcon\Helper\Number` [#13889](https://github.com/phalcon/cphalcon/pull/13889) - Added `Phalcon\Collection`, an object implementing `ArrayAccess`, `Countable`, `IteratorAggregate`, `JsonSerializable`, `Serializable`, offering an easy way to handle collections of data such as arrays, superglobals etc. [#13886](https://github.com/phalcon/cphalcon/issues/13886) +- Added `Phalcon\Collection`, in `Phalcon\Http\Message\Request` and `Phalcon\Http\Message\ServerRequest` to handle the headers [#13907](https://github.com/phalcon/cphalcon/issues/13907) ## Fixed - Fixed `Phalcon\Image\Adapter\Imagick::_watermark`, `setImageAlpha()` fills the alpha channel with black before execution (replaced by `evaluateImage()`). Improved imagick compatibility. [#13911](https://github.com/phalcon/cphalcon/pull/13911) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index dea08e48ab2..91ba0e57dfc 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -93,7 +93,7 @@ class Request implements RequestInterface /** * Constructor */ - public function __construct(string method = "GET", var uri = null, var body = "php://memory", array headers = []) + public function __construct(string method = "GET", var uri = null, var body = "php://memory", var headers = []) { if "php://input" === body { let body = new Input(); @@ -566,19 +566,35 @@ class Request implements RequestInterface /** * Sets the headers */ - internal function processHeaders(array headers) -> + internal function processHeaders(var headers) -> { - var collection, name, value; + var collection, host, name, value; - let collection = new Collection(); - for name, value in headers { + if typeof headers === "array" { + let collection = new Collection(); + for name, value in headers { - this->checkHeaderName(name); + this->checkHeaderName(name); - let name = (string) name, - value = this->getHeaderValue(value); + let name = (string) name, + value = this->getHeaderValue(value); - collection->set(name, value); + collection->set(name, value); + } + + if true === collection->has("host") && "" !== this->uri->getHost() { + let host = this->getUriHost(this->uri); + + collection->set("Host", [host]); + } + } else { + if headers instanceof Collection { + let collection = headers; + } else { + throw new \InvalidArgumentException( + "Headers needs to be either an array or instance of Phalcon\Collection" + ); + } } return collection; diff --git a/phalcon/http/message/serverrequest.zep b/phalcon/http/message/serverrequest.zep index f96a44d703e..7dbbaf59d92 100644 --- a/phalcon/http/message/serverrequest.zep +++ b/phalcon/http/message/serverrequest.zep @@ -191,7 +191,7 @@ class ServerRequest implements ServerRequestInterface var uri = null, array serverParams = [], var body = "php://input", - array headers = [], + var headers = [], array cookies = [], array queryParams = [], array uploadFiles = [], @@ -858,25 +858,35 @@ class ServerRequest implements ServerRequestInterface /** * Sets the headers */ - internal function processHeaders(array headers) -> + internal function processHeaders(var headers) -> { var collection, host, name, value; - let collection = new Collection(); - for name, value in headers { + if typeof headers === "array" { + let collection = new Collection(); + for name, value in headers { - this->checkHeaderName(name); + this->checkHeaderName(name); - let name = (string) name, - value = this->getHeaderValue(value); + let name = (string) name, + value = this->getHeaderValue(value); - collection->set(name, value); - } + collection->set(name, value); + } - if true === collection->has("host") && "" !== this->uri->getHost() { - let host = this->getUriHost(this->uri); + if true === collection->has("host") && "" !== this->uri->getHost() { + let host = this->getUriHost(this->uri); - collection->set("Host", [host]); + collection->set("Host", [host]); + } + } else { + if headers instanceof Collection { + let collection = headers; + } else { + throw new \InvalidArgumentException( + "Headers needs to be either an array or instance of Phalcon\Collection" + ); + } } return collection; From 8bcc7e58eeab4a4b5a69d2c4270eba0e0a186b31 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 22 Mar 2019 17:22:44 -0400 Subject: [PATCH 13/14] [#13907] - Added more tests initializing headers with a collection --- .../Http/Message/Request/GetHeadersCest.php | 27 +++++++++++++++++++ .../Message/ServerRequest/GetHeadersCest.php | 27 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tests/unit/Http/Message/Request/GetHeadersCest.php b/tests/unit/Http/Message/Request/GetHeadersCest.php index 0a3865c56a0..817a3c62fe7 100644 --- a/tests/unit/Http/Message/Request/GetHeadersCest.php +++ b/tests/unit/Http/Message/Request/GetHeadersCest.php @@ -12,6 +12,7 @@ namespace Phalcon\Test\Unit\Http\Message\Request; +use Phalcon\Collection; use Phalcon\Http\Message\Request; use UnitTester; @@ -45,6 +46,32 @@ public function httpMessageRequestGetHeaders(UnitTester $I) $I->assertEquals($expected, $actual); } + /** + * Tests Phalcon\Http\Message\Request :: getHeaders() - collection + * + * @param UnitTester $I + * + * @author Phalcon Team + * @since 2019-02-10 + */ + public function httpMessageRequestGetHeadersCollection(UnitTester $I) + { + $I->wantToTest('Http\Message\Request - getHeaders()'); + $data = [ + 'Cache-Control' => ['max-age=0'], + 'Accept' => ['text/html'], + ]; + $headers = new Collection($data); + $request = new Request('GET', null, 'php://memory', $headers); + + $expected = [ + 'Accept' => ['text/html'], + 'Cache-Control' => ['max-age=0'], + ]; + $actual = $request->getHeaders(); + $I->assertEquals($expected, $actual); + } + /** * Tests Phalcon\Http\Message\Request :: getHeaders() - empty * diff --git a/tests/unit/Http/Message/ServerRequest/GetHeadersCest.php b/tests/unit/Http/Message/ServerRequest/GetHeadersCest.php index afd568e5fe2..36913966e0b 100644 --- a/tests/unit/Http/Message/ServerRequest/GetHeadersCest.php +++ b/tests/unit/Http/Message/ServerRequest/GetHeadersCest.php @@ -12,6 +12,7 @@ namespace Phalcon\Test\Unit\Http\Message\ServerRequest; +use Phalcon\Collection; use Phalcon\Http\Message\ServerRequest; use UnitTester; @@ -45,6 +46,32 @@ public function httpMessageServerRequestGetHeaders(UnitTester $I) $I->assertEquals($expected, $actual); } + /** + * Tests Phalcon\Http\Message\ServerRequest :: getHeaders() - collection + * + * @param UnitTester $I + * + * @author Phalcon Team + * @since 2019-02-10 + */ + public function httpMessageServerRequestGetHeadersCollection(UnitTester $I) + { + $I->wantToTest('Http\Message\ServerRequest - getHeaders() - collection'); + $data = [ + 'Cache-Control' => ['max-age=0'], + 'Accept' => ['text/html'], + ]; + $headers = new Collection($data); + $request = new ServerRequest('GET', null, [], 'php://input', $headers); + + $expected = [ + 'Accept' => ['text/html'], + 'Cache-Control' => ['max-age=0'], + ]; + $actual = $request->getHeaders(); + $I->assertEquals($expected, $actual); + } + /** * Tests Phalcon\Http\Message\ServerRequest :: getHeaders() - empty * From c5f8b4989988a0c7444ebf1f00e3e0855c1c11c9 Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 22 Mar 2019 17:31:55 -0400 Subject: [PATCH 14/14] [#13907] - Changing internal to private to check the Windows build --- phalcon/http/message/request.zep | 20 ++++++++++---------- phalcon/http/message/response.zep | 16 ++++++++-------- phalcon/http/message/serverrequest.zep | 24 ++++++++++++------------ 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/phalcon/http/message/request.zep b/phalcon/http/message/request.zep index 91ba0e57dfc..ef85275b557 100644 --- a/phalcon/http/message/request.zep +++ b/phalcon/http/message/request.zep @@ -424,7 +424,7 @@ class Request implements RequestInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - internal function checkHeaderName(var name) -> void + private function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -476,7 +476,7 @@ class Request implements RequestInterface * * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 */ - internal function checkHeaderValue(var value) -> void + private function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -493,7 +493,7 @@ class Request implements RequestInterface /** * Returns a new instance having set the parameter */ - internal function cloneInstance(var element, string property) -> + private function cloneInstance(var element, string property) -> { var newInstance; @@ -508,7 +508,7 @@ class Request implements RequestInterface /** * Returns the header values checked for validity */ - internal function getHeaderValue(var values) -> array + private function getHeaderValue(var values) -> array { var value; array valueData; @@ -535,7 +535,7 @@ class Request implements RequestInterface /** * Return the host and if applicable the port */ - internal function getUriHost( uri) -> string + private function getUriHost( uri) -> string { var host; @@ -550,7 +550,7 @@ class Request implements RequestInterface /** * Set a valid stream */ - internal function processBody(var body = "php://memory", string mode = "r+b") -> + private function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -566,7 +566,7 @@ class Request implements RequestInterface /** * Sets the headers */ - internal function processHeaders(var headers) -> + private function processHeaders(var headers) -> { var collection, host, name, value; @@ -603,7 +603,7 @@ class Request implements RequestInterface /** * Check the method */ - internal function processMethod(var method = "") -> string + private function processMethod(var method = "") -> string { array methods; @@ -629,7 +629,7 @@ class Request implements RequestInterface /** * Checks the protocol */ - internal function processProtocol(var protocol = "") -> string + private function processProtocol(var protocol = "") -> string { array protocols; @@ -654,7 +654,7 @@ class Request implements RequestInterface /** * Sets a valid Uri */ - internal function processUri(var uri) -> + private function processUri(var uri) -> { var localUri; diff --git a/phalcon/http/message/response.zep b/phalcon/http/message/response.zep index 0806470f191..eade144a0fc 100644 --- a/phalcon/http/message/response.zep +++ b/phalcon/http/message/response.zep @@ -314,7 +314,7 @@ class Response implements ResponseInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - internal function checkHeaderName(var name) -> void + private function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -364,7 +364,7 @@ class Response implements ResponseInterface * except where necessary to quote parentheses ["(" and ")"] and * backslash octets occurring within that comment. */ - internal function checkHeaderValue(var value) -> void + private function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -381,7 +381,7 @@ class Response implements ResponseInterface /** * Returns a new instance having set the parameter */ - internal function cloneInstance(var element, string property) -> + private function cloneInstance(var element, string property) -> { var newInstance; @@ -396,7 +396,7 @@ class Response implements ResponseInterface /** * Returns the header values checked for validity */ - internal function getHeaderValue(var values) -> array + private function getHeaderValue(var values) -> array { var value; array valueData; @@ -423,7 +423,7 @@ class Response implements ResponseInterface /** * Returns the list of status codes available */ - internal function getPhrases() -> array + private function getPhrases() -> array { return [ 100 : "Continue", // Information - RFC 7231, 6.2.1 @@ -523,7 +523,7 @@ class Response implements ResponseInterface /** * Set a valid stream */ - internal function processBody(var body = "php://memory", string mode = "r+b") -> + private function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -569,7 +569,7 @@ class Response implements ResponseInterface /** * Sets the headers */ - internal function processHeaders(array headers) -> + private function processHeaders(array headers) -> { var collection, name, value; @@ -590,7 +590,7 @@ class Response implements ResponseInterface /** * Checks the protocol */ - internal function processProtocol(var protocol = "") -> string + private function processProtocol(var protocol = "") -> string { array protocols; diff --git a/phalcon/http/message/serverrequest.zep b/phalcon/http/message/serverrequest.zep index 7dbbaf59d92..21eff55c802 100644 --- a/phalcon/http/message/serverrequest.zep +++ b/phalcon/http/message/serverrequest.zep @@ -697,7 +697,7 @@ class ServerRequest implements ServerRequestInterface * * @see http://tools.ietf.org/html/rfc7230#section-3.2 */ - internal function checkHeaderName(var name) -> void + private function checkHeaderName(var name) -> void { if typeof name !== "string" || !preg_match("/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/", name) { throw new \InvalidArgumentException("Invalid header name " . name); @@ -749,7 +749,7 @@ class ServerRequest implements ServerRequestInterface * * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 */ - internal function checkHeaderValue(var value) -> void + private function checkHeaderValue(var value) -> void { if typeof value !== "string" && typeof value !== "int" && typeof value !== "float" { throw new \InvalidArgumentException("Invalid header value"); @@ -766,7 +766,7 @@ class ServerRequest implements ServerRequestInterface /** * Checks the uploaded files */ - internal function checkUploadedFiles(array files) -> void + private function checkUploadedFiles(array files) -> void { var file; @@ -785,7 +785,7 @@ class ServerRequest implements ServerRequestInterface /** * Returns a new instance having set the parameter */ - internal function cloneInstance(var element, string property) -> + private function cloneInstance(var element, string property) -> { var newInstance; @@ -800,7 +800,7 @@ class ServerRequest implements ServerRequestInterface /** * Returns the header values checked for validity */ - internal function getHeaderValue(var values) -> array + private function getHeaderValue(var values) -> array { var value; array valueData; @@ -827,7 +827,7 @@ class ServerRequest implements ServerRequestInterface /** * Return the host and if applicable the port */ - internal function getUriHost( uri) -> string + private function getUriHost( uri) -> string { var host; @@ -842,7 +842,7 @@ class ServerRequest implements ServerRequestInterface /** * Set a valid stream */ - internal function processBody(var body = "php://memory", string mode = "r+b") -> + private function processBody(var body = "php://memory", string mode = "r+b") -> { if body instanceof StreamInterface { return body; @@ -858,7 +858,7 @@ class ServerRequest implements ServerRequestInterface /** * Sets the headers */ - internal function processHeaders(var headers) -> + private function processHeaders(var headers) -> { var collection, host, name, value; @@ -884,7 +884,7 @@ class ServerRequest implements ServerRequestInterface let collection = headers; } else { throw new \InvalidArgumentException( - "Headers needs to be either an array or instance of Phalcon\Collection" + "Headers need to be either an array or instance of Phalcon\Collection" ); } } @@ -895,7 +895,7 @@ class ServerRequest implements ServerRequestInterface /** * Check the method */ - internal function processMethod(var method = "") -> string + private function processMethod(var method = "") -> string { array methods; @@ -921,7 +921,7 @@ class ServerRequest implements ServerRequestInterface /** * Checks the protocol */ - internal function processProtocol(var protocol = "") -> string + private function processProtocol(var protocol = "") -> string { array protocols; @@ -946,7 +946,7 @@ class ServerRequest implements ServerRequestInterface /** * Sets a valid Uri */ - internal function processUri(var uri) -> + private function processUri(var uri) -> { var localUri;