1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\HTTP; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehler/** 6*a1a3b679SAndreas Boehler * PHP SAPI 7*a1a3b679SAndreas Boehler * 8*a1a3b679SAndreas Boehler * This object is responsible for: 9*a1a3b679SAndreas Boehler * 1. Constructing a Request object based on the current HTTP request sent to 10*a1a3b679SAndreas Boehler * the PHP process. 11*a1a3b679SAndreas Boehler * 2. Sending the Response object back to the client. 12*a1a3b679SAndreas Boehler * 13*a1a3b679SAndreas Boehler * It could be said that this class provides a mapping between the Request and 14*a1a3b679SAndreas Boehler * Response objects, and php's: 15*a1a3b679SAndreas Boehler * 16*a1a3b679SAndreas Boehler * * $_SERVER 17*a1a3b679SAndreas Boehler * * $_POST 18*a1a3b679SAndreas Boehler * * $_FILES 19*a1a3b679SAndreas Boehler * * php://input 20*a1a3b679SAndreas Boehler * * echo() 21*a1a3b679SAndreas Boehler * * header() 22*a1a3b679SAndreas Boehler * * php://output 23*a1a3b679SAndreas Boehler * 24*a1a3b679SAndreas Boehler * You can choose to either call all these methods statically, but you can also 25*a1a3b679SAndreas Boehler * instantiate this as an object to allow for polymorhpism. 26*a1a3b679SAndreas Boehler * 27*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/). 28*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 29*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 30*a1a3b679SAndreas Boehler */ 31*a1a3b679SAndreas Boehlerclass Sapi { 32*a1a3b679SAndreas Boehler 33*a1a3b679SAndreas Boehler /** 34*a1a3b679SAndreas Boehler * This static method will create a new Request object, based on the 35*a1a3b679SAndreas Boehler * current PHP request. 36*a1a3b679SAndreas Boehler * 37*a1a3b679SAndreas Boehler * @return Request 38*a1a3b679SAndreas Boehler */ 39*a1a3b679SAndreas Boehler static function getRequest() { 40*a1a3b679SAndreas Boehler 41*a1a3b679SAndreas Boehler $r = self::createFromServerArray($_SERVER); 42*a1a3b679SAndreas Boehler $r->setBody(fopen('php://input', 'r')); 43*a1a3b679SAndreas Boehler $r->setPostData($_POST); 44*a1a3b679SAndreas Boehler return $r; 45*a1a3b679SAndreas Boehler 46*a1a3b679SAndreas Boehler } 47*a1a3b679SAndreas Boehler 48*a1a3b679SAndreas Boehler /** 49*a1a3b679SAndreas Boehler * Sends the HTTP response back to a HTTP client. 50*a1a3b679SAndreas Boehler * 51*a1a3b679SAndreas Boehler * This calls php's header() function and streams the body to php://output. 52*a1a3b679SAndreas Boehler * 53*a1a3b679SAndreas Boehler * @param ResponseInterface $response 54*a1a3b679SAndreas Boehler * @return void 55*a1a3b679SAndreas Boehler */ 56*a1a3b679SAndreas Boehler static function sendResponse(ResponseInterface $response) { 57*a1a3b679SAndreas Boehler 58*a1a3b679SAndreas Boehler header('HTTP/' . $response->getHttpVersion() . ' ' . $response->getStatus() . ' ' . $response->getStatusText()); 59*a1a3b679SAndreas Boehler foreach ($response->getHeaders() as $key => $value) { 60*a1a3b679SAndreas Boehler 61*a1a3b679SAndreas Boehler foreach ($value as $k => $v) { 62*a1a3b679SAndreas Boehler if ($k === 0) { 63*a1a3b679SAndreas Boehler header($key . ': ' . $v); 64*a1a3b679SAndreas Boehler } else { 65*a1a3b679SAndreas Boehler header($key . ': ' . $v, false); 66*a1a3b679SAndreas Boehler } 67*a1a3b679SAndreas Boehler } 68*a1a3b679SAndreas Boehler 69*a1a3b679SAndreas Boehler } 70*a1a3b679SAndreas Boehler 71*a1a3b679SAndreas Boehler $body = $response->getBody(); 72*a1a3b679SAndreas Boehler if (is_null($body)) return; 73*a1a3b679SAndreas Boehler 74*a1a3b679SAndreas Boehler $contentLength = $response->getHeader('Content-Length'); 75*a1a3b679SAndreas Boehler if ($contentLength !== null) { 76*a1a3b679SAndreas Boehler $output = fopen('php://output', 'wb'); 77*a1a3b679SAndreas Boehler if (is_resource($body) && get_resource_type($body) == 'stream') { 78*a1a3b679SAndreas Boehler stream_copy_to_stream($body, $output, $contentLength); 79*a1a3b679SAndreas Boehler } else { 80*a1a3b679SAndreas Boehler fwrite($output, $body, $contentLength); 81*a1a3b679SAndreas Boehler } 82*a1a3b679SAndreas Boehler } else { 83*a1a3b679SAndreas Boehler file_put_contents('php://output', $body); 84*a1a3b679SAndreas Boehler } 85*a1a3b679SAndreas Boehler 86*a1a3b679SAndreas Boehler if (is_resource($body)) { 87*a1a3b679SAndreas Boehler fclose($body); 88*a1a3b679SAndreas Boehler } 89*a1a3b679SAndreas Boehler 90*a1a3b679SAndreas Boehler } 91*a1a3b679SAndreas Boehler 92*a1a3b679SAndreas Boehler /** 93*a1a3b679SAndreas Boehler * This static method will create a new Request object, based on a PHP 94*a1a3b679SAndreas Boehler * $_SERVER array. 95*a1a3b679SAndreas Boehler * 96*a1a3b679SAndreas Boehler * @param array $serverArray 97*a1a3b679SAndreas Boehler * @return Request 98*a1a3b679SAndreas Boehler */ 99*a1a3b679SAndreas Boehler static function createFromServerArray(array $serverArray) { 100*a1a3b679SAndreas Boehler 101*a1a3b679SAndreas Boehler $headers = []; 102*a1a3b679SAndreas Boehler $method = null; 103*a1a3b679SAndreas Boehler $url = null; 104*a1a3b679SAndreas Boehler $httpVersion = '1.1'; 105*a1a3b679SAndreas Boehler 106*a1a3b679SAndreas Boehler $protocol = 'http'; 107*a1a3b679SAndreas Boehler $hostName = 'localhost'; 108*a1a3b679SAndreas Boehler 109*a1a3b679SAndreas Boehler foreach ($serverArray as $key => $value) { 110*a1a3b679SAndreas Boehler 111*a1a3b679SAndreas Boehler switch ($key) { 112*a1a3b679SAndreas Boehler 113*a1a3b679SAndreas Boehler case 'SERVER_PROTOCOL' : 114*a1a3b679SAndreas Boehler if ($value === 'HTTP/1.0') { 115*a1a3b679SAndreas Boehler $httpVersion = '1.0'; 116*a1a3b679SAndreas Boehler } 117*a1a3b679SAndreas Boehler break; 118*a1a3b679SAndreas Boehler case 'REQUEST_METHOD' : 119*a1a3b679SAndreas Boehler $method = $value; 120*a1a3b679SAndreas Boehler break; 121*a1a3b679SAndreas Boehler case 'REQUEST_URI' : 122*a1a3b679SAndreas Boehler $url = $value; 123*a1a3b679SAndreas Boehler break; 124*a1a3b679SAndreas Boehler 125*a1a3b679SAndreas Boehler // These sometimes should up without a HTTP_ prefix 126*a1a3b679SAndreas Boehler case 'CONTENT_TYPE' : 127*a1a3b679SAndreas Boehler $headers['Content-Type'] = $value; 128*a1a3b679SAndreas Boehler break; 129*a1a3b679SAndreas Boehler case 'CONTENT_LENGTH' : 130*a1a3b679SAndreas Boehler $headers['Content-Length'] = $value; 131*a1a3b679SAndreas Boehler break; 132*a1a3b679SAndreas Boehler 133*a1a3b679SAndreas Boehler // mod_php on apache will put credentials in these variables. 134*a1a3b679SAndreas Boehler // (fast)cgi does not usually do this, however. 135*a1a3b679SAndreas Boehler case 'PHP_AUTH_USER' : 136*a1a3b679SAndreas Boehler if (isset($serverArray['PHP_AUTH_PW'])) { 137*a1a3b679SAndreas Boehler $headers['Authorization'] = 'Basic ' . base64_encode($value . ':' . $serverArray['PHP_AUTH_PW']); 138*a1a3b679SAndreas Boehler } 139*a1a3b679SAndreas Boehler break; 140*a1a3b679SAndreas Boehler 141*a1a3b679SAndreas Boehler // Similarly, mod_php may also screw around with digest auth. 142*a1a3b679SAndreas Boehler case 'PHP_AUTH_DIGEST' : 143*a1a3b679SAndreas Boehler $headers['Authorization'] = 'Digest ' . $value; 144*a1a3b679SAndreas Boehler break; 145*a1a3b679SAndreas Boehler 146*a1a3b679SAndreas Boehler // Apache may prefix the HTTP_AUTHORIZATION header with 147*a1a3b679SAndreas Boehler // REDIRECT_, if mod_rewrite was used. 148*a1a3b679SAndreas Boehler case 'REDIRECT_HTTP_AUTHORIZATION' : 149*a1a3b679SAndreas Boehler $headers['Authorization'] = $value; 150*a1a3b679SAndreas Boehler break; 151*a1a3b679SAndreas Boehler 152*a1a3b679SAndreas Boehler case 'HTTP_HOST' : 153*a1a3b679SAndreas Boehler $hostName = $value; 154*a1a3b679SAndreas Boehler $headers['Host'] = $value; 155*a1a3b679SAndreas Boehler break; 156*a1a3b679SAndreas Boehler 157*a1a3b679SAndreas Boehler case 'HTTPS' : 158*a1a3b679SAndreas Boehler if (!empty($value) && $value !== 'off') { 159*a1a3b679SAndreas Boehler $protocol = 'https'; 160*a1a3b679SAndreas Boehler } 161*a1a3b679SAndreas Boehler break; 162*a1a3b679SAndreas Boehler 163*a1a3b679SAndreas Boehler default : 164*a1a3b679SAndreas Boehler if (substr($key, 0, 5) === 'HTTP_') { 165*a1a3b679SAndreas Boehler // It's a HTTP header 166*a1a3b679SAndreas Boehler 167*a1a3b679SAndreas Boehler // Normalizing it to be prettier 168*a1a3b679SAndreas Boehler $header = strtolower(substr($key, 5)); 169*a1a3b679SAndreas Boehler 170*a1a3b679SAndreas Boehler // Transforming dashes into spaces, and uppercasing 171*a1a3b679SAndreas Boehler // every first letter. 172*a1a3b679SAndreas Boehler $header = ucwords(str_replace('_', ' ', $header)); 173*a1a3b679SAndreas Boehler 174*a1a3b679SAndreas Boehler // Turning spaces into dashes. 175*a1a3b679SAndreas Boehler $header = str_replace(' ', '-', $header); 176*a1a3b679SAndreas Boehler $headers[$header] = $value; 177*a1a3b679SAndreas Boehler 178*a1a3b679SAndreas Boehler } 179*a1a3b679SAndreas Boehler break; 180*a1a3b679SAndreas Boehler 181*a1a3b679SAndreas Boehler 182*a1a3b679SAndreas Boehler } 183*a1a3b679SAndreas Boehler 184*a1a3b679SAndreas Boehler } 185*a1a3b679SAndreas Boehler 186*a1a3b679SAndreas Boehler $r = new Request($method, $url, $headers); 187*a1a3b679SAndreas Boehler $r->setHttpVersion($httpVersion); 188*a1a3b679SAndreas Boehler $r->setRawServerData($serverArray); 189*a1a3b679SAndreas Boehler $r->setAbsoluteUrl($protocol . '://' . $hostName . $url); 190*a1a3b679SAndreas Boehler return $r; 191*a1a3b679SAndreas Boehler 192*a1a3b679SAndreas Boehler } 193*a1a3b679SAndreas Boehler 194*a1a3b679SAndreas Boehler} 195