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) 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 if (PHP_INT_SIZE !== 4){ 79 // use the dedicated function on 64 Bit systems 80 stream_copy_to_stream($body, $output, $contentLength); 81 } else { 82 // workaround for 32 Bit systems to avoid stream_copy_to_stream 83 while (!feof($body)) { 84 fwrite($output, fread($body, 8192)); 85 } 86 } 87 } else { 88 fwrite($output, $body, $contentLength); 89 } 90 } else { 91 file_put_contents('php://output', $body); 92 } 93 94 if (is_resource($body)) { 95 fclose($body); 96 } 97 98 } 99 100 /** 101 * This static method will create a new Request object, based on a PHP 102 * $_SERVER array. 103 * 104 * @param array $serverArray 105 * @return Request 106 */ 107 static function createFromServerArray(array $serverArray) { 108 109 $headers = []; 110 $method = null; 111 $url = null; 112 $httpVersion = '1.1'; 113 114 $protocol = 'http'; 115 $hostName = 'localhost'; 116 117 foreach ($serverArray as $key => $value) { 118 119 switch ($key) { 120 121 case 'SERVER_PROTOCOL' : 122 if ($value === 'HTTP/1.0') { 123 $httpVersion = '1.0'; 124 } 125 break; 126 case 'REQUEST_METHOD' : 127 $method = $value; 128 break; 129 case 'REQUEST_URI' : 130 $url = $value; 131 break; 132 133 // These sometimes show up without a HTTP_ prefix 134 case 'CONTENT_TYPE' : 135 $headers['Content-Type'] = $value; 136 break; 137 case 'CONTENT_LENGTH' : 138 $headers['Content-Length'] = $value; 139 break; 140 141 // mod_php on apache will put credentials in these variables. 142 // (fast)cgi does not usually do this, however. 143 case 'PHP_AUTH_USER' : 144 if (isset($serverArray['PHP_AUTH_PW'])) { 145 $headers['Authorization'] = 'Basic ' . base64_encode($value . ':' . $serverArray['PHP_AUTH_PW']); 146 } 147 break; 148 149 // Similarly, mod_php may also screw around with digest auth. 150 case 'PHP_AUTH_DIGEST' : 151 $headers['Authorization'] = 'Digest ' . $value; 152 break; 153 154 // Apache may prefix the HTTP_AUTHORIZATION header with 155 // REDIRECT_, if mod_rewrite was used. 156 case 'REDIRECT_HTTP_AUTHORIZATION' : 157 $headers['Authorization'] = $value; 158 break; 159 160 case 'HTTP_HOST' : 161 $hostName = $value; 162 $headers['Host'] = $value; 163 break; 164 165 case 'HTTPS' : 166 if (!empty($value) && $value !== 'off') { 167 $protocol = 'https'; 168 } 169 break; 170 171 default : 172 if (substr($key, 0, 5) === 'HTTP_') { 173 // It's a HTTP header 174 175 // Normalizing it to be prettier 176 $header = strtolower(substr($key, 5)); 177 178 // Transforming dashes into spaces, and uppercasing 179 // every first letter. 180 $header = ucwords(str_replace('_', ' ', $header)); 181 182 // Turning spaces into dashes. 183 $header = str_replace(' ', '-', $header); 184 $headers[$header] = $value; 185 186 } 187 break; 188 189 190 } 191 192 } 193 194 $r = new Request($method, $url, $headers); 195 $r->setHttpVersion($httpVersion); 196 $r->setRawServerData($serverArray); 197 $r->setAbsoluteUrl($protocol . '://' . $hostName . $url); 198 return $r; 199 200 } 201 202} 203