| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- <?php
- include 'router.class.php';
- class xuanxuan extends router
- {
- /**
- * The input params.
- *
- * @var array
- * @access public
- */
- public $input = array();
- /**
- * The request params.
- *
- * @var array
- * @access public
- */
- public $params = array();
- /**
- * 构造方法, 设置路径,类,超级变量等。注意:
- * 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
- * @access public
- * @return void
- */
- public function __construct($appName = 'sys', $appRoot = '')
- {
- parent::__construct($appName, $appRoot);
- $this->setViewType();
- $this->setXuanClientLang();
- $this->setXuanDebug();
- }
- /**
- * Set view type.
- *
- * @access public
- * @return void
- */
- public function setViewType()
- {
- $this->viewType = RUN_MODE == 'xuanxuan' ? 'json' : 'html';
- }
- /**
- * 根据用户浏览器的语言设置和服务器配置,选择显示的语言。
- * 优先级:$lang参数 > session > cookie > 浏览器 > 配置文件。
- *
- * Set the language.
- * Using the order of method $lang param, session, cookie, browser and the default lang.
- *
- * @param string $lang zh-cn|zh-tw|zh-hk|en
- * @access public
- * @return void
- */
- public function setXuanClientLang()
- {
- $row = $this->dbh->query('SELECT `value` FROM ' . TABLE_CONFIG . " WHERE `owner`='system' AND `module`='common' AND `section`='xuanxuan' AND `key`='backendLang'")->fetch();
- $lang = empty($row) ? 'zh-cn' : $row->value;
- parent::setClientLang($lang);
- }
- /**
- * Set debug.
- *
- * @access public
- * @return void
- */
- public function setXuanDebug()
- {
- $row = $this->dbh->query('SELECT `value` FROM ' . TABLE_CONFIG . " WHERE `owner`='system' AND `module`='common' AND `section`='xuanxuan' AND `key`='debug'")->fetch();
- $this->debug = empty($row) ? false : ($row->value == 1);
- }
- /**
- * Set input params.
- *
- * @access public
- * @return void
- */
- public function setInput()
- {
- if(RUN_MODE == 'xuanxuan')
- {
- $input = empty($_POST) ? file_get_contents("php://input") : $_POST;
- /* Decrypt only if AES is enabled. */
- $enableAES = $this->dbh->query('SELECT `value` FROM ' . TABLE_CONFIG . " WHERE `owner`='system' AND `module`='common' AND `section`='xuanxuan' AND `key`='aes'")->fetch();
- if(empty($enableAES) || $enableAES->value == 'on') $this->enableAES = true;
- if(!empty($enableAES) && $enableAES->value == 'off') $this->enableAES = false;
- if($this->enableAES) $this->initAES();
- $input = $this->decrypt($input);
- $this->input['rid'] = zget($input, 'rid' , '');
- $this->input['userID'] = zget($input, 'userID' , '');
- $this->input['client'] = zget($input, 'client' , '');
- $this->input['module'] = zget($input, 'module' , 'im');
- $this->input['method'] = zget($input, 'method' , '');
- $this->input['lang'] = zget($input, 'lang' , 'zh-cn');
- $this->input['params'] = zget($input, 'params' , array());
- $this->input['version'] = zget($input, 'version', '');
- $this->input['device'] = zget($input, 'device' , 'desktop');
- }
- else
- {
- $this->input['module'] = 'im';
- $this->input['method'] = 'debug';
- $this->input['params'] = array();
- }
- }
- /**
- * Init aes object.
- *
- * @access public
- * @return void
- */
- public function initAES()
- {
- $row = $this->dbh->query('SELECT `value` FROM ' . TABLE_CONFIG . " WHERE `owner`='system' AND `module`='common' AND `section`='xuanxuan' AND `key`='key'")->fetch();
- $key = $row->value;
- $iv = substr($key, 0, 16);
- $this->aes = $this->loadClass('phpaes');
- $this->aes->init($key, $iv);
- if($this->debug)
- {
- $this->log("engine: " . $this->aes->getEngine());
- }
- }
- /**
- * Set params.
- *
- * @param array $params
- * @access public
- * @return void
- */
- public function setParams($params = array())
- {
- $this->params = $params;
- }
- /**
- * 解析本次请求的入口方法,根据请求的类型(PATH_INFO GET),调用相应的方法。
- * The entrance of parseing request. According to the requestType, call related methods.
- *
- * @access public
- * @return void
- */
- public function parseRequest()
- {
- $this->setInput();
- extract($this->input);
- $module = strtolower($module);
- $method = strtolower($method);
- if(RUN_MODE == 'xuanxuan')
- {
- if(!isset($this->config->xuanxuan->enabledMethods[$module][$method]))
- {
- $data = new stdclass();
- $data->module = 'im';
- $data->method = 'error';
- $data->data = 'Illegal Request.';
- $this->output($this->encrypt($data));
- return false;
- }
- /* Check for default parameters of the method if params is an object instead of an array. */
- $filledWithDefaults = false;
- if(is_object($params)) // cannot check ($params !== array_values($params)) for now because the decoder could not tell if data type name is needed and the name is always set.
- {
- $inputParams = (object)$params;
- $defaultParams = $this->getFunctionParams($method, $module);
- $filledParams = array();
- foreach($defaultParams as $name => $defaultValue)
- {
- if(in_array($name, array('userID', 'version', 'device'))) continue;
- $filledParams[] = isset($inputParams->$name) ? $inputParams->$name : $defaultValue;
- }
- $filledWithDefaults = true;
- $params = $filledParams;
- }
- /* Unset servername param of handshake methods. */
- $handshakeMethods = array('userlogin', 'sysgetserverinfo');
- if(!$filledWithDefaults && $module == 'im' && in_array(strtolower($method), $handshakeMethods) && is_array($params)) unset($params[0]);
- if(is_array($params))
- {
- $params[] = $userID;
- $params[] = $version;
- $params[] = $device;
- }
- $this->session->set('userID', $userID);
- $this->session->set('clientIP', $client);
- $this->session->set('clientLang', $lang);
- }
- elseif($module != 'im' or $method != 'debug')
- {
- $this->output('Access Denied');
- return false;
- }
- $this->setModuleName($module);
- $this->setMethodName($method);
- $this->setParams($params);
- $this->setControlFile();
- return true;
- }
- /**
- * 使用反射机制获取函数参数的默认值。
- * Get the default settings of the method to be called using the reflecting.
- *
- * @param string $methodName
- * @param string $moduleName
- * @access public
- * @return array
- */
- public function getFunctionParams($methodName, $moduleName = 'im')
- {
- $control = $this->getExtensionRoot() . "xuan/" . $moduleName . DS . 'control.php';
- $moduleExtPaths = $this->getModuleExtPath($moduleName, 'control');
- if(!empty($moduleExtPaths))
- {
- $extActionFile = $moduleExtPaths['common'] . $methodName . '.php';
- if(file_exists($extActionFile))
- {
- $control = $extActionFile;
- }
- elseif(isset($moduleExtPaths['xuan']))
- {
- $extActionFile = $moduleExtPaths['xuan'] . $methodName . '.php';
- if(file_exists($extActionFile)) $control = $extActionFile;
- }
- }
- helper::cd(dirname($control));
- helper::import($control);
- helper::cd();
- $moduleName = class_exists("my$moduleName") ? "my$moduleName" : $moduleName;
- $defaultParams = array();
- $methodReflect = new reflectionMethod($moduleName, $methodName);
- foreach($methodReflect->getParameters() as $param)
- {
- $name = $param->getName();
- $default = '_NOT_SET';
- if($param->isDefaultValueAvailable()) $default = $param->getDefaultValue();
- $defaultParams[$name] = $default;
- }
- return $defaultParams;
- }
- /**
- * 加载一个模块:
- * 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.
- */
- public function loadModule()
- {
- $appName = $this->appName;
- $moduleName = $this->moduleName;
- $methodName = $this->methodName;
- /*
- * 引入该模块的control文件。
- * Include the control file of the module.
- **/
- $file2Included = $this->setActionExtFile() ? $this->extActionFile : $this->controlFile;
- chdir(dirname($file2Included));
- helper::import($file2Included);
- /*
- * 设置control的类名。
- * Set the class name of the control.
- **/
- $className = class_exists("my$moduleName") ? "my$moduleName" : $moduleName;
- if(!class_exists($className))
- {
- $this->triggerError("the control $className not found", __FILE__, __LINE__);
- return false;
- }
- /*
- * 创建control类的实例。
- * Create a instance of the control.
- **/
- $module = new $className();
- if(!method_exists($module, $methodName))
- {
- $this->triggerError("the module $moduleName has no $methodName method", __FILE__, __LINE__);
- return false;
- }
- /* If the db server restarted, must reset dbh. */
- $this->control = $module;
- /* include default value for module*/
- $defaultValueFiles = glob($this->getTmpRoot() . "defaultvalue/*.php");
- if($defaultValueFiles) foreach($defaultValueFiles as $file) include $file;
- /*
- * 使用反射机制获取函数参数的默认值。
- * Get the default settings of the method to be called using the reflecting.
- *
- * */
- $defaultParams = array();
- $methodReflect = new reflectionMethod($className, $methodName);
- foreach($methodReflect->getParameters() as $param)
- {
- $name = $param->getName();
- $default = '_NOT_SET';
- if(isset($paramDefaultValue[$appName][$className][$methodName][$name]))
- {
- $default = $paramDefaultValue[$appName][$className][$methodName][$name];
- }
- elseif(isset($paramDefaultValue[$className][$methodName][$name]))
- {
- $default = $paramDefaultValue[$className][$methodName][$name];
- }
- elseif($param->isDefaultValueAvailable())
- {
- $default = $param->getDefaultValue();
- }
- $defaultParams[$name] = $default;
- }
- /* Merge params. */
- $mergedParams = array();
- if(isset($this->params))
- {
- $mergedParams = $this->mergeParams($defaultParams, (array)$this->params);
- }
- else
- {
- $this->triggerError("param error: {$this->request->raw}", __FILE__, __LINE__);
- return false;
- }
- /* Call the method. */
- $this->response = call_user_func_array(array($module, $methodName), $mergedParams);
- return true;
- }
- /**
- * 合并请求的参数和默认参数,这样就可以省略已经有默认值的参数了。
- * Merge the params passed in and the default params. Thus the params which have default values needn't pass value, just like a function.
- *
- * @param array $defaultParams the default params defined by the method.
- * @param array $passedParams the params passed in through url.
- * @access public
- * @return array the merged params.
- */
- public function mergeParams($defaultParams, $passedParams)
- {
- /* Remove these two params. */
- unset($passedParams['HTTP_X_REQUESTED_WITH']);
- /* Check params from URL. */
- foreach($passedParams as $param => $value)
- {
- if(preg_match('/[^a-zA-Z0-9_\.]/', $param))
- {
- $this->output('Bad Request!');
- return array();
- }
- }
- $passedParams = array_values($passedParams);
- $i = 0;
- foreach($defaultParams as $key => $defaultValue)
- {
- if(isset($passedParams[$i]))
- {
- $defaultParams[$key] = $passedParams[$i];
- }
- else
- {
- if($defaultValue === '_NOT_SET') $this->triggerError("The param '$key' should pass value. ", __FILE__, __LINE__, $exit = true);
- }
- $i++;
- }
- return $defaultParams;
- }
- /**
- * Decrypt an input string.
- *
- * @param string $input
- * @access public
- * @return object
- */
- public function decrypt($input = '')
- {
- if($this->enableAES) $input = $this->aes->decrypt($input);
- if($this->debug) $this->log("decrypt: " . $input);
- $input = json_decode($input);
- if(!$input) $this->triggerError('Input data is not json.', __FILE__, __LINE__);
- if($input && is_object($input)) return $input;
- return $this->decodeInput($input);
- }
- /**
- * Encrypt an output object.
- *
- * @param mixed $output array | object
- * @access public
- * @return string
- */
- public function encrypt($output = null)
- {
- if(is_array($output) or is_object($output)) $output = json_encode($output);
- if($this->debug)
- {
- $this->log("encrypt: " . $output);
- }
- if($this->enableAES) $output = $this->aes->encrypt($output);
- return helper::removeUTF8Bom($output);
- }
- /**
- * Decode input params.
- *
- * @param array $input
- * @access public
- * @return array
- */
- public function decodeInput($inputArray)
- {
- list($api, $input) = $inputArray;
- $maps = zget($this->config->maps, $api, array());
- /* Using requestPack as fallback maps */
- if(empty($maps)) $maps = zget($this->config->maps, 'requestPack', array());
- if($this->debug && empty($maps))
- {
- $this->log("warning: decode maps is empty for api \"$api\"");
- }
- $decodedParams = self::decodeArray($maps, $input);
- if($this->debug)
- {
- $this->log("decode input($api): " . json_encode($decodedParams));
- }
- return $decodedParams;
- }
- /**
- * Decode array to assorted array.
- *
- * @param array $maps
- * @param array $data
- * @static
- * @access public
- * @return array
- */
- public static function decodeArray($maps, $data)
- {
- $params = array();
- if(empty($maps)) return array();
- /* $maps should be a type with dataType set. */
- foreach($maps['dataType'] as $key => $prop)
- {
- /* Skip extra dataTypes that do not exist in the $data array. */
- if(!isset($data[$key])) continue;
- /* Basic type may contain options that allow using an index to represent a value defined in the scheme. */
- if($prop['type'] == 'basic')
- {
- if(isset($prop['options']))
- {
- $params[$prop['name']] = zget($prop['options'], $data[$key]);
- }
- else
- {
- $params[$prop['name']] = zget($data, $key, '');
- }
- continue;
- }
- /* Object type may have a dataType of nested or mixed types. */
- if($prop['type'] == 'object')
- {
- $params[$prop['name']] = self::decodeArray($prop, $data[$key]);
- continue;
- }
- /* List type describes an array of its dataType instances. */
- if($prop['type'] == 'list')
- {
- $params[$prop['name']] = self::decodeArray(array('dataType' => array($prop['dataType'])), $data[$key]);
- }
- }
- return $params;
- }
- /**
- * Output message with echo.
- *
- * @param string $message
- * @access public
- * @return void
- */
- public function output($message)
- {
- echo $message;
- }
- /**
- * Save a log.
- *
- * @param string $log
- * @param string $file
- * @param string $line
- * @access public
- * @return void
- */
- public function log($message, $file = '', $line = '')
- {
- $log = "\n" . date('H:i:s') . " $message";
- if($file) $log .= " in <strong>$file</strong>";
- if($line) $log .= " on line <strong>$line</strong> ";
- $file = $this->getLogRoot() . 'xuanxuan.' . date('Ymd') . '.log.php';
- if(!is_file($file)) file_put_contents($file, "<?php\n die();\n?>\n");
- $fh = @fopen($file, 'a');
- if($fh) fwrite($fh, $log) && fclose($fh);
- }
- }
|