<?php /** * The router file of ZenTaoPMS. * * All request should be routed by this router. * * @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com) * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html) * @author Chunsheng Wang <chunsheng@cnezsoft.com> * @package ZenTaoPMS * @version $Id: index.php 5036 2013-07-06 05:26:44Z wyd621@gmail.com $ * @link http://www.zentao.net */ /* Set the error reporting. */ error_reporting(E_ALL);
/* Start output buffer. */ ob_start();
/* Set cookie_httponly. */ ini_set("session.cookie_httponly", 1);
/* Load the framework. */ include'../framework/router.class.php'; include'../framework/control.class.php'; include'../framework/model.class.php'; include'../framework/helper.class.php';
/* Log the time and define the run mode. */ $startTime = getTime();
/* Instance the app. */ $app = router::createApp('pms', dirname(dirname(__FILE__)), 'router');
/* installed or not. */ if(!$app->checkInstalled()) die(header('location: install.php'));
/* Check for need upgrade. */ $config->installedVersion = $app->getInstalledVersion(); if($config->version != $config->installedVersion) die(header('location: upgrade.php'));
/* Run the app. */ $app->setStartTime($startTime); $common = $app->loadCommon();
/* Check the request is getconfig or not. */ if(isset($_GET['mode']) and$_GET['mode'] == 'getconfig') die(helper::removeUTF8Bom($app->exportConfig()));
/* If client device is mobile and version is pro, set the default view as mthml. */ if($app->clientDevice == 'mobile'and (strpos($config->version, 'pro') === 0orstrpos($config->version, 'biz') === 0orstrpos($config->version, 'max') === 0) and$config->default->view == 'html') $config->default->view = 'mhtml'; if(!empty($_GET['display']) && $_GET['display'] == 'card') $config->default->view = 'xhtml';
/** * 构造方法, 设置路径,类,超级变量等。注意: * 1.应该使用createApp()方法实例化router类; * 2.如果$appRoot为空,框架会根据$appName计算应用路径。 * * The construct function. * Prepare all the paths, classes, super objects and so on. * Notice: * 1. You should use the createApp() method to get an instance of the router. * 2. If the $appRoot is empty, the framework will compute the appRoot according the $appName * * @param string $appName the name of the app * @param string $appRoot the root path of the app * @param string $mode the mode of the app running|installing|upgrading * @access public * @return void */ publicfunction__construct(string$appName = 'demo', string$appRoot = '', string$mode = 'running') { if($mode != 'running') $this->{$mode} = true;
/** * 从类库中加载一个类文件。 * * Load a class file. * * @param string $className the class name * @param bool $static statis class or not * @access public * @return object|bool the instance of the class or just true. */ publicfunctionloadClass($className, $static = false) { $className = strtolower($className);
/* 实例化该类(Instance it) */ global ${$className}; if(!class_exists($className)) $this->triggerError("the class $className not found in $classFile", __FILE__, __LINE__, true); if(!is_object(${$className})) ${$className} = new$className(); return ${$className}; }
/** * 使用helper::import()来引入文件,不要直接使用include或者require. * Using helper::import() to import a file, instead of include or require. * * @param string $file the file to be imported. * @static * @access public * @return bool */ staticpublicfunctionimport($file) { $file = realpath($file); if($file === false) returnfalse;
/** * 加载common模块。 * * common模块比较特别,它会执行几乎每次请求都需要执行的操作,例如: * 打开session,检查权限等等。 * 加载完$lang, $config, $dbh后,需要在入口文件(www/index.php)中手动调用该方法。 * * Load the common module * * The common module is a special module, which can be used to do some common things. For example: * start session, check privilege and so on. * This method should called manually in the router file(www/index.php) after the $lang, $config, $dbh loaded. * * @access public * @return object|bool the common model object or false if not exits. */ publicfunctionloadCommon() { $this->setModuleName('common'); $commonModelFile = $this->setModelFile('common'); if(!file_exists($commonModelFile)) returnfalse;
/* Override the items defined in config/config.php and config/my.php. */ if(isset($this->config->system->common)) $this->app->mergeConfig($this->config->system->common, 'common'); if(isset($this->config->personal->common)) $this->app->mergeConfig($this->config->personal->common, 'common');
/** * 检查请求的模块和方法是否应该调用工作流引擎进行处理。 * Check if the requested module and method should call the workflow engine for processing. * * 处理逻辑: * Processing logic: * 1、如果当前版本不是企业版,或者当前请求处于安装模式或升级模式,调用父类方法并返回。 * 1. If the current version is not the enterprise version, or if the current request is in install mode or upgrade mode, call the parent class method and return. * * 2、如果当前请求的模块在TABLE_WORKFLOW表中不存在,调用父类方法并返回。 * 2. If the currently requested module does not exist in the TABLE_WORKFLOW table, call the parent class method and return. * * 3、如果当前请求的模块在TABLE_WORKFLOW表中存在并且是内置模块,并且请求的方法名是browselabel,则修改请求的模块名为flow,修改请求的方法名为browse,重新设置URI参数,调用父类方法并返回。 * 3. If the currently requested module exists in the TABLE_WORKFLOW table and is a built-in module, and the requested method name is * browselabel, rename the module of the request to flow and the method of the request to browse, and reset the URI, call the parent class method and return. * * 4、如果不满足3中的条件但当前请求的方法在TABLE_WORKFLOWACTION表中存在,且方法扩展类型为重写,则修改请求的模块名为flow,方法名根据5中的规则修改,重新设置URI参数,调用父类方法并返回。 * 4. If the condition of 3 is not satisfied but the currently requested method exists in the TABLE_WORKFLOWACTION table, and the method * extension type is overwrite, rename the module of the request to flow, and rename the method of the request according to the rule in 5. * Then reset the URI, call the parent class method and return. * * 5、如果当前请求的方法名为browse、create、edit、view、delete、export中任意一个,则方法名不变,否则方法名改为operate。 * 5. If the currently requested method is named any one of browse, create, edit, view, delete, or export, the method name is unchanged, otherwise the method name is changed to operate. * * @param bool $exitIfNone 没有找到该控制器文件的情况:如果该参数为true,则终止程序;如果为false,则打印错误日志 * The controller file was not found: if the parameter is true, the program is terminated; * if false, the error log is printed. * @access public * @return bool */ publicfunctionsetControlFile($exitIfNone = true) { /* Set raw module and method name for fetch control. */ if(empty($this->rawModule)) $this->rawModule = $this->moduleName; if(empty($this->rawMethod)) $this->rawMethod = $this->methodName;
/* If is not a biz version or is in install mode or in in upgrade mode, call parent method. */ if($this->config->edition == 'open'or$this->installing or$this->upgrading) returnparent::setControlFile($exitIfNone);
/* Check if the requested module is defined in workflow. */ $flow = $this->dbQuery("SELECT * FROM " . TABLE_WORKFLOW . " WHERE `module` = '$this->moduleName'")->fetch(); if(!$flow) returnparent::setControlFile($exitIfNone); if($flow->status != 'normal') helper::end("<html><head><meta charset='utf-8'></head><body>{$this->lang->flowNotRelease}</body></html>");
/** * 工作流中配置的标签应该请求browse方法,而某些内置流程本身包含browse方法。在这里处理请求的时候会无法区分是内置的browse方法还是工作 * 流标签的browse方法,为了避免此类冲突,在工作流中配置出的标签请求的方法改为browseLabel,在设置控制器文件时需要将其重设为browse。 * Tags configured in the workflow should request the browse method, and some built-in processes themselves contain the browse * method. When processing a request here, it is impossible to distinguish between the built-in browse method and the browse * method of the workflow tag. In order to avoid such conflicts, the method of configuring the label request in the workflow * is changed to browseLabel, which needs to be reset to browse when setting the controller file. */ if($flow->buildin && $this->methodName == 'browselabel') { $this->rawModule = $this->moduleName; $this->rawMethod = 'browse'; $this->isFlow = true;
$moduleName = 'flow'; $methodName = $this->methodName; /* * 工作流中除了内置方法外的方法,如果是批量操作调用batchOperate方法,其它操作调用operate方法来执行。 * In addition to the built-in methods in the workflow, if the batch operation calls the batchOperate method, other operations call the operate method to execute. */ if(!in_array($this->methodName, $this->config->workflowaction->default->actions)) { if($action->type == 'single') $methodName = 'operate'; if($action->type == 'batch') $methodName = 'batchOperate'; }
$this->setFlowURI($moduleName, $methodName); } }
/* Call method of parent. */ returnparent::setControlFile($exitIfNone); }
正常版本调用到if($this->config->edition == 'open' or $this->installing or $this->upgrading) return parent::setControlFile($exitIfNone);就结束了,也就是开源版,只有在非开源版本如企业版就会有工作流workflow相关代码逻辑
/** * 禅道鉴权核心方法,如果用户没有当前模块、方法的权限,则跳转到登录页面或者拒绝页面。 * Check the user has permission to access this method, if not, locate to the login page or deny page. * * @access public * @return void */ publicfunctioncheckPriv() { try { $module = $this->app->getModuleName(); $method = $this->app->getMethodName(); if($this->app->isFlow) { $module = $this->app->rawModule; $method = $this->app->rawMethod; }
/** * 加载一个模块: * 1. 引入控制器文件或扩展的方法文件; * 2. 创建control对象; * 3. 解析url,得到请求的参数; * 4. 使用call_user_function_array调用相应的方法。 * * Load a module. * 1. include the control file or the extension action file. * 2. create the control object. * 3. set the params passed in through url. * 4. call the method by call_user_function_array * * @access public * @return bool|object if the module object of die. */ publicfunctionloadModule() { if(is_null($this->params) and !$this->setParams()) { $this->outputXhprof(); returnfalse; }