friendship ended with social-app. php is my new best friend
1<?php 2/** 3 * Class SapiEmitter 4 * 5 * @created 22.10.2022 6 * @author smiley <smiley@chillerlan.net> 7 * @copyright 2022 smiley 8 * @license MIT 9 */ 10declare(strict_types=1); 11 12namespace chillerlan\HTTP\Utils\Emitter; 13 14use chillerlan\HTTP\Utils\HeaderUtil; 15use RuntimeException; 16use function header, headers_sent, is_array, ob_get_length, ob_get_level, sprintf; 17 18class SapiEmitter extends ResponseEmitterAbstract{ 19 20 public function emit():void{ 21 22 if(ob_get_level() > 0 && ob_get_length() > 0){ 23 throw new RuntimeException('Output has been emitted previously; cannot emit response.'); 24 } 25 26 if(headers_sent($file, $line)){ 27 throw new RuntimeException(sprintf('Headers already sent in file %s on line %s.', $file, $line)); 28 } 29 30 $this->emitHeaders(); 31 $this->emitBody(); 32 } 33 34 /** 35 * Emits the headers 36 * 37 * There are two special-case header calls. The first is a header 38 * that starts with the string "HTTP/" (case is not significant), 39 * which will be used to figure out the HTTP status code to send. 40 * For example, if you have configured Apache to use a PHP script 41 * to handle requests for missing files (using the ErrorDocument 42 * directive), you may want to make sure that your script generates 43 * the proper status code. 44 * 45 * The second special case is the "Location:" header. 46 * Not only does it send this header back to the browser, 47 * but it also returns a REDIRECT (302) status code to the browser 48 * unless the 201 or a 3xx status code has already been set. 49 * 50 * @see https://www.php.net/manual/en/function.header.php 51 */ 52 protected function emitHeaders():void{ 53 $headers = HeaderUtil::normalize($this->response->getHeaders()); 54 55 foreach($headers as $name => $value){ 56 57 if($name === 'Set-Cookie'){ 58 continue; 59 } 60 61 $this->sendHeader(sprintf('%s: %s', $name, $value), true); 62 } 63 64 if(isset($headers['Set-Cookie']) && is_array($headers['Set-Cookie'])){ 65 66 foreach($headers['Set-Cookie'] as $cookie){ 67 $this->sendHeader(sprintf('Set-Cookie: %s', $cookie), false); 68 } 69 70 } 71 72 // Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers. 73 // See https://github.com/slimphp/Slim/issues/1730 74 $this->sendHeader($this->getStatusLine(), true, $this->response->getStatusCode()); 75 } 76 77 /** 78 * Allow to intercept header calls in tests 79 * 80 * @codeCoverageIgnore (overridden in test) 81 */ 82 protected function sendHeader(string $header, bool $replace, int $response_code = 0):void{ 83 header($header, $replace, $response_code); 84 } 85 86}