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