control.class.php 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. <?php
  2. /**
  3. * ZenTaoPHP的baseControl类。
  4. * The baseControl class file of ZenTaoPHP framework.
  5. *
  6. * @package framework
  7. *
  8. * The author disclaims copyright to this source code. In place of
  9. * a legal notice, here is a blessing:
  10. *
  11. * May you do good and not evil.
  12. * May you find forgiveness for yourself and forgive others.
  13. * May you share freely, never taking more than you give.
  14. */
  15. class baseControl
  16. {
  17. /**
  18. * 全局对象 $app。
  19. * The global $app object.
  20. *
  21. * @var object
  22. * @access public
  23. */
  24. public $app;
  25. /**
  26. * 应用名称 $appName
  27. * The global $appName.
  28. *
  29. * @var string
  30. * @access public
  31. */
  32. public $appName;
  33. /**
  34. * 全局对象 $config。
  35. * The global $config object.
  36. *
  37. * @var object
  38. * @access public
  39. */
  40. public $config;
  41. /**
  42. * 全局对象 $lang。
  43. * The global $lang object.
  44. *
  45. * @var object
  46. * @access public
  47. */
  48. public $lang;
  49. /**
  50. * 全局对象 $dbh,数据库连接句柄。
  51. * The global $dbh object, the database connection handler.
  52. *
  53. * @var object
  54. * @access public
  55. */
  56. public $dbh;
  57. /**
  58. * $dao对象,实现sql的拼装和执行。
  59. * The $dao object, used to join sql and excute sql.
  60. *
  61. * @var dao
  62. * @access public
  63. */
  64. public $dao;
  65. /**
  66. * $post对象,用户可以通过$this->post->key来引用$_POST变量。
  67. * The $post object, useer can access a post var by $this->post->key.
  68. *
  69. * @var object
  70. * @access public
  71. */
  72. public $post;
  73. /**
  74. * $get对象,用户可以通过$this->get->key来引用$_GET变量。
  75. * The $get object, useer can access a get var by $this->get->key.
  76. *
  77. * @var object
  78. * @access public
  79. */
  80. public $get;
  81. /**
  82. * $session对象,用户可以通过$this->session->key来引用$_SESSION变量。
  83. * The $session object, useer can access a session var by $this->session->key.
  84. *
  85. * @var object
  86. * @access public
  87. */
  88. public $session;
  89. /**
  90. * $server对象,用户可以通过$this->server->key来引用$_SERVER变量。
  91. * The $server object, useer can access a server var by $this->server->key.
  92. *
  93. * @var object
  94. * @access public
  95. */
  96. public $server;
  97. /**
  98. * $cookie对象,用户可以通过$this->cookie->key来引用$_COOKIE变量。
  99. * The $cookie object, user can access a cookie var by $this->cookie->key.
  100. *
  101. * @var object
  102. * @access public
  103. */
  104. public $cookie;
  105. /**
  106. * 当前模块的名称。
  107. * The name of current module.
  108. *
  109. * @var string
  110. * @access public
  111. */
  112. public $moduleName;
  113. /**
  114. * $view用于存放从control传到view视图的数据。
  115. * The vars assigned to the view page.
  116. *
  117. * @var object
  118. * @access public
  119. */
  120. public $view;
  121. /**
  122. * 视图的类型,比如html, json。
  123. * The type of the view, such html, json.
  124. *
  125. * @var string
  126. * @access public
  127. */
  128. public $viewType;
  129. /**
  130. * 输出到浏览器的内容。
  131. * The content to display.
  132. *
  133. * @var string
  134. * @access public
  135. */
  136. public $output;
  137. /**
  138. * 客户端设备。
  139. * The client device.
  140. *
  141. * @var string
  142. * @access public
  143. */
  144. public $clientDevice;
  145. /**
  146. * 不同设备下视图文件的前缀。
  147. * The prefix of view file for mobile or PC.
  148. *
  149. * @var string
  150. * @access public
  151. */
  152. public $devicePrefix;
  153. /**
  154. * $mao对象,用于访问缓存。
  155. * The $mao object, used to access the cache.
  156. *
  157. * @var object
  158. * @access public
  159. */
  160. public $mao;
  161. /**
  162. * 构造方法。
  163. *
  164. * 1. 将全局变量设为baseControl类的成员变量,方便baseControl的派生类调用;
  165. * 2. 设置当前模块,读取该模块的model类;
  166. * 3. 初始化$view视图类。
  167. *
  168. * The construct function.
  169. *
  170. * 1. global the global vars, refer them by the class member such as $this->app.
  171. * 2. set the paths of current module, and load it's model class.
  172. * 3. auto assign the $lang and $config to the view.
  173. *
  174. * @param string $moduleName
  175. * @param string $methodName
  176. * @param string $appName
  177. * @access public
  178. * @return void
  179. */
  180. public function __construct($moduleName = '', $methodName = '', $appName = '')
  181. {
  182. /*
  183. * 将全局变量设为baseControl类的成员变量,方便baseControl的派生类调用。
  184. * Global the globals, and refer them as a class member.
  185. */
  186. global $app, $config, $lang, $dbh, $common;
  187. $this->app = $app;
  188. $this->config = $config;
  189. $this->lang = $lang;
  190. $this->dbh = $dbh;
  191. $this->mao = $app->mao;
  192. $this->viewType = $this->app->getViewType();
  193. $this->appName = $appName ?: $this->app->getAppName();
  194. /**
  195. * 设置当前模块,读取该模块的model类。
  196. * Load the model file auto.
  197. */
  198. $this->setModuleName($moduleName);
  199. $this->setMethodName($methodName);
  200. $this->loadModel($this->moduleName, $appName);
  201. /**
  202. * 检查用户是否登录,如果没有登录,跳转到登录页面。
  203. * Check the user has logon or not, if not, goto the login page.
  204. */
  205. if($this->config->installed && !in_array($this->moduleName, $this->config->openModules) && empty($this->app->user) && !$this->loadModel('common')->isOpenMethod($this->moduleName, $this->methodName))
  206. {
  207. $uri = $this->app->getURI(true);
  208. if($this->moduleName == 'message' and $this->methodName == 'ajaxgetmessage')
  209. {
  210. $uri = helper::createLink('my');
  211. }
  212. else if(isInModal())
  213. {
  214. helper::end(json_encode(array('result' => 'fail', 'load' => true)));
  215. }
  216. else if(helper::isAjaxRequest())
  217. {
  218. helper::end(json_encode(array('result' => false, 'message' => $this->lang->error->loginTimeout, 'load' => 'login')));
  219. }
  220. $referer = helper::safe64Encode($uri);
  221. $this->locate(helper::createLink('user', 'login', "referer=$referer"));
  222. }
  223. /**
  224. * 如果客户端是手机的话,视图文件增加m.前缀。
  225. * If the client is mobile, add m. as prefix for view file.
  226. */
  227. $this->setClientDevice();
  228. $this->setDevicePrefix();
  229. /**
  230. * 初始化$view视图类。
  231. * Init the view vars.
  232. */
  233. $this->view = new stdclass();
  234. $this->view->app = $app;
  235. $this->view->lang = $lang;
  236. $this->view->config = $config;
  237. $this->view->common = $common;
  238. $this->view->title = '';
  239. /**
  240. * 设置超级变量,从$app引用过来。
  241. * Set super vars.
  242. */
  243. $this->setSuperVars();
  244. /**
  245. * 读取当前模块的zen类。
  246. * Load the zen file auto.
  247. */
  248. $zenClass = $this->moduleName . 'Zen';
  249. $selfClass = static::class;
  250. $parentClasses = class_parents($this);
  251. if($selfClass != $zenClass && !isset($parentClasses[$zenClass])) $this->loadZen($this->moduleName, $appName);
  252. }
  253. //-------------------- Model相关方法(Model related methods) --------------------//
  254. /*
  255. * 设置模块名。
  256. * Set the module name.
  257. *
  258. * @param string $moduleName 模块名,如果为空,则从$app中获取. The module name, if empty, get it from $app.
  259. * @access public
  260. * @return void
  261. */
  262. /**
  263. * @param string $moduleName
  264. */
  265. public function setModuleName($moduleName = '')
  266. {
  267. $this->moduleName = $moduleName ? strtolower((string) $moduleName) : $this->app->getModuleName();
  268. }
  269. /**
  270. * 设置方法名。
  271. * Set the method name.
  272. *
  273. * @param string $methodName 方法名,如果为空,则从$app中获取。The method name, if empty, get it from $app.
  274. * @access public
  275. * @return void
  276. */
  277. public function setMethodName($methodName = '')
  278. {
  279. $this->methodName = $methodName ? strtolower($methodName) : $this->app->getMethodName();
  280. }
  281. /**
  282. * 加载一个模块的model对象。加载完成后,使用$this->$moduleName来访问这个model对象。
  283. * 比如:loadModel('user')引入user模块的model实例对象,可以通过$this->user来访问它。
  284. *
  285. * Load the model object of one module. After loaded, can use $this->$moduleName to visit the model object.
  286. *
  287. * @param string $moduleName 模块名,如果为空,使用当前模块。The module name, if empty, use current module's name.
  288. * @param string $appName 应用名,如果为空,使用当前应用。The app name, if empty, use current app's name.
  289. * @access public
  290. * @return object|bool 如果没有model文件,返回false,否则返回model对象。If no model file, return false, else return the model object.
  291. */
  292. public function loadModel($moduleName = '', $appName = '')
  293. {
  294. $model = $this->app->loadTarget($moduleName, $appName);
  295. /**
  296. * 如果加载model失败,尝试加载config, lang配置信息。
  297. * If model is not loaded, try load config and lang.
  298. */
  299. if(!$model)
  300. {
  301. $this->app->loadModuleConfig($moduleName, $appName);
  302. $this->app->loadLang($moduleName, $appName);
  303. $this->dao = new dao($this->app);
  304. return false;
  305. }
  306. $this->{$moduleName} = $model;
  307. $this->dao = $model->dao;
  308. return $model;
  309. }
  310. /**
  311. * 加载一个模块的zen对象。加载完成后,使用$this->{$moduleName}Zen来访问这个zen对象。
  312. * 比如:loadZen('user')引入user模块的zen实例对象,可以通过$this->userZen来访问它。
  313. *
  314. * Load the zen object of one module. After loaded, can use $this->{$moduleName}Zen to visit the zen object.
  315. *
  316. * @param string $moduleName 模块名,如果为空,使用当前模块。The module name, if empty, use current module's name.
  317. * @param string $appName 应用名,如果为空,使用当前应用。The app name, if empty, use current app's name.
  318. * @access public
  319. * @return object|bool 如果没有zen文件,返回false,否则返回zen对象。If no zen file, return false, else return the zen object.
  320. */
  321. public function loadZen($moduleName = '', $appName = '')
  322. {
  323. $zen = $this->app->loadTarget($moduleName, $appName, 'zen');
  324. if(!$zen) return false;
  325. $zen->view = $this->view;
  326. $zenObjectName = $moduleName . 'Zen';
  327. $this->{$zenObjectName} = $zen;
  328. return $zen;
  329. }
  330. /**
  331. * 设置超级全局变量,方便直接引用。
  332. * Set the super vars.
  333. *
  334. * @access public
  335. * @return void
  336. */
  337. public function setSuperVars()
  338. {
  339. $this->post = $this->app->post;
  340. $this->get = $this->app->get;
  341. $this->server = $this->app->server;
  342. $this->session = $this->app->session;
  343. $this->cookie = $this->app->cookie;
  344. }
  345. /**
  346. * 设置客户端的设备类型。
  347. * Set client device.
  348. *
  349. * @access public
  350. * @return void
  351. */
  352. public function setClientDevice()
  353. {
  354. $this->clientDevice = $this->app->clientDevice;
  355. }
  356. /**
  357. * 如果客户端是手机的话,视图文件增加m.前缀。
  358. * If the client is mobile, add m. as prefix for view file.
  359. *
  360. * @access public
  361. * @return void
  362. */
  363. public function setDevicePrefix()
  364. {
  365. $this->devicePrefix = zget($this->config->devicePrefix, $this->viewType, '');
  366. }
  367. //-------------------- 视图相关方法(View related methods) --------------------//
  368. /**
  369. * 设置视图文件:主视图文件,扩展视图文件, 站点扩展视图文件,以及钩子脚本。
  370. * Set view files: the main file, extension view file, site extension view file and hook files.
  371. *
  372. * @param string $moduleName module name
  373. * @param string $methodName method name
  374. * @param string $viewDir
  375. * @access public
  376. * @return string the view file
  377. */
  378. public function setViewFile($moduleName, $methodName, $viewDir = 'view')
  379. {
  380. $moduleName = strtolower(trim($moduleName));
  381. $methodName = strtolower(trim($methodName));
  382. $modulePath = $this->app->getModulePath($this->appName, $moduleName);
  383. $viewExtPath = $this->app->getModuleExtPath($moduleName, $viewDir);
  384. $viewType = $this->viewType == 'mhtml' ? 'html' : $this->viewType;
  385. $mainViewFile = $modulePath . $viewDir . DS . $this->devicePrefix . $methodName . '.' . $viewType . '.php';
  386. $viewFile = $mainViewFile;
  387. if(!empty($viewExtPath))
  388. {
  389. $commonExtViewFile = $viewExtPath['common'] . $this->devicePrefix . $methodName . ".{$viewType}.php";
  390. $siteExtViewFile = empty($viewExtPath['site']) ? '' : $viewExtPath['site'] . $this->devicePrefix . $methodName . ".{$viewType}.php";
  391. $viewFile = file_exists($commonExtViewFile) ? $commonExtViewFile : $mainViewFile;
  392. $viewFile = (!empty($siteExtViewFile) and file_exists($siteExtViewFile)) ? $siteExtViewFile : $viewFile;
  393. if(!is_file($viewFile)) $this->app->triggerError("the view file $viewFile not found", __FILE__, __LINE__, true);
  394. $commonExtHookFiles = glob($viewExtPath['common'] . $this->devicePrefix . $methodName . ".*.{$viewType}.hook.php");
  395. $siteExtHookFiles = empty($viewExtPath['site']) ? '' : glob($viewExtPath['site'] . $this->devicePrefix . $methodName . ".*.{$viewType}.hook.php");
  396. $extHookFiles = array_merge((array)$commonExtHookFiles, (array)$siteExtHookFiles);
  397. }
  398. if(!empty($extHookFiles)) return array('viewFile' => $viewFile, 'hookFiles' => $extHookFiles);
  399. return $viewFile;
  400. }
  401. /**
  402. * 获取某一个视图文件的扩展。
  403. * Get the extension file of an view.
  404. *
  405. * @param string $viewFile
  406. * @access public
  407. * @return string|bool If extension view file exists, return the path. Else return fasle.
  408. */
  409. public function getExtViewFile($viewFile)
  410. {
  411. /**
  412. * 首先找sitecode下的扩展文件,如果没有,再找ext下的扩展文件。
  413. * Find extViewFile in ext/_$siteCode/view first, then try ext/view/.
  414. */
  415. $moduleName = basename(dirname(realpath($viewFile), 2));
  416. $extPath = $this->app->getModuleExtPath($moduleName, 'view');
  417. $checkedOrder = array('site', 'saas', 'custom', 'vision', 'xuan', 'common');
  418. $fileName = basename($viewFile);
  419. foreach($checkedOrder as $checkedType)
  420. {
  421. if(!empty($extPath[$checkedType]))
  422. {
  423. $extViewFile = $extPath[$checkedType] . $fileName;
  424. if(file_exists($extViewFile))
  425. {
  426. helper::cd($extPath[$checkedType]);
  427. return $extViewFile;
  428. }
  429. }
  430. }
  431. return false;
  432. }
  433. /**
  434. * 获取适用于当前方法的css:该模块公用的css + 当前方法的css + 扩展的css。
  435. * Get css codes applied to current method: module common css + method css + extension css.
  436. *
  437. * @param string $moduleName
  438. * @param string $methodName
  439. * @param string $suffix
  440. * @access public
  441. * @return string
  442. */
  443. public function getCSS($moduleName, $methodName, $suffix = '')
  444. {
  445. $moduleName = strtolower(trim($moduleName));
  446. $methodName = strtolower(trim($methodName));
  447. $modulePath = $this->app->getModulePath($this->appName, $moduleName);
  448. $cssExtPath = $this->app->getModuleExtPath($moduleName, 'css');
  449. $clientLang = $this->app->getClientLang();
  450. $notCNLang = strpos('|zh-cn|zh-tw|', "|{$clientLang}|") === false;
  451. $css = '';
  452. $devicePrefix = $this->devicePrefix;
  453. $mainCssPath = $modulePath . 'css' . DS;
  454. /* Common css file. like module/story/css/common.css. */
  455. $mainCssFile = $mainCssPath . $devicePrefix . "common{$suffix}.css";
  456. if(is_file($mainCssFile)) $css .= file_get_contents($mainCssFile);
  457. /* Common css file with lang. like module/story/css/common.en.css. */
  458. $mainCssLangFile = $mainCssPath . $devicePrefix . "common.{$clientLang}{$suffix}.css";
  459. if(!file_exists($mainCssLangFile) and $notCNLang) $mainCssLangFile = $mainCssPath . $devicePrefix . "common{$suffix}.en.css";
  460. if(is_file($mainCssLangFile)) $css .= file_get_contents($mainCssLangFile);
  461. /* Method css file. like module/story/css/create.css. */
  462. $methodCssFile = $mainCssPath . $devicePrefix . $methodName . "$suffix.css";
  463. if(is_file($methodCssFile)) $css .= file_get_contents($methodCssFile);
  464. /* Method css file with lang. like module/story/css/create.en.css. */
  465. $methodCssLangFile = $mainCssPath . $devicePrefix . "{$methodName}{$suffix}.{$clientLang}.css";
  466. if(!file_exists($methodCssLangFile) and $notCNLang) $methodCssLangFile = $mainCssPath . $devicePrefix . "{$methodName}{$suffix}.en.css";
  467. if(is_file($methodCssLangFile)) $css .= file_get_contents($methodCssLangFile);
  468. if(!empty($cssExtPath))
  469. {
  470. foreach($cssExtPath as $cssPath)
  471. {
  472. if(empty($cssPath)) continue;
  473. $cssMethodExt = $cssPath . $methodName . DS;
  474. $cssCommonExt = $cssPath . 'common' . DS;
  475. $cssExtFiles = glob($cssCommonExt . $devicePrefix . "*{$suffix}.css");
  476. if(!empty($cssExtFiles) and is_array($cssExtFiles)) $css .= $this->getExtCSS($cssExtFiles, $suffix);
  477. $cssExtFiles = glob($cssMethodExt . $devicePrefix . "*{$suffix}.css");
  478. if(!empty($cssExtFiles) and is_array($cssExtFiles)) $css .= $this->getExtCSS($cssExtFiles, $suffix);
  479. }
  480. }
  481. return $css;
  482. }
  483. /**
  484. * Get extension css and extension css with lang.
  485. *
  486. * @param array $files
  487. * @param string $suffix
  488. * @access public
  489. * @return string
  490. */
  491. public function getExtCSS($files, $suffix = '')
  492. {
  493. $clientLang = $this->app->getClientLang();
  494. $notCNLang = strpos('|zh-cn|zh-tw|', "|{$clientLang}|") === false;
  495. $filePairs = array();
  496. foreach($files as $cssFile)
  497. {
  498. $fileName = basename((string) $cssFile);
  499. $filePairs[$fileName] = $cssFile;
  500. }
  501. $css = '';
  502. $usedCodes = array();
  503. foreach($filePairs as $fileName => $cssFile)
  504. {
  505. if(preg_match('/^\w+\.css$/', $fileName))
  506. {
  507. /* Method extension css file. like module/story/ext/css/create/effort.css. */
  508. $css .= file_get_contents($cssFile);
  509. [$code] = explode('.', $fileName);
  510. }
  511. else
  512. {
  513. [$code] = explode('.', $fileName);
  514. if(isset($usedCodes[$code])) continue;
  515. }
  516. /* Method extension css file. like module/story/ext/css/create/effort.zh-cn.css. */
  517. if(isset($filePairs["{$code}{$suffix}.css"])) $css .= file_get_contents($filePairs["{$code}{$suffix}.css"]);
  518. if(isset($filePairs["{$code}.{$clientLang}{$suffix}.css"])) $css .= file_get_contents($filePairs["{$code}.{$clientLang}{$suffix}.css"]);
  519. if($notCNLang and isset($filePairs["{$code}.en{$suffix}.css"])) $css .= file_get_contents($filePairs["{$code}.en{$suffix}.css"]);
  520. $usedCodes[$code] = $code;
  521. }
  522. return $css;
  523. }
  524. /**
  525. * 获取适用于当前方法的js:该模块公用的js + 当前方法的js + 扩展的js。
  526. * Get js codes applied to current method: module common js + method js + extension js.
  527. *
  528. * @param string $moduleName
  529. * @param string $methodName
  530. * @access public
  531. * @return string
  532. * @param string $suffix
  533. */
  534. public function getJS($moduleName, $methodName, $suffix = '')
  535. {
  536. $moduleName = strtolower(trim($moduleName));
  537. $methodName = strtolower(trim($methodName));
  538. $modulePath = $this->app->getModulePath($this->appName, $moduleName);
  539. $jsExtPath = $this->app->getModuleExtPath($moduleName, 'js');
  540. $js = '';
  541. $mainJsFile = $modulePath . 'js' . DS . $this->devicePrefix . "common{$suffix}.js";
  542. $methodJsFile = $modulePath . 'js' . DS . $this->devicePrefix . $methodName . $suffix . '.js';
  543. if(file_exists($mainJsFile)) $js .= file_get_contents($mainJsFile);
  544. if(is_file($methodJsFile)) $js .= file_get_contents($methodJsFile);
  545. if(!empty($jsExtPath))
  546. {
  547. foreach($jsExtPath as $jsPath)
  548. {
  549. if(empty($jsPath)) continue;
  550. $jsMethodExt = $jsPath . $methodName . DS;
  551. $jsCommonExt = $jsPath . 'common' . DS;
  552. $jsExtFiles = glob($jsCommonExt . $this->devicePrefix . "*{$suffix}.js");
  553. if(!empty($jsExtFiles) and is_array($jsExtFiles)) foreach($jsExtFiles as $jsFile) $js .= file_get_contents($jsFile);
  554. $jsExtFiles = glob($jsMethodExt . $this->devicePrefix . "*{$suffix}.js");
  555. if(!empty($jsExtFiles) and is_array($jsExtFiles)) foreach($jsExtFiles as $jsFile) $js .= file_get_contents($jsFile);
  556. }
  557. }
  558. return $js;
  559. }
  560. /**
  561. * 向$view传递一个变量。
  562. * Assign one var to the view vars.
  563. *
  564. * @param string $name the name.
  565. * @param mixed $value the value.
  566. * @access public
  567. * @return void
  568. */
  569. public function assign($name, $value)
  570. {
  571. $this->view->$name = $value;
  572. }
  573. /**
  574. * 清空$output。
  575. * Clear the output.
  576. *
  577. * @access public
  578. * @return void
  579. */
  580. public function clear()
  581. {
  582. $this->output = '';
  583. }
  584. /**
  585. * 渲染视图文件。
  586. * Parse view file.
  587. *
  588. * @param string $moduleName module name, if empty, use current module.
  589. * @param string $methodName method name, if empty, use current method.
  590. * @access public
  591. * @return string the parsed result.
  592. */
  593. public function parse($moduleName = '', $methodName = '')
  594. {
  595. if(empty($moduleName)) $moduleName = $this->moduleName;
  596. if(empty($methodName)) $methodName = $this->methodName;
  597. if($this->viewType == 'json') $this->parseJSON($moduleName, $methodName);
  598. if($this->viewType != 'json') $this->parseDefault($moduleName, $methodName);
  599. return $this->output;
  600. }
  601. /**
  602. * 渲染json格式。
  603. * Parse json format.
  604. *
  605. * @param string $moduleName module name
  606. * @param string $methodName method name
  607. * @access public
  608. * @return void
  609. */
  610. public function parseJSON($moduleName, $methodName)
  611. {
  612. $output = array();
  613. unset($this->view->app);
  614. unset($this->view->config);
  615. unset($this->view->lang);
  616. unset($this->view->header);
  617. unset($this->view->position);
  618. unset($this->view->moduleTree);
  619. unset($this->view->common);
  620. unset($this->view->pager->app);
  621. unset($this->view->pager->lang);
  622. $output['status'] = is_object($this->view) ? 'success' : 'fail';
  623. $output['data'] = json_encode($this->view) ? json_encode($this->view) : '';
  624. $output['md5'] = md5($output['data']);
  625. $this->output = json_encode($output);
  626. }
  627. /**
  628. * 默认渲染方法,适用于viewType = html的时候。
  629. * Default parse method when viewType != json, like html.
  630. *
  631. * @param string $moduleName module name
  632. * @param string $methodName method name
  633. * @access public
  634. * @return void
  635. */
  636. public function parseDefault($moduleName, $methodName)
  637. {
  638. /**
  639. * 设置视图文件。(PHP7有一个bug,不能直接$viewFile = $this->setViewFile())。
  640. * Set viewFile. (Can't assign $viewFile = $this->setViewFile() directly because one php7's bug.)
  641. */
  642. $results = $this->setViewFile($moduleName, $methodName);
  643. $viewFile = $results;
  644. if(is_array($results)) extract($results);
  645. /**
  646. * 获得当前页面的CSS和JS。
  647. * Get css and js codes for current method.
  648. */
  649. $css = $this->getCSS($moduleName, $methodName);
  650. $js = $this->getJS($moduleName, $methodName);
  651. if($css) $this->view->pageCSS = $css;
  652. if($js) $this->view->pageJS = $js;
  653. /**
  654. * 切换到视图文件所在的目录,以保证视图文件里面的include语句能够正常运行。
  655. * Change the dir to the view file to keep the relative paths work.
  656. */
  657. $currentPWD = getcwd();
  658. chdir(dirname($viewFile));
  659. /**
  660. * 使用extract和ob方法渲染$viewFile里面的代码。
  661. * Use extract and ob functions to eval the codes in $viewFile.
  662. */
  663. extract((array)$this->view);
  664. ob_start();
  665. include $viewFile;
  666. if(isset($hookFiles)) foreach($hookFiles as $hookFile) if(file_exists($hookFile)) include $hookFile;
  667. $this->setResponseHeader();
  668. $this->output .= ob_get_contents();
  669. ob_end_clean();
  670. /**
  671. * 渲染完毕后,再切换回之前的路径。
  672. * At the end, chang the dir to the previous.
  673. */
  674. chdir($currentPWD);
  675. }
  676. /**
  677. * 获取一个方法的输出内容,这样我们可以在一个方法里获取其他模块方法的内容。
  678. * 如果模块名为空,则调用该模块、该方法;如果设置了模块名,调用指定模块指定方法。
  679. *
  680. * Get the output of one module's one method as a string, thus in one module's method, can fetch other module's content.
  681. * If the module name is empty, then use the current module and method. If set, use the user defined module and method.
  682. *
  683. * @param string $moduleName module name.
  684. * @param string $methodName method name.
  685. * @param array|string $params params.
  686. * @access public
  687. * @return string the parsed html.
  688. * @param string $appName
  689. */
  690. public function fetch($moduleName = '', $methodName = '', $params = array(), $appName = '')
  691. {
  692. /**
  693. * 如果模块名为空,则调用该模块、该方法。
  694. * If the module name is empty, then use the current module and method.
  695. */
  696. if($moduleName == '') $moduleName = $this->moduleName;
  697. if($methodName == '') $methodName = $this->methodName;
  698. if($appName == '') $appName = $this->appName;
  699. if($moduleName == $this->moduleName and $methodName == $this->methodName)
  700. {
  701. $this->parse($moduleName, $methodName);
  702. return $this->output;
  703. }
  704. $currentModuleName = $this->moduleName;
  705. $currentMethodName = $this->methodName;
  706. $currentParams = $this->app->getParams();
  707. /**
  708. * 设置调用指定模块的指定方法。
  709. * chang the dir to the previous.
  710. */
  711. $this->app->setModuleName($moduleName);
  712. $this->app->setMethodName($methodName);
  713. $this->app->setControlFile();
  714. $fetchParams = array();
  715. if(!is_array($params))
  716. {
  717. parse_str($params, $params);
  718. $defaultParams = $this->app->getDefaultParams();
  719. $this->app->params = empty($defaultParams) ? array() : $this->app->mergeParams($defaultParams, $params);
  720. /*
  721. * 设置要fetch的方法的参数类型。
  722. * Set fetch method param type.
  723. */
  724. $paramKeys = array_keys($this->app->params);
  725. $keyIndex = 0;
  726. foreach($params as $param => $value)
  727. {
  728. if(empty($paramKeys[$keyIndex])) break;
  729. $paramKey = $paramKeys[$keyIndex];
  730. settype($value, gettype($this->app->params[$paramKey]));
  731. $fetchParams[] = $value;
  732. $keyIndex ++;
  733. }
  734. }
  735. else
  736. {
  737. $params = array_values($params);
  738. $fetchParams = $params;
  739. $this->app->params = $params;
  740. }
  741. $currentPWD = getcwd();
  742. /**
  743. * 设置引用的文件和路径。
  744. * Set the paths and files to included.
  745. */
  746. $modulePath = $this->app->getModulePath($appName, $moduleName);
  747. $moduleControlFile = $modulePath . 'control.php';
  748. $actionExtPath = $this->app->getModuleExtPath($moduleName, 'control');
  749. $file2Included = $moduleControlFile;
  750. if(!empty($actionExtPath))
  751. {
  752. /**
  753. * 设置公共扩展。
  754. * set common extension.
  755. */
  756. $file2Included = $moduleControlFile;
  757. if(!empty($actionExtPath['common']))
  758. {
  759. $commonActionExtFile = $actionExtPath['common'] . strtolower((string) $methodName) . '.php';
  760. if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
  761. }
  762. if(!empty($actionExtPath['xuan']))
  763. {
  764. $commonActionExtFile = $actionExtPath['xuan'] . strtolower((string) $methodName) . '.php';
  765. if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
  766. }
  767. if(!empty($actionExtPath['vision']))
  768. {
  769. $commonActionExtFile = $actionExtPath['vision'] . strtolower((string) $methodName) . '.php';
  770. if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
  771. }
  772. $commonActionExtFile = $actionExtPath['custom'] . strtolower((string) $methodName) . '.php';
  773. if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
  774. if(!empty($actionExtPath['saas']))
  775. {
  776. $commonActionExtFile = $actionExtPath['saas'] . strtolower((string) $methodName) . '.php';
  777. if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
  778. }
  779. if(!empty($actionExtPath['site']))
  780. {
  781. /**
  782. * 设置站点扩展。
  783. * every site has it's extension.
  784. */
  785. $siteActionExtFile = $actionExtPath['site'] . strtolower((string) $methodName) . '.php';
  786. $file2Included = file_exists($siteActionExtFile) ? $siteActionExtFile : $file2Included;
  787. }
  788. }
  789. /**
  790. * 加载控制器文件。
  791. * Load the control file.
  792. */
  793. if(!is_file($file2Included)) $this->app->triggerError("The control file $file2Included not found", __FILE__, __LINE__, true);
  794. chdir(dirname($file2Included));
  795. helper::import($file2Included);
  796. /**
  797. * 设置调用的类名。
  798. * Set the name of the class to be called.
  799. */
  800. $className = class_exists("my$moduleName") ? "my$moduleName" : $moduleName;
  801. if(!class_exists($className)) $this->app->triggerError(" The class $className not found", __FILE__, __LINE__, true);
  802. /**
  803. * 解析参数,创建模块control对象。
  804. * Parse the params, create the $module control object.
  805. */
  806. $module = new $className($moduleName, $methodName, $appName);
  807. $module->viewType = $this->viewType;
  808. /**
  809. * 调用对应方法,使用ob方法获取输出内容。
  810. * Call the method and use ob function to get the output.
  811. */
  812. ob_start();
  813. call_user_func_array(array($module, $methodName), $fetchParams);
  814. $output = ob_get_contents();
  815. if(ob_get_level() > 0) ob_end_clean();
  816. unset($module);
  817. /**
  818. * 切换回之前的模块和方法。
  819. * Chang the module、method to the previous.
  820. */
  821. $this->app->setModuleName($currentModuleName);
  822. $this->app->setMethodName($currentMethodName);
  823. $this->app->params = $currentParams;
  824. chdir($currentPWD);
  825. /**
  826. * 返回内容。
  827. * Return the content.
  828. */
  829. return $output;
  830. }
  831. /**
  832. * 向浏览器输出内容。
  833. * Print the content of the view.
  834. *
  835. * @param string $moduleName module name
  836. * @param string $methodName method name
  837. * @access public
  838. * @return void
  839. */
  840. public function display($moduleName = '', $methodName = '')
  841. {
  842. if($this->viewType === 'html' && (!isset($_GET['zin']) || $_GET['zin'] != '0'))
  843. {
  844. if(empty($moduleName)) $moduleName = $this->moduleName;
  845. if(empty($methodName)) $methodName = $this->methodName;
  846. $modulePath = $this->app->getModulePath($this->appName, $moduleName);
  847. $viewType = $this->viewType == 'mhtml' ? 'html' : $this->viewType;
  848. $mainViewFile = $modulePath . 'ui' . DS . $this->devicePrefix . strtolower($methodName) . '.' . $viewType . '.php';
  849. if($moduleName != 'index') $this->app->loadModuleConfig('index');
  850. if(!in_array("{$moduleName}-{$methodName}", $this->config->index->oldPages)) return $this->render($moduleName, $methodName);
  851. }
  852. if(empty($this->output)) $this->parse($moduleName, $methodName);
  853. echo $this->output;
  854. }
  855. /**
  856. * 向浏览器输出内容。
  857. * Print the content of the view.
  858. *
  859. * @param string $moduleName module name
  860. * @param string $methodName method name
  861. * @access public
  862. * @return void
  863. */
  864. public function render($moduleName = '', $methodName = '')
  865. {
  866. if(isset($_GET['zin']) && $_GET['zin'] == '0')
  867. {
  868. $this->display($moduleName, $methodName);
  869. return;
  870. }
  871. if(empty($moduleName)) $moduleName = $this->moduleName;
  872. if(empty($methodName)) $methodName = $this->methodName;
  873. /* Load zin lib */
  874. $this->app->loadClass('zin', true);
  875. \zin\loadConfig();
  876. /**
  877. * 设置视图文件。(PHP7有一个bug,不能直接$viewFile = $this->setViewFile())。
  878. * Set viewFile. (Can't assign $viewFile = $this->setViewFile() directly because one php7's bug.)
  879. */
  880. $results = $this->setViewFile($moduleName, $methodName, 'ui');
  881. $viewFile = $results;
  882. if(is_array($results)) extract($results);
  883. /**
  884. * 获得当前页面的CSS和JS。
  885. * Get css and js codes for current method.
  886. */
  887. $css = $this->getCSS($moduleName, $methodName, '.ui');
  888. $js = $this->getJS($moduleName, $methodName, '.ui');
  889. if($css) $this->view->pageCSS = $css;
  890. if($js) $this->view->pageJS = $js;
  891. /**
  892. * 切换到视图文件所在的目录,以保证视图文件里面的include语句能够正常运行。
  893. * Change the dir to the view file to keep the relative paths work.
  894. */
  895. $currentPWD = getcwd();
  896. chdir(dirname($viewFile));
  897. /**
  898. * Init zin context data.
  899. * 设置 zin 渲染上下文数据。
  900. */
  901. $context = \zin\context();
  902. $context->control = $this;
  903. $context->data = (array)$this->view;
  904. $context->data['zinDebug'] = array();
  905. if($this->config->debug && $this->config->debug >= 2 && $this->config->installed && $this->config->db->driver == 'mysql')
  906. {
  907. $context->data['zinDebug']['trace'] = $this->app->loadClass('trace')->getTrace();
  908. }
  909. /**
  910. * 使用extract和ob方法渲染$viewFile里面的代码。
  911. * Use extract and ob functions to eval the codes in $viewFile.
  912. */
  913. extract($context->data);
  914. /* 将 hooks 文件添加到当前 context 中。 */
  915. if(!empty($hookFiles)) $context->addHookFiles($hookFiles);
  916. /* 加载 common.field.php 和 method.field.php。 */
  917. $commonFieldFile = dirname($viewFile) . DS . 'common.field.php';
  918. $methodFieldFile = dirname($viewFile) . DS . $methodName . '.field.php';
  919. helper::import($commonFieldFile);
  920. helper::import($methodFieldFile);
  921. $this->setResponseHeader();
  922. ob_start();
  923. include $viewFile;
  924. if(!$context->rendered) \zin\renderPage();
  925. $content = ob_get_clean();
  926. ob_start();
  927. echo $content;
  928. /**
  929. * 渲染完毕后,再切换回之前的路径。
  930. * At the end, chang the dir to the previous.
  931. */
  932. chdir($currentPWD);
  933. }
  934. /**
  935. * 设置响应头。
  936. * Set response header.
  937. *
  938. * @access public
  939. * @return void
  940. */
  941. public function setResponseHeader()
  942. {
  943. if($this->app->isServing() && $this->config->cache->client->enable && $this->app->useClientCache)
  944. {
  945. helper::setStatus(304);
  946. helper::end();
  947. }
  948. helper::header('X-Zin-Cache-Time', strval(time()- 1));
  949. }
  950. /**
  951. * 直接输出data数据,通常用于ajax请求中。
  952. * Send data directly, for ajax requests.
  953. *
  954. * @param mixed $data
  955. * @param string $type
  956. * @access public
  957. * @return void
  958. */
  959. public function send($data, $type = 'json')
  960. {
  961. if($type != 'json') return helper::end();
  962. $data = (array)$data;
  963. /* Make sure locate in this tab. */
  964. global $lang;
  965. $moduleName = $this->app->rawModule;
  966. $notSameTab = isset($lang->navGroup->{$moduleName}) && $lang->navGroup->{$moduleName} != $this->app->tab;
  967. $hasLocate = !empty($data['locate']) && $data['locate'][0] == '/';
  968. if($notSameTab && $hasLocate && !helper::inOnlyBodyMode())
  969. {
  970. $data['locate'] .= "#app={$this->app->tab}";
  971. }
  972. if(helper::isAjaxRequest() || $this->viewType == 'json')
  973. {
  974. if(defined('RUN_MODE') && in_array(RUN_MODE, array('api', 'xuanxuan')))
  975. {
  976. print(json_encode($data, JSON_UNESCAPED_UNICODE));
  977. $response = helper::removeUTF8Bom(ob_get_clean());
  978. return print($response);
  979. }
  980. /* Zand will use ob_get_clean() to print, so cannot clean so early. */
  981. // $obLevel = ob_get_level();
  982. // for($i = 0; $i < $obLevel; $i++) ob_end_clean();
  983. $response = helper::removeUTF8Bom(json_encode($data, JSON_UNESCAPED_UNICODE));
  984. $this->app->outputXhprof();
  985. return helper::end($response);
  986. }
  987. /**
  988. * 响应非ajax的请求。
  989. * Response request not ajax.
  990. */
  991. if(isset($data['result']) && $data['result'] == 'success')
  992. {
  993. if(!empty($data['message'])) echo js::alert($data['message']);
  994. $locate = $data['locate'] ?? $_SERVER['HTTP_REFERER'] ?? '';
  995. if($locate && preg_match('/\(|\)|\'|\"|\[|\]|\{|\}|\<|\>/', $locate)) $locate = $this->config->webRoot;
  996. if(!empty($locate)) return helper::end(js::locate($locate));
  997. return helper::end($data['message'] ?? 'success');
  998. }
  999. if(isset($data['result']) && $data['result'] == 'fail')
  1000. {
  1001. if(!empty($data['message']))
  1002. {
  1003. if(is_string($data['message']))
  1004. {
  1005. echo js::alert($data['message']);
  1006. $locate = $data['locate'] ?? $_SERVER['HTTP_REFERER'] ?? '';
  1007. if($locate && preg_match('/\(|\)|\'|\"|\[|\]|\{|\}|\<|\>/', $locate)) $locate = $this->config->webRoot;
  1008. if (!empty($locate)) return helper::end(js::locate($locate));
  1009. return helper::end($data['message'] ?? 'fail');
  1010. }
  1011. $message = json_decode(json_encode($data['message']), true);
  1012. foreach($message as $item => $errors) $message[$item] = implode(',', $errors);
  1013. return helper::end(js::alert(strip_tags(implode('\n', $message))));
  1014. }
  1015. elseif((empty($_SERVER['HTTP_REFERER']) || $this->viewType == 'html') && !empty($data['load']['alert']))
  1016. {
  1017. if(empty($data['load']['locate'])) return helper::end(js::alert($data['load']['alert']));
  1018. return helper::end(js::alert($data['load']['alert']) . js::locate($data['load']['locate']));
  1019. }
  1020. return helper::end('fail');
  1021. }
  1022. }
  1023. /**
  1024. * return error json
  1025. *
  1026. * @param mixed $error
  1027. * @param string|bool $locate
  1028. * @return void
  1029. */
  1030. public function sendError($error, $locate = false)
  1031. {
  1032. $result = array('result' => 'fail');
  1033. if($locate)
  1034. {
  1035. if(empty($error)) $error = $this->lang->error->accessDenied;
  1036. $result['load'] = array('alert' => $error);
  1037. if(is_string($locate)) $result['load']['locate'] = $locate;
  1038. }
  1039. else
  1040. {
  1041. $result['message'] = $error;
  1042. }
  1043. return $this->send($result);
  1044. }
  1045. /**
  1046. * send success json
  1047. *
  1048. * @param array $data
  1049. * @return void
  1050. */
  1051. public function sendSuccess($data = array())
  1052. {
  1053. $data['result'] = 'success';
  1054. if(!isset($data['message'])) $data['message'] = $this->lang->saveSuccess;
  1055. if(!isset($data['closeModal']) && helper::isAjaxRequest('modal'))
  1056. {
  1057. $data['closeModal'] = true;
  1058. if(isset($data['load']) and $data['load'] !== true) unset($data['load']);
  1059. }
  1060. return $this->send($data);
  1061. }
  1062. /**
  1063. * 创建一个模块方法的链接。
  1064. * Create a link to one method of one module.
  1065. *
  1066. * @param string $moduleName module name
  1067. * @param string $methodName method name
  1068. * @param string|array $vars the params passed, can be array(key=>value) or key1=value1&key2=value2
  1069. * @param string $viewType the view type
  1070. * @param bool $onlybody remove header and footer or not in iframe
  1071. * @access public
  1072. * @return string the link string.
  1073. */
  1074. public function createLink($moduleName, $methodName = 'index', $vars = array(), $viewType = '', $onlybody = false)
  1075. {
  1076. if(empty($moduleName)) $moduleName = $this->moduleName;
  1077. return helper::createLink($moduleName, $methodName, $vars, $viewType, $onlybody);
  1078. }
  1079. /**
  1080. * 创建当前模块的一个方法链接。
  1081. * Create a link to the inner method of current module.
  1082. *
  1083. * @param string $methodName method name
  1084. * @param string|array $vars the params passed, can be array(key=>value) or key1=value1&key2=value2
  1085. * @param string $viewType the view type
  1086. * @param bool $onlybody remove header and footer or not in iframe
  1087. * @access public
  1088. * @return string the link string.
  1089. */
  1090. public function inlink($methodName = 'index', $vars = array(), $viewType = '', $onlybody = false)
  1091. {
  1092. return helper::createLink($this->moduleName, $methodName, $vars, $viewType, $onlybody);
  1093. }
  1094. /**
  1095. * 重定向到另一个页面。
  1096. * Location to another page.
  1097. *
  1098. * @param string $url the target url.
  1099. * @access public
  1100. * @return void
  1101. */
  1102. public function locate($url)
  1103. {
  1104. helper::header('location', $url);
  1105. helper::end();
  1106. }
  1107. }