Security.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. <?php
  2. /**
  3. * [Discuz!] (C)2001-2099 Comsenz Inc.
  4. * This is NOT a freeware, use is subject to license terms
  5. *
  6. * $Id: Security.php 30564 2012-06-04 05:38:45Z songlixin $
  7. */
  8. if(!defined('IN_DISCUZ')) {
  9. exit('Access Denied');
  10. }
  11. class Cloud_Service_Security {
  12. protected static $debug = 0;
  13. protected static $_secClient;
  14. protected static $_secStatus;
  15. protected static $postAction = array('newThread', 'newPost', 'editPost', 'editThread');
  16. protected static $userAction = array('register', 'login');
  17. protected static $delPostAction = array('delThread', 'delPost');
  18. protected static $delUserAction = array('banUser');
  19. protected static $retryLimit = 8;
  20. protected static $specialType = array('1' => 'poll', '2' => 'trade', '3' => 'reward', '4' => 'activity', '5' => 'debate');
  21. protected static $_instance;
  22. public static function getInstance() {
  23. if (!(self::$_instance instanceof self)) {
  24. self::$_instance = new self();
  25. $cloudAppService = Cloud::loadClass('Service_App');
  26. self::$_secStatus = $cloudAppService->getCloudAppStatus('security');
  27. self::$_instance->_setClient();
  28. }
  29. return self::$_instance;
  30. }
  31. private function _getUA() {
  32. return $_SERVER['HTTP_USER_AGENT'];
  33. }
  34. private function _setClient() {
  35. if (!self::$_secStatus) {
  36. return false;
  37. }
  38. self::$_secClient = Cloud::loadClass('Service_Client_Security');
  39. }
  40. public function reportRegister($uid) {
  41. global $_G;
  42. if (!self::$_secStatus) {
  43. return false;
  44. }
  45. $startTime = microtime(true);
  46. $uid = dintval($uid);
  47. $member = C::t('common_member')->fetch($uid);
  48. if (!is_array($member)) {
  49. return true;
  50. }
  51. $openId = $this->_getOpenId($uid);
  52. $secReportCodeStatus = ($_G['setting']['seccodestatus'] & 1) ? 1 : 2;
  53. $batchData = array();
  54. $batchData[] = array(
  55. 'siteUid' => $member['uid'],
  56. 'username' => $member['username'],
  57. 'email' => $member['email'],
  58. 'openId' => $openId,
  59. 'registerTime' => $_G['timestamp'],
  60. 'clientIp' => $_G['clientip'],
  61. 'remoteIp' => $_SERVER['REMOTE_ADDR'],
  62. 'hasVerifyCode' => $secReportCodeStatus,
  63. 'regResult' => 1,
  64. 'userAgent' => $this->_getUA(),
  65. 'extra' => $extra
  66. );
  67. $result = false;
  68. try {
  69. $result = self::$_secClient->securityReportUserRegister($batchData);
  70. } catch (Cloud_Service_Client_RestfulException $e) {
  71. $ids = array($uid);
  72. $this->logFailed('register', $ids);
  73. } catch (Exception $e) {
  74. }
  75. $this->benchMarkLog($startTime, $member['uid'], $batchData, 'register');
  76. return $result;
  77. }
  78. public function reportLogin($uid) {
  79. global $_G;
  80. if (!self::$_secStatus) {
  81. return false;
  82. }
  83. $startTime = microtime(true);
  84. $uid = dintval($uid);
  85. $member = C::t('common_member')->fetch($uid, 0 ,1);
  86. if (!is_array($member)) {
  87. return true;
  88. }
  89. $memberField = C::t('common_member_field_forum')->fetch($uid, 0, 1);
  90. $memberStatus = C::t('common_member_status')->fetch($uid, 0, 1);
  91. $memberCount = C::t('common_member_count')->fetch($uid, 0, 1);
  92. $memberVerify = C::t('common_member_verify')->fetch($uid);
  93. $openId = $this->_getOpenId($uid);
  94. $userBitMap['isAdmin'] = $member['adminid'] ? 1 : 2;
  95. $userBitMap['hasMedal'] = $memberField['medals'] ? 1 : 2;
  96. $userBitMap['hasAvatar'] = $member['avatarstatus'] ? 1 : 2;
  97. $userBitMap['hasVerify'] = (count($memberVerify)) ? 1 : 2;
  98. $username = $member['username'];
  99. $email = $member['email'];
  100. $emailStatus = $member['emailstatus'];
  101. $sUrl = $_G['siteurl'];
  102. $credits = $member['credits'];
  103. $regIp = $memberStatus['regip'];
  104. $regDate = $member['regdate'];
  105. $friends = $memberCount['friends'];
  106. $onlineTime = $memberCount['oltime']*3600;
  107. $threads = $memberCount['threads'];
  108. $posts = $memberCount['posts'];
  109. $signature = $memberField['sightml'];
  110. if (!$regIp) {
  111. $regIp = 'N/A';
  112. }
  113. if ($_G['clientip'] == NULL) {
  114. $_G['clientip'] = 'N/A';
  115. }
  116. $batchData = array();
  117. $batchData[] = array(
  118. 'siteUid' => $uid,
  119. 'openId' => $openId,
  120. 'loginTime' => TIMESTAMP,
  121. 'clientIp' => $_G['clientip'],
  122. 'remoteIp' => $_SERVER['REMOTE_ADDR'],
  123. 'username' => $username,
  124. 'email' => $email,
  125. 'emailStatus' => $emailStatus,
  126. 'sUrl' => $sUrl,
  127. 'credits' => $credits,
  128. 'registerIp' => $regIp,
  129. 'registerTime' => $regDate,
  130. 'friends' => $friends,
  131. 'onlineTime' => $onlineTime,
  132. 'threads' => $threads,
  133. 'posts' => $posts,
  134. 'signature' => $signature,
  135. 'userBitMap' => $userBitMap,
  136. 'userAgent' => $this->_getUA(),
  137. 'extra' => $extra
  138. );
  139. $result = false;
  140. try {
  141. $result = self::$_secClient->securityReportUserLogin($batchData);
  142. } catch (Cloud_Service_Client_RestfulException $e) {
  143. $ids = array($uid);
  144. $this->logFailed('login', $ids);
  145. } catch (Exception $e) {
  146. }
  147. $this->benchMarkLog($startTime, $uid, $batchData, 'login');
  148. return $result;
  149. }
  150. public function reportPost($type, $tid, $pid, $extra = NULL, $isFollow = 0) {
  151. global $_G;
  152. $utilService = Cloud::loadClass('Service_Util');
  153. if (!self::$_secStatus) {
  154. return false;
  155. }
  156. $startTime = microtime(true);
  157. $tid = dintval($tid);
  158. $pid = dintval($pid);
  159. $url = $_G['siteurl'] . "forum.php?mod=redirect&goto=findpost&ptid=$tid&pid=$pid";
  160. include_once libfile('function/forum');
  161. $thread = get_thread_by_tid($tid);
  162. if (!is_array($thread)) {
  163. return true;
  164. }
  165. $post = get_post_by_pid($pid);
  166. $member = C::t('common_member')->fetch($post['authorid'], 0, 1);
  167. $memberField = C::t('common_member_field_forum')->fetch($post['authorid'], 0, 1);
  168. $memberStatus = C::t('common_member_status')->fetch($post['authorid'], 0, 1);
  169. $memberVerify = C::t('common_member_verify')->fetch($post['authorid']);
  170. if ($post['first'] == 1) {
  171. $type = $type . 'Thread';
  172. } else {
  173. $type = $type . 'Post';
  174. }
  175. $id = 'pid:' . $pid;
  176. $aids = C::t('forum_attachment')->fetch_all_by_id('pid', $pid);
  177. $aids = array_keys($aids);
  178. $postAttachs = C::t('forum_attachment_n')->fetch_all($id, $aids);
  179. if (!$post['first']) {
  180. $firstPost = C::t('forum_post')->fetch_all_by_tid($thread['posttableid'], $tid, 1, '', 0, 0, 1);
  181. $firstPost = array_pop($firstPost);
  182. $id = 'pid:' . $firstPost['pid'];
  183. $aids = C::t('forum_attachment')->fetch_all_by_id('pid', $firstPost['pid']);
  184. $aids = array_keys($aids);
  185. $threadAttachs = C::t('forum_attachment_n')->fetch_all($id, $aids);
  186. } else {
  187. $firstPost = $post;
  188. $firstPostAttachs = $postAttachs;
  189. }
  190. $views = dintval($thread['views']);
  191. $replies = dintval($thread['replies']);
  192. $favourites = dintval($thread['favtimes']);
  193. $supports = dintval($thread['recommend_add']);
  194. $opposes = dintval($thread['recommend_sub']);
  195. $shares = dintval($thread['sharetimes']);
  196. $openId = $this->_getOpenId($_G['uid']);
  197. if (!$thread || !$post) {
  198. return true;
  199. }
  200. $fid = $thread["fid"];
  201. if ($post['first']) {
  202. $threadShield = ($post['status'] & 1) ? 1 : 2;
  203. $threadWarning = ($post['status'] & 2) ? 1 : 2;
  204. } else {
  205. $threadShield = ($firstPost['status'] & 1) ? 1 : 2;
  206. $threadWarning = ($firstPost['status'] & 2) ? 1 : 2;
  207. }
  208. $contentBitMap = array(
  209. 'onTop' => $thread['displayorder'] ? 1:2,
  210. 'hide' => (strpos($post['message'], '[hide')) ? 1:2,
  211. 'digest' => $thread['digest'] ? 1 : 2,
  212. 'highLight' => $thread['highlight'] ? 1:2,
  213. 'special' => $thread['special'] ? 1:2,
  214. 'threadAttach' => 2,
  215. 'threadAttachFlash' => 2,
  216. 'threadAttachPic' => 2,
  217. 'threadAttachVideo' => 2,
  218. 'threadAttachAudio' => 2,
  219. 'threadShield' => $threadShield,
  220. 'threadWarning' => $threadWarning,
  221. 'postAttach' => 2,
  222. 'postAttachFlash' => 2,
  223. 'postAttachPic' => 2,
  224. 'postAttachVideo' => 2,
  225. 'postAttachAudio' => 2,
  226. 'postShield' => ($post['status'] & 1) ? 1 : 2,
  227. 'postWarning' => ($post['status'] & 2) ? 1 : 2,
  228. 'isAdmin' => $member['adminid'] ? 1 : 2,
  229. 'isRush' => getstatus($thread['status'], 3) ? 1 : 2,
  230. 'hasReadPerm' => $thread['readperm'] ? 1 : 2,
  231. 'hasStamp' => ($thread['stamp'] >= 0) ? 1 : 2,
  232. 'hasIcon' => ($thread['icon'] >= 0) ? 1 : 2,
  233. 'isPushed' => $thread['pushedaid'] ? 1 : 2,
  234. 'hasCover' => $thread['cover'] ? 1 : 2,
  235. 'hasReward' => $thread['replycredit'] ? 1 : 2,
  236. 'isFollow' => $isFollow ? 1 : 2,
  237. 'threadStatus' => $thread['status'],
  238. 'postStatus' => $post['status'],
  239. );
  240. if ($post['first']) {
  241. $contentBitMap['isMobile'] = $utilService->isMobile($thread['status']) ? 1 : 2;
  242. if ($contentBitMap['isMobile'] == 1) {
  243. $contentBitMap['isMobileSound'] = $utilService->mobileHasSound($thread['status']) ? 1 : 2;
  244. $contentBitMap['isMobilePhoto'] = $utilService->mobileHasPhoto($thread['status']) ? 1 : 2;
  245. $contentBitMap['isMobileGPS'] = $utilService->mobileHasGPS($thread['status']) ? 1 : 2;
  246. }
  247. } else {
  248. $contentBitMap['isMobile'] = getstatus($post['status'], 4) ? 1 : 2;
  249. }
  250. $userBitMap['isAdmin'] = $member['adminid'] ? 1 : 2;
  251. $userBitMap['hasMedal'] = $memberField['medals'] ? 1 : 2;
  252. $userBitMap['hasAvatar'] = $member['avatarstatus'] ? 1 : 2;
  253. $userBitMap['hasVerify'] = (count($memberVerify)) ? 1 : 2;
  254. $videoExt = array('.rm', '.flv', '.mkv', '.rmvb', '.avi', '.wmv', '.mp4', '.mpeg', '.mpg');
  255. $audioExt = array('.wav', '.mid', '.mp3', '.m3u', '.wma', '.asf', '.asx');
  256. if ($firstPostAttachs) {
  257. foreach($firstPostAttachs as $attach) {
  258. $fileExt = substr($attach['filename'], strrpos($attach['filename'], '.'));
  259. if ($fileExt == '.bmp' || $fileExt == '.jpg' || $fileExt == '.jpeg' || $fileExt == '.gif' || $fileExt == '.png') {
  260. $contentBitMap['threadAttachPic'] = 1;
  261. }
  262. if ($fileExt == '.swf' || $fileExt == '.fla') {
  263. $contentBitMap['threadAttachFlash'] = 1;
  264. }
  265. if (in_array($fileExt, $videoExt)) {
  266. $contentBitMap['threadAttachVideo'] = 1;
  267. }
  268. if (in_array($fileExt, $audioExt)) {
  269. $contentBitMap['threadAttachAudio'] = 1;
  270. }
  271. }
  272. $contentBitMap['threadAttach'] = 1;
  273. }
  274. if ($postAttachs) {
  275. foreach($postAttachs as $attach) {
  276. $fileExt = substr($attach['filename'], strrpos($attach['filename'], '.'));
  277. if ($fileExt == '.bmp' || $fileExt == '.jpg' || $fileExt == '.jpeg' || $fileExt == '.gif' || $fileExt == '.png') {
  278. $contentBitMap['postAttachPic'] = 1;
  279. }
  280. if ($fileExt == '.swf' || $fileExt == '.fla') {
  281. $contentBitMap['postAttachFlash'] = 1;
  282. }
  283. if (in_array($fileExt, $videoExt)) {
  284. $contentBitMap['postAttachVideo'] = 1;
  285. }
  286. if (in_array($fileExt, $audioExt)) {
  287. $contentBitMap['postAttachAudio'] = 1;
  288. }
  289. }
  290. $contentBitMap['postAttach'] = 1;
  291. }
  292. if ($thread['authorid'] == $_G['uid']) {
  293. $threadEmail = $_G['member']['email'];
  294. } else {
  295. $threadMember = C::t('common_member')->fetch($thread['authorid'], 0, 1);
  296. $threadEmail = $threadMember['email'];
  297. }
  298. if ($post['authorid'] == $_G['uid']) {
  299. $postEmail = $_G['member']['email'];
  300. } else {
  301. $postEmail = $member['email'];
  302. }
  303. if ($thread['special']) {
  304. if (array_key_exists($thread['special'], $this->specialType)) {
  305. $threadSpecial = self::$specialType[$thread['special']];
  306. } else {
  307. $threadSpecial = 'other';
  308. }
  309. }
  310. $threadSort = 2;
  311. if ($thread['sortid']) {
  312. $threadSort = 1;
  313. if ($post['first']) {
  314. $sortMessage = $this->_convertSortInfo($thread['sortid'], $thread['tid']);
  315. }
  316. }
  317. $contentBitMap['threadSort'] = $threadSort;
  318. if ($_GET['action'] == 'newtrade') {
  319. $type = 'newThread';
  320. $pid = $firstPost['pid'];
  321. }
  322. $batchData[] = array(
  323. 'tId' => $tid,
  324. 'pId' => $pid,
  325. 'threadUid' => dintval($thread['authorid']),
  326. 'threadUsername' => $thread['author'],
  327. 'threadEmail' => $threadEmail,
  328. 'postUid' => dintval($post['authorid']),
  329. 'postUsername' => $post['author'],
  330. 'postEmail' => $postEmail,
  331. 'openId' => $openId,
  332. 'fId' => dintval($fid),
  333. 'threadUrl' => $url,
  334. 'operateTime' => $_G['timestamp'],
  335. 'clientIp' => $_G['clientip'],
  336. 'remoteIp' => $_SERVER['REMOTE_ADDR'],
  337. 'views' => $views,
  338. 'replies' => $replies,
  339. 'favourites' => $favourites,
  340. 'supports' => $supports,
  341. 'opposes' => $opposes,
  342. 'shares' => $shares,
  343. 'title' => $post['subject'],
  344. 'content' => $post['message'],
  345. 'sortMessage' => $sortMessage,
  346. 'attachList' => $postAttachs,
  347. 'reportType' => $type,
  348. 'contentBitMap' => $contentBitMap,
  349. 'userBitMap' => $userBitMap,
  350. 'extra' => $extra,
  351. 'specialType' => $threadSpecial,
  352. 'signature' => $memberField['sightml'],
  353. 'userAgent' => $this->_getUA(),
  354. );
  355. $result = false;
  356. try {
  357. $result = self::$_secClient->securityReportPost($batchData);
  358. } catch (Cloud_Service_Client_RestfulException $e) {
  359. $ids = array($tid, $pid);
  360. $this->logFailed($type, $ids);
  361. } catch (Exception $e) {
  362. }
  363. $this->benchMarkLog($startTime, $pid, $batchData, $type);
  364. return $result;
  365. }
  366. private function _convertSortInfo($sortId, $tid) {
  367. global $_G;
  368. $returnStr = array();
  369. require_once libfile('function/threadsort');
  370. $sortInfo = threadsortshow($sortId, $tid);
  371. foreach ($sortInfo['optionlist'] as $value) {
  372. if ($value['type'] != 'select') {
  373. $returnStr[] = $value['title'] . ':' . $value['value'];
  374. }
  375. }
  376. if (count($returnStr)) {
  377. return implode('<br/>', $returnStr);
  378. }
  379. return false;
  380. }
  381. public function reportDelPost($logId) {
  382. if (!self::$_secStatus) {
  383. return false;
  384. }
  385. if (!$logId) {
  386. return true;
  387. }
  388. $log = C::t('#security#security_failedlog')->fetch($logId);
  389. if ($log['pid'] == 0) {
  390. return true;
  391. }
  392. $extraData = dunserialize($log['extra2']);
  393. $batchData[] = array(
  394. 'tid' => $log['tid'],
  395. 'pid' => $log['pid'],
  396. 'uid' => $log['uid'],
  397. 'delType' => $log['reporttype'],
  398. 'findEvilTime' => $log['createtime'],
  399. 'postTime' => $log['posttime'],
  400. 'reason' => $log['delreason'],
  401. 'fid' => $extraData['fid'],
  402. 'clientIp' => $extraData['clientIp'],
  403. 'openId' => $extraData['openId'],
  404. );
  405. $result = false;
  406. try {
  407. $result = self::$_secClient->securityReportDelPost($batchData);
  408. } catch (Cloud_Service_Client_RestfulException $e) {
  409. $ids = array($log['tid'], $log['pid']);
  410. $this->logFailed('delPost', $ids);
  411. } catch (Exception $e) {
  412. }
  413. return $result;
  414. }
  415. public function reportBanUser($logId) {
  416. if (!self::$_secStatus) {
  417. return false;
  418. }
  419. if (!$logId) {
  420. return true;
  421. }
  422. $log = C::t('#security#security_failedlog')->fetch($logId);
  423. if ($log['uid'] == 0) {
  424. return true;
  425. }
  426. $extraData = dunserialize($log['extra2']);
  427. $batchData[] = array(
  428. 'uid' => $log['uid'],
  429. 'findEvilTime' => $log['createtime'],
  430. 'postTime' => $log['posttime'],
  431. 'reason' => $log['delreason'],
  432. 'clientIp' => $extraData['clientIp'],
  433. 'openId' => $extraData['openId'],
  434. );
  435. $result = false;
  436. try {
  437. $result = self::$_secClient->securityReportBanUser($batchData);
  438. } catch (Cloud_Service_Client_RestfulException $e) {
  439. $ids = array($log['uid']);
  440. $this->logFailed('banUser', $ids);
  441. } catch (Exception $e) {
  442. }
  443. return $result;
  444. }
  445. public function retryReportData($num = 1) {
  446. global $_G;
  447. if (!self::$_secStatus) {
  448. return false;
  449. }
  450. C::t('#security#security_failedlog')->deleteDirtyLog();
  451. $num = dintval($num) ? dintval($num) : 1;
  452. $result = 0;
  453. $clearIds = array();
  454. $retryData = C::t('#security#security_failedlog')->range(0, $num, 'ASC');
  455. foreach ($retryData as $data) {
  456. if (!$data['uid'] && !$data['tid'] && !$data['pid']) {
  457. continue;
  458. }
  459. if ($data['scheduletime'] > $_G['timestamp']) {
  460. continue;
  461. }
  462. $reportType = $data['reporttype'];
  463. $uid = $data['uid'];
  464. $tid = $data['tid'];
  465. $pid = $data['pid'];
  466. $failcount = $data['failcount'];
  467. if ($failcount >= self::$retryLimit) {
  468. $clearIds[] = $data['id'];
  469. } else {
  470. switch ($reportType) {
  471. case 'newThread':
  472. case 'newPost':
  473. $result = $this->reportPost('new', $tid, $pid);
  474. break;
  475. case 'editPost':
  476. case 'editThread':
  477. $result = $this->reportPost('edit', $tid, $pid);
  478. break;
  479. case 'register':
  480. $result = $this->reportRegister($uid);
  481. break;
  482. case 'login':
  483. $result = $this->reportLogin($uid);
  484. break;
  485. case 'delThread':
  486. case 'delPost':
  487. $result = $this->reportDelPost($data['id']);
  488. break;
  489. case 'banUser':
  490. $result = $this->reportBanUser($data['id']);
  491. break;
  492. default:break;
  493. }
  494. if ($result) {
  495. $clearIds[] = $data['id'];
  496. }
  497. }
  498. }
  499. $this->_clearFailed($clearIds);
  500. }
  501. private function _clearFailed($ids) {
  502. if (!is_array($ids)) {
  503. $ids = array($ids);
  504. }
  505. if (count($ids) < 1) {
  506. return false;
  507. }
  508. C::t('#security#security_failedlog')->delete($ids);
  509. }
  510. public function writeLog($id, $type) {
  511. if (!self::$debug) {
  512. return false;
  513. }
  514. return true;
  515. }
  516. function logFailed($reportType, $ids, $reason = '') {
  517. global $_G;
  518. if (!self::$_secStatus) {
  519. return false;
  520. }
  521. $this->_checkAndClearFailNum();
  522. if (!is_array($ids)) {
  523. $ids = array($ids);
  524. }
  525. $postTime = 0;
  526. if (in_array($reportType, self::$postAction) || in_array($reportType, self::$delPostAction)) {
  527. $tid = dintval($ids[0]) ? dintval($ids[0]) : dintval($ids['tid']);
  528. $pid = dintval($ids[1]) ? dintval($ids[1]) : dintval($ids['pid']);
  529. $uid = dintval($ids['uid']);
  530. if ($pid == 0) {
  531. return false;
  532. }
  533. if (in_array($reportType, self::$delPostAction)) {
  534. require_once libfile('function/forum');
  535. $postInfo = get_post_by_pid($pid);
  536. $postTime = $postInfo['dateline'];
  537. $fid = $postInfo['fid'];
  538. $uid = $postInfo['authorid'];
  539. $clientIp = $postInfo['useip'];
  540. $openId = $this->_getOpenId($uid);
  541. }
  542. $oldData = C::t('#security#security_failedlog')->fetch_by_pid($pid);
  543. } elseif (in_array($reportType, self::$userAction) || in_array($reportType, self::$delUserAction)) {
  544. $tid = 0;
  545. $pid = 0;
  546. $uid = dintval($ids[0]) ? dintval($ids[0]) : dintval($ids['uid']);
  547. if ($uid == 0) {
  548. return false;
  549. }
  550. if (in_array($reportType, self::$delUserAction)) {
  551. $memberStatus = C::t('common_member_status')->fetch($uid, 0, 1);
  552. $postTime = $memberStatus['lastpost'];
  553. $clientIp = $this->_getMemberIp($uid);
  554. $openId = $this->_getOpenId($uid);
  555. }
  556. $oldData = C::t('#security#security_failedlog')->fetch_by_uid($uid);
  557. } else {
  558. return false;
  559. }
  560. $extraData = array(
  561. 'fid' => $fid,
  562. 'clientIp' => $clientIp,
  563. 'openId' => $openId,
  564. );
  565. if (is_array($oldData) && $oldData['id']) {
  566. $data = $oldData;
  567. $data['reporttype'] = $reportType;
  568. $data['lastfailtime'] = $_G['timestamp'];
  569. $data['scheduletime'] = $_G['timestamp'] + 300;
  570. $data['failcount']++;
  571. } else {
  572. $data = array(
  573. 'reporttype' => $reportType,
  574. 'tid' => $tid,
  575. 'pid' => $pid,
  576. 'uid' => $uid,
  577. 'failcount' => 1,
  578. 'createtime' => $_G['timestamp'],
  579. 'posttime' => $postTime,
  580. 'delreason' => $reason,
  581. 'scheduletime' => $_G['timestamp'] + 60,
  582. 'lastfailtime' => $_G['timestamp'],
  583. );
  584. }
  585. if ($extraData['fid'] || $extraData['clientIp'] || $extraData['openId']) {
  586. $data['extra2'] = serialize($extraData);
  587. }
  588. if (!$data['uid'] && !$data['tid'] && !$data['pid']) {
  589. return false;
  590. }
  591. C::t('#security#security_failedlog')->insert($data, 0, 1);
  592. }
  593. private function _getOpenId($uid) {
  594. $member = C::t('common_member')->fetch($uid, 0, 1);
  595. if ($member['conisbind']) {
  596. $connectInfo = C::t('#qqconnect#common_member_connect')->fetch($uid);
  597. $openId = $connectInfo['conopenid'];
  598. } else {
  599. $openId = '';
  600. }
  601. return $openId;
  602. }
  603. private function _getMemberIp($uid) {
  604. if (empty($uid)) {
  605. return false;
  606. }
  607. $member = C::t('common_member_status')->fetch($uid, 0, 1);
  608. if ($member['lastip']) {
  609. return $member['lastip'];
  610. } else {
  611. return $member['regip'];
  612. }
  613. }
  614. private function _checkAndClearFailNum($maxNum = '50000') {
  615. $num = C::t('#security#security_failedlog')->count();
  616. if ($num >= $maxNum) {
  617. C::t('#security#security_failedlog')->truncate();
  618. }
  619. return true;
  620. }
  621. public function logDeletePost($pids, $reason = 'Admin Delete') {
  622. if (!is_array($pids)) {
  623. $pids = array($pids);
  624. }
  625. $logData = array();
  626. require_once libfile('function/forum');
  627. foreach ($pids as $pid) {
  628. $postInfo = get_post_by_pid($pid);
  629. if ($postInfo['invisible'] != '-5') {
  630. $logData[] = array(
  631. 'tid' => $postInfo['tid'],
  632. 'pid' => $postInfo['pid'],
  633. 'fid' => $postInfo['fid'],
  634. 'uid' => $postInfo['authorid'],
  635. 'clientIp' => $postInfo['useip'],
  636. 'openId' => $this->_getOpenId($postInfo['authorid']),
  637. );
  638. }
  639. }
  640. if (count($logData)) {
  641. foreach ($logData as $data) {
  642. $this->logFailed('delPost', $data, $reason);
  643. }
  644. }
  645. }
  646. public function logBannedMember($username, $reason = 'Admin Banned') {
  647. if (!$username || !self::$_secStatus) {
  648. return false;
  649. }
  650. $uid = C::t('common_member')->fetch_uid_by_username($username);
  651. if ($uid) {
  652. $data = array(
  653. 'uid' => $uid,
  654. 'openId' => $this->_getOpenId($uid),
  655. 'clientIp' => $this->_getMemberIp($uid),
  656. );
  657. $this->logFailed('banUser', $data, $reason);
  658. }
  659. }
  660. public function logDeleteThread($tids, $reason = 'Admin Delete') {
  661. global $_G;
  662. if (!is_array($tids)) {
  663. $tids = array($tids);
  664. }
  665. $postids = array();
  666. $logData = array();
  667. loadcache(array('threadtableids', 'posttableids'));
  668. $threadtableids = !empty($_G['cache']['threadtableids']) ? $_G['cache']['threadtableids'] : array();
  669. $posttableids = !empty($_G['cache']['posttableids']) ? $_G['cache']['posttableids'] : array();
  670. $threadtableids = array_unique(array_merge(array('0'), $threadtableids));
  671. $posttableids = array_unique(array_merge(array('0'), $threadtableids));
  672. foreach($threadtableids as $tableid) {
  673. $threads = C::t('forum_thread')->fetch_all_by_tid($tids, 0, 0, $tableid);
  674. if (count($threads)) {
  675. foreach ($threads as $tid => $thread) {
  676. if ($thread['displayorder'] == '-1') {
  677. unset($threads[$tid]);
  678. }
  679. }
  680. $postids[$tableid] = array_keys($threads);
  681. }
  682. }
  683. foreach ($posttableids as $postTableId) {
  684. if (count($postids[$postTableId])) {
  685. $posts = C::t('forum_post')->fetch_all_by_tid($postTableId, $tids, 1, '', 0, 0, 1);
  686. foreach ($posts as $data) {
  687. $logData[] = array(
  688. 'tid' => $data['tid'],
  689. 'pid' => $data['pid'],
  690. 'fid' => $data['fid'],
  691. 'uid' => $data['authorid'],
  692. 'clientIp' => $data['useip'],
  693. 'openId' => $this->_getOpenId($data['authorid']),
  694. );
  695. }
  696. }
  697. }
  698. if (count($logData)) {
  699. foreach ($logData as $data) {
  700. $this->logFailed('delThread', $data, $reason);
  701. }
  702. }
  703. }
  704. public function getOperateData($type, $limit = 20) {
  705. if (!self::$_secStatus) {
  706. return false;
  707. }
  708. $allowType = array('post', 'user', 'member');
  709. $operateData = array();
  710. $operateResultData = array();
  711. if ($type == 'member') {
  712. $type = 'user';
  713. }
  714. if (!in_array($type, $allowType)) {
  715. return false;
  716. }
  717. $tableName = '#security#security_evil' . $type;
  718. $operateData = C::t($tableName)->fetch_all_report($limit);
  719. foreach($operateData as $tempData) {
  720. $operateResult = $tempData['operateresult'] == 1 ? 'recover' : 'delete';
  721. if ($type == 'post') {
  722. require_once libfile('function/forum');
  723. $detailData = get_post_by_pid($tempData['pid']);
  724. $detailData['pid'] = $tempData['pid'];
  725. $detailData['tid'] = $tempData['tid'];
  726. $detailData['uid'] = $id = $tempData['pid'];
  727. } elseif ($type == 'user') {
  728. $detailData = C::t('common_member')->fetch($tempData['uid'], 0, 1);
  729. $detailData['uid'] = $id = $tempData['uid'];
  730. }
  731. if ($type == 'post') {
  732. $operateType = $detailData['first'] ? 'thread' : 'post';
  733. } elseif ($type == 'user') {
  734. $operateType = 'member';
  735. }
  736. $data = array(
  737. 'tid' => $detailData['tid'] ? $detailData['tid'] : 0,
  738. 'pid' => $detailData['pid'] ? $detailData['pid'] : 0,
  739. 'fid' => $detailData['fid'] ? $detailData['fid'] : 0,
  740. 'operateType' => $operateType,
  741. 'operate' => $operateResult,
  742. 'operateId' => $id,
  743. 'uid' => $detailData['authorid'] ? $detailData['authorid'] : $detailData['uid'],
  744. );
  745. $data['openId'] = $this->_getOpenId($data['uid']);
  746. $data['clientIp'] = $detailData['useip'] ? $detailData['useip'] : $this->_getMemberIp($data['uid']);
  747. $operateResultData[] = $data;
  748. }
  749. return $operateResultData;
  750. }
  751. public function markasreported($operateType, $operateData) {
  752. if (!self::$_secStatus) {
  753. return false;
  754. }
  755. foreach ($operateData as $data) {
  756. $operateId[] = $data['operateId'];
  757. }
  758. if (!is_array($operateId) || !count($operateId)) {
  759. return false;
  760. }
  761. if ($operateType == 'member') {
  762. C::t('#security#security_eviluser')->update($operateId, array('isreported' => 1));
  763. } elseif(in_array($operateType, array('thread', 'post'))) {
  764. C::t('#security#security_evilpost')->update($operateId, array('isreported' => 1));
  765. }
  766. return true;
  767. }
  768. public function updatePostOperate($ids, $operate) {
  769. if (!self::$_secStatus) {
  770. return false;
  771. }
  772. $result = $this->_getOperateResult($operate);
  773. C::t('#security#security_evilpost')->update($ids, array('operateresult' => $result));
  774. return true;
  775. }
  776. public function updateThreadOperate($ids, $operate) {
  777. if (!self::$_secStatus) {
  778. return false;
  779. }
  780. $result = $this->_getOperateResult($operate);
  781. C::t('#security#security_evilpost')->update_by_tid($ids, array('operateresult' => $result));
  782. return true;
  783. }
  784. public function updateMemberOperate($ids, $operate) {
  785. if (!self::$_secStatus) {
  786. return false;
  787. }
  788. $result = $this->_getOperateResult($operate);
  789. C::t('#security#security_eviluser')->update($ids, array('operateresult' => $result));
  790. return true;
  791. }
  792. public function updateMemberRecover($username) {
  793. if (!$username || !self::$_secStatus) {
  794. return false;
  795. }
  796. $uid = C::t('common_member')->fetch_uid_by_username($username);
  797. $this->updateMemberOperate(array($uid), 'recover');
  798. return true;
  799. }
  800. private function _getOperateResult($str) {
  801. $mapArray = array(
  802. 'recover' => 1,
  803. 'delete' => 2,
  804. );
  805. return $mapArray[$str];
  806. }
  807. private function benchMarkLog($startTime, $id, $data, $type) {
  808. return true;
  809. $util = Cloud::loadClass('Service_Util');
  810. $endTime = microtime(true);
  811. $dataSize = strlen($util->httpBuildQuery($data));
  812. $content = array(
  813. date('Y-m-d H:i:s', $startTime),
  814. $endTime - $startTime,
  815. $type,
  816. $id,
  817. $dataSize,
  818. );
  819. $content = join(',', $content) . "\n";
  820. }
  821. }