PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/index.php

http://github.com/volomike/Faster
PHP | 1565 lines | 825 code | 126 blank | 614 comment | 126 complexity | 5dfd9d5d1a83f9ac671f6bfaa546b9c0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Faster -- A Minimalist PHP MVC Framework
  4. *
  5. * This is a single file MVC framework, combining bootstrap, framework, and front controller
  6. * into one file.
  7. *
  8. * @package Faster-Framework-API
  9. * @author Volo, LLC
  10. * @link http://volosites.com/
  11. * @version 1.0370
  12. */
  13. // SPEED UP PHP BY TURNING OFF UNNECESSARY ASP TAG PARSING
  14. ini_set('asp_tags','0');
  15. // FIX MAGIC QUOTES IF TURNED ON
  16. if (get_magic_quotes_gpc()) {
  17. $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
  18. while (list($key, $val) = each($process)) {
  19. foreach ($val as $k => $v) {
  20. unset($process[$key][$k]);
  21. if (is_array($v)) {
  22. $process[$key][stripslashes($k)] = $v;
  23. $process[] = &$process[$key][stripslashes($k)];
  24. } else {
  25. $process[$key][stripslashes($k)] = stripslashes($v);
  26. }
  27. }
  28. }
  29. unset($process);
  30. }
  31. // FIXES A PROBLEM WHERE fgets() AND file() MAY NOT READ LINEWRAPS ON MAC OR WINDOWS FILES PROPERLY.
  32. // BSD UNIX AND UNIX AND LINUX ALL USE \n FOR LINE WRAPS.
  33. // MACS, EVEN THOUGH BASED ON BSD UNIX, USES \r FOR LINE WRAPS IN MOST GUI-BASED APPS.
  34. // WINDOWS ABOUT 99% OF THE TIME USES \r\n FOR LINE WRAPS IN FILES.
  35. ini_set('auto_detect_line_endings','1');
  36. // TURN ON SHORT OPEN TAGS
  37. ini_set('short_open_tag','On');
  38. // SET SESSION TIMEOUT
  39. ini_set('session.cookie_lifetime','3600'); //an hour
  40. ini_set('session.gc_maxlifetime','3600');
  41. // SOMETIMES IN VERY RARE CASES WE MAY ARRIVE HERE BY REDIRECT_QUERY STRING.
  42. // IT MESSES UP OUR $_GET AND WE HAVE TO REPAIR IT.
  43. if (isset($_SERVER['REDIRECT_QUERY_STRING'])) {
  44. $_GET = array();
  45. $_SERVER['QUERY_STRING'] = $_SERVER['REDIRECT_QUERY_STRING'];
  46. parse_str(preg_replace('/&(\w+)(&|$)/', '&$1=$2', strtr($_SERVER['QUERY_STRING'], ';', '&')), $_GET);
  47. }
  48. // boot our framework
  49. $mvc = new Faster();
  50. $mvc->core = new Faster_Core();
  51. $mvc->view = new Faster_View();
  52. $mvc->request = new Faster_Request();
  53. $mvc->model = new Faster_Model();
  54. $mvc->data = new Faster_Data();
  55. // Remember, Faster_Core does not inherit from Faster. This is because we want to restrict $this only to
  56. // variables ($this->VARIABLE) and core things like baseurl(), etc.
  57. $mvc->view->core = $mvc->core;
  58. $mvc->view->_setRequest($mvc->request);
  59. // inherits from Faster and therefore gets full $this objects for the framework
  60. $mvc->request->core = $mvc->core;
  61. $mvc->request->view = $mvc->view;
  62. $mvc->request->request = $mvc->request;
  63. $mvc->request->model = $mvc->model;
  64. $mvc->request->data = $mvc->data;
  65. // inherits from Faster and therefore gets full $this objects for the framework
  66. $mvc->model->core = $mvc->core;
  67. $mvc->model->view = $mvc->view;
  68. $mvc->model->request = $mvc->request;
  69. $mvc->model->model = $mvc->model;
  70. $mvc->model->data = $mvc->data;
  71. // does not inherit from Faster because it only needs the core object for pathing reasons
  72. $mvc->data->_setCore($mvc->core);
  73. // set our page timer
  74. $mvc->core->_setPageLoadStart();
  75. // let our request object figure out the incoming URL
  76. $sTest = @ $argv[1];
  77. $bCLI = (!empty($sTest));
  78. if ($bCLI) {
  79. $sPath = $sTest;
  80. $sPath = str_replace('--PATH','',$sPath);
  81. $sPath = str_replace('--path','',$sPath);
  82. $sPath = str_replace('--','',$sPath);
  83. $sPath = str_replace('.php','',$sPath);
  84. $sPath = str_replace('.PHP','',$sPath);
  85. $sPath = str_replace('=','',$sPath);
  86. $sPath = str_replace('"','',$sPath);
  87. $sPath = str_replace("'",'',$sPath);
  88. $sPath = str_replace('\\','/',$sPath);
  89. $sPath = str_replace(' ','',$sPath);
  90. $mvc->request->_setGroup($mvc->request->polishGroup($sPath));
  91. $mvc->request->_setAction($mvc->request->polishAction($sPath));
  92. } else {
  93. $mvc->request->_setGroup($mvc->request->getGroup());
  94. $mvc->request->_setAction($mvc->request->getAction());
  95. }
  96. // SET OUR TIMEZONE STUFF
  97. try {
  98. $sTimeZone = @ $mvc->core->config['TIMEZONE'];
  99. $sTimeZone = (empty($sTimeZone)) ? 'GMT' : $sTimeZone;
  100. if (function_exists('date_default_timezone_set')) {
  101. date_default_timezone_set($sTimeZone);
  102. }
  103. else {
  104. putenv('TZ=' .$sTimeZone);
  105. }
  106. ini_set('date.timezone', $sTimeZone);
  107. } catch(Exception $e) {}
  108. // display errors or log them instead
  109. $sDisplayErrors = @ $mvc->core->config['DISPLAY_ERRORS'];
  110. $sDisplayErrors = (empty($sDisplayErrors)) ? 'Off' : $sDisplayErrors;
  111. ini_set('display_errors',$sDisplayErrors);
  112. // set our error reporting
  113. $sErrReporting = @ $mvc->core->config['ERROR_REPORTING'];
  114. $sErrReporting = (empty($sErrReporting)) ? E_ALL : $sErrReporting;
  115. error_reporting($sErrReporting);
  116. // define our FRAMEWORK_LOADED constant, used by files to keep out prying eyes
  117. /**
  118. * Our constant to identify that the framework has been loaded, and therefore avoid issues with
  119. * prying eyes directly on application folder scripts.
  120. *
  121. */
  122. define('FRAMEWORK_LOADED',TRUE);
  123. $sBase = $mvc->core->base();
  124. /**
  125. * Our constant to provide a quick way to identify a header path.
  126. *
  127. */
  128. define('HEADER',$sBase . '/app/_views/HEADER.php');
  129. /**
  130. * Our constant to provide a quick way to identify a footer path.
  131. *
  132. */
  133. define('FOOTER',$sBase . '/app/_views/FOOTER.php');
  134. // handle our front controller task
  135. $bStopWhenRouted = TRUE;
  136. $mvc->request->dispatchRoute('',$bStopWhenRouted);
  137. /**
  138. * Faster Class
  139. *
  140. * Serves up the entire framework off the $this variable, as in $this->core, $this->request,
  141. * $this->model, and $this->data.
  142. *
  143. * @package Faster-Framework-API
  144. */
  145. class Faster {
  146. /**
  147. * Gets mapped to Faster_Core
  148. */
  149. public $core;
  150. /**
  151. * Gets mapped to Faster_Request; synonym for controller for faster typing
  152. */
  153. public $request;
  154. /**
  155. * Gets mapped to Faster_Model
  156. */
  157. public $model;
  158. /**
  159. * Gets mapped to Faster_View
  160. */
  161. public $view;
  162. /**
  163. * Gets mapped to Faster_Data
  164. */
  165. public $data;
  166. } // end class Faster
  167. /**
  168. * This class handles our controller details and loads our page controllers with the framework
  169. * objects hanging off of the $this object.
  170. *
  171. * @package Faster-Framework-API
  172. */
  173. class Faster_Request extends Faster {
  174. /**
  175. * Private variable storing our group, parsed from the url.
  176. */
  177. private $_request_group;
  178. /**
  179. * Private variable storing our action, parsed from the url.
  180. */
  181. private $_request_action;
  182. /**
  183. * Private variable storing our interpreted params past the group and action parts of the url.
  184. */
  185. private $_params;
  186. /**
  187. * Set the Group. Note that this is public only for when the framework is loaded, but isn't
  188. * meant to be part of the API.
  189. *
  190. * @ignore
  191. * @param string $sGroup Passes in a group portion of the URL when framework is loaded
  192. */
  193. public function _setGroup($sGroup) {
  194. $this->_request_group = $sGroup;
  195. }
  196. /**
  197. * Set the Action. Note that this is public only for when the framework is loaded, but isn't
  198. * meant to be part of the API.
  199. *
  200. * @ignore
  201. * @param string $sAction Passes in an action portion of the URL when framework is loaded
  202. */
  203. public function _setAction($sAction) {
  204. $this->_request_action = $sAction;
  205. }
  206. /**
  207. * Redirect the user's browser to another location. If 404 location, then show a 404 condition.
  208. *
  209. * @param string $sPath Where to redirect the user.
  210. * @param bool $bTemp Defaults to 1; designates whether this is a permanent or temporary redirection.
  211. */
  212. public function redirectRoute($sPath, $bTemp = 1) {
  213. if ($sPath == 404) {
  214. trigger_error('404');
  215. $this->dispatchRoute(404);
  216. exit;
  217. }
  218. $sPath = trim($sPath);
  219. if (($bTemp == 1) and ($sPath != '')) {
  220. header('HTTP/1.1 302 Moved Temporarily');
  221. header("Location: $sPath");
  222. exit;
  223. }
  224. if ($sPath != '') {
  225. header('HTTP/1.1 301 Moved Permanently');
  226. header("Location: $sPath");
  227. exit;
  228. }
  229. }
  230. /**
  231. * Identify whether someone posted a form to the site.
  232. *
  233. * @return bool Whether someone posetd a form to the site via $_POST or $_FILES
  234. */
  235. public function isPosted() {
  236. if ((empty($_POST)) and (empty($_FILES))) {
  237. return FALSE;
  238. }
  239. return TRUE;
  240. }
  241. /**
  242. * Returns a session variable.
  243. *
  244. * @param string $sVar The session variable key
  245. * @return string The session variable value
  246. */
  247. public function getSessionVar($sVar) {
  248. @ session_set_cookie_params(0, '/');
  249. @ session_start();
  250. $sResult = @ $_SESSION[session_id() . '_' . strtoupper($sVar)];
  251. return $sResult;
  252. }
  253. /**
  254. * Sets a session variable.
  255. *
  256. * @param string $sVar The session variable key to set
  257. * @param string $sVal The session variable value to set
  258. */
  259. public function setSessionVar($sVar, $sVal) {
  260. @ session_set_cookie_params(0, '/');
  261. @ session_start();
  262. $_SESSION[session_id() . '_' . strtoupper($sVar)] = $sVal;
  263. }
  264. /**
  265. * Returns the IP address of this user
  266. *
  267. * @return string IP Address
  268. */
  269. public function getIP() {
  270. $sTest = '';
  271. if (isset($_SERVER['HTTP_X_FORWARD_FOR'])) {
  272. $sTest = $_SERVER['HTTP_X_FORWARD_FOR'];
  273. }
  274. if ($sTest) {
  275. $s = $sTest;
  276. } else {
  277. $s = $_SERVER['REMOTE_ADDR'];
  278. }
  279. $s = strip_tags($s);
  280. if (function_exists('filter_var')) {
  281. $s = filter_var($s,FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
  282. }
  283. return $s;
  284. }
  285. /**
  286. * Returns the User Agent string of this user
  287. *
  288. * @return string User Agent string
  289. */
  290. public function getUserAgent() {
  291. $s = $_SERVER['HTTP_USER_AGENT'];
  292. $s = strip_tags($s);
  293. if (function_exists('filter_var')) {
  294. $s = filter_var($s,FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
  295. }
  296. return $s;
  297. }
  298. /**
  299. * Returns the referring page to the current web page.
  300. *
  301. * @return string The referring page
  302. */
  303. public function getReferrer() {
  304. $s = @ $_SERVER['HTTP_REFERER'];
  305. $s = strip_tags($s);
  306. if (function_exists('filter_var')) {
  307. $s = filter_var($s,FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
  308. }
  309. return $s;
  310. }
  311. /**
  312. * Another version of getReferrer, in case misspelled
  313. *
  314. * @return string The referring page
  315. */
  316. public function getReferer() {
  317. return $this->getReferrer();
  318. }
  319. /**
  320. * Returns the actual base file path of the site
  321. *
  322. * @return string Base file path
  323. */
  324. public function getPath(){
  325. $sPath = str_replace('index.php','',$_SERVER['SCRIPT_NAME']);
  326. $s = @ $_SERVER['REQUEST_URI'];
  327. $sTest = substr($s, 0, strlen($sPath));
  328. if ($sTest == $sPath) {
  329. $s = substr($s, strlen($sPath));
  330. }
  331. if (empty($s)) {
  332. $s = dirname(__FILE__);
  333. }
  334. return $s;
  335. }
  336. /**
  337. * Converts the Group (aka "controller") portion of the URL from dashes into the form that is
  338. * used by this framework in its ProperCase format.
  339. *
  340. * @param string $s The path. This is parsed from getPath() unless a URL is passed to it.
  341. * @return string Group portion of the URL
  342. */
  343. public function polishGroup($s) {
  344. $s = ltrim($s, '/');
  345. $s = rtrim($s, '/');
  346. $s = str_replace('-',' ',$s);
  347. $s = ucwords(strtolower($s));
  348. $s = str_replace(' ','',$s);
  349. $s = strrev($s);
  350. $s = basename($s);
  351. $s = strrev($s);
  352. return $s;
  353. }
  354. /**
  355. * Converts the Action portion of the URL from dashes into the form that is
  356. * used by this framework in its ProperCase format.
  357. *
  358. * @param string $s The path. This is parsed from getPath() unless a URL is passed to it.
  359. * @return string Action portion of the URL
  360. */
  361. public function polishAction($s){
  362. $s = ltrim($s, '/');
  363. $s = rtrim($s, '/');
  364. $s = str_replace('-',' ',$s);
  365. $s = ucwords(strtolower($s));
  366. $s = str_replace(' ','',$s);
  367. if (strpos(' ' . $s,'/') === FALSE) {
  368. $s = (empty($s)) ? 'Default' : $s;
  369. return $s;
  370. }
  371. $asParts = explode('/',$s);
  372. $s = @ $asParts[1];
  373. $s = ucfirst($s);
  374. $s = (empty($s)) ? 'Default' : $s;
  375. if (substr($s,-4) == '.php') {
  376. $s = str_replace('.php','',$s);
  377. }
  378. return $s;
  379. }
  380. /**
  381. * Returns a guess of a group from the URL, which comes right after the base URL.
  382. * It is not entirely accurate and cannot be trusted yet because the value may be a parameter,
  383. * instead. Therefore, this routine is used by another class method, which is why it is marked
  384. * private and not meant for the outside world.
  385. *
  386. * @return string Guessed group parameter of the URL
  387. */
  388. private function _getGuessGroup(){
  389. $s = $this->getPath();
  390. return $this->polishGroup($s);
  391. }
  392. /**
  393. * Returns a guess of the action part of the URL, which comes right after the detected group
  394. * parameter. It is not entirel yaccurate and cannot be trusted yet because the value may be
  395. * a parameter, instead. Therefore, this routine is used by another class method, which is why
  396. * it is marked private and not meant for the outside world.
  397. *
  398. * @return string Guessed action parameter of the URL
  399. */
  400. private function _getGuessAction(){
  401. $s = $this->getPath();
  402. return $this->polishAction($s);
  403. }
  404. /**
  405. * Returns the actual group paramter of the URL, which comes right after the base part of the
  406. * URL. Has been checked to see if this location exists with the controllers.
  407. *
  408. * @return string Actual group parameter of the URL.
  409. */
  410. public function getGroup(){
  411. if (isset($this->_request_group)) {
  412. return $this->_request_group;
  413. }
  414. $sGGroup = $this->_getGuessGroup();
  415. $sGAction = $this->_getGuessAction();
  416. $F = $this->core->base();
  417. $sTestPath1 = $F . '/app/_controllers/' . $sGGroup . '/c' . $sGAction . '.php';
  418. $sTestPath2 = $F . '/app/_controllers/' . $sGGroup . '/cDefault.php';
  419. if ((file_exists($sTestPath1)) or (file_exists($sTestPath2))) {
  420. $this->_request_group = $sGGroup;
  421. return $sGGroup;
  422. }
  423. $this->_request_group = 'Default';
  424. return 'Default';
  425. }
  426. /**
  427. * Returns the actual action paramter of the URL, which comes right after the group part of the
  428. * URL. Has been checked to see if this location exists with the controllers.
  429. *
  430. * @return string Actual action parameter of the URL.
  431. */
  432. public function getAction(){
  433. if (isset($this->_request_action)) {
  434. return $this->_request_action;
  435. }
  436. $sGGroup = $this->_getGuessGroup();
  437. $sGAction = $this->_getGuessAction();
  438. $F = $this->core->base();
  439. $sTestPath1 = $F . '/app/_controllers/' . $sGGroup . '/c' . $sGAction . '.php';
  440. $sTestPath2 = $F . '/app/_controllers/' . $sGGroup . '/cDefault.php';
  441. if ((file_exists($sTestPath1)) or (file_exists($sTestPath2))) {
  442. if (file_exists($sTestPath1)) {
  443. $this->_request_action = $sGAction;
  444. return $sGAction;
  445. } else {
  446. $this->_request_action = 'Default';
  447. return 'Default';
  448. }
  449. }
  450. $this->_request_action = 'Default';
  451. return 'Default';
  452. }
  453. public function getParam($nIndex) {
  454. $asParams = $this->getParams();
  455. $sVal = @ $asParams[$nIndex];
  456. return $sVal;
  457. }
  458. /**
  459. * Returns the parameters of the URL that come after the group and action. Has been checked
  460. * to prove that these parameters are not part of the controller path.
  461. *
  462. * @return array An Array of string parameters of the URL, if present, beyond the action parameter of the URL.
  463. */
  464. public function getParams(){
  465. if (isset($this->_params)) {
  466. return $this->_params;
  467. }
  468. global $argv;
  469. $sTest = @ $argv[1];
  470. $bCLI = (!empty($sTest));
  471. if ($bCLI) {
  472. $asParams = $argv;
  473. array_shift($asParams);
  474. array_shift($asParams);
  475. foreach($asParams as $sKey => $sVal) {
  476. if (substr($sVal, 0, 2) == '--') {
  477. $sVal = preg_replace('/^--/','',$sVal);
  478. $asParams[$sKey] = $sVal;
  479. }
  480. if ((substr($sVal, 0, 1) == '"') and (substr($sVal, -1, 1) == '"')) {
  481. $sVal = ltrim($sVal, '"');
  482. $sVal = rtrim($sVal, '"');
  483. $asParams[$sKey] = $sVal;
  484. } else if ((substr($sVal, 0, 1) == "'") and (substr($sVal, -1, 1) == "'")) {
  485. $sVal = ltrim($sVal, "'");
  486. $sVal = rtrim($sVal, "'");
  487. $asParams[$sKey] = $sVal;
  488. }
  489. }
  490. $this->_params = $asParams;
  491. return $asParams;
  492. }
  493. $F = $this->core->base();
  494. $sGroup = $this->getGroup();
  495. $sAction = $this->getAction();
  496. $s = $this->getPath();
  497. if (strpos(' ' . $s, '?') > 0) {
  498. $nPos = strpos($s, '?');
  499. $s = substr($s, 0, $nPos);
  500. }
  501. $s = ltrim($s, '/');
  502. $s = rtrim($s, '/');
  503. $asParts = explode('/', $s);
  504. $sPossibleGroup = @ $asParts[0];
  505. $sPossibleAction = @ $asParts[1];
  506. $sPossibleGroup = str_replace('-',' ',$sPossibleGroup);
  507. $sPossibleGroup = ucwords(strtolower($sPossibleGroup));
  508. $sPossibleGroup = str_replace(' ','',$sPossibleGroup);
  509. $sPossibleGroup = ucfirst($sPossibleGroup);
  510. $sPossibleAction = str_replace('-',' ',$sPossibleAction);
  511. $sPossibleAction = ucwords(strtolower($sPossibleAction));
  512. $sPossibleAction = str_replace(' ','',$sPossibleAction);
  513. $sPossisPossibleActionbleGroup = ucfirst($sPossibleAction);
  514. if (file_exists($F . '/app/_controllers/' . $sPossibleGroup)) {
  515. array_shift($asParts);
  516. }
  517. if (file_exists($F . '/app/_controllers/' . $sPossibleGroup . '/c' . $sPossibleAction . '.php')) {
  518. array_shift($asParts);
  519. }
  520. if ($sAction == 'Default') {
  521. $sScript = @ $_SERVER['SCRIPT_NAME'];
  522. $sRequest = @ $_SERVER['REQUEST_URI'];
  523. $sScript = str_replace('/index.php','',$sScript);
  524. $sRequest = str_replace($sScript,'',$sRequest);
  525. $sRequest .= '?';
  526. $asParts = explode('?',$sRequest);
  527. $sRequest = $asParts[0];
  528. $sRequest = ltrim($sRequest, '/');
  529. $sRequest = rtrim($sRequest,'/');
  530. if (strlen($sRequest) == 0) {
  531. return array();
  532. }
  533. $asParts = explode('/',$sRequest);
  534. if ($sGroup != 'Default') {
  535. array_shift($asParts);
  536. }
  537. }
  538. $this->_params = $asParts;
  539. return $asParts;
  540. }
  541. /**
  542. * Returns the $_GET -- added to keep the framework consistent.
  543. *
  544. * @return array The $_GET parameters
  545. */
  546. public function getVars(){
  547. foreach($_GET as $sKey => $sVal){
  548. $sVal = urldecode($sVal);
  549. $_GET[$sKey] = trim($sVal);
  550. }
  551. return $_GET;
  552. }
  553. /**
  554. * Returns the $_POST -- added to keep the framework consistent.
  555. *
  556. * @return array The $_POST parameters
  557. */
  558. public function getPostedVars(){
  559. foreach($_POST as $sKey => $sVal){
  560. $_POST[$sKey] = trim($sVal);
  561. }
  562. return $_POST;
  563. }
  564. /**
  565. * Returns the $_SERVER -- added to keep the framework consistent.
  566. *
  567. * @return array The $_SERVER parameters
  568. */
  569. public function getServerVars(){
  570. return $_SERVER;
  571. }
  572. /**
  573. * Returns the $_GET by key param
  574. *
  575. * @param string $sKey The key
  576. * @param boolean $bStripTags Whether to apply strip_tags(). Defaults to TRUE.
  577. * @return string The value
  578. */
  579. public function getVar($sKey, $bStripTags = TRUE){
  580. $sVal = @ $_GET[$sKey];
  581. if ($bStripTags) {
  582. $sVal = strip_tags($sVal);
  583. }
  584. $sVal = urldecode($sVal);
  585. $sVal = trim($sVal);
  586. return $sVal;
  587. }
  588. /**
  589. * Returns the $_POST by key param
  590. *
  591. * @param string $sKey The key
  592. * @param boolean $bStripTags Whether to apply strip_tags(). Defaults to TRUE.
  593. * @return string The value
  594. */
  595. public function getPostedVar($sKey, $bStripTags = TRUE){
  596. $sVal = @ $_POST[$sKey];
  597. if ($bStripTags) {
  598. $sVal = strip_tags($sVal);
  599. }
  600. $sVal = trim($sVal);
  601. return $sVal;
  602. }
  603. /**
  604. * Returns the $_SERVER by key param
  605. *
  606. * @param string $sKey The key
  607. * @return string The value
  608. */
  609. public function getServerVar($sKey){
  610. $sVal = @ $_SERVER[$sKey];
  611. return $sVal;
  612. }
  613. /**
  614. * Block the Default page controller Default/cDefault.php from being able to process
  615. * ending URL parameters, and send them to 404 pages instead.
  616. *
  617. * Drop a call to this in app/_controllers/Default/cDefault.php at the top and it will
  618. * give you 404 pages. This gives you better debugging if you're actually wanting 404.
  619. *
  620. */
  621. public function blockDefaultURLParams(){
  622. $sScript = @ $_SERVER['SCRIPT_NAME'];
  623. $sRequest = @ $_SERVER['REQUEST_URI'];
  624. $sScript = str_replace('/index.php','',$sScript);
  625. $sRequest = str_replace($sScript,'',$sRequest);
  626. if (strpos(' ' . $sRequest,'?')>0) {
  627. $asParts = explode('?',$sRequest);
  628. $sRequest = $asParts[0];
  629. }
  630. if ($sRequest != '/') {
  631. $this->request->redirectRoute(404);
  632. }
  633. }
  634. /**
  635. * Looks at the incoming URL, or the $sWhichController variable, and routes the site workflow
  636. * to that controller. Can also be used for 404 handling. As well, can also be used to dispatch
  637. * a route but not stop (exit(0)) when done. An example of possible URLs and their routing are:
  638. *
  639. * <code>
  640. * http://example.com/ = app/_controllers/Default/cDefault.php
  641. * http://example.com/my-blog-post = app/_controllers/Default/cDefault.php
  642. * http://example.com/articles/my-blog-post = app/_controllers/Articles/cDefault.php
  643. * http://example.com/membership-system/get-user = app/_controllers/MembershipSystem/cGetUser.php
  644. * http://example.com/members/get-user/400 = app/_controllers/Members/cGetUser.php
  645. * http://example.com/members/get-user/400/500 = app/_controllers/Members/cGetUser.php
  646. * </code>
  647. *
  648. * Therefore, the typical URL is either in the format:
  649. *
  650. * <code>
  651. * http://example.com/
  652. * http://example.com/{PARAMETER 1..n}
  653. * http://example.com/{GROUP}/{PARAMETER 1...n}
  654. * http://example.com/{GROUP}/{ACTION}
  655. * http://example.com/{GROUP}/{ACTION}/{PARAMETER 1...n}
  656. * </code>
  657. *
  658. * The Default controller group is a folder called Default.
  659. * The Default controller action is a file called cDefault.php.
  660. * The actual controller file begins with a 'c' prefix because it helps us in tabbed text editors
  661. * so as not to confuse these with models or views.
  662. * All dashes in the group and action slots cause the group or action to be ProperCased with
  663. * dashes removed, but this is not applied to the parameters that follow that.
  664. * It is possible to have a group like Articles, but then map to cDefault.php for action in order to
  665. * absorb the parameters that may follow.
  666. * When nothing comes after the base of the site, like http://example.com/, the site defaults to
  667. * using the controller path app/_controllers/Default/cDefault.php
  668. *
  669. * Note underscores in variables in this function are so that the controller doesn't inherit
  670. * variables. (I mean, it does, but it would have to use underscore vars.) This is actually a
  671. * failsafe in case this function gets edited. We will do unset() on all variables possible.
  672. *
  673. * Note also an alternative action path. Instead of cDefault.php, you can name it the same as the
  674. * group path. So, if you have /about for the URL, then you could use About/cAbout.php for the
  675. * controller path. This helps when working with multiple files at once in a text editor, where
  676. * you won't confuse all the cDefault.php files together.
  677. *
  678. * @param string $_sWhichController By default, the front controller leaves this empty and therefore
  679. * parses the URL for that value. However, this can be overridden. Pass a value of 404 here and the
  680. * framework will try to send 404 headers and try to load either a 404.php or 404.html file, if found
  681. * or merely stop with the 404 headers.
  682. * @param string $_bStopWhenRouted By default, the front controller stops code execution after the
  683. * routing, which means it runs through the controller code and then stops. However, this can be
  684. * overridden.
  685. */
  686. public function dispatchRoute($_sWhichController = '', $_bStopWhenRouted = TRUE){
  687. $_F = $this->core->base();
  688. if ($_sWhichController == 404) {
  689. if (!headers_sent()) {
  690. header('HTTP/1.1 404 Not Found');
  691. header('Status: 404 Not Found');
  692. }
  693. if (file_exists($_F . '/404.php')) {
  694. unset($_sWhichController);
  695. unset($_bStopWhenRouted);
  696. require_once($_F . '/404.php');
  697. } else {
  698. @ include($_F . '/404.html');
  699. }
  700. die();
  701. }
  702. if (empty($_sWhichController)) {
  703. $_sGroup = $this->getGroup();
  704. $_sAction = $this->getAction();
  705. if (!file_exists($_F . '/app/_controllers')) {
  706. trigger_error('Your folder layout is missing a app/_controllers folder', E_USER_ERROR);
  707. }
  708. if (!file_exists($_F . '/app/_controllers/Default')) {
  709. trigger_error('Your folder layout is missing a app/_controllers/Default controller folder', E_USER_ERROR);
  710. }
  711. if (!file_exists($_F . '/app/_controllers/Default/cDefault.php')) {
  712. trigger_error('Your folder layout is missing a app/_controllers/Default/cDefault.php controller file', E_USER_ERROR);
  713. }
  714. $_sPath = $_F . '/app/_controllers/' . $_sGroup . '/c' . $_sAction . '.php';
  715. if (!file_exists($_sPath)) {
  716. $_sPath = $_F . '/app/_controllers/' . $_sGroup . '/c' . $_sGroup . '.php';
  717. if (!file_exists($_sPath)) {
  718. trigger_error('Your folder layout is missing a "' . $_sPath . '" controller file', E_USER_ERROR);
  719. }
  720. }
  721. unset($_sWhichController);
  722. unset($_F);
  723. unset($_sGroup);
  724. unset($_sAction);
  725. require_once($_sPath);
  726. } else {
  727. // syntax on $_sWhichController would be like 'Test/MeOut'
  728. $_s = $_sWhichController;
  729. unset($_sWhichController);
  730. $_s = str_replace('.php','',$_s);
  731. $_s = ltrim($_s, '/');
  732. $_s = rtrim($_s, '/');
  733. $_s .= '.x';
  734. $_sBase = basename($_s);
  735. $_s = str_replace('/' . $_sBase,'/c' . $_sBase,$_s);
  736. $_s = str_replace('.x','',$_s);
  737. require_once($_F . '/app/_controllers/' . $_s . '.php');
  738. }
  739. if ($_bStopWhenRouted) {
  740. exit(0);
  741. }
  742. }
  743. /**
  744. * Returns an unencrypted cookie value.
  745. *
  746. * @param string $sLabel The key of that cookie value
  747. * @return string The value of that cookie by key
  748. */
  749. public function readCookie($sLabel) {
  750. $sCookiePrefix = @ $this->core->config['COOKIE_PREFIX'] . '_';
  751. $sLabel = $sCookiePrefix . strtolower($sLabel);
  752. if (isset($_COOKIE[$sLabel])) {
  753. return $_COOKIE[$sLabel];
  754. } else {
  755. return '';
  756. }
  757. }
  758. /**
  759. * Returns an unencrypted cookie value that was encrypted.
  760. *
  761. * @param string $sLabel The key of that cookie value
  762. * @return string The value of that cookie by key
  763. */
  764. public function readEncryptedCookie($sLabel) {
  765. $sValue = $this->readCookie($sLabel);
  766. $sValue = $this->_decryptData($sValue);
  767. return $sValue;
  768. }
  769. /**
  770. * Writes a cookie value. This is a session cookie, not persistent.
  771. *
  772. * @param string $sLabel The key of that cookie value
  773. * @param string $sValue The value of that cookie by key
  774. */
  775. public function writeCookie($sLabel, $sValue) {
  776. $sCookiePrefix = @ $this->core->config['COOKIE_PREFIX'] . '_';
  777. $sPath = '/';
  778. if ($sValue == '') {
  779. $this->deleteCookie($sLabel);
  780. } else {
  781. setcookie(strtolower($sCookiePrefix . $sLabel), $sValue, 0, $sPath);
  782. }
  783. }
  784. /**
  785. * Writes a cookie value. This is a persistent, not session, cookie. The persistence is for
  786. * 365 days.
  787. *
  788. * @param string $sLabel The key of that cookie value
  789. * @param string $sValue The value of that cookie by key
  790. * @param integer $nDays The number of days to keep the cookie. Defaults to 365 days.
  791. */
  792. public function writePersistentCookie($sLabel, $sValue,$nDays = 365) {
  793. $sCookiePrefix = @ $this->core->config['COOKIE_PREFIX'] . '_';
  794. $sPath = '/';
  795. if (!headers_sent()) {
  796. header ('Cache-control: private'); // IE 6 Fix.
  797. }
  798. setcookie(strtolower($sCookiePrefix . $sLabel), $sValue, time()+60*60*24*$nDays, $sPath);
  799. }
  800. /**
  801. * Encrypts and writes an encrypted cookie value. This is a session cookie, not persistent.
  802. *
  803. * @param string $sLabel The key of that cookie value
  804. * @param string $sValue The value of that cookie by key
  805. */
  806. public function writeEncryptedCookie($sLabel, $sValue) {
  807. $sValue = $this->_encryptData($sValue);
  808. $this->writeCookie($sLabel, $sValue);
  809. }
  810. /**
  811. * Encrypts and writes an encrypted cookie value. This is a persistent cookie.
  812. *
  813. * @param string $sLabel The key of that cookie value
  814. * @param string $sValue The value of that cookie by key
  815. * @param integer $nDays The number of days to keep the cookie. Defaults to 365 days.
  816. */
  817. public function writeEncryptedPersistentCookie($sLabel, $sValue,$nDays = 365) {
  818. $sValue = $this->_encryptData($sValue);
  819. $this->writePersistentCookie($sLabel, $sValue,$nDays);
  820. }
  821. /**
  822. * Given a key, this will delete a cookie.
  823. *
  824. * @param string $sLabel the key of that cookie
  825. */
  826. public function deleteCookie($sLabel) {
  827. $sCookiePrefix = @ $this->core->config['COOKIE_PREFIX'] . '_';
  828. $sPath = '/';
  829. $sLabel = strtolower($sLabel);
  830. setcookie ($sCookiePrefix . $sLabel, ' ', 0, $sPath);
  831. setcookie ($sCookiePrefix . $sLabel, '', time() - 3600, $sPath);
  832. }
  833. /**
  834. * This private class method decrypts our data.
  835. *
  836. * @param string $sData String of encrypted data.
  837. * @return string Unencrypted data.
  838. */
  839. private function _decryptData($sData){
  840. $sCookiePrefix = @ $this->core->config['COOKIE_PREFIX'];
  841. $sPrivateKey = md5($sCookiePrefix);
  842. if (trim($sData) == '') {
  843. return '';
  844. }
  845. // REVERSE THE PRIVATE KEY
  846. $sPrivateKey = strrev($sPrivateKey);
  847. // URL DECODE THE DATA
  848. $sData = urldecode($sData);
  849. // BASE64 DECODE THE DATA
  850. $sData = base64_decode($sData);
  851. if (function_exists('mcrypt_encrypt')) {
  852. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
  853. $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  854. $sData = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$sPrivateKey,$sData,
  855. MCRYPT_MODE_ECB, $iv);
  856. } else {
  857. // XOR EACH CHAR BY EACH CHAR IN A PRIVATE KEY (PRIVATE KEY REPEATED
  858. // OVER AND OVER AGAIN)
  859. $j=0; $nLen = strlen($sData);
  860. for($i = 0; $i < $nLen; $i++){
  861. $sData[$i] = chr(ord($sData[$i]) ^ ord($sPrivateKey[$j]));
  862. $j++;
  863. $j = ($j >= strlen($sPrivateKey)) ? 0 : $j;
  864. }
  865. // REVERSE OUR DATA
  866. $sData = strrev($sData);
  867. }
  868. // RETURN OUR DATA
  869. return trim($sData);
  870. }
  871. /**
  872. * This private class method encrypts our data.
  873. *
  874. * @param string $sData String of unencrypted data.
  875. * @return string Encrypted data.
  876. */
  877. private function _encryptData($sData){
  878. $sCookiePrefix = @ $this->core->config['COOKIE_PREFIX'];
  879. $sPrivateKey = md5($sCookiePrefix);
  880. if (trim($sData) == '') {
  881. return '';
  882. }
  883. // REVERSE THE PRIVATE KEY
  884. $sPrivateKey = strrev($sPrivateKey);
  885. if (function_exists('mcrypt_encrypt')) {
  886. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
  887. $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  888. $sData = mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$sPrivateKey,$sData,
  889. MCRYPT_MODE_ECB,$iv);
  890. } else {
  891. // REVERSE OUR DATA
  892. $sData = strrev($sData);
  893. // XOR EACH CHAR BY EACH CHAR IN A PRIVATE KEY (PRIVATE KEY REPEATED
  894. // OVER AND OVER AGAIN)
  895. $j=0; $nLen = strlen($sData);
  896. for($i = 0; $i < $nLen; $i++){
  897. $sData[$i] = chr(ord($sData[$i]) ^ ord($sPrivateKey[$j]));
  898. $j++;
  899. $j = ($j >= strlen($sPrivateKey)) ? 0 : $j;
  900. }
  901. }
  902. // BASE64 OUR DATA
  903. $sData = trim(base64_encode($sData));
  904. // FIX THE = PROBLEM IN THAT RESULT
  905. $sData = str_replace('=','',$sData);
  906. // URL ENCODE THE DATA
  907. $sData = urlencode($sData);
  908. // RETURN THE DATA
  909. return $sData;
  910. }
  911. } // end class Faster_Request
  912. /**
  913. * A class for loading model objects and enabling them with a powerful $this object, just like our
  914. * controllers have.
  915. *
  916. * @package Faster-Framework-API
  917. */
  918. class Faster_Model extends Faster {
  919. /**
  920. * Loads a model script to be executed and to return an object variable.
  921. *
  922. * Note all variables use underscores so as not to pass them to the model class file. This is
  923. * just a precautionary failsafe. We do an unset() on all variables we can before the
  924. * require_once() call.
  925. *
  926. * @param string $_sModelName The model path, such as 'Test', or 'SampleSystem/Test'. This translates
  927. * to app/_models/Test.php and app/_models/SampleSystem/Test.php, for example. Note that models do not have
  928. * an 'm' prefix before the filename because we really only needed in tabbed text editors to delineate
  929. * files which are controllers or views, which is why controllers have the "c" prefix, while views
  930. * have the "v" prefix.
  931. */
  932. public function load($_sModelName) {
  933. $_F = $this->core->base();
  934. if (strpos(' ' . $_sModelName,'/')>0) {
  935. $_sBaseName = basename($_sModelName);
  936. $_sPath = dirname($_sModelName);
  937. $_sPath = rtrim($_sPath, '/') . '/';
  938. $_sModelPath = $_sPath . $_sBaseName . '.php';
  939. $_sModelName = basename($_sModelName);
  940. } else {
  941. $_sModelPath = $_sModelName . '.php';
  942. }
  943. if (!file_exists($_F . '/app/_models')) {
  944. trigger_error('Your folder layout is missing a app/_models folder',E_USER_ERROR);
  945. }
  946. $_sPath = $_F . '/app/_models/' . $_sModelPath;
  947. if (!file_exists($_sPath)) {
  948. trigger_error('Your folder layout is missing a "' . $_sPath . '" models file',E_USER_ERROR);
  949. }
  950. unset($_sBaseName);
  951. unset($_sModelPath);
  952. unset($_F);
  953. require_once($_sPath);
  954. $_o = new $_sModelName();
  955. $_o->core = $this->core;
  956. $_o->request = $this->request;
  957. $_o->model = $this;
  958. $_o->view = $this->view;
  959. $_o->data = $this->data;
  960. return $_o;
  961. }
  962. }
  963. /**
  964. * This class is for common class methods for things not dealing with requests, views, data, or
  965. * models.
  966. *
  967. * @package Faster-Framework-API
  968. */
  969. class Faster_Core {
  970. /**
  971. * Gets mapped to app/config.php file, where we store an array of settings.
  972. */
  973. public $config;
  974. /**
  975. * Private variable to store the page load start time
  976. */
  977. private $_page_load_start_time;
  978. /**
  979. * Load our configuration file, app/config.php, so that the $config public variable is accessible with
  980. * the array of returned values.
  981. */
  982. public function __construct(){
  983. $this->config = $this->getConfig();
  984. }
  985. /**
  986. * Sets our microtime() for the Page Load Time. Is not meant to be exposed publicly as part of the framework API.
  987. *
  988. * @ignore
  989. */
  990. public function _setPageLoadStart(){
  991. $asMicro = explode(' ',microtime());
  992. $nStartTime = $asMicro[0] + $asMicro[1];
  993. $this->_page_load_start_time = $nStartTime;
  994. }
  995. /**
  996. * Loads our configuration file.
  997. *
  998. * @return array An array of settings from app/config.php
  999. */
  1000. public function getConfig() {
  1001. $F = $this->base();
  1002. return include $F . '/app/config.php';
  1003. }
  1004. /**
  1005. * Returns our base URL of a site.
  1006. *
  1007. * @return string The Base URL
  1008. */
  1009. public function baseurl() {
  1010. static $sRoot;
  1011. if (!isset($sRoot)) {
  1012. $sProtocol = empty($_SERVER['HTTPS'])? 'http' : 'https';
  1013. $sServerName = $_SERVER['SERVER_NAME'];
  1014. $sPort = $_SERVER['SERVER_PORT']=='80'? '' : ':' . $_SERVER['SERVER_PORT'];
  1015. $sPath = str_replace('index.php','',$_SERVER['SCRIPT_NAME']);
  1016. $sPath = $sProtocol . '://' . $sServerName . $sPort . $sPath;
  1017. $sRoot = rtrim($sPath, '/');
  1018. }
  1019. return $sRoot;
  1020. }
  1021. /**
  1022. * Returns our base file path of a site.
  1023. *
  1024. * @return string The Base File Path
  1025. */
  1026. public function base() {
  1027. static $sPath;
  1028. if (!isset($sPath)) {
  1029. $sPath = dirname(__FILE__);
  1030. $sPath = rtrim($sPath, '/');
  1031. }
  1032. return $sPath;
  1033. }
  1034. /**
  1035. * Returns our max session lifetime in seconds.
  1036. *
  1037. * @return int The max session lifetime in seconds
  1038. */
  1039. public function sessiontimeout() {
  1040. static $nSecs;
  1041. if (!isset($nSecs)) {
  1042. $nSecs = ini_get('session.gc_maxlifetime');
  1043. }
  1044. return $nSecs;
  1045. }
  1046. /**
  1047. * Returns the total page load time.
  1048. *
  1049. * @return int Total time in seconds
  1050. */
  1051. public function page_load_time(){
  1052. $asMicro = explode(' ',microtime());
  1053. $nEndTime = $asMicro[0] + $asMicro[1];
  1054. $nTotalTime = ($nEndTime - $this->_page_load_start_time);
  1055. return $nTotalTime;
  1056. }
  1057. } // end class Faster_Core
  1058. /**
  1059. * This class handles our view details.
  1060. *
  1061. * @package Faster-Framework-API
  1062. */
  1063. class Faster_View {
  1064. /**
  1065. * Gets mapped to Faster_Core so that this functionality is exposed to the View.
  1066. */
  1067. public $core;
  1068. /**
  1069. * Private variable where we store our request object when the framework loads
  1070. */
  1071. private $_request;
  1072. /**
  1073. * Private variable where we store variables that can be utilized in Views with $this->VARIABLE
  1074. */
  1075. private $_asVars = array();
  1076. /**
  1077. * Constant used by some of the class methods to indicate no desire to alter variable.
  1078. */
  1079. const ENCODE_DEFAULT = 0;
  1080. /**
  1081. * Constant used by some of the class methods to indicate we need to use htmlentities() on the variable.
  1082. */
  1083. const ENCODE_HTML = 1;
  1084. /**
  1085. * Constant used by some of the class methods to indicate we need to use urlencode() on the variable.
  1086. */
  1087. const ENCODE_URL = 2;
  1088. /**
  1089. * Private class method to set our request object when the framework loads. It's not designed to
  1090. * be used by people using the framework.
  1091. *
  1092. * @ignore
  1093. * @param object $request The request object
  1094. */
  1095. public function _setRequest($request){
  1096. $this->_request = $request;
  1097. }
  1098. /**
  1099. * Injects a variable into a view. The view can then access it via $this->VARIABLE.
  1100. *
  1101. * Note that View variables must be in UPPERCASE or an error is triggered.
  1102. *
  1103. * @param string $sKey The key we want to set for our variable.
  1104. * @param string $sVal The value we want to store.
  1105. * @param int $nType A selector from the ENCODE_* constants of this class which lets us do some
  1106. * encoding on the variable either through htmlentities() or urlencode(), or not at all. The
  1107. * default is ENCODE_DEFAULT (unaltered)
  1108. */
  1109. public function setVar($sKey, $sVal, $nType = self::ENCODE_DEFAULT){
  1110. $sUpper = strtoupper($sKey);
  1111. if ($sUpper != $sKey) {
  1112. trigger_error('View variables must be in uppercase',E_USER_ERROR);
  1113. }
  1114. switch ($nType) {
  1115. case self::ENCODE_HTML: // show the html
  1116. $sVal = htmlentities($sVal);
  1117. break;
  1118. case self::ENCODE_URL: // prepare for urls
  1119. $sVal = urlencode($sVal);
  1120. break;
  1121. default: // 0, default, as is, unaltered
  1122. break;
  1123. }
  1124. $this->_asVars[$sUpper] = $sVal;
  1125. }
  1126. /**
  1127. * Injects a variable into a view. The view can then access it via $this->VARIABLE.
  1128. *
  1129. * Note that View variables must be in UPPERCASE or an error is triggered.
  1130. * Note the difference with setVar() is that setVarH() assumes default ENCODE_HTML
  1131. *
  1132. * @param string $sKey The key we want to set for our variable.
  1133. * @param string $sVal The value we want to store.
  1134. */
  1135. public function setVarH($sKey, $sVal){
  1136. $sUpper = strtoupper($sKey);
  1137. if ($sUpper != $sKey) {
  1138. trigger_error('View variables must be in uppercase',E_USER_ERROR);
  1139. }
  1140. $sVal = htmlentities($sVal);
  1141. $this->_asVars[$sUpper] = $sVal;
  1142. }
  1143. /**
  1144. * Is the inverse of setVar(). Is used to provide $this->VARIABLE functionality in the view for
  1145. * accessing variables that were previously assigned with setVar().
  1146. *
  1147. * Note that View variables must be in UPPERCASE or an error is triggered.
  1148. *
  1149. * @param string $sKey The key we want to use to access our variable.
  1150. */
  1151. public function __get($sKey){
  1152. $sUpper = strtoupper($sKey);
  1153. if ($sUpper != $sKey) {
  1154. trigger_error('View variables must be in uppercase',E_USER_ERROR);
  1155. }
  1156. return $this->_asVars[$sKey];
  1157. }
  1158. /**
  1159. * Injects a variable into a view. What it does, in reality, is create a global constant which
  1160. * the view can read.
  1161. *
  1162. * Note that View variables must be in UPPERCASE or an error is triggered.
  1163. *
  1164. * @param string $sKey The key we want to set for our variable. Becomes the constant name.
  1165. * @param string $sVal The value we want to store.
  1166. * @param int $nType A selector from the ENCODE_* constants of this class which lets us do some
  1167. * encoding on the variable either through htmlentities() or urlencode(), or not at all.
  1168. */
  1169. public function setCVar($sKey, $sVal, $nType = self::ENCODE_DEFAULT) {
  1170. $sUpper = strtoupper($sKey);
  1171. if ($sUpper != $sKey) {
  1172. trigger_error('View variables must be in uppercase',E_USER_ERROR);
  1173. }
  1174. switch ($nType) {
  1175. case self::ENCODE_HTML: // show the html
  1176. $sVal = htmlentities($sVal);
  1177. break;
  1178. case self::ENCODE_URL: // prepare for urls
  1179. $sVal = urlencode($sVal);
  1180. break;
  1181. default: // 0, default, as is, unaltered
  1182. break;
  1183. }
  1184. define($sUpper, $sVal);
  1185. }
  1186. /**
  1187. * Does the same thing as setCVar(), but does so with an array of vars at once.
  1188. *
  1189. * @param array $asVars Array of key => value pairs.
  1190. * @param int $nType A selector from the ENCODE_* constants of this class which lets us do some
  1191. * encoding on the variable either through htmlentities() or urlencode(), or not at all.
  1192. */
  1193. public function setCVars($asVars, $nType = self::ENCODE_DEFAULT) {
  1194. foreach($asVars as $sVarName => $sVal){
  1195. $this->setCVar($sVarName, $sVal, $nType);
  1196. }
  1197. }
  1198. /**
  1199. * Does the same thing as setVar(), but does so with an array of vars at once.
  1200. *
  1201. * @param array $asVars Array of key => value pairs.
  1202. * @param int $nType A selector from the ENCODE_* constants of this class which lets us do some
  1203. * encoding on the variable either through htmlentities() or urlencode(), or not at all.
  1204. */
  1205. public function setVars($asVars, $nType = self::ENCODE_DEFAULT) {
  1206. foreach($asVars as $sVarName => $sVal){
  1207. $this->setCVar($sVarName, $sVal, $nType);
  1208. }
  1209. }
  1210. /**
  1211. * Renders our view with variables intact, and then returns as a string. The view uses PHP
  1212. * Alternative Syntax.
  1213. *
  1214. * Note all variables use underscores so as not to pass them to the view file. This is
  1215. * just a precautionary failsafe. We do an unset() on all variables we can before the
  1216. * require_once() call.
  1217. *
  1218. * Note that the view path naturally mimics the controller path if you leave $_sFile empty.
  1219. *
  1220. * Note the alternative syntax for the Action parameter of the path. For instance if you have
  1221. * /about for the URL, then this can map to either About/vDefault.php --OR-- About/vAbout.php.
  1222. * This helps in text editors by limiting the confusion with all the vDefault.php files.
  1223. *
  1224. * @param string $_sFile A specified file path to the view. If not specified, it will assume the
  1225. * same path as the controller path, but with "v" instead of "c" on the final file prefix.
  1226. * @param bool $_bDrawImmediately Defines whether to cache the view until all elements are drawn
  1227. * to the browser, and then show it, or show it as it is built.
  1228. */
  1229. public function render($_sFile = '', $_bDrawImmediately = FALSE) {
  1230. $_F = $this->core->base();
  1231. if (empty($_sFile)) {
  1232. $_sFile = $this->_request->getGroup() . '/' . $this->_request->getAction();
  1233. }
  1234. $_sFile = strrev($_sFile);
  1235. $_sFile = str_replace('/','~',$_sFile);
  1236. $_sFile = preg_replace('/~/','v~',$_sFile,1);
  1237. $_sFile = str_replace('~','/',$_sFile);
  1238. $_sFile = strrev($_sFile);
  1239. if (!$_bDrawImmediately) {
  1240. ob_start();
  1241. }
  1242. if (!file_exists($_F . '/app/_views')) {
  1243. trigger_error('Your folder layout is missing a app/_views folder',E_USER_ERROR);
  1244. }
  1245. $_sPath = $_F . '/app/_views/' . $_sFile . '.php';
  1246. if (!file_exists($_sPath)) {
  1247. trigger_error('Your folder layout is missing a "' . $_sPath . '" views file',E_USER_ERROR);
  1248. }
  1249. if (file_exists($_sPath)) {
  1250. unset($_F);
  1251. unset($_sFile);
  1252. require_once($_sPath);
  1253. } else {
  1254. $_sFile = $this->_request->getGroup() . '/' . $this->_request->getGroup();
  1255. $_sFile = strrev($_sFile);
  1256. $_sFile = str_replace('/','~',$_sFile);
  1257. $_sFile = preg_replace('/~/','v~',$_sFile,1);
  1258. $_sFile = str_replace('~','/',$_sFile);
  1259. $_sFile = strrev($_sFile);
  1260. $_sPath = $_F . '/app/_views/' . $_sFile . '.php';
  1261. unset($_F);
  1262. unset($_sFile);
  1263. require_once($_sPath);
  1264. }
  1265. if (!$_bDrawImmediately) {
  1266. $_sOut = ob_get_contents();
  1267. ob_end_clean();
  1268. return $_sOut;
  1269. }
  1270. }
  1271. /**
  1272. * Displays our view. See render() for more information. All this class method does is echo
  1273. * the result of render().
  1274. *
  1275. * @param string $sFile A specified file path to the view. If not specified, it will assume the
  1276. * same path as the controller path, but with "v" instead of "c" on the final file prefix.
  1277. * @param bool $bDrawImmediately Defines whether to cache the view until all elements are drawn
  1278. * to the browser, and then show it, or show it as it is built.
  1279. */
  1280. public function display($sFile = '', $bDrawImmediately = FALSE) {
  1281. echo $this->render($sFile, $bDrawImmediately);
  1282. }
  1283. } // end class Faster_View
  1284. /**
  1285. * A simplistic data class that helps us with PDO with MySQL or SQLite. This class is intentionally
  1286. * small and simple.
  1287. *
  1288. * @package Faster-Framework-API
  1289. */
  1290. class Faster_Data {
  1291. /**
  1292. * Private variable to store our core object, used by this class.
  1293. */
  1294. private $_core;
  1295. /**
  1296. * Is used only at boot time of the framework in order to set the core object of the data class.
  1297. * It is not meant to be exposed to be used by someone who wants to use the framework.
  1298. *
  1299. * @ignore
  1300. * @param object $core Our core object
  1301. */
  1302. public function _setCore($core){
  1303. $this->_core = $core;
  1304. }
  1305. /**
  1306. * Returns a PDO object variable for the given MySQL connection as specified in the $this->_core
  1307. * ->config parameters for the given database.
  1308. *
  1309. * @return object The PDO object
  1310. */
  1311. public function mysql(){
  1312. static $PDO;
  1313. if (!$PDO) {
  1314. $sPort = @ $this->_core->config['DB_PORT'];
  1315. $sPort = (empty($sPort)) ? '3306' : $sPort;
  1316. $DSN = sprintf('mysql:dbname=%s;host=%s;port=%s', $this->_core->config['DB_DATABASE'], $this->_core->config['DB_SERVER'], $sPort);
  1317. try {
  1318. $PDO = new PDO($DSN, $this->_core->config['DB_USER'],$this->_core->config['DB_PASS']);
  1319. } catch(PDOException $e) {
  1320. $SQLSTATE = $this->get_ANSI_SQLSTATE_Code($e);
  1321. if ($SQLSTATE == '42000') {
  1322. trigger_error('Missing database "' . $this->_core->config['DB_DATABASE'] . '"', E_USER_ERROR);
  1323. }
  1324. }
  1325. $PDO->setAttribute(PDO::MYSQL_ATTR_MAX_BUFFER_SIZE, 1024*1024*50);
  1326. $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  1327. $PDO->setAttribute(PDO::ATTR_PERSISTENT,TRUE);
  1328. $PDO->setAttribute(PDO::ATTR_CURSOR, PDO::CURSOR_FWDONLY);
  1329. }
  1330. return $PDO;
  1331. }
  1332. /**
  1333. * Returns a PDO object variable for the given SQLite connection as specified in the $this->_core
  1334. * ->config parameters for the given database.
  1335. *
  1336. * @return object The PDO object
  1337. */
  1338. public function sqlite(){
  1339. static $PDO;
  1340. if (!$PDO){
  1341. $DSN = sprintf('sqlite:%s', $this->_core->config['DB_DATABASE']);
  1342. try {
  1343. $PDO = new PDO($DSN, $this->_core->config['DB_USER'],$this->_core->config['DB_PASS']);
  1344. $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  1345. } catch(PDOException $e) {
  1346. $SQLSTATE = $this->get_ANSI_SQLSTATE_Code($e);
  1347. if ($SQLSTATE == 'HY000') {
  1348. trigger_error('The database file "' . $this->_core->config['DB_DATABASE'] . '" could not be found.',E_USER_ERROR);
  1349. }
  1350. }
  1351. }
  1352. return $PDO;
  1353. }
  1354. /**
  1355. * A handy class method to give you a unique ID if you don't like a database default autonumbering.
  1356. * Some people don't like database default autonumbering because programmers can mess up the data
  1357. * integrity if they don't know what they are doing in transferring a database. By using these keys
  1358. * instead, the data integrity remains intact.
  1359. *
  1360. * WARNING: Be aware that 8 digit trigesimals with dashes and no leading zeroes gives you a range of
  1361. * around 21.8 billion potential numbers. If you need more numbers, then expand the $nSize and/or
  1362. * remove the dash. If you expand the size, note that your table primary key and foreign key size
  1363. * will need to change too.
  1364. *
  1365. * The SQL for creating this table in MySQL would be:
  1366. *
  1367. * CREATE TABLE IF NOT EXISTS `ids` (
  1368. * `id` char(8) COLLATE ascii_bin NOT NULL,
  1369. * `group` varchar(80) COLLATE ascii_bin NOT NULL,
  1370. * `dt_created` datetime NOT NULL,
  1371. * PRIMARY KEY (`id`,`group`)
  1372. *) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin;
  1373. *
  1374. * ...and for SQLite would be:
  1375. *
  1376. * CREATE TABLE IF NOT EXISTS `ids` (
  1377. * `id` TEXT PRIMARY KEY,
  1378. * `group` TEXT NOT NULL,
  1379. * `dt_created` TEXT NOT NULL
  1380. * );
  1381. *
  1382. * @param object $PDO The current PDO object
  1383. * @param string $sTable The table by which we need this new unique ID value.
  1384. * @param integer $nSize The number of digits you wish to have.
  1385. * @param boolean $bWithDash Whether the number should have a dash in it or not
  1386. * @return string A unique ID for our record. It is in the format 999-ABCD and is fixed at 8
  1387. * characters. The dash helps us identify the record faster, visually, if viewing the records
  1388. * in a table.
  1389. */
  1390. public function getNewID($PDO, $sTable, $nSize = 8, $bWithDash = TRUE) {
  1391. // generate variant trigesimal (base 30)
  1392. // note trigesimals help us avoid numbers with negative meanings in them
  1393. $sKey = '';
  1394. $sPossible = '0123456789BCDFGHJKLMNPQRSTVWXZ';
  1395. for ($i = 1; $i <= $nSize; $i++) {
  1396. if (($bWithDash) and ($i == 4)) {
  1397. $sKey .= '-';
  1398. continue;
  1399. }
  1400. $nRand = ($i == 1) ? mt_rand(1,29) : mt_rand(0,29);
  1401. $c = substr($sPossible, $nRand, 1);
  1402. $sKey .= $c;
  1403. }
  1404. $sTable = strtoupper($sTable);
  1405. $sDate = gmdate('Y-m-d H:i:s');
  1406. $sSQL = "INSERT INTO `ids` (`id`, `group`, `dt_created`) VALUES ('$sKey', '$sTable', '$sDate');";
  1407. try {
  1408. $PDO->exec($sSQL);
  1409. } catch (PDOException $e) {
  1410. $SQLSTATE = $this->get_ANSI_SQLSTATE_Code($e);
  1411. if ($SQLSTATE == '42S02') {
  1412. trigger_error('The "ids" table does not exist.', E_USER_ERROR);
  1413. }
  1414. if ($SQLSTATE == '23000') {
  1415. return $this->getNewID($PDO, $sTable, $nSize, $bWithDash);
  1416. }
  1417. trigger_error("The SQLSTATE ($SQLSTATE) error code happened in getNewID() of the Faster_Data class.", E_USER_ERROR);
  1418. }
  1419. return $sKey;
  1420. }
  1421. /**
  1422. * Takes a PDOException variable and converts it into an ANSI SQLSTATE code.
  1423. *
  1424. * For SQLSTATE variables and their meanings, see the attached links.
  1425. * @link http://dev.mysql.com/doc/refman/5.0/en/error-messages-server.html
  1426. * @link http://www.php.net/manual/en/pdo.errorcode.php
  1427. *
  1428. * @param object $e PDOException object from a Try/Catch routine
  1429. * @return string A translated PDOException as an ANSI SQLSTATE code.
  1430. */
  1431. public function get_ANSI_SQLSTATE_Code($e) {
  1432. $s = $e->__toString();
  1433. $asItems = explode('[', $s);
  1434. $s = @ $asItems[1];
  1435. $asItems = explode(']', $s);
  1436. $s = @ $asItems[0];
  1437. return trim($s);
  1438. }
  1439. } // end class Faster_Data