psf
apibase.php
1 <?php
2 
3 // Part of php simple framework (psf)
4 
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 
15 // Copyright (c) Petr Bena <petr@bena.rocks> 2015 - 2019
16 
17 if (!defined("PSF_ENTRY_POINT"))
18  die("Not a valid psf entry point");
19 
20 require_once (dirname(__FILE__) . "/../object.php");
21 require_once (dirname(__FILE__) . "/../html_stack.php");
22 
24 abstract class PsfApiParameterType
25 {
26  const NULL = 0;
27  const Variant = 1;
28  const Number = 2;
29  const String = 3;
30  const Boolean = 4;
31 
32  public static function ToString($type)
33  {
34  if ($type === PsfApiParameterType::NULL)
35  return "NULL";
36  if ($type === PsfApiParameterType::Variant)
37  return "Variant";
38  if ($type === PsfApiParameterType::Number)
39  return "Number";
40  if ($type === PsfApiParameterType::String)
41  return "String";
42  if ($type === PsfApiParameterType::Boolean)
43  return "Boolean";
44  return "invalid type";
45  }
46 }
47 
49 {
50  public $Name;
52  public $Type;
53  public $Description;
54 
55  public function __construct($_name, $_type = PsfApiParameterType::Variant, $_description = NULL)
56  {
57  $this->Name = $_name;
58  $this->Type = $_type;
59  $this->Description = $_description;
60  }
61 };
62 
66 class PsfApi extends PsfObject
67 {
68  public $Name = NULL;
69  public $ParametersRequired = [];
70  public $ParametersOptional = [];
71  public $ShortDescription = NULL;
72  public $LongDescription = NULL;
73  public $Example = NULL;
74  public $Callback = NULL;
75  public $RequiresAuthentication = false;
78  public $POSTOnly = false;
79 
80  public function __construct($_name, $_callback = NULL, $short_description = NULL, $long_description = NULL, $params_req = NULL, $params_opt = NULL)
81  {
82  $this->Name = $_name;
83  $this->LongDescription = $long_description;
84  $this->ShortDescription = $short_description;
85  $this->Callback = $_callback;
86  if ($params_req !== NULL)
87  $this->ParametersRequired = $params_req;
88  if ($params_opt !== NULL)
89  $this->ParametersOptional = $params_opt;
90  }
91 
92  public function Process()
93  {
94  if ($this->Callback !== NULL)
95  {
96  return call_user_func($this->Callback, $this);
97  }
98  return false;
99  }
100 
101  public function GetParameterCount()
102  {
103  return count($this->ParametersOptional) + count($this->ParametersRequired);
104  }
105 }
106 
107 class PsfApiBase extends PsfObject
108 {
109  public $ApiList_GET = [];
110  public $ApiList_POST = [];
111  public $ApiList_DELETE = [];
112  public $ApiList_PUT = [];
113  public $ApiList_Action = [];
114  public $ShowHelpOnNoAction = true;
115  public $ApiBaseName = "API";
116  public $ApiBaseIntro = "Welcome to web API. These APIs can be used to perform various actions on the website.";
117  public $TreatDocsAsHTML = false;
119  public $ExamplePrefix = "";
121  public $AuthenticationBackend = NULL;
122 
123  public function RegisterAPI_Action($api, $name = NULL)
124  {
125  if ($name === NULL)
126  $name = $api->Name;
127  $name = strtolower($name);
128  $api->Parent = $this;
129  $this->ApiList_Action[$name] = $api;
130  }
131 
132  public function RegisterAPI_GET($api)
133  {
134  $api->Parent = $this;
135  array_push ($this->ApiList_GET, $api);
136  }
137 
138  public function RegisterAPI_PUT($api)
139  {
140  $api->Parent = $this;
141  array_push ($this->ApiList_PUT, $api);
142  }
143 
144  public function RegisterAPI_POST($api)
145  {
146  $api->Parent = $this;
147  array_push ($this->ApiList_POST, $api);
148  }
149 
150  public function RegisterAPI_DELETE($api)
151  {
152  $api->Parent = $this;
153  array_push ($this->ApiList_DELETE, $api);
154  }
155 
156  public function ProcessAction()
157  {
158  $method = NULL;
159  if (isset($_GET['action']))
160  {
161  $method = 'GET';
162  $action = strtolower($_GET['action']);
163  } else if (isset($_POST['action']))
164  {
165  $method = 'POST';
166  $action = strtolower($_POST['action']);
167  } else
168  {
169  return false;
170  }
171 
172  if (!array_key_exists($action, $this->ApiList_Action))
173  return false;
174 
175  if ($method !== 'POST' && $this->ApiList_Action[$action]->POSTOnly)
176  $this->ThrowError("POST only", "This call must be submitted via POST method", 403);
177 
178  if ($this->ApiList_Action[$action]->RequiresAuthentication && !$this->AuthenticationBackend->IsAuthenticated())
179  $this->ThrowError("Not authenticated", "This call requires authentication, but you are not logged in", 403);
180 
181  return $this->ApiList_Action[$action]->Process();
182  }
183 
184  public function ProcessGET()
185  {
186  return false;
187  }
188 
189  public function ProcessPOST()
190  {
191  return false;
192  }
193 
194  public function ProcessDELETE()
195  {
196  return false;
197  }
198 
199  public function ProcessPUT()
200  {
201  return false;
202  }
203 
204  public function Process()
205  {
206  $result = false;
207  if ($this->ProcessAction() ||
208  $this->ProcessGET() ||
209  $this->ProcessPOST() ||
210  $this->ProcessDELETE() ||
211  $this->ProcessPUT())
212  $result = true;
213 
214  if ($this->ShowHelpOnNoAction && !$result)
215  $this->PrintHelpAsHtml();
216  }
217 
218  private function appendDocs($c, $t)
219  {
220  if (!$this->TreatDocsAsHTML)
221  $c->AppendParagraph($t);
222  else
223  $c->AppendHtml($t);
224  }
225 
226  public function ThrowError($error, $message = NULL, $code = -1)
227  {
228  print("Error: " . $error . "\n");
229  if ($message !== NULL)
230  print("Details: " . $message . "\n");
231 
232  // Terminate here
233  die($code);
234  }
235 
236  public function PrintHelpAsHtml()
237  {
238  global $psf_containers_auto_insert_child;
239  $def_psf_containers_auto_insert_child = $psf_containers_auto_insert_child;
240  $psf_containers_auto_insert_child = true;
241  $help = new HtmlPage($this->ApiBaseName . ": help");
242  bootstrap_init($help);
243  $help->Style->items["blockquote"]["font-size"] = "14px";
244  $c = new BS_FluidContainer($help);
245  $c->AppendHeader($this->ApiBaseName . " documentation");
246  $this->appendDocs($c, $this->ApiBaseIntro);
247 
248  if (!empty($this->ApiList_Action))
249  {
250  $c->AppendHeader("Action APIs", 2);
251  $c->AppendHtmlLine('<p>These APIs can be called using standard GET or POST web request with parameter <code>action</code> (for example: <code>' . $this->ExamplePrefix . '?action=test</code>) where action is one of these:</p>');
252  foreach ($this->ApiList_Action as $key => $value)
253  {
254  $c->AppendHeader($key, 3);
255  if ($value->ShortDescription !== NULL)
256  $this->appendDocs($c, $value->ShortDescription);
257  $c->AppendHtmlLine('<blockquote>');
258  if ($value->RequiresAuthentication)
259  $c->AppendHtmlLine('<p class="text-danger"><span class="glyphicon glyphicon-exclamation-sign"></span> This action requires authentication</p>');
260  if ($value->POSTOnly)
261  $c->AppendHtmlLine('<p class="text-danger"><span class="glyphicon glyphicon-exclamation-sign"></span> This action must be called via POST method</p>');
262  if ($value->GetParameterCount() === 0)
263  {
264  $c->AppendParagraph("This action has no parameters", "text-info");
265  } else
266  {
267  if (count($value->ParametersRequired) > 0)
268  {
269  $c->AppendHeader("Parameters (required)", 4);
270  foreach ($value->ParametersRequired as $reqp)
271  {
272  $c->AppendHtmlLine('<p><b>' . $reqp->Name . '</b> (<code>' . PsfApiParameterType::ToString($reqp->Type) . '</code>): ' . $reqp->Description . '</p>');
273  }
274  }
275  if (count($value->ParametersOptional) > 0)
276  {
277  $c->AppendHeader("Parameters (optional)", 4);
278  foreach ($value->ParametersOptional as $optp)
279  {
280  $c->AppendHtmlLine('<p><b>' . $optp->Name . '</b> (<code>' . PsfApiParameterType::ToString($optp->Type) . '</code>): ' . $optp->Description . '</p>');
281  }
282  }
283  }
284  if ($value->LongDescription !== NULL)
285  $this->appendDocs($c, $value->LongDescription);
286  if ($value->Example !== NULL)
287  $c->AppendHtmlLine('<p><b>Example:</b> <code>' . htmlspecialchars($this->ExamplePrefix . $value->Example) . '</code></p>');
288  $c->AppendHtmlLine('</blockquote>');
289  }
290  }
291 
292  $psf_containers_auto_insert_child = $def_psf_containers_auto_insert_child;
293  $help->PrintHtml();
294  }
295 }
Represent a single Html page.
Definition: htmlpage.php:32
Base class used for every single PSF object.
Definition: object.php:21
This class represents a single API PSF supports quite flexible API framework which can be used to cre...
Definition: apibase.php:66
Data types supported by API parameters.
Definition: apibase.php:24
$Type
Type of.
Definition: apibase.php:52