PageRenderTime 35ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/limonade.php

http://github.com/sofadesign/limonade-blog-example
PHP | 2289 lines | 1264 code | 231 blank | 794 comment | 206 complexity | 456870fec8c582b9fc2e0710b534f574 MD5 | raw file

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

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