Passed
Push — main ( d1069b...891daf )
by Sammy
04:00 queued 02:32
created

hopper::set_file_root()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
/**
3
* huppel konijntje huppel and wiebel
4
* Hommage to Grace Hopper, programmer & expert in *litteral* duck taping
5
***/
6
7
namespace HexMakina\Hopper;
8
9
class hopper extends \AltoRouter implements RouterInterface
10
{
11
  private $match=null;
12
  private $file_root=null;
13
  private $controller_namespaces = null;
14
15
  //----------------------------------------------------------- INITIALISATION
16
  public function __construct($settings)
17
  {
18
    if(!isset($settings['route_home']))
19
      throw new RouterException('ROUTE_HOME_UNDEFINED');
20
21
    parent::__construct();
22
23
    $this->set_web_base($settings['web_base'] ?? '');
24
    $this->set_file_root($settings['file_root'] ?? __DIR__);
25
26
    $this->controller_namespaces = $settings['controllers_namespaces'] ?? [];
27
28
    $this->map(self::REQUEST_GET, '', $settings['route_home'], self::ROUTE_HOME_NAME);
29
  }
30
31
  public function __debugInfo() : array
32
  {
33
    $dbg = get_object_vars($this);
34
    $dbg['routes'] = count($dbg['routes']);
35
    $dbg['namedRoutes'] = count($dbg['namedRoutes']);
36
    unset($dbg['matchTypes']);
37
    return $dbg;
38
  }
39
  // -- MATCHING REQUESTS
40
  public function match($requestUrl = NULL, $requestMethod = NULL)
41
  {
42
    $this->match = parent::match($requestUrl, $requestMethod);
43
44
    if($this->match === false)
45
      throw new RouterException('ROUTE_MATCH_FALSE');
46
47
    $res = explode('::', $this->target());
48
49
    if($res === false || !isset($res[1]) || isset($res[2]))
50
      throw new RouterException('INVALID_TARGET');
51
52
    $target_controller = $res[0];
53
    $target_method = $res[1];
54
    $found = false;
55
56
    $controller_class_name = null;
57
    foreach($this->controller_namespaces as $controller_ns)
58
      if($found = class_exists($controller_class_name = "$controller_ns$target_controller"))
59
        break;
60
61
    if($found === false)
62
      throw new RouterException('INVALID_CONTROLLER_NAME');
63
64
    $this->match['target_controller'] = $controller_class_name;
65
    $this->match['target_method'] = $target_method;
66
67
    return [$controller_class_name, $target_method];
68
  }
69
70
  public function params($param_name=null)
71
  {
72
    return $this->extract_request($this->match['params'] ?? [], $param_name);
73
  }
74
75
  public function submitted($param_name=null)
76
  {
77
    return $this->extract_request($_POST, $param_name);
78
  }
79
80
  private function extract_request($dat_ass, $key=null)
81
  {
82
83
    // $key is null, returns $dat_ass or empty array
84
    if(is_null($key))
85
      return $dat_ass ?? [];
86
87
    // $dat_ass[$key] not set, returns null
88
    if(!isset($dat_ass[$key]))
89
      return null;
90
91
    // $dat_ass[$key] is a string, returns decoded value
92
    if(is_string($dat_ass[$key]))
93
      return urldecode($dat_ass[$key]);
94
95
    // $dat_ass[$key] is not a string, return match[$key]
96
    return $dat_ass[$key];
97
98
  }
99
100
  public function target()
101
  {
102
    return $this->match['target'];
103
  }
104
105
  public function target_controller()
106
  {
107
    return $this->match['target_controller'];
108
  }
109
110
  public function target_method()
111
  {
112
    return $this->match['target_method'];
113
  }
114
115
  public function name()
116
  {
117
    return $this->match['name'];
118
  }
119
120
  // -- ROUTING TOOLS
121
  public function route_exists($route) : bool
122
  {
123
    return isset($this->namedRoutes[$route]);
124
  }
125
126
  public function named_routes()
127
  {
128
    return $this->namedRoutes;
129
  }
130
131
  /*
132
   * @param route_name string  requires
133
   *  - a valid AltoRouter route name
134
   *  - OR a Descendant of Model
135
   * @route_params requires
136
   *  - an assoc_array of url params (strongly AltoRouter-based)
137
   * returns: something to put in a href="", action="" or header('Location:');
138
   */
139
  public function prehop($route, $route_params=[])
140
  {
141
    try{
142
      $url = $this->generate($route, $route_params);
143
    }catch(\Exception $e){
144
      $url = $this->prehop(self::ROUTE_HOME_NAME);
145
    }
146
147
    return $url;
148
  }
149
150
  public function prehop_here($url=null)
151
  {
152
    return $url ?? $_SERVER['REQUEST_URI'];
153
  }
154
155
  /*
156
   * @params $route is
157
   *    - empty: default is ROUTE_HOME_NAME
158
   *    - an existing route name: make url with optional [$route_params])
159
   *    - a url, go there
160
   * @params $route_params, assoc_data for url creation (i:id, a:format, ..)
161
   */
162
  public function hop($route=null, $route_params=[])
163
  {
164
    $url = null;
165
166
    if(is_null($route))
167
      $url = $this->prehop(self::ROUTE_HOME_NAME, $route_params);
168
    elseif(is_string($route) && $this->route_exists($route))
169
      $url = $this->prehop($route, $route_params);
170
    else
171
      $url = $route;
172
173
    $this->hop_url($url);
174
  }
175
176
  // hops back to previous page (referer()), or home if no referer
177
  public function hop_back()
178
  {
179
    if(!is_null($back = $this->referer()))
180
      $this->hop_url($back);
181
182
    $this->hop();
183
  }
184
185
  public function hop_url($url)
186
  {
187
  	header('Cache-Control: no-cache, must-revalidate');
188
  	header('Expires: Mon, 01 Jan 1970 00:00:00 GMT');
189
    header('Location: '.$url);
190
    exit();
191
  }
192
193
  // returns full URL of the refering URL
194
  // returns null if same as current URL (prevents endless redirection loop)
195
  public function referer()
196
  {
197
    if(isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] != $this->web_host() .$_SERVER['REQUEST_URI'])
198
      return $_SERVER['HTTP_REFERER'];
199
200
    return null;
201
  }
202
203
  public function send_file($file_path)
204
  {
205
    if(!file_exists($file_path))
206
      throw new RouterException('SENDING_NON_EXISTING_FILE');
207
208
    $file_name = basename($file_path);
209
210
    //Get file type and set it as Content Type
211
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
212
213
    header('Content-Type: ' . finfo_file($finfo, $file_path));
214
215
    finfo_close($finfo);
216
217
    //Use Content-Disposition: attachment to specify the filename
218
    header('Content-Disposition: attachment; filename='.$file_name);
219
220
    //No cache
221
    header('Expires: 0');
222
    header('Cache-Control: must-revalidate');
223
    header('Pragma: public');
224
225
    //Define file size
226
    header('Content-Length: ' . filesize($file_path));
227
228
    ob_clean();
229
    flush();
230
    readfile($file_path);
231
    die;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
232
  }
233
234
  // -- PROCESSING REQUESTS
235
  public function requests() : bool
236
  {
237
    return $_SERVER['REQUEST_METHOD'] === self::REQUEST_GET;
238
  }
239
240
  public function submits() : bool
241
  {
242
    return $_SERVER['REQUEST_METHOD'] === self::REQUEST_POST;
243
  }
244
245
  public function web_host() : string
246
  {
247
    return $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'];
248
  }
249
250
  public function web_root() : string
251
  {
252
    return $this->web_host() . $this->web_base();
253
  }
254
255
  public function web_base() : string
256
  {
257
    return $this->basePath ?? '';
258
  }
259
260
  public function set_web_base($setter)
261
  {
262
    $this->setBasePath($setter);
263
  }
264
265
  public function file_root() : string
266
  {
267
    return $this->file_root ?? __DIR__;
268
  }
269
270
  public function set_file_root($setter)
271
  {
272
    $this->file_root = realpath($setter).'/';
273
  }
274
275
}
276