Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that may
have been out of the question in PHP 5.
I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.
The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw request/response
messages in any way the user deems fit. This alleviates cases like "what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.
Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no the
implementation itself. To remove all confusion, consider the way an HTTP
message actually looks.
GET /foo?bar=1 HTTP/1.1
Host: foobar.com
baz=2
Instead of treating this with current $_GET, $_POST, let's consider for a
moment how we might treat it in an HttpRequest object:
If the HttpRequest class implements an HttpParameters object that parses
and treats the entire HTTP request line as a string of parameters we could
accomplish the following...
var_dump(HttpRequest::$parameters->bar); // int(1)
var_dump((string) HttpRequest::$parameters); // string(6)"?bar=1"
Now consider how the body can be treated...
echo HttpRequest::$body; // baz=2
echo HttpRequest::$body->baz; // 2
Since the HttpRequest object can lazily parse the body it can also lazily
apply custom filters directly to the request variables and parameters...
For example, say you wish to treat baz only as an integer? This can be
easily accomplished by setting the filters directly in the HttpRequest
object and upon access the filter is directly applied to chosen variables.
This also alleviates the need to worry about overwriting superglobal
variables or having to copy from them. So from an efficiency stand-point
this approach works much better. It also allows you to separate clearly
between HTTP request parameters and HTTP request body as well as the HTTP
request method. Since the request object should be capable of handling
callbacks for each method to apply different sets of filters or rules on
treating the request body given different request methods this could prove
a lot more useful than existing techniques applied directly in PHP with
php://input, for example.
We don't need to copy the internal stream and we don't need to modify or
copy superglobals around to different parts of our code.
I'm in the process of writing up a cleaner implementation to introduce in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.
Thanks,
Sherif
Hi,
On Thu, Oct 30, 2014 at 7:23 PM, Sherif Ramadan theanomaly.is@gmail.com
wrote:
Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that may
have been out of the question in PHP 5.I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw request/response
messages in any way the user deems fit. This alleviates cases like "what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no the
implementation itself.
I find this very... useless. Sure, interfaces are not useless. But I don't
think php-src is there to dictate what userland code should look like. It
should provide implementations, not interfaces.
To remove all confusion, consider the way an HTTP
message actually looks.GET /foo?bar=1 HTTP/1.1
Host: foobar.combaz=2
Instead of treating this with current $_GET, $_POST, let's consider for a
moment how we might treat it in an HttpRequest object:If the HttpRequest class implements an HttpParameters object that parses
and treats the entire HTTP request line as a string of parameters we could
accomplish the following...var_dump(HttpRequest::$parameters->bar); // int(1)
var_dump((string) HttpRequest::$parameters); // string(6)"?bar=1"Now consider how the body can be treated...
echo HttpRequest::$body; // baz=2
echo HttpRequest::$body->baz; // 2Since the HttpRequest object can lazily parse the body it can also lazily
apply custom filters directly to the request variables and parameters...For example, say you wish to treat baz only as an integer? This can be
easily accomplished by setting the filters directly in the HttpRequest
object and upon access the filter is directly applied to chosen variables.
This also alleviates the need to worry about overwriting superglobal
variables or having to copy from them. So from an efficiency stand-point
this approach works much better. It also allows you to separate clearly
between HTTP request parameters and HTTP request body as well as the HTTP
request method. Since the request object should be capable of handling
callbacks for each method to apply different sets of filters or rules on
treating the request body given different request methods this could prove
a lot more useful than existing techniques applied directly in PHP with
php://input, for example.We don't need to copy the internal stream and we don't need to modify or
copy superglobals around to different parts of our code.I'm in the process of writing up a cleaner implementation to introduce in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.Thanks,
Sherif
The other thing I don't like in your RFC is the removal of superglobals.
Sure, they're not the best interface out there, but breaking every single
codebase out there is not the way to go. Especially if we don't want a
perl6/python3-like failure to adoption.
Regards,
--
Florian Margaine
Florian Margaine wrote on 30/10/2014 18:30:
Hi,
On Thu, Oct 30, 2014 at 7:23 PM, Sherif Ramadan theanomaly.is@gmail.com
wrote:Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no the
implementation itself.I find this very... useless. Sure, interfaces are not useless. But I don't
think php-src is there to dictate what userland code should look like. It
should provide implementations, not interfaces.
Agreed, I still don't understand the purpose of SplObserver and
SplSubject, for instance. To be fair, it's not clear from this early
stage whether the RFC is going to define interfaces with a special
relationship to core, more like Countable or Iterable.
The other thing I don't like in your RFC is the removal of superglobals.
Sure, they're not the best interface out there, but breaking every single
codebase out there is not the way to go. Especially if we don't want a
perl6/python3-like failure to adoption.
Yes, this; 1000 times this! I will lay you a bet that if the RFC reaches
a vote with the intention to remove superglobals in tact, it will not
pass. If that is removed and it provides a useful alternative to
superglobals, that allows things not currently possible (e.g. callback
request-response patterns, rather than the current
one-process-per-thread CGI-style model), then it might be useful.
If all you're after is standardised handling in userland, then this is
better addressed to PHP-FIG to publish an advisory set of interfaces
that major frameworks can transition to from whatever handling they have
currently.
--
Rowan Collins
[IMSoP]
On Thu, Oct 30, 2014 at 2:30 PM, Florian Margaine florian@margaine.com
wrote:
I find this very... useless. Sure, interfaces are not useless. But I don't
think php-src is there to dictate what userland code should look like. It
should provide implementations, not interfaces.
Well, let's look at how well providing implementation has worked out for
PHP so far.
GPC variables are implementation. They pose rigidity to userland code for a
number of reasons. For example, if you do send a PUT request to PHP, PHP
will not bother populating GPC at all. Instead it leaves the user to define
their own handling from the input stream directly. If you do send GET/POST
requests to PHP, the variable names can be mangled and $_GET/$_POST are
treated differently for encoding as one is run through url_decode and the
other is not. $_FILES is also an awkward one as the array is backwardly
multidimensional in that $_FILES['userfile'][$meta] are each partitioned
rather than having a more intuitive structure wherein one can iterate over
the $_FILES['userfile'] array directly.
Takeaway: PHP offering up implementation makes userland more rigid. PHP
offering up an interface makes userland inherently more appealing and
extensible. Take the session interface as one example where we one with
interface over implementation.
The other thing I don't like in your RFC is the removal of superglobals.
Sure, they're not the best interface out there, but breaking every single
codebase out there is not the way to go. Especially if we don't want a
perl6/python3-like failure to adoption.
I think pitting the Perl 6 and Python 3 scenarios as failure to adoption is
like lumping together the Betamax with the Blackberry. Perl 6 failed for a
number of reasons, not one of which was an effort to revamp antiquated
interfaces. Calling Python 3 a failure to adopt, is a bit ambitious. I
don't think people have failed to adopted Python 3.
I will tell you what will surely lead to failure, though. When we begin
ignoring the problem. Because then we are insisting that the proposed
solutions are useless since there is no problem to solve. There is an
evident problem in the way PHP handles the incoming Http Request and how it
makes it accessible to userland. Whether or not this solution is optimal
remains to be seen, but to say that the problem itself is non-existent is
pure denial without basis.
A failure to act is worse than an act of failure.
Regards,
--
Florian Margaine
Well, let's look at how well providing implementation has worked out for
PHP so far.GPC variables are implementation. They pose rigidity to userland code for a
number of reasons. For example, if you do send a PUT request to PHP, PHP
will not bother populating GPC at all. Instead it leaves the user to define
their own handling from the input stream directly. If you do send GET/POST
requests to PHP, the variable names can be mangled and $_GET/$_POST are
treated differently for encoding as one is run through url_decode and the
other is not.
We could just fix these problems rather than adding an entirely new implementation.
Andrea Faulds
http://ajf.me/
On 30 Oct 2014, at 19:49, Sherif Ramadan theanomaly.is@gmail.com
wrote:Well, let's look at how well providing implementation has worked out for
PHP so far.GPC variables are implementation. They pose rigidity to userland code
for a
number of reasons. For example, if you do send a PUT request to PHP, PHP
will not bother populating GPC at all. Instead it leaves the user to
define
their own handling from the input stream directly. If you do send
GET/POST
requests to PHP, the variable names can be mangled and $_GET/$_POST are
treated differently for encoding as one is run through url_decode and the
other is not.We could just fix these problems rather than adding an entirely new
implementation.
Yes, this proposal is intended to do two things. 1) Fix the aforementioned
problems. 2) Improve upon the capabilities of PHP's request handling for
future use cases through a unified interface.
To say that this proposal and fixing the aforementioned problems are two
distinct options (as in we can either fix these problems or go with this
proposal) is a very reductive form of thinking in which the only outcome
favors one party or the other.
My proposal is intended to result in a win-win situation where everyone
involved can be satisfied, not an ultimatum.
If you consider all of the major existing PHP frameworks today there is
always some form of HttpRequest class handling these things and almost all
of them do it slightly differently. What's worse, is they are all very
inefficient implementations that I believe can be done far more efficiently
in php-src. A lost of them are also unnecessarily complex. I think all of
this can be simplified if the interface is just laid out in a
straight-forward manner and then userland implementations will find less
and less reason to over-engineer the implementation.
--
Andrea Faulds
http://ajf.me/
Yes, this proposal is intended to do two things. 1) Fix the aforementioned problems.
By the sounds of things, it doesn’t fix these problems, it just adds a new interface which lacks them. That’s not the same thing.
- Improve upon the capabilities of PHP's request handling for future use cases through a unified interface.
What unified interface? You’re allowing anyone and everyone to implement their own request handling.
If you consider all of the major existing PHP frameworks today there is always some form of HttpRequest class handling these things and almost all of them do it slightly differently. What's worse, is they are all very inefficient implementations that I believe can be done far more efficiently in php-src. A lost of them are also unnecessarily complex. I think all of this can be simplified if the interface is just laid out in a straight-forward manner and then userland implementations will find less and less reason to over-engineer the implementation.
The only reason an implementation of HttpRequest would be inefficient is because it has to work-around problems with $_GET and $_POST. Problems we could simply fix.
--
Andrea Faulds
http://ajf.me/
On 30 Oct 2014, at 20:33, Sherif Ramadan theanomaly.is@gmail.com
wrote:Yes, this proposal is intended to do two things. 1) Fix the
aforementioned problems.By the sounds of things, it doesn’t fix these problems, it just adds a new
interface which lacks them. That’s not the same thing.
No, the interface makes it possible to implement your own behavior, but it
does not prevent PHP from implementing default behavior. In that PHP would
implement its own HttpRequest class, for example, which the user can then
extend to override default behavior or modify it as they see fit for their
particular use case. This is much like the Session interface, which makes
it possible to change session storage mechanisms in userland, but still
have a confirming method of session handling in PHP.
- Improve upon the capabilities of PHP's request handling for future
use cases through a unified interface.What unified interface? You’re allowing anyone and everyone to implement
their own request handling.
Yes, by allowing this you make it extensible. However, having the interface
is what makes it possible to unify the efforts of dealing with the HTTP
messages both in userland and in PHP internals.
If you consider all of the major existing PHP frameworks today there is
always some form of HttpRequest class handling these things and almost all
of them do it slightly differently. What's worse, is they are all very
inefficient implementations that I believe can be done far more efficiently
in php-src. A lost of them are also unnecessarily complex. I think all of
this can be simplified if the interface is just laid out in a
straight-forward manner and then userland implementations will find less
and less reason to over-engineer the implementation.The only reason an implementation of HttpRequest would be inefficient is
because it has to work-around problems with $_GET and $_POST. Problems we
could simply fix.
So the fix to something like PUT/DELETE requests is to add yet another
superglobal. However, this is still a very rigid fix that requires
continuous maintenance and fulfilling feature requests on the part of
internals. Think of implementing a new session handler for every session
storage mechanism in PHP. This is a lot of unneeded effort when we can just
expose the session interface to userland and make it extensible by nature.
The alternative is far more useful and less closed up (preventing future
problems to fix).
Let's not also ignore the fact that such features have been forsaken by PHP
internals for years. I have bug reports dating back to 2010 that have asked
for such features that have long been unanswered. So the current desire to
fix anything along these lines appears to be minimal, if not non-existent,
right now.
--
Andrea Faulds
http://ajf.me/
No, the interface makes it possible to implement your own behavior, but it does not prevent PHP from implementing default behavior. In that PHP would implement its own HttpRequest class, for example, which the user can then extend to override default behavior or modify it as they see fit for their particular use case. This is much like the Session interface, which makes it possible to change session storage mechanisms in userland, but still have a confirming method of session handling in PHP.
You know, before I keep up this discussion, it’d be nice if you clarified what, exactly, you are proposing. The RFC contains no detail at all. I really haven’t the faintest.
Also, removing $_GET and $_POST is a massive backwards-compatibility break. I would vote against this proposal and I hope everyone else will join me in doing so, for that reason alone.
Please, don’t completely break every single PHP site I’ve ever written. :(
So the fix to something like PUT/DELETE requests is to add yet another super global.
No, not really. $_PUT and $_DELETE don’t really make sense, why are you sending form data to PUT or DELETE? Populating $_POST also makes sense, it’s not a POST request. The answer is just to add a function to do multipart parsing, to expose PHP’s current parser, which satisfies the obscure use case of needing form data parsing for PUT and DELETE. I don’t think this would be too hard to do.
Andrea Faulds
http://ajf.me/
No, the interface makes it possible to implement your own behavior, but it does not prevent PHP from implementing default behavior. In that PHP would implement its own HttpRequest class, for example, which the user can then extend to override default behavior or modify it as they see fit for their particular use case. This is much like the Session interface, which makes it possible to change session storage mechanisms in userland, but still have a confirming method of session handling in PHP.
You know, before I keep up this discussion, it’d be nice if you clarified what, exactly, you are proposing. The RFC contains no detail at all. I really haven’t the faintest.
Also, removing $_GET and $_POST is a massive backwards-compatibility break. I would vote against this proposal and I hope everyone else will join me in doing so, for that reason alone.
Please, don’t completely break every single PHP site I’ve ever written. :(
So the fix to something like PUT/DELETE requests is to add yet another super global.
No, not really. $_PUT and $_DELETE don’t really make sense, why are you sending form data to PUT or DELETE? Populating $_POST also makes sense, it’s not a POST request. The answer is just to add a function to do multipart parsing, to expose PHP’s current parser, which satisfies the obscure use case of needing form data parsing for PUT and DELETE. I don’t think this would be too hard to do.
It's not hard. Again, pecl/http v2 proposal will give core everything it needs. I honestly don't know why this is being discussed any further when theirs a solution that gives functionality requested here and contains zero BC breaks.
--
Andrea Faulds
http://ajf.me/
Hi!
Also, removing $_GET and $_POST is a massive
backwards-compatibility break. I would vote against this proposal and
I hope everyone else will join me in doing so, for that reason
alone.
I think removing $_* is a no go and even discussing it is kind of
pointless unless somebody wants to create a completely new language only
barely connected to PHP. Creating a more advanced HTTP API is a good
thing, but I'd look to cooperate with pecl/http on that maybe?
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that may
have been out of the question in PHP 5.
snip
I'm in the process of writing up a cleaner implementation to introduce in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.Thanks,
Sherif
As you note, there's an enormous amount of existing and active
discussion around PSR-7 on the FIG mailing list, and I would urge anyone
pursuing such an effort for core to read through that discussion in
detail. There are a lot of tricky bits that we have been hashing
through that you don't want to hash through again, especially around
supported use cases.
In practice, honestly, I think userspace can experiment and innovate
here better than internals can, at least for a while. The main place
where core could help would be streams. One of the things we're still
struggling with is supporting message bodies (request or response) that
can be strings OR a stream, such as a file off disk that we don't want
in memory all at once, OR a callable that generates output on the fly
(say, reading records out of a DB and generating a CSV file).
Part of the problem is that the native streams API, while powerful, is
horribly annoying to work with. Michael Dowling has documented many of
the issues with it from a request/response perspective here:
http://mtdowling.com/blog/2014/07/03/a-case-for-higher-level-php-streams/
Honestly, I think one of the best things internals could do to help
really robust request/response support for PHP 7 isn't writing a new
interface, but improving the streams API in order to simplify the many
use cases we've identified (and render the whole "detach" stuff we're
looking at now unnecessary).
--Larry Garfield
So far there seems to be a lot of concern around BC, and particularly
removing or getting rid of GPC superglobals. So I completely understand the
concerns and hope to address them as clearly as possible.
First, for the sake of BC I think removing the superglobals from the
language should not be done here. Instead, for performance reasons, I'm
going to propose that the superglobals are not populated at the request
level. This means that the implementation is free to populate them at will
since they will still exist, but will be initialized to empty arrays by the
language.
Second, it's a valid concern that's there's no actual proposed interface.
So let me be begin by proposing a rough draft for one.
So let's consider the following interface layout and some sample
implementations as a start...
https://gist.github.com/srgoogleguy/f729053e3e88b2d2b3ec
Then let's consider the kind of flexibility this would allow userland in
terms of filtering, validating, and modifying the request data under
various conditions. Obviously, PHP has to provide some form of default
implementation so some base class HttpRequest can be implemented in PHP and
this can be easily extended by userland.
Also, take into consideration the kind of performance gains you might get
out of this by doing things like lazy-loading or lazy parsing or
lazy-filtering of request data. Filters also need not be applied at the
global level. PHP's default implementation would simply use the input
stream to populate GPC as normal (as it currently does), but I believe
introducing the base class will encourage others to make better use of
request/response handling in their own code.
So far there seems to be a lot of concern around BC, and particularly
removing or getting rid of GPC superglobals. So I completely understand the
concerns and hope to address them as clearly as possible.First, for the sake of BC I think removing the superglobals from the
language should not be done here. Instead, for performance reasons, I'm
going to propose that the superglobals are not populated at the request
level. This means that the implementation is free to populate them at will
since they will still exist, but will be initialized to empty arrays by the
language.
This is no less of a backwards-compatibility headache. This still breaks every PHP app I have ever written.
Second, it's a valid concern that's there's no actual proposed interface.
So let me be begin by proposing a rough draft for one.So let's consider the following interface layout and some sample
implementations as a start...https://gist.github.com/srgoogleguy/f729053e3e88b2d2b3ec
Then let's consider the kind of flexibility this would allow userland in
terms of filtering, validating, and modifying the request data under
various conditions. Obviously, PHP has to provide some form of default
implementation so some base class HttpRequest can be implemented in PHP and
this can be easily extended by userland.Also, take into consideration the kind of performance gains you might get
out of this by doing things like lazy-loading or lazy parsing or
lazy-filtering of request data. Filters also need not be applied at the
global level. PHP's default implementation would simply use the input
stream to populate GPC as normal (as it currently does), but I believe
introducing the base class will encourage others to make better use of
request/response handling in their own code.
No no, I'm not concerned about the contents of the interface. I'm wondering what, exactly, this "interface" does? I don't see how a mere interface would replace the superglobals, unless you want a superglobal request object that anyone can swap out, which sounds like a bad idea.
--
Andrea Faulds
http://ajf.me/
This is no less of a backwards-compatibility headache. This still breaks
every PHP app I have ever written.
To be perfectly clear, the default behavior would remain the same, so no
PHP app you have ever written would break. The difference is, you would now
be able to override any part of the default behavior by extending the
HttpRequest class in your own code.
No no, I'm not concerned about the contents of the interface. I'm
wondering what, exactly, this "interface" does? I don't see how a mere
interface would replace the superglobals, unless you want a superglobal
request object that anyone can swap out, which sounds like a bad idea.
The interfaces do exactly what you see here. They specified which methods
the HttpRequest and HttpResponse objects must implement.
If you bothered to invest nearly as much time in reading the updates to the
RFC as you did to making blanket statements and objections, you might
actually find less reason to respond with objections so abruptly. The
HttpRequest and HttpResponse classes are intended to provide a central
place for message handling behaviors and their properties can be used to
describe these behaviors.
So, if you wanted to support a $_PUT superglobal, rather than adding one to
the language, you can simply add the behavior to do the processing of PUT
requests in your HttpRequest class, by extending HttpRequest and defining
how PUT variables are handled there.
--
Andrea Faulds
http://ajf.me/
Sherif Ramadan wrote on 31/10/2014 14:30:
This is no less of a backwards-compatibility headache. This still breaks
every PHP app I have ever written.To be perfectly clear, the default behavior would remain the same, so no
PHP app you have ever written would break. The difference is, you would now
be able to override any part of the default behavior by extending the
HttpRequest class in your own code.No no, I'm not concerned about the contents of the interface. I'm
wondering what, exactly, this "interface" does? I don't see how a mere
interface would replace the superglobals, unless you want a superglobal
request object that anyone can swap out, which sounds like a bad idea.The interfaces do exactly what you see here. They specified which methods
the HttpRequest and HttpResponse objects must implement.If you bothered to invest nearly as much time in reading the updates to the
RFC as you did to making blanket statements and objections, you might
actually find less reason to respond with objections so abruptly. The
HttpRequest and HttpResponse classes are intended to provide a central
place for message handling behaviors and their properties can be used to
describe these behaviors.So, if you wanted to support a $_PUT superglobal, rather than adding one to
the language, you can simply add the behavior to do the processing of PUT
requests in your HttpRequest class, by extending HttpRequest and defining
how PUT variables are handled there.
I think the piece that's missing is how exactly these interfaces would
interact with core, or rather with the SAPIs which handle the actual
transfer of HTTP requests and responses.
Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive",
what do I then do with this class in order for it to perform any actions?
Presumably there will need to be some mechanism where I can register
this so that it is passed the actual data from the PHP SAPI?
In order to actually replace the default behaviour, this would need to
be an ini setting, since no PHP code can run before the default
superglobal behaviour occurs. Alternatively, it could be repeatable, by
having some global function like populate_http_message_object( new
AwesomeHTTPReceive );
Similarly, there would need to be some mechanism for tying up the
response object to the HTTP response to be issued by the SAPI, with some
way for existing functions such as header()
to interact with it
appropriately.
Rowan Collins
[IMSoP]
On Fri, Oct 31, 2014 at 11:56 AM, Rowan Collins rowan.collins@gmail.com
wrote:
I think the piece that's missing is how exactly these interfaces would
interact with core, or rather with the SAPIs which handle the actual
transfer of HTTP requests and responses.
PHP would have an HttpRequest class, as noted in the updated RFC, which
implements the HttpMessageReceive interface. The HttpRequest class's
default behavior would be to just populate the superglobals (i.e. having
the same net-effect as the current behavior).
If a user wanted to override that default behavior they would just extend
HttpRequest and implement the functions/methods they wanted to override.
Sherif Ramadan wrote on 31/10/2014 16:07:
On Fri, Oct 31, 2014 at 11:56 AM, Rowan Collins
<rowan.collins@gmail.com mailto:rowan.collins@gmail.com> wrote:I think the piece that's missing is how exactly these interfaces would interact with core, or rather with the SAPIs which handle the actual transfer of HTTP requests and responses.
PHP would have an HttpRequest class, as noted in the updated RFC,
which implements the HttpMessageReceive interface. The HttpRequest
class's default behavior would be to just populate the superglobals
(i.e. having the same net-effect as the current behavior).If a user wanted to override that default behavior they would just
extend HttpRequest and implement the functions/methods they wanted to
override.
Let me repeat my question:
Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive",
what do I then do with this class in order for it to perform any actions?
How does PHP know that my class is the one it should populate, or when
that population should happen?
On Fri, Oct 31, 2014 at 1:09 PM, Rowan Collins rowan.collins@gmail.com
wrote:
Let me repeat my question:
Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive",
what do I then do with this class in order for it to perform any actions?How does PHP know that my class is the one it should populate, or when
that population should happen?
It wouldn't. You would need to extend the base class, since it already
implements the necessary interface. PHP would simply call on the last
subtype of HttpRequest during the request init phase. Of course, this is an
implementation detail as of now. There could certainly be other/better ways
to accomplish this. I just want to keep it as simple as possible for now
without introducing more configuration nightmares that people often
complain about. I really don't like the idea of adding yet another INI
directive to control this behavior (making it harder to port).
What do you propose?
Hi,
Le 31 oct. 2014 18:28, "Sherif Ramadan" theanomaly.is@gmail.com a écrit :
On Fri, Oct 31, 2014 at 1:09 PM, Rowan Collins rowan.collins@gmail.com
wrote:Let me repeat my question:
Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive",
what do I then do with this class in order for it to perform any
actions?How does PHP know that my class is the one it should populate, or when
that population should happen?It wouldn't. You would need to extend the base class, since it already
implements the necessary interface. PHP would simply call on the last
subtype of HttpRequest during the request init phase.
What if there is multiple subtypes?
class A extends HttpRequest {}
class B extends HttpRequest {}
What happens there?
Of course, this is an
implementation detail as of now. There could certainly be other/better
ways
to accomplish this. I just want to keep it as simple as possible for now
without introducing more configuration nightmares that people often
complain about. I really don't like the idea of adding yet another INI
directive to control this behavior (making it harder to port).What do you propose?
Regards,
Florian Margaine
On Fri, Oct 31, 2014 at 1:32 PM, Florian Margaine florian@margaine.com
wrote:
Hi,
Le 31 oct. 2014 18:28, "Sherif Ramadan" theanomaly.is@gmail.com a écrit
:On Fri, Oct 31, 2014 at 1:09 PM, Rowan Collins rowan.collins@gmail.com
wrote:Let me repeat my question:
Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive",
what do I then do with this class in order for it to perform any
actions?How does PHP know that my class is the one it should populate, or when
that population should happen?It wouldn't. You would need to extend the base class, since it already
implements the necessary interface. PHP would simply call on the last
subtype of HttpRequest during the request init phase.What if there is multiple subtypes?
class A extends HttpRequest {}
class B extends HttpRequest {}What happens there?
As of now, all the subtypes would be called, i.e. if A has a receiveMessage
method, it would be handed the message, and if B has a receiveMessage
method it too would be handed the message. It's up to those methods to call
on subsequent parsing methods to do something with the message, obviously
any methods they don't implement are forwarded to the parent.
This clearly has some conflicts, like if default parsing is left we
overwrite superglobal variables. However, it also has benefits, in that we
can have multiple implementations for handling the request in the same code
base and it is left up to the user to decide which one to use.
So, again, this is still a draft and I'm open to suggestions about how to
handle/deal with such problems.
Of course, this is an
implementation detail as of now. There could certainly be other/better
ways
to accomplish this. I just want to keep it as simple as possible for now
without introducing more configuration nightmares that people often
complain about. I really don't like the idea of adding yet another INI
directive to control this behavior (making it harder to port).What do you propose?
Regards,
Florian Margaine
On Fri, Oct 31, 2014 at 1:32 PM, Florian Margaine florian@margaine.com
wrote:Hi,
Le 31 oct. 2014 18:28, "Sherif Ramadan" theanomaly.is@gmail.com a écrit
:On Fri, Oct 31, 2014 at 1:09 PM, Rowan Collins rowan.collins@gmail.com
wrote:Let me repeat my question:
Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive",
what do I then do with this class in order for it to perform any
actions?How does PHP know that my class is the one it should populate, or when
that population should happen?It wouldn't. You would need to extend the base class, since it already
implements the necessary interface. PHP would simply call on the last
subtype of HttpRequest during the request init phase.What if there is multiple subtypes?
class A extends HttpRequest {}
class B extends HttpRequest {}What happens there?
As of now, all the subtypes would be called, i.e. if A has a receiveMessage
method, it would be handed the message, and if B has a receiveMessage
method it too would be handed the message. It's up to those methods to call
on subsequent parsing methods to do something with the message, obviously
any methods they don't implement are forwarded to the parent.This clearly has some conflicts, like if default parsing is left we
overwrite superglobal variables. However, it also has benefits, in that we
can have multiple implementations for handling the request in the same code
base and it is left up to the user to decide which one to use.So, again, this is still a draft and I'm open to suggestions about how to
handle/deal with such problems.
I think the root problem is that you're solving an issue that doesn't exist.
You're talking about providing alternate ways to parse the raw HTTP
stream into user-accessible variables, ie, by pushing them into an
object of a known interface rather than/in addition to the superglobals.
In my 15 years of writing PHP I have never wanted to change the way the
raw HTTP is parsed. I have, however, frequently wanted to have the data
accessible in a more logical, semantic, and HTTP-correct way. ($_GET is
not about HTTP GET, it's about URI query parameters. $_POST isn't about
HTTP POST, it's about application/x-www-form-encoded. Etc.) And I've
wanted that information available in a non-global, OOP-injectable way.
But I've never once had any desire to change the way an
application/x-www-form-encoded is parsed.
Implementation problems aside, your proposal is not solving an extant
problem.
If we want to improve PHP's HTTP handling, then having an object that
exposes the HTTP request in a more logical fashion would be far more
useful, and/or providing that data in a more logical way so that someone
in user-space can provide that data in a logical fashion (eg, via a
PSR-7-implementing object.) I already stated in an earlier email what I
felt would be most beneficial for internals to do toward that goal
(specifically, clean up the streams API so that we can use it directly
from an OOP world rather than a 1980s C world.)
IF internals wanted to add implementation, not just improving streams,
something like the following would be much more useful:
$request = http_get_request(PHP_STDIN); // or something
Where $request is an object that implements the PSR-7 RequestInterface
(or at least the read-only parts of it), or something similar. Then
implementers can compose that object however they want.
Although at least for the near term I think it's better to not do that
and just do the lower-level plumbing to make FIG's work with PSR-7 easier.
--Larry Garfield
So for the purposes of this discussion and in an effort to remain on-topic
and productive, let's keep all of the FIG/PSR and other third party efforts
out of the discussion unless it is intended to improve/help this particular
RFC. Please keep in mind that this is a PHP internals discussion and not a
FIG/PSR discussion. This RFC is about core PHP and I really don't care how
many competing ideas exist out there that are closely or mildly related to
this RFC.
This RFC has two primary goals in mind:
- Expose the parsing/handling of the HTTP request to userland in a
consistent way - Avoid having the request parsed/mangled at multiple levels during the
request by presenting one central place to handle the parsing
These goals can not be achieved purely in userland, because you would
potentially have to do the parsing step twice. I wish to make it possible
for the user to override that with their own implementation just like they
can override the Session handler with the Session interface.
How we end up deciding to do that may change from my initial proposal, and
that's fine, but let's focus on that rather than getting off topic about
other third party efforts.
Thanks!
So for the purposes of this discussion and in an effort to remain on-topic
and productive, let's keep all of the FIG/PSR and other third party efforts
out of the discussion unless it is intended to improve/help this particular
RFC. Please keep in mind that this is a PHP internals discussion and not a
FIG/PSR discussion. This RFC is about core PHP and I really don't care how
many competing ideas exist out there that are closely or mildly related to
this RFC.
Discussing prior-art for a proposal is entirely on topic. We do it all
the time when comparing PHP to other languages and their syntax, for
example. Internals should be informed by user-space usage patterns.
This RFC has two primary goals in mind:
- Expose the parsing/handling of the HTTP request to userland in a
consistent way
It already is. It's the access TO that parsed data that is currently
clunky. That's a problem worth addressing.
- Avoid having the request parsed/mangled at multiple levels during the
request by presenting one central place to handle the parsing
This only applies to the body of a request; other properties have
well-defined and not really variable parsing rules called HTTP.
A better way to parse the body is useful, and we've been discussing that
in FIG. Please look at the existing discussions and prior art before
continuing. That's also a much smaller, tighter discussion than
request/response interfaces.
These goals can not be achieved purely in userland, because you would
potentially have to do the parsing step twice. I wish to make it possible
for the user to override that with their own implementation just like they
can override the Session handler with the Session interface.How we end up deciding to do that may change from my initial proposal, and
that's fine, but let's focus on that rather than getting off topic about
other third party efforts.Thanks!
Those 3rd party efforts are entirely on topic. That's the point.
--Larry Garfield
On Fri, Oct 31, 2014 at 3:00 PM, Larry Garfield larry@garfieldtech.com
wrote:
This RFC has two primary goals in mind:
- Expose the parsing/handling of the HTTP request to userland in a
consistent wayIt already is. It's the access TO that parsed data that is currently
clunky. That's a problem worth addressing.
No, it's not. There is no way for you to prevent PHP from populating
superglobals, or change the way PHP mangles variable names, or change the
fact that PHP won't bother populating data in $_FILES or $_GET/$_POST when
the request method is PUT or if the content-type is not multipart, for
example. None of this is exposed to userland.
Sherif Ramadan wrote on 31/10/2014 18:52:
This RFC is about core PHP and I really don't care how
many competing ideas exist out there that are closely or mildly related to
this RFC.
The decision about whether this is needed in core is not something you
can ignore by saying "this is about core". The fact that PHP-FIG is
working on something very closely related to this makes a difference to
that question, and pretending that's irrelevant is not constructive.
On Fri, Oct 31, 2014 at 3:35 PM, Rowan Collins rowan.collins@gmail.com
wrote:
Sherif Ramadan wrote on 31/10/2014 18:52:
This RFC is about core PHP and I really don't care how
many competing ideas exist out there that are closely or mildly related to
this RFC.The decision about whether this is needed in core is not something you
can ignore by saying "this is about core". The fact that PHP-FIG is working
on something very closely related to this makes a difference to that
question, and pretending that's irrelevant is not constructive.
First of all, I'm not ignoring anything. I very much appreciate all of your
input. However, reiterating what you've already said with every single one
of your responses attempting to derail this discussion into a matter that
concerns FIG or PSR or whatever other third party concern that is
tangentially related to the word HTTP is something I will not stand for.
I read what you've had to say about FIG and PSR and I'm taking it into
consideration. That doesn't mean I have to yield to your preference. Nor
does that mean this RFC has now become irrelevant because somewhere on
planet earth someone has come up with a competing idea/concept. I welcome
competition. That is only beneficial to PHP.
If you would like to further this discussion beyond reiterating the words
PSR and FIG then please explain to me how what you're talking about solves
any of the problems I'm attempting to solve with this RFC? Namely, how does
this PSR solve the problem that PHP will not populate $_FILES or $_POST if
a multipart PUT request is sent to PHP? Pointing out specifics, using
references, and providing any additional examples/documentation is more
than welcome if it will help me improve this RFC (but only if it is geared
toward the same goals that this RFC has).
Thanks
On Fri, Oct 31, 2014 at 3:35 PM, Rowan Collins rowan.collins@gmail.com
wrote:Sherif Ramadan wrote on 31/10/2014 18:52:
This RFC is about core PHP and I really don't care how
many competing ideas exist out there that are closely or mildly related to
this RFC.The decision about whether this is needed in core is not something you
can ignore by saying "this is about core". The fact that PHP-FIG is working
on something very closely related to this makes a difference to that
question, and pretending that's irrelevant is not constructive.First of all, I'm not ignoring anything. I very much appreciate all of your
input. However, reiterating what you've already said with every single one
of your responses attempting to derail this discussion into a matter that
concerns FIG or PSR or whatever other third party concern that is
tangentially related to the word HTTP is something I will not stand for.
While not too specific to Rowan, reiterating the pecl/http approach is indirectly what your asking for? I have mentioned this numerous times, but you haven’t responded with a reason not to take this approach - which is an RFC that was presented for discussion prior to yours. Forgetting about FIG or PSR, if pecl/http v2 made it into core/ext, would this not satisfy your concerns described in your RFC and conversations?
We’re spinning wheels here, and so many, mostly core developers, have been reiterating the resistance to superglobals, and rightfully so. I would suggest either concentrating the efforts you’re trying here towards existing efforts (pecl/http), or present a better approach.
I read what you've had to say about FIG and PSR and I'm taking it into
consideration. That doesn't mean I have to yield to your preference. Nor
does that mean this RFC has now become irrelevant because somewhere on
planet earth someone has come up with a competing idea/concept. I welcome
competition. That is only beneficial to PHP.If you would like to further this discussion beyond reiterating the words
PSR and FIG then please explain to me how what you're talking about solves
any of the problems I'm attempting to solve with this RFC? Namely, how does
this PSR solve the problem that PHP will not populate $_FILES or $_POST if
a multipart PUT request is sent to PHP? Pointing out specifics, using
references, and providing any additional examples/documentation is more
than welcome if it will help me improve this RFC (but only if it is geared
toward the same goals that this RFC has).Thanks
While not too specific to Rowan, reiterating the pecl/http approach is
indirectly what your asking for? I have mentioned this numerous times, but
you haven’t responded with a reason not to take this approach - which is an
RFC that was presented for discussion prior to yours.
I'm trying to understand how pecl/http solves the aforementioned problem
any better? Again, I have no problem with competing ideas and it's not as
though one is prohibited from presenting an idea for the mere fact that
there exists a competing one. I'm just not seeing how pecl/http solves the
problem I intend to solve better. The reason I haven't responded to you yet
is because I'm stilling weighing the two to try and make sense of whether
or not these are in fact competing ideas or complimenting ones.
Please, feel free to weigh in with anything that contradicts or concludes
what I'm saying. I certainly don't expect to have all of the answers.
While not too specific to Rowan, reiterating the pecl/http approach is indirectly what your asking for? I have mentioned this numerous times, but you haven’t responded with a reason not to take this approach - which is an RFC that was presented for discussion prior to yours.
I'm trying to understand how pecl/http solves the aforementioned problem any better? Again, I have no problem with competing ideas and it's not as though one is prohibited from presenting an idea for the mere fact that there exists a competing one. I'm just not seeing how pecl/http solves the problem I intend to solve better. The reason I haven't responded to you yet is because I'm stilling weighing the two to try and make sense of whether or not these are in fact competing ideas or complimenting ones.
Please, feel free to weigh in with anything that contradicts or concludes what I'm saying. I certainly don't expect to have all of the answers.
What doesn’t pecl/http solve under your situation? The fact that’s it’s not directly integrated as part of ZE and handling process?
I certainly have no problem with competing ideas either. However, the only proposed patch in this RFC is a gist with PHP pseudocode.
On Oct 31, 2014, at 4:21 PM, Sherif Ramadan theanomaly.is@gmail.com
wrote:While not too specific to Rowan, reiterating the pecl/http approach is
indirectly what your asking for? I have mentioned this numerous times, but
you haven’t responded with a reason not to take this approach - which is an
RFC that was presented for discussion prior to yours.I'm trying to understand how pecl/http solves the aforementioned problem
any better? Again, I have no problem with competing ideas and it's not as
though one is prohibited from presenting an idea for the mere fact that
there exists a competing one. I'm just not seeing how pecl/http solves the
problem I intend to solve better. The reason I haven't responded to you yet
is because I'm stilling weighing the two to try and make sense of whether
or not these are in fact competing ideas or complimenting ones.Please, feel free to weigh in with anything that contradicts or concludes
what I'm saying. I certainly don't expect to have all of the answers.What doesn’t pecl/http solve under your situation? The fact that’s it’s
not directly integrated as part of ZE and handling process?
Well, you're the one suggesting an alternative. The onus is on you to prove
that it solves the same problem, not me. However, I'll bite for the
purposes of moving the discussion along...
As far as I understand, pecl/http attempts to solve a much larger scope of
problems than this RFC. Namely, dealing with HTTP messages in general,
whether they are a part of PHP's request/response model or not. i.e. there
is no direct integration of the PHP request into pecl/http and as such it
doesn't directly solve a problem such as properly parsing the HTTP request
body during a PUT request and properly populating the $_FILES/$_POST
superglobals. It also doesn't solve similar problems where a transport
message body is sent entirely in JSON to PHP and PHP is responsible for
handling.
Of course, yes, you can do accomplish this today with some hacks like using
the php://input stream, but it's only up until recently that this stream
has become reusable. It's also potentially creating some duplication, but
albeit this isn't the only problem.
This RFC also attempts to make it possible for users to directly apply
filters to input from the HTTP request so that they can simply retrieve the
fitlered data from the HttpRequest object directly without having to do
things like $foo = isset($_POST['foo']) ? filter_var($_POST['foo'],
FILTER_VAR_INT) : 0; // for example
I have nothing against pecl/http. I think it's a very useful library and
Mike seems to have put a great deal of work into it. I would gladly vote it
into PHP core. I'm just not clear on how it solves the same problems this
RFC attempts to solve. They can actually compliment each other in some
areas; I can see that.
I certainly have no problem with competing ideas either. However, the only
proposed patch in this RFC is a gist with PHP pseudocode.
It's not pseudocode since it's actually perfectly valid PHP code that will
compile and run in the PHP interpreter. However, it is intended to
demonstrate the behavior. The pecl/http RFC is also further along as it's
in discussion phase with an actual implementation. This RFC is merely a
draft, with no actual implementation proposed yet (but that's not at all
uncommon as many RFCs proposed in PHP did not provide an actual
implementation until after they were voted in: generators, list in foreach,
and finally are among a small number that come to mind). So let's not get
hung up on implementation being the barrier to entry for an RFC as that's
never ever been the case in the past.
It is, however, entirely understandable that the RFC should explain the
actual behavior and consequences as well as possible if it does not provide
an actual implementation. This is just a very early stage discussion to
gather ideas so that I can improve and finalize the RFC. I have not
actually placed the RFC into discussion or voting phase just yet. So let's
not put the cart before the horse.
On Oct 31, 2014, at 4:21 PM, Sherif Ramadan theanomaly.is@gmail.com
wrote:While not too specific to Rowan, reiterating the pecl/http approach is
indirectly what your asking for? I have mentioned this numerous times, but
you haven’t responded with a reason not to take this approach - which is an
RFC that was presented for discussion prior to yours.I'm trying to understand how pecl/http solves the aforementioned problem
any better? Again, I have no problem with competing ideas and it's not as
though one is prohibited from presenting an idea for the mere fact that
there exists a competing one. I'm just not seeing how pecl/http solves the
problem I intend to solve better. The reason I haven't responded to you yet
is because I'm stilling weighing the two to try and make sense of whether
or not these are in fact competing ideas or complimenting ones.Please, feel free to weigh in with anything that contradicts or concludes
what I'm saying. I certainly don't expect to have all of the answers.What doesn’t pecl/http solve under your situation? The fact that’s it’s
not directly integrated as part of ZE and handling process?Well, you're the one suggesting an alternative. The onus is on you to prove
that it solves the same problem, not me. However, I'll bite for the
purposes of moving the discussion along…
I’m actually not suggesting an alternative - I’m suggesting this RFC isn’t an option.
As far as I understand, pecl/http attempts to solve a much larger scope of
problems than this RFC. Namely, dealing with HTTP messages in general,
whether they are a part of PHP's request/response model or not. i.e. there
is no direct integration of the PHP request into pecl/http and as such it
doesn't directly solve a problem such as properly parsing the HTTP request
body during a PUT request and properly populating the $_FILES/$_POST
superglobals. It also doesn't solve similar problems where a transport
message body is sent entirely in JSON to PHP and PHP is responsible for
handling.
Sure, pecl/http solves a much larger scope of problems related to HTTP, but that does not mean it can’t serve the purpose you’re trying to accomplish. If your attempt is to force everyone into an approach using the defined interfaces/classes in the RFC, this is going nowhere. First of all, you’re assuming PHP is an OOP-only language.
Of course, yes, you can do accomplish this today with some hacks like using
the php://input stream, but it's only up until recently that this stream
has become reusable. It's also potentially creating some duplication, but
albeit this isn't the only problem.
You don’t need to tie into the input stream - use pecl/http...
This RFC also attempts to make it possible for users to directly apply
filters to input from the HTTP request so that they can simply retrieve the
fitlered data from the HttpRequest object directly without having to do
things like $foo = isset($_POST['foo']) ? filter_var($_POST['foo'],
FILTER_VAR_INT) : 0; // for example
I understand why you’d want this in specific use-cases, but don’t tie everyone to your needs. This isn’t a requirement for a language. Plenty of frameworks can provide exactly what you’re describing.
I have nothing against pecl/http. I think it's a very useful library and
Mike seems to have put a great deal of work into it. I would gladly vote it
into PHP core. I'm just not clear on how it solves the same problems this
RFC attempts to solve. They can actually compliment each other in some
areas; I can see that.I certainly have no problem with competing ideas either. However, the only
proposed patch in this RFC is a gist with PHP pseudocode.It's not pseudocode since it's actually perfectly valid PHP code that will
compile and run in the PHP interpreter. However, it is intended to
demonstrate the behavior. The pecl/http RFC is also further along as it's
in discussion phase with an actual implementation. This RFC is merely a
draft, with no actual implementation proposed yet (but that's not at all
uncommon as many RFCs proposed in PHP did not provide an actual
implementation until after they were voted in: generators, list in foreach,
and finally are among a small number that come to mind). So let's not get
hung up on implementation being the barrier to entry for an RFC as that's
never ever been the case in the past.
My apologies. Please replace pseudocode with prototypes.
It is, however, entirely understandable that the RFC should explain the
actual behavior and consequences as well as possible if it does not provide
an actual implementation. This is just a very early stage discussion to
gather ideas so that I can improve and finalize the RFC. I have not
actually placed the RFC into discussion or voting phase just yet. So let's
not put the cart before the horse.
I”m not suggesting you provide a patch, and I’m actually glad you didn’t do the work yet.
I’m actually not suggesting an alternative - I’m suggesting this RFC isn’t
an option.
Great, your suggestion has been noted. Thanks for your contribution to this
discussion! :)
I’m actually not suggesting an alternative - I’m suggesting this RFC isn’t
an option.Great, your suggestion has been noted. Thanks for your contribution to this
discussion! :)
Let's try a different tactic...
Sherif, can you provide a complete PHP script that you believe would
exist/work were this RFC adopted? Nothing fancy, just a "new version"
Hello world-level implementation. Because right now, from your
descriptions I don't even know what that would look like. I can imagine
what a PSR-7-based Hello World script would look like; if I read up on
pecl_http (I admit I have not) I could probably imagine a pecl_http
Hello World, too. But I really don't understand how I'd even write code
with what you're proposing, which makes it difficult to determine what
you're even trying to do.
--Larry Garfield
I think the root problem is that you're solving an issue that doesn't exist.
You're talking about providing alternate ways to parse the raw HTTP stream into user-accessible variables, ie, by pushing them into an object of a known interface rather than/in addition to the superglobals.
In my 15 years of writing PHP I have never wanted to change the way the raw HTTP is parsed. I have, however, frequently wanted to have the data accessible in a more logical, semantic, and HTTP-correct way. ($_GET is not about HTTP GET, it's about URI query parameters. $_POST isn't about HTTP POST, it's about application/x-www-form-encoded. Etc.) And I've wanted that information available in a non-global, OOP-injectable way. But I've never once had any desire to change the way an application/x-www-form-encoded is parsed.
Implementation problems aside, your proposal is not solving an extant problem.
If we want to improve PHP's HTTP handling, then having an object that exposes the HTTP request in a more logical fashion would be far more useful, and/or providing that data in a more logical way so that someone in user-space can provide that data in a logical fashion (eg, via a PSR-7-implementing object.) I already stated in an earlier email what I felt would be most beneficial for internals to do toward that goal (specifically, clean up the streams API so that we can use it directly from an OOP world rather than a 1980s C world.)
IF internals wanted to add implementation, not just improving streams, something like the following would be much more useful:
$request = http_get_request(PHP_STDIN); // or something
Where $request is an object that implements the PSR-7 RequestInterface (or at least the read-only parts of it), or something similar. Then implementers can compose that object however they want.
Although at least for the near term I think it's better to not do that and just do the lower-level plumbing to make FIG's work with PSR-7 easier.
This sums up my thoughts on this very well. Nobody needs to change how we parse the data. We just need better access to the results of the parsing.
Andrea Faulds
http://ajf.me/
IF internals wanted to add implementation, not just improving streams, something like the following would be much more useful:
$request = http_get_request(PHP_STDIN); // or something
Where $request is an object that implements the PSR-7 RequestInterface (or at least the read-only parts of it), or something similar. Then implementers can compose that object however they want.
[...]This sums up my thoughts on this very well. Nobody needs to change how we parse the data. We just need better access to the results of the parsing.
Alternatively, what I would see as extremely useful would be to be
able to expose the "main loop" of the SAPI. Have a way (via an ini
mechanism) to register a callback that is executed when a requests
start processing. Essentially, similar to what is provided by WSGI
(for Python) and Rack (for Ruby).
The default implementation would be something like:
<?php
function default_entrypoint($env) {
php\register_superglobal($env);
php\execute_script();
}
?>
(with this callback executed in the scope of the new request)
But you could override any of it if you wanted to, and that would pave
the way nicely to more advanced PHP SAPIs (possibly evented) down the
road.
Damien
On 31 Oct 2014, at 18:37, Larry Garfield larry@garfieldtech.com
wrote:
IF internals wanted to add implementation, not just improving
streams, something like the following would be much more useful:$request = http_get_request(PHP_STDIN); // or something
Where $request is an object that implements the PSR-7
RequestInterface (or at least the read-only parts of it), or something
similar. Then implementers can compose that object however they want.
[...]This sums up my thoughts on this very well. Nobody needs to change
how we parse the data. We just need better access to the results of the
parsing.Alternatively, what I would see as extremely useful would be to be
able to expose the "main loop" of the SAPI. Have a way (via an ini
mechanism) to register a callback that is executed when a requests
start processing. Essentially, similar to what is provided by WSGI
(for Python) and Rack (for Ruby).The default implementation would be something like:
<?php
function default_entrypoint($env) {
php\register_superglobal($env);
php\execute_script();
}
?>(with this callback executed in the scope of the new request)
But you could override any of it if you wanted to, and that would pave
the way nicely to more advanced PHP SAPIs (possibly evented) down the
road.
This is actually quite an appealing idea; it provides a stepping-stone towards an evented SAPI without pre-empting other decisions which would need to be made (such as how global and static scopes would be handled). I particularly like the idea of exposing elements of default behaviour as non-magic functions, so that you could pass some other/modified request object to populate superglobals, for instance.
It could perhaps be implemented as a special function, which if present in the file targeted by the HTTP request (i.e. not via include()/require()) is called automatically, and passed a standard object providing access to the raw request.
I'm not sure how the response could best be managed so that it interacted smoothly with existing mechanisms; the function could optionally return a response object, but would perhaps need access to a magic object representing the default response built with echo, header_*() etc. Waiting for the entire response to be ready before streaming it to the SAPI isn't always desirable, either; I guess these are the kinds of issue FIG have been discussing...
In short, though, you would have an index.php file something like this:
<?php
function __main(HTTPRequst $request, HTTPResponse $default_response) {
require 'autoloader.php';
$action = Router::selectAction($request->getQueryStringParam('action'));
$custom_response = $action->process($request);
return $custom_response;
}
Sherif Ramadan wrote on 31/10/2014 17:27:
On Fri, Oct 31, 2014 at 1:09 PM, Rowan Collins
<rowan.collins@gmail.com mailto:rowan.collins@gmail.com> wrote:Let me repeat my question: Say I write a class "AwesomeHTTPReceive implements HttpMessageReceive", what do I then do with this class in order for it to perform any actions? How does PHP know that my class is the one it should populate, or when that population should happen?
It wouldn't. You would need to extend the base class, since it already
implements the necessary interface.
If extending the base class is mandatory, then an interface should not
exist. An interface's purpose is to define something's structure
independent of an inheritance tree.
However, this doesn't change the question, because "AwesomeHTTPReceive
extends HttpMessageReceive" still doesn't tell PHP anything about when
this class will be used.
The only possibility it opens is that the base class could have a
constructor (marked as final) which slurped the HTTP response out of
some invisible superglobal whenever you ran "$foo = new AwesomeHTTPReceive"
PHP would simply call on the last subtype of HttpRequest during the
request init phase.
It is not possible for a declarative piece of code to be discovered
during the init phase without an ini setting or similar, because there
is no way of knowing what files will be require()d during execution.
Moreover, modern practice is to put each class in a separate file and
use an autoloader, so a class is declared when it is first used.
Of course, this is an implementation detail as of now. There could
certainly be other/better ways to accomplish this.
I think this detail is fundamental to how the proposal will work, and it
is hard to proceed any further with the discussion without some idea of
what mechanism would be used to tie the custom implementation into the
engine/SAPI.
What do you propose?
Nothing, it's not my RFC, and I am trying to understand what you
intended by its proposal.
--
Rowan Collins
[IMSoP]
To be perfectly clear, the default behavior would remain the same, so no PHP app you have ever written would break. The difference is, you would now be able to override any part of the default behavior by extending the HttpRequest class in your own code.
So there’s still a default implementation, then? So, if you want to parse in userland, how does that work? The default implementation fills in the variables and then your implementation parses it again, wasting CPU time and making the request take longer? Or does the default implementation do nothing at all unless asked to, breaking existing apps unless they’re modified to request parsing? Or is it INI-determined??
The interfaces do exactly what you see here. They specified which methods the HttpRequest and HttpResponse objects must implement.
OK. So they’re just interfaces, then? In which case, why not leave the PHP-FIG to finish its HTTP Message proposal instead?
If you bothered to invest nearly as much time in reading the updates to the RFC as you did to making blanket statements and objections, you might actually find less reason to respond with objections so abruptly. The HttpRequest and HttpResponse classes are intended to provide a central place for message handling behaviors and their properties can be used to describe these behaviors.
So, if you wanted to support a $_PUT superglobal, rather than adding one to the language, you can simply add the behavior to do the processing of PUT requests in your HttpRequest class, by extending HttpRequest and defining how PUT variables are handled there.
So, all you’re proposing is a set of interfaces, to compete with the work the PHP-FIG is doing.
I don’t see how this is useful. How, exactly, does adding interfaces solve the problems with superglobals? Because you’re creating a common standard for alternative request implementations? But, we already have such a WIP standard in userland from the PSR people.
I really don’t get this RFC. If this was to add implementations of the PSR Request/Response stuff, that might be useful. But merely adding new interfaces… I don’t get it. Why duplicate effort? How does this fix superglobals?
--
Andrea Faulds
http://ajf.me/
So there’s still a default implementation, then? So, if you want to parse
in userland, how does that work? The default implementation fills in the
variables and then your implementation parses it again, wasting CPU time
and making the request take longer? Or does the default implementation do
nothing at all unless asked to, breaking existing apps unless they’re
modified to request parsing? Or is it INI-determined??
No, by overriding the parseBody or parseParameters methods, for example,
you can prevent the default behavior from happening. (i.e. it is not doing
the same thing twice). Simply by extending the HttpRequest class, we can
call on the child class instead. Any methods not implemented in the
extending class would be forwarded to the parent class as per normal PHP
inheritance rules.
OK. So they’re just interfaces, then? In which case, why not leave the
PHP-FIG to finish its HTTP Message proposal instead?
snip
So, all you’re proposing is a set of interfaces, to compete with the work
the PHP-FIG is doing.I don’t see how this is useful. How, exactly, does adding interfaces solve
the problems with superglobals? Because you’re creating a common standard
for alternative request implementations? But, we already have such a WIP
standard in userland from the PSR people.I really don’t get this RFC. If this was to add implementations of the PSR
Request/Response stuff, that might be useful. But merely adding new
interfaces… I don’t get it. Why duplicate effort? How does this fix
superglobals?
Competing ideas are good and the very reason that drives innovation. This
proposal is for both the interface and the implementing class, which can be
extended to create custom behavior in handling the HTTP request/response. I
have no idea why you think PHP-FIG or PSR is involved in this conversation.
This is a PHP internals matter and should be considered for PHP internals
purposes. The benefits and cons of this proposal are pretty clear, I think.
You get the ability to handle different kinds of requests as you see fit or
you leave the default behavior intact and everyone wins.
The only thing you don't get if you do this in userland instead, is you
have to do the parsing of the message twice, which this RFC attempts to
circumvent, but offering a way to overrride the parser before parsing takes
place (if you choose to implement it).
I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw request/response
messages in any way the user deems fit. This alleviates cases like "what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.
OK, I’ve gone and re-read the RFC and I finally understand this proposal, sorry for my previous misunderstanding. You’re proposing a mechanism to plug in your own parser for the HTTP message headers and body, right?
I’m not sure I really see what it solves, though? Why should we allow users to implement their own slow parsers in userland? Why can’t we just have a single built-in parser like we’ve had the last two decades? I don’t see the point.
Andrea Faulds
http://ajf.me/
I’m not sure I really see what it solves, though? Why should we allow
users to implement their own slow parsers in userland? Why can’t we just
have a single built-in parser like we’ve had the last two decades? I don’t
see the point.
For one, it would solve the problem addressed by the bug report (
http://php.net/55815) listed in the RFC, where users are asking for
additional features to parse and handle different kinds of requests like
PUT, which PHP currently doesn't do. Additionally, it solves problems such
as filtering input from the request with a more abstract interface that
doesn't rely on modifying or copying globals. The implementation can be
devised to do filtering at the request level or even lazy-loaded so that
filters are only applied when the data is requested. In addition, you could
utilize this approach to apply different kinds of custom filters based on
the request type using the onReceive hook, for example. Further more it can
be used to ensure that the request data is immutable so that there is no
wonder if the superglobals have been modified/tainted. This is something
many frameworks try to abstract themselves in fear that someone might
accidentally modify the superglobal variables (as this is very easy to do
in userland).
Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that
may
have been out of the question in PHP 5.I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw request/response
messages in any way the user deems fit. This alleviates cases like "what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no the
implementation itself. To remove all confusion, consider the way an HTTP
message actually looks.GET /foo?bar=1 HTTP/1.1
Host: foobar.combaz=2
Instead of treating this with current $_GET, $_POST, let's consider for a
moment how we might treat it in an HttpRequest object:If the HttpRequest class implements an HttpParameters object that parses
and treats the entire HTTP request line as a string of parameters we could
accomplish the following...var_dump(HttpRequest::$parameters->bar); // int(1)
var_dump((string) HttpRequest::$parameters); // string(6)"?bar=1"Now consider how the body can be treated...
echo HttpRequest::$body; // baz=2
echo HttpRequest::$body->baz; // 2Since the HttpRequest object can lazily parse the body it can also lazily
apply custom filters directly to the request variables and parameters...For example, say you wish to treat baz only as an integer? This can be
easily accomplished by setting the filters directly in the HttpRequest
object and upon access the filter is directly applied to chosen variables.
This also alleviates the need to worry about overwriting superglobal
variables or having to copy from them. So from an efficiency stand-point
this approach works much better. It also allows you to separate clearly
between HTTP request parameters and HTTP request body as well as the HTTP
request method. Since the request object should be capable of handling
callbacks for each method to apply different sets of filters or rules on
treating the request body given different request methods this could prove
a lot more useful than existing techniques applied directly in PHP with
php://input, for example.We don't need to copy the internal stream and we don't need to modify or
copy superglobals around to different parts of our code.I'm in the process of writing up a cleaner implementation to introduce in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.Thanks,
Sherif
This is clearly a responsibility of PHPFIG for interface recommendations
and not the responsibility of the core language.
2014-10-30 19:23 GMT+01:00 Sherif Ramadan theanomaly.is@gmail.com:
Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that may
have been out of the question in PHP 5.I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw request/response
messages in any way the user deems fit. This alleviates cases like "what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no the
implementation itself. To remove all confusion, consider the way an HTTP
message actually looks.GET /foo?bar=1 HTTP/1.1
Host: foobar.combaz=2
Instead of treating this with current $_GET, $_POST, let's consider for a
moment how we might treat it in an HttpRequest object:If the HttpRequest class implements an HttpParameters object that parses
and treats the entire HTTP request line as a string of parameters we could
accomplish the following...var_dump(HttpRequest::$parameters->bar); // int(1)
var_dump((string) HttpRequest::$parameters); // string(6)"?bar=1"Now consider how the body can be treated...
echo HttpRequest::$body; // baz=2
echo HttpRequest::$body->baz; // 2Since the HttpRequest object can lazily parse the body it can also lazily
apply custom filters directly to the request variables and parameters...For example, say you wish to treat baz only as an integer? This can be
easily accomplished by setting the filters directly in the HttpRequest
object and upon access the filter is directly applied to chosen variables.
This also alleviates the need to worry about overwriting superglobal
variables or having to copy from them. So from an efficiency stand-point
this approach works much better. It also allows you to separate clearly
between HTTP request parameters and HTTP request body as well as the HTTP
request method. Since the request object should be capable of handling
callbacks for each method to apply different sets of filters or rules on
treating the request body given different request methods this could prove
a lot more useful than existing techniques applied directly in PHP with
php://input, for example.We don't need to copy the internal stream and we don't need to modify or
copy superglobals around to different parts of our code.I'm in the process of writing up a cleaner implementation to introduce in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.Thanks,
Sherif
I'm all for adding a standardized way of handling PHP's input in a OO
way, however, no way we touch the existing super globals.
I don't see the benefit of an interface and how you would interact
with that with userland implementations. However, having simple and
immutable objects on top of what already exists sounds interesting
and reasonable.
From the top of my head, something like:
var_dump($_HTTP_REQUEST);
object(PHP\HttpRequest)#1 (11) {
["protocol"]=>
string(8) "HTTP/1.1"
["uri"]=>
string(9) "/info.php"
["host"]=>
string(11) "example.com"
["method"]=>
string(3) "GET"
["port"]=>
int(80)
["time"]=>
float(1415015570.096)
["queryString"]=>
string(11) "foo=1&bar=2"
["uriParams"]=>
array(2) {
["foo"]=>
int(1)
["bar"]=>
int(2)
}
["cookies"]=>
array(1) {
["language"]=>
string(2) "fr"
}
["acceptEncoding"]=>
array(3) {
["gzip"]=>
bool(true)
["deflate"]=>
bool(true)
["sdch"]=>
bool(true)
}
["userAgent"]=>
string(105) "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36"
}
Note that super globals are created on demand, so there is no impact
on keeping $_GET, $_POST, ... variables aside a new OO implementation
which should also benefit from this lazy loading mechanism.
Patrick
I'm not keen on the idea of adding more superglobals to PHP, although I
certainly understand the grave concern of breaking people's code and as
such I've chosen not to pursue the idea of removing superglobals.
I will, however, revisit the idea of exposing the underlying SAPI
callbacks, for handling the incoming HTTP request in PHP, to userland. From
a rough skim through the code, so far, it appears that this is already
entirely possible and shouldn't be very difficult to expose the SAPI API to
userland without breaking BC. This would make it possible for people to
register request handlers in the same way they can register autoloaders and
as such make it possible to handle things like PUT/MOVE/PROP FIND HTTP
requests through some custom callback.
The only concern there is would people prefer to use their own custom
callbacks in userland or would they prefer for PHP to do it for them?
From all the people I've spoken with that have a problem with handling PUT
requests in PHP, it seems that they'd rather have PHP populate
$_FILES/$_POST automatically in this case. Which would be relatively easy
to do by modifying the default post reader function in the SAPI
http://lxr.php.net/xref/PHP_5_6/main/php_content_types.c#51 however, that
is itself a small BC break.
Does anyone have any recommendations on what they think the best approach
is? I'd appreciate any feedback/suggestions/constructive-criticism. Thanks!
On Mon, Nov 3, 2014 at 7:08 AM, Patrick ALLAERT patrickallaert@php.net
wrote:
2014-10-30 19:23 GMT+01:00 Sherif Ramadan theanomaly.is@gmail.com:
Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that
may
have been out of the question in PHP 5.I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw request/response
messages in any way the user deems fit. This alleviates cases like "what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no the
implementation itself. To remove all confusion, consider the way an HTTP
message actually looks.GET /foo?bar=1 HTTP/1.1
Host: foobar.combaz=2
Instead of treating this with current $_GET, $_POST, let's consider for a
moment how we might treat it in an HttpRequest object:If the HttpRequest class implements an HttpParameters object that parses
and treats the entire HTTP request line as a string of parameters we
could
accomplish the following...var_dump(HttpRequest::$parameters->bar); // int(1)
var_dump((string) HttpRequest::$parameters); // string(6)"?bar=1"Now consider how the body can be treated...
echo HttpRequest::$body; // baz=2
echo HttpRequest::$body->baz; // 2Since the HttpRequest object can lazily parse the body it can also lazily
apply custom filters directly to the request variables and parameters...For example, say you wish to treat baz only as an integer? This can be
easily accomplished by setting the filters directly in the HttpRequest
object and upon access the filter is directly applied to chosen
variables.
This also alleviates the need to worry about overwriting superglobal
variables or having to copy from them. So from an efficiency stand-point
this approach works much better. It also allows you to separate clearly
between HTTP request parameters and HTTP request body as well as the HTTP
request method. Since the request object should be capable of handling
callbacks for each method to apply different sets of filters or rules on
treating the request body given different request methods this could
prove
a lot more useful than existing techniques applied directly in PHP with
php://input, for example.We don't need to copy the internal stream and we don't need to modify or
copy superglobals around to different parts of our code.I'm in the process of writing up a cleaner implementation to introduce in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.Thanks,
SherifI'm all for adding a standardized way of handling PHP's input in a OO
way, however, no way we touch the existing super globals.
I don't see the benefit of an interface and how you would interact
with that with userland implementations. However, having simple and
immutable objects on top of what already exists sounds interesting
and reasonable.
From the top of my head, something like:var_dump($_HTTP_REQUEST);
object(PHP\HttpRequest)#1 (11) {
["protocol"]=>
string(8) "HTTP/1.1"
["uri"]=>
string(9) "/info.php"
["host"]=>
string(11) "example.com"
["method"]=>
string(3) "GET"
["port"]=>
int(80)
["time"]=>
float(1415015570.096)
["queryString"]=>
string(11) "foo=1&bar=2"
["uriParams"]=>
array(2) {
["foo"]=>
int(1)
["bar"]=>
int(2)
}
["cookies"]=>
array(1) {
["language"]=>
string(2) "fr"
}
["acceptEncoding"]=>
array(3) {
["gzip"]=>
bool(true)
["deflate"]=>
bool(true)
["sdch"]=>
bool(true)
}
["userAgent"]=>
string(105) "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36"
}Note that super globals are created on demand, so there is no impact
on keeping $_GET, $_POST, ... variables aside a new OO implementation
which should also benefit from this lazy loading mechanism.Patrick
Me as a user and developer PHP RESTful, enough auto filling the global
variable.
Make an abstract variable names (_BODY or _FORM), and filled with the value
in all the HTTP methods.
Perhaps it makes sense to do lazy loading of data in these variables, it is
simply done through an ArrayAccess interface to $_FORM variables were the
objects that implement the interface to access an array when you first
access the Elements massif, to parse HTTP message body
Your effort is better spent on creating an interface of the PHP as a demon
when Launched PHP script handles the HTTP requests.
2014-11-06 0:29 GMT+02:00 Sherif Ramadan theanomaly.is@gmail.com:
I'm not keen on the idea of adding more superglobals to PHP, although I
certainly understand the grave concern of breaking people's code and as
such I've chosen not to pursue the idea of removing superglobals.I will, however, revisit the idea of exposing the underlying SAPI
callbacks, for handling the incoming HTTP request in PHP, to userland. From
a rough skim through the code, so far, it appears that this is already
entirely possible and shouldn't be very difficult to expose the SAPI API to
userland without breaking BC. This would make it possible for people to
register request handlers in the same way they can register autoloaders and
as such make it possible to handle things like PUT/MOVE/PROP FIND HTTP
requests through some custom callback.The only concern there is would people prefer to use their own custom
callbacks in userland or would they prefer for PHP to do it for them?From all the people I've spoken with that have a problem with handling PUT
requests in PHP, it seems that they'd rather have PHP populate
$_FILES/$_POST automatically in this case. Which would be relatively easy
to do by modifying the default post reader function in the SAPI
http://lxr.php.net/xref/PHP_5_6/main/php_content_types.c#51 however, that
is itself a small BC break.Does anyone have any recommendations on what they think the best approach
is? I'd appreciate any feedback/suggestions/constructive-criticism. Thanks!On Mon, Nov 3, 2014 at 7:08 AM, Patrick ALLAERT patrickallaert@php.net
wrote:2014-10-30 19:23 GMT+01:00 Sherif Ramadan theanomaly.is@gmail.com:
Hello Internals,
I've been meaning to write up a full-blown RFC for introducing a new
standardized HTTP interface for PHP core for some time now. I figure
now
with PHP 7 on the road map this might be a good time to start this
discussion since it involves breaking some backwards compatibility that
may
have been out of the question in PHP 5.I've started a draft RFC, but please be patient as this is a working in
progress, here https://wiki.php.net/rfc/http-interface on the wiki.The point here is to allow users to implement their own HttpRequest and
HttpResponse classes that can deal directly with the raw
request/response
messages in any way the user deems fit. This alleviates cases like
"what
about when I want to have $_PUT or $_DELETE" and removes the ambiguity
of
the $_POST, $_GET superglobals to a more conforming way of handling the
messages.Since it's an interface, it only dictates the facilitation of PHP's
built-in functionality and the user's desired implementation, but no
the
implementation itself. To remove all confusion, consider the way an
HTTP
message actually looks.GET /foo?bar=1 HTTP/1.1
Host: foobar.combaz=2
Instead of treating this with current $_GET, $_POST, let's consider
for a
moment how we might treat it in an HttpRequest object:If the HttpRequest class implements an HttpParameters object that
parses
and treats the entire HTTP request line as a string of parameters we
could
accomplish the following...var_dump(HttpRequest::$parameters->bar); // int(1)
var_dump((string) HttpRequest::$parameters); // string(6)"?bar=1"Now consider how the body can be treated...
echo HttpRequest::$body; // baz=2
echo HttpRequest::$body->baz; // 2Since the HttpRequest object can lazily parse the body it can also
lazily
apply custom filters directly to the request variables and
parameters...For example, say you wish to treat baz only as an integer? This can be
easily accomplished by setting the filters directly in the HttpRequest
object and upon access the filter is directly applied to chosen
variables.
This also alleviates the need to worry about overwriting superglobal
variables or having to copy from them. So from an efficiency
stand-point
this approach works much better. It also allows you to separate clearly
between HTTP request parameters and HTTP request body as well as the
HTTP
request method. Since the request object should be capable of handling
callbacks for each method to apply different sets of filters or rules
on
treating the request body given different request methods this could
prove
a lot more useful than existing techniques applied directly in PHP with
php://input, for example.We don't need to copy the internal stream and we don't need to modify
or
copy superglobals around to different parts of our code.I'm in the process of writing up a cleaner implementation to introduce
in
the RFC, but in the mean time I'd like to open up to discussion and see
what others think or how they feel we might approach this problem more
cleanly.Thanks,
SherifI'm all for adding a standardized way of handling PHP's input in a OO
way, however, no way we touch the existing super globals.
I don't see the benefit of an interface and how you would interact
with that with userland implementations. However, having simple and
immutable objects on top of what already exists sounds interesting
and reasonable.
From the top of my head, something like:var_dump($_HTTP_REQUEST);
object(PHP\HttpRequest)#1 (11) {
["protocol"]=>
string(8) "HTTP/1.1"
["uri"]=>
string(9) "/info.php"
["host"]=>
string(11) "example.com"
["method"]=>
string(3) "GET"
["port"]=>
int(80)
["time"]=>
float(1415015570.096)
["queryString"]=>
string(11) "foo=1&bar=2"
["uriParams"]=>
array(2) {
["foo"]=>
int(1)
["bar"]=>
int(2)
}
["cookies"]=>
array(1) {
["language"]=>
string(2) "fr"
}
["acceptEncoding"]=>
array(3) {
["gzip"]=>
bool(true)
["deflate"]=>
bool(true)
["sdch"]=>
bool(true)
}
["userAgent"]=>
string(105) "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36"
}Note that super globals are created on demand, so there is no impact
on keeping $_GET, $_POST, ... variables aside a new OO implementation
which should also benefit from this lazy loading mechanism.Patrick
From all the people I've spoken with that have a problem with handling PUT
requests in PHP, it seems that they'd rather have PHP populate
$_FILES/$_POST automatically in this case. Which would be relatively easy
to do by modifying the default post reader function in the SAPI
http://lxr.php.net/xref/PHP_5_6/main/php_content_types.c#51 however, that
is itself a small BC break.Does anyone have any recommendations on what they think the best approach
is? I'd appreciate any feedback/suggestions/constructive-criticism. Thanks!
I don’t think auto-populating for PUT/DELETE etc. is a good idea, they’re quite different semantically. If I send a DELETE request to code expecting a POST, and PHP pretends it’s a POST request, that’s bad.
However, I think the solution is simple: Add a function to do multipart/form-data parsing. Not a suite of functions, not a class, just one simple function. That way, for the few people that need it, they can do $_POST = multipart_form_data_parse(file_get_contents(‘php://input')); and their problem’s solved.
If we can’t expose the parser, we could also just add a function to force population (force_parse_post_data() or something?). Again, this allows the few that need this to do so explicitly, but doesn’t make $_POST allow it for everyone else.
Andrea Faulds
http://ajf.me/
From all the people I've spoken with that have a problem with handling
PUT
requests in PHP, it seems that they'd rather have PHP populate
$_FILES/$_POST automatically in this case. Which would be relatively easy
to do by modifying the default post reader function in the SAPI
http://lxr.php.net/xref/PHP_5_6/main/php_content_types.c#51 however,
that
is itself a small BC break.Does anyone have any recommendations on what they think the best approach
is? I'd appreciate any feedback/suggestions/constructive-criticism.
Thanks!I don’t think auto-populating for PUT/DELETE etc. is a good idea, they’re
quite different semantically. If I send a DELETE request to code expecting
a POST, and PHP pretends it’s a POST request, that’s bad.
So you're actually describing two semi-different problems here. One is that
PHP doesn't actually inform you of the HTTP request VERB strictly through
the naming of the super global variables $_POST and $_GET. However, $_POST
being populated, right now, in PHP, strictly means the request verb was
POST and that the content-type header received was multipart form data.
Which means that sending something like a JSON payload (Content-type
application/x-json or whatever) in the body of a POST request still doesn't
populate the $_POST super global variable even though the HTTP request VERB
was indeed POST.
The other problem is that the semantics of REST itself are quite different
from how PHP currently deals with the request data. In that PHP only cares
about form data. However, this is quite antiquated with todays' modern use
of HTTP growing in API-specific functionality. For example, companies like
Twitter and Tumblr, demonstrate a vast majority of their traffic currently
coming in at the API-level where things are usually handled in a RESTful
manner. So for the PHP power houses today, PHP doesn't quite lend itself
well to dealing with these problems first-hand. Instead we have to hack our
way around them in userland, which can be more error-prone and less obvious.
However, I think the solution is simple: Add a function to do
multipart/form-data parsing. Not a suite of functions, not a class, just
one simple function. That way, for the few people that need it, they can do
$_POST = multipart_form_data_parse(file_get_contents(‘php://input')); and
their problem’s solved.
If we can’t expose the parser, we could also just add a function to force
population (force_parse_post_data() or something?). Again, this allows the
few that need this to do so explicitly, but doesn’t make $_POST allow it
for everyone else.
While that solution solves one specific problem (dealing with multipart
form data of request types other than POST), it doesn't quite tackle some
of the broader issues of dealing with incoming HTTP request in PHP that I
would like to tackle. I also think you're diminishing scope of this problem
and the number of people affected by it. You not only have to think of the
number of programmers dealing with the code, but the number of end-users
indirectly affected by the problem as well. PHP is primarily a web-oriented
language, and I think as such it should deal with these kinds of issues
more readily. If you take a good look at the number of web-based APIs out
there and how certain PHP client libraries try to deal with these kinds of
problems the solutions are sometimes very poorly implemented or just
outright wrong.
We solved password hashing dilemmas with password_hash for a similar reason
in PHP. In that people were just doing it wrong and didn't know any better.
So I think making a more robust, and simpler interface to deal with these
kinds of issues will encourage people to get it right in the future.
--
Andrea Faulds
http://ajf.me/
So you're actually describing two semi-different problems here. One is that PHP doesn't actually inform you of the HTTP request VERB strictly through the naming of the super global variables $_POST and $_GET. However, $_POST being populated, right now, in PHP, strictly means the request verb was POST and that the content-type header received was multipart form data. Which means that sending something like a JSON payload (Content-type application/x-json or whatever) in the body of a POST request still doesn't populate the $_POST super global variable even though the HTTP request VERB was indeed POST.
That’s not actually my complaint. The thing is that, until now, you could assume what was in $_POST was from a POST request. To allow data from PUT and DELETE requests to go there by default is probably not a good idea, because POST has quite a different meaning from PUT and DELETE.
The other problem is that the semantics of REST itself are quite different from how PHP currently deals with the request data. In that PHP only cares about form data. However, this is quite antiquated with todays' modern use of HTTP growing in API-specific functionality. For example, companies like Twitter and Tumblr, demonstrate a vast majority of their traffic currently coming in at the API-level where things are usually handled in a RESTful manner. So for the PHP power houses today, PHP doesn't quite lend itself well to dealing with these problems first-hand. Instead we have to hack our way around them in userland, which can be more error-prone and less obvious.
Er… I wouldn’t say that PHP really handles REST APIs badly, or that the userland approach is error-prone or less obvious. Using JSON isn’t difficult, you just do this:
$data = json_decode(file_get_contents(‘php://input')) or die();
This isn’t a hack. It’s a straightforward and obvious way to do this.
While that solution solves one specific problem (dealing with multipart form data of request types other than POST), it doesn't quite tackle some of the broader issues of dealing with incoming HTTP request in PHP that I would like to tackle.
Yes, I’m aware it doesn’t. I don’t think that the PUT/DELETE issue really justifies your RFC. I don’t think there are any other problems which do, either. There are better ways to solve them.
I also think you're diminishing scope of this problem and the number of people affected by it. You not only have to think of the number of programmers dealing with the code, but the number of end-users indirectly affected by the problem as well. PHP is primarily a web-oriented language, and I think as such it should deal with these kinds of issues more readily. If you take a good look at the number of web-based APIs out there and how certain PHP client libraries try to deal with these kinds of problems the solutions are sometimes very poorly implemented or just outright wrong.
Your solution is to put even more stuff in userland so web developers can produce even less functional applications which have buggy request parsing. I don’t think that really helps anyone.
We solved password hashing dilemmas with password_hash for a similar reason in PHP. In that people were just doing it wrong and didn't know any better. So I think making a more robust, and simpler interface to deal with these kinds of issues will encourage people to get it right in the future.
Sure, a nicer response/request interface, like the PSR proposals, would be great. Your mechanism for parsing raw request data does not solve this problem, in fact I suspect it would make it worse. Aside from that, it’d also severely hurt performance.
Andrea Faulds
http://ajf.me/
So you're actually describing two semi-different problems here. One is
that PHP doesn't actually inform you of the HTTP request VERB strictly
through the naming of the super global variables $_POST and $_GET. However,
$_POST being populated, right now, in PHP, strictly means the request verb
was POST and that the content-type header received was multipart form data.
Which means that sending something like a JSON payload (Content-type
application/x-json or whatever) in the body of a POST request still doesn't
populate the $_POST super global variable even though the HTTP request VERB
was indeed POST.That’s not actually my complaint. The thing is that, until now, you could
assume what was in $_POST was from a POST request. To allow data from PUT
and DELETE requests to go there by default is probably not a good idea,
because POST has quite a different meaning from PUT and DELETE.
Sure, $_POST has become synonymous with form data. I get that. I have no
idea why you think populating it with data from other request types,
however, would necessarily be a bad idea. If the request verb changes but
the request contains a multipart mime, I see no reason not to populate it
other than its name becoming more alluding. The meaning of PUT or DELETE is
irrelevant here because all we're discussing is parsing the form data part
of the multipart request (regardless of it's HTTP request VERB). So the
meaning of the request verb isn't a justification for what to name the
super global variable that gets populated either. The super global was
intended for form data and I'm not changing that intention when allowing it
to get populated by additional request verbs.
The other problem is that the semantics of REST itself are quite
different from how PHP currently deals with the request data. In that PHP
only cares about form data. However, this is quite antiquated with todays'
modern use of HTTP growing in API-specific functionality. For example,
companies like Twitter and Tumblr, demonstrate a vast majority of their
traffic currently coming in at the API-level where things are usually
handled in a RESTful manner. So for the PHP power houses today, PHP doesn't
quite lend itself well to dealing with these problems first-hand. Instead
we have to hack our way around them in userland, which can be more
error-prone and less obvious.Er… I wouldn’t say that PHP really handles REST APIs badly, or that the
userland approach is error-prone or less obvious. Using JSON isn’t
difficult, you just do this:$data = json_decode(file_get_contents(‘php://input')) or die();
This isn’t a hack. It’s a straightforward and obvious way to do this.
Again, I think you're oversimplifying the problem. For one, you don't know
that the payload is JSON unless you check the Content-type header yourself,
and you really shouldn't have to since PHP could easily do this for you.
Further more, you ignore all the other aspects of parsing the request body
like when the PUT payload is a multipart mime, with both form data and a
base64 encoded binary part or several of them. Again, PHP could just as
easily take care of this in the same way it does now with POST and populate
$_FILES and other form data accordingly.
While that solution solves one specific problem (dealing with multipart
form data of request types other than POST), it doesn't quite tackle some
of the broader issues of dealing with incoming HTTP request in PHP that I
would like to tackle.Yes, I’m aware it doesn’t. I don’t think that the PUT/DELETE issue really
justifies your RFC. I don’t think there are any other problems which do,
either. There are better ways to solve them.
Well, the RFC is intended to tackle the current issues of dealing with the
HTTP request where PHP now fails. Everything outside of form data and
multipart requests specifically using POST fall under that umbrella. So I'm
not sure why you think this RFC isn't justified.
What are these better ways? Please, do elaborate. I'm more than open to a
better solution even if that entails heading down a different path. I just
don't think that a response of "this RFC doesn't help because there's
something better", without stating what that is or why this RFC is less
than acceptable is a very constructive response. In that it only aims to
shutter the discussion and turn people away from it rather than help it
evolve into something better.
I also think you're diminishing scope of this problem and the number of
people affected by it. You not only have to think of the number of
programmers dealing with the code, but the number of end-users indirectly
affected by the problem as well. PHP is primarily a web-oriented language,
and I think as such it should deal with these kinds of issues more readily.
If you take a good look at the number of web-based APIs out there and how
certain PHP client libraries try to deal with these kinds of problems the
solutions are sometimes very poorly implemented or just outright wrong.Your solution is to put even more stuff in userland so web developers can
produce even less functional applications which have buggy request parsing.
I don’t think that really helps anyone.
That's not my solution. I actually posed the two options to contrast
between their trade offs. I think that handling this stuff in PHP is likely
to prove more efficient. What I hope to gain from this discussion is the
optimal path to that implementation and what it would look like. Because
the parts that really matter are just taking advantage of the existing PHP
source code that handles things like parsing multipart data in the payload
and perhaps refining it to also deal with a wider array of request types
like PUT.
We solved password hashing dilemmas with password_hash for a similar
reason in PHP. In that people were just doing it wrong and didn't know any
better. So I think making a more robust, and simpler interface to deal with
these kinds of issues will encourage people to get it right in the future.Sure, a nicer response/request interface, like the PSR proposals, would be
great. Your mechanism for parsing raw request data does not solve this
problem, in fact I suspect it would make it worse. Aside from that, it’d
also severely hurt performance.
So as it stands, this RFC is still a draft, and I will admit I did a very
poor job of constructing a reasonable proposal. Right now, yes, the idea of
an interface that allows userland to do the parsing may likely prove more
problematic.
However, taking a closer look at the problem, perhaps the solution
shouldn't be to attempt to tackle this problem entirely in userland after
all. I've since realized that a simpler approach might solve this problem a
lot better. For example, rather than exposing all of the underlying
mechanisms that go in parsing the request data, why not just expose those
that make things like handling a multipart form data request under HTTP
verbs other than POST possible? There's very little added to accomplish
this other than modifying the post hanlder in the SAPI to accept things
like PUT and to alter the way content-type header is interpreted to decode
the form data.
So in the case of a JSON payload rather than doing this...
$data = json_decode(file('php://input')) or die;
it may prove helpful to know what the Content-type header was in the coming
request and just let PHP decode the payload through json_decode itself,
rather than urldecode?
In the case of multipart form data from a PUT request it may also prove
helpful to populate $_FILES accordingly so that the user doesn't have to?
I'm pretty sure these are reasonable solutions and it's already what people
are expecting. The only real question was whether or not we should create
another superglobal for something like $_PUT or not. Which I'm personally
not a fan of and hope we can find a better alternative, because then people
might start expecting more super global variables for other request types
in the future and it only lends itself to increasing the ambiguity about
how to handle each request.
--
Andrea Faulds
http://ajf.me/
So you're actually describing two semi-different problems here. One is
that PHP doesn't actually inform you of the HTTP request VERB strictly
through the naming of the super global variables $_POST and $_GET. However,
$_POST being populated, right now, in PHP, strictly means the request verb
was POST and that the content-type header received was multipart form data.
Which means that sending something like a JSON payload (Content-type
application/x-json or whatever) in the body of a POST request still doesn't
populate the $_POST super global variable even though the HTTP request VERB
was indeed POST.That’s not actually my complaint. The thing is that, until now, you could
assume what was in $_POST was from a POST request. To allow data from PUT
and DELETE requests to go there by default is probably not a good idea,
because POST has quite a different meaning from PUT and DELETE.Sure, $_POST has become synonymous with form data. I get that. I have no
idea why you think populating it with data from other request types,
however, would necessarily be a bad idea. If the request verb changes but
the request contains a multipart mime, I see no reason not to populate it
other than its name becoming more alluding. The meaning of PUT or DELETE is
irrelevant here because all we're discussing is parsing the form data part
of the multipart request (regardless of it's HTTP request VERB). So the
meaning of the request verb isn't a justification for what to name the
super global variable that gets populated either. The super global was
intended for form data and I'm not changing that intention when allowing it
to get populated by additional request verbs.
Easy - you have no idea what the input type is from PUT without checking the incoming type. With POST, you know exactly what it is. PUT input code be JSON, multipart mime, a file or a whatever the dev wants.
The other problem is that the semantics of REST itself are quite
different from how PHP currently deals with the request data. In that PHP
only cares about form data. However, this is quite antiquated with todays'
modern use of HTTP growing in API-specific functionality. For example,
companies like Twitter and Tumblr, demonstrate a vast majority of their
traffic currently coming in at the API-level where things are usually
handled in a RESTful manner. So for the PHP power houses today, PHP doesn't
quite lend itself well to dealing with these problems first-hand. Instead
we have to hack our way around them in userland, which can be more
error-prone and less obvious.Er… I wouldn’t say that PHP really handles REST APIs badly, or that the
userland approach is error-prone or less obvious. Using JSON isn’t
difficult, you just do this:$data = json_decode(file_get_contents(‘php://input')) or die();
This isn’t a hack. It’s a straightforward and obvious way to do this.
Again, I think you're oversimplifying the problem. For one, you don't know
that the payload is JSON unless you check the Content-type header yourself,
and you really shouldn't have to since PHP could easily do this for you.
Further more, you ignore all the other aspects of parsing the request body
like when the PUT payload is a multipart mime, with both form data and a
base64 encoded binary part or several of them. Again, PHP could just as
easily take care of this in the same way it does now with POST and populate
$_FILES and other form data accordingly.
You’re suggesting we change the fundamental approach of PHP in terms of what these superglobals represent. I think from the feedback on this list, the approach you’re suggesting is far from welcome. Perhaps this is something you should stop arguing and start looking at improving your RFC with something that’s different and potentially acceptable.
While that solution solves one specific problem (dealing with multipart
form data of request types other than POST), it doesn't quite tackle some
of the broader issues of dealing with incoming HTTP request in PHP that I
would like to tackle.Yes, I’m aware it doesn’t. I don’t think that the PUT/DELETE issue really
justifies your RFC. I don’t think there are any other problems which do,
either. There are better ways to solve them.Well, the RFC is intended to tackle the current issues of dealing with the
HTTP request where PHP now fails. Everything outside of form data and
multipart requests specifically using POST fall under that umbrella. So I'm
not sure why you think this RFC isn't justified.What are these better ways? Please, do elaborate. I'm more than open to a
better solution even if that entails heading down a different path. I just
don't think that a response of "this RFC doesn't help because there's
something better", without stating what that is or why this RFC is less
than acceptable is a very constructive response. In that it only aims to
shutter the discussion and turn people away from it rather than help it
evolve into something better.I also think you're diminishing scope of this problem and the number of
people affected by it. You not only have to think of the number of
programmers dealing with the code, but the number of end-users indirectly
affected by the problem as well. PHP is primarily a web-oriented language,
and I think as such it should deal with these kinds of issues more readily.
If you take a good look at the number of web-based APIs out there and how
certain PHP client libraries try to deal with these kinds of problems the
solutions are sometimes very poorly implemented or just outright wrong.Your solution is to put even more stuff in userland so web developers can
produce even less functional applications which have buggy request parsing.
I don’t think that really helps anyone.That's not my solution. I actually posed the two options to contrast
between their trade offs. I think that handling this stuff in PHP is likely
to prove more efficient. What I hope to gain from this discussion is the
optimal path to that implementation and what it would look like. Because
the parts that really matter are just taking advantage of the existing PHP
source code that handles things like parsing multipart data in the payload
and perhaps refining it to also deal with a wider array of request types
like PUT.We solved password hashing dilemmas with password_hash for a similar
reason in PHP. In that people were just doing it wrong and didn't know any
better. So I think making a more robust, and simpler interface to deal with
these kinds of issues will encourage people to get it right in the future.Sure, a nicer response/request interface, like the PSR proposals, would be
great. Your mechanism for parsing raw request data does not solve this
problem, in fact I suspect it would make it worse. Aside from that, it’d
also severely hurt performance.So as it stands, this RFC is still a draft, and I will admit I did a very
poor job of constructing a reasonable proposal. Right now, yes, the idea of
an interface that allows userland to do the parsing may likely prove more
problematic.However, taking a closer look at the problem, perhaps the solution
shouldn't be to attempt to tackle this problem entirely in userland after
all. I've since realized that a simpler approach might solve this problem a
lot better. For example, rather than exposing all of the underlying
mechanisms that go in parsing the request data, why not just expose those
that make things like handling a multipart form data request under HTTP
verbs other than POST possible? There's very little added to accomplish
this other than modifying the post hanlder in the SAPI to accept things
like PUT and to alter the way content-type header is interpreted to decode
the form data.So in the case of a JSON payload rather than doing this...
$data = json_decode(file('php://input')) or die;
it may prove helpful to know what the Content-type header was in the coming
request and just let PHP decode the payload through json_decode itself,
rather than urldecode?In the case of multipart form data from a PUT request it may also prove
helpful to populate $_FILES accordingly so that the user doesn't have to?I'm pretty sure these are reasonable solutions and it's already what people
are expecting. The only real question was whether or not we should create
another superglobal for something like $_PUT or not. Which I'm personally
not a fan of and hope we can find a better alternative, because then people
might start expecting more super global variables for other request types
in the future and it only lends itself to increasing the ambiguity about
how to handle each request.--
Andrea Faulds
http://ajf.me/
Easy - you have no idea what the input type is from PUT without checking
the incoming type. With POST, you know exactly what it is. PUT input code
be JSON, multipart mime, a file or a whatever the dev wants.
That's not necessarily true. There are many APIs that will send POST
requests with a JSON payload in the request body. This is specifically why
PHP won't bother parsing the request entity body unless the content-type
header is form ulr-encoded. Additionally you have to take
Content-encoding[1] into consideration as HTTP doesn't require that the
body of a POST request be url-encoded, just that the client specifies the
content-encoding and content-type[2][3] for entity decoding and then it
becomes up to the server how to handle or even accept the entity.
[1] http://tools.ietf.org/html/rfc2616#section-14.11
[2] http://tools.ietf.org/html/rfc2616#section-14.17
[3] http://tools.ietf.org/html/rfc2616#section-7.2.1
You’re suggesting we change the fundamental approach of PHP in terms of
what these superglobals represent.
Not at all, $_GET and $_POST in PHP have always represented form data. I
wish to keep that intact. This approach merely amends under which HTTP
verbs form data can be accepted and the potential to accept media types
other than form/url-encoded. If the latter part deviates too much from the
concept of form data (it likely does) then that can become a separate vote
in the RFC.
I think from the feedback on this list, the approach you’re suggesting is
far from welcome. Perhaps this is something you should stop arguing and
start looking at improving your RFC with something that’s different and
potentially acceptable.
Improving the RFC is precisely what I'm looking to do :)
Surely the only way to find out what is or is not acceptable is to poll
others get some form of popular consensus. Perhaps you should take the
discussion as less of a battle and more of an opportunity to voice
individual objectivity? I have no intention of being hostile. I'm also more
than open to the possibility that this RFC may not be favored, but that
doesn't negate the effort to build a more favorable RFC based on this
discussion.
Easy - you have no idea what the input type is from PUT without checking the incoming type. With POST, you know exactly what it is. PUT input code be JSON, multipart mime, a file or a whatever the dev wants.
That's not necessarily true. There are many APIs that will send POST requests with a JSON payload in the request body. This is specifically why PHP won't bother parsing the request entity body unless the content-type header is form ulr-encoded. Additionally you have to take Content-encoding[1] into consideration as HTTP doesn't require that the body of a POST request be url-encoded, just that the client specifies the content-encoding and content-type[2][3] for entity decoding and then it becomes up to the server how to handle or even accept the entity.
I think a simple quote from RFC 2616 is necessary:
"The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,
it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request."
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)
There is nothing relevant to data transformation between PUT and POST. It is, for all intents and purposes, two completely different methods and you should not assume one is similar to the other - especially based solely on what you want PUT to do. PUT can contain query strings, POST-like bodies and files or a combination of any.
Bottom line - you’re trying to change PHP’s form handling approach with your view of what PUT could/should be doing. Don’t do that.
It’s blowing my mind that you are still arguing this point, and I believe it’s time to put it to bed. Come up with a better solution, put this RFC to a vote (even without a patch) or retract it. You have have almost nothing but criticism, and this thread is at the point of wasting valuable time.
[1] http://tools.ietf.org/html/rfc2616#section-14.11
[2] http://tools.ietf.org/html/rfc2616#section-14.17
[3] http://tools.ietf.org/html/rfc2616#section-7.2.1You’re suggesting we change the fundamental approach of PHP in terms of what these superglobals represent.
Not at all, $_GET and $_POST in PHP have always represented form data. I wish to keep that intact. This approach merely amends under which HTTP verbs form data can be accepted and the potential to accept media types other than form/url-encoded. If the latter part deviates too much from the concept of form data (it likely does) then that can become a separate vote in the RFC.
I think from the feedback on this list, the approach you’re suggesting is far from welcome. Perhaps this is something you should stop arguing and start looking at improving your RFC with something that’s different and potentially acceptable.
Improving the RFC is precisely what I'm looking to do :)
Surely the only way to find out what is or is not acceptable is to poll others get some form of popular consensus. Perhaps you should take the discussion as less of a battle and more of an opportunity to voice individual objectivity? I have no intention of being hostile. I'm also more than open to the possibility that this RFC may not be favored, but that doesn't negate the effort to build a more favorable RFC based on this discussion.
On Nov 5, 2014, at 10:00 PM, Sherif Ramadan theanomaly.is@gmail.com
wrote:Easy - you have no idea what the input type is from PUT without checking
the incoming type. With POST, you know exactly what it is. PUT input code
be JSON, multipart mime, a file or a whatever the dev wants.That's not necessarily true. There are many APIs that will send POST
requests with a JSON payload in the request body. This is specifically why
PHP won't bother parsing the request entity body unless the content-type
header is form ulr-encoded. Additionally you have to take
Content-encoding[1] into consideration as HTTP doesn't require that the
body of a POST request be url-encoded, just that the client specifies the
content-encoding and content-type[2][3] for entity decoding and then it
becomes up to the server how to handle or even accept the entity.I think a simple quote from RFC 2616 is necessary:
"The fundamental difference between the POST and PUT requests is reflected
in the different meaning of the Request-URI. The URI in a POST request
identifies the resource that will handle the enclosed entity. That resource
might be a data-accepting process, a gateway to some other protocol, or a
separate entity that accepts annotations. In contrast, the URI in a PUT
request identifies the entity enclosed with the request -- the user agent
knows what URI is intended and the server MUST NOT attempt to apply the
request to some other resource. If the server desires that the request be
applied to a different URI,
it MUST send a 301 (Moved Permanently) response; the user agent MAY then
make its own decision regarding whether or not to redirect the request."(http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)
There is nothing relevant to data transformation between PUT and POST. It
is, for all intents and purposes, two completely different methods and you
should not assume one is similar to the other - especially based solely on
what you want PUT to do. PUT can contain query strings, POST-like bodies
and files or a combination of any.
Correct, the HTTP request verb is about describing the intent of the
request, which is what I said earlier. It is not about how to treat the
enclosed entity body. For that the specification describes additional
headers such as that of Content-type header. Nowhere did I suggest that the
request verbs themselves (i.e. PUT and POST) have the same intent. Just
that the handling of multipart-form data is not specific to either one of
those verbs.
Bottom line - you’re trying to change PHP’s form handling approach with
your view of what PUT could/should be doing. Don’t do that.
I'm trying to take advantage of the fact that PHP can parse the multipart
data regardless of the request verb. This is a good thing. It has added
benefits. I see no reason why this would be a negative impact on PHP. If
anything it makes PHP more useful in dealing with additional request types
without the user having to parse the input stream themselves.
It’s blowing my mind that you are still arguing this point, and I believe
it’s time to put it to bed. Come up with a better solution, put this RFC
to a vote (even without a patch) or retract it. You have have almost
nothing but criticism, and this thread is at the point of wasting valuable
time.
I'm sorry you feel that there is a waste of valuable time in this thread.
By all means, if you feel that this thread is a waste of your time please
disregard it. I have no intention of putting anything to a vote until I
feel it is ready. Since it is currently a draft I feel no obligation to
retract it. I do appreciate your time and input, however.
Nowhere did I suggest that the request verbs themselves (i.e. PUT and POST) have the same intent. Just
that the handling of multipart-form data is not specific to either one of
those verbs.
Define "handling." :/
"Handling" as in "interpreting multipart/form-data as key-value
pairs": a specific, intimate relationship with POST exists in RFC 1867
and in the HTML4 and 5 specs. These documents show the relationship
between POST and multipart/form-data to be a very special one, one in
which the innards of a form-data entity-body are meant to be expanded
at runtime to replay the individual fields of an originating form.
There is no such document that relates to PUT.
"Handling" as in "accepting data that happens to be
multipart/form-data": of course that's not method-specific. It's not
even HTTP-specific anymore. As of RFC 2388, form-data can be sent from
Adobe Acrobat over IPX/SPX to an AS/400. That's great, it's a real
standard. MIME decoders/encoders will grok it as a specialization of
multipart MIME, and apps can apply stricter validation than for
multipart/mixed (for example, mandatory part names). The expanded
standard also means that intermediate systems may be designed to
transport or save multipart/form-data messages instead of
reading them. Which brings us back to the point: hands off PUT
entities, unless there's overriding local knowledge that they must be
read instead of stored.
I see no reason why this would be a negative impact on PHP.
Because if someone PUTs 2 GB of multipart/form-data I don't want it
decoded just because somewhere in my code path there's a reference to
$_POST.
-- S.
On Thu, Nov 6, 2014 at 3:20 AM, Sanford Whiteman figureonecpr@gmail.com
wrote:
Nowhere did I suggest that the request verbs themselves (i.e. PUT and
POST) have the same intent. Just
that the handling of multipart-form data is not specific to either one of
those verbs.Define "handling." :/
Specifically, parsing the form data and populating it somewhere accessible
to the user as it is today in $_POST and making any binary upload available
in $_FILES or some other fashion. Ideally, making handling PUT more
consistent with the way PHP handles POST.
"Handling" as in "interpreting multipart/form-data as key-value
pairs": a specific, intimate relationship with POST exists in RFC 1867
First of all, RFC 1867 is not a standard. It's an experimental protocol
definition. No where in the internet standards tracking documents do I see
a definition that restricts multipart/form-data to POST. I think what
you're referring to is the fact that the client UAs typically only ever
handle form data as multipart/form-data mime as POST-specific requests.
This is of course tied to the fact that client UAs don't typically follow
the same intents of a RESTful API client/server relationship. Allow me to
re-iterate the fact that this is one of the primary focuses of this
discussion. That people normally want to deal with PUT requests in PHP
under the umbrella of building their own RESTful APIs.
I see no reason why this would be a negative impact on PHP.
Because if someone PUTs 2 GB of multipart/form-data I don't want it
decoded just because somewhere in my code path there's a reference to
$_POST.
It's the same thing as with a POST request today in PHP. Nothing is
stopping anyone from sending a you 2 GB multipart/form-data POST request
either. You should be checking intent before dealing with $_POST from the
$_SERVER['REQUEST_METHOD'] anyway, since you can't realy on $_POST
necessarily being indicative of the request method anyway.
-- S.
Specifically, parsing the form data and populating it somewhere accessible
to the user as it is today in $_POST and making any binary upload available
in $_FILES or some other fashion. Ideally, making handling PUT more
consistent with the way PHP handles POST.
OK, the first definition: "handling" means parsing multipart/form-data
automatically into form field names and values. And again there are
specific documents that expect this to be done for POST (and
understandably so) but no such documents for PUT. Which means you
want PUT to act as if it were as formally defined as POST. Which is
where we started from: you are transplanting a standard from one
method to the other. This doesn't mean you are violating an extant
standard, it just is very, very far from compelling. And your best
justifications for a present-tense need were wontfixes submitted by
relative newbies.
First of all, RFC 1867 is not a standard. It's an experimental protocol
definition.
Oh nonsense. You know very well that RFC 1867 conformance is an
industry standard for file uploading When 2388 says "originally set
out in [RFC1867] and subsequently incorporated into [HTML40]" it is
not treating 1867 as some fringe document. Non-HTML uploaders
(Flash/Java/Silverlight/cURL/all of them) use RFC 1867 as their design
spec, not as some wacky experiment.
http://lmgtfy.com/?q=rfc+1867+file+upload+support
No where in the internet standards tracking documents do I see a
definition that restricts multipart/form-data to POST.
You're deliberately phrasing it backwards. The documents re: POST
enshrine multipart/form-data as one of two encodings. There are no
documents re: PUT that refer to form encoding.
And I never said there was a restriction; in fact I specifically
outlined how 2388 breaks all restrictions on multipart/form-data.
However "no restriction" !== "an automatic connection."
I think what you're
referring to is the fact that the client UAs typically only ever handle form
data as multipart/form-data mime as POST-specific requests. This is of
course tied to the fact that client UAs don't typically follow the same
intents of a RESTful API client/server relationship. Allow me to re-iterate
the fact that this is one of the primary focuses of this discussion. That
people normally want to deal with PUT requests in PHP under the umbrella of
building their own RESTful APIs.
Show me the RESTful justification for decomposing PUT requests
automatically. There is none.
There may be local knowledge that justifies decomposing PUT requests
as if they are POST-like but it is not RESTful. I've read all the
REST cookbooks there are. You're trying to make this a thing, and
it's not.
It's the same thing as with a POST request today in PHP. Nothing is stopping
anyone from sending a you 2 GB multipart/form-data POST request either.
Stop moving the damn goalposts and stay on topic. We are talking
about a PUT today in PHP. Right now, that doesn't cost me
anything. In your model it can cost me a lot. We have plenty of ways
of warding off oversize requests depending on method.
should be checking intent before dealing with $_POST from the $_SERVER['REQUEST_METHOD'] anyway, since you can't relay on $_POST
necessarily being indicative of the request method anyway.
Certainly with your new feature one would be ill-advised to assume
that anything is what it seems.
On Thu, Nov 6, 2014 at 4:32 AM, Sanford Whiteman figureonecpr@gmail.com
wrote:
First of all, RFC 1867 is not a standard. It's an experimental protocol
definition.Oh nonsense. You know very well that RFC 1867 conformance is an
industry standard for file uploading When 2388 says "originally set
out in [RFC1867] and subsequently incorporated into [HTML40]" it is
not treating 1867 as some fringe document. Non-HTML uploaders
(Flash/Java/Silverlight/cURL/all of them) use RFC 1867 as their design
spec, not as some wacky experiment.
http://lmgtfy.com/?q=rfc+1867+file+upload+support
I know that RFC 1867 clearly states it is not a standard.
"This memo defines an Experimental Protocol for the Internet community.
This memo does not specify an Internet standard of any kind." [1]
Also, you seem to be quoting out of context with the intention that the
reader will not try to seek out said context and simply assume your
supporting argument is sound and well-rounded. It is not. The standard you
are referring to [RFC 2388] only mentions the non-standard [RFC 1867] in
its introduction to state where the definition of multipart form data was
derived in these applications. This does not constitute RFC 1867 as a
standard.
Yes, HTML form data is where the need for multipart form data was
originally derived. As we know, client UAs implementing forms typically
either restrict the method to either GET, or in the case of constructing
multipart/form-data MIME, POST. However, as you mentioned, it has since
spread to be implemented in many other applications (outside of the scope
of HTML) such as in the case of FDFs.
I understand all of this and I get why you're making a strong connection
between POST and multipart/form-data mime. The part I'm not getting is why
you believe a multipart/form-data mime cannot be sent along with a PUT
request. The two things are independent of one another as I see it. One is
a media type header and describes the enclosed entity type (i.e.
multipart/form-data or application/x-json or whatever the content type may
be) and the other is an intent of request verb that describes the user's
intention in making the request (i.e. POST/PUT).
For the umpteenth time, in what situation must you PUT multipart/form-data or multipart/x-www-form-urlencoded only to treat it, semantically, as a POST? Which UA cannot send a POST? It's like we're completely upside down on this thread.
If you're PUTing such POSTful content-types for any reason other than storing the entire resource, you're doing HTTP wrong. Truthfully: if someone said, "Yeah, so we got into PUT lately, we use it for Ajax form, er, posts, for, um, speed or something," would you not be like, "Wat?"
-- S.
On Wed, Nov 5, 2014 at 10:03 PM, Sanford Whiteman figureonecpr@gmail.com
wrote:
For the umpteenth time, in what situation must you PUT
multipart/form-data or multipart/x-www-form-urlencoded only to treat it,
semantically, as a POST? Which UA cannot send a POST? It's like we're
completely upside down on this thread.
If you're PUTing such POSTful content-types for any reason other than
storing the entire resource, you're doing HTTP wrong. Truthfully: if
someone said, "Yeah, so we got into PUT lately, we use it for Ajax form,
er, posts, for, um, speed or something," would you not be like, "Wat?"
The HTTP specification doesn't restrict how the request body is encoded
based on the request verb. That is up to the content-type and
content-encoding headers. The request verbs themselves are indicative of
intent in the request, not necessarily the composition of said request. So
we're dealing with decomposition not intent. That part is up to the user
not PHP.
multipart form data is useful for including both form data and binary data
with successive parts. Typically the method applied for this mime in the
client UA is POST, but many APIs may apply a PUT request using multipart
form. There's no reason to be restrictive of that in PHP if we doesn't
break compatibility, I don't think.
These are real world problems that people deal with in on the web every day.
Here are some sources to demonstrate real world use cases and issues:
http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
Let's face it. The web is a very imperfect place, but it's very tolerance
to fault is what makes it work so well. Clearly we don't agree with
everything that's done on the web, but that doesn't mean we can't help make
PHP a little more useful on the web.
-- S.
The HTTP specification doesn't restrict how the request body is encoded
based on the request verb.
I never said it did... please don't put words in my mouth.
As Will notes, you're sidestepping the point, which standards-savvy
people have been driving at for years: the semantic differences (==
intent, == meaning) among HTTP methods. HTTP specifications do
define -- in your words, "restrict" -- the intended disposition of the
entity-body based on the HTTP method. The methods do distinguish
whether the entity-body is intended as a precomposed resource to be
stored at the request-URI (PUT) -- or whether it may contain key-value
strings, multipart MIME data, or arbitrary text and/or binary data
ranges (POST) which must be interpreted by application code at the
request-URI (which must itself exist) as they have no inherent final
disposition.
It's easy to certify the semantics in your lab.
Set up a capable web server with no preprocessor at all (no PHP, no
SSI, nothing). Choose a URI that currently returns a 404, like
/test.abc. PUT a well-formed multipart/form-data body to that URI.
What you will get is the entire multipart stored within the filesystem
at the mapped URI. And provided the server's file extension <-> MIME
mappings are consistent, you'll then be able to GET the file as
multipart/form-data.
Now POST that body to another nonexistent URI. You'll get a 404 or
- Full stop.
This core difference is really not that hard to understand, and
there's no reason for PHP to act, stupidly, like it it isn't there (as
in make-people-dumber stupid, not make-life-easy stupid).
multipart form data is useful for including both form data and binary data with successive parts
Of course. Multipart MIME is also key to the modern e-mail ecosystem.
And, similarly, multipart e-mails are kept as opaque as possible in
transit. Antivirus and spam scanners need to peek inside multipart
mail, but they don't decompose them and put the parts back on the wire
separately, because that is not the meaning of "transfer this e-mail."
Neither do end-user apps aim to decompose MIME messages when they're
idling in a message db, because that's not the meaning of "save this
e-mail." On the other hand multiparts are intended to be decomposed
by mail apps when a user opens them: in that case, there's a clear
semantic justification for expanding the contents for the user: "read
this e-mail."
In sum, "multipart is useful" is quite obviously true, but it's a
straw man, as it does not respond to the question about expanding
multipart entities in all contexts.
but many APIs may apply a PUT request using multipart form
People do dumb things. You haven't answered why they would fixate upon
PUT, since they cannot possibly lack support for POST. What, now for
the umpteenth++ time, is the technical/business/personal justification
for this design, with POST available? Again this whole debate is
upside down. People have to choose to use PUT, even in cURL. It
doesn't happen by accident. It's not the XMLHttpRequest default. It
can't happen from an HTML form. Why are they doing it?
If you read that report carefully you will see that it starts with
people name-dropping POST and PUT (because they don't understand the
difference), including bugs that appear to deal with POST alone.
Then, the feature request that does appear PUT-related is shot down by
the Symfony maintainers. Obviously, it wasn't wontfixed because it
couldn't be done, but because there was insufficient cause, despite
the initial claim that Symfony's update API was broken.
A wontfix "bug" report that doesn't even try to justify why PUT would
be used, only that it doesn't work. If a newbie confuses POST and PUT
when creating an Ajax object, is that a bug on the server?
http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
There's no mention at all in this post of a need for PUT, just a
note that Angular applies the same default content-type to POST and
PUT.
I see no compelling use case here, only an unsourced claim that "every
RESTful interface" would make use of this feature, which would be
better phrased "one particular not-at-all-RESTful interface."
On Thu, Nov 6, 2014 at 2:44 AM, Sanford Whiteman figureonecpr@gmail.com
wrote:
The HTTP specification doesn't restrict how the request body is encoded
based on the request verb.I never said it did... please don't put words in my mouth.
As Will notes, you're sidestepping the point, which standards-savvy
people have been driving at for years: the semantic differences (==
intent, == meaning) among HTTP methods. HTTP specifications do
define -- in your words, "restrict" -- the intended disposition of the
entity-body based on the HTTP method. The methods do distinguish
whether the entity-body is intended as a precomposed resource to be
stored at the request-URI (PUT) -- or whether it may contain key-value
strings, multipart MIME data, or arbitrary text and/or binary data
ranges (POST) which must be interpreted by application code at the
request-URI (which must itself exist) as they have no inherent final
disposition.It's easy to certify the semantics in your lab.
Set up a capable web server with no preprocessor at all (no PHP, no
SSI, nothing). Choose a URI that currently returns a 404, like
/test.abc. PUT a well-formed multipart/form-data body to that URI.
What you will get is the entire multipart stored within the filesystem
at the mapped URI. And provided the server's file extension <-> MIME
mappings are consistent, you'll then be able to GET the file as
multipart/form-data.Now POST that body to another nonexistent URI. You'll get a 404 or
- Full stop.
This core difference is really not that hard to understand, and
there's no reason for PHP to act, stupidly, like it it isn't there (as
in make-people-dumber stupid, not make-life-easy stupid).
First off, let's make some discrepancies abundantly clear.
PUT is not intended to necessarily store the request entity body on the
file system. Its intention is to store the entity body at the request URI.
That is to say, the URI !== File System.
So this unfounded claim that decomposition should not happen within PHP at
the request level, isn't a justification for prohibiting PHP from
decomposing the body. For example, if the Content-type designated in the
request indicates application/binary it is safe to say that PHP should not
attempt to disassemble the input stream beyond applying the decoding from
the Content-encoding header (which may actually happen at the web server
level). However, in this event it would make it a lot more convenient for
the client if the entity is stored in $_FILES where its access is still
more manageable through the receiving code. Wherein one can take advantage
of reliable features such as move_uploaded_file()
, which inhibit some
security measures that would be beneficial to the user. Again, we haven't
changed the intent of the request by making it easier for the user to take
advantage of existing PHP features to service said request. We also haven't
we changed the typical outcome of this request, because through today's
work-flow the input stream remains at the discretion of the user. With the
change of storing the input stream in $_FILES, the temporary file gets
discarded by PHP if the user doesn't move it. Same thing if they don't do
anything with the input stream (today).
Additionally, I don't believe that this makes PHP or its users any
"dumber". It just makes handling the request in PHP more consistent and
intuitive. This has both added convenience as well as added performance and
security benefits by taking advantage of already existing functionality in
PHP.
I completely understand, however, that the existing functionality only
targets form data. So while PUT requests aren't form data, they are still
very much a part of the overall handling of requests that can be sent to
PHP. So why not expand the same functionality to also target those use
cases? While you may see this as a fundamental change in the way PHP works,
it's not actually too far off from what PHP had always intended (which was
dealing with the web in the first place). It just so happens that PHP's
primary intention has been outgrown by the evolution of the web, which now
entails more RESTful APIs than before.
multipart form data is useful for including both form data and binary
data with successive partsOf course. Multipart MIME is also key to the modern e-mail ecosystem.
And, similarly, multipart e-mails are kept as opaque as possible in
transit. Antivirus and spam scanners need to peek inside multipart
mail, but they don't decompose them and put the parts back on the wire
separately, because that is not the meaning of "transfer this e-mail."
Neither do end-user apps aim to decompose MIME messages when they're
idling in a message db, because that's not the meaning of "save this
e-mail." On the other hand multiparts are intended to be decomposed
by mail apps when a user opens them: in that case, there's a clear
semantic justification for expanding the contents for the user: "read
this e-mail."In sum, "multipart is useful" is quite obviously true, but it's a
straw man, as it does not respond to the question about expanding
multipart entities in all contexts.
Sure, they are in transit up until they reach PHP. At which point they have
reached an end point capable of dealing with the request. In this analogy,
PHP would be the mail app. It would deal with both the opening and
facilitating of the message, because it very well may need to decompose
that message before storing it and then reassemble it in the retrieval
phase. It also may not have to, but that's up to the user writing the PHP
code on how they chose to deal with that part. Because PHP is a
pre-processor, after all. It's job is to assemble and disassemble
information in order to facilitate the request/response model that it's
built on.
Also, I think you're the one creating the straw man here as nothing in the
spec prohibits the use of a multipart mime based on the request verb. So we
aren't expanding it to all contexts since its context remains intact. It's
a media type intended to disclose itself to the server for the purpose of
identifying the enclosed body. It's still up to the server how to handle
that media type. No one says you may not decompose the multipart mime at
the server level.
but many APIs may apply a PUT request using multipart form
People do dumb things. You haven't answered why they would fixate upon
PUT, since they cannot possibly lack support for POST. What, now for
the umpteenth++ time, is the technical/business/personal justification
for this design, with POST available? Again this whole debate is
upside down. People have to choose to use PUT, even in cURL. It
doesn't happen by accident. It's not the XMLHttpRequest default. It
can't happen from an HTML form. Why are they doing it?
I think you're losing sight of the intent here. We're talking about people
trying to build RESTful APIs. Meaning that the intent of PUT varies from
POST. If you wanted to build a RESTful API similar to that of Google Drive,
for example, you wouldn't use POST to create new files on the drive. You
would want your API to make intentions very clear to differentiate between
POST/PUT/DELETE and so on... So the justification for using PUT is
self-serving. The choice of wanting to use a multipart mime is not for us
to try and justify. Why would you prohibit the user on the content-type if
the very protocol doesn't? We're just trying to make it easier for them to
handle that request as many are clearly struggling with it.
Finally I'd like to say that...
I think a lot of these arguments against allowing PHP to do something are
very opinionated and shouldn't be the basis of our decision. I think that
the decision to let PHP do something should be based on need, feasibility,
and maintainability, as they have usually been in the past. The idea of
letting PHP deal with PUT and other request verbs as consistently as it
deals with POST and GET is clearly needed. Whether or not some people like
it isn't important. What's important is that it's feasible (or seemingly so
up until this point) and only the actual implementation can prove its
maintainability. So I'd much rather focus on analyzing these points rather
than the opinions of whether not someone thinks one way of doing things is
considered under the guise of REST or not. Or whether not PHP should be
allowed to handle things other than form data. Why wouldn't it? PHP is a
web-focused language. This is an HTTP-specific problem and PHP is capable
of handling it.
PUT is not intended to necessarily store the request entity body on the file
system. Its intention is to store the entity body at the request URI.
I never said it was. I used the expression "store at the URI" about
10 ten times on this topic. You are arguing in bad faith by putting
words in my mouth. Stop.
In a barebones implementation with just an HTTPd, PUT does mean the
filesystem, which gives an easy example of how incredibly semantically
different it is from POST. Most people do not understand the concept
unless you give them a simple example.
So this unfounded claim that decomposition should not happen within PHP at the request level, isn't a justification for prohibiting PHP from decomposing the body.
I made no such claim. I maintain that decomposition not be required
to happen within PHP. I couldn't care less if you make it optional
and don't use the $_POST superglobal. I've said this over and over.
Expose the core MIME parser to the user. That'll make it easily used
by frameworks, or via auto_prepend_file. Do not do it automatically
for all requests.
For example, if the Content-type designated in the request indicates application/binary it is safe to say that PHP should not attempt to disassemble the input stream beyond applying > the decoding from the Content-encoding header (which may actually happen at the web server level). However, in this event it would make it a lot more convenient for the client if the > entity is stored in $_FILES where its access is still more manageable through the receiving code.
I noted this case in the other thread and let it be laughed off, but I
actually believe that this is a relatively sensible option, since it
doesn't require any decoding. For that matter, I
ninety-percent-kiddingly wondered if an application/tar body could be
decomposed and its constituent files put into $_FILES, since that's a
case we actually use daily. Again under user control, and not for
every request to a given PHP install, but a kind of pre-superglobal
API would be cool. Of course I know it'll never happen and I'm fine
with that.
On Thu, Nov 6, 2014 at 4:56 AM, Sanford Whiteman figureonecpr@gmail.com
wrote:
PUT is not intended to necessarily store the request entity body on the
file
system. Its intention is to store the entity body at the request URI.I never said it was. I used the expression "store at the URI" about
10 ten times on this topic. You are arguing in bad faith by putting
words in my mouth. Stop.
Well, let's not exaggerate. You used the term "store at the request-URI"
once in the message from which that reply was intended. However, I was
responding to: "What you will get is the entire multipart stored within the
filesystem at the mapped URI."
Which isn't necessarily true. Albeit the phrasing here can be ambiguous and
open to interpretation, because I read it as "the URI maps to the
filesystem". The object of the sentence is pretty ambiguous here, but in
any case the filesystem itself really has nothing to do with where the data
will be stored. It could be stored in a database, or directly on the node
accepting the request, or even distributed remotely to other nodes. That
part is an implementation detail left up to the server. The point is that
the URI signifies the place where the client intends to make the resource
available. So the client should be able to retrieve said resource from that
URI (or such is the intent).
In a barebones implementation with just an HTTPd, PUT does mean the
filesystem, which gives an easy example of how incredibly semantically
different it is from POST. Most people do not understand the concept
unless you give them a simple example.
Again, you're getting into implementation details here and deviating away
from the specification. There are httpd implementations where PUT does not
correlate URI to file system path. I do fully understand the intent of PUT.
I can also do without snarky remarks like this where you feel you need to
dumb things down as though I have no clue what I"m talking about (like with
the LMGTF urls and this feeble attempt at explaining PUT vs. actually
focusing on the discussion).
I do have some understand of how the web works. I am responsible for
working out problems on the web for one of the world's largest sites, after
all. So give me some credit.
To tackle your point fully, however, you want to keep in mind that you are
reading too much into the specification. The spec is laying out the intent
of PUT in that the client should be allowed to determine the designated URI
where the entity will be stored. This doesn't restrict the media type of
the entity in any way. You're assuming that the enclosed entity and the way
in which it is stored are disconnected. This is not necessarily true nor is
it a part of the specification.
Here we just want to ensure two things...
- That the request URI is the place where client will store the entity
- That the server cannot decide to change this URI without the approval of
the client
We can fully meet all of these requirements even if the enclosed entity is
infact a multipart mime. There should also be no restriction on the server
or end-point decomposing this request in order to better figure out how it
should be stored. Just like your email server can inspect headers and
decompose the mime to inspect the email for spam/viruses/etc... before
figuring out where it should go. It doesn't mean we've broken anything.
Just that we've made it easier for PHP users to handle these requests more
consistently. For example, perhaps I need check for authentication data, or
there are multiple files enclosed in the request (file versioning, for
example which is possible in Amazon S3 today). These are important factors
you don't seem to be taking into consideration at all. In fact the more you
try to dumb down the specification, the less you are sticking to its
requirements, because the spec is actually very straight forward and
simple. It's describing the client's intent from the request. That's it.
Nothing less, and nothing more. We aren't violating that intent if we allow
multipart form data to be populated in PHP by this request.
So this unfounded claim that decomposition should not happen within PHP
at the request level, isn't a justification for prohibiting PHP from
decomposing the body.I made no such claim. I maintain that decomposition not be required
to happen within PHP. I couldn't care less if you make it optional
and don't use the $_POST superglobal. I've said this over and over.
Expose the core MIME parser to the user. That'll make it easily used
by frameworks, or via auto_prepend_file. Do not do it automatically
for all requests.
We are exposing the benefits to the user by populating the super global.
Letting userland do the work would make for a less efficient
implementation. I'm not seeing any objective reason why we shouldn't do it
automatically. Just that you're suggesting we don't. Is there a reason why
not?
For example, if the Content-type designated in the request indicates
application/binary it is safe to say that PHP should not attempt to
disassemble the input stream beyond applying > the decoding from the
Content-encoding header (which may actually happen at the web server
level). However, in this event it would make it a lot more convenient for
the client if the > entity is stored in $_FILES where its access is still
more manageable through the receiving code.I noted this case in the other thread and let it be laughed off, but I
actually believe that this is a relatively sensible option, since it
doesn't require any decoding. For that matter, I
ninety-percent-kiddingly wondered if an application/tar body could be
decomposed and its constituent files put into $_FILES, since that's a
case we actually use daily. Again under user control, and not for
every request to a given PHP install, but a kind of pre-superglobal
API would be cool. Of course I know it'll never happen and I'm fine
with that.
I can see that you're opposed to doing things in every request, but is
there an actual reason to take existing functionality, and rather than
amend it to handle a broader array of requests, simply augment it to
diverge off into two separate code paths, where one is optional and the
other is mandatory?
I'm still having trouble understanding the why. The objection, I've clearly
heard, and a 2GB PUT request is not going to lend itself as an argument
against when it applies equally to POST. They would both be handled in the
same manner (in respect to multipart form data) so how can you say that
it's only bad when it's PUT, but it's OK when it's POST if they would
exhibit the same behavior? That part just doesn't make any sense to me.
Hi!
Again, I think you're oversimplifying the problem. For one, you don't know
that the payload is JSON unless you check the Content-type header yourself,
and you really shouldn't have to since PHP could easily do this for you.
Sure, PHP could easily do this, or any other one specific use case for
you. What it can't do, however, is to do all 1000 use cases that modern
REST application presents, automatically for you. What if you use XML
and not JSON? What if you use both and determine which one it is by
request URL suffix being .xml or .json? What if it instead is switched
by query parameter? What if also it can be compressed, encrypted and
wrapped in some MIME multipart message? Having all these complications
handled in the core of PHP would be extremely hard, not because each of
them is hard, but because there can be so many of them. And you'd run a
big change of PHP still not matching your specific case exactly, or
being behind times, because core can not evolve as quickly as userland
does. That's why it's better done in extensions or user space - unless
you can identify a case which covers a huge proportion of all cases -
just like forms are for POST. For generic REST, I'm not sure there's
such case, except for very generic API giving access to the basic
request, its fields and supporting basic URL/MIME parsing.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hi!
Again, I think you're oversimplifying the problem. For one, you don't know
that the payload is JSON unless you check the Content-type header yourself,
and you really shouldn't have to since PHP could easily do this for you.Sure, PHP could easily do this, or any other one specific use case for
you. What it can't do, however, is to do all 1000 use cases that modern
REST application presents, automatically for you. What if you use XML
and not JSON? What if you use both and determine which one it is by
request URL suffix being .xml or .json? What if it instead is switched
by query parameter? What if also it can be compressed, encrypted and
wrapped in some MIME multipart message? Having all these complications
handled in the core of PHP would be extremely hard, not because each of
them is hard, but because there can be so many of them. And you'd run a
big change of PHP still not matching your specific case exactly, or
being behind times, because core can not evolve as quickly as userland
does. That's why it's better done in extensions or user space - unless
you can identify a case which covers a huge proportion of all cases -
just like forms are for POST. For generic REST, I'm not sure there's
such case, except for very generic API giving access to the basic
request, its fields and supporting basic URL/MIME parsing.
Even just parsing JSON isn’t as simple as it sounds. There are several things users might like to configure, several ways to parse JSON (objects vs. arrays, big numbers as floats or strings, etc.), while for form-data there’s only one way.
--
Andrea Faulds
http://ajf.me/
Hi!
Again, I think you're oversimplifying the problem. For one, you don't
know
that the payload is JSON unless you check the Content-type header
yourself,
and you really shouldn't have to since PHP could easily do this for you.Sure, PHP could easily do this, or any other one specific use case for
you. What it can't do, however, is to do all 1000 use cases that modern
REST application presents, automatically for you. What if you use XML
and not JSON? What if you use both and determine which one it is by
request URL suffix being .xml or .json? What if it instead is switched
by query parameter? What if also it can be compressed, encrypted and
wrapped in some MIME multipart message? Having all these complications
handled in the core of PHP would be extremely hard, not because each of
them is hard, but because there can be so many of them. And you'd run a
big change of PHP still not matching your specific case exactly, or
being behind times, because core can not evolve as quickly as userland
does. That's why it's better done in extensions or user space - unless
you can identify a case which covers a huge proportion of all cases -
just like forms are for POST. For generic REST, I'm not sure there's
such case, except for very generic API giving access to the basic
request, its fields and supporting basic URL/MIME parsing.Even just parsing JSON isn’t as simple as it sounds. There are several
things users might like to configure, several ways to parse JSON (objects
vs. arrays, big numbers as floats or strings, etc.), while for form-data
there’s only one way.
Well, in this case it will be parsed as an array since $_POST is naturally
parsed as an array. Also, since $_POST/$_GET are typically always processed
as strings it would only make sense to use big numbers as strings in the
JSON parsing as well. I don't think this is the big issue. The bigger issue
is do users typically find the population of $_POST more useful than just
reading the input stream themselves and handling the JSON payload on their
own.
--
Andrea Faulds
http://ajf.me/
Hi!
Again, I think you're oversimplifying the problem. For one, you don't
know
that the payload is JSON unless you check the Content-type header
yourself,
and you really shouldn't have to since PHP could easily do this for you.Sure, PHP could easily do this, or any other one specific use case for
you. What it can't do, however, is to do all 1000 use cases that modern
REST application presents, automatically for you. What if you use XML
and not JSON? What if you use both and determine which one it is by
request URL suffix being .xml or .json? What if it instead is switched
by query parameter? What if also it can be compressed, encrypted and
wrapped in some MIME multipart message? Having all these complications
handled in the core of PHP would be extremely hard, not because each of
them is hard, but because there can be so many of them. And you'd run a
big change of PHP still not matching your specific case exactly, or
being behind times, because core can not evolve as quickly as userland
does. That's why it's better done in extensions or user space - unless
you can identify a case which covers a huge proportion of all cases -
just like forms are for POST. For generic REST, I'm not sure there's
such case, except for very generic API giving access to the basic
request, its fields and supporting basic URL/MIME parsing.Even just parsing JSON isn’t as simple as it sounds. There are several
things users might like to configure, several ways to parse JSON (objects
vs. arrays, big numbers as floats or strings, etc.), while for form-data
there’s only one way.Well, in this case it will be parsed as an array since $_POST is naturally
parsed as an array. Also, since $_POST/$_GET are typically always processed
as strings it would only make sense to use big numbers as strings in the
JSON parsing as well. I don't think this is the big issue. The bigger issue
is do users typically find the population of $_POST more useful than just
reading the input stream themselves and handling the JSON payload on their
own.
Sherif - I’m just going to be straight here. I haven’t seen support for your proposal at all in this thread. You continue to try and make this case, but it continues to be shot down with absolutely valid issues, and your only responsive action is to argue back. Why aren’t you considering alternatives? Everything - and I do mean everything - that you want is available in pecl/http, and there’s already an RFC to get it into core. Why can’t you get behind that and either support it, or move to propose an alternative that is supportable by at least someone. Your current proposal is not supported by anyone in this thread, and you still can’t see that.
I admire and appreciate your efforts in making PHP better, but it’s time to go back to the drawing board on this proposal. Everyone is against it, and I feel this thread’s patience is running thin.
--
Andrea Faulds
http://ajf.me/ <http://ajf.me/
Sherif - I’m just going to be straight here. I haven’t seen support for
your proposal at all in this thread. You continue to try and make this
case, but it continues to be shot down with absolutely valid issues, and
your only responsive action is to argue back. Why aren’t you considering
alternatives? Everything - and I do mean everything - that you want is
available in pecl/http, and there’s already an RFC to get it into core.
Why can’t you get behind that and either support it, or move to propose an
alternative that is supportable by at least someone. Your current proposal
is not supported by anyone in this thread, and you still can’t see that.I admire and appreciate your efforts in making PHP better, but it’s time
to go back to the drawing board on this proposal. Everyone is against it,
and I feel this thread’s patience is running thin.
I think you're looking too closely at the problem to have an objective
view. While I appreciate your continued input and feedback, I don't believe
you're fairly judging my motives or my objectives. Who says I'm not
considering alternatives? You have to keep in mind the RFC is still in
draft. I'm technically not even putting up for discussion yet because I've
failed to make a coherent proposal. I get that. I'd still like to hear what
others have to say. I will make my own assessments of the collective facts.
In the mean time I'm OK with the discussion of my initial proposal being
objectionable. I gladly embrace failure as I expect to learn from it.
I'm not sure why it is you feel as though me having a technical discussion
with the community equates to me agreeing with everyone else's opinion or
ending a discussion on the note that it is no longer useful because
everyone disagrees with me.
I gather valuable knowledge from disagreement and intend to pursue those
disagreements until I can reach a fully objective outlook on all of the
moving parts at hand. I don't wish to abandon this discussion because the
initial proposal has no support.
I'm sorry if you feel that you are no longer interested in the discussion,
but can you at least refrain from cluttering the discussion aggressively
with your synopsis? Everyone is providing valuable objective outlooks and
those that have no more objectivity have seemingly refrained from further
discussion. That I'm perfectly OK with. What I'm not OK with is someone
that feels they must terminate the discussion because there is
disagreement. I am in the very process of understanding others'
disagreements. Please do not impede on my efforts by assuming you have any
idea what is going on in my head.
Thanks.
Sherif - I’m just going to be straight here. I haven’t seen support for your proposal at all in this thread. You continue to try and make this case, but it continues to be shot down with absolutely valid issues, and your only responsive action is to argue back. Why aren’t you considering alternatives? Everything - and I do mean everything - that you want is available in pecl/http, and there’s already an RFC to get it into core. Why can’t you get behind that and either support it, or move to propose an alternative that is supportable by at least someone. Your current proposal is not supported by anyone in this thread, and you still can’t see that.
I admire and appreciate your efforts in making PHP better, but it’s time to go back to the drawing board on this proposal. Everyone is against it, and I feel this thread’s patience is running thin.
I think you're looking too closely at the problem to have an objective view. While I appreciate your continued input and feedback, I don't believe you're fairly judging my motives or my objectives. Who says I'm not considering alternatives? You have to keep in mind the RFC is still in draft. I'm technically not even putting up for discussion yet because I've failed to make a coherent proposal. I get that. I'd still like to hear what others have to say. I will make my own assessments of the collective facts. In the mean time I'm OK with the discussion of my initial proposal being objectionable. I gladly embrace failure as I expect to learn from it.
It’s only a failure if you don’t learn from it and stop. I admire your efforts.
I'm not sure why it is you feel as though me having a technical discussion with the community equates to me agreeing with everyone else's opinion or ending a discussion on the note that it is no longer useful because everyone disagrees with me.
The discussion would be more useful if you proposed an alternative. So far, all I’ve seen is arguments why your original discussion could work.
I gather valuable knowledge from disagreement and intend to pursue those disagreements until I can reach a fully objective outlook on all of the moving parts at hand. I don't wish to abandon this discussion because the initial proposal has no support.
Nor should you. I do feel that time has been reached as there are multiple people that have retired from discussing this further. That is an indicator that this discussion has run its course.
I'm sorry if you feel that you are no longer interested in the discussion, but can you at least refrain from cluttering the discussion aggressively with your synopsis? Everyone is providing valuable objective outlooks and those that have no more objectivity have seemingly refrained from further discussion. That I'm perfectly OK with. What I'm not OK with is someone that feels they must terminate the discussion because there is disagreement. I am in the very process of understanding others' disagreements. Please do not impede on my efforts by assuming you have any idea what is going on in my head.
I am very interested in discussing this - but not in discussing the same proposal over and over. We have beaten a dead horse, and the horse has come back as a zombie and been defeated twice over. I actually believe your point is valid that the HTTP interface could use some work, but the approach you’re pushing just isn’t it.
Thanks.
On Nov 7, 2014, at 12:38 AM, Sherif Ramadan theanomaly.is@gmail.com
wrote:Sherif - I’m just going to be straight here. I haven’t seen support for
your proposal at all in this thread. You continue to try and make this
case, but it continues to be shot down with absolutely valid issues, and
your only responsive action is to argue back. Why aren’t you considering
alternatives? Everything - and I do mean everything - that you want is
available in pecl/http, and there’s already an RFC to get it into core.
Why can’t you get behind that and either support it, or move to propose an
alternative that is supportable by at least someone. Your current proposal
is not supported by anyone in this thread, and you still can’t see that.I admire and appreciate your efforts in making PHP better, but it’s time
to go back to the drawing board on this proposal. Everyone is against it,
and I feel this thread’s patience is running thin.I think you're looking too closely at the problem to have an objective
view. While I appreciate your continued input and feedback, I don't believe
you're fairly judging my motives or my objectives. Who says I'm not
considering alternatives? You have to keep in mind the RFC is still in
draft. I'm technically not even putting up for discussion yet because I've
failed to make a coherent proposal. I get that. I'd still like to hear what
others have to say. I will make my own assessments of the collective facts.
In the mean time I'm OK with the discussion of my initial proposal being
objectionable. I gladly embrace failure as I expect to learn from it.It’s only a failure if you don’t learn from it and stop. I admire your
efforts.I'm not sure why it is you feel as though me having a technical discussion
with the community equates to me agreeing with everyone else's opinion or
ending a discussion on the note that it is no longer useful because
everyone disagrees with me.The discussion would be more useful if you proposed an alternative. So
far, all I’ve seen is arguments why your original discussion could work.I gather valuable knowledge from disagreement and intend to pursue those
disagreements until I can reach a fully objective outlook on all of the
moving parts at hand. I don't wish to abandon this discussion because the
initial proposal has no support.Nor should you. I do feel that time has been reached as there are multiple
people that have retired from discussing this further. That is an indicator
that this discussion has run its course.I'm sorry if you feel that you are no longer interested in the discussion,
but can you at least refrain from cluttering the discussion aggressively
with your synopsis? Everyone is providing valuable objective outlooks and
those that have no more objectivity have seemingly refrained from further
discussion. That I'm perfectly OK with. What I'm not OK with is someone
that feels they must terminate the discussion because there is
disagreement. I am in the very process of understanding others'
disagreements. Please do not impede on my efforts by assuming you have any
idea what is going on in my head.I am very interested in discussing this - but not in discussing the same
proposal over and over. We have beaten a dead horse, and the horse has
come back as a zombie and been defeated twice over. I actually believe
your point is valid that the HTTP interface could use some work, but the
approach you’re pushing just isn’t it.Thanks.
Will, once again, you continue to make unfounded assumptions about me and
about the discussion. I get that you don't like what I'm saying. I just
feel that you've stated it enough times now :)
Remember, email doesn't disappear. People can always scroll back up and
reread what you've already said.
Thanks again for your reiterated input. I'd like to continue reading what
others are adding to the discussion like Stas, which had not voiced in
opinion prior to your little interjection.
On Thu, Nov 6, 2014 at 7:53 PM, Stas Malyshev smalyshev@sugarcrm.com
wrote:
Hi!
Again, I think you're oversimplifying the problem. For one, you don't
know
that the payload is JSON unless you check the Content-type header
yourself,
and you really shouldn't have to since PHP could easily do this for you.Sure, PHP could easily do this, or any other one specific use case for
you. What it can't do, however, is to do all 1000 use cases that modern
REST application presents, automatically for you. What if you use XML
and not JSON? What if you use both and determine which one it is by
request URL suffix being .xml or .json? What if it instead is switched
by query parameter? What if also it can be compressed, encrypted and
wrapped in some MIME multipart message? Having all these complications
handled in the core of PHP would be extremely hard, not because each of
them is hard, but because there can be so many of them. And you'd run a
big change of PHP still not matching your specific case exactly, or
being behind times, because core can not evolve as quickly as userland
does. That's why it's better done in extensions or user space - unless
you can identify a case which covers a huge proportion of all cases -
just like forms are for POST. For generic REST, I'm not sure there's
such case, except for very generic API giving access to the basic
request, its fields and supporting basic URL/MIME parsing.
Sure, you make a good point, here. The handling of a RESTful request in
user land may vary based on individual requirements. However, I'm not
proposing that PHP does the actual handling of the request, just that it
makes user land code more readily equipped to enable the user to do that
handling. In the same way that it does for POST. This creates some more
consistency and makes the typical request slightly more ubiquitous since
users are already used to $_POST and $_FILES when handling incoming request
input.
For this to be possible in a more generic sense this would mean that PHP
only relies on the Content-encoding and Content-type headers to determine
how to decode the payload and parse its contents into super global
variables such as $_POST and $_FILES. This is currently what PHP's SAPI
implementation already does. The changes required to make this available to
a wider array of use cases such as JSON vs form-url-encoded encoding, for
example, are not so complicated. After that it's up to the user to decide
what to do with the data in terms of handling the request.
Content-encoding will most likely be handled at a higher level than PHP as
it is in most cases today (deflate, etc... handled by the webserver)
If the Content-type is applicatoin/json, for example, instead of the normal
application/x-www-form-urlencoded, PHP would simply parse the enclosed
entity body as JSON rather than urldecode it. If the Content-type header is
set to a multipart/form-data MIME, then PHP does what it typically does
with POST, but allows PUT to work the same. You would still stick to the
same boundary requirements of the multipart/form-data MIME in the same way
that post does, so encoding can't vary. If the Content-type header is
application/binary, for example, we can simply make the file available in
$_FILES or just leave it in the input stream (probably best to just leave
it in that case). If PHP fails to find these headers properly set it would
fall back to the same thing it does today (leave it up to the input stream
consumer to parse the entity body).
I suppose if we also exposed the request headers to the user we could make
it more effective for them to make their own decisions about handling other
edge cases differently based on those request headers (such as in the case
of non-standard headers X-*, for example).
Here, I'm just proposing that PHP take on the addition of PUT handling in a
similar fashion that it does for POST, but only in the even that the
request comes in as a mulitpart/form-data MIME type. This could make a lot
of people's lives a little easier in dealing with PUT, but it's clearly not
a solution to for abstracting away the entire logic of handling RESTful
requests.
So I can definitely see your hesitation to include this in core.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hi!
makes user land code more readily equipped to enable the user to do that
handling. In the same way that it does for POST. This creates some more
Well, for POST PHP actually parses the data - url encoding, form
encoding, files, etc. - and puts it into the data structure. For generic
REST case, it'd be harder to do the same because there are too many
options of how the data could arrive.
For this to be possible in a more generic sense this would mean that PHP
only relies on the Content-encoding and Content-type headers to
determine how to decode the payload and parse its contents into super
global variables such as $_POST and $_FILES. This is currently what
PHP's SAPI implementation already does. The changes required to make
Currently, it supports only basic form encodings. But if we get into
handling all application types, it's a huge can of worms to have in core.
If the Content-type is applicatoin/json, for example, instead of the
normal application/x-www-form-urlencoded, PHP would simply parse the
enclosed entity body as JSON rather than urldecode it. If the
That's not as easy as you think. Even JSON can have different encodings,
be parsed in different way (json_decode right now has three options, and
could have more in the future) an so on. But that's only JSON - why
would then we single out JSON and not support XML or YAML or iCalendar
or any other 1001 formats?
multipart/form-data MIME in the same way that post does, so encoding
can't vary. If the Content-type header is application/binary, for
example, we can simply make the file available in $_FILES or just leave
There's no application/binary in standard MIME, ITYM
application/octet-stream, but files do not have to be octet-stream, they
can be of any type. And when you get the data, you in general don't know
if it is meant to be a file or field or something else - that's on the
app to decide. In the specific multipart/form-data case, we have
content-disposition which tells us it was a file upload, but if it's not
that format, all bets are off. In fact, nothing prevents a client from
sending a file contents but the server treating it as a regular data field.
Here, I'm just proposing that PHP take on the addition of PUT handling
in a similar fashion that it does for POST, but only in the even that
The problem is that while POST is used for forms (not only, but
frequenly especially in webform context), PUT can be used for anything.
We could of course make the core to identify PUT with
mulitpart/form-data and parse it in the POST manner, I don't see any
technical reason preventing that, but I think if you're already doing
generic REST, then you'd be better served by generic parsing library (or
a set of them) than by selecting one use case. I could be wrong of
course, if PUT+mulitpart/form-data is a frequent use case and I just am
not aware of it, then it makes sense to make RFC to add handling of it.
So the question here is how common is the case of PUT+mulitpart/form-data?
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
On Fri, Nov 7, 2014 at 4:49 PM, Stas Malyshev smalyshev@sugarcrm.com
wrote:
Hi!
So the question here is how common is the case of PUT+mulitpart/form-data?
Well, that's what I'm trying to establish. Based on the information I have
available, there have been a few dated bug reports asking for this. There
are also a lot of forums questions found on github/stackoverflow/etc...
that apparently find this useful. How useful it is and how common the use
case is may not be enough, though. Based on your feedback I can definitely
see a lot of people making future feature requests to add support for
additional content-types and I really don't think the SAPI implementation
should necessarily start heading down that road. Only because based on this
discussion I fear that no one other than myself will be eager to support
it. I'd rather not introduce cruft into PHP if I can avoid it.
I'll gather some more data and perhaps see if an initial implementation can
prove extensible enough.
On 5 Nov 2014, at 22:29, Sherif Ramadan theanomaly.is@gmail.com
wrote:From all the people I've spoken with that have a problem with
handling PUT
requests in PHP, it seems that they'd rather have PHP populate
$_FILES/$_POST automatically in this case. Which would be relatively
easy
to do by modifying the default post reader function in the SAPI
http://lxr.php.net/xref/PHP_5_6/main/php_content_types.c#51 however,
that
is itself a small BC break.Does anyone have any recommendations on what they think the best
approach
is? I'd appreciate any feedback/suggestions/constructive-criticism.
Thanks!I don’t think auto-populating for PUT/DELETE etc. is a good idea,
they’re quite different semantically. If I send a DELETE request to
code expecting a POST, and PHP pretends it’s a POST request, that’s
bad.However, I think the solution is simple: Add a function to do
multipart/form-data parsing. Not a suite of functions, not a class,
just one simple function. That way, for the few people that need it,
they can do $_POST =
multipart_form_data_parse(file_get_contents(‘php://input')); and their
problem’s solved.
I haven't caught up with every post in this thread, but I think this is actually the cleanest approach - functions which expose, or behave identically to, the parsing done to populate $_POST and $_FILE
A few weeks back, there was a discussion about supporting a particular binary serialisation format (I forget the name), and it occurred to me that we could have a framework for switching between various encodings, perhaps a bit like ext/filter. For the current case, you might write something like $_POST = decode_from_string(file_get_contents('php://input'), ENC_MULTIPART_FORM_DATA)
It could provide a much-needed decoder for session serialisation (without the awkward side effects of session_decode()
), and expose an interface for other extensions to register formats. This would be great for REST applications, because they could pass the incoming content type header to switch() and select a format (and perhaps some optional flags) to pass to the generic decoder.
The actual detail of expected formats, preferred flags, and the destination of the parsed data would be in the PHP application, where it can be easily tweaked, while the hard work of reading through the bytes, which users shouldn't need to modify anyway, would be left to C code. All without the behaviour of the SAPIs themselves having to change at all, as long as php://input is correctly populated.
Regards,
Rowan Collins
[IMSoP]
On 5 Nov 2014, at 22:29, Sherif Ramadan theanomaly.is@gmail.com
wrote:
From all the people I've spoken with that have a problem with
handling PUT
requests in PHP, it seems that they'd rather have PHP populate
$_FILES/$_POST automatically in this case. Which would be relatively
easy
to do by modifying the default post reader function in the SAPI
http://lxr.php.net/xref/PHP_5_6/main/php_content_types.c#51 however,
that
is itself a small BC break.Does anyone have any recommendations on what they think the best
approach
is? I'd appreciate any feedback/suggestions/constructive-criticism.
Thanks!I don’t think auto-populating for PUT/DELETE etc. is a good idea,
they’re quite different semantically. If I send a DELETE request to
code expecting a POST, and PHP pretends it’s a POST request, that’s
bad.However, I think the solution is simple: Add a function to do
multipart/form-data parsing. Not a suite of functions, not a class,
just one simple function. That way, for the few people that need it,
they can do $_POST =
multipart_form_data_parse(file_get_contents(‘php://input')); and their
problem’s solved.
I haven't caught up with every post in this thread, but I think this is actually the cleanest approach - functions which expose, or behave identically to, the parsing done to populate $_POST and $_FILEA few weeks back, there was a discussion about supporting a particular binary serialisation format (I forget the name), and it occurred to me that we could have a framework for switching between various encodings, perhaps a bit like ext/filter. For the current case, you might write something like $_POST = decode_from_string(file_get_contents('php://input'), ENC_MULTIPART_FORM_DATA)
It could provide a much-needed decoder for session serialisation (without the awkward side effects of
session_decode()
), and expose an interface for other extensions to register formats. This would be great for REST applications, because they could pass the incoming content type header to switch() and select a format (and perhaps some optional flags) to pass to the generic decoder.The actual detail of expected formats, preferred flags, and the destination of the parsed data would be in the PHP application, where it can be easily tweaked, while the hard work of reading through the bytes, which users shouldn't need to modify anyway, would be left to C code. All without the behaviour of the SAPIs themselves having to change at all, as long as php://input is correctly populated.
Regards,
On further reading and thought, perhaps an additional piece that would
make this feel less like the user having to do all the work themselves
would be a function which checked the Content-Type and Content-Encoding
headers and picked an appropriate flag for the decode function
automatically?
There is definitely a balance to be struck between code which magically
does the right thing in the majority of cases, and code which can be
reused in a variety of different recipes - for instance, using a mocked
HTTP request rather than the information coming out of the SAPI.
--
Rowan Collins
[IMSoP]