[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
14082024
/
Data
/
htdocs
/
htdocs
/
ojs
/
248
/
lib
/
pkp
/
classes
/
handler
/
[
Home
]
File: PKPHandler.inc.php
<?php /** * @file classes/core/PKPHandler.inc.php * * Copyright (c) 2013-2019 Simon Fraser University * Copyright (c) 2000-2019 John Willinsky * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING. * * @package core * @class PKPHandler * * Base request handler abstract class. * */ // FIXME: remove these import statements - handler validators are deprecated. import('lib.pkp.classes.handler.validation.HandlerValidator'); import('lib.pkp.classes.handler.validation.HandlerValidatorRoles'); import('lib.pkp.classes.handler.validation.HandlerValidatorCustom'); class PKPHandler { /** * @var string identifier of the controller instance - must be unique * among all instances of a given controller type. */ var $_id; /** @var Dispatcher, mainly needed for cross-router url construction */ var $_dispatcher; /** @var array validation checks for this page - deprecated! */ var $_checks = array(); /** * @var array * The value of this variable should look like this: * array( * ROLE_ID_... => array(...allowed handler operations...), * ... * ) */ var $_roleAssignments = array(); /** @var AuthorizationDecisionManager authorization decision manager for this handler */ var $_authorizationDecisionManager; /** * Constructor */ function PKPHandler() { } // // Setters and Getters // /** * Set the controller id * @param $id string */ function setId($id) { $this->_id = $id; } /** * Get the controller id * @return string */ function getId() { return $this->_id; } /** * Get the dispatcher * * NB: The dispatcher will only be set after * handler instantiation. Calling getDispatcher() * in the constructor will fail. * * @return Dispatcher */ function &getDispatcher() { assert(!is_null($this->_dispatcher)); return $this->_dispatcher; } /** * Set the dispatcher * @param $dispatcher PKPDispatcher */ function setDispatcher(&$dispatcher) { $this->_dispatcher =& $dispatcher; } /** * Fallback method in case request handler does not implement index method. */ function index() { $dispatcher =& $this->getDispatcher(); if (isset($dispatcher)) $dispatcher->handle404(); else Dispatcher::handle404(); // For old-style handlers } /** * Add a validation check to the handler. * * NB: deprecated! * * @param $handlerValidator HandlerValidator */ function addCheck(&$handlerValidator) { // FIXME: Add a deprecation warning once we've refactored // all HandlerValidator occurrences. $this->_checks[] =& $handlerValidator; } /** * Add an authorization policy for this handler which will * be applied in the authorize() method. * * Policies must be added in the class constructor or in the * subclasses' authorize() method before the parent::authorize() * call so that PKPHandler::authorize() will be able to enforce * them. * * @param $authorizationPolicy AuthorizationPolicy * @param $addToTop boolean whether to insert the new policy * to the top of the list. */ function addPolicy($authorizationPolicy, $addToTop = false) { if (is_null($this->_authorizationDecisionManager)) { // Instantiate the authorization decision manager import('lib.pkp.classes.security.authorization.AuthorizationDecisionManager'); $this->_authorizationDecisionManager = new AuthorizationDecisionManager(); } // Add authorization policies to the authorization decision manager. $this->_authorizationDecisionManager->addPolicy($authorizationPolicy, $addToTop); } /** * Retrieve authorized context objects from the * decision manager. * @param $assocType integer any of the ASSOC_TYPE_* constants * @return mixed */ function &getAuthorizedContextObject($assocType) { assert(is_a($this->_authorizationDecisionManager, 'AuthorizationDecisionManager')); return $this->_authorizationDecisionManager->getAuthorizedContextObject($assocType); } /** * Get the authorized context. * * NB: You should avoid accessing the authorized context * directly to avoid accidentally overwriting an object * in the context. Try to use getAuthorizedContextObject() * instead where possible. * * @return array */ function &getAuthorizedContext() { assert(is_a($this->_authorizationDecisionManager, 'AuthorizationDecisionManager')); return $this->_authorizationDecisionManager->getAuthorizedContext(); } /** * Retrieve the last authorization message from the * decision manager. * @return string */ function getLastAuthorizationMessage() { assert(is_a($this->_authorizationDecisionManager, 'AuthorizationDecisionManager')); $authorizationMessages =& $this->_authorizationDecisionManager->getAuthorizationMessages(); return end($authorizationMessages); } /** * Add role - operation assignments to the handler. * * @param $roleIds integer|array one or more of the ROLE_ID_* * constants * @param $operations string|array a single method name or * an array of method names to be assigned. */ function addRoleAssignment($roleIds, $operations) { // Allow single operations to be passed in as scalars. if (!is_array($operations)) $operations = array($operations); // Allow single roles to be passed in as scalars. if (!is_array($roleIds)) $roleIds = array($roleIds); // Add the given operations to all roles. foreach($roleIds as $roleId) { // Create an empty assignment array if no operations // have been assigned to the given role before. if (!isset($this->_roleAssignments[$roleId])) { $this->_roleAssignments[$roleId] = array(); } // Merge the new operations with the already assigned // ones for the given role. $this->_roleAssignments[$roleId] = array_merge( $this->_roleAssignments[$roleId], $operations ); } } /** * This method returns an assignment of operation names for the * given role. * * @return array assignment for the given role. */ function getRoleAssignment($roleId) { if (!is_null($roleId)) { if (isset($this->_roleAssignments[$roleId])) { return $this->_roleAssignments[$roleId]; } else { return null; } } } /** * This method returns an assignment of roles to operation names. * * @return array assignments for all roles. */ function getRoleAssignments() { return $this->_roleAssignments; } /** * Authorize this request. * * Routers will call this method automatically thereby enforcing * authorization. This method will be called before the * validate() method and before passing control on to the * handler operation. * * NB: This method will be called once for every request only. * * @param $request Request * @param $args array request arguments * @param $roleAssignment array the operation role assignment, * see getRoleAssignment() for more details. * @return boolean */ function authorize(&$request, &$args, $roleAssignments) { // Enforce restricted site access. import('lib.pkp.classes.security.authorization.RestrictedSiteAccessPolicy'); $this->addPolicy(new RestrictedSiteAccessPolicy($request), true); // Enforce SSL site-wide. if ($this->requireSSL()) { import('lib.pkp.classes.security.authorization.HttpsPolicy'); $this->addPolicy(new HttpsPolicy($request), true); } if (!defined('SESSION_DISABLE_INIT')) { // Add user roles in authorized context. $user = $request->getUser(); if (is_a($user, 'User')) { import('lib.pkp.classes.security.authorization.UserRolesRequiredPolicy'); $this->addPolicy(new UserRolesRequiredPolicy($request), true); } } // Make sure that we have a valid decision manager instance. assert(is_a($this->_authorizationDecisionManager, 'AuthorizationDecisionManager')); $router =& $request->getRouter(); if (is_a($router, 'PKPPageRouter')) { // We have to apply a blacklist approach for page // controllers to maintain backwards compatibility: // Requests are implicitly authorized if no policy // explicitly denies access. $this->_authorizationDecisionManager->setDecisionIfNoPolicyApplies(AUTHORIZATION_PERMIT); } else { // We implement a strict whitelist approach for // all other components: Requests will only be // authorized if at least one policy explicitly // grants access and none denies access. $this->_authorizationDecisionManager->setDecisionIfNoPolicyApplies(AUTHORIZATION_DENY); } // Let the authorization decision manager take a decision. $decision = $this->_authorizationDecisionManager->decide(); if ($decision == AUTHORIZATION_PERMIT) { return true; } else { return false; } } /** * Perform data integrity checks. * * This method will be called once for every request only. * * NB: Any kind of authorization check is now deprecated * within this method. This method is purely meant for data * integrity checks that do not lead to denial of access * to resources (e.g. via redirect) like handler operations * or data objects. * * @param $requiredContexts array * @param $request Request */ function validate($requiredContexts = null, $request = null) { // FIXME: for backwards compatibility only - remove when request/router refactoring complete if (!isset($request)) { // FIXME: Trigger a deprecation warning when enough instances of this // call have been fixed to not clutter the error log. $request =& Registry::get('request'); } foreach ($this->_checks as $check) { // Using authorization checks in the validate() method is deprecated // FIXME: Trigger a deprecation warning. // WARNING: This line is for PHP4 compatibility when // instantiating handlers without reference. Should not // be removed or otherwise used. // See <http://pkp.sfu.ca/wiki/index.php/Information_for_Developers#Use_of_.24this_in_the_constructor> // for a similar problem. $check->_setHandler($this); // check should redirect on fail and continue on pass // default action is to redirect to the index page on fail if ( !$check->isValid() ) { if ( $check->redirectToLogin ) { Validation::redirectLogin(); } else { // An unauthorized page request will be re-routed // to the index page. $request->redirect(null, 'index'); } } } return true; } /** * Subclasses can override this method to configure the * handler. * * NB: This method will be called after validation and * authorization. * * @param $request PKPRequest * @param $args array */ function initialize(&$request, $args = null) { // Set the controller id to the requested // page (page routing) or component name // (component routing) by default. $router =& $request->getRouter(); if (is_a($router, 'PKPComponentRouter')) { $componentId = $router->getRequestedComponent($request); // Create a somewhat compressed but still globally unique // and human readable component id. // Example: "grid.citation.CitationGridHandler" // becomes "grid-citation-citationgrid" $componentId = str_replace('.', '-', PKPString::strtolower(PKPString::substr($componentId, 0, -7))); $this->setId($componentId); } else { assert(is_a($router, 'PKPPageRouter')); $this->setId($router->getRequestedPage($request)); } } /** * Return the DBResultRange structure and misc. variables describing the current page of a set of pages. * @param $rangeName string Symbolic name of range of pages; must match the Smarty {page_list ...} name. * @param $contextData array If set, this should contain a set of data that are required to * define the context of this request (for maintaining page numbers across requests). * To disable persistent page contexts, set this variable to null. * @return array ($pageNum, $dbResultRange) */ function &getRangeInfo($rangeName, $contextData = null) { //FIXME: is there any way to get around calling a Request (instead of a PKPRequest) here? $context =& Request::getContext(); $pageNum = PKPRequest::getUserVar($rangeName . 'Page'); if (empty($pageNum)) { $session =& PKPRequest::getSession(); $pageNum = 1; // Default to page 1 if ($session && $contextData !== null) { // See if we can get a page number from a prior request $contextHash = PKPHandler::hashPageContext($contextData); if (PKPRequest::getUserVar('clearPageContext')) { // Explicitly clear the old page context $session->unsetSessionVar("page-$contextHash"); } else { $oldPage = $session->getSessionVar("page-$contextHash"); if (is_numeric($oldPage)) $pageNum = $oldPage; } } } else { $session =& PKPRequest::getSession(); if ($session && $contextData !== null) { // Store the page number $contextHash = PKPHandler::hashPageContext($contextData); $session->setSessionVar("page-$contextHash", $pageNum); } } if ($context) $count = $context->getSetting('itemsPerPage'); if (!isset($count)) $count = Config::getVar('interface', 'items_per_page'); import('lib.pkp.classes.db.DBResultRange'); if (isset($count)) $returner = new DBResultRange($count, $pageNum); else $returner = new DBResultRange(-1, -1); return $returner; } function setupTemplate() { AppLocale::requireComponents( LOCALE_COMPONENT_PKP_COMMON, LOCALE_COMPONENT_PKP_USER ); if (defined('LOCALE_COMPONENT_APPLICATION_COMMON')) { AppLocale::requireComponents(LOCALE_COMPONENT_APPLICATION_COMMON); } $templateMgr =& TemplateManager::getManager(); $templateMgr->assign('userRoles', $this->getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES)); $accessibleWorkflowStages = $this->getAuthorizedContextObject(ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES); if ($accessibleWorkflowStages) $templateMgr->assign('accessibleWorkflowStages', $accessibleWorkflowStages); } /** * Generate a unique-ish hash of the page's identity, including all * context that differentiates it from other similar pages (e.g. all * articles vs. all articles starting with "l"). * @param $contextData array A set of information identifying the page * @return string hash */ function hashPageContext($contextData = array()) { return md5( implode(',', Request::getRequestedContextPath()) . ',' . Request::getRequestedPage() . ',' . Request::getRequestedOp() . ',' . serialize($contextData) ); } /** * Get a list of pages that don't require login, even if the system does * FIXME: Delete this method when authorization re-factoring is complete. * @return array */ function getLoginExemptions() { import('lib.pkp.classes.security.authorization.RestrictedSiteAccessPolicy'); return RestrictedSiteAccessPolicy::_getLoginExemptions(); } /** * Assume SSL is required for all handlers, unless overridden in subclasses. * @return boolean */ function requireSSL() { return true; } } ?>