control.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?php
  2. /**
  3. * The control file of misc of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Chunsheng Wang <chunsheng@cnezsoft.com>
  8. * @package misc
  9. * @version $Id: control.php 5128 2013-07-13 08:59:49Z chencongzhi520@gmail.com $
  10. * @link https://www.zentao.net
  11. */
  12. class misc extends control
  13. {
  14. /**
  15. * 保持心跳防止session过期。
  16. * Ping the server every 5 minutes to keep the session.
  17. *
  18. * @access public
  19. * @return void
  20. */
  21. public function ping()
  22. {
  23. if(empty($this->config->global->sn) && mt_rand(0, 1) == 1) $this->loadModel('setting')->setSN();
  24. }
  25. /**
  26. * 展示php服务器的配置信息。
  27. * Show php info.
  28. *
  29. * @access public
  30. * @return void
  31. */
  32. public function phpinfo()
  33. {
  34. phpinfo();
  35. }
  36. /**
  37. * 展示关于禅道页面。
  38. * Show about info of zentao.
  39. *
  40. * @access public
  41. * @return void
  42. */
  43. public function about()
  44. {
  45. $this->display();
  46. }
  47. /**
  48. * 检查是否存在更新的禅道版本。
  49. * Check current version is latest or not.
  50. *
  51. * @param string $sn
  52. * @param string $force
  53. * @access public
  54. * @return void
  55. */
  56. public function checkUpdate($sn = '', $force = '')
  57. {
  58. session_write_close();
  59. /* 检查服务端是否联网。 */
  60. $hasInternet = $this->session->hasInternet;
  61. if(empty($hasInternet))
  62. {
  63. $hasInternet = $this->loadModel('admin')->checkInternet();
  64. $this->session->set('hasInternet', $hasInternet);
  65. if(!$hasInternet) return;
  66. }
  67. if($this->session->isSlowNetwork) return;
  68. /* 检查距离上一次调用函数是否已超过1小时。 */
  69. $startTime = microtime(true);
  70. if(empty($force) && !empty($this->config->checkUpdate->lastTime) && $startTime - (float)$this->config->checkUpdate->lastTime < 3600) return;
  71. $this->loadModel('setting')->updateItem('system.common.checkUpdate.lastTime', (string)$startTime);
  72. if(empty($sn)) $sn = $this->loadModel('setting')->getItem('owner=system&module=common&section=global&key=sn');
  73. $website = $this->config->misc->api;
  74. if(isset($this->config->qcVersion)) $website = $this->config->misc->qucheng;
  75. if(isset($this->config->isINT)) $website = $this->config->misc->enApi;
  76. /* 获取禅道或者渠成的最新版本。 */
  77. $source = isset($this->config->qcVersion) ? 'qucheng' : 'zentao';
  78. $lang = str_replace('-', '_', $this->app->getClientLang());
  79. $link = $website . "/updater-getLatest-{$this->config->version}-$source-$lang-$sn.html";
  80. $data = $this->misc->getStatisticsForAPI();
  81. $latestVersionList = $this->misc->getLatestVersionList($link, $this->miscZen->encodeStatistics($data));
  82. if(!isset($this->config->global->latestVersionList) || $this->config->global->latestVersionList != $latestVersionList)
  83. {
  84. $this->loadModel('setting')->setItem('system.common.global.latestVersionList', $latestVersionList);
  85. }
  86. /* 请求超过一定时间后判断为网络请求缓慢。 */
  87. if(microtime(true) - $startTime > $this->config->timeout / 1000) $this->session->set('isSlowNetwork', true);
  88. }
  89. /**
  90. * 打印 hello world。
  91. * Check model extension logic.
  92. *
  93. * @access public
  94. * @return string
  95. */
  96. public function checkExtension()
  97. {
  98. echo $this->miscZen->hello();
  99. }
  100. /**
  101. * 下载桌面提醒。
  102. * Down notify.
  103. *
  104. * @access public
  105. * @return void
  106. */
  107. public function downNotify()
  108. {
  109. $notifyDir = $this->app->getBasePath() . 'tmp/cache/notify/';
  110. if(!is_dir($notifyDir))mkdir($notifyDir, 0755, true);
  111. $account = $this->app->user->account;
  112. $packageFile = $notifyDir . $account . 'notify.zip';
  113. $loginFile = $notifyDir . 'config.json';
  114. /* write login info into tmp file. */
  115. $userInfo = new stdclass();
  116. $userInfo->Account = $account;
  117. $userInfo->Url = common::getSysURL() . $this->config->webRoot;
  118. $userInfo->PassMd5 = '';
  119. $userInfo->Role = $this->app->user->role;
  120. $userInfo->AutoSignIn = true;
  121. $userInfo->Lang = $this->cookie->lang;
  122. $loginInfo = new stdclass();
  123. $loginInfo->User = $userInfo;
  124. $loginInfo->LastLoginTime = time() / 86400 + 25569;
  125. $loginInfo = json_encode($loginInfo);
  126. file_put_contents($packageFile, file_get_contents("http://dl.zentao.net/notify/newest/zentaonotify.win_32.zip"));
  127. file_put_contents($loginFile, $loginInfo);
  128. define('PCLZIP_TEMPORARY_DIR', $notifyDir);
  129. $this->app->loadClass('pclzip', true);
  130. /* remove the old config.json, add a new one. */
  131. $archive = new pclzip($packageFile);
  132. $result = $archive->delete(PCLZIP_OPT_BY_NAME, 'config.json');
  133. if($result == 0) return print("Error : " . $archive->errorInfo(true));
  134. $result = $archive->add($loginFile, PCLZIP_OPT_REMOVE_ALL_PATH, PCLZIP_OPT_ADD_PATH, 'notify');
  135. if($result == 0) return print("Error : " . $archive->errorInfo(true));
  136. $zipContent = file_get_contents($packageFile);
  137. unlink($loginFile);
  138. unlink($packageFile);
  139. $this->fetch('file', 'sendDownHeader', array('fileName' => 'notify.zip', 'zip', $zipContent));
  140. }
  141. /**
  142. * 忽略浏览器通知。
  143. * Ajax ignore browser.
  144. *
  145. * @access public
  146. * @return void
  147. */
  148. public function ajaxIgnoreBrowser()
  149. {
  150. $this->loadModel('setting')->setItem($this->app->user->account . '.common.global.browserNotice', 'true');
  151. }
  152. /**
  153. * 显示当前版本的变更日志。
  154. * Show version changelog.
  155. *
  156. * @access public
  157. * @return void
  158. * @param string $version
  159. */
  160. public function changeLog($version = '')
  161. {
  162. if(empty($version)) $version = key($this->lang->misc->feature->all);
  163. $this->view->version = $version;
  164. $this->view->features = zget($this->lang->misc->feature->all, $version, '');
  165. $detailed = '';
  166. $changeLogFile = $this->app->getBasePath() . 'doc' . DS . 'CHANGELOG';
  167. if(file_exists($changeLogFile))
  168. {
  169. $handle = fopen($changeLogFile, 'r');
  170. $tag = false;
  171. while($line = fgets($handle))
  172. {
  173. $line = trim($line);
  174. if($tag && empty($line)) break;
  175. if($tag) $detailed .= $line . '<br />';
  176. if(preg_match("/{$version}$/", $line) > 0) $tag = true;
  177. }
  178. fclose($handle);
  179. }
  180. $this->view->detailed = $detailed;
  181. $this->display();
  182. }
  183. /**
  184. * 检查是否能访问禅道官网插件接口。
  185. * Check net connect.
  186. *
  187. * @access public
  188. * @return void
  189. */
  190. public function checkNetConnect()
  191. {
  192. $this->app->loadConfig('extension');
  193. $context = stream_context_create(array("ssl" => array("verify_peer" => false, "verify_peer_name" => false)));
  194. $check = @fopen(dirname($this->config->extension->apiRoot), "r", false, $context);
  195. print($check ? 'success' : 'fail');
  196. }
  197. /**
  198. * 展示验证码图片。
  199. * Show captcha and save to session.
  200. *
  201. * @access public
  202. * @return void
  203. */
  204. public function captcha()
  205. {
  206. $captcha = $this->app->loadClass('captcha');
  207. $this->session->set('captcha', $captcha->getPhrase());
  208. $captcha->build();
  209. $obLevel = ob_get_level();
  210. for($i = 0; $i < $obLevel; $i++) ob_end_clean();
  211. helper::header('Content-Type', 'image/jpeg');
  212. $captcha->output();
  213. }
  214. /**
  215. * 记录被展开的对象ID。
  216. * Ajax set unfoldID.
  217. *
  218. * @param int $objectID
  219. * @param string $objectType
  220. * @param string $action add|delete
  221. * @access public
  222. * @return string
  223. */
  224. public function ajaxSetUnfoldID($objectID, $objectType, $action = 'add')
  225. {
  226. $newUnfoldID = $this->post->newUnfoldID;
  227. if(empty($newUnfoldID)) return '';
  228. $account = $this->app->user->account;
  229. if($objectType == 'execution')
  230. {
  231. $condition = "owner={$account}&module={$objectType}&section=task&key=unfoldTasks";
  232. $settingPath = $account . ".{$objectType}.task.unfoldTasks";
  233. }
  234. elseif($objectType == 'productplan')
  235. {
  236. $condition = "owner={$account}&module={$objectType}&section=browse&key=unfoldPlans";
  237. $settingPath = $account . ".{$objectType}.browse.unfoldPlans";
  238. }
  239. else
  240. {
  241. $condition = "owner={$account}&module=product&section=browse&key=unfoldStories";
  242. $settingPath = $account . ".{$objectType}.browse.unfoldStories";
  243. }
  244. $this->loadModel('setting');
  245. $setting = $this->setting->createDAO($this->setting->parseItemParam($condition), 'select')->fetch();
  246. $unfoldIdList = $setting ? json_decode($setting->value, true) : array();
  247. $newUnfoldID = json_decode($newUnfoldID);
  248. foreach($newUnfoldID as $unfoldID)
  249. {
  250. unset($unfoldIdList[$objectID][$unfoldID]);
  251. if($action == 'add') $unfoldIdList[$objectID][$unfoldID] = $unfoldID;
  252. }
  253. if(!empty($setting))
  254. {
  255. $this->dao->update(TABLE_CONFIG)->set('value')->eq(json_encode($unfoldIdList))->where('id')->eq($setting->id)->exec();
  256. }
  257. else
  258. {
  259. $this->setting->setItem($settingPath, json_encode($unfoldIdList));
  260. }
  261. echo 'success';
  262. }
  263. /**
  264. * 获取15版本之后的最新特性。
  265. * Features dialog.
  266. *
  267. * @access public
  268. * @return void
  269. */
  270. public function features()
  271. {
  272. $features = array();
  273. foreach($this->config->newFeatures as $feature)
  274. {
  275. $accounts = zget($this->config->global, 'skip' . ucfirst($feature), '');
  276. if(strpos(",$accounts,", $this->app->user->account) === false) $features[] = $feature;
  277. }
  278. $this->app->loadLang('install');
  279. $this->view->features = $features;
  280. $this->display();
  281. }
  282. /**
  283. * 保存已看过最新特性的记录。
  284. * Save viewed feature.
  285. *
  286. * @param string $feature
  287. * @access public
  288. * @return void
  289. */
  290. public function ajaxSaveViewed($feature)
  291. {
  292. $accounts = zget($this->config->global, 'skip' . ucfirst($feature), '');
  293. if(strpos(",$accounts,", $this->app->user->account) === false) $accounts .= ',' . $this->app->user->account;
  294. $this->loadModel('setting')->setItem('system.common.global.skip' . ucfirst($feature), $accounts);
  295. }
  296. /**
  297. * 向官网发送安装事件。
  298. * Send event to website with step.
  299. *
  300. * @param string $step start|success
  301. * @return void
  302. */
  303. public function ajaxSendEvent($step)
  304. {
  305. session_write_close();
  306. $this->loadModel('common');
  307. $api = $this->config->misc->sendEventAPI . '?action=' . $step . '&version=' . $this->config->version;
  308. commonModel::http($api, null, array(), array(), 'data', 'GET', $timeout = 2);
  309. }
  310. /**
  311. * 安装过程的事件埋点。
  312. * Event burial points during installation process.
  313. *
  314. * @access public
  315. * @return void
  316. */
  317. public function installEvent()
  318. {
  319. $data = new stdClass();
  320. $data->location = $this->post->location;
  321. $data->fingerprint = $this->post->fingerprint;
  322. $this->misc->sendInstallEvent($data);
  323. }
  324. }