{
    "href": "/post/2016/11/22/the-php-7-request-extension/",
    "relId": "2016/11/22/the-php-7-request-extension",
    "title": "The PHP 7 \"Request\" Extension",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/programming/",
            "relId": "programming",
            "title": "Programming",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2016-11-22 13:09:29 UTC",
    "updated": [
        "2016-11-22 13:09:29 UTC"
    ],
    "html": "<p><em>tl;dr: The new <a href=\"https://pecl.php.net/package/request\">request extension</a> provides server-side request and response objects for PHP 7. Use it as a replacement object for request superglobals and response functions. An equivalent PHP 5 version is available in userland as <a href=\"https://packagist.org/packages/pmjones/request\">pmjones/request</a>.</em></p>\n<hr>\n<p>You're tired of dealing with the <code>$_GET</code>, <code>$_POST</code>, etc. superglobals in your PHP 7 application.  You wish <code>$_FILES</code> was easer to deal with.  You'd prefer to wrap them all in an object to pass around to your class methods, so they'd be easier to test. And as long as they're all in an object, it might be nice to have parsed representations of the various incoming headers. Preferably, you'd like for it to be read-only, so that the various libraries you use can't modify superglobal state out from under you.</p>\n<p>Likewise, seeing the \u201cCannot modify header information - headers already sent\u201d warning is getting on your nerves. You'd like to get away from using <code>header()</code>, <code>setcookie()</code>, and the rest. You know they're hard to inspect, and they're hard to test. What would be great is to have all that response work wrapped in another object that you can pass around, and inspect or modify it before sending the response back to the client.</p>\n<p>You could maybe adopt a framework, but why do that for your custom project? Just a pair of server-side request and response objects would make your life so much easer.  Why can't there be set of internal PHP classes for that?</p>\n<p>Well, now there is. You can install <a href=\"https://pecl.php.net/package/request\">the <code>request</code> extension</a> from John Boehr and myself to get ServerRequest and ServerReponse objects as if PHP itself provided them.</p>\n<h3>ServerRequest</h3>\n<p>After you install the extension, you can issue <code>$request = new ServerRequest()</code>, and then:</p>\n<pre><code style=\"font-size: 0.8em;\">Instead of ...                          ... use:\n--------------------------------------- ---------------------------------------\n$_COOKIE                                $request-&gt;cookie\n$_ENV                                   $request-&gt;env\n$_GET                                   $request-&gt;get\n$_FILES                                 $request-&gt;files\n$_POST                                  $request-&gt;post\n$_SERVER                                $request-&gt;server\n$_SERVER['REQUEST_METHOD']              $request-&gt;method\n$_SERVER['HTTP_HEADER_NAME']            $request-&gt;headers['header-name']\nfile_get_contents('php://input')        $request-&gt;content\n$_SERVER['HTTP_CONTENT_LENGTH']         $request-&gt;contentLength\n$_SERVER['HTTP_CONTENT_MD5']            $request-&gt;contentMd5\n$_SERVER['PHP_AUTH_PW']                 $request-&gt;authPw\n$_SERVER['PHP_AUTH_TYPE']               $request-&gt;authType\n$_SERVER['PHP_AUTH_USER']               $request-&gt;authUser\n</code></pre>\n<p>Likewise:</p>\n<pre><code style=\"font-size: 0.8em;\">Instead of parsing ...                  ... use:\n--------------------------------------- ---------------------------------------\nisset($_SERVER['key'])                  $request-&gt;server['key'] ?? 'default'\n  ? $_SERVER['key']                     (good for all superglobals)\n  : 'default';\n$_FILES to look more like $_POST        $request-&gt;uploads\n$_SERVER['HTTP_CONTENT_TYPE']           $request-&gt;contentType and\n                                        $request-&gt;contentCharset\n$_SERVER['HTTP_ACCEPT']                 $request-&gt;accept\n$_SERVER['HTTP_ACCEPT_CHARSET']         $request-&gt;acceptCharset\n$_SERVER['HTTP_ACCEPT_ENCODING']        $request-&gt;acceptEncoding\n$_SERVER['HTTP_ACCEPT_LANGUAGE']        $request-&gt;acceptLanguage\n$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] $request-&gt;method\n$_SERVER['PHP_AUTH_DIGEST']             $request-&gt;authDigest\n$_SERVER['HTTP_X_REQUESTED_WITH']       $request-&gt;xhr\n  == 'XmlHttpRequest'\n</code></pre>\n<p>Those properties are all read-only, so there's no chance of them being changed without you knowing. (There are some true immutables for application-related values as well; see the <a href=\"https://gitlab.com/pmjones/ext-request#application-related\">documentation</a>.)</p>\n<h3>ServerResponse</h3>\n<p>For responses, you can issue <code>$response = new ServerResponse()</code>, and then:</p>\n<pre><code style=\"font-size: 0.8em;\">Instead of ...                          ... use:\n--------------------------------------- ---------------------------------------\nheader('Foo: bar', true);               $response-&gt;setHeader('Foo', 'bar');\nheader('Foo: bar', false);              $response-&gt;addHeader('Foo', 'bar');\nsetcookie('foo', 'bar');                $response-&gt;setCookie('foo', 'bar');\nsetrawcookie('foo', 'bar');             $response-&gt;setRawCookie('foo', 'bar');\necho $content;                          $response-&gt;setContent($content);\n</code></pre>\n<p>You can inspect the <code>$response</code> object, and then call <code>$response-&gt;send()</code> to<br>\nsend it to the client.</p>\n<p>Working with JSON?</p>\n<pre><code>// instead of ...\nheader('Content-Type: application/json')\necho json_encode($value);\n\n// .. use:\n$response-&gt;setContentJson($value);\n</code></pre>\n<p>Sending a <code>$file</code> for download?</p>\n<pre><code>// instead of ...\nheader('Content-Type: application/octet-stream');\nheader('Content-Transfer-Encoding: binary');\nheader(\n    'Content-Disposition: attachment;filename=\"'\n    . rawurlencode(basename($file)) . '\"'\n);\n$fh = fopen($file, 'rb+');\nfpasthru($fh);\n\n// use:\n$fh = fopen($file, 'rb+');\n$response-&gt;setContentDownload($fh, basename($file));\n</code></pre>\n<p>Building a complex header? Pass an array instead of a string:</p>\n<pre><code>$response-&gt;setHeader('Cache-Control', [\n    'public',\n    'max-age' =&gt; '123',\n    's-maxage' =&gt; '456',\n    'no-cache',\n]); // Cache-Control: public, max-age=123, s-maxage=456, no-cache\n\n$response-&gt;setHeader('X-Whatever', [\n    'foo',\n    'bar' =&gt; [\n        'baz' =&gt; 'dib',\n        'zim',\n        'gir' =&gt; 'irk',\n    ],\n    'qux' =&gt; 'quux',\n]); // X-Whatever: foo, bar;baz=dib;zim;gir=irk, qux=quux\n</code></pre>\n<h3>Find Out More</h3>\n<p>You can read the rest of the documentation at <a href=\"https://gitlab.com/pmjones/ext-request\">https://gitlab.com/pmjones/ext-request</a> to discover more convenient functionality. And if you're stuck on PHP 5.x for now, the extension has a userland version installable via Composer as <a href=\"https://packagist.org/packages/pmjones/request\">pmjones/request</a>.</p>\n<p>Try out <a href=\"https://pecl.php.net/package/request\">the <code>request</code> extension</a> today, because a pair of server-side request and response objects will make your life a lot easier.</p>\n"
}
