PSR-7 Progress and request for comments

394 views
Skip to first unread message

Matthew Weier O'Phinney

unread,
Oct 2, 2014, 10:24:37 AM10/2/14
to php...@googlegroups.com
Now that it's been around a week, I thought I'd give a progress
report, and point out the areas that still need discussion on PSR-7,
HTTP Message Interfaces.

### Progress

Two nights ago, I had Phil Sturgeon merge pull requests for PSR-7 for
the following:

- #330: Add attach($stream) to the stream interface; accepts a new
stream resource.
- #331: Clarify the return value of detach() (it should return a
stream resource, or, if the underlying "stream" is not a resource,
null).
- #332: Add getMetadata($key = null) to the stream interface; should
proxy to stream_get_meta_data
- #333: Remove $maxLength argument from the getContents() method of
the stream interface.
- #334: Rename StreamInterface to StreamableInterface (to prevent
confusing the interface with an actual stream wrapper).

These have all been merged, and the following have been updated to
reflect the changes:

- https://github.com/php-fig/http-message - the published package
containing the interfaces. Additionally, the repo was tagged 0.1.0 for
the last commit prior to merging the above changes, and then 0.2.0
afterwards.
- https://github.com/phly/http - my implementation of the above interfaces.
- https://github.com/phly/conduit - as it defined proxy/decorators for
the HTTP messages.

There's still some work to be done.

### Incoming Request

First, I created a pull request for describing an "incoming request":

- https://github.com/php-fig/fig-standards/pull/338

The idea here is that for server-side requests, developers will want
access to some standard request artifacts that cannot be easily
described in terms of an HTTP message. As such, this new interface,
Psr\Http\Message\IncomingRequestInterface, extends the
RequestInterface, and adds methods for accessing those artifacts.
Currently, it defines the following:

- getQueryParams() - which should return an array or array-like object
- setQueryParams($params) - which should expect an array or array-like
object of the deserialized query string arguments.
- getBodyParams() - which would return deserialized body parameters.
- setBodyParams($params) - which would allow injecting deserialized
body parameters.
- getIncomingFiles() - which would essentially return $_FILES
- setIncomingFiles($files) - which would allow injecting $_FILES

One comment on the PR notes that the setters may not need to be part
of the interface, as they can be injected at instantiation. I agree
that this is true for query string parameters (for which $_GET is
always correct) and incoming files (for which $_FILES is always
correct), I disagree when it comes to the body parameters. Body
parameters can NOT always be assumed to be $_POST -- in fact, with the
rising number of API-centric applications PHP developers are often now
building, it's more often than not exactly the wrong assumption. In
cases where POST is not the request method, and when it is but the
content-type is not application/x-www-form-urlencoded, you will need
to perform content negotiation to determine how to deserialize the
body content, and then do so. This is something outside the scope of
the request object -- but we still will want to be able to inject the
request object so that consumers can obtain that information once
another process has parsed it. (This is also why I went with the
naming of "body params" instead of "post"; "post" implies only POST
and even more specifically $_POST.)

This leaves me with the following:

- We don't necessarily need setters for query parameters or incoming
files; in fact, keeping them could lead to cases where the request has
an inconsistent state if something in the execution chain chooses to
call the setters mid-way through the request cycle.
- However, removing them for just the query params and incoming files
makes the interface look inconsistent (i.e., why do some properties
have setters, and others do not?). Additionally, for testing purposes,
setters are far easier than having to construct a new request for each
test.

One other suggestion for this interface has been to allow injecting
the results of routing. My primary objection to this is that routing
results vary tremendously between frameworks and libraries.
Aura.Router and ZF2's router return objects, neither of which act like
or can be cast to arrays. I assume Symfony does as well, but it's hard
to tell -- matched route parameters are auto-magically injected into
controllers, which tells me the information is aggregated somehow. My
primary point, though, is: I'm a bit concerned about adding methods to
an interface that allow for arbitrary types. That said, if people feel
this would be useful, I'd recommend the following two methods:

- getRouteInfo()
- setRouteInfo($data)

I'm going with "RouteInfo" here as the results of routing may have
more than matched parameters (e.g., Aura.Router provides the matched
route name).

I'd love some feedback on this part of the proposal:

- Setters for query params, incoming files: yea or nay?
- Methods for adding retrieving route information: yea or nay?

### URI Interface

Second (there was a "First" a few paragraphs back...), I created a
pull request for describing a URI interface:

- https://github.com/php-fig/fig-standards/pull/337

I am far less certain about this one, for a number of reasons:

- It's not HTTP-specific; as such, I'm not sure it belongs in the same
proposal. In fact, honestly, it needs to be under a separate
namespace, which means including it in the psr/http-message package is
not even a good fit.
- The message interfaces indicate that the URL should be a string **or
an object that can be cast to a string**. As such, you already have
guarantees that you can:
- represent the URI as a string
- pass the URI to tools such as parse_url() in order to get its
various segments

The most common use cases for access the URI are:

- Using its string representation
- Getting at the scheme (to redirect to HTTP or HTTPS)
- Getting at the path (for routing)

These can be done as follows:

- echo $uri;
- $scheme = parse_url($uri, PHP_URL_SCHEME);
- $path = parse_url($uri, PHP_URL_PATH);

Implementations can always specify a URI object if they want. In
phly/http and phly/conduit, I cast any incoming url to the request to
a Phly\Http\Url instance, which means that consumers can be assured
they have an object. If they want, they can also cast it to one:

- $url = ($url instanceof Phly\Http\Uri) ? $url : new Phly\Http\Uri($url);

and then access the segments via OOP.

My points are:

- Getting at the segments of a URI are trivial using PHP.
- The Message interfaces already indicate that URLs can be either
strings or objects that can be cast to strings.
- Casting a string URL to an object will typically be simple.

As such, I think we can withdraw #337 from consideration.

- URI interface for PSR-7: yea or nay?


--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Paul M. Jones

unread,
Oct 2, 2014, 10:41:29 AM10/2/14
to php...@googlegroups.com

On Oct 2, 2014, at 9:24 AM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> ### Incoming Request
>
> First, I created a pull request for describing an "incoming request":
>
> - https://github.com/php-fig/fig-standards/pull/338

Thanks for this.


> - getQueryParams() - which should return an array or array-like object
> - setQueryParams($params) - which should expect an array or array-like
> object of the deserialized query string arguments.
> - getBodyParams() - which would return deserialized body parameters.
> - setBodyParams($params) - which would allow injecting deserialized
> body parameters.
> - getIncomingFiles() - which would essentially return $_FILES
> - setIncomingFiles($files) - which would allow injecting $_FILES


...

> - We don't necessarily need setters for query parameters or incoming
> files; in fact, keeping them could lead to cases where the request has
> an inconsistent state if something in the execution chain chooses to
> call the setters mid-way through the request cycle.

Agreed.


> - However, removing them for just the query params and incoming files
> makes the interface look inconsistent (i.e., why do some properties
> have setters, and others do not?). Additionally, for testing purposes,
> setters are far easier than having to construct a new request for each
> test.

I don't think it's inconsistent at all. Note that they are intended to be immutable, and we're done.


> One other suggestion for this interface has been to allow injecting
> the results of routing. My primary objection to this is that routing
> results vary tremendously between frameworks and libraries.

I think this was from me. To clarify the request, I'm suggesting *not* the entirety of the route, but only the extracted path-info parameters, be placed in the route. AFAICT these are always (or almost always) implemented as key-value arrays.


> If people feel
> this would be useful, I'd recommend the following two methods:
>
> - getRouteInfo()
> - setRouteInfo($data)

I think (set|get)PathParams() would make sense here, given my above clarification.


> - Setters for query params, incoming files: yea or nay?

Nay.


> - Methods for adding retrieving route information: yea or nay?

Yea, subject to my comments above.


> ### URI Interface
>
> Second (there was a "First" a few paragraphs back...), I created a
> pull request for describing a URI interface:
>
> - https://github.com/php-fig/fig-standards/pull/337
>
> I am far less certain about this one, for a number of reasons:

I am beginning to share your uncertainty. Looking back over my own work, it has been very rare that I've needed to deal with the URL outside of the front-controller elements and the occasional presentation helper.

> - Getting at the segments of a URI are trivial using PHP.
> - The Message interfaces already indicate that URLs can be either
> strings or objects that can be cast to strings.
> - Casting a string URL to an object will typically be simple.
>
> As such, I think we can withdraw #337 from consideration.
>
> - URI interface for PSR-7: yea or nay?

I'm still going to go with a temporary "yea" (i.e., retain the PR without merging) so that the work does not get lost, but I agree that this is a moderately-strong candidate for eventual removal.


--
Paul M. Jones
pmjo...@gmail.com
http://paul-m-jones.com

Modernizing Legacy Applications in PHP
http://mlaphp.com



Paul M. Jones

unread,
Oct 2, 2014, 11:43:07 AM10/2/14
to php...@googlegroups.com
Hi all,

(Summarized ...)

>> - getQueryParams() - which should return an array or array-like object
>> - getBodyParams() - which would return deserialized body parameters.
>> - setBodyParams($params) - which would allow injecting deserialized
>> body parameters.
>> - getIncomingFiles() - which would essentially return $_FILES
...
>> - getRouteInfo()
>> - setRouteInfo($data)
>
> I think (set|get)PathParams() would make sense here, given my above clarification.

... in further consideration along this path, it may be wise to add getCookieParams() as a representation of $_COOKIE.

Matthew Weier O'Phinney

unread,
Oct 2, 2014, 6:11:13 PM10/2/14
to php...@googlegroups.com
(ugh... not getting emails in my inbox, so having to use the groups interface to reply... sorry in advance for the stupid formatting...)


On Thursday, October 2, 2014 10:43:07 AM UTC-5, pmjones wrote:
Hi all,

(Summarized ...)

>> - getQueryParams() - which should return an array or array-like object
>> - getBodyParams() - which would return deserialized body parameters.
>> - setBodyParams($params) - which would allow injecting deserialized
>> body parameters.
>> - getIncomingFiles() - which would essentially return $_FILES
...
>> - getRouteInfo()
>> - setRouteInfo($data)
>
> I think (set|get)PathParams() would make sense here, given my above clarification.

... in further consideration along this path, it may be wise to add getCookieParams() as a representation of $_COOKIE.

Okay, at this point I've updated the pull request for the IncomingRequestInterface to define the following methods:

- getQueryParams()
- getFileParams() -- renamed this from getIncomingFiles() per a comment from PMJ ("Incoming" was redundant with the interface name, and suffixing with Params makes it consistent with the other methods)
- getCookieParams() -- nice catch, Paul!
- getBodyParams()
- setBodyParams($params) -- also updated to allow setting either an array or an object -- particularly as deserialization may return an object, or you may want to return something like an XmlReader instance.
- getPathParams()
- setPathParams($params) -- with a note that $params SHOULD be an array or array-like object.

If anybody has further feedback, please add to this thread or via a comment on the PR.
 

Korvin Szanto

unread,
Oct 2, 2014, 7:08:27 PM10/2/14
to php...@googlegroups.com
> - Setters for query params, incoming files: yea or nay?
I think setters would only encourage changing the object before the
request cycle has completed.
Secondarily, even with setters for those values, I'd probably build
new request objects for each test already anyway.

> - Methods for adding retrieving route information: yea or nay?
Wouldn't these methods cause deep coupling?

Matthew Weier O'Phinney

unread,
Oct 2, 2014, 7:14:06 PM10/2/14
to php...@googlegroups.com


On Oct 2, 2014 6:08 PM, "Korvin Szanto" <korvin...@gmail.com> wrote:
>
> > - Setters for query params, incoming files: yea or nay?
> I think setters would only encourage changing the object before the
> request cycle has completed.
> Secondarily, even with setters for those values, I'd probably build
> new request objects for each test already anyway.

Agreed - I've already updated the PR to reflect this.

> > - Methods for adding retrieving route information: yea or nay?
> Wouldn't these methods cause deep coupling?

Not necessarily. The recommendation is to inject an array or array-like object. Most routing solutions already return this, or something capable of providing that information. This would only provide a common interface for getting at that information.

Paul M. Jones

unread,
Oct 2, 2014, 8:35:03 PM10/2/14
to php...@googlegroups.com

On Oct 2, 2014, at 5:11 PM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> Okay, at this point I've updated the pull request for the IncomingRequestInterface to define the following methods:
>
> - getQueryParams()
> - getFileParams() -- renamed this from getIncomingFiles() per a comment from PMJ ("Incoming" was redundant with the interface name, and suffixing with Params makes it consistent with the other methods)
> - getCookieParams() -- nice catch, Paul!
> - getBodyParams()
> - setBodyParams($params) -- also updated to allow setting either an array or an object -- particularly as deserialization may return an object, or you may want to return something like an XmlReader instance.
> - getPathParams()
> - setPathParams($params) -- with a note that $params SHOULD be an array or array-like object.
>
> If anybody has further feedback, please add to this thread or via a comment on the PR.

I very much appreciate this. I think we're really moving in the right direction for an IncomingRequest case.

FWIW, I'm compiling a further list of items for discussion, but that'll take a bit.

Have I mentioned that I'm happy you're on the case here, MWOP? :-)

Chris Wilkinson

unread,
Oct 3, 2014, 3:26:13 AM10/3/14
to php...@googlegroups.com
On Thursday, 2 October 2014 15:24:37 UTC+1, Matthew Weier O'Phinney wrote:
### URI Interface

Second (there was a "First" a few paragraphs back...), I created a
pull request for describing a URI interface:

- https://github.com/php-fig/fig-standards/pull/337


Chris 

Roman Tsjupa

unread,
Oct 5, 2014, 6:02:05 AM10/5/14
to php...@googlegroups.com
Hey guys =) 
I'm curios as to why there is no MessageInterface::setProtocolVersion() ? 

Matthew Weier O'Phinney

unread,
Oct 6, 2014, 8:59:39 AM10/6/14
to php...@googlegroups.com
On Sun, Oct 5, 2014 at 5:02 AM, Roman Tsjupa <draco...@gmail.com> wrote:
> Hey guys =)
> I'm curios as to why there is no MessageInterface::setProtocolVersion() ?

Because it's rare that you'd need to set it after instantiation;
protocol is determined in the first line of either a request or a
response, and typically will not affect anything other than casting
the message to a string (an operation not defined by the interfaces).
In phly/http, I have it as a constructor argument.
> --
> You received this message because you are subscribed to the Google Groups
> "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/6aab647d-412c-483e-b3aa-96a81de137c7%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

Taylor Otwell

unread,
Oct 6, 2014, 10:25:56 AM10/6/14
to php...@googlegroups.com
Are there plans for adding methods for working with Cookies?

Hari K T

unread,
Oct 6, 2014, 10:32:09 AM10/6/14
to php...@googlegroups.com

Are there plans for adding methods for working with Cookies?

Matthew Weier O'Phinney

unread,
Oct 6, 2014, 10:41:32 AM10/6/14
to php...@googlegroups.com
On Mon, Oct 6, 2014 at 9:25 AM, Taylor Otwell <taylor...@gmail.com> wrote:
> Are there plans for adding methods for working with Cookies?

Yes -- PMJ suggested it as well, and I added getCookieParams() to the
IncomingRequestInterface last week:
https://github.com/weierophinney/fig-standards/commit/8786a7c3a80e3ec13c9b1a2cab43835c645761a5
> --
> You received this message because you are subscribed to the Google Groups
> "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/b68ace9a-7fec-4147-a519-b1d408965543%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



Taylor Otwell

unread,
Oct 6, 2014, 5:58:50 PM10/6/14
to php...@googlegroups.com
Not sure if this is the right thread for this, but I'll bite. Cookies *might* not be immutable over the course of the request, heh. For instance, in Laravel, all cookies are encrypted and signed. This is done via a very early middleware on the middleware stack (CookieGuard). When the request first comes in, the Cookie params will be encrypted garbage, and the middleware decrypts them and sets the value back on the request, or, if the cookie has been tampered with (as evidenced by MAC checking), the cookie will be cleared and considered invalid.

Thoughts?

Matthew Weier O'Phinney

unread,
Oct 6, 2014, 6:17:45 PM10/6/14
to php...@googlegroups.com
On Mon, Oct 6, 2014 at 4:58 PM, Taylor Otwell <taylor...@gmail.com> wrote:
> Not sure if this is the right thread for this, but I'll bite. Cookies
> *might* not be immutable over the course of the request, heh. For instance,
> in Laravel, all cookies are encrypted and signed. This is done via a very
> early middleware on the middleware stack (CookieGuard). When the request
> first comes in, the Cookie params will be encrypted garbage, and the
> middleware decrypts them and sets the value back on the request, or, if the
> cookie has been tampered with (as evidenced by MAC checking), the cookie
> will be cleared and considered invalid.
>
> Thoughts?

I'd consider that specialized behavior at this point (read: the
practice is not widespread in PHP), making it hard to determine if it
would be a good candidate for inclusion in the interface.

What I _can_ say at this point is that if you know you'll be working
with middleware that does this within your application, you could
either instantiate a request instance that provides a setter OR
introduce a middleware layer that decorates the request instance to
provide the setter; that way any middleware encapsulated by that layer
will get the behavior you need. (I do something like this in Conduit
-- the Middleware object will decorate the incoming request and
response instances in order to provide additional behavior --
arbitrary property access on the request, and convenience methods on
the response.)

It _does_ become a documentation issue for the
library/project/application, but it can be accomplished now without
any interface changes.

So, the bigger question here is: would anybody else need setters for
cookie parameters? Is it a general use-case the interface should
support?
> https://groups.google.com/d/msgid/php-fig/320aba80-6458-4219-a844-ba8802d6c288%40googlegroups.com.

Roman Tsjupa

unread,
Oct 6, 2014, 6:32:08 PM10/6/14
to php...@googlegroups.com
Having HTTP version as a constructor argument is ok, but I don't really see the point of leaving it out of being editable later on. By the same logic one could say that HTTP method is also rarely edited later on.
Imho HTTP requests shouldn't be viewed from the framework/middleware standpoint, rather from a more global view. The obvious example would be some curl wrapper which can execute such requests. From that standpoint the request may be totally mutable back and forth.

A HTTP request in the contest of a framework might composite this general HTTP request and thus be immutabe

Paul M. Jones

unread,
Oct 6, 2014, 10:28:08 PM10/6/14
to php...@googlegroups.com

On Oct 6, 2014, at 5:17 PM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> So, the bigger question here is: would anybody else need setters for
> cookie parameters? Is it a general use-case the interface should
> support?

Related to this, I am beginning to think that using a plain-old header method for cookies in an outgoing response might be insufficient. PHP itself has setcookie() and setrawcookie() aside from header(); I surmise this is because the cookie format is relatively specialized, and thus is worthy of special treatment aside from other headers.

With that in mind, it might be useful to pair an OutgoingResponse object, containing setCookie() and setRawCookie() methods, with the new IncomingRequest object to account for this. However, doing so would require us to specify how the cookie values are stored, so that they can be retrieved for sending via setcookie() and setrawcookie(). That would add even more to the interface, which I'm pretty sure nobody wants to do at this point. Even so, I think it might be a good addition.

Evert Pot

unread,
Oct 6, 2014, 10:35:08 PM10/6/14
to php...@googlegroups.com


On Monday, October 6, 2014 10:28:08 PM UTC-4, pmjones wrote:

On Oct 6, 2014, at 5:17 PM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> So, the bigger question here is: would anybody else need setters for
> cookie parameters? Is it a general use-case the interface should
> support?

Related to this, I am beginning to think that using a plain-old header method for cookies in an outgoing response might be insufficient. PHP itself has setcookie() and setrawcookie() aside from header(); I surmise this is because the cookie format is  relatively specialized, and thus is worthy of special treatment aside from other headers.

With that in mind, it might be useful to pair an OutgoingResponse object, containing setCookie() and setRawCookie() methods, with the new IncomingRequest object to account for this.  However, doing so would require us to specify how the cookie values are stored, so that they can be retrieved for sending via setcookie() and setrawcookie(). That would add even more to the interface, which I'm pretty sure nobody wants to do at this point. Even so, I think it might be a good addition.

The general problem is that there are *lots* of HTTP headers that can really use handy utility functions to either generate or parse. Just think of accept headers, caching headers, If-* headers, etc.

I don't think you'll want to add all these utility functions to the base messaging interfaces. They can just as easily live outside interfaces and affect the messaging objects. I also don't think they really need to be part of the core proposal for this reason. It's not the type of thing that we need to interop on.

For the incoming request, a few a bit exceptional, because we're dealing with PHP's superglobals, and they are already parsed and populated. You really don't want to abstract $_POST back into a request body..
You could argue that the damage of doing that isn't as severe with $_COOKIE (e.g.: just re-parse), but I definitely do think there's no point to add more api sugar, if these methods will just end up calling $this->addHeader().

If you really feel that for your purposes, methods such as ->setCookie() belong on your HTTP response object, you can always choose to decorate them on.

Evert

Paul M. Jones

unread,
Oct 6, 2014, 10:38:32 PM10/6/14
to php...@googlegroups.com

On Oct 6, 2014, at 9:35 PM, Evert Pot <ever...@gmail.com> wrote:

>
>
> On Monday, October 6, 2014 10:28:08 PM UTC-4, pmjones wrote:
>
> On Oct 6, 2014, at 5:17 PM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:
>
> > So, the bigger question here is: would anybody else need setters for
> > cookie parameters? Is it a general use-case the interface should
> > support?
>
> Related to this, I am beginning to think that using a plain-old header method for cookies in an outgoing response might be insufficient. PHP itself has setcookie() and setrawcookie() aside from header(); I surmise this is because the cookie format is relatively specialized, and thus is worthy of special treatment aside from other headers.
>
>> With that in mind, it might be useful to pair an OutgoingResponse object, containing setCookie() and setRawCookie() methods, with the new IncomingRequest object to account for this. However, doing so would require us to specify how the cookie values are stored, so that they can be retrieved for sending via setcookie() and setrawcookie(). That would add even more to the interface, which I'm pretty sure nobody wants to do at this point. Even so, I think it might be a good addition.
>
> The general problem is that there are *lots* of HTTP headers that can really use handy utility functions to either generate or parse. Just think of accept headers, caching headers, If-* headers, etc.
>
> I don't think you'll want to add all these utility functions to the base messaging interfaces.

I get that. Even so, cookies appear to be "special enough" that PHP itself has functions for them. I think we can take that as a hint for our work here.

Evert Pot

unread,
Oct 6, 2014, 10:42:25 PM10/6/14
to php...@googlegroups.com

I get that. Even so, cookies appear to be "special enough" that PHP itself has functions for them. I think we can take that as a hint for our work here.


That might just as well be for legacy reasons :)
This is a slippery slope, and I think it's a bad idea.

Evert

Paul M. Jones

unread,
Oct 6, 2014, 10:45:14 PM10/6/14
to php...@googlegroups.com
Fair. By way of example, what does setting an outgoing cookie look like in the proposal as it exists now?

Evert Pot

unread,
Oct 6, 2014, 10:49:30 PM10/6/14
to php...@googlegroups.com

On Monday, October 6, 2014 10:45:14 PM UTC-4, pmjones wrote:

On Oct 6, 2014, at 9:42 PM, Evert Pot wrote:

>
> I get that. Even so, cookies appear to be "special enough" that PHP itself has functions for them. I think we can take that as a hint for our work here.
>
>
> That might just as well be for legacy reasons :)
> This is a slippery slope, and I think it's a bad idea.

Fair. By way of example, what does setting an outgoing cookie look like in the proposal as it exists now?

Would be something like this:

$response->addHeader('Set-Cookie', 'key=val');
$response->addHeader('Set-Cookie', 'key=val; Expires=Mon, 06 Oct 2015 22:47:00 GMT');

Aint pretty ;)

Evert

Paul M. Jones

unread,
Oct 6, 2014, 10:55:57 PM10/6/14
to php...@googlegroups.com
Right. There's a lot more to it as well: path, domain, secure, and http only. It's pretty complex, comparatively speaking.

In fact, I think it's the single most complex header in the spec. As I recall, even the cache-related headers are nowhere near as complex. Admittedly their values must be in particular formats, but the end result is "Header: value".

Because I am not fully up on the spec, *is* there any other header that approaches this kind of complexity?

Evert Pot

unread,
Oct 6, 2014, 11:12:54 PM10/6/14
to php...@googlegroups.com


On Monday, October 6, 2014 10:55:57 PM UTC-4, pmjones wrote:

On Oct 6, 2014, at 9:49 PM, Evert Pot wrote:

>
> On Monday, October 6, 2014 10:45:14 PM UTC-4, pmjones wrote:
>
> On Oct 6, 2014, at 9:42 PM, Evert Pot wrote:
>
> >
> > I get that. Even so, cookies appear to be "special enough" that PHP itself has functions for them. I think we can take that as a hint for our work here.
> >
> >
> > That might just as well be for legacy reasons :)
> > This is a slippery slope, and I think it's a bad idea.
>
> Fair. By way of example, what does setting an outgoing cookie look like in the proposal as it exists now?
>
> Would be something like this:
>
> $response->addHeader('Set-Cookie', 'key=val');
> $response->addHeader('Set-Cookie', 'key=val; Expires=Mon, 06 Oct 2015 22:47:00 GMT');
>
> Aint pretty ;)

Right. There's a lot more to it as well: path, domain, secure, and http only. It's pretty complex, comparatively speaking.

In fact, I think it's the single most complex header in the spec. As I recall, even the cache-related headers are nowhere near as complex. Admittedly their values must be in particular formats, but the end result is "Header: value".

Because I am not fully up on the spec, *is* there any other header that approaches this kind of complexity?

The winner for me would be the If: header, but that's WebDAV.. standard extension of HTTP.

If I'm confined to the base HTTP spec, my vote would go to the Accept header.

It's main structure is something like this:
   Accept: type/subtype; param1; param2; q=0.5; ext1; ext2, type/subtype; param1=val1; q=0.5; ext=token;

The parameters, quality thingy and extensions all look similar, but the q= acts as a separator between them.

Modified-Since is also pretty weird because it supports 3 different date formats.

Range and Content-Range are also a bit weird.

What about the Digest authorization header. It's rfc7235 so today we can consider that 'base http spec' I think.

My general point is:

.. There's a very large amount of HTTP headers that have a unique, structured format beyond plain key->value.
I think it's super useful to create utilities to generate and parse these based on future PSR-7 messages.

And every time there's another header that's useful to parse or generate, these can be added to these utilities.
It's a lot harder to create an extensive exhaustive list of methods on these interfaces.

I'm slightly saddened that they are needed for the IncomingRequest, because it makes the whole thing less
pure, but we have a solid technical problem we need to solve.

I don't think cookie headers are special or unique at all, especially in the context of setting them.

Evert

Roman Tsjupa

unread,
Oct 6, 2014, 11:27:50 PM10/6/14
to php...@googlegroups.com
There is no concept of a 'cookie' from a transfer protocol point of view. All of the actual meaning behind most of the headers is given in higher OSI Model levels, and should be taken car of in a higher-level interface. One could easily have a separate decoupled cookie manager class that sets and gets those headers on a request, so merging this functionality into the request itself would kind of break separation of concerns


On Thursday, October 2, 2014 4:24:37 PM UTC+2, Matthew Weier O'Phinney wrote:

Michael Dowling

unread,
Oct 7, 2014, 2:50:16 AM10/7/14
to php...@googlegroups.com, php...@googlegroups.com
I completely agree.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Matthew Weier O'Phinney

unread,
Oct 7, 2014, 9:37:22 AM10/7/14
to php...@googlegroups.com
On Mon, Oct 6, 2014 at 5:32 PM, Roman Tsjupa <draco...@gmail.com> wrote:
> Having HTTP version as a constructor argument is ok, but I don't really see
> the point of leaving it out of being editable later on. By the same logic
> one could say that HTTP method is also rarely edited later on.
> Imho HTTP requests shouldn't be viewed from the framework/middleware
> standpoint, rather from a more global view. The obvious example would be
> some curl wrapper which can execute such requests. From that standpoint the
> request may be totally mutable back and forth.
>
> A HTTP request in the contest of a framework might composite this general
> HTTP request and thus be immutabe

Looking back at the MessageInterface, considering everything else has
both getters and setters, I'm going to concur that a setter should be
available.

I've opened a PR for this: https://github.com/php-fig/fig-standards/pull/340
> --
> You received this message because you are subscribed to the Google Groups
> "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/cc4e5a30-f87d-4ce6-bbaa-8d86c10959db%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



Matthew Weier O'Phinney

unread,
Oct 7, 2014, 9:41:11 AM10/7/14
to php...@googlegroups.com
On Mon, Oct 6, 2014 at 10:27 PM, Roman Tsjupa <draco...@gmail.com> wrote:
> There is no concept of a 'cookie' from a transfer protocol point of view.

We're not discussing the basic message interfaces at this point --
this discussion is generally positing server-side specific extensions
to the request/response interfaces to abstract common functionality
used when _processing_ an incoming request. (See
https://github.com/php-fig/fig-standards/pull/338 for more details.)

What is being asked is: should we have specific methods in an
IncomingRequest or a ServerResponse for handling cookies?
> --
> You received this message because you are subscribed to the Google Groups
> "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/50f0e735-90ed-4077-aadb-6431b60c1d03%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



Matthew Weier O'Phinney

unread,
Oct 7, 2014, 9:54:09 AM10/7/14
to php...@googlegroups.com
On Mon, Oct 6, 2014 at 10:12 PM, Evert Pot <ever...@gmail.com> wrote:
> On Monday, October 6, 2014 10:55:57 PM UTC-4, pmjones wrote:
>> On Oct 6, 2014, at 9:49 PM, Evert Pot wrote:
>> > On Monday, October 6, 2014 10:45:14 PM UTC-4, pmjones wrote:
>> > On Oct 6, 2014, at 9:42 PM, Evert Pot wrote:

<snip>

> The winner for me would be the If: header, but that's WebDAV.. standard
> extension of HTTP.
>
> If I'm confined to the base HTTP spec, my vote would go to the Accept
> header.
>
> It's main structure is something like this:
> Accept: type/subtype; param1; param2; q=0.5; ext1; ext2, type/subtype;
> param1=val1; q=0.5; ext=token;
>
> The parameters, quality thingy and extensions all look similar, but the q=
> acts as a separator between them.
>
> Modified-Since is also pretty weird because it supports 3 different date
> formats.
>
> Range and Content-Range are also a bit weird.
>
> What about the Digest authorization header. It's rfc7235 so today we can
> consider that 'base http spec' I think.
>
> My general point is:
>
> .. There's a very large amount of HTTP headers that have a unique,
> structured format beyond plain key->value.
> I think it's super useful to create utilities to generate and parse these
> based on future PSR-7 messages.

Exactly.

This wouldn't even need to be part of FIG, to be honest.

The interfaces detail how to aggregate and retrieve headers; that's
all they need to do. Parsing/Assembly can be left to utility
libraries. Either Evert or Paul brought up the Accept header, and
that's a great example: I would not expect my Request object to be
able to parse that and perform content negotiation based on it.
However, I *would* like to be able to get at the value, so I can pass
it to a dedicated library such as willdurand/Negotiation or
aura/accept. Similarly, if I need to set cookies, I have the following
options:

- Just use setcookie() (not testable, but hey, it works)
- Assemble the value manually and pass it to addHeader()
- Use a library that models cookies and which can spit out the value
for a header, and add that to addHeader()

This latter is interesting in that you can then add more functionality
-- encryption, verification, etc. These also become nice, small,
commodity libraries.

So: I'm in favor of leaving the cookie functionality as-is. The
headers can be set manually, or a library can be used to generate the
value for you to inject.

--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Matthew Weier O'Phinney

unread,
Oct 7, 2014, 9:55:39 AM10/7/14
to php...@googlegroups.com
I did some searching on packagist, and discovered at least a
half-dozen libraries that implement secure cookie functionality, most
of them using encryption -- suggesting that the practice is much more
common than I thought. As such, I'm going to amend the
IncomingRequestInterface pull request to add setters for cookies.

Paul M. Jones

unread,
Oct 7, 2014, 10:06:15 AM10/7/14
to php...@googlegroups.com

On Oct 6, 2014, at 10:12 PM, Evert Pot <ever...@gmail.com> wrote:

>> On Monday, October 6, 2014 10:55:57 PM UTC-4, pmjones wrote:
>>
>> On Oct 6, 2014, at 9:49 PM, Evert Pot wrote:
>>
>> >
>> > On Monday, October 6, 2014 10:45:14 PM UTC-4, pmjones wrote:
>> >
>> > On Oct 6, 2014, at 9:42 PM, Evert Pot wrote:
>> >
>> > >
>> > > I get that. Even so, cookies appear to be "special enough" that PHP itself has functions for them. I think we can take that as a hint for our work here.
>> > >
>> > >
>> > > That might just as well be for legacy reasons :)
>> > > This is a slippery slope, and I think it's a bad idea.
>> >
>> > Fair. By way of example, what does setting an outgoing cookie look like in the proposal as it exists now?
>> >
>> > Would be something like this:
>> >
>> > $response->addHeader('Set-Cookie', 'key=val');
>> > $response->addHeader('Set-Cookie', 'key=val; Expires=Mon, 06 Oct 2015 22:47:00 GMT');
>> >
>> > Aint pretty ;)
>>
>> Right. There's a lot more to it as well: path, domain, secure, and http only. It's pretty complex, comparatively speaking.
>>
>> In fact, I think it's the single most complex header in the spec. As I recall, even the cache-related headers are nowhere near as complex. Admittedly their values must be in particular formats, but the end result is "Header: value".
>>
>> Because I am not fully up on the spec, *is* there any other header that approaches this kind of complexity?
>
> The winner for me would be the If: header, but that's WebDAV.. standard extension of HTTP.
>
> If I'm confined to the base HTTP spec, my vote would go to the Accept header.
>
> It's main structure is something like this:
> Accept: type/subtype; param1; param2; q=0.5; ext1; ext2, type/subtype; param1=val1; q=0.5; ext=token;
>
> The parameters, quality thingy and extensions all look similar, but the q= acts as a separator between them.
>
> Modified-Since is also pretty weird because it supports 3 different date formats.
>
> Range and Content-Range are also a bit weird.
>
> What about the Digest authorization header. It's rfc7235 so today we can consider that 'base http spec' I think.

By way of reminder, I'm speaking specifically about an hypothetical OutboundResponse object, one that is delivered by PHP to the requesting client. With that in mind, I think we can ignore any of the request-related headers. That leaves us with ...

- Cache-Control
- Content-Disposition
- Content-Range
- Content-Type
- Link
- Set-Cookie

... and I think that's it. These are the things that apps generating an OutboundResponse might need help with.


> I'm slightly saddened that they are needed for the IncomingRequest, because it makes the whole thing less pure, but we have a solid technical problem we need to solve.

That's exactly the point I'm raising with a hypothetical OutboundResponse; i.e., there are some activities that are very commonly performed by PHP apps.


> I don't think cookie headers are special or unique at all, especially in the context of setting them.

/me nods

Maybe, maybe not. Given other developments, this may be worth examining.

Matthew Weier O'Phinney

unread,
Oct 7, 2014, 10:17:07 AM10/7/14
to php...@googlegroups.com
I suspect we were responding at the same time... :)

Curious what you think of the "use library code to generate the header
value" idea I threw out in a previous post on this thread in reply to
Evert. While I see your point about "these are common response
activities", they are also things library code can create and inject
into the response. As such, there's really no need to complicate the
response further (or add an OutgoingResponse or ServerResponse
interface) -- they're just headers, and the values can be generated
elsewhere.

--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Paul M. Jones

unread,
Oct 7, 2014, 11:17:57 AM10/7/14
to php...@googlegroups.com

On Oct 7, 2014, at 9:17 AM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> I suspect we were responding at the same time... :)

So do I. :-)


> Curious what you think of the "use library code to generate the header
> value" idea I threw out in a previous post on this thread in reply to
> Evert.

It sounds worthy to me. In fact, it might be cool to see header-building libraries that are decoupled (ha!) from HTTP message libraries. Mix and match.


> While I see your point about "these are common response
> activities", they are also things library code can create and inject
> into the response. As such, there's really no need to complicate the
> response further (or add an OutgoingResponse or ServerResponse
> interface) -- they're just headers, and the values can be generated
> elsewhere.

/me nods

I like the idea. HeaderHelpers, if you will.

Paul M. Jones

unread,
Oct 7, 2014, 11:25:44 AM10/7/14
to php...@googlegroups.com

On Oct 7, 2014, at 8:55 AM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> I did some searching on packagist, and discovered at least a
> half-dozen libraries that implement secure cookie functionality, most
> of them using encryption -- suggesting that the practice is much more
> common than I thought. As such, I'm going to amend the
> IncomingRequestInterface pull request to add setters for cookies.

Given that we're thinking about using external libraries as helpers to build header values in an outgoing response, perhaps the solution here is to use an external library to decode $_COOKIE before injecting them into the IncomingRequest?

Evert Pot

unread,
Oct 7, 2014, 11:28:05 AM10/7/14
to php...@googlegroups.com


On Tuesday, October 7, 2014 11:25:44 AM UTC-4, pmjones wrote:

On Oct 7, 2014, at 8:55 AM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:

> I did some searching on packagist, and discovered at least a
> half-dozen libraries that implement secure cookie functionality, most
> of them using encryption -- suggesting that the practice is much more
> common than I thought. As such, I'm going to amend the
> IncomingRequestInterface pull request to add setters for cookies.

Given that we're thinking about using external libraries as helpers to build header values in an outgoing response, perhaps the solution here is to use an external library to decode $_COOKIE before injecting them into the IncomingRequest?


Well is there a decoding step to $_COOKIE ? The only merit to doing that in the incomingRequest is because the PHP engine has done the work for us.

Evert

Paul M. Jones

unread,
Oct 7, 2014, 11:29:25 AM10/7/14
to php...@googlegroups.com
Sorry, I used the wrong word there. I should have said "decrypt" (since we're talking about encrypted cookies). Does that make my meaning more clear?

Paul M. Jones

unread,
Oct 7, 2014, 11:30:34 AM10/7/14
to php...@googlegroups.com
To follow up again, by "inject" I mean "through the constructor", thus obviating the need for a setter method.

Evert Pot

unread,
Oct 7, 2014, 11:35:14 AM10/7/14
to php...@googlegroups.com

If a middelware library wants to provide transparent encryption, they would have to have a setter regardless right?
Otherwise they would need to create a whole new object with the decoded data. Is that acceptable? Seems like that could be a heavy operation.

Evert

Evert Pot

unread,
Oct 7, 2014, 11:38:47 AM10/7/14
to php...@googlegroups.com

Another issue is that if I create a custom PSR-7 based Request object (but with a few of my additions) and I pass that object to PSR-7 middleware, such as cookie-decryption, I don't want that middleware layer to give me a different object back. I'd want it to be able to operate on my instance of that object.

Evert

Matthew Weier O'Phinney

unread,
Oct 7, 2014, 12:30:28 PM10/7/14
to php...@googlegroups.com
On Tue, Oct 7, 2014 at 10:25 AM, Paul M. Jones <pmjo...@gmail.com> wrote:
>
> On Oct 7, 2014, at 8:55 AM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:
>
>> I did some searching on packagist, and discovered at least a
>> half-dozen libraries that implement secure cookie functionality, most
>> of them using encryption -- suggesting that the practice is much more
>> common than I thought. As such, I'm going to amend the
>> IncomingRequestInterface pull request to add setters for cookies.
>
> Given that we're thinking about using external libraries as helpers to build header values in an outgoing response, perhaps the solution here is to use an external library to decode $_COOKIE before injecting them into the IncomingRequest?

Considering the request is often created early, without necessarily
knowledge of the full application environment, it can be useful to
intercept outside of bootstrapping in order to do this. (I keep
bringing up middleware as an example, and it's relevant here; also,
consider event-driven frameworks, where you might do this only after
you know you have a matching route, as the process of decrypting may
be expensive.)

--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/
Reply all
Reply to author
Forward
0 new messages