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 (Http::getStatus() !== self::STATUS_ALL_GOOD) { 101 LogUtility::log2file($this->msg, LogUtility::LVL_MSG_ERROR, $this->canonical); 102 } 103 exit; 104 } else { 105 106 /** 107 * Stop the propagation and prevent the default 108 */ 109 if ($this->event !== null) { 110 $this->event->stopPropagation(); 111 $this->event->preventDefault(); 112 } 113 114 /** 115 * Add test info into the request 116 */ 117 $testRequest = TestRequest::getRunning(); 118 119 if ($testRequest !== null) { 120 $testRequest->addData(self::EXIT_KEY, $payload); 121 } 122 123 /** 124 * Output buffer 125 * Stop the buffer 126 * Test request starts a buffer at {@link TestRequest::execute()}, 127 * it will capture the body until this point 128 */ 129 ob_end_clean(); 130 /** 131 * To avoid phpunit warning `Test code or tested code did not (only) close its own output buffers` 132 * and 133 * Send the output to the void 134 */ 135 ob_start(function ($value) { 136 }); 137 138 } 139 } 140 141 public function setCanonical($canonical): HttpResponse 142 { 143 $this->canonical = $canonical; 144 return $this; 145 } 146 147 148 public function addHeader(string $header): HttpResponse 149 { 150 $this->headers[] = $header; 151 return $this; 152 } 153 154 /** 155 * @param string|array $messages 156 */ 157 public function sendMessage($messages) 158 { 159 if (is_array($messages) && sizeof($messages) == 0) { 160 $messages = ["No information, no errors"]; 161 } 162 $message = json_encode(["message" => $messages]); 163 $this->send($message, Mime::JSON); 164 165 } 166 167} 168