1: <?php
2:
3: 4: 5: 6: 7:
8: class vodka {
9:
10: const ver = '1.0.1';
11: const rev = 101;
12:
13: const head = '{VODKA:HEAD}';
14: const canonical = '{VODKA:CANONICAL}';
15: const description = '{VODKA:DESCRIPTION}';
16: const keywords = '{VODKA:KEYWORDS}';
17: const menu = '{VODKA:MENU}';
18: const content = '{VODKA:CONTENT}';
19: const title = '{VODKA:TITLE}';
20: const template = '{VODKA:TEMPLATE}';
21: const url = '{VODKA:URL}';
22: const baseurl = '{VODKA:BASEURL}';
23: const name = '{VODKA:NAME}';
24: const cclass = '{VODKA:CLASS}';
25:
26: protected $base_url;
27: protected $root;
28: protected $show_errors = true;
29: protected $forbid_scriptname = true;
30: protected $clean_unused_vars;
31: protected $auto_pages;
32: protected $main_page;
33: protected $notfound_page;
34: protected $pages;
35: protected $menu;
36: protected $templates;
37: protected $aliases;
38:
39: protected $template;
40: protected $content;
41:
42: protected $current_page;
43: protected $current_template;
44:
45: protected $page_built;
46: protected $output;
47:
48: protected $built_head;
49: protected $built_menu;
50:
51: protected $uri;
52:
53: protected $replace = [];
54: protected $subject = [];
55:
56: protected $start_time;
57:
58: private function printError($error,$die = true) {
59: if ($this->show_errors) {
60: $trace = array_reverse(debug_backtrace());
61: echo '<div style="color:white;border:1px solid black;background-color:#990000">[vodka '.$this::ver.'] ERROR - '.$error.'<br>';
62: foreach ($trace as $tritem) {
63: echo $tritem['file'].':'.$tritem['line'].'<br>';
64: }
65: echo '</div>';
66: }
67: if ($die) {
68: header($_SERVER['SERVER_PROTOCOL']." 418 I'm a teapot",true,418);
69: exit;
70: }
71: }
72:
73: private function _pathinfo($path,$opt = '') {
74: $separator = ' qq ';
75: $path = preg_replace('/[^ ]/u',$separator."\$0".$separator,$path);
76: if ($opt == '') $pathinfo = pathinfo($path);
77: else $pathinfo = pathinfo($path,$opt);
78: if (is_array($pathinfo)) {
79: $pathinfo2 = $pathinfo;
80: foreach($pathinfo2 as $key => $val) {
81: $pathinfo[$key] = str_replace($separator,'',$val);
82: }
83: }
84: else if (is_string($pathinfo)) $pathinfo = str_replace($separator,'',$pathinfo);
85: return $pathinfo;
86: }
87:
88: 89: 90: 91: 92: 93: 94: 95:
96: function __construct($params) {
97: $this->start_time = microtime(true);
98:
99: if (!isset($params)) {
100: $this->printError('no params defined.');
101: return false;
102: }
103: if (!isset($params['system'])) {
104: $this->printError('no system params defined.');
105: return false;
106: }
107: if (!isset($params['system']['base_url'])) {
108: $this->printError('base_url is required.');
109: return false;
110: } else {
111: $this->base_url = $params['system']['base_url'];
112: }
113:
114: if (isset($params['system']['show_errors'])) {
115: $this->show_errors = $params['system']['show_errors'];
116: }
117: if (isset($params['system']['clean_unused_vars'])) {
118: $this->clean_unused_vars = $params['system']['clean_unused_vars'];
119: }
120: if ($this->show_errors == true) {
121: error_reporting(E_ERROR|E_WARNING|E_PARSE);
122: } else {
123: error_reporting(0);
124: }
125:
126: if (isset($params['system']['root'])) {
127: $this->root = $params['system']['root'];
128: } else {
129: $this->root = realpath(dirname(__FILE__));
130: }
131: if (isset($params['system']['forbid_scriptname'])) {
132: $this->forbid_scriptname = $params['system']['forbid_scriptname'];
133: }
134: if (isset($params['system']['main_page'])) {
135: $this->main_page = $params['system']['main_page'];
136: }
137: if (isset($params['system']['404_page'])) {
138: $this->notfound_page = $params['system']['404_page'];
139: }
140: if (isset($params['system']['auto_pages'])) {
141: $this->auto_pages = $params['system']['auto_pages'];
142: }
143:
144: if (isset($params['menu'])) {
145: $this->menu = $params['menu'];
146: } elseif (isset($params['menus'])) {
147: $this->menu = $params['menus'];
148: }
149:
150: if (!isset($params['templates'])) {
151: $this->printError('no templates defined.');
152: return false;
153: }
154: if ((!isset($params['pages'])) && (!$this->auto_pages)) {
155: $this->printError('no pages defined.');
156: return false;
157: }
158:
159: if (isset($params['aliases'])) {
160: $this->aliases = $params['aliases'];
161: }
162:
163: $this->pages = $params['pages'];
164: foreach ($this->pages as $key => &$page) {
165: if (!isset($page['path'])) {
166: $this->printError('no path defined for page #'.($key+1).'.');
167: return false;
168: }
169: if (!isset($page['name'])) {
170: $page['name'] = $this->_pathinfo($page['path'],PATHINFO_FILENAME);
171: }
172: if (!isset($page['title'])) {
173: $page['title'] = $page['name'];
174: }
175: if (!isset($page['description'])) {
176: $page['description'] = $page['title'];
177: }
178: if (!isset($page['keywords'])) {
179: $page['keywords'] = "";
180: }
181: if (!isset($page['isAJAX'])) {
182: $page['isAJAX'] = false;
183: }
184: }
185:
186: if ($this->auto_pages) {
187: foreach (glob($this->auto_pages."/*.{html,htm,txt}",GLOB_BRACE) as $file) {
188: $add = true;
189: foreach ($this->pages as $addedpage) {
190: if ($addedpage['path'] == $file) {
191: $add = false;
192: break;
193: }
194: }
195: if ($add) {
196: $this->pages[] = [
197: 'path' => $file,
198: 'title' => $this->_pathinfo($file,PATHINFO_FILENAME),
199: 'name' => $this->_pathinfo($file,PATHINFO_FILENAME)
200: ];
201: }
202: }
203: }
204:
205: $this->templates = $params['templates'];
206:
207: $this->uri = urldecode($_SERVER['REQUEST_URI']);
208: $pos = strpos($this->uri,basename($_SERVER['PHP_SELF']));
209: if ($pos !== false) {
210: $this->uri = substr_replace($this->uri,'',$pos,strlen(basename($_SERVER['PHP_SELF'])));
211: }
212: $pos = strpos($this->uri,dirname($_SERVER['PHP_SELF']));
213: if ($pos !== false) {
214: $this->uri = substr_replace($this->uri,'',$pos,strlen(dirname($_SERVER['PHP_SELF'])));
215: }
216: $this->uri = preg_replace('~/{2,}~','/',$this->uri);
217: $this->uri = ltrim($this->uri,'/');
218: $this->uri = explode('?',$this->uri);
219: $this->uri = $this->uri[0];
220:
221: if ($this->forbid_scriptname) {
222: if (strpos($_SERVER['REQUEST_URI'],$_SERVER['PHP_SELF']) === 0) {
223: $_SERVER['REQUEST_URI'] = str_replace($_SERVER['PHP_SELF'],'',$_SERVER['REQUEST_URI']);
224: $_SERVER['REQUEST_URI'] = preg_replace('~/{2,}~','/',$_SERVER['REQUEST_URI']);
225:
226: header('Location: '.rtrim($this->base_url,'/').$_SERVER['REQUEST_URI'],true,301);
227: exit;
228: }
229: }
230:
231: if ($this->main_page) {
232: if ($this->uri == $this->main_page) {
233: $_SERVER['REQUEST_URI'] = str_replace($_SERVER['PHP_SELF'],'',$_SERVER['REQUEST_URI']);
234: $_SERVER['REQUEST_URI'] = preg_replace('~/{2,}~','/',$_SERVER['REQUEST_URI']);
235: $_SERVER['REQUEST_URI'] = str_replace($this->main_page,'',$_SERVER['REQUEST_URI']);
236:
237: header('Location: '.rtrim($this->base_url,'/').$_SERVER['REQUEST_URI'],true,301);
238: exit;
239: }
240: }
241:
242: foreach ($this->pages as &$page) {
243: if (($page['name'].'/' == $this->uri) || ($page['name'] == $this->uri.'/')) {
244: $_SERVER['REQUEST_URI'] = str_replace($this->uri,$page['name'],urldecode($_SERVER['REQUEST_URI']));
245:
246: header('Location: '.$_SERVER['REQUEST_URI'],true,301);
247: exit;
248: }
249: }
250:
251: if (isset($_GET)) {
252: foreach ($_GET as $key => $value) {
253: unset($_GET[$key]);
254: $key = explode('?',$key);
255: if (isset($key[1])) {
256: $_GET = [$key[1] => $value] + $_GET;
257: }
258: break;
259: }
260: }
261: }
262:
263: 264: 265: 266: 267:
268: public function getStartTime() {
269: return $this->start_time;
270: }
271:
272: 273: 274: 275: 276: 277:
278: public function loadTemplate($name) {
279: $this->page_built = false;
280: if (isset($this->templates[$name])) {
281: if (file_exists($this->root.'/'.$this->templates[$name].'/template.html')) {
282: $this->template = file_get_contents($this->root."/".$this->templates[$name].'/template.html');
283: } else {
284: $this->printError('template `$name` not found.');
285: return false;
286: }
287: } else {
288: $this->printError('no such template defined.');
289: return false;
290: }
291: if (dirname($_SERVER['PHP_SELF']) == '/') {
292: $this->current_template = '/'.$this->templates[$name];
293: }
294: else {
295: $this->current_template = htmlspecialchars(dirname($_SERVER['PHP_SELF'])).'/'.$this->templates[$name];
296: }
297: return true;
298: }
299:
300: 301: 302: 303: 304: 305:
306: public function getPageByName($name) {
307: if (isset($this->aliases[$name])) {
308: foreach ($this->pages as $page) {
309: if ($page['name'] == $this->aliases[$name]) {
310: return $page;
311: }
312: }
313: }
314: foreach ($this->pages as $page) {
315: if ($page['name'] == $name) {
316: return $page;
317: }
318: }
319: return false;
320: }
321:
322: 323: 324: 325: 326:
327: public function getCurrentPage() {
328: if (is_array($this->current_page)) {
329: return $this->current_page;
330: }
331: if (isset($this->aliases[$this->uri])) {
332: foreach ($this->pages as $page) {
333: if ($page['name'] == $this->aliases[$this->uri]) {
334: $this->current_page = $page;
335: return $page;
336: }
337: }
338: }
339: foreach ($this->pages as $page) {
340: if ($page['name'] == $this->uri) {
341: $this->current_page = $page;
342: return $page;
343: }
344: }
345: if (!$this->uri) {
346: if ($this->main_page) {
347: foreach ($this->pages as $page) {
348: if ($page['name'] == $this->main_page) {
349: $this->current_page = $page;
350: return $page;
351: }
352: }
353: } else {
354: $random_page = rand(0,count($this->pages)-1);
355: $this->current_page = $this->pages[$random_page];
356: return $this->pages[$random_page];
357: }
358: }
359: if ($this->notfound_page) {
360: foreach ($this->pages as $page) {
361: if ($page['name'] == $this->notfound_page) {
362: $this->current_page = $page;
363: return $page;
364: }
365: }
366: }
367: return false;
368: }
369:
370: 371: 372: 373: 374:
375: public function loadCurrentPage() {
376: return $this->loadPage($this->getCurrentPage());
377: }
378:
379: 380: 381: 382: 383: 384:
385: public function loadPage($page) {
386: $this->content = '';
387: $this->page_built = false;
388: if (!is_array($page)) {
389: $page = $this->getPageByName($page);
390: if (!is_array($page)) {
391: $this->printError('page not defined.');
392: return false;
393: }
394: }
395: if (isset($page['path'])) {
396: if (file_exists($this->root.'/'.$page['path'])) {
397: $this->content = file_get_contents($this->root.'/'.$page['path']);
398: return true;
399: } else {
400: $this->printError('page not found, check your config.',false);
401: return false;
402: }
403: } else {
404: $this->printError('page not defined.');
405: return false;
406: }
407: }
408:
409: 410: 411: 412: 413: 414:
415: public function getPageURL($page) {
416: if (!is_array($page)) {
417: $page = $this->getPageByName($page);
418: if (!is_array($page)) {
419: $this->printError('page not defined.',false);
420: return false;
421: }
422: }
423: return $this->base_url.($page['name'] == $this->main_page ? '' : $page['name']);
424: }
425:
426: 427: 428: 429: 430:
431: public function buildCurrentMenu() {
432: return $this->buildMenu($this->getCurrentPage());
433: }
434:
435: 436: 437: 438: 439: 440:
441: public function buildMenu($page) {
442: if (!is_array($this->menu)) {
443: return false;
444: }
445: if (!is_array($page)) {
446: $page = $this->getPageByName($page);
447: if (!is_array($page)) {
448: $this->printError('page not defined.');
449: return false;
450: }
451: }
452: for ($i = 0;$i < count($this->pages);$i++) {
453: $cur_item = $this->menu['html'];
454: $visible = true;
455: if (isset($this->pages[$i]['visible'])) {
456: $visible = $this->pages[$i]['visible'];
457: }
458: if ($visible) {
459: if (($this->pages[$i]['name'] == $page['name']) && isset($this->menu['selected_class'])) {
460: $replace = $this->menu['selected_class'];
461: if (($i == 0) && (isset($this->menu['selected_class_first']))) {
462: $replace .= ' '.$this->menu['selected_class_first'];
463: }
464: if (($i == count($this->pages) - 1) && (isset($this->menu['selected_class_last']))) {
465: $replace .= ' '.$this->menu['selected_class_last'];
466: }
467: $cur_item = str_replace($this::cclass,$replace,$cur_item);
468: } else {
469: $cur_item = str_replace($this::cclass,'',$cur_item);
470: }
471: $cur_item = str_replace($this::name,$this->pages[$i]['name'],$cur_item);
472:
473: if (dirname($_SERVER['PHP_SELF']) != '/') {
474: $cur_item = str_replace($this::url,htmlspecialchars(dirname($_SERVER['PHP_SELF'])).'/'.($this->pages[$i]['name'] == $this->main_page ? '' : $this->pages[$i]['name']),$cur_item);
475: } else {
476: $cur_item = str_replace($this::url,'/'.($this->pages[$i]['name'] == $this->main_page ? '' : $this->pages[$i]['name']),$cur_item);
477: }
478: $cur_item = str_replace($this::title,$this->pages[$i]['title'],$cur_item);
479: $this->built_menu .= $cur_item;
480: }
481: }
482: return true;
483: }
484:
485: 486: 487: 488: 489:
490: public function buildCurrentPage() {
491: return $this->buildPage($this->getCurrentPage());
492: }
493:
494: 495: 496: 497: 498: 499:
500: public function buildPage($page) {
501: if (!is_array($page)) {
502: $page = $this->getPageByName($page);
503: if (!is_array($page)) {
504: $this->printError('page not defined.');
505: return false;
506: }
507: }
508: if ($page['isAJAX']) {
509: $this->output = $this::content;
510: } else {
511: $this->output = $this->template;
512: }
513: if (isset($page['custom'])) {
514: $page['custom'] = array_reverse($page['custom']);
515: while ($custom = current($page['custom'])) {
516: $var = key($page['custom']);
517: if (substr($var,0,1) != '{') {
518: $var = '{'.$var;
519: }
520: if (substr($var,-1) != '}') {
521: $var .= "}";
522: }
523: array_unshift($this->replace,$var);
524: array_unshift($this->subject,$page['custom'][key($page['custom'])]);
525: next($page['custom']);
526: }
527: }
528: array_unshift(
529: $this->replace,
530: $this::content,
531: $this::head,
532: $this::canonical,
533: $this::description,
534: $this::keywords,
535: $this::template,
536: $this::title,
537: $this::menu,
538: $this::baseurl
539: );
540: array_unshift(
541: $this->subject,
542: $this->content,
543: $this->built_head,
544: $this->base_url.($page['name'] == $this->main_page ? '' : $page['name']),
545: $page['description'],
546: $page['keywords'],
547: $this->current_template,
548: $page['title'],
549: $this->built_menu,
550: $this->base_url
551: );
552: $this->output = str_replace($this->replace,$this->subject,$this->output);
553: if ($this->clean_unused_vars) {
554: $this->output = preg_replace('/{[A-Z0-9:]+}/','',$this->output);
555: }
556: if ($page['name'] == $this->notfound_page) {
557: header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found',true,404);
558: }
559: $this->page_built = true;
560: echo $this->output;
561: return true;
562: }
563:
564: 565: 566: 567: 568: 569: 570: 571: 572: 573:
574: public function replaceVar($var,$string = null) {
575: if (substr($var,0,1) != '{') {
576: $var = '{'.$var;
577: }
578: if (substr($var,-1) != '}') {
579: $var .= "}";
580: }
581: $this->replace[] = $var;
582: $this->subject[] = $string;
583: return true;
584: }
585:
586: 587: 588: 589: 590: 591: 592: 593: 594:
595: public function appendHead($string) {
596: $this->built_head .= $string;
597: return true;
598: }
599:
600: }
601:
602: ?>