国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

460 lines
9.7KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. // 允许的函数
  4. $GLOBALS['allowedCalls'] = array(
  5. // 系统
  6. 'var_dump',
  7. // 数学
  8. 'ceil',
  9. 'floor',
  10. 'fmod',
  11. 'log',
  12. 'mt_rand',
  13. 'mt_srand',
  14. 'pow',
  15. 'rand',
  16. 'sqrt',
  17. 'srand',
  18. // 变量
  19. 'empty',
  20. 'floatval',
  21. 'intval',
  22. 'is_array',
  23. 'is_binary',
  24. 'is_bool',
  25. 'is_double',
  26. 'is_float',
  27. 'is_int',
  28. 'is_integer',
  29. 'is_long',
  30. 'is_null',
  31. 'is_numeric',
  32. 'is_real',
  33. 'is_scalar',
  34. 'is_string',
  35. 'is_unicode',
  36. 'isset',
  37. 'strval',
  38. 'unset',
  39. // 数组
  40. 'array_change_key_case',
  41. 'array_chunk',
  42. 'array_combine',
  43. 'array_count_values',
  44. 'array_diff_assoc',
  45. 'array_diff_key',
  46. 'array_diff',
  47. 'array_fill_keys',
  48. 'array_fill',
  49. 'array_flip',
  50. 'array_intersect_assoc',
  51. 'array_intersect_key',
  52. 'array_intersect',
  53. 'array_key_exists',
  54. 'array_keys',
  55. 'array_merge_recursive',
  56. 'array_merge',
  57. 'array_multisort',
  58. 'array_pad',
  59. 'array_pop',
  60. 'array_product',
  61. 'array_push',
  62. 'array_rand',
  63. 'array_reverse',
  64. 'array_search',
  65. 'array_shift',
  66. 'array_slice',
  67. 'array_splice',
  68. 'array_sum',
  69. 'array_unique',
  70. 'array_unshift',
  71. 'array_values',
  72. 'array',
  73. 'arsort',
  74. 'asort',
  75. 'compact',
  76. 'count',
  77. 'current',
  78. 'each',
  79. 'end',
  80. 'in_array',
  81. 'key',
  82. 'krsort',
  83. 'ksort',
  84. 'natcasesort',
  85. 'natsort',
  86. 'next',
  87. 'pos',
  88. 'prev',
  89. 'range',
  90. 'reset',
  91. 'rsort',
  92. 'shuffle',
  93. 'sizeof',
  94. 'sort',
  95. // 字符串
  96. 'json_encode',
  97. 'json_decode',
  98. 'json_last_error',
  99. 'json_last_error_msg',
  100. 'base64_decode',
  101. 'base64_encode',
  102. 'urlencode',
  103. 'urldecode',
  104. 'parse_url',
  105. 'addslashes',
  106. 'addcslashes',
  107. 'chop',
  108. 'count_chars',
  109. 'explode',
  110. 'implode',
  111. 'join',
  112. 'levenshtein',
  113. 'ltrim',
  114. 'metaphone',
  115. 'money_format',
  116. 'number_format',
  117. 'rtrim',
  118. 'similar_text',
  119. 'soundex',
  120. 'str_getcsv',
  121. 'str_ireplace',
  122. 'str_pad',
  123. 'str_repeat',
  124. 'str_replace',
  125. 'str_rot13',
  126. 'str_shuffle',
  127. 'str_split',
  128. 'str_word_count',
  129. 'strcasecmp',
  130. 'strchr',
  131. 'strcmp',
  132. 'strcspn',
  133. 'stripos',
  134. 'stristr',
  135. 'strlen',
  136. 'strnatcasecmp',
  137. 'strnatcmp',
  138. 'strncasecmp',
  139. 'strncmp',
  140. 'strpbrk',
  141. 'strpos',
  142. 'strrchr',
  143. 'strrev',
  144. 'strripos',
  145. 'strrpos',
  146. 'strspn',
  147. 'strstr',
  148. 'strtolower',
  149. 'strtoupper',
  150. 'strtr',
  151. 'substr_compare',
  152. 'substr_count',
  153. 'substr_replace',
  154. 'substr',
  155. 'trim',
  156. 'ucfirst',
  157. 'ucwords',
  158. 'wordwrap',
  159. // dede内置
  160. 'html2text',
  161. 'removexss',
  162. 'htmlreplace',
  163. 'getmktime',
  164. 'getpinyin',
  165. 'cn_substr',
  166. 'cn_substrr',
  167. 'mydate',
  168. 'subday',
  169. 'addday',
  170. 'getdatetimemk',
  171. 'getdatemk',
  172. 'floortime',
  173. 'getcururl',
  174. 'utf82gb',
  175. 'gb2utf8',
  176. 'u2utf8',
  177. 'utf82u',
  178. 'big52gb',
  179. 'gb2big5',
  180. 'litimgurls',
  181. 'split',
  182. // 时间
  183. 'strtotime',
  184. 'date',
  185. 'idate',
  186. 'gmdate',
  187. 'mktime',
  188. 'gmmktime',
  189. 'checkdate',
  190. 'strftime',
  191. 'gmstrftime',
  192. 'time',
  193. 'localtime',
  194. 'getdate',
  195. 'date_create',
  196. 'date_create_immutable',
  197. 'date_create_from_format',
  198. 'date_create_immutable_from_format',
  199. 'date_parse',
  200. 'date_parse_from_format',
  201. 'date_get_last_errors',
  202. 'date_format',
  203. 'date_modify',
  204. 'date_add',
  205. 'date_sub',
  206. 'date_timezone_get',
  207. 'date_timezone_set',
  208. 'date_offset_get',
  209. 'date_diff',
  210. 'date_time_set',
  211. 'date_date_set',
  212. 'date_isodate_set',
  213. 'date_timestamp_set',
  214. 'date_timestamp_get',
  215. 'timezone_open',
  216. 'timezone_name_get',
  217. 'timezone_name_from_abbr',
  218. 'timezone_offset_get',
  219. 'timezone_transitions_get',
  220. 'timezone_location_get',
  221. 'timezone_identifiers_list',
  222. 'timezone_abbreviations_list',
  223. 'timezone_version_get',
  224. 'date_interval_create_from_date_string',
  225. 'date_interval_format',
  226. 'date_default_timezone_set',
  227. 'date_default_timezone_get',
  228. 'date_sunrise',
  229. 'date_sunset',
  230. 'date_sun_info',
  231. // mb字符串处理
  232. 'mb_convert_case',
  233. 'mb_strtoupper',
  234. 'mb_strtolower',
  235. 'mb_language',
  236. 'mb_internal_encoding',
  237. 'mb_http_input',
  238. 'mb_http_output',
  239. 'mb_detect_order',
  240. 'mb_substitute_character',
  241. 'mb_parse_str',
  242. 'mb_output_handler',
  243. 'mb_preferred_mime_name',
  244. 'mb_strlen',
  245. 'mb_strpos',
  246. 'mb_strrpos',
  247. 'mb_stripos',
  248. 'mb_strripos',
  249. 'mb_strstr',
  250. 'mb_strrchr',
  251. 'mb_stristr',
  252. 'mb_strrichr',
  253. 'mb_substr_count',
  254. 'mb_substr',
  255. 'mb_strcut',
  256. 'mb_strwidth',
  257. 'mb_strimwidth',
  258. 'mb_convert_encoding',
  259. 'mb_detect_encoding',
  260. 'mb_list_encodings',
  261. 'mb_encoding_aliases',
  262. 'mb_convert_kana',
  263. 'mb_encode_mimeheader',
  264. 'mb_decode_mimeheader',
  265. 'mb_convert_variables',
  266. 'mb_encode_numericentity',
  267. 'mb_decode_numericentity',
  268. 'mb_send_mail',
  269. 'mb_get_info',
  270. 'mb_check_encoding',
  271. 'mb_ord',
  272. 'mb_chr',
  273. 'mb_scrub',
  274. 'mb_regex_encoding',
  275. 'mb_regex_set_options',
  276. 'mb_ereg',
  277. 'mb_eregi',
  278. 'mb_ereg_replace',
  279. 'mb_eregi_replace',
  280. 'mb_ereg_replace_callback',
  281. 'mb_split',
  282. 'mb_ereg_match',
  283. 'mb_ereg_search',
  284. 'mb_ereg_search_pos',
  285. 'mb_ereg_search_regs',
  286. 'mb_ereg_search_init',
  287. 'mb_ereg_search_getregs',
  288. 'mb_ereg_search_getpos',
  289. 'mb_ereg_search_setpos',
  290. );
  291. // 允许的语法
  292. $GLOBALS['allowedTokens'] = array(
  293. 'T_AND_EQUAL',
  294. 'T_ARRAY',
  295. 'T_ARRAY_CAST',
  296. 'T_AS',
  297. 'T_BOOLEAN_AND',
  298. 'T_BOOLEAN_OR',
  299. 'T_BOOL_CAST',
  300. 'T_BREAK',
  301. 'T_CASE',
  302. 'T_CHARACTER',
  303. 'T_CONCAT_EQUAL',
  304. 'T_CONSTANT_ENCAPSED_STRING',
  305. 'T_CONTINUE',
  306. 'T_CURLY_OPEN',
  307. 'T_DEC',
  308. 'T_DECLARE',
  309. 'T_DEFAULT',
  310. 'T_DIV_EQUAL',
  311. 'T_DNUMBER',
  312. 'T_DO',
  313. 'T_DOUBLE_ARROW',
  314. 'T_DOUBLE_CAST',
  315. 'T_ELSE',
  316. 'T_ELSEIF',
  317. 'T_EMPTY',
  318. 'T_ENCAPSED_AND_WHITESPACE',
  319. 'T_ENDDECLARE',
  320. 'T_ENDFOR',
  321. 'T_ENDFOREACH',
  322. 'T_ENDIF',
  323. 'T_ENDSWITCH',
  324. 'T_FOR',
  325. 'T_FOREACH',
  326. 'T_IF',
  327. 'T_INC',
  328. 'T_INT_CAST',
  329. 'T_ISSET',
  330. 'T_IS_EQUAL',
  331. 'T_IS_GREATER_OR_EQUAL',
  332. 'T_IS_IDENTICAL',
  333. 'T_IS_NOT_EQUAL',
  334. 'T_IS_NOT_IDENTICAL',
  335. 'T_IS_SMALLER_OR_EQUAL',
  336. 'T_LNUMBER',
  337. 'T_LOGICAL_AND',
  338. 'T_LOGICAL_OR',
  339. 'T_LOGICAL_XOR',
  340. 'T_MINUS_EQUAL',
  341. 'T_MOD_EQUAL',
  342. 'T_MUL_EQUAL',
  343. 'T_NUM_STRING',
  344. 'T_OR_EQUAL',
  345. 'T_PLUS_EQUAL',
  346. 'T_RETURN',
  347. 'T_SL',
  348. 'T_SL_EQUAL',
  349. 'T_SR',
  350. 'T_SR_EQUAL',
  351. 'T_STRING',
  352. 'T_STRING_CAST',
  353. 'T_STRING_VARNAME',
  354. 'T_SWITCH',
  355. 'T_UNSET',
  356. 'T_UNSET_CAST',
  357. 'T_VARIABLE',
  358. 'T_WHILE',
  359. 'T_WHITESPACE',
  360. 'T_XOR_EQUAL',
  361. );
  362. // 禁止的表达式
  363. $GLOBALS['disallowedExpressions'] = array(
  364. '/`/',
  365. '/\$\W/',
  366. '/(\]|\})\s*\(/',
  367. '/\$\w\w*\s*\(/',
  368. );
  369. // 执行脚本
  370. function evalCode($code)
  371. {
  372. ob_start();
  373. $code = eval('if(0){' . "\n" . $code . "\n" . '}');
  374. ob_end_clean();
  375. return $code !== false;
  376. }
  377. // 校验脚本
  378. function checkCode($code)
  379. {
  380. global $allowedCalls;
  381. global $allowedTokens;
  382. global $disallowedExpressions;
  383. $tokens = token_get_all('<?php ' . $code . ' ?>');
  384. $errors = array();
  385. $braces = 0;
  386. foreach ($tokens as $token) {
  387. if ($token == '{') $braces = $braces + 1;
  388. else if ($token == '}') $braces = $braces - 1;
  389. if ($braces < 0) {
  390. $errors[0]['name'] = 'Syntax error.';
  391. break;
  392. }
  393. }
  394. if (empty($errors)) {
  395. if ($braces) $errors[0]['name'] = 'Unbalanced braces.';
  396. } else if (!evalCode($code)) {
  397. $errors[0]['name'] = 'Syntax error.';
  398. }
  399. if (empty($errors)) foreach ($disallowedExpressions as $disallowedExpression) {
  400. unset($matches);
  401. preg_match($disallowedExpression, $code, $matches);
  402. if ($matches) {
  403. $errors[0]['name'] = 'Execution operator / variable function name / variable variable name detected.';
  404. break;
  405. }
  406. }
  407. if (empty($errors)) {
  408. unset($tokens[0]);
  409. unset($tokens[0]);
  410. array_pop($tokens);
  411. array_pop($tokens);
  412. $i = 0;
  413. foreach ($tokens as $key => $token) {
  414. $i++;
  415. if (is_array($token)) {
  416. $id = token_name($token[0]);
  417. switch ($id) {
  418. case ('T_STRING'):
  419. if (in_array($token[1], $allowedCalls) === false) {
  420. $errors[$i]['name'] = 'Illegal function: ' . $token[1];
  421. $errors[$i]['line'] = $token[2];
  422. }
  423. break;
  424. default:
  425. if (in_array($id, $allowedTokens) === false) {
  426. $errors[$i]['name'] = 'Illegal token: ' . $token[1];
  427. $errors[$i]['line'] = $token[2];
  428. }
  429. break;
  430. }
  431. }
  432. }
  433. }
  434. if (!empty($errors)) {
  435. return $errors;
  436. }
  437. }
  438. // 错误提示
  439. function htmlErrors($errors = null)
  440. {
  441. if ($errors) {
  442. $errorsHTML = "<div style='width:98%;margin:1rem auto;color:#842029;background:#f8d7da;border-color:#842029;position:relative;padding:.75rem 1.25rem;border:1px solid transparent;border-radius:.2rem'>";
  443. $errorsHTML .= 'PHP内嵌脚本错误:';
  444. $errorsHTML .= '<dl>';
  445. foreach ($errors as $error) {
  446. if ($error['line']) {
  447. $errorsHTML .= '<dt>Line ' . $error['line'] . '</dt>';
  448. }
  449. $errorsHTML .= '<dd>' . $error['name'] . '</dd>';
  450. }
  451. $errorsHTML .= '</dl>';
  452. $errorsHTML .= "</div>\r\n";
  453. echo $errorsHTML;
  454. }
  455. }