zendframework/zend-expressive-swoole

$_SERVER miss some important keys

Closed this issue · 7 comments

Hello,

As I said in issue #32 , the $_SERVER var miss some important keys like HTTP_HOST, HTTP_USER_AGENT... when you do an HTTP request.

A typical $_SERVER var in a Nginx server show as next:

Array
(
    [USER] => www-data
    [HOME] => /var/www
    [HTTP_CACHE_CONTROL] => max-age=0
    [HTTP_UPGRADE_INSECURE_REQUESTS] => 1
    [HTTP_CONNECTION] => keep-alive
    [HTTP_COOKIE] => PHPSESSID=ro1oc6i2u42l1scn2avlsss8l5
    [HTTP_ACCEPT_ENCODING] => gzip, deflate
    [HTTP_ACCEPT_LANGUAGE] => es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    [HTTP_USER_AGENT] => Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
    [HTTP_HOST] => localhost:8910
    [APPLICATION_ENV] => production
    [SERVER_NAME] => 
    [SERVER_PORT] => 80
    [SERVER_ADDR] => 192.168.80.2
    [REMOTE_PORT] => 46794
    [REMOTE_ADDR] => 192.168.80.1
    [SERVER_SOFTWARE] => nginx
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [DOCUMENT_ROOT] => /var/www/public
    [DOCUMENT_URI] => /index.php
    [REQUEST_URI] => /microservice/pdf
    [SCRIPT_FILENAME] => /var/www/public/index.php
    [SCRIPT_NAME] => /index.php
    [CONTENT_LENGTH] => 
    [CONTENT_TYPE] => 
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [PATH_TRANSLATED] => /var/www/public
    [PATH_INFO] => 
    [DN] => 
    [FCGI_ROLE] => RESPONDER
    [PHP_SELF] => /index.php
    [REQUEST_TIME_FLOAT] => 1537960083.3503
    [REQUEST_TIME] => 1537960083
)

But if you do a $request->getServerParams() in your handler you can see $_SERVER miss many keys

Array
(
    [QUERY_STRING] => getvar=getvalue
    [REQUEST_METHOD] => POST
    [REQUEST_URI] => /document
    [PATH_INFO] => /document
    [REQUEST_TIME] => 1537958456
    [REQUEST_TIME_FLOAT] => 1537958457.4177
    [SERVER_PORT] => 80
    [REMOTE_PORT] => 49168
    [REMOTE_ADDR] => 192.168.4.20
    [MASTER_TIME] => 1537958456
    [SERVER_PROTOCOL] => HTTP/1.1
    [SERVER_SOFTWARE] => swoole-http-server
)

Also, if you inspect the $request->server property in Zend\Expressive\Swoole\SwooleRequestHandlerRunner::onRequest you can see the keys are different too

Array
(
    [HOSTNAME] => nnode
    [PWD] => /var/www
    [HOME] => /root
    [affinity:container] => =9a6cd4c7a947936e067b172056fb0512f74503cfed9b636e3f8eb8bc3095a613
    [PHP_APP_SUPPORT] => jgalvez@soax.es
    [TERM] => xterm
    [SHLVL] => 1
    [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    [OLDPWD] => /
    [_] => /usr/bin/php
    [PHP_SELF] => public/index.php
    [SCRIPT_NAME] => public/index.php
    [SCRIPT_FILENAME] => public/index.php
    [PATH_TRANSLATED] => public/index.php
    [DOCUMENT_ROOT] => 
    [REQUEST_TIME_FLOAT] => 1537958454.4858
    [REQUEST_TIME] => 1537958454
    [argv] => Array
        (
            [0] => public/index.php
            [1] => start
        )

    [argc] => 2
    [SHELL_VERBOSITY] => 0
)

You can see that the last $_SERVER var is the correspondent to a php cli environment.

Could it be possible to have, approximately, the same keys than in Nginx server for $_SERVER var and $request->getServerParams()?

@jgalvezsoax Actually all begin with HTTP_ parameters are belongs to Header of HTTP Request, not Server parameters, you could get these value via $request->getHeaders()

Indeed @huangzhhui , HTTP_ parameters are in $request->getHeaders(), I didn't know it.

Array
(
    [content-type] => Array
        (
            [0] => multipart/form-data; boundary=--------------------------153560298166903737033389
        )

    [cache-control] => Array
        (
            [0] => no-cache
        )

    [postman-token] => Array
        (
            [0] => 60c27c86-904c-420e-a6b7-12f0bda8355c
        )

    [authorization] => Array
        (
            [0] => Basic STFkMWdYYWNDcFNnNUpuaTZ5WmdDWTc4MzpCZWZxU0tGN1pWeXJZNDd5QTJveE5BYkNST0NuYjV3aHNtMElVaUUzY24xOFFLUW9sSg==
        )

    [user-agent] => Array
        (
            [0] => PostmanRuntime/7.3.0
        )

    [accept] => Array
        (
            [0] => */*
        )

    [accept-encoding] => Array
        (
            [0] => gzip, deflate
        )

    [content-length] => Array
        (
            [0] => 171
        )

    [connection] => Array
        (
            [0] => keep-alive
        )

    [Host] => Array
        (
            [0] => 192.168.4.20:8912
        )

)

But the names of the keys are not the standard shown in php documentation - http://php.net/manual/en/reserved.variables.server.php - so it could be very difficult to adjust an existing application to work with the Zend Expressive Swoole implementation.

I still think it should appear in $_SERVER and $request->getServerParams()

Thank for your help

It's impossible appear these parameters in $_SERVER, $_SERVER is a global variables, it will mixed the parameters between different requests in same worker.
And whether if these parameters should appear in $request->getServerParams(), lets zend team make this decision. @weierophinney

@jgalvezsoax you are missing the main point here. The zend-expressive-swoole is a library to execute Expressive application using Swoole. That means you need to code using [PSR-7] request and response, no usage of global variables like $_SERVER or $_GET, $_POST, etc.

@ezimuel now I know I can't use global vars in Zend Expressive Swoole (thanks for opening my eyes), but, what about to get the standard $_SERVER keys through $request->getServerParams() ?

Actually to get the HTTP_params you must call $request->getHeaders(). Maybe I'm wrong but I think it's not where it is expected to be found.

Anyway thanks for your help

@jgalvezsoax

In terms of retrieving the various HTTP_* parameters, these are in fact documented in the PHP manual as representing HTTP headers. Why? Because they originate with Common Gateway Interface, which defined this as a standard naming mechanism for HTTP headers, and which was the original way that PHP applications were spawned back in the PHP/FI 2 days. When the mod_php Server API (SAPI) was developed, most of these keys were kept as they were familiar to CGI developers; however, tools such as apache_request_headers() were also added, as there was a realization that there may be a better way. The php-fpm SAPI also keeps these, but this is because it responds to FastCGI, which uses the same practices.

That said, in most modern PHP applications, you will retrieve incoming request headers from whatever HTTP abstraction you use. As others have pointed out, Expressive uses PSR-7, which standardizes interfaces for interacting with HTTP messages, including headers. So, yes, this is the expected place to find these values. If you are unclear about that, you need to brush up on the HTTP protocol and PSR-7.

With regards to why "standard" $_SERVER keys are not present, $_SERVER is generated by whichever Server API (SAPI) is used in the current request and/or invocation (the latter is important when you consider Swoole, which is invoked once, but which answers many requests). These are parameters that represent the server environment at initialization.

This means the keys that are in it vary based on the SAPI. Swoole is essentially a SAPI, and defines its own keys. In fact, its keys are generally lowercase; we normalize them to uppercase in our server params as that is how people will generally request them. Additionally, because it is invoked once, this means that it does not contain many of the standard CGI/FastCGI parameters, as those are request-specific. Most of the common SAPI parameters describe HTTP request artifacts: headers, request method, elements of the URI. This information largely duplicates what is already present directly within PSR-7 methods, and there's no need for us to seed the server parameters with that data: we're already seeding their direct counterparts in the request!

As such, we will NOT be adding any more than what we already have present, as there's already better ways to get at that data.