PageRenderTime 56ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/vendors/limonade/lib/limonade.php

https://github.com/s-aska/php-openid-with-ld
PHP | 2664 lines | 1477 code | 256 blank | 931 comment | 241 complexity | d05a67344019fffae0da72b446fedbbc MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. # ============================================================================ #
  3. /**
  4. * L I M O N A D E
  5. *
  6. * a PHP micro framework.
  7. *
  8. * For more informations: {@link http://github/sofadesign/limonade}
  9. *
  10. * @author Fabrice Luraine
  11. * @copyright Copyright (c) 2009 Fabrice Luraine
  12. * @license http://opensource.org/licenses/mit-license.php The MIT License
  13. * @package limonade
  14. */
  15. # ----------------------------------------------------------------------- #
  16. # Copyright (c) 2009 Fabrice Luraine #
  17. # #
  18. # Permission is hereby granted, free of charge, to any person #
  19. # obtaining a copy of this software and associated documentation #
  20. # files (the "Software"), to deal in the Software without #
  21. # restriction, including without limitation the rights to use, #
  22. # copy, modify, merge, publish, distribute, sublicense, and/or sell #
  23. # copies of the Software, and to permit persons to whom the #
  24. # Software is furnished to do so, subject to the following #
  25. # conditions: #
  26. # #
  27. # The above copyright notice and this permission notice shall be #
  28. # included in all copies or substantial portions of the Software. #
  29. # #
  30. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, #
  31. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES #
  32. # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND #
  33. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #
  34. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, #
  35. # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING #
  36. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
  37. # OTHER DEALINGS IN THE SOFTWARE. #
  38. # ============================================================================ #
  39. # ============================================================================ #
  40. # 0. PREPARE #
  41. # ============================================================================ #
  42. ## CONSTANTS __________________________________________________________________
  43. /**
  44. * Limonade version
  45. */
  46. define('LIMONADE', '0.5.0');
  47. define('LIM_NAME', 'Un grand cru qui sait se faire attendre');
  48. define('LIM_START_MICROTIME', (float)substr(microtime(), 0, 10));
  49. define('LIM_SESSION_NAME', 'LIMONADE'.str_replace('.','x',LIMONADE));
  50. define('LIM_SESSION_FLASH_KEY', '_lim_flash_messages');
  51. if(function_exists('memory_get_usage'))
  52. define('LIM_START_MEMORY', memory_get_usage());
  53. define('E_LIM_HTTP', 32768);
  54. define('E_LIM_PHP', 65536);
  55. define('E_LIM_DEPRECATED', 35000);
  56. define('NOT_FOUND', 404);
  57. define('SERVER_ERROR', 500);
  58. define('ENV_PRODUCTION', 10);
  59. define('ENV_DEVELOPMENT', 100);
  60. define('X-SENDFILE', 10);
  61. define('X-LIGHTTPD-SEND-FILE', 20);
  62. # for PHP 5.3.0 <
  63. if(!defined('E_DEPRECATED')) define('E_DEPRECATED', 8192);
  64. if(!defined('E_USER_DEPRECATED')) define('E_USER_DEPRECATED', 16384);
  65. # for PHP 5.2.0 <
  66. if (!defined('E_RECOVERABLE_ERROR')) define('E_RECOVERABLE_ERROR', 4096);
  67. ## SETTING BASIC SECURITY _____________________________________________________
  68. # A. Unsets all global variables set from a superglobal array
  69. /**
  70. * @access private
  71. * @return void
  72. */
  73. function unregister_globals()
  74. {
  75. $args = func_get_args();
  76. foreach($args as $k => $v)
  77. if(array_key_exists($k, $GLOBALS)) unset($GLOBALS[$k]);
  78. }
  79. if(ini_get('register_globals'))
  80. {
  81. unregister_globals( '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER',
  82. '_ENV', '_FILES');
  83. ini_set('register_globals', 0);
  84. }
  85. # B. removing magic quotes
  86. /**
  87. * @access private
  88. * @param string $array
  89. * @return array
  90. */
  91. function remove_magic_quotes($array)
  92. {
  93. foreach ($array as $k => $v)
  94. $array[$k] = is_array($v) ? remove_magic_quotes($v) : stripslashes($v);
  95. return $array;
  96. }
  97. if (get_magic_quotes_gpc())
  98. {
  99. $_GET = remove_magic_quotes($_GET);
  100. $_POST = remove_magic_quotes($_POST);
  101. $_COOKIE = remove_magic_quotes($_COOKIE);
  102. ini_set('magic_quotes_gpc', 0);
  103. }
  104. if(function_exists('set_magic_quotes_runtime') && get_magic_quotes_runtime()) set_magic_quotes_runtime(false);
  105. # C. Disable error display
  106. # by default, no error reporting; it will be switched on later in run().
  107. # ini_set('display_errors', 1); must be called explicitly in app file
  108. # if you want to show errors before running app
  109. ini_set('display_errors', 0);
  110. ## SETTING INTERNAL ROUTES _____________________________________________________
  111. dispatch(array("/_lim_css/*.css", array('_lim_css_filename')), 'render_limonade_css');
  112. /**
  113. * Internal controller that responds to route /_lim_css/*.css
  114. *
  115. * @access private
  116. * @return string
  117. */
  118. function render_limonade_css()
  119. {
  120. option('views_dir', file_path(option('limonade_public_dir'), 'css'));
  121. $fpath = file_path(params('_lim_css_filename').".css");
  122. return css($fpath, null); // with no layout
  123. }
  124. dispatch(array("/_lim_public/**", array('_lim_public_file')), 'render_limonade_file');
  125. /**
  126. * Internal controller that responds to route /_lim_public/**
  127. *
  128. * @access private
  129. * @return void
  130. */
  131. function render_limonade_file()
  132. {
  133. $fpath = file_path(option('limonade_public_dir'), params('_lim_public_file'));
  134. return render_file($fpath, true);
  135. }
  136. # # #
  137. # ============================================================================ #
  138. # 1. BASE #
  139. # ============================================================================ #
  140. ## ABSTRACTS ___________________________________________________________________
  141. # Abstract methods that might be redefined by user:
  142. #
  143. # - function configure(){}
  144. # - function initialize(){}
  145. # - function autoload_controller($callback){}
  146. # - function before($route){}
  147. # - function after($output, $route){}
  148. # - function not_found($errno, $errstr, $errfile=null, $errline=null){}
  149. # - function server_error($errno, $errstr, $errfile=null, $errline=null){}
  150. # - function route_missing($request_method, $request_uri){}
  151. # - function before_exit(){}
  152. # - function before_render($content_or_func, $layout, $locals, $view_path){}
  153. # - function autorender($route){}
  154. # - function before_sending_header($header){}
  155. #
  156. # See abstract.php for more details.
  157. ## MAIN PUBLIC FUNCTIONS _______________________________________________________
  158. /**
  159. * Set and returns options values
  160. *
  161. * If multiple values are provided, set $name option with an array of those values.
  162. * If there is only one value, set $name option with the provided $values
  163. *
  164. * @param string $name
  165. * @param mixed $values,...
  166. * @return mixed option value for $name if $name argument is provided, else return all options
  167. */
  168. function option($name = null, $values = null)
  169. {
  170. static $options = array();
  171. $args = func_get_args();
  172. $name = array_shift($args);
  173. if(is_null($name)) return $options;
  174. if(!empty($args))
  175. {
  176. $options[$name] = count($args) > 1 ? $args : $args[0];
  177. }
  178. if(array_key_exists($name, $options)) return $options[$name];
  179. return;
  180. }
  181. /**
  182. * Set and returns params
  183. *
  184. * Depending on provided arguments:
  185. *
  186. * * Reset params if first argument is null
  187. *
  188. * * If first argument is an array, merge it with current params
  189. *
  190. * * If there is a second argument $value, set param $name (first argument) with $value
  191. * <code>
  192. * params('name', 'Doe') // set 'name' => 'Doe'
  193. * </code>
  194. * * If there is more than 2 arguments, set param $name (first argument) value with
  195. * an array of next arguments
  196. * <code>
  197. * params('months', 'jan', 'feb', 'mar') // set 'month' => array('months', 'jan', 'feb', 'mar')
  198. * </code>
  199. *
  200. * @param mixed $name_or_array_or_null could be null || array of params || name of a param (optional)
  201. * @param mixed $value,... for the $name param (optional)
  202. * @return mixed all params, or one if a first argument $name is provided
  203. */
  204. function params($name_or_array_or_null = null, $value = null)
  205. {
  206. static $params = array();
  207. $args = func_get_args();
  208. if(func_num_args() > 0)
  209. {
  210. $name = array_shift($args);
  211. if(is_null($name))
  212. {
  213. # Reset params
  214. $params = array();
  215. return $params;
  216. }
  217. if(is_array($name))
  218. {
  219. $params = array_merge($params, $name);
  220. return $params;
  221. }
  222. $nargs = count($args);
  223. if($nargs > 0)
  224. {
  225. $value = $nargs > 1 ? $args : $args[0];
  226. $params[$name] = $value;
  227. }
  228. return array_key_exists($name,$params) ? $params[$name] : null;
  229. }
  230. return $params;
  231. }
  232. /**
  233. * Set and returns template variables
  234. *
  235. * If multiple values are provided, set $name variable with an array of those values.
  236. * If there is only one value, set $name variable with the provided $values
  237. *
  238. * @param string $name
  239. * @param mixed $values,...
  240. * @return mixed variable value for $name if $name argument is provided, else return all variables
  241. */
  242. function set($name = null, $values = null)
  243. {
  244. static $vars = array();
  245. $args = func_get_args();
  246. $name = array_shift($args);
  247. if(is_null($name)) return $vars;
  248. if(!empty($args))
  249. {
  250. $vars[$name] = count($args) > 1 ? $args : $args[0];
  251. }
  252. if(array_key_exists($name, $vars)) return $vars[$name];
  253. return $vars;
  254. }
  255. /**
  256. * Sets a template variable with a value or a default value if value is empty
  257. *
  258. * @param string $name
  259. * @param string $value
  260. * @param string $default
  261. * @return mixed setted value
  262. */
  263. function set_or_default($name, $value, $default)
  264. {
  265. return set($name, value_or_default($value, $default));
  266. }
  267. /**
  268. * Running application
  269. *
  270. * @param string $env
  271. * @return void
  272. */
  273. function run($env = null)
  274. {
  275. if(is_null($env)) $env = env();
  276. # 0. Set default configuration
  277. $root_dir = dirname(app_file());
  278. $lim_dir = dirname(__FILE__);
  279. $base_path = dirname(file_path($env['SERVER']['SCRIPT_NAME']));
  280. $base_file = basename($env['SERVER']['SCRIPT_NAME']);
  281. $base_uri = file_path($base_path, (($base_file == 'index.php') ? '?' : $base_file.'?'));
  282. option('root_dir', $root_dir);
  283. option('limonade_dir', file_path($lim_dir));
  284. option('limonade_views_dir', file_path($lim_dir, 'limonade', 'views'));
  285. option('limonade_public_dir',file_path($lim_dir, 'limonade', 'public'));
  286. option('public_dir', file_path($root_dir, 'public'));
  287. option('views_dir', file_path($root_dir, 'views'));
  288. option('controllers_dir', file_path($root_dir, 'controllers'));
  289. option('lib_dir', file_path($root_dir, 'lib'));
  290. option('error_views_dir', option('limonade_views_dir'));
  291. option('base_path', $base_path);
  292. option('base_uri', $base_uri); // set it manually if you use url_rewriting
  293. option('env', ENV_PRODUCTION);
  294. option('debug', true);
  295. option('session', LIM_SESSION_NAME); // true, false or the name of your session
  296. option('encoding', 'utf-8');
  297. option('signature', LIM_NAME); // X-Limonade header value or false to hide it
  298. option('gzip', false);
  299. option('x-sendfile', 0); // 0: disabled,
  300. // X-SENDFILE: for Apache and Lighttpd v. >= 1.5,
  301. // X-LIGHTTPD-SEND-FILE: for Apache and Lighttpd v. < 1.5
  302. # 1. Set handlers
  303. # 1.1 Set error handling
  304. ini_set('display_errors', 1);
  305. set_error_handler('error_handler_dispatcher', E_ALL ^ E_NOTICE);
  306. # 1.2 Register shutdown function
  307. register_shutdown_function('stop_and_exit');
  308. # 2. Set user configuration
  309. call_if_exists('configure');
  310. # 2.1 Set gzip compression if defined
  311. if(is_bool(option('gzip')) && option('gzip'))
  312. {
  313. ini_set('zlib.output_compression', '1');
  314. }
  315. # 2.2 Set X-Limonade header
  316. if($signature = option('signature')) send_header("X-Limonade: $signature");
  317. # 3. Loading libs
  318. require_once_dir(option('lib_dir'));
  319. fallbacks_for_not_implemented_functions();
  320. # 4. Starting session
  321. if(!defined('SID') && option('session'))
  322. {
  323. if(!is_bool(option('session'))) session_name(option('session'));
  324. if(!session_start()) trigger_error("An error occured while trying to start the session", E_USER_WARNING);
  325. }
  326. # 5. Set some default methods if needed
  327. if(!function_exists('after'))
  328. {
  329. function after($output)
  330. {
  331. return $output;
  332. }
  333. }
  334. if(!function_exists('route_missing'))
  335. {
  336. function route_missing($request_method, $request_uri)
  337. {
  338. halt(NOT_FOUND, "($request_method) $request_uri");
  339. }
  340. }
  341. call_if_exists('initialize');
  342. # 6. Check request
  343. if($rm = request_method($env))
  344. {
  345. if(request_is_head($env)) ob_start(); // then no output
  346. if(!request_method_is_allowed($rm))
  347. halt(HTTP_NOT_IMPLEMENTED, "The requested method <code>'$rm'</code> is not implemented");
  348. # 6.1 Check matching route
  349. if($route = route_find($rm, request_uri($env)))
  350. {
  351. params($route['params']);
  352. # 6.2 Load controllers dir
  353. if(!function_exists('autoload_controller'))
  354. {
  355. function autoload_controller($callback)
  356. {
  357. require_once_dir(option('controllers_dir'));
  358. }
  359. }
  360. autoload_controller($route['callback']);
  361. if(is_callable($route['callback']))
  362. {
  363. # 6.3 Call before function
  364. call_if_exists('before', $route);
  365. # 6.4 Call matching controller function and output result
  366. $output = call_user_func_array($route['callback'], array_values($route['params']));
  367. if(is_null($output)) $output = call_if_exists('autorender', $route);
  368. echo after(error_notices_render() . $output, $route);
  369. }
  370. else halt(SERVER_ERROR, "Routing error: undefined function '{$route['callback']}'", $route);
  371. }
  372. else route_missing($rm, request_uri($env));
  373. }
  374. else halt(HTTP_NOT_IMPLEMENTED, "The requested method <code>'$rm'</code> is not implemented");
  375. }
  376. /**
  377. * Stop and exit limonade application
  378. *
  379. * @access private
  380. * @param boolean exit or not
  381. * @return void
  382. */
  383. function stop_and_exit($exit = true)
  384. {
  385. call_if_exists('before_exit', $exit);
  386. $headers = headers_list();
  387. if(request_is_head())
  388. {
  389. ob_end_clean();
  390. } else {
  391. $flash_sweep = true;
  392. foreach($headers as $header)
  393. {
  394. // If a Content-Type header exists, flash_sweep only if is text/html
  395. // Else if there's no Content-Type header, flash_sweep by default
  396. if(stripos($header, 'Content-Type:') === 0)
  397. {
  398. $flash_sweep = stripos($header, 'Content-Type: text/html') === 0;
  399. break;
  400. }
  401. }
  402. if($flash_sweep) flash_sweep();
  403. }
  404. if(defined('SID')) session_write_close();
  405. if($exit) exit;
  406. }
  407. /**
  408. * Returns limonade environment variables:
  409. *
  410. * 'SERVER', 'FILES', 'REQUEST', 'SESSION', 'ENV', 'COOKIE',
  411. * 'GET', 'POST', 'PUT', 'DELETE'
  412. *
  413. * If a null argument is passed, reset and rebuild environment
  414. *
  415. * @param null @reset reset and rebuild environment
  416. * @return array
  417. */
  418. function env($reset = null)
  419. {
  420. static $env = array();
  421. if(func_num_args() > 0)
  422. {
  423. $args = func_get_args();
  424. if(is_null($args[0])) $env = array();
  425. }
  426. if(empty($env))
  427. {
  428. if(empty($GLOBALS['_SERVER']))
  429. {
  430. // Fixing empty $GLOBALS['_SERVER'] bug
  431. // http://sofadesign.lighthouseapp.com/projects/29612-limonade/tickets/29-env-is-empty
  432. $GLOBALS['_SERVER'] =& $_SERVER;
  433. $GLOBALS['_FILES'] =& $_FILES;
  434. $GLOBALS['_REQUEST'] =& $_REQUEST;
  435. $GLOBALS['_SESSION'] =& $_SESSION;
  436. $GLOBALS['_ENV'] =& $_ENV;
  437. $GLOBALS['_COOKIE'] =& $_COOKIE;
  438. }
  439. $glo_names = array('SERVER', 'FILES', 'REQUEST', 'SESSION', 'ENV', 'COOKIE');
  440. $vars = array_merge($glo_names, request_methods());
  441. foreach($vars as $var)
  442. {
  443. $varname = "_$var";
  444. if(!array_key_exists($varname, $GLOBALS)) $GLOBALS[$varname] = array();
  445. $env[$var] =& $GLOBALS[$varname];
  446. }
  447. $method = request_method($env);
  448. if($method == 'PUT' || $method == 'DELETE')
  449. {
  450. $varname = "_$method";
  451. if(array_key_exists('_method', $_POST) && $_POST['_method'] == $method)
  452. {
  453. foreach($_POST as $k => $v)
  454. {
  455. if($k == "_method") continue;
  456. $GLOBALS[$varname][$k] = $v;
  457. }
  458. }
  459. else
  460. {
  461. parse_str(file_get_contents('php://input'), $GLOBALS[$varname]);
  462. }
  463. }
  464. }
  465. return $env;
  466. }
  467. /**
  468. * Returns application root file path
  469. *
  470. * @return string
  471. */
  472. function app_file()
  473. {
  474. static $file;
  475. if(empty($file))
  476. {
  477. $debug_backtrace = debug_backtrace();
  478. $stacktrace = array_pop($debug_backtrace);
  479. $file = $stacktrace['file'];
  480. }
  481. return file_path($file);
  482. }
  483. # # #
  484. # ============================================================================ #
  485. # 2. ERROR #
  486. # ============================================================================ #
  487. /**
  488. * Associate a function with error code(s) and return all associations
  489. *
  490. * @param string $errno
  491. * @param string $function
  492. * @return array
  493. */
  494. function error($errno = null, $function = null)
  495. {
  496. static $errors = array();
  497. if(func_num_args() > 0)
  498. {
  499. $errors[] = array('errno'=>$errno, 'function'=> $function);
  500. }
  501. return $errors;
  502. }
  503. /**
  504. * Raise an error, passing a given error number and an optional message,
  505. * then exit.
  506. * Error number should be a HTTP status code or a php user error (E_USER...)
  507. * $errno and $msg arguments can be passsed in any order
  508. * If no arguments are passed, default $errno is SERVER_ERROR (500)
  509. *
  510. * @param int,string $errno Error number or message string
  511. * @param string,string $msg Message string or error number
  512. * @param mixed $debug_args extra data provided for debugging
  513. * @return void
  514. */
  515. function halt($errno = SERVER_ERROR, $msg = '', $debug_args = null)
  516. {
  517. $args = func_get_args();
  518. $error = array_shift($args);
  519. # switch $errno and $msg args
  520. # TODO cleanup / refactoring
  521. if(is_string($errno))
  522. {
  523. $msg = $errno;
  524. $oldmsg = array_shift($args);
  525. $errno = empty($oldmsg) ? SERVER_ERROR : $oldmsg;
  526. }
  527. else if(!empty($args)) $msg = array_shift($args);
  528. if(empty($msg) && $errno == NOT_FOUND) $msg = request_uri();
  529. if(empty($msg)) $msg = "";
  530. if(!empty($args)) $debug_args = $args;
  531. set('_lim_err_debug_args', $debug_args);
  532. error_handler_dispatcher($errno, $msg, null, null);
  533. }
  534. /**
  535. * Internal error handler dispatcher
  536. * Find and call matching error handler and exit
  537. * If no match found, call default error handler
  538. *
  539. * @access private
  540. * @param int $errno
  541. * @param string $errstr
  542. * @param string $errfile
  543. * @param string $errline
  544. * @return void
  545. */
  546. function error_handler_dispatcher($errno, $errstr, $errfile, $errline)
  547. {
  548. $back_trace = debug_backtrace();
  549. while($trace = array_shift($back_trace))
  550. {
  551. if($trace['function'] == 'halt')
  552. {
  553. $errfile = $trace['file'];
  554. $errline = $trace['line'];
  555. break;
  556. }
  557. }
  558. # Notices and warning won't halt execution
  559. if(error_wont_halt_app($errno))
  560. {
  561. error_notice($errno, $errstr, $errfile, $errline);
  562. return;
  563. }
  564. else
  565. {
  566. # Other errors will stop application
  567. static $handlers = array();
  568. if(empty($handlers))
  569. {
  570. error(E_LIM_PHP, 'error_default_handler');
  571. $handlers = error();
  572. }
  573. $is_http_err = http_response_status_is_valid($errno);
  574. while($handler = array_shift($handlers))
  575. {
  576. $e = is_array($handler['errno']) ? $handler['errno'] : array($handler['errno']);
  577. while($ee = array_shift($e))
  578. {
  579. if($ee == $errno || $ee == E_LIM_PHP || ($ee == E_LIM_HTTP && $is_http_err))
  580. {
  581. echo call_if_exists($handler['function'], $errno, $errstr, $errfile, $errline);
  582. exit;
  583. }
  584. }
  585. }
  586. }
  587. }
  588. /**
  589. * Default error handler
  590. *
  591. * @param string $errno
  592. * @param string $errstr
  593. * @param string $errfile
  594. * @param string $errline
  595. * @return string error output
  596. */
  597. function error_default_handler($errno, $errstr, $errfile, $errline)
  598. {
  599. $is_http_err = http_response_status_is_valid($errno);
  600. $http_error_code = $is_http_err ? $errno : SERVER_ERROR;
  601. status($http_error_code);
  602. return $http_error_code == NOT_FOUND ?
  603. error_not_found_output($errno, $errstr, $errfile, $errline) :
  604. error_server_error_output($errno, $errstr, $errfile, $errline);
  605. }
  606. /**
  607. * Returns not found error output
  608. *
  609. * @access private
  610. * @param string $msg
  611. * @return string
  612. */
  613. function error_not_found_output($errno, $errstr, $errfile, $errline)
  614. {
  615. if(!function_exists('not_found'))
  616. {
  617. /**
  618. * Default not found error output
  619. *
  620. * @param string $errno
  621. * @param string $errstr
  622. * @param string $errfile
  623. * @param string $errline
  624. * @return string
  625. */
  626. function not_found($errno, $errstr, $errfile=null, $errline=null)
  627. {
  628. option('views_dir', option('error_views_dir'));
  629. $msg = h(rawurldecode($errstr));
  630. return html("<h1>Page not found:</h1><p><code>{$msg}</code></p>", error_layout());
  631. }
  632. }
  633. return not_found($errno, $errstr, $errfile, $errline);
  634. }
  635. /**
  636. * Returns server error output
  637. *
  638. * @access private
  639. * @param int $errno
  640. * @param string $errstr
  641. * @param string $errfile
  642. * @param string $errline
  643. * @return string
  644. */
  645. function error_server_error_output($errno, $errstr, $errfile, $errline)
  646. {
  647. if(!function_exists('server_error'))
  648. {
  649. /**
  650. * Default server error output
  651. *
  652. * @param string $errno
  653. * @param string $errstr
  654. * @param string $errfile
  655. * @param string $errline
  656. * @return string
  657. */
  658. function server_error($errno, $errstr, $errfile=null, $errline=null)
  659. {
  660. $is_http_error = http_response_status_is_valid($errno);
  661. $args = compact('errno', 'errstr', 'errfile', 'errline', 'is_http_error');
  662. option('views_dir', option('limonade_views_dir'));
  663. $html = render('error.html.php', null, $args);
  664. option('views_dir', option('error_views_dir'));
  665. return html($html, error_layout(), $args);
  666. }
  667. }
  668. return server_error($errno, $errstr, $errfile, $errline);
  669. }
  670. /**
  671. * Set and returns error output layout
  672. *
  673. * @param string $layout
  674. * @return string
  675. */
  676. function error_layout($layout = false)
  677. {
  678. static $o_layout = 'default_layout.php';
  679. if($layout !== false)
  680. {
  681. option('error_views_dir', option('views_dir'));
  682. $o_layout = $layout;
  683. }
  684. return $o_layout;
  685. }
  686. /**
  687. * Set a notice if arguments are provided
  688. * Returns all stored notices.
  689. * If $errno argument is null, reset the notices array
  690. *
  691. * @access private
  692. * @param string, null $str
  693. * @return array
  694. */
  695. function error_notice($errno = false, $errstr = null, $errfile = null, $errline = null)
  696. {
  697. static $notices = array();
  698. if($errno) $notices[] = compact('errno', 'errstr', 'errfile', 'errline');
  699. else if(is_null($errno)) $notices = array();
  700. return $notices;
  701. }
  702. /**
  703. * Returns notices output rendering and reset notices
  704. *
  705. * @return string
  706. */
  707. function error_notices_render()
  708. {
  709. if(option('debug') && option('env') > ENV_PRODUCTION)
  710. {
  711. $notices = error_notice();
  712. error_notice(null); // reset notices
  713. $c_view_dir = option('views_dir'); // keep for restore after render
  714. option('views_dir', option('limonade_views_dir'));
  715. $o = render('_notices.html.php', null, array('notices' => $notices));
  716. option('views_dir', $c_view_dir); // restore current views dir
  717. return $o;
  718. }
  719. }
  720. /**
  721. * Checks if an error is will halt application execution.
  722. * Notices and warnings will not.
  723. *
  724. * @access private
  725. * @param string $num error code number
  726. * @return boolean
  727. */
  728. function error_wont_halt_app($num)
  729. {
  730. return $num == E_NOTICE ||
  731. $num == E_WARNING ||
  732. $num == E_CORE_WARNING ||
  733. $num == E_COMPILE_WARNING ||
  734. $num == E_USER_WARNING ||
  735. $num == E_USER_NOTICE ||
  736. $num == E_DEPRECATED ||
  737. $num == E_USER_DEPRECATED ||
  738. $num == E_LIM_DEPRECATED;
  739. }
  740. /**
  741. * return error code name for a given code num, or return all errors names
  742. *
  743. * @param string $num
  744. * @return mixed
  745. */
  746. function error_type($num = null)
  747. {
  748. $types = array (
  749. E_ERROR => 'ERROR',
  750. E_WARNING => 'WARNING',
  751. E_PARSE => 'PARSING ERROR',
  752. E_NOTICE => 'NOTICE',
  753. E_CORE_ERROR => 'CORE ERROR',
  754. E_CORE_WARNING => 'CORE WARNING',
  755. E_COMPILE_ERROR => 'COMPILE ERROR',
  756. E_COMPILE_WARNING => 'COMPILE WARNING',
  757. E_USER_ERROR => 'USER ERROR',
  758. E_USER_WARNING => 'USER WARNING',
  759. E_USER_NOTICE => 'USER NOTICE',
  760. E_STRICT => 'STRICT NOTICE',
  761. E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR',
  762. E_DEPRECATED => 'DEPRECATED WARNING',
  763. E_USER_DEPRECATED => 'USER DEPRECATED WARNING',
  764. E_LIM_DEPRECATED => 'LIMONADE DEPRECATED WARNING'
  765. );
  766. return is_null($num) ? $types : $types[$num];
  767. }
  768. /**
  769. * Returns http response status for a given error number
  770. *
  771. * @param string $errno
  772. * @return int
  773. */
  774. function error_http_status($errno)
  775. {
  776. $code = http_response_status_is_valid($errno) ? $errno : SERVER_ERROR;
  777. return http_response_status($code);
  778. }
  779. # # #
  780. # ============================================================================ #
  781. # 3. REQUEST #
  782. # ============================================================================ #
  783. /**
  784. * Returns current request method for a given environment or current one
  785. *
  786. * @param string $env
  787. * @return string
  788. */
  789. function request_method($env = null)
  790. {
  791. if(is_null($env)) $env = env();
  792. $m = array_key_exists('REQUEST_METHOD', $env['SERVER']) ? $env['SERVER']['REQUEST_METHOD'] : null;
  793. if($m == "POST" && array_key_exists('_method', $env['POST']))
  794. $m = strtoupper($env['POST']['_method']);
  795. if(!in_array(strtoupper($m), request_methods()))
  796. {
  797. trigger_error("'$m' request method is unknown or unavailable.", E_USER_WARNING);
  798. $m = false;
  799. }
  800. return $m;
  801. }
  802. /**
  803. * Checks if a request method or current one is allowed
  804. *
  805. * @param string $m
  806. * @return bool
  807. */
  808. function request_method_is_allowed($m = null)
  809. {
  810. if(is_null($m)) $m = request_method();
  811. return in_array(strtoupper($m), request_methods());
  812. }
  813. /**
  814. * Checks if request method is GET
  815. *
  816. * @param string $env
  817. * @return bool
  818. */
  819. function request_is_get($env = null)
  820. {
  821. return request_method($env) == "GET";
  822. }
  823. /**
  824. * Checks if request method is POST
  825. *
  826. * @param string $env
  827. * @return bool
  828. */
  829. function request_is_post($env = null)
  830. {
  831. return request_method($env) == "POST";
  832. }
  833. /**
  834. * Checks if request method is PUT
  835. *
  836. * @param string $env
  837. * @return bool
  838. */
  839. function request_is_put($env = null)
  840. {
  841. return request_method($env) == "PUT";
  842. }
  843. /**
  844. * Checks if request method is DELETE
  845. *
  846. * @param string $env
  847. * @return bool
  848. */
  849. function request_is_delete($env = null)
  850. {
  851. return request_method($env) == "DELETE";
  852. }
  853. /**
  854. * Checks if request method is HEAD
  855. *
  856. * @param string $env
  857. * @return bool
  858. */
  859. function request_is_head($env = null)
  860. {
  861. return request_method($env) == "HEAD";
  862. }
  863. /**
  864. * Returns allowed request methods
  865. *
  866. * @return array
  867. */
  868. function request_methods()
  869. {
  870. return array("GET","POST","PUT","DELETE", "HEAD");
  871. }
  872. /**
  873. * Returns current request uri (the path that will be compared with routes)
  874. *
  875. * (Inspired from codeigniter URI::_fetch_uri_string method)
  876. *
  877. * @return string
  878. */
  879. function request_uri($env = null)
  880. {
  881. static $uri = null;
  882. if(is_null($env))
  883. {
  884. if(!is_null($uri)) return $uri;
  885. $env = env();
  886. }
  887. if(array_key_exists('uri', $env['GET']))
  888. {
  889. $uri = $env['GET']['uri'];
  890. }
  891. else if(array_key_exists('u', $env['GET']))
  892. {
  893. $uri = $env['GET']['u'];
  894. }
  895. // bug: dot are converted to _... so we can't use it...
  896. // else if (count($env['GET']) == 1 && trim(key($env['GET']), '/') != '')
  897. // {
  898. // $uri = key($env['GET']);
  899. // }
  900. else
  901. {
  902. $app_file = app_file();
  903. $path_info = isset($env['SERVER']['PATH_INFO']) ? $env['SERVER']['PATH_INFO'] : @getenv('PATH_INFO');
  904. $query_string = isset($env['SERVER']['QUERY_STRING']) ? $env['SERVER']['QUERY_STRING'] : @getenv('QUERY_STRING');
  905. // Is there a PATH_INFO variable?
  906. // Note: some servers seem to have trouble with getenv() so we'll test it two ways
  907. if (trim($path_info, '/') != '' && $path_info != "/".$app_file)
  908. {
  909. if(strpos($path_info, '&') !== 0)
  910. {
  911. # exclude GET params
  912. $params = explode('&', $path_info);
  913. $path_info = array_shift($params);
  914. # populate $_GET
  915. foreach($params as $param)
  916. {
  917. if(strpos($param, '=') > 0)
  918. {
  919. list($k, $v) = explode('=', $param);
  920. $env['GET'][$k] = $v;
  921. }
  922. }
  923. }
  924. $uri = $path_info;
  925. }
  926. // No PATH_INFO?... What about QUERY_STRING?
  927. elseif (trim($query_string, '/') != '')
  928. {
  929. $uri = $query_string;
  930. $get = $env['GET'];
  931. if(count($get) > 0)
  932. {
  933. # exclude GET params
  934. $keys = array_keys($get);
  935. $first = array_shift($keys);
  936. if(strpos($query_string, $first) === 0) $uri = $first;
  937. }
  938. }
  939. elseif(array_key_exists('REQUEST_URI', $env['SERVER']) && !empty($env['SERVER']['REQUEST_URI']))
  940. {
  941. $request_uri = rtrim(rawurldecode($env['SERVER']['REQUEST_URI']), '?/').'/';
  942. $base_path = $env['SERVER']['SCRIPT_NAME'];
  943. if($request_uri."index.php" == $base_path) $request_uri .= "index.php";
  944. $uri = str_replace($base_path, '', $request_uri);
  945. }
  946. elseif($env['SERVER']['argc'] > 1 && trim($env['SERVER']['argv'][1], '/') != '')
  947. {
  948. $uri = $env['SERVER']['argv'][1];
  949. }
  950. }
  951. $uri = rtrim($uri, "/"); # removes ending /
  952. if(empty($uri))
  953. {
  954. $uri = '/';
  955. }
  956. else if($uri[0] != '/')
  957. {
  958. $uri = '/' . $uri; # add a leading slash
  959. }
  960. return rawurldecode($uri);
  961. }
  962. # # #
  963. # ============================================================================ #
  964. # 4. ROUTER #
  965. # ============================================================================ #
  966. /**
  967. * An alias of {@link dispatch_get()}
  968. *
  969. * @return void
  970. */
  971. function dispatch($path_or_array, $callback, $options = array())
  972. {
  973. dispatch_get($path_or_array, $callback, $options);
  974. }
  975. /**
  976. * Add a GET route. Also automatically defines a HEAD route.
  977. *
  978. * @param string $path_or_array
  979. * @param string $callback
  980. * @param array $options (optional). See {@link route()} for available options.
  981. * @return void
  982. */
  983. function dispatch_get($path_or_array, $callback, $options = array())
  984. {
  985. route("GET", $path_or_array, $callback, $options);
  986. route("HEAD", $path_or_array, $callback, $options);
  987. }
  988. /**
  989. * Add a POST route
  990. *
  991. * @param string $path_or_array
  992. * @param string $callback
  993. * @param array $options (optional). See {@link route()} for available options.
  994. * @return void
  995. */
  996. function dispatch_post($path_or_array, $callback, $options = array())
  997. {
  998. route("POST", $path_or_array, $callback, $options);
  999. }
  1000. /**
  1001. * Add a PUT route
  1002. *
  1003. * @param string $path_or_array
  1004. * @param string $callback
  1005. * @param array $options (optional). See {@link route()} for available options.
  1006. * @return void
  1007. */
  1008. function dispatch_put($path_or_array, $callback, $options = array())
  1009. {
  1010. route("PUT", $path_or_array, $callback, $options);
  1011. }
  1012. /**
  1013. * Add a DELETE route
  1014. *
  1015. * @param string $path_or_array
  1016. * @param string $callback
  1017. * @param array $options (optional). See {@link route()} for available options.
  1018. * @return void
  1019. */
  1020. function dispatch_delete($path_or_array, $callback, $options = array())
  1021. {
  1022. route("DELETE", $path_or_array, $callback, $options);
  1023. }
  1024. /**
  1025. * Add route if required params are provided.
  1026. * Delete all routes if null is passed as a unique argument
  1027. * Return all routes
  1028. *
  1029. * @see route_build()
  1030. * @access private
  1031. * @param string $method
  1032. * @param string|array $path_or_array
  1033. * @param callback $func
  1034. * @param array $options (optional). Available options:
  1035. * - 'params' key with an array of parameters: for parametrized routes.
  1036. * those parameters will be merged with routes parameters.
  1037. * @return array
  1038. */
  1039. function route()
  1040. {
  1041. static $routes = array();
  1042. $nargs = func_num_args();
  1043. if( $nargs > 0)
  1044. {
  1045. $args = func_get_args();
  1046. if($nargs === 1 && is_null($args[0])) $routes = array();
  1047. else if($nargs < 3) trigger_error("Missing arguments for route()", E_USER_ERROR);
  1048. else
  1049. {
  1050. $method = $args[0];
  1051. $path_or_array = $args[1];
  1052. $func = $args[2];
  1053. $options = $nargs > 3 ? $args[3] : array();
  1054. $routes[] = route_build($method, $path_or_array, $func, $options);
  1055. }
  1056. }
  1057. return $routes;
  1058. }
  1059. /**
  1060. * An alias of route(null): reset all routes
  1061. *
  1062. * @access private
  1063. * @return void
  1064. */
  1065. function route_reset()
  1066. {
  1067. route(null);
  1068. }
  1069. /**
  1070. * Build a route and return it
  1071. *
  1072. * @access private
  1073. * @param string $method allowed http method (one of those returned by {@link request_methods()})
  1074. * @param string|array $path_or_array
  1075. * @param callback $callback callback called when route is found. It can be
  1076. * a function, an object method, a static method or a closure.
  1077. * See {@link http://php.net/manual/en/language.pseudo-types.php#language.types.callback php documentation}
  1078. * to learn more about callbacks.
  1079. * @param array $options (optional). Available options:
  1080. * - 'params' key with an array of parameters: for parametrized routes.
  1081. * those parameters will be merged with routes parameters.
  1082. * @return array array with keys "method", "pattern", "names", "callback", "options"
  1083. */
  1084. function route_build($method, $path_or_array, $callback, $options = array())
  1085. {
  1086. $method = strtoupper($method);
  1087. if(!in_array($method, request_methods()))
  1088. trigger_error("'$method' request method is unkown or unavailable.", E_USER_WARNING);
  1089. if(is_array($path_or_array))
  1090. {
  1091. $path = array_shift($path_or_array);
  1092. $names = $path_or_array[0];
  1093. }
  1094. else
  1095. {
  1096. $path = $path_or_array;
  1097. $names = array();
  1098. }
  1099. $single_asterisk_subpattern = "(?:/([^\/]*))?";
  1100. $double_asterisk_subpattern = "(?:/(.*))?";
  1101. $optionnal_slash_subpattern = "(?:/*?)";
  1102. $no_slash_asterisk_subpattern = "(?:([^\/]*))?";
  1103. if($path[0] == "^")
  1104. {
  1105. if($path{strlen($path) - 1} != "$") $path .= "$";
  1106. $pattern = "#".$path."#i";
  1107. }
  1108. else if(empty($path) || $path == "/")
  1109. {
  1110. $pattern = "#^".$optionnal_slash_subpattern."$#";
  1111. }
  1112. else
  1113. {
  1114. $parsed = array();
  1115. $elts = explode('/', $path);
  1116. $parameters_count = 0;
  1117. foreach($elts as $elt)
  1118. {
  1119. if(empty($elt)) continue;
  1120. $name = null;
  1121. # extracting double asterisk **
  1122. if($elt == "**"):
  1123. $parsed[] = $double_asterisk_subpattern;
  1124. $name = $parameters_count;
  1125. # extracting single asterisk *
  1126. elseif($elt == "*"):
  1127. $parsed[] = $single_asterisk_subpattern;
  1128. $name = $parameters_count;
  1129. # extracting named parameters :my_param
  1130. elseif($elt[0] == ":"):
  1131. if(preg_match('/^:([^\:]+)$/', $elt, $matches))
  1132. {
  1133. $parsed[] = $single_asterisk_subpattern;
  1134. $name = $matches[1];
  1135. };
  1136. elseif(strpos($elt, '*') !== false):
  1137. $sub_elts = explode('*', $elt);
  1138. $parsed_sub = array();
  1139. foreach($sub_elts as $sub_elt)
  1140. {
  1141. $parsed_sub[] = preg_quote($sub_elt, "#");
  1142. $name = $parameters_count;
  1143. }
  1144. //
  1145. $parsed[] = "/".implode($no_slash_asterisk_subpattern, $parsed_sub);
  1146. else:
  1147. $parsed[] = "/".preg_quote($elt, "#");
  1148. endif;
  1149. /* set parameters names */
  1150. if(is_null($name)) continue;
  1151. if(!array_key_exists($parameters_count, $names) || is_null($names[$parameters_count]))
  1152. $names[$parameters_count] = $name;
  1153. $parameters_count++;
  1154. }
  1155. $pattern = "#^".implode('', $parsed).$optionnal_slash_subpattern."?$#i";
  1156. }
  1157. return array( "method" => $method,
  1158. "pattern" => $pattern,
  1159. "names" => $names,
  1160. "callback" => $callback,
  1161. "options" => $options );
  1162. }
  1163. /**
  1164. * Find a route and returns it.
  1165. * Parameters values extracted from the path are added and merged
  1166. * with the default 'params' option of the route
  1167. * If not found, returns false.
  1168. * Routes are checked from first added to last added.
  1169. *
  1170. * @access private
  1171. * @param string $method
  1172. * @param string $path
  1173. * @return array,false route array has same keys as route returned by
  1174. * {@link route_build()} ("method", "pattern", "names", "callback", "options")
  1175. * + the processed "params" key
  1176. */
  1177. function route_find($method, $path)
  1178. {
  1179. $routes = route();
  1180. $method = strtoupper($method);
  1181. foreach($routes as $route)
  1182. {
  1183. if($method == $route["method"] && preg_match($route["pattern"], $path, $matches))
  1184. {
  1185. $options = $route["options"];
  1186. $params = array_key_exists('params', $options) ? $options["params"] : array();
  1187. if(count($matches) > 1)
  1188. {
  1189. array_shift($matches);
  1190. $n_matches = count($matches);
  1191. $names = array_values($route["names"]);
  1192. $n_names = count($names);
  1193. if( $n_matches < $n_names )
  1194. {
  1195. $a = array_fill(0, $n_names - $n_matches, null);
  1196. $matches = array_merge($matches, $a);
  1197. }
  1198. else if( $n_matches > $n_names )
  1199. {
  1200. $names = range($n_names, $n_matches - 1);
  1201. }
  1202. $arr_comb = array_combine($names, $matches);
  1203. $params = array_replace($params, $arr_comb);
  1204. }
  1205. $route["params"] = $params;
  1206. return $route;
  1207. }
  1208. }
  1209. return false;
  1210. }
  1211. # ============================================================================ #
  1212. # 5. OUTPUT AND RENDERING #
  1213. # ============================================================================ #
  1214. /**
  1215. * Returns a string to output
  1216. *
  1217. * It might use a template file, a function, or a formatted string (like {@link sprintf()}).
  1218. * It could be embraced by a layout or not.
  1219. * Local vars can be passed in addition to variables made available with the {@link set()}
  1220. * function.
  1221. *
  1222. * @param string $content_or_func
  1223. * @param string $layout
  1224. * @param string $locals
  1225. * @return string
  1226. */
  1227. function render($content_or_func, $layout = '', $locals = array())
  1228. {
  1229. $args = func_get_args();
  1230. $content_or_func = array_shift($args);
  1231. $layout = count($args) > 0 ? array_shift($args) : layout();
  1232. $view_path = file_path(option('views_dir'),$content_or_func);
  1233. if(function_exists('before_render'))
  1234. list($content_or_func, $layout, $locals, $view_path) = before_render($content_or_func, $layout, $locals, $view_path);
  1235. $vars = array_merge(set(), $locals);
  1236. $flash = flash_now();
  1237. if(array_key_exists('flash', $vars)) trigger_error('A $flash variable is already passed to view. Flash messages will only be accessible through flash_now()', E_USER_NOTICE);
  1238. else if(!empty($flash)) $vars['flash'] = $flash;
  1239. $infinite_loop = false;
  1240. # Avoid infinite loop: this function is in the backtrace ?
  1241. if(function_exists($content_or_func))
  1242. {
  1243. $back_trace = debug_backtrace();
  1244. while($trace = array_shift($back_trace))
  1245. {
  1246. if($trace['function'] == strtolower($content_or_func))
  1247. {
  1248. $infinite_loop = true;
  1249. break;
  1250. }
  1251. }
  1252. }
  1253. if(function_exists($content_or_func) && !$infinite_loop)
  1254. {
  1255. ob_start();
  1256. call_user_func($content_or_func, $vars);
  1257. $content = ob_get_clean();
  1258. }
  1259. elseif(file_exists($view_path))
  1260. {
  1261. ob_start();
  1262. extract($vars);
  1263. include $view_path;
  1264. $content = ob_get_clean();
  1265. }
  1266. else
  1267. {
  1268. if(substr_count($content_or_func, '%') !== count($vars)) $content = $content_or_func;
  1269. else $content = vsprintf($content_or_func, $vars);
  1270. }
  1271. if(empty($layout)) return $content;
  1272. return render($layout, null, array('content' => $content));
  1273. }
  1274. /**
  1275. * Returns a string to output
  1276. *
  1277. * Shortcut to render with no layout.
  1278. *
  1279. * @param string $content_or_func
  1280. * @param string $locals
  1281. * @return string
  1282. */
  1283. function partial($content_or_func, $locals = array())
  1284. {
  1285. return render($content_or_func, null, $locals);
  1286. }
  1287. /**
  1288. * Returns html output with proper http headers
  1289. *
  1290. * @param string $content_or_func
  1291. * @param string $layout
  1292. * @param string $locals
  1293. * @return string
  1294. */
  1295. function html($content_or_func, $layout = '', $locals = array())
  1296. {
  1297. send_header('Content-Type: text/html; charset='.strtolower(option('encoding')));
  1298. $args = func_get_args();
  1299. return call_user_func_array('render', $args);
  1300. }
  1301. /**
  1302. * Set and return current layout
  1303. *
  1304. * @param string $function_or_file
  1305. * @return string
  1306. */
  1307. function layout($function_or_file = null)
  1308. {
  1309. static $layout = null;
  1310. if(func_num_args() > 0) $layout = $function_or_file;
  1311. return $layout;
  1312. }
  1313. /**
  1314. * Returns xml output with proper http headers
  1315. *
  1316. * @param string $content_or_func
  1317. * @param string $layout
  1318. * @param string $locals
  1319. * @return string
  1320. */
  1321. function xml($data)
  1322. {
  1323. send_header('Content-Type: text/xml; charset='.strtolower(option('encoding')));
  1324. $args = func_get_args();
  1325. return call_user_func_array('render', $args);
  1326. }
  1327. /**
  1328. * Returns css output with proper http headers
  1329. *
  1330. * @param string $content_or_func
  1331. * @param string $layout
  1332. * @param string $locals
  1333. * @return string
  1334. */
  1335. function css($content_or_func, $layout = '', $locals = array())
  1336. {
  1337. send_header('Content-Type: text/css; charset='.strtolower(option('encoding')));
  1338. $args = func_get_args();
  1339. return call_user_func_array('render', $args);
  1340. }
  1341. /**
  1342. * Returns javacript output with proper http headers
  1343. *
  1344. * @param string $content_or_func
  1345. * @param string $layout
  1346. * @param string $locals
  1347. * @return string
  1348. */
  1349. function js($content_or_func, $layout = '', $locals = array())
  1350. {
  1351. send_header('Content-Type: application/javascript; charset='.strtolower(option('encoding')));
  1352. $args = func_get_args();
  1353. return call_user_func_array('render', $args);
  1354. }
  1355. /**
  1356. * Returns txt output with proper http headers
  1357. *
  1358. * @param string $content_or_func
  1359. * @param string $layout
  1360. * @param string $locals
  1361. * @return string
  1362. */
  1363. function txt($content_or_func, $layout = '', $locals = array())
  1364. {
  1365. send_header('Content-Type: text/plain; charset='.strtolower(option('encoding')));
  1366. $args = func_get_args();
  1367. return call_user_func_array('render', $args);
  1368. }
  1369. /**
  1370. * Returns json representation of data with proper http headers.
  1371. * On PHP 5 < PHP 5.2.0, you must provide your own implementation of the
  1372. * <code>json_encode()</code> function beore using <code>json()</code>.
  1373. *
  1374. * @param string $data
  1375. * @param int $json_option
  1376. * @return string
  1377. */
  1378. function json($data, $json_option = 0)
  1379. {
  1380. send_header('Content-Type: application/json; charset='.strtolower(option('encoding')));
  1381. return version_compare(PHP_VERSION, '5.3.0', '>=') ? json_encode($data, $json_option) : json_encode($data);
  1382. }
  1383. /**
  1384. * undocumented function
  1385. *
  1386. * @param string $filename
  1387. * @param string $return
  1388. * @return mixed number of bytes delivered or file output if $return = true
  1389. */
  1390. function render_file($filename, $return = false)
  1391. {
  1392. # TODO implements X-SENDFILE headers
  1393. // if($x-sendfile = option('x-sendfile'))
  1394. // {
  1395. // // add a X-Sendfile header for apache and Lighttpd >= 1.5
  1396. // if($x-sendfile > X-SENDFILE) // add a X-LIGHTTPD-send-file header
  1397. //
  1398. // }
  1399. // else
  1400. // {
  1401. //
  1402. // }
  1403. $filename = str_replace('../', '', $filename);
  1404. if(file_exists($filename))
  1405. {
  1406. $content_type = mime_type(file_extension($filename));
  1407. $header = 'Content-type: '.$content_type;
  1408. if(file_is_text($filename)) $header .= '; charset='.strtolower(option('encoding'));
  1409. send_header($header);
  1410. return file_read($filename, $return);
  1411. }
  1412. else halt(NOT_FOUND, "unknown filename $filename");
  1413. }
  1414. /**
  1415. * Call before_sending_header() if it exists, then send headers
  1416. *
  1417. * @param string $header
  1418. * @return void
  1419. */
  1420. function send_header($header = null, $replace = true, $code = false)
  1421. {
  1422. if(!headers_sent())
  1423. {
  1424. call_if_exists('before_sending_header', $header);
  1425. header($header, $replace, $code);
  1426. }
  1427. }
  1428. # # #
  1429. # ============================================================================ #
  1430. # 6. HELPERS #
  1431. # ============================================================================ #
  1432. /**
  1433. * Returns an url composed of params joined with /
  1434. * A param can be a string or an array.
  1435. * If param is an array, its members will be added at the end of the return url
  1436. * as GET parameters "&key=value".
  1437. *
  1438. * @param string or array $param1, $param2 ...
  1439. * @return string
  1440. */
  1441. function url_for($params = null)
  1442. {
  1443. $paths = array();
  1444. $params = func_get_args();
  1445. $GET_params = array();
  1446. foreach($params as $param)
  1447. {
  1448. if(is_array($param))
  1449. {
  1450. $GET_params = array_merge($GET_params, $param);
  1451. continue;
  1452. }
  1453. if(filter_var_url($param))
  1454. {
  1455. $paths[] = $param;
  1456. continue;
  1457. }
  1458. $p = explode('/',$param);
  1459. foreach($p as $v)
  1460. {
  1461. if($v != "") $paths[] = str_replace('%23', '#', rawurlencode($v));
  1462. }
  1463. }
  1464. $path = rtrim(implode('/', $paths), '/');
  1465. if(!filter_var_url($path))
  1466. {
  1467. # it's a relative URL or an URL without a schema
  1468. $base_uri = option('base_uri');
  1469. $path = file_path($base_uri, $path);
  1470. }
  1471. if(!empty($GET_params))
  1472. {
  1473. $is_first_qs_param = true;
  1474. $path_as_no_question_mark = strpos($path, '?') === false;
  1475. foreach($GET_params as $k => $v)
  1476. {
  1477. $qs_separator = $is_first_qs_param && $path_as_no_question_mark ?
  1478. '?' : '&amp;';
  1479. $path .= $qs_separator . rawurlencode($k) . '=' . rawurlencode($v);
  1480. $is_first_qs_param = false;
  1481. }
  1482. }
  1483. if(DIRECTORY_SEPARATOR != '/') $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
  1484. return $path;
  1485. }
  1486. /**
  1487. * An alias of {@link htmlspecialchars()}.
  1488. * If no $charset is provided, uses option('encoding') value
  1489. *
  1490. * @param string $str
  1491. * @param string $quote_style
  1492. * @param string $charset
  1493. * @return void
  1494. */
  1495. function h($str, $quote_style = ENT_NOQUOTES, $charset = null)
  1496. {
  1497. if(is_null($charset)) $charset = strtoupper(option('encoding'));
  1498. return htmlspecialchars($str, $quote_style, $charset);
  1499. }
  1500. /**
  1501. * Set and returns flash messages that will be available in the next action
  1502. * via the {@link flash_now()} function or the view variable <code>$flash</code>.
  1503. *
  1504. * If multiple values are provided, set <code>$name</code> variable with an array of those values.
  1505. * If there is only one value, set <code>$name</code> variable with the provided $values
  1506. * or if it's <code>$name</code> is an array, merge it with current messages.
  1507. *
  1508. * @param string, array $name
  1509. * @param mixed $values,...
  1510. * @return mixed variable value for $name if $name argument is provided, else return all variables
  1511. */
  1512. function flash($name = null, $value = null)
  1513. {
  1514. if(!defined('SID')) trigger_error("Flash messages can't be used because session isn't enabled", E_USER_WARNING);
  1515. static $messages = array();
  1516. $args = func_get_args();
  1517. $name = array_shift($args);
  1518. if(is_null($name)) return $messages;
  1519. if(is_array($name)) return $messages = array_merge($messages, $name);
  1520. if(!empty($args))
  1521. {
  1522. $messages[$name] = count($args) > 1 ? $args : $args[0];
  1523. }
  1524. if(!array_key_exists($name, $messages)) return null;
  1525. else return $messages[$name];
  1526. return $messages;
  1527. }
  1528. /**
  1529. * Set and returns flash messages available for the current action, included those
  1530. * defined in the previous action with {@link flash()}
  1531. * Those messages will also be passed to the views and made available in the
  1532. * <code>$flash</code> variable.
  1533. *
  1534. * If multiple values are provided, set <code>$name</code> variable with an array of those values.
  1535. * If there is only one value, set <code>$name</code> variable with the provided $values
  1536. * or if it's <code>$name</code> is an array, merge it with current messages.
  1537. *
  1538. * @param string, array $name
  1539. * @param mixed $values,...
  1540. * @return mixed variable value for $name if $name argument is provided, else return all variables
  1541. */
  1542. function flash_now($name = null, $value = null)
  1543. {
  1544. static $messages = null;
  1545. if(is_null($messages))
  1546. {
  1547. $fkey = LIM_SESSION_FLASH_KEY;
  1548. $messages = array();
  1549. if(defined('SID') && array_key_exists($fkey, $_SESSION)) $messages = $_SESSION[$fkey];
  1550. }
  1551. $args = func_get_args();
  1552. $name = array_shift($args);
  1553. if(is_null($name)) return $messages;
  1554. if(is_array($name)) return $messages = array_merge($messages, $name);
  1555. if(!empty($args))
  1556. {
  1557. $messages[$name] = count($args) > 1 ? $args : $args[0];
  1558. }
  1559. if(!array_key_exists($name, $messages)) return null;
  1560. else return $messages[$name];
  1561. return $messages;
  1562. }
  1563. /**
  1564. * Delete current flash messages in session, and set new ones stored with
  1565. * flash function.
  1566. * Called before application exit.
  1567. *
  1568. * @access private
  1569. * @return void

Large files files are truncated, but you can click here to view the full file