entry.class.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. <?php /**
  2. * 禅道API的entry类。
  3. * The entry class file of ZenTao API.
  4. *
  5. * @package framework
  6. *
  7. * The author disclaims copyright to this source code. In place of
  8. * a legal notice, here is a blessing:
  9. *
  10. * May you do good and not evil.
  11. * May you find forgiveness for yourself and forgive others.
  12. * May you share freely, never taking more than you give.
  13. */
  14. class entry extends baseEntry
  15. {
  16. public function __construct()
  17. {
  18. parent::__construct();
  19. if($this->app->action == 'options') throw EndResponseException::create($this->send(204));
  20. if(!$this->loadModel('user')->isLogon()) throw EndResponseException::create($this->sendError(401, 'Unauthorized'));
  21. $this->dao = $this->loadModel('common')->dao;
  22. }
  23. }
  24. /**
  25. * 禅道API的baseEntry类。
  26. * The baseEntry class file of ZenTao API.
  27. *
  28. */
  29. class baseEntry
  30. {
  31. /**
  32. * 全局对象 $app。
  33. * The global $app object.
  34. *
  35. * @var object
  36. * @access public
  37. */
  38. public $app;
  39. /**
  40. * 语言项 $lang。
  41. * The global $app object.
  42. *
  43. * @var object
  44. * @access public
  45. */
  46. public $lang;
  47. /**
  48. * 提交的POST数据
  49. * The decoded request body.
  50. *
  51. * @var object
  52. * @access public
  53. */
  54. public $requestBody;
  55. /**
  56. * 构造方法。
  57. * The construct function.
  58. *
  59. * @access public
  60. * @return void
  61. */
  62. public function __construct()
  63. {
  64. global $app, $config, $lang;
  65. $this->app = $app;
  66. $this->config = $config;
  67. $this->lang = $lang;
  68. $this->parseRequestBody();
  69. }
  70. /**
  71. * 获取请求数据(POST PUT)
  72. * Get request data(POST or PUT)
  73. *
  74. * @param string $key
  75. * @access public
  76. * @return mixed
  77. */
  78. public function request($key, $defaultValue = '')
  79. {
  80. if(isset($this->requestBody->$key)) return $this->requestBody->$key;
  81. return $defaultValue;
  82. }
  83. /**
  84. * 获取请求参数
  85. * Get request params.
  86. *
  87. * @param string $key
  88. * @access public
  89. * @return mixed
  90. */
  91. public function param($key, $defaultValue = '')
  92. {
  93. if(isset($_GET[$key])) return $_GET[$key];
  94. return $defaultValue;
  95. }
  96. /**
  97. * 设置请求参数
  98. * Set request param.
  99. *
  100. * @param string|array $key if is array, set params by its key-value pairs.
  101. * @access public
  102. * @return void
  103. */
  104. public function setParam($key, $value = null)
  105. {
  106. if(is_array($key))
  107. {
  108. foreach($key as $k => $v) $_GET[$k] = $v;
  109. return;
  110. }
  111. $_GET[$key] = $value;
  112. }
  113. /**
  114. * 解析请求数据
  115. * Parse body of request data.
  116. *
  117. * @access public
  118. * @return void
  119. */
  120. private function parseRequestBody()
  121. {
  122. $this->requestBody = new stdClass();
  123. if($this->app->action == 'post' or $this->app->action == 'put')
  124. {
  125. $requestBody = file_get_contents("php://input");
  126. if($requestBody) $this->requestBody = json_decode($requestBody);
  127. }
  128. }
  129. /**
  130. * 发送请求的响应数据
  131. * Send response data
  132. *
  133. * @param int $code
  134. * @param mixed $data
  135. * @access public
  136. * @return string
  137. */
  138. public function send($code, $data = '')
  139. {
  140. return helper::response($data, $code);
  141. }
  142. /**
  143. * 发送错误信息
  144. * Send error response
  145. *
  146. * @param int $code
  147. * @param string|object|array $msg
  148. * @access public
  149. * @return string
  150. */
  151. public function sendError($code, $msg)
  152. {
  153. $response = new stdclass();
  154. $response->error = $msg;
  155. return $this->send($code, $response);
  156. }
  157. /**
  158. * 发送成功提示
  159. * Send success response
  160. *
  161. * @param int $code
  162. * @param string $msg
  163. * @access public
  164. * @return string
  165. */
  166. public function sendSuccess($code, $msg)
  167. {
  168. $response = new stdclass();
  169. $response->message = $msg;
  170. return $this->send($code, $response);
  171. }
  172. /**
  173. * Send 400 response.
  174. *
  175. * @param string message
  176. * @access public
  177. * @return string
  178. */
  179. public function send400($message = 'error')
  180. {
  181. return $this->sendError(400, $message);
  182. }
  183. /**
  184. * Send 404 response.
  185. *
  186. * @access public
  187. * @return string
  188. */
  189. public function send404()
  190. {
  191. return $this->sendError(404, '404 Not found');
  192. }
  193. /**
  194. * 加载禅道的控制器类
  195. * Load controller of zentaopms
  196. *
  197. * @param string $moduleName
  198. * @param string $methodName
  199. * @access public
  200. * @return object
  201. */
  202. public function loadController($moduleName, $methodName)
  203. {
  204. ob_start();
  205. global $app;
  206. if(!class_exists($moduleName) and !class_exists("my$moduleName"))
  207. {
  208. $app->setModuleName($moduleName);
  209. $app->setMethodName($methodName);
  210. $app->viewType = 'json';
  211. /* Check user permission. */
  212. $this->checkPriv();
  213. $app->setControlFile();
  214. $app->importControlFile();
  215. }
  216. /*
  217. * 设置control的类名。
  218. * Set the class name of the control.
  219. **/
  220. $className = class_exists("my$moduleName") ? "my$moduleName" : $moduleName;
  221. if(!class_exists($className)) $app->triggerError("the control $className not found", __FILE__, __LINE__, true);
  222. $controller = new $className();
  223. $controller->viewType = 'json';
  224. $app->control = $controller;
  225. return $controller;
  226. }
  227. /**
  228. * 加载指定模块的model文件。
  229. * Load the model file of one module.
  230. *
  231. * @param string $moduleName 模块名,如果为空,使用当前模块。The module name, if empty, use current module's name.
  232. * @param string $appName The app name, if empty, use current app's name.
  233. * @access public
  234. * @return object|bool 如果没有model文件,返回false,否则返回model对象。If no model file, return false, else return the model object.
  235. */
  236. public function loadModel($moduleName = '', $appName = '')
  237. {
  238. if(empty($moduleName)) $moduleName = $this->app->moduleName;
  239. if(empty($appName)) $appName = $this->app->appName;
  240. global $loadedModels;
  241. if(isset($loadedModels[$appName][$moduleName]))
  242. {
  243. $this->$moduleName = $loadedModels[$appName][$moduleName];
  244. $this->dao = $this->$moduleName->dao;
  245. return $this->$moduleName;
  246. }
  247. $modelFile = $this->app->setModelFile($moduleName, $appName);
  248. /**
  249. * 如果没有model文件,尝试加载config配置信息。
  250. * If no model file, try load config.
  251. */
  252. if(!helper::import($modelFile))
  253. {
  254. $this->app->loadModuleConfig($moduleName, $appName);
  255. $this->app->loadLang($moduleName, $appName);
  256. $this->dao = new dao($this->app);
  257. return false;
  258. }
  259. /**
  260. * 如果没有扩展文件,model类名是$moduleName + 'model',如果有扩展,还需要增加ext前缀。
  261. * If no extension file, model class name is $moduleName + 'model', else with 'ext' as the prefix.
  262. */
  263. $modelClass = class_exists('ext' . $appName . $moduleName. 'model') ? 'ext' . $appName . $moduleName . 'model' : $appName . $moduleName . 'model';
  264. if(!class_exists($modelClass))
  265. {
  266. $modelClass = class_exists('ext' . $moduleName. 'model') ? 'ext' . $moduleName . 'model' : $moduleName . 'model';
  267. if(!class_exists($modelClass)) $this->app->triggerError(" The model $modelClass not found", __FILE__, __LINE__, true);
  268. }
  269. /**
  270. * 初始化model对象,在control对象中可以通过$this->$moduleName来引用。同时将dao对象赋为control对象的成员变量,方便引用。
  271. * Init the model object thus you can try $this->$moduleName to access it. Also assign the $dao object as a member of control object.
  272. */
  273. $loadedModels[$appName][$moduleName] = new $modelClass($appName);
  274. $this->$moduleName = $loadedModels[$appName][$moduleName];
  275. $this->dao = $this->$moduleName->dao;
  276. return $this->$moduleName;
  277. }
  278. /**
  279. * 获取控制器执行返回的数据,在output缓存中.
  280. * Get controller data from output.
  281. *
  282. * @access public
  283. * @return object.
  284. */
  285. public function getData()
  286. {
  287. $output = helper::removeUTF8Bom(ob_get_clean());
  288. $output = json_decode((string) $output);
  289. if(isset($output->data) && !is_object($output->data)) $output->data = json_decode((string) $output->data);
  290. if(!isset($output->status) && isset($output->result)) $output->status = $output->result;
  291. if(isset($output->load->alert))
  292. {
  293. $output->code = 400;
  294. $output->status = 'fail';
  295. $output->message = $output->load->alert;
  296. unset($output->load);
  297. }
  298. return $output;
  299. }
  300. /**
  301. * 添加$_POST全局变量.
  302. * Add data to $_POST.
  303. *
  304. * @param string $key
  305. * @access public
  306. * @return void
  307. */
  308. public function setPost($key, $value)
  309. {
  310. $_POST[$key] = $value;
  311. }
  312. /**
  313. * 批量添加$_POST全局变量.
  314. * Batch set data to $_POST.
  315. *
  316. * @param string $fields
  317. * @access public
  318. * @return void
  319. */
  320. public function batchSetPost($fields, $object = '')
  321. {
  322. $fields = explode(',', $fields);
  323. /* Append flow fields to post. */
  324. if($this->config->edition != 'open')
  325. {
  326. $fieldList = $this->loadModel('workflowaction')->getPageFields($this->app->rawModule, $this->app->rawMethod, true, null, 0, 0);
  327. if(!empty($fieldList))
  328. {
  329. foreach($fieldList as $field)
  330. {
  331. if(!in_array($field->field, $fields)) $fields[] = $field->field;
  332. }
  333. }
  334. }
  335. foreach($fields as $field)
  336. {
  337. /*
  338. * If the field exists in request body, use it.
  339. * Otherwise set default value from $object.
  340. */
  341. if(isset($this->requestBody->$field))
  342. {
  343. $value = $this->requestBody->$field;
  344. }
  345. else
  346. {
  347. if(!$object or !isset($object->$field)) continue;
  348. $value = $object->$field;
  349. }
  350. $this->setPost($field, $value);
  351. }
  352. }
  353. /**
  354. * 确保字段不能为空.
  355. * Make sure the fields is not empty.
  356. *
  357. * @param string $fields
  358. * @access public
  359. * @return void
  360. */
  361. public function requireFields($fields)
  362. {
  363. $fields = explode(',', $fields);
  364. foreach($fields as $field)
  365. {
  366. if(!isset($_POST[$field]))
  367. {
  368. $module = $this->app->moduleName;
  369. $name = $this->app->lang->$module->$field ?? $field;
  370. throw EndResponseException::create($this->sendError(400, sprintf($this->app->lang->error->notempty, $name)));
  371. }
  372. }
  373. }
  374. /**
  375. * 检查是否在后台启用了代号.
  376. * Check whether config->setCode are used in product,project,execution.
  377. *
  378. * @access public
  379. * @return bool
  380. */
  381. public function checkCodeUsed()
  382. {
  383. return isset($this->config->setCode) ? $this->config->setCode : 0;
  384. }
  385. /**
  386. * 格式化数据的字段类型.
  387. * Format fields of response data.
  388. *
  389. * @param object|array $data
  390. * @param string $fields
  391. * @access public
  392. * @return object|array
  393. */
  394. public function format($data, $fields)
  395. {
  396. if(is_array($data))
  397. {
  398. foreach($data as $object) $this->formatFields($object, $fields);
  399. }
  400. else
  401. {
  402. $this->formatFields($data, $fields);
  403. }
  404. return $data;
  405. }
  406. /**
  407. * 格式化对象的字段类型.
  408. * Format fields of object.
  409. *
  410. * @param object $object
  411. * @param string $fields
  412. * @access public
  413. * @return object
  414. */
  415. private function formatFields(&$object, $fields)
  416. {
  417. $fields = explode(',', $fields);
  418. foreach($fields as $field)
  419. {
  420. $field = explode(':', $field);
  421. $key = $field[0];
  422. $type = $field[1];
  423. $isArray = false;
  424. if(!isset($object->$key)) continue;
  425. $pos = strpos($type, ']');
  426. if($pos !== false)
  427. {
  428. $isArray = true;
  429. $type = substr($type, $pos + 1);
  430. }
  431. else if(strpos($type, 'array') !== false)
  432. {
  433. $isArray = true;
  434. $type = 'object';
  435. }
  436. /* Format value. */
  437. if(!$isArray)
  438. {
  439. $object->$key = $this->cast(trim((string) $object->$key, ','), $type);
  440. continue;
  441. }
  442. /* Format array. */
  443. $value = array();
  444. if(is_array($object->$key) or is_object($object->$key))
  445. {
  446. foreach($object->$key as $v) $value[] = $this->cast($v, $type);
  447. }
  448. else
  449. {
  450. $vs = explode(',', $object->$key);
  451. foreach($vs as $v)
  452. {
  453. if($v === '') continue;
  454. $value[] = $this->cast($v, $type);
  455. }
  456. }
  457. $object->$key = $value;
  458. }
  459. }
  460. /**
  461. * Filter fields.
  462. *
  463. * @param object $object
  464. * @param string $allowable
  465. * @access public
  466. * @return object
  467. */
  468. public function filterFields($object, $allowable = '')
  469. {
  470. if(empty($allowable)) return $object;
  471. if(is_string($allowable)) $allowable = explode(',', $allowable);
  472. $filtered = new stdclass();
  473. foreach($allowable as $field)
  474. {
  475. $field = trim((string) $field);
  476. if(empty($field)) continue;
  477. if(!isset($object->$field)) continue;
  478. $filtered->$field = $object->$field;
  479. }
  480. return $filtered;
  481. }
  482. /**
  483. * Format user.
  484. *
  485. * @param string $account
  486. * @param array|object $users
  487. * @access public
  488. * @return array
  489. */
  490. public function formatUser($account, $users)
  491. {
  492. $user = array();
  493. $user['account'] = $account;
  494. $user['realname'] = zget($users, $account);
  495. return $user;
  496. }
  497. /**
  498. * 类型转换.
  499. * Typecasting.
  500. *
  501. * @param mixed $vaule
  502. * @param string $type
  503. * @access public
  504. * @return mixed
  505. */
  506. private function cast($value, $type)
  507. {
  508. switch($type)
  509. {
  510. case 'time':
  511. $timeFormat = $this->param('timeFormat', 'utc');
  512. if($timeFormat == 'utc')
  513. {
  514. if(!$value or $value == '0000-00-00 00:00:00') return null;
  515. return gmdate("Y-m-d\TH:i:s\Z", strtotime((string) $value));
  516. }
  517. return $value;
  518. case 'date':
  519. if(!$value or $value == '0000-00-00') return null;
  520. return $value;
  521. case 'bool':
  522. return !empty($value);
  523. case 'int':
  524. return (int) $value;
  525. case 'idList':
  526. $values = explode(',', (string) $value);
  527. if(empty($values)) return array();
  528. $idList = array();
  529. foreach($values as $val)
  530. {
  531. if($val !== '') $idList[] = (int) $val;
  532. }
  533. return $idList;
  534. case 'stringList':
  535. $values = explode(',', (string) $value);
  536. if(empty($values)) return array();
  537. $stringList = array();
  538. foreach($values as $val)
  539. {
  540. if($val !== '') $stringList[] = $val;
  541. }
  542. return $stringList;
  543. case 'array':
  544. $array = array();
  545. if(!empty($value)) foreach($value as $v) $array[] = $v;
  546. return $array;
  547. case 'user':
  548. if(empty($value)) return null;
  549. if(empty($this->users)) $this->users = $this->dao->select('id,account,avatar,realname')->from(TABLE_USER)->fetchAll('account');
  550. return zget($this->users, $value, null);
  551. case 'userList':
  552. $values = explode(',', (string) $value);
  553. if(empty($values)) return array();
  554. $userList = array();
  555. foreach($values as $val)
  556. {
  557. $val = $this->cast($val, 'user');
  558. if($val) $userList[] = $val;
  559. }
  560. return $userList;
  561. case 'decodeHtml':
  562. return htmlspecialchars_decode((string) $value);
  563. default:
  564. return $value;
  565. }
  566. }
  567. /**
  568. * 获取其他方法的执行结果。
  569. * Fetch result of other method.
  570. *
  571. * @param string $entry
  572. * @param string $method
  573. * @param array $params
  574. * @access public
  575. * @return mixed
  576. */
  577. public function fetch($entry, $method, $params = array())
  578. {
  579. include($this->app->appRoot . "api/{$this->app->version}/entries/" . strtolower($entry) . ".php");
  580. $entryName = $entry . 'Entry';
  581. $entry = new $entryName();
  582. return call_user_func_array(array($entry, $method), $params);
  583. }
  584. /**
  585. * Check the user has permission to access this method, if not, return 403.
  586. *
  587. * @access public
  588. * @return void|string
  589. */
  590. public function checkPriv()
  591. {
  592. $module = $this->app->getModuleName();
  593. $method = $this->app->getMethodName();
  594. if($module and $method and !$this->loadModel('common')->isOpenMethod($module, $method) and !commonModel::hasPriv($module, $method))
  595. {
  596. die($this->send(403, array('error' => 'Access not allowed')));
  597. }
  598. }
  599. /**
  600. * Reset open app.
  601. *
  602. * @param string $tab
  603. * @access public
  604. * @return void
  605. */
  606. public function resetOpenApp($tab)
  607. {
  608. $_COOKIE['tab'] = $tab;
  609. $this->app->tab = $tab;
  610. $this->app->session->tab = $tab;
  611. }
  612. }