19

I'm testing my code, and i have some problem with header. In each api i use

$headers = getallheaders();

to get that, and this works fine when i test with the app or crhome postman extension. When i lauch my test, like this

 $client = $this->createClient();
    $client->request('GET', '/api/shotcard',
        ['qrcode'=>'D0m1c173'], [],
        ['HTTP_API_TOKEN' => 'abc123']
    );

    $this->assertEquals(200, $client->getResponse()->getStatusCode());

where i try to shot a card with that qrcode with a user with that test token (not the token i'll use in the application), i see a call like this here: https://stackoverflow.com/a/11681422/5475228 . The test fails in this way:

PHP Fatal error: Call to undefined function AppBackendBundle\Controller\getallheaders() in /var/www/pitstop/src/AppBackendBundle/Controller/ApiController.php on line 42

Community
  • 1
  • 1
NicolaPez
  • 567
  • 1
  • 4
  • 27
  • from the doc: This function is an alias for apache_request_headers(). Please read the apache_request_headers() documentation for more information on how this function works. http://php.net/manual/en/function.apache-request-headers.php – Matteo Jan 02 '17 at 13:41
  • which version of php are you using? it should be available form the CLI since PHP 5.5.7 – Matteo Jan 02 '17 at 13:44

3 Answers3

52

From this article:

If you use Nginx, PHP-FPM or any other FastCGI method of running PHP you’ve probably noticed that the function getallheaders() does not exist. There are many creative workarounds in the wild, but PHP offers two very nice features to ease your pain.

From user contributed comments at getallheaders() function on PHP manual by joyview at gmail dot com

if (!function_exists('getallheaders')) {
    function getallheaders() {
    $headers = [];
    foreach ($_SERVER as $name => $value) {
        if (substr($name, 0, 5) == 'HTTP_') {
            $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
        }
    }
    return $headers;
    }
}
kuttumiah
  • 525
  • 1
  • 11
  • 19
Matteo
  • 37,680
  • 11
  • 100
  • 115
  • I also use this solution, and works fine when i test from app or postman. But with PHPUnit dont, I tried also to print the headers, PHPUnit print a empty value. I'm using php 5.5.9 – NicolaPez Jan 02 '17 at 13:54
  • Unfortunately, this only recognizes headers prefixed with `HTTP_`. Headers like `Accept`, `User-Agent`, and any custom HTTP headers will not be retrieved by this implementation. – Ondřej Bouda Nov 16 '18 at 14:35
  • 1
    yes @OndřejBouda but you can implements the behaviour adding an `else` statement I suppose – Matteo Nov 16 '18 at 14:56
  • @Matteo Sorry for wrong comment, `$_SERVER` actually *contains* `Accept` and `User-Agent`. However, as regards to custom HTTP headers, these may not be retrieved this way. The variable `$_SERVER` only contains several standard HTTP headers, as [documented](http://php.net/manual/en/reserved.variables.server.php), compared to `getallheaders()`, which returns all headers sent by the client. – Ondřej Bouda Nov 19 '18 at 07:35
  • Hi @OndřejBouda the `HTTP_` trick is about of the `BrowserKit` implementation, as example described [here](https://github.com/symfony/symfony/issues/5074): `headers are also part of $_SERVER, by prefixing them with HTTP_` – Matteo Nov 19 '18 at 07:45
  • @Matteo Thanks for sharing the link. It appears that only custom HTTP headers _prefixed with `X-`_ make their way to the `$_SERVER` variable. **Without the `X-` prefix, they cannot be retrieved this way.** Unfortunately, this is not documented on the [`$_SERVER` page](http://php.net/manual/en/reserved.variables.server.php) so I can only tell from observing the specific PHP implementation I currently use (PHP 7.2.6 on Apache 2.4). Note that custom HTTP headers are _discouraged_ from being prefixed with `X-` so that's somewhat inconsistent of PHP. – Ondřej Bouda Nov 19 '18 at 09:30
4

i resolve in that way(thanks to https://stackoverflow.com/a/11681422/5475228)

private function request_headers($type, Request $request)
{
    if(function_exists("getallheaders"))
    {
        if($header = getallheaders()[$type])
        {
            return $header;
        }
    }

    return $request->headers->get($type);
}

so the normal request from app get header with getallheaders(), the request from PHPUnit get it from Request object. I don't know why (if someone can explain) but works.

Community
  • 1
  • 1
NicolaPez
  • 567
  • 1
  • 4
  • 27
0

A slight variation from @Matteos code which removes Mod-Rewrite and adds in Content-Length and Content-Type which are normally returned by getallheaders(). Interestingly, the case of the array keys returned by getallheaders() seems to be all over the place and not consistent whereas obviously this version ensures consistency.

$allHeaders = array();
foreach($_SERVER as $name => $value) {
    if($name != 'HTTP_MOD_REWRITE' && (substr($name, 0, 5) == 'HTTP_' || $name == 'CONTENT_LENGTH' || $name == 'CONTENT_TYPE')) {
        $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', str_replace('HTTP_', '', $name)))));
        $allHeaders[$name] = $value;
    }
}
adrian
  • 111
  • 3
  • 11