PageRenderTime 65ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/limonade.php

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

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