PageRenderTime 107ms CodeModel.GetById 25ms app.highlight 30ms RepoModel.GetById 44ms app.codeStats 1ms

/paraglide.php

https://github.com/kballenegger/Paraglide
PHP | 788 lines | 583 code | 162 blank | 43 comment | 180 complexity | a85f0820c635caa6e4d087d256d25915 MD5 | raw file
  1<?php
  2/*
  3paraglide.php
  4Copyright (c) 2011 Brandon Goldman
  5Modifications by Kenneth Ballenegger
  6Released under the MIT License.
  7*/
  8
  9Paraglide::init();
 10
 11class ParaglideExitException extends Exception {}
 12
 13class Paraglide {
 14	private static $_data = array();
 15	private static $_done_loading = false;
 16	private static $_controller_instance = null;
 17	private static $_request_types = array(
 18		'html' => 'text/html',
 19		'json' => 'text/javascript',
 20		'rss' => 'application/rss+xml',
 21		'txt' => 'text/plain',
 22		'xml' => 'text/xml',
 23		'csv' => 'text/csv'
 24	);
 25	private static $_skip_layout = false;
 26	
 27	public static $action = null;
 28	public static $controller = null;
 29	public static $layout = null;
 30	public static $nested_dir = '';
 31	public static $request_type = null;
 32	public static $wrapper = null;
 33	
 34	private static function _execute_hook($source = null, $hook) {
 35		if ($source == 'file') {
 36			if (file_exists(APP_PATH . 'lib/hooks.php')) {
 37				require_once APP_PATH . 'lib/hooks.php';
 38			}
 39			
 40			if (method_exists('Hooks', $hook)) {
 41				call_user_func(array('Hooks', $hook));
 42			}
 43			
 44			return;
 45		}
 46
 47		if ($source == 'controller') {
 48			if (method_exists(self::$_controller_instance, '_' . $hook)) {
 49				call_user_func(array(self::$_controller_instance, '_' . $hook));
 50			}
 51		}
 52	}
 53
 54	private static function _inflect_camelize($word) {
 55		return str_replace(' ', '', ucwords(str_replace(array('_', ' '), ' ', $word)));
 56	}
 57	
 58	private static function _inflect_underscore($word) {
 59		$return = '';
 60		
 61		for ($i = 0; $i < strlen($word); $i++) {
 62			$letter = $word{$i};
 63
 64			if (strtolower($letter) !== $letter) {
 65				if ($i != 0) $return .= '_';
 66				$letter = strtolower($letter);
 67			}
 68
 69			$return .= $letter;
 70		}
 71
 72		return $return;
 73	}
 74	
 75	private static function _render() {
 76		if (self::$_skip_layout) {
 77			echo self::$_data['PAGE_CONTENT'];
 78			return;
 79		}
 80		
 81		$master_view = 'layout';
 82		$modal_view = 'modal.layout';
 83		$nested_view = self::$nested_dir . 'layout';
 84		$controller_view = self::$nested_dir . self::$controller . '/layout';
 85		$controller_wrapper = self::$nested_dir . self::$controller . '/wrapper';
 86		$local_view = self::$nested_dir . self::$controller . '/' . self::$action . '.layout';
 87		$local_wrapper = self::$nested_dir . self::$controller . '/' . self::$action . '.wrapper';
 88			
 89		if (file_exists(APP_PATH . 'views/' . $local_wrapper . '.tpl')) {
 90			$wrapper = $local_wrapper;
 91		}
 92		else if (file_exists(APP_PATH . 'views/' . $controller_wrapper . '.tpl')) {
 93			$wrapper = $controller_wrapper;
 94		}
 95
 96		if (!empty(self::$layout) && file_exists(APP_PATH . 'views/' . self::$layout . '.tpl')) {
 97			$view = self::$layout;
 98		} elseif (!empty($_GET['modal'])) {
 99			$view = $modal_view;
100		} elseif (file_exists(APP_PATH . 'views/' . $local_view . '.tpl')) {
101			$view = $local_view;
102		} elseif (file_exists(APP_PATH . 'views/' . $controller_view . '.tpl')) {
103			$view = $controller_view;
104		} elseif (file_exists(APP_PATH . 'views/' . $nested_view . '.tpl')) {
105			$view = $nested_view;
106		} else {
107			$view = $master_view;
108		}
109		
110		if (!empty($wrapper)) {
111			ob_start();
112			self::render_view($wrapper);
113			self::$_data['PAGE_CONTENT'] = ob_get_clean();
114		}
115
116		self::render_view($view);
117		self::$_done_loading = true;
118	}
119	
120	private static function _set_cache() {
121		if (empty($GLOBALS['config']['cache'])) {
122			return;
123		}
124		
125		if (empty($GLOBALS['config']['cache'][ENVIRONMENT])) {
126			self::error('Cache config not found for environment \'' . ENVIRONMENT . '\' in <strong>cache.cfg</strong>');
127		}
128		
129		$c = $GLOBALS['config']['cache'][ENVIRONMENT];
130		$default_class = 'Memcache';
131		$class = $default_class;
132		
133		if (!empty($c['class']) && $c['class'] != $default_class) {
134			$class = $c['class'];
135			$filename = APP_PATH . 'lib/classes/' . self::_inflect_underscore($class) . '.php';
136
137			if (!file_exists($filename)) {
138				self::error('Cache class \'' . $class . '\' not found at <em>' . $filename . '</em> in <strong>cache.cfg</strong>');
139			}
140
141			require_once $filename;
142		}
143
144		$GLOBALS['cache'] = new $class();
145		$servers = explode(',', $c['servers']);
146		
147		foreach ($servers as $key => $server) {
148			$server_parts = explode(':', $server);
149			$host = $server_parts[0];
150			$port = !empty($server_parts[1]) ? $server_parts[1] : null;
151			$GLOBALS['cache']->addServer($host, $port, false);
152		}
153	}
154	
155	private static function _set_config_and_environment() {
156		// set the main config first, because the environment relies on options in this config
157		$GLOBALS['config'] = array();
158		$GLOBALS['config']['app'] = self::parse_config('app');
159		
160		// set the environment
161		self::_set_environment();
162		
163		// set the other configs later, because they rely on the environment
164		$GLOBALS['config']['cache'] = self::parse_config('cache', true);
165		$GLOBALS['config']['database'] = self::parse_config('database', true);
166		$GLOBALS['config']['mail'] = self::parse_config('mail', true);
167		$GLOBALS['config']['memcache'] = self::parse_config('memcache', true);
168		
169		// DEFAULT_CONTROLLER is the controller your application executes if the one being accessed doesn't exist or one isn't provided (it's usually main)
170		define('DEFAULT_CONTROLLER', $GLOBALS['config']['app']['main']['default_controller']);
171		
172		// make sure the default controller exists
173		if (!file_exists(APP_PATH . 'controllers/' . DEFAULT_CONTROLLER . '_controller.php')) {
174			self::error('Missing required default controller file <strong>controllers/' . DEFAULT_CONTROLLER . '_controller.php</strong>');
175		}
176	}
177	
178	private static function _set_constants() {
179		if (empty($_SERVER['REQUEST_URI'])) {
180			$_SERVER['REQUEST_URI'] = '/';
181		}
182
183		// APP_PATH is the full server path to the directory of this application, with leading and trailing slashes
184		// example: for http://www.example.com/shop/index.php/categories/5?size=medium, APP_PATH is something like /home/example.com/
185		define('APP_PATH', dirname(__FILE__) . '/');
186
187		// SITE_PATH is the full server path to the directory of this application relative to the domain, with leading and trailing slashes
188		// example: for http://www.example.com/shop/index.php/categories/5?size=medium, SITE_PATH is something like /home/example.com/public_html/shop/
189		define('SITE_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . '/');
190		
191		// SITE_ROOT is the path of this application relative to the domain, with leading and trailing slashes
192		// example: for http://www.example.com/shop/index.php/categories/5?size=medium, SITE_ROOT is /shop/
193		$docroot = realpath($_SERVER['DOCUMENT_ROOT']);
194		if (substr($docroot, -1) == '/') $docroot = substr($docroot, 0, -1);
195		if ($docroot === false) $docroot = '';
196		define('SITE_ROOT', substr(SITE_PATH, strlen($docroot)));
197		
198		// CURRENT_URL is the this request's URL relative to the domain, with a leading slash and with or without a trailing slash
199		// example: for http://www.example.com/shop/categories/5?size=medium, CURRENT_URL is /shop/categories/5?size=medium
200		define('CURRENT_URL', $_SERVER['REQUEST_URI']);
201		
202		// SITE_FILENAME is the path and real filename of this application relative to the domain, with leading and trailing slashes
203		// example: for http://www.example.com/shop/index[.php]/categories/5?size=medium, SITE_FILENAME is /shop/index.php/
204		define('SITE_FILENAME', substr($_SERVER['SCRIPT_FILENAME'], strlen($_SERVER['DOCUMENT_ROOT'])));
205		
206		// LOCATION is this request's URL relative to SITE_ROOT, excluding the query string, without leading or trailing slashes
207		// example: for http://www.example.com/shop/categories/5?size=medium, LOCATION is categories/5
208		$location = $_SERVER['REQUEST_URI'];
209		if (strpos($location, '?') != false) $location = substr($location, 0, strpos($location, '?'));
210		if (substr($location, 0, strlen(SITE_FILENAME)) == SITE_FILENAME) $location = substr($location, strlen(SITE_FILENAME));
211		if ($location === false) $location = '';
212		if (substr($location, 0, strlen(SITE_ROOT)) == SITE_ROOT) $location = substr($location, strlen(SITE_ROOT));
213		if (substr($location, 0, 1) == '/') $location = substr($location, 1);
214		define('LOCATION', $location);
215		
216		// SITE_URL is path and accessed filename of this application relative to the domain, with leading and trailing slashes
217		// example: for http://www.example.com/shop/index[.php]/categories/5?size=medium, SITE_URL is /shop/index[.php]/
218		$uri = $_SERVER['REQUEST_URI'];
219		$pos = strpos($uri, '?');
220		if ($pos != false) $uri = substr($uri, 0, $pos);
221		if (LOCATION != '') $uri = substr($uri, 0, -strlen(LOCATION));
222		define('SITE_URL', $uri);
223	}
224	
225	private static function _set_database() {
226		return false; // assumes mysql, unnecessary
227		if (empty($GLOBALS['config']['database'])) {
228			return;
229		}
230		
231		$GLOBALS['databases'] = array();
232		
233		$configs = array();
234		
235		foreach ($GLOBALS['config']['database'] as $key => $config) {
236			if (
237				$key != ENVIRONMENT
238				&& substr($key, 0, strlen(ENVIRONMENT . '-')) != ENVIRONMENT . '-'
239			) {
240				continue;
241			}
242			
243			if ($key == ENVIRONMENT) {
244				$key = ENVIRONMENT . '-_default_';
245			}
246
247			$k = $key;
248			$key = substr($key, strlen(ENVIRONMENT . '-'));
249			$last_char = substr($key, -1);
250			$last_digit = (int) $last_char;
251			$last_digit = (string) $last_digit;
252			$last_two_chars = substr($key, -2);
253			$last_two_digits = (int) $last_two_chars;
254			$last_two_digits = (string) $last_two_digits;
255			
256			if ($last_two_digits === $last_two_chars) {
257				$key = substr($key, 0, -2);
258			}
259			
260			if ($last_digit === $last_char) {
261				$key = substr($key, 0, -1);
262			}
263
264			if (empty($configs[$key])) $configs[$key] = array();
265			$configs[$key][] = $config;
266		}
267
268		foreach ($configs as $key => $key_configs) {
269			shuffle($key_configs);
270			$configs[$key] = $key_configs;
271		}
272
273		foreach ($configs as $key => $key_configs) {
274			$default_class = 'mysqli';
275			
276			foreach ($key_configs as $config) {
277				$class = $default_class;
278
279				if (!empty($config['class']) && $config['class'] != $default_class) {
280					$class = $config['class'];
281					$filename = APP_PATH . 'lib/classes/' . self::_inflect_underscore($class) . '.php';
282			
283					if (!file_exists($filename)) {
284						self::error('Database class \'' . $class . '\' not found at <em>' . $filename . '</em> in <strong>database.cfg</strong>');
285					}
286			
287					require_once $filename;
288				}
289	
290				$database = @new $class($config['server'], $config['username'], $config['password']);
291		
292				if (!$database) {
293					continue;
294				}
295		
296				if (!$database->select_db($config['name'])) {
297					continue;
298				}
299
300				$GLOBALS['databases'][$key] = $database;
301				break;
302			}
303		}
304		
305		if (empty($GLOBALS['databases'])) {
306			self::error('Database config not found for environment \'' . ENVIRONMENT . '\' in <strong>database.cfg</strong>');
307		}
308
309		$GLOBALS['database'] = reset($GLOBALS['databases']);
310	}
311
312	private static function _set_environment() {
313		if (empty($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI'] = '';
314		if (empty($_SERVER['HTTP_HOST'])) $_SERVER['HTTP_HOST'] = 'localhost';
315		$server = strtolower($_SERVER['HTTP_HOST']);
316		
317		$environment_conf = !empty($GLOBALS['config']['app']['environments']) ? $GLOBALS['config']['app']['environments'] : array();
318		$deployment_conf = !empty($GLOBALS['config']['app']['deployments']) ? $GLOBALS['config']['app']['deployments'] : array('main' => $server);
319		$confs = array(
320			'ENVIRONMENT' => $environment_conf,
321			'DEPLOYMENT' => $deployment_conf,
322		);
323		
324		foreach ($confs as $const => $conf) {
325			if (getenv('PARAGLIDE_'.$const)) {
326				define($const, getenv('PARAGLIDE_'.$const));
327			} else {
328				foreach ($conf as $env => $domains) {
329					$domains_array = explode(',', $domains);
330
331					foreach ($domains_array as $domain) {
332						$domain = trim($domain);
333						$domain = strtolower($domain);
334						$domain = str_replace('.', '\.', $domain);
335						$domain = str_replace('*', '.+', $domain);
336						if (!preg_match('/' . $domain . '/', $server)) continue;
337						define($const, $env);
338						break;
339					}
340
341					if (defined($const)) break;
342				}
343
344				if (!defined($const)) {
345					$const_lower = strtolower($const);
346					self::error('No ' . $const_lower . ' found for \'' . $server . '\' in <strong>config/app.cfg</strong>');
347				}
348			}
349		}
350		
351		error_reporting(ENVIRONMENT == 'live' ? 0 : E_ALL);
352	}
353	
354	private static function _to_output_array($data) {
355		$function = function(&$item, $key) {
356			if (is_object($item) && method_exists($item, '__toArray'))
357				$item = $item->__toArray();
358		};
359		array_walk_recursive($data, $function);
360		
361		return $data;
362	}
363
364	public static function error($message) {
365		if (!file_exists(APP_PATH . 'views/framework_error.tpl')) {
366			die($message);
367		}
368		
369		require_once APP_PATH . 'views/framework_error.tpl';
370		die;
371	}
372	
373	public static function init() {
374		self::_set_constants();
375		self::_set_config_and_environment();
376		self::_set_database();
377		self::_set_cache();
378		self::_execute_hook('file', 'init');
379		$GLOBALS['data'] = array();
380	}
381	
382	public static function load($location) {
383		// fix the location
384		if (strlen($location) > 0 && substr($location, 0, 1) == '/') $location = substr($location, 1);
385	
386		// set the query string if passed in
387		$location_parts = explode('?', $location, 2);
388		$location = $location_parts[0];
389
390		if (!empty($location_parts[1])) {
391			$query_string = $location_parts[1];
392			$query_string_parts = explode('&', $query_string);
393			$_GET = array();
394			
395			foreach ($query_string_parts as $part) {
396				$pair = explode('=', $part);
397				$_GET[$pair[0]] = isset($pair[1]) ? $pair[1] : null;
398			}
399		}
400		
401		if (empty(self::$request_type)) {
402			// set the request type
403			$pos = strrpos($location, '.');
404
405			if ($pos != false) {
406				$type = substr($location, $pos + 1);
407			
408				if (!empty(self::$_request_types[$type])) {
409					self::$request_type = $type;
410					$location = substr($location, 0, $pos);
411				}
412			}
413			
414			if (empty(self::$request_type)) {
415				self::$request_type = 'html';
416			}
417		}
418	
419		// perform routing
420		$GLOBALS['arguments'] = array();
421		$arguments = explode('/', $location);
422		$nested_dirs = $arguments;
423		$controller = DEFAULT_CONTROLLER;
424		self::$nested_dir = '';
425		
426		while (true) {
427			$try = APP_PATH . 'controllers/';
428			$try_controller = str_replace('-', '_', DEFAULT_CONTROLLER);
429			$i = count($nested_dirs);
430			foreach ($nested_dirs as $dir) $try .= str_replace('-', '_', $dir) . '/';
431			
432			if (is_dir($try)) {
433				$try_controller = str_replace('-', '_', isset($arguments[$i]) ? $arguments[$i] : DEFAULT_CONTROLLER);
434
435				if (!file_exists($try . $try_controller . '_controller.php')) {
436					$try_controller = str_replace('-', '_', DEFAULT_CONTROLLER);
437				} else {
438					$i++;
439				}
440			}
441			
442			if (!file_exists($try . $try_controller . '_controller.php')) {
443				if (count($nested_dirs) == 0) break;
444				$nested_dirs = array_slice($nested_dirs, 0, -1);
445				continue;
446			}
447			
448			if (count($nested_dirs) > 0) self::$nested_dir = implode('/', $nested_dirs) . '/';
449			$arguments = array_slice($arguments, $i);
450			$controller = $try_controller;
451			break;
452		}
453
454		// set the controller
455		self::$controller = $controller;
456		
457		// run file preprocessing
458		self::_execute_hook('file', 'preprocess');
459		
460		// init the controller
461		if (empty(self::$nested_dir)) {
462			$controller_file = 'controllers/' . self::$controller . '_controller.php';
463		} else {
464			$controller_file = 'controllers/' . self::$nested_dir . '/' . self::$controller . '_controller.php';
465		}
466
467		require_once $controller_file;
468		$controller_class = str_replace(' ', '', self::_inflect_camelize(self::$controller)) . 'Controller';
469
470		if (!class_exists($controller_class)) {
471			self::error('Undefined controller class \'' . $controller_class . '\' in <strong>' . $controller_file . '</strong>');
472		}
473
474		self::$_controller_instance = new $controller_class();
475
476		// load the classes, helpers, and models
477		if (!empty(self::$_controller_instance->classes)) self::load_classes(self::$_controller_instance->classes);
478		if (!empty(self::$_controller_instance->helpers)) self::load_helpers(self::$_controller_instance->helpers);
479		if (!empty(self::$_controller_instance->models)) self::load_models(self::$_controller_instance->models);
480		
481		// set the function
482		$action = !empty($arguments[0]) ? $arguments[0] : 'index';
483		if (substr($action, 0, 1) == '_') $action = 'index';
484
485		$function = str_replace('-', '_', $action);
486		$function = method_exists(self::$_controller_instance, $function) ? $function : 'index';
487		
488		if (!empty($arguments[0]) && str_replace('-', '_', $arguments[0]) == $function) {
489			$arguments = array_slice($arguments, 1);
490		}
491		
492		// FIX -- Weird hack that was making requests failing (Sean)
493		if (count($arguments) == 1 && empty($arguments[0]))
494			$arguments = array();
495		
496		foreach ($arguments as $key => $val) {
497			$arguments[$key] = urldecode($val);
498		}
499
500		$GLOBALS['arguments'] = $arguments;
501		
502		self::$action = str_replace('_', '-', $function);
503
504		if (!method_exists(self::$_controller_instance, 'index')) {
505			self::error('Missing required function \'index\' in <strong>' . $controller_file . '</strong>');
506		}
507		
508		// run controller preprocessing
509		self::_execute_hook('controller', 'preprocess');
510
511		// start buffering the output for display later
512		ob_start();
513
514		// run the controller and generate the view
515		try {
516			call_user_func_array(array(self::$_controller_instance, $function), $GLOBALS['arguments']);
517		} catch (ParaglideExitException $e) {
518			// do nothing
519		}
520		
521		// if the request was redirected, stop here
522		if (self::$_done_loading) {
523			ob_end_flush(); // turn off output buffering so it's not nested
524			return;
525		}
526
527		// get the content
528		self::$_data['PAGE_CONTENT'] = ob_get_clean();
529		
530		// run any postprocessing
531		self::_execute_hook('controller', 'postprocess');
532		self::_execute_hook('file', 'postprocess');
533		
534		// render
535		self::_render();
536	}
537	
538	public static function load_classes($classes) {
539		if (empty($classes)) {
540			return;
541		}
542		
543		self::load_files('class', 'lib/classes', $classes);
544	}
545
546	public static function load_files($type, $dir, $files) {
547		if (empty($files) || !is_array($files)) {
548			return;
549		}
550
551		foreach ($files as $file) {
552			$filename = self::_inflect_underscore($file);
553			$path = APP_PATH . $dir . "/{$filename}.php";
554
555			if (!file_exists($path)) {
556				$controller_file = 'controllers/' . self::$nested_dir . self::$controller . '_controller.php';
557				self::error('Missing ' . $type . ' file \'' . $path . '\' referenced from <strong>' . $controller_file . '</strong>');
558			}
559
560			require_once $path;
561		}
562	}
563
564	public static function load_helpers($helpers) {
565		if (empty($helpers)) {
566			return;
567		}
568		
569		self::load_files('helper', 'lib/helpers', $helpers);
570	}
571
572	public static function load_models($models) {
573		if (empty($models)) {
574			return;
575		}
576		
577		self::load_files('model', 'models', $models);
578	}
579
580	public static function long_url($controller = null, $action = null, $params = null, $query_string = null, $ssl = false) {
581		$url = self::url($controller, $action, $params, $query_string, $ssl);
582		if (substr($url, 0, 7) == 'http://') return $url;
583		if (substr($url, 0, 8) == 'https://') return $url;
584		$prefix = ($ssl == true) ? 'https' : 'http';
585		return $prefix . '://' . $_SERVER['HTTP_HOST'] . $url;
586	}
587	
588	public static function parse_config($file, $ignore_errors = false) {
589		$local_filename = APP_PATH . 'config/local/' . $file . '.cfg';
590		if (file_exists($local_filename)) $filename = $local_filename;
591		
592		if (defined('DEPLOYMENT') && empty($filename)) {
593			$deployment_filename = APP_PATH . 'config/deployments/' . DEPLOYMENT . '/' . $file . '.cfg';
594			if (file_exists($deployment_filename)) $filename = $deployment_filename;
595		}
596		
597		if (empty($filename)) {
598			$filename = APP_PATH . 'config/' . $file . '.cfg';
599			
600			if (!file_exists($filename)) {
601				if ($ignore_errors) return null;
602				die('Config file \'config/' . $file . '.cfg\' not found');
603			}
604		}
605
606		return parse_ini_file($filename, true);
607	}
608
609	public static function query_string($params) {
610		if (empty($params) || !is_array($params)) {
611			return '';
612		}
613		
614		$parts = array();
615		foreach ($params as $key => $val) $parts[] = urlencode($key) . '=' . urlencode($val);
616		$string = '?' . implode('&', $parts);
617		return $string;
618	}
619
620	public static function redirect($controller = null, $action = null, $params = null, $query_string = null, $ssl = false) {
621		if (self::$request_type != 'html') {
622			$url = $controller;
623			
624			if (strlen($action) > 0) {
625				if (strlen($controller) > 0) $url .= '/';
626				$url .= $action;
627			}
628			
629			if (is_array($params)) $params = implode('/', $params);
630			if ($params != '') $url .= '/' . $params;
631
632			if (is_array($query_string)) $query_string = self::query_string($query_string);
633			if ($query_string{0} != '?') $query_string = '?' . $query_string;
634			if (strlen($query_string) == 1) $query_string = '';
635			$url .= $query_string;
636			
637			if (!empty($_GET['jsonp'])) {
638				$jsonp = $_GET['jsonp'];
639			}
640			
641			$_GET = null;
642			$_POST = null;
643			
644			if (!empty($jsonp)) {
645				$_GET['jsonp'] = $jsonp;
646			}
647			
648			self::load($url);
649			die;
650		}
651	
652		$url = self::url($controller, $action, $params, $query_string, $ssl);
653		self::redirect_to($url);
654	}
655
656	public static function redirect_to($url) {
657		header('Location: ' . $url);
658		die;
659	}
660
661	public static function render_view($_view, $_data = null, $_buffer = false) {
662		if (!$_buffer && self::$request_type == 'json') {
663			$_data = self::_to_output_array($_data);
664			$js = json_encode($_data);
665			if (!empty($_GET['jsonp'])) $js = $_GET['jsonp'] . '(' . $js . ')';
666			echo $js;
667			self::$_skip_layout = true;
668			return;
669		} if (!$_buffer && self::$request_type == 'csv') {
670			header('Content-type: text/csv');
671			$_data = self::_to_output_array($_data);
672			foreach ($_data as $line) {
673				if (!is_array($line))
674					continue;
675				$prefix = '';
676				foreach ($line as $item) {
677					echo $prefix.'"'.str_replace('"', '\"', $item).'"';
678					$prefix = ',';
679				}
680				echo "\n";
681			}
682			self::$_skip_layout = true;
683			return;
684		}
685	
686		if (!file_exists(APP_PATH . "views/{$_view}.tpl")) {
687			self::error('View \'' . $_view . '\' not found at <strong>views/' . $_view . '.tpl</strong>');
688		}
689
690		foreach ($GLOBALS['data'] as $key => $val) {
691			$$key = $val;
692		}
693
694		if (!empty($_data) && is_array($_data)) {
695			self::$_data = array_merge(self::$_data, $_data);
696		}
697		
698		foreach (self::$_data as $key => $val) {
699			$$key = $val;
700		}
701		
702		if ($_buffer) {
703			ob_start();
704		}
705
706		require APP_PATH . 'views/' . $_view . '.tpl';
707		
708		if ($_buffer) {
709			return ob_get_clean();
710		}
711	}
712
713	public static function require_not_ssl() {
714		if (empty($_SERVER['HTTPS'])) {
715			return;
716		}
717		 
718		$host = $_SERVER['HTTP_HOST'];
719		$url = $_SERVER['REQUEST_URI'];
720		self::redirect_to('http://' . $host . $url);
721    }
722    
723	public static function require_json() {
724		if (self::$request_type == 'json') {
725			return;
726		}
727		
728		$url = LOCATION . '.json';
729		if (!empty($_GET)) $url .= self::_query_string($_GET);
730		self::redirect_to($url);
731	}
732
733	public static function require_ssl() {
734		if (!empty($_SERVER['HTTPS'])) {
735			return;
736		}
737		
738		$host = $_SERVER['HTTP_HOST'];
739		$url = $_SERVER['REQUEST_URI'];
740		self::redirect_to('https://' . $host . $url);
741	}
742
743	public static function url($controller = null, $action = null, $params = null, $query_string = null, $ssl = false) {
744        $server_port = (!empty($_SERVER['SERVER_PORT'])) ? $_SERVER['SERVER_PORT'] : '';
745        
746		if ($server_port == 443 && $ssl == false) {
747			$prefix = 'http://' . $_SERVER['HTTP_HOST'];
748		} elseif ($server_port != 443 && $ssl == true) {
749			$prefix = 'https://' . $_SERVER['HTTP_HOST'];
750		} else {
751			$prefix = '';
752		}
753
754		$prefix .= SITE_URL;
755		if (substr($prefix, -1) != '/') $prefix .= '/';
756		$url = $prefix . $controller;
757		
758		if (strlen($action) > 0) {
759			if (strlen($controller) > 0) $url .= '/';
760			$url .= $action;
761		}
762		
763		if (!empty($params)) {
764			$new_params = array();
765			if (!is_array($params)) $params = array($params);
766		
767			foreach ($params as $key => $value) {
768				if (strlen($value) > 0) {
769					$new_params[] = $value;
770				}
771			}
772		
773			$params = $new_params;
774		}
775		
776		if (is_array($params)) $params = implode('/', $params);
777		if ($params != '') $url .= '/' . $params;
778
779		if (!empty($query_string)) {
780			if (is_array($query_string)) $query_string = self::query_string($query_string);
781			if ($query_string{0} != '?') $query_string = '?' . $query_string;
782			if (strlen($query_string) == 1) $query_string = '';
783			$url .= $query_string;
784		}
785		
786		return $url;
787	}
788}