running on php-7.3 now
[mdref/mdref] / mdref / Action.php
1 <?php
2
3 namespace mdref;
4
5 use http\Env\Request;
6 use http\Env\Response;
7 use http\Message\Body;
8 use stdClass;
9 use function file_get_contents;
10 use function htmlspecialchars;
11 use function ob_start;
12 use const ROOT;
13
14 /**
15 * Request handler
16 */
17 class Action {
18 /**
19 * The reference
20 * @var \mdref\Reference
21 */
22 private $reference;
23
24 /**
25 * @var \http\Env\Request
26 */
27 private $request;
28
29 /**
30 * @var \http\Env\Response
31 */
32 private $response;
33
34 /**
35 * @var \http\Url
36 */
37 private $baseUrl;
38
39 /**
40 * Initialize the reference
41 */
42 public function __construct(Reference $ref, Request $req, Response $res, BaseUrl $baseUrl) {
43 $this->reference = $ref;
44 $this->request = $req;
45 $this->response = $res;
46 $this->baseUrl = $baseUrl;
47 ob_start($res);
48 }
49
50 /**
51 * Shorthand for \htmlspecialchars()
52 * @param $txt string
53 * @return string
54 */
55 function esc(string $txt) : string {
56 return htmlspecialchars($txt);
57 }
58
59 /**
60 * Create the view payload
61 * @return \stdClass
62 */
63 private function createPayload() : object {
64 $pld = new stdClass;
65
66 $pld->esc = "htmlspecialchars";
67 $pld->anchor = [$this->reference, "formatAnchor"];
68 $pld->quick = [$this->reference, "formatString"];
69 $pld->file = [$this->reference, "formatFile"];
70
71 $pld->ref = $this->baseUrl->pathinfo(
72 $this->baseUrl->mod($this->request->getRequestUrl()));
73
74 $pld->refs = $this->reference;
75 $pld->baseUrl = $this->baseUrl;
76
77 return $pld;
78 }
79
80 /**
81 * Redirect to canonical url
82 * @param string $cnn
83 */
84 private function serveCanonical(string $cnn) : void {
85 $this->response->setHeader("Location", $this->baseUrl->mod(["path" => $cnn]));
86 $this->response->setResponseCode(301);
87 $this->response->send();
88 }
89
90 /**
91 * Serve index.css
92 */
93 private function serveStylesheet() : void {
94 $this->response->setHeader("Content-Type", "text/css");
95 $this->response->setBody(new Body(\fopen(ROOT."/public/index.css", "r")));
96 $this->response->send();
97 }
98
99 /**
100 * Serve index.js
101 */
102 private function serveJavascript() : void {
103 $this->response->setHeader("Content-Type", "application/javascript");
104 $this->response->setBody(new Body(\fopen(ROOT."/public/index.js", "r")));
105 $this->response->send();
106 }
107
108 /**
109 * Server a PHP stub
110 * @throws Exception
111 *
112 */
113 private function serveStub() : void {
114 $name = $this->request->getQuery("ref", "s");
115 $repo = $this->reference->getRepoForEntry($name);
116 if (!$repo->hasStub($stub)) {
117 throw new Exception(404, "Stub not found");
118 }
119 $this->response->setHeader("Content-Type", "application/x-php");
120 $this->response->setContentDisposition(["attachment" => ["filename" => "$name.stub.php"]]);
121 $this->response->setBody(new Body(\fopen($stub, "r")));
122 $this->response->send();
123 }
124
125 /**
126 * Serve a preset
127 * @param object $pld
128 * @return true to continue serving the payload
129 * @throws Exception
130 */
131 private function servePreset(object $pld) : bool {
132 switch ($pld->ref) {
133 case "AUTHORS":
134 case "LICENSE":
135 case "VERSION":
136 $pld->text = file_get_contents(ROOT."/$pld->ref");
137 return true;
138 case "index.css":
139 $this->serveStylesheet();
140 break;
141 case "index.js":
142 $this->serveJavascript();
143 break;
144 case "stub":
145 $this->serveStub();
146 break;
147 default:
148 throw new Exception(404, "$pld->ref not found");
149 }
150 return false;
151 }
152
153 /**
154 * Serve a payload
155 */
156 private function serve() : void {
157 extract((array) func_get_arg(0));
158 include ROOT."/views/layout.phtml";
159 $this->response->addHeader("Link", "<" . $this->baseUrl->path . "index.css>; rel=preload; as=style");
160 $this->response->addHeader("Link", "<" . $this->baseUrl->path . "index.js>; rel=preload; as=script");
161 $this->response->send();
162 }
163
164 /**
165 * Request handler
166 */
167 public function handle() : void {
168 try {
169 $pld = $this->createPayload();
170
171 if (strlen($pld->ref)) {
172 $cnn = null;
173 if (($repo = $this->reference->getRepoForEntry($pld->ref, $cnn))) {
174 if (strlen($cnn)) {
175 /* redirect */
176 $this->serveCanonical($cnn);
177 return;
178 } else {
179 /* direct match */
180 $pld->entry = $repo->getEntry($pld->ref);
181 }
182 } elseif (!$this->servePreset($pld)) {
183 return;
184 }
185 }
186
187 } catch (\Exception $e) {
188 $pld->exception = $e;
189 }
190
191 $this->serve($pld);
192 }
193 }