PSR-7: "PHP as Client" vs "PHP as Server"

203 views
Skip to first unread message

Paul M. Jones

unread,
Sep 27, 2014, 11:51:36 AM9/27/14
to php...@googlegroups.com
Hi all,

Again, I'm ecstatic that MWOP is on the case with PSR-7. Matthew, if you are already working on addressing the following points, please attend or dismiss as you see fit. But if you are not ...

* * *

On further review, I am growing skeptical that PSR-7 as currently constructed is sufficient to handle *both* "PHP as client" Request/Response pairs, *and* "PHP as server" Request/Response pairs.

By "PHP as client" I mean that some PHP code builds up an outgoing Request, primarily by writing to it, then sends that Request. In time, the PHP code receives an incoming Response, which the PHP code then reads.

By "PHP as server" I mean that some PHP code receives an incoming Request, which it uses primarily for reading. In time, the PHP code builds up an outgoing Response, primarily by writing to it, which it then sends.

I am beginning to think the two use cases are not as similar as I hoped. Yes, we have to both read from and write to both the Request and Response in both bases. But the fact that one is an *outgoing Request* with an incoming Response, and the other is an *incoming Request* with an outgoing Response, means that the kinds of reading and writing are different.

I think PSR-7 as presented suits the "client" case well, which makes sense, since the original proposer was in the business of building clients. Unfortunately, I do *not* think it suits the "server" case well; at least, not without significant added work for implementors.

For example, MWOP suggests (and I strongly desire) a "PHP as server" incoming Request as way for applications to use the same Request interface. Yet PSR-7 provides no way to easily read independent parts of the URL information (scheme, host, path, etc). Indeed, the Request remains mutable, and yet as a representation of the client Request it should probably be *im*mutable (at least in most cases). In fairness, MWOP's Phly\Http attempts to address this, but does so through a new Uri class that is not in the PSR-7 proposal. (I believe there are other cases addressed by non-PSR-7 elements there as well.)

Similarly, PSR-7 provides no methods to easily read $_GET, $_POST, or $_FILES information (and since $_FILES is built differently from the others, it needs a different addressing mechanism). Nor is there a method to read (or set!) the path-info parameters that are so useful in routing. These data are critical to controllers, actions, middleware, etc. being able to get the input they need for their processing work. For them to get that data, they will need to do some additional parsing of the Request-provided data every time they need it. Finally, re-parsing php://input as a default measure seems a bit too much for me. In most cases, merely reading from $_GET and $_POST should be sufficient; parsing php://input should be needed only for, say, XML- or JSON-encoded Request bodies.

As a "client" implementation, I think PSR-7 is asymptotically approaching completion. But as MWOP is pushing the "server" case for PSR-7, and as I agree on its desirability, I think the above points (and perhaps others I have not discovered) need to be addressed.



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

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



Hari K T

unread,
Sep 27, 2014, 12:28:08 PM9/27/14
to php...@googlegroups.com
Hey Paul,

Nice to see your mail. I was playing with phly/http and seeing how things can be worked out.  Frankly I am not an expert in the middleware . Just playing and learning.

https://github.com/harikt/middleware-experiments

The one problem I was also having trouble was with the url as Paul mentioned https://github.com/harikt/middleware-experiments/blob/master/src/Kernel.php#L68

May be there can be a different way.

Thank you.

Hari K T

You can ring me : +91 9388 75 8821

Skype  : kthari85
Twitter : harikt

--
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/20CB9622-95E3-4723-8565-05219B13EFDF%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Philip Sturgeon

unread,
Sep 28, 2014, 10:00:56 AM9/28/14
to php...@googlegroups.com
Still got 50 miles to ride so in smashing this out over lunch.

We've never once proposed PSR-7 was client or server, it's just a PHP representation of a HTTP message.

The only difference between that and a http client to my knowledge is that a client is built to actually make and send these requests, then return a response.

We aren't doing the client bit, just the request and the response.

We agreed there?

Client and server would both wrap around and use these messages.

For a controller to build up a response is easy enough, you just need to set headers and body and send it on it's way. Or make a stream perhaps. That's all a response needs to do, then the server implementation (out of scope) is responsible for actually putting that out there.

How many convenience methods we define for these request/response get/set get and files stuff is up to you lot, but I'd not be a fan of this scope creeping too far. Making this into a HTTP client would certainly be scope creep.

Paul M. Jones

unread,
Sep 28, 2014, 10:04:54 AM9/28/14
to php...@googlegroups.com

On Sep 28, 2014, at 9:00 AM, Philip Sturgeon <pjstu...@gmail.com> wrote:

> Still got 50 miles to ride so in smashing this out over lunch.
...
> We aren't doing the client bit, just the request and the response.
...
> Making this into a HTTP client would certainly be scope creep.

Given that you are "smashing this out" you may have read this in a rush.

To be clear, I am definitely *not* talking about expanding PSR-7 into an HTTP client.

I am talking about, when PHP itself is acting as a client that uses PSR-7 messages, PHP has one set of needs; when PHP itself is acting as a server that uses PSR-7 messages, PHP has a somewhat different (or expanded) set of needs.

Philip Sturgeon

unread,
Sep 28, 2014, 6:54:10 PM9/28/14
to php...@googlegroups.com
Gotcha. I've re-read and I now see what you mean, but only because you explained in the last message. :)

I think server implementations will be just fine taking the URL and using other code to split it up. We don't need to care what they do there or how, we just document the raw message and let them use parse_url() or league\url or whatever else.

Right? Are there other examples of problems that I'm not thinking of?

Paul M. Jones

unread,
Sep 28, 2014, 7:24:34 PM9/28/14
to php...@googlegroups.com

On Sep 28, 2014, at 5:54 PM, Philip Sturgeon <pjstu...@gmail.com> wrote:

> I think server implementations will be just fine taking the URL and using other code to split it up. We don't need to care what they do there or how, we just document the raw message and let them use parse_url() or league\url or whatever else.

That's part of my points about "making extra work" and "re-parsing every time". Also, the return result of getUrl() (or whatever) will be different depending on the implementation, meaning there's no standard for it. Then there retrieval of $_GET, $_POST, $_FILES, and other values in a standard way. Etc etc.

Like I said, for PSR-7 a Request to be truly useful as a standard all-purpose generic "incoming Request", it needs more fleshing out. As an "outgoing Request" it is as pretty close to complete.

Philip Sturgeon

unread,
Sep 30, 2014, 2:36:25 PM9/30/14
to php...@googlegroups.com
Inline


On Sunday, September 28, 2014 7:24:34 PM UTC-4, pmjones wrote:

On Sep 28, 2014, at 5:54 PM, Philip Sturgeon <pjstu...@gmail.com> wrote:

> I think server implementations will be just fine taking the URL and using other code to split it up. We don't need to care what they do there or how, we just document the raw message and let them use parse_url() or league\url or whatever else.

That's part of my points about "making extra work" and "re-parsing every time".

Re-parsing every time? Why? You ask for the body then work with it. An implementation could cache the hit on php://input. What use-cases lead to re-parsing? 
 
Also, the return result of getUrl() (or whatever) will be different depending on the implementation, meaning there's no standard for it.

No I mean you just get the URL and tada. A message is the following: 
  • Status Code
  • Host
  • URL (eeeeverything, not just a path or 
  • Headers
  • Body (which is maybe a stream?)
Nothing else. Maybe the getUrl() smashes host + url together, or maybe its two methods, but we define that in the standard once and thats that. I dont see how it could be different for different people.  

Then there retrieval of $_GET, $_POST, $_FILES, and other values in a standard way. Etc etc.

I think we've probably discusses this already but I dont think that has any place in the HTTP Message interface, because files, post items, etc are a bit out of scope of the actual message itself. They - like cookies - are contracts between server and PHP that do certain stuff, but its a layer on top of the message, and has more to do with the server or client than anything else.

If we start adding convenience methods for files and cookies, do we have to add them for Authentication and proxies and etags etc? When does it stop? 

Or, do we just use this message to define the raw messages and let those get passed around by clients and servers and set up in controllers at a super basic level, so we have at least one base to work off.

Paul M. Jones

unread,
Sep 30, 2014, 6:39:10 PM9/30/14
to php...@googlegroups.com

On Sep 30, 2014, at 1:36 PM, Philip Sturgeon <pjstu...@gmail.com> wrote:

>> Then there retrieval of $_GET, $_POST, $_FILES, and other values in a standard way. Etc etc.
>
> I think we've probably discusses this already but I dont think that has any place in the HTTP Message interface, because files, post items, etc are a bit out of scope of the actual message itself.

This gets to the heart of what I'm talking about. If we are going to specify something for interoperable server-side pieces of code to work with, it should probably have easy access to these (and other) things that are already provided by PHP. Again: they are already derived from the incoming request by PHP, and so I assert we should expose them through the "incoming Request" object.


> If we start adding convenience methods for files and cookies, do we have to add them for Authentication and proxies and etags etc? When does it stop?

A fair question. As a first heuristic, perhaps if PHP itself has constructed something from the Request in some fashion, we should consider providing the same thing. If PHP itself has not done so, we should consider also not doing so.

Paul M. Jones

unread,
Sep 30, 2014, 6:42:55 PM9/30/14
to php...@googlegroups.com

On Sep 30, 2014, at 1:36 PM, Philip Sturgeon <pjstu...@gmail.com> wrote:

> Inline
>
> On Sunday, September 28, 2014 7:24:34 PM UTC-4, pmjones wrote:
>
> On Sep 28, 2014, at 5:54 PM, Philip Sturgeon <pjstu...@gmail.com> wrote:
>
> > I think server implementations will be just fine taking the URL and using other code to split it up. We don't need to care what they do there or how, we just document the raw message and let them use parse_url() or league\url or whatever else.
>
>> That's part of my points about "making extra work" and "re-parsing every time".
>
> Re-parsing every time? Why? You ask for the body then work with it. An implementation could cache the hit on php://input. What use-cases lead to re-parsing?

I failed to respond to this earlier. That's an easy one to illustrate.

Middleware Foo needs a $_POST value, so it parses php://input and grabs that value. Middleware Bar needs a $_POST value, so it parses php://input and grabs that value. Middleware Baz needs a $_POST value, so it parses php://input and grabs that value. Middleware Dib needs a $_POST value, so it parses php://input and grabs that value. And so on.

The alternative is that each Middleware reads $request->getPost('whatever') and doesn't have to re-parse.

Philip Sturgeon

unread,
Oct 1, 2014, 12:39:27 PM10/1/14
to php...@googlegroups.com
If these middlewares have access to a $request instance for the sake of getPost(), why could they not have the same access to $request for getBody()? Why are they running off to php://input each time? 

Alessandro Pellizzari

unread,
Oct 2, 2014, 4:34:10 AM10/2/14
to php...@googlegroups.com
On 2014-10-01 17:39, Philip Sturgeon wrote:

Hi all,

I'm new here. I have been following this PSR because I am particularly
interested in it.

> On Tuesday, September 30, 2014 6:42:55 PM UTC-4, pmjones wrote:

>> Middleware Foo needs a $_POST value, so it parses php://input and
>> grabs that value. Middleware Bar needs a $_POST value, so it parses
>> php://input and grabs that value. Middleware Baz needs a $_POST
>> value, so it parses php://input and grabs that value. Middleware Dib
>> needs a $_POST value, so it parses php://input and grabs that value.
>> And so on.

> If these middlewares have access to a $request instance for the sake
> of getPost(), why could they not have the same access to $request for
> getBody()? Why are they running off to php://input each time?

I agree with P.M. Jones here, unless your getBody() method returns an
array with all the body variables.

If getBody() simply returns a dump of the request body received from
the client and a middleware (or a controller) needs to get the
Content-type header from the request, parse the body to find the
variable it needs, potentially checking for !isset or for null, then a
Request object is of very little use, and every framework will implement
it in a different way (provide a getPost that returns a string, or an
array, or an object, or an array of objects, etc.), making the PSR
useless, IMO.

If getBody() returns an array of values, then the name is wrong. It
should be getBodyParsed() or getBodyVars() or something like that.

Bye.

Matthew Weier O'Phinney

unread,
Oct 2, 2014, 7:07:29 PM10/2/14
to php...@googlegroups.com
Grr... Despite updating my subscription preferences, and double checking my filters, it appears I'm only getting the occasional message to my account, and nothing in this thread. (In fact, this thread did not show for me on the website even until an hour ago.)

Anyways... I think all of Paul's concerns are now addressed with the proposed IncomingRequestInterface.

Reply all
Reply to author
Forward
0 new messages