1<?php 2 3 4namespace ComboStrap; 5 6 7use TestRequest; 8 9class HttpResponse 10{ 11 public const EXIT_KEY = 'exit'; 12 13 14 const STATUS_NOT_FOUND = 404; 15 public const STATUS_ALL_GOOD = 200; 16 const STATUS_NOT_MODIFIED = 304; 17 const STATUS_PERMANENT_REDIRECT = 301; 18 public const STATUS_DOES_NOT_EXIST = 404; 19 public const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; 20 public const STATUS_BAD_REQUEST = 400; 21 public const STATUS_INTERNAL_ERROR = 500; 22 public const STATUS_NOT_AUTHORIZED = 401; 23 const MESSAGE_ATTRIBUTE = "message"; 24 25 /** 26 * @var int 27 */ 28 private $status; 29 30 private $canonical = "support"; 31 /** 32 * @var \Doku_Event 33 */ 34 private $event; 35 /** 36 * @var array 37 */ 38 private $headers = []; 39 private $msg; 40 41 42 /** 43 * Error constructor. 44 */ 45 public function __construct($status, $msg) 46 { 47 $this->status = $status; 48 $this->msg = $msg; 49 } 50 51 public static function create(int $status, string $msg = null): HttpResponse 52 { 53 return new HttpResponse($status, $msg); 54 } 55 56 57 public function setEvent(\Doku_Event $event): HttpResponse 58 { 59 $this->event = $event; 60 return $this; 61 } 62 63 public function send($payload = null, $contentType = null) 64 { 65 66 if ($contentType != null) { 67 Http::setMime($contentType); 68 } else { 69 Http::setMime(Mime::PLAIN_TEXT); 70 } 71 72 // header should before the status 73 // because for instance a `"Location` header changes the status to 302 74 foreach ($this->headers as $header) { 75 header($header); 76 } 77 78 if ($this->status !== null) { 79 Http::setStatus($this->status); 80 } else { 81 $status = Http::getStatus(); 82 if ($status === null) { 83 Http::setStatus(self::STATUS_INTERNAL_ERROR); 84 LogUtility::log2file("No status was set for this soft exit, the default was set instead", LogUtility::LVL_MSG_ERROR, $this->canonical); 85 } 86 } 87 88 89 /** 90 * Payload 91 */ 92 if ($payload !== null) { 93 echo $payload; 94 } 95 96 /** 97 * Exit 98 */ 99 if (!PluginUtility::isTest()) { 100 if ($this->status !== self::STATUS_ALL_GOOD && $this->msg !== null) { 101 // if this is a 304, there is no body, no message 102 LogUtility::log2file("Bad Http Response: $this->status : $this->msg", LogUtility::LVL_MSG_ERROR, $this->canonical); 103 } 104 exit; 105 } else { 106 107 /** 108 * Stop the propagation and prevent the default 109 */ 110 if ($this->event !== null) { 111 $this->event->stopPropagation(); 112 $this->event->preventDefault(); 113 } 114 115 /** 116 * Add test info into the request 117 */ 118 $testRequest = TestRequest::getRunning(); 119 120 if ($testRequest !== null) { 121 $testRequest->addData(self::EXIT_KEY, $payload); 122 } 123 124 /** 125 * Output buffer 126 * Stop the buffer 127 * Test request starts a buffer at {@link TestRequest::execute()}, 128 * it will capture the body until this point 129 */ 130 ob_end_clean(); 131 /** 132 * To avoid phpunit warning `Test code or tested code did not (only) close its own output buffers` 133 * and 134 * Send the output to the void 135 */ 136 ob_start(function ($value) { 137 }); 138 139 } 140 } 141 142 public function setCanonical($canonical): HttpResponse 143 { 144 $this->canonical = $canonical; 145 return $this; 146 } 147 148 149 public function addHeader(string $header): HttpResponse 150 { 151 $this->headers[] = $header; 152 return $this; 153 } 154 155 /** 156 * @param string|array $messages 157 */ 158 public function sendMessage($messages) 159 { 160 if (is_array($messages) && sizeof($messages) == 0) { 161 $messages = ["No information, no errors"]; 162 } 163 $message = json_encode(["message" => $messages]); 164 $this->send($message, Mime::JSON); 165 166 } 167 168} 169