/** * Find and load the real ZFDemo bootstrap.php file */ function ZFDemoGrub($installDir, $configEnv) { error_reporting(E_ALL | E_STRICT); // verbose $ds = DIRECTORY_SEPARATOR; // too much typing ;) // where to find this application's configuration (using Conventional Modular Layout) if ($installDir[0] === $ds) { $tmp = $installDir; $appDir = $tmp; // skip costly realpath($tmp) } else { $tmp = dirname(__FILE__) . $ds . '..' . $ds . '..' . $ds . 'zfdemo' . $ds . $installDir; $appDir = realpath($tmp) . $ds; } // show installation help, if loading bootstrap fails if ((include $appDir . 'bootstrap.php') === false) { $log = "Looking for application directory in:\n realpath({$tmp}" . $ds . ")\n"; $log .= " = {$appDir}bootstrap.php\n"; $file = __FILE__; echo <<<EOD <html><head><title>ZFDemo - Installation problem</title></head><body> <pre>{$log}</pre> <h1>Instructions</h1> <p>Check for existence and permissions of the directories above.</p> <p>Then edit "\$installDir" in this file ( {$file} ).</p> <p>See also: <a href="http://framework.zend.com/wiki/display/ZFDEV/Tutorial" >http://framework.zend.com/wiki/display/ZFDEV/Tutorial</a></p> </body></html> EOD; exit; } if (false === ZFDemo::bootstrap($installDir, $appDir, $configEnv)) { // Run! ZFDemo_log::show(); } }
/** * STAGE 2: Find the right action and execute it. */ public static function stage2($frontController) { ///////////////////////////// // ==> SECTION: mvc <== $frontController->returnResponse(true); // return the response (do not echo it to the browser) // show exceptions immediately, instead of adding to the response $frontController->throwExceptions(true); // without this no exceptions are thrown $config = self::$registry['config']; require 'lib/Controller/Action.php'; // ZFDemo's customized Zend_Controller_Action require_once 'Zend/Controller/Request/Http.php'; $request = new Zend_Controller_Request_Http(); require_once 'Zend/Controller/Response/Http.php'; $response = new Zend_Controller_Response_Http(); $response->append('body', ''); // initialize a body segment // safety shutoff, in case controllers are stuck in loop, each calling the other $maxDispatches = isset($config->maxDispatches) ? $config->maxDispatches : 5; // rerouteTo will designate either an error code (mapped to error controller), or module/controller/action $rerouteTo = $didRerouteTo = $rerouteToReason = null; if (isset(self::$registry['testDbFailed']) && substr($request->getRequestUri(), -12) !== '/index/reset') { // during STAGE 1, sanity check of the DB connection/tables failed, so reroute to informative page $rerouteTo = self::reroute($request, self::$registry['config']->testDbFailed, $frontController); } do { if ($rerouteTo) { // if a reroute was requested, process it now $didRerouteTo = self::reroute($request, $rerouteTo, $frontController, $rerouteToReason); $rerouteToReason = $rerouteTo = null; } ///////////////////////////// // ==> SECTION: mvc <== try { // "Run" the configured MVC "program" - the calculated action of the selected controller $frontController->dispatch($request, $response); } catch (ZFDemo_Exception_Reroute $exception) { // action controller requested a reroute form of internal redirection $rerouteTo = $exception->getRouteTo(); $suggestedHttpCode = $exception->getHttpCode(); $rerouteToReason = 'Reroute: ' . $exception->getMessage() . '; ' . $exception->responseCodeAsText(); } catch (Exception $exception) { // don't allow *any* exceptions to end this script, without handling them properly if (!$config->analyzeDispatchErrors) { // we are not analyzing the errors, so self::doExit(404, $exception); // log event and exit } ///////////////////////////// // ==> SECTION: except <== list($suggestedHttpCode, $rerouteToReason) = self::analyzeError($exception, $request, $response); // if we have not already tried dispatching this controller code if ($didRerouteTo['code'] !== $suggestedHttpCode) { $rerouteTo = $suggestedHttpCode; #$rerouteToReason = $exception->getMessage(); } else { // Already tried to dispatch the selected error controller, so now fail hard. ZFDemo_Log::logDispatchFailure($didRerouteTo); if (self::isLocalRequest() && $config->view->showLog) { echo ZFDemo_Log::get($exception); } // Reader excercise: make output "pretty" when dispatching error controller fails self::doExit($suggestedHttpCode, $exception, is_int($didRerouteTo['code']) && $didRerouteTo['code'] > 400 ? _('An additional error occurred while trying to use the error action controller.') : ''); } } } while ($rerouteTo && --$maxDispatches); // now loop to dispatch the alternative controller (if any) if ($maxDispatches === 0) { ZFDemo_Log::log(_('ERROR Too many reroutes. Controllers stuck in loop?') . $request->getRequestUri()); } ///////////////////////////// // ==> SECTION: except <== if (isset($suggestedHttpCode) && $suggestedHttpCode != 200) { // something unusual happened during dispatch, like a 404 or 500 error self::setHeaderStatus($suggestedHttpCode); } ///////////////////////////// // ==> SECTION: mvc <== $baseUrl = $request->getBaseUrl(); // save for use in header/footer/site templates if (false === strpos($baseUrl, '/index.php')) { $baseUrl .= '/index.php'; } self::$view->baseUrl = $baseUrl; if (ZFDemo::isLocalRequest()) { // Since this is only added for local network requests, this code // may remain in production applications to aid in ongoing development. // Add some helpful debugging information for inserting into HTML comments: self::$view->controller = $request->getControllerName(); self::$view->module = $request->getModuleName(); self::$view->action = $request->getActionName(); } return $response; }
/** * Modules are semi-standalone, encapsulated "mini" applications. * Thus, there is a need for a global module initialization process, * for the dispatched module to provide shared initializations for * all controllers within this module. */ public function preDispatch(Zend_Controller_Request_Abstract $request) { $frontController = Zend_Controller_Front::getInstance(); $moduleName = $request->getModuleName(); $registry = Zend_Registry::getInstance(); $moduleInit = $registry['appDir'] . $moduleName . DIRECTORY_SEPARATOR . $moduleName . '.php'; $modulesIni = $registry['configDir'] . 'modules.ini'; // If a module has an initialization / authorization component if (is_readable($moduleInit)) { include_once $moduleInit; if (!isset($registry['config']->cache)) { // if caching of module ini files is not enabled, just load it now $config = new Zend_Config_Ini($modulesIni, $moduleName); } ///////////////////////////// // ==> SECTION: auth <== $rerouteTo = null; /* Allow modules.ini to disable anonymous access to individual modules. * Authenticate #2 ( see "Authenticate Where?" http://framework.zend.com/wiki/x/fUw ) */ if (empty($config->allowAnonymousUse)) { if (empty($registry['authenticationId'])) { // if not already authenticated $rerouteTo = $config->authenticate; } } if ($rerouteTo === null) { // Access control could also be selectively applied to entire modules, instead of inside the module: $rerouteTo = call_user_func(array('ZFModule_' . ucfirst($moduleName), 'moduleAuth'), $config, $request); } if ($rerouteTo) { if (--$this->maxDispatches > 0) { if ($rerouteTo == $this->didRerouteTo) { $msg = _('ERROR Looping detected in preDispatch().') . $request->getRequestUri(); ZFDemo_Log::log($msg); throw new ZFDemo_Exception_Reroute($msg, 500); } ZFDemo::reroute($request, $rerouteTo, $frontController, null, true); $this->didRerouteTo = $rerouteTo; } else { $msg = _('ERROR Too many reroutes in preDispatch(). Looping?') . $request->getRequestUri(); ZFDemo_Log::log($msg); throw new ZFDemo_Exception_Reroute($msg, 500); } } } // dynamic configurations, DRY, O(1) with respect to number of modules // http://framework.zend.com/issues/browse/ZF-1125 // $frontController->setControllerDirectory(array($moduleName => Zend_Registry::get('appDir') // . $moduleName . $ds . 'controllers')); return; }
public static function bootstrap($installDir) { if (self::testEnvironment() === false) { echo 'Environment fails to meet minimum requirements for this demo tutorial.'; return; } // where to find this application's configuration (using Conventional Modular Layout) $ds = DIRECTORY_SEPARATOR; // too much typing ;) if ($installDir[0] === '/') { $tmp = $installDir; } else { $tmp = dirname(__FILE__) . $ds . '..' . $ds . '..' . $ds . 'zfdemo' . $ds . $installDir; } // STAGE 0: Initializations / Loading Configuration ZFDemo_Log::log("looking for application directory in: realpath({$tmp}" . $ds . ')'); $appDir = realpath($tmp) . $ds; ZFDemo_Log::log('$appDir =' . $appDir); self::$registry = Zend_Registry::getInstance(); self::$registry['appDir'] = $appDir; if (!is_readable($appDir)) { ZFDemo_Log::log("ERROR: Application directory is not readable (path problem).\n", true); return false; } // this application's configuration information $configDir = realpath($appDir . $ds . 'config' . $ds) . $ds; self::$registry['configDir'] = $configDir; ZFDemo_Log::log('$configDir =' . $configDir); if (!is_readable($configDir)) { ZFDemo_Log::log("ERROR: Application configuration directory 'config' is not readable (path problem).\n", true); return false; } // persistent dynamic data, like log files or SQLite files $dataDir = realpath($appDir . $ds . 'data' . $ds) . $ds; self::$registry['dataDir'] = $dataDir; ZFDemo_Log::log('$dataDir =' . $dataDir); if (!is_readable("{$dataDir}")) { ZFDemo_Log::log("ERROR: Application 'data' directory is not readable (path problem).\n", true); return false; } // temporary data, like PHP session state files $temporaryDir = realpath($appDir . $ds . 'temporary' . $ds) . $ds; self::$registry['temporaryDir'] = $temporaryDir; ZFDemo_Log::log('$temporaryDir =' . $temporaryDir); if (!is_readable("{$temporaryDir}")) { ZFDemo_Log::log("ERROR: Application 'temporary' directory is not readable (path problem).\n", true); return false; } // add the application-specific source file path to PHP's include path for the Conventional Modular Layout set_include_path($appDir . PATH_SEPARATOR . get_include_path()); ZFDemo_Log::log("PHP Include Path = \n " . str_replace(':', "\n ", ini_get('include_path'))); self::$environment = 'sandbox'; // after this point, all defaults come from config files require 'Zend/Config/Ini.php'; $config = new Zend_Config_Ini($configDir . 'config.ini', self::$environment, true); ZFDemo_Log::log("config.ini=" . print_r($config->asArray(), true)); if (strpos($config->log, '/') !== 0) { $config->log = $dataDir . $config->log; } self::$registry['config'] = $config; // application configuration array date_default_timezone_set($config->timezone); $sessionConfig = new Zend_Config_Ini($configDir . 'Zend_Session.ini', self::$environment, true); $sessionConfig->save_path = $temporaryDir . $sessionConfig->save_path; ZFDemo_Log::log("Zend_Session.ini=" . print_r($sessionConfig->asArray(), true)); require 'Zend/Session.php'; Zend_Session::setOptions($sessionConfig->asArray()); Zend_Session::start(); /* * The zfdemo will not work unless the following code results creates a session file * in your save_path folder, * with file contents like: * foo|a:2:{s:3:"bar";s:5:"apple";s:4:"time";s:19:"2007-02-20 21:30:36";} */ $testSpace = new Zend_Session_Namespace('spaceFoo'); $testSpace->keyBar = 'valueBar'; $testSpace->time = time(); $testSpace->date = date('Y-m-d H:i:s'); // preemptively write session file now Zend_Session::writeClose(); self::testPdo($config); // sanity check connection and zfdemo tables using PDO // Now test using ZF's MySQL PDO DB adapter: require 'Zend/Db.php'; require 'Zend/Db/Adapter/Pdo/Mysql.php'; // setup our DB adapter $db = new Zend_Db_Adapter_Pdo_Mysql($config->db->asArray()); self::$registry['db'] = $db; self::testDb($db); // sanity check connection and zfdemo tables using Zend Db Adapter // STAGE 1: Prepare the front (primary) controller. require 'Zend/Controller/Front.php'; $frontController = Zend_Controller_Front::getInstance(); // manages the overall workflow $baseUrl = substr($_SERVER['PHP_SELF'], 0, strpos($_SERVER['PHP_SELF'], '/index.php')); ZFDemo_Log::log("baseUrl={$baseUrl}"); //$frontController->setBaseUrl($baseUrl); $frontController->setControllerDirectory(array('default' => $appDir . 'default' . $ds . 'controllers', 'forum' => $appDir . 'forum' . $ds . 'controllers')); // Initialize views require 'Zend/View.php'; self::$view = new Zend_View(); self::$view->sectionName = basename($installDir); // e.g. "section1_install" self::$view->setScriptPath($appDir . 'default' . $ds . 'views'); self::$view->showLog = true; ZFDemo_Log::log("scriptPaths=\n " . implode("\n ", self::$view->getScriptPaths())); $frontController->setParam('view', self::$view); // STAGE 2: Find the right action and execute it. // Use routes to calculate controllers and actions to execute // Dispatch calculated actions of the selected controllers $frontController->returnResponse(true); // return the response (do not echo it to the browser) // Use UTF-8. See "1. Content-type, Charset, DOCTYPE" in NOTES.txt require_once 'Zend/Controller/Response/Http.php'; $response = new Zend_Controller_Response_Http(); $response->setHeader('Content-type', 'text/html; charset=utf-8', true); $response->setBody(self::$view->render('header.php')); try { require_once 'Zend/Controller/Request/Http.php'; $request = new Zend_Controller_Request_Http(); // show exceptions immediately, instead of adding to the response $frontController->throwExceptions(true); // without this no exceptions are thrown // similar to "running" the configured MVC "program" $frontController->dispatch($request, $response); } catch (Zend_Controller_Dispatcher_Exception $exception) { self::analyzeError($frontController->getDispatcher(), $exception, $request, $response); return false; } // STAGES 3 to 5 occur in an action controller: /zfdemo/forum/*/controllers/*Controller.php // STAGE 6 occurs in a view template: /zfdemo/forum/*/views/*.phtml /** * STAGE 7: Render results in response to request. */ $response->renderExceptions(true); // show any excpetions in the visible output (i.e. debug mode) // OR: Handle exceptions thrown in the dispatch loop. // Examine the exception type, and then redirect to an error page. ksort($_SERVER); self::$view->SERVER = $_SERVER; self::$view->log = ZFDemo_Log::get(); $response->appendBody(self::$view->render('footer.php'), 'footer'); //Zend::debug($frontController->getRequest());exit // debug the request object //Zend_Debug::dump($response);exit; // examine the inner details of the response object $response->sendResponse(); // send final results to browser, including headers }
/** * The default action is "indexAction", unless explcitly set to something else. */ public function indexAction() { // STAGE 4: Apply business logic to create a presentation model for the view. $origRequest = $this->getInvokeArg('origRequest'); $this->view->rerouteToReason = $this->getInvokeArg('rerouteToReason'); $this->view->origRequestUri = $origRequest->REQUEST_URI; // if no credentials if (empty($_REQUEST['username'])) { // should be _POST, but this makes demo easier to tweak // STAGE 5: Choose view template and submit presentation model to view template for rendering. // if an admin area was requested, and authentication has been enabled in config.ini if (isset($this->authSpace->authenticationId)) { ZFDemo_Log::log(_('already have authentication id, showing logout form')); $this->_forward('logoutDecision'); // show logout form } else { ZFDemo_Log::log(_('no authentication id, showing login form')); $this->renderToSegment('body'); // show login form } return; } // prepare to authenticate credentials received from a form require_once 'Zend/Auth/Result.php'; require_once 'Zend/Auth/Adapter/Digest.php'; $config = Zend_Registry::get('config'); $username = trim($_REQUEST['username']); // ought to be _POST, but this simplifies experimentation $password = trim($_REQUEST['password']); // by the reader of the tutorial // filtering will be added in a later section ///////////////////////////// // ==> SECTION: filter <== require_once 'Zend/Validate/Alnum.php'; require_once 'Zend/Validate/Regex.php'; // input filtering is enabled, so .. $validator_name = new Zend_Validate_Alnum(); // alphabetic and numeric characters are permitted if (!$validator_name->isValid($username)) { $this->renderToSegment('body', 'invalidUsername'); return; } // this application has "special" requirements, so we show how to use custom regex: $validator_password = new Zend_Validate_Regex('/^[a-z0-9_]{5,16}$/'); if (!$validator_password->isValid($password)) { $this->renderToSegment('body', 'invalidPassword'); return; } ///////////////////////////// // ==> SECTION: auth <== $result = false; try { // try to authenticate using the md5 "digest" adapter $filename = $config->authenticate->filename; // file containing username:realm:password digests if ($filename[0] !== DIRECTORY_SEPARATOR) { $filename = Zend_Registry::get('dataDir') . $filename; // prepend path, if filename not absolute } $adapter = new Zend_Auth_Adapter_Digest($filename, $config->authenticate->realm, $username, $password); $result = $adapter->authenticate(); // result of trying to authenticate credentials $this->view->resultCode = $result->getCode(); // allow view to see result status (reason) } catch (Exception $exception) { $this->view->exception = ZFDemo::filterException($exception); // record exception description $this->view->resultCode = false; } if ($result && $result->isValid()) { // if successful authentication, save the authentication identity ( http://framework.zend.com/wiki/x/fUw ) $id = $result->getIdentity(); Zend_Registry::set('authenticationId', $id); // publish the identity (really need Observer pattern) $this->authSpace->authenticationId = $id; $this->authSpace->date = time(); // save the timestamp when authenticated successfully $this->authSpace->attempts = 0; // success, so forget the number of previous login failures // @TODO: filter this ... $this->_redirect($_REQUEST['origPathInfo']); // now return to wherever user came from } else { $this->authSpace->attempts++; // record the authentication failure if ($this->authSpace->attempts > $config->authenticate->maxAttempts) { // Overly simplistic account "lockout" lasts for at least 10 seconds, // but increases with repeated failures. $this->view->lockout = 5 * $this->authSpace->attempts; // Lockout time will be "forgotten" later, and expired from session, allowing logins. $this->authSpace->setExpirationSeconds($this->view->lockout); $this->blockHacker(); // show a view indicating account lockout return; } } // STAGE 5: Choose view template and submit presentation model to view template for rendering. $this->renderToSegment('body'); }
/** * STAGE 2: Find the right action and execute it. */ public static function stage2($frontController) { ///////////////////////////// // ==> SECTION: mvc <== $frontController->returnResponse(true); // return the response (do not echo it to the browser) // show exceptions immediately, instead of adding to the response $frontController->throwExceptions(true); // without this no exceptions are thrown $config = self::$registry['config']; require 'lib/Controller/Action.php'; // ZFDemo's customized Zend_Controller_Action require_once 'Zend/Controller/Request/Http.php'; $request = new Zend_Controller_Request_Http(); require_once 'Zend/Controller/Response/Http.php'; $response = new Zend_Controller_Response_Http(); $response->append('body', ''); // initialize a body segment ///////////////////////////// // ==> SECTION: mvc <== try { // "Run" the configured MVC "program" - the calculated action of the selected controller $frontController->dispatch($request, $response); } catch (Exception $exception) { // don't allow *any* exceptions to end this script, without handling them properly if (!$config->analyzeDispatchErrors) { // we are not analyzing the errors, so self::doExit(404, $exception); // log event and exit } } ///////////////////////////// // ==> SECTION: mvc <== $baseUrl = $request->getBaseUrl(); // save for use in header/footer/site templates if (false === strpos($baseUrl, '/index.php')) { $baseUrl .= '/index.php'; } self::$view->baseUrl = $baseUrl; if (ZFDemo::isLocalRequest()) { // Since this is only added for local network requests, this code // may remain in production applications to aid in ongoing development. // Add some helpful debugging information for inserting into HTML comments: self::$view->controller = $request->getControllerName(); self::$view->module = $request->getModuleName(); self::$view->action = $request->getActionName(); } return $response; }