国内流行的内容管理系统(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.

561 lines
19KB

  1. <?php
  2. if (!defined('DEDEINC')) exit ('dedebiz');
  3. /**
  4. * 会员登录
  5. *
  6. * @version $id:userlogin.class.php 15:59 2010年7月5日 tianya $
  7. * @package DedeBIZ.Libraries
  8. * @copyright Copyright (c) 2022 DedeBIZ.COM
  9. * @license https://www.dedebiz.com/license
  10. * @link https://www.dedebiz.com
  11. */
  12. //使用缓存助手
  13. helper('cache');
  14. /**
  15. * 检查会员名的合法性
  16. *
  17. * @access public
  18. * @param string $uid 会员UID
  19. * @param string $msgtitle 提示标题
  20. * @param string $ckhas 检查是否存在
  21. * @return string
  22. */
  23. function CheckUserID($uid, $msgtitle = '会员名', $ckhas = TRUE)
  24. {
  25. global $cfg_mb_notallow, $cfg_mb_idmin, $cfg_md_idurl, $cfg_soft_lang, $dsql;
  26. if ($cfg_mb_notallow != '') {
  27. $nas = explode(',', $cfg_mb_notallow);
  28. if (in_array($uid, $nas)) {
  29. return $msgtitle.'为系统禁止的标识';
  30. }
  31. }
  32. if ($cfg_md_idurl == 'Y' && preg_match("/[^a-z0-9]/i", $uid)) {
  33. return $msgtitle.'必须由英文字母或数字组成';
  34. }
  35. if ($cfg_soft_lang == 'utf-8') {
  36. $ck_uid = utf82gb($uid);
  37. } else {
  38. $ck_uid = $uid;
  39. }
  40. for ($i = 0; isset($ck_uid[$i]); $i++) {
  41. if (ord($ck_uid[$i]) > 0x80) {
  42. if (isset($ck_uid[$i + 1]) && ord($ck_uid[$i + 1]) > 0x40) {
  43. $i++;
  44. } else {
  45. return $msgtitle.'建议用英文字母和数字组合';
  46. }
  47. } else {
  48. if (preg_match("/[^0-9a-z@\.-]/i", $ck_uid[$i])) {
  49. return $msgtitle.'不能含有[@]、[.]、[-]以外的特殊符号';
  50. }
  51. }
  52. }
  53. if ($ckhas) {
  54. $row = $dsql->GetOne("SELECT * FROM `#@__member` WHERE userid LIKE '$uid' ");
  55. if (is_array($row)) return $msgtitle."已经存在";
  56. }
  57. return 'ok';
  58. }
  59. /**
  60. * 检查会员是否被禁言
  61. *
  62. * @return void
  63. */
  64. function CheckNotAllow()
  65. {
  66. global $cfg_ml;
  67. if (empty($cfg_ml->M_ID)) return;
  68. if ($cfg_ml->M_Spacesta == -2) {
  69. ShowMsg("您已经被禁言,请与管理员联系", "-1");
  70. exit();
  71. } else if ($cfg_ml->M_Spacesta == -10) {
  72. ShowMsg("系统开启了邮件审核机制,因此您的帐号需要审核后才能发信息", "-1");
  73. exit();
  74. } else if ($cfg_ml->M_Spacesta < 0) {
  75. ShowMsg('系统开启了审核机制,因此您的帐号需要管理员审核后才能发信息', '-1');
  76. exit();
  77. }
  78. }
  79. function FormatUsername($username)
  80. {
  81. $username = str_replace("`", "‘", $username);
  82. $username = str_replace("'", "‘", $username);
  83. $username = str_replace("\"", "“", $username);
  84. $username = str_replace(",", ",", $username);
  85. $username = str_replace("(", "(", $username);
  86. $username = str_replace(")", ")", $username);
  87. return addslashes($username);
  88. }
  89. /**
  90. * 网站会员登录类
  91. *
  92. * @package MemberLogin
  93. * @subpackage DedeBIZ.Libraries
  94. * @link https://www.dedebiz.com
  95. */
  96. class MemberLogin
  97. {
  98. var $M_ID;
  99. var $M_LoginID;
  100. var $M_MbType;
  101. var $M_Money;
  102. var $M_UserMoney;
  103. var $M_Scores;
  104. var $M_UserName;
  105. var $M_Rank;
  106. var $M_Face;
  107. var $M_LoginTime;
  108. var $M_KeepTime;
  109. var $M_Spacesta;
  110. var $fields;
  111. var $M_UpTime;
  112. var $M_ExpTime;
  113. var $M_HasDay;
  114. var $M_JoinTime;
  115. var $M_Honor = '';
  116. var $M_SendMax = 0;
  117. var $memberCache = 'memberlogin';
  118. var $dsql;
  119. //php5构造函数
  120. function __construct($kptime = -1, $cache = FALSE)
  121. {
  122. global $dsql;
  123. $this->dsql = $dsql;
  124. if ($kptime == -1) {
  125. $this->M_KeepTime = 3600 * 24 * 7;
  126. } else {
  127. $this->M_KeepTime = $kptime;
  128. }
  129. $formcache = FALSE;
  130. $this->M_ID = $this->GetNum(GetCookie("DedeUserID"));
  131. $this->M_LoginTime = GetCookie("DedeLoginTime");
  132. $this->fields = array();
  133. if (empty($this->M_ID)) {
  134. $this->ResetUser();
  135. } else {
  136. $this->M_ID = intval($this->M_ID);
  137. if ($cache) {
  138. $this->fields = GetCache($this->memberCache, $this->M_ID);
  139. if (empty($this->fields)) {
  140. $this->fields = $this->dsql->GetOne("SELECT * FROM `#@__member` WHERE mid='{$this->M_ID}' ");
  141. } else {
  142. $formcache = TRUE;
  143. }
  144. } else {
  145. $this->fields = $this->dsql->GetOne("SELECT * FROM `#@__member` WHERE mid='{$this->M_ID}' ");
  146. }
  147. if (is_array($this->fields)) {
  148. //间隔一小时更新一次会员登录时间
  149. if (time() - $this->M_LoginTime > 3600) {
  150. $this->dsql->ExecuteNoneQuery("update `#@__member` set logintime='".time()."',loginip='".GetIP()."' WHERE mid='".$this->fields['mid']."';");
  151. PutCookie("DedeLoginTime", time(), $this->M_KeepTime);
  152. }
  153. $this->M_LoginID = $this->fields['userid'];
  154. $this->M_MbType = $this->fields['mtype'];
  155. $this->M_Money = $this->fields['money'];
  156. $this->M_UserMoney = $this->fields['user_money'];
  157. $this->M_UserName = FormatUsername($this->fields['uname']);
  158. $this->M_Scores = $this->fields['scores'];
  159. $this->M_Face = $this->fields['face'];
  160. $this->M_Rank = $this->fields['rank'];
  161. $this->M_Spacesta = $this->fields['spacesta'];
  162. $sql = "SELECT titles From `#@__scores` WHERE integral<={$this->fields['scores']} ORDER BY integral DESC";
  163. $scrow = $this->dsql->GetOne($sql);
  164. $this->fields['honor'] = $scrow['titles'];
  165. $this->M_Honor = $this->fields['honor'];
  166. $this->M_UpTime = $this->fields['uptime'];
  167. $this->M_ExpTime = $this->fields['exptime'];
  168. $this->M_SendMax = $this->fields['send_max'];
  169. $this->M_JoinTime = MyDate('Y-m-d', $this->fields['jointime']);
  170. if ($this->M_Rank > 10 && $this->M_UpTime > 0) {
  171. $this->M_HasDay = $this->Judgemember();
  172. }
  173. if (!$formcache) {
  174. SetCache($this->memberCache, $this->M_ID, $this->fields, 1800);
  175. }
  176. } else {
  177. $this->ResetUser();
  178. }
  179. }
  180. }
  181. function MemberLogin($kptime = -1)
  182. {
  183. $this->__construct($kptime);
  184. }
  185. /**
  186. * 删除缓存,每次登录时和在修改会员资料的地方会清除
  187. *
  188. * @access public
  189. * @param string
  190. * @return string
  191. */
  192. function DelCache($mid)
  193. {
  194. DelCache($this->memberCache, $mid);
  195. }
  196. /**
  197. * 判断会员是否到期
  198. *
  199. * @return string
  200. */
  201. function Judgemember()
  202. {
  203. global $cfg_mb_rank;
  204. $nowtime = time();
  205. $mhasDay = $this->M_ExpTime - ceil(($nowtime - $this->M_UpTime) / 3600 / 24) + 1;
  206. if ($mhasDay <= 0) {
  207. $this->dsql->ExecuteNoneQuery("UPDATE `#@__member` SET uptime='0',exptime='0',`rank`='$cfg_mb_rank' WHERE mid='".$this->fields['mid']."';");
  208. }
  209. return $mhasDay;
  210. }
  211. /**
  212. * 退出cookie的会话
  213. *
  214. * @return void
  215. */
  216. function ExitCookie()
  217. {
  218. $this->ResetUser();
  219. }
  220. /**
  221. * 验证会员是否已经登录
  222. *
  223. * @return bool
  224. */
  225. function IsLogin()
  226. {
  227. if ($this->M_ID > 0) return TRUE;
  228. else return FALSE;
  229. }
  230. /**
  231. * 检测会员上传空间
  232. *
  233. * @return int
  234. */
  235. function GetUserSpace()
  236. {
  237. $uid = $this->M_ID;
  238. $row = $this->dsql->GetOne("SELECT sum(filesize) AS fs FROM `#@__uploads` WHERE mid='$uid';");
  239. return $row['fs'];
  240. }
  241. /**
  242. * 检查会员空间信息
  243. *
  244. * @return void
  245. */
  246. function CheckUserSpace()
  247. {
  248. global $cfg_mb_max;
  249. $uid = $this->M_ID;
  250. $hasuse = $this->GetUserSpace();
  251. $maxSize = $cfg_mb_max * 1024 * 1024;
  252. if ($hasuse >= $maxSize) {
  253. ShowMsg('您的空间已满,不允许上传新文件', '-1');
  254. exit();
  255. }
  256. }
  257. /**
  258. * 更新会员信息统计表
  259. *
  260. * @access public
  261. * @param string $field 字段信息
  262. * @param string $uptype 更新类型
  263. * @return string
  264. */
  265. function UpdateUserTj($field, $uptype = 'add')
  266. {
  267. $mid = $this->M_ID;
  268. $arr = $this->dsql->GetOne("SELECT * `#@__member_tj` WHERE mid='$mid' ");
  269. if (!is_array($arr)) {
  270. $arr = array('article' => 0, 'album' => 0, 'archives' => 0, 'homecount' => 0, 'pagecount' => 0, 'feedback' => 0, 'friend' => 0, 'stow' => 0);
  271. }
  272. extract($arr);
  273. if (isset($$field)) {
  274. if ($uptype == 'add') {
  275. $$field++;
  276. } else if ($$field > 0) {
  277. $$field--;
  278. }
  279. }
  280. $inquery = "INSERT INTO `#@__member_tj` (`mid`,`article`,`album`,`archives`,`homecount`,`pagecount`,`feedback`,`friend`,`stow`) VALUES ('$mid','$article','$album','$archives','$homecount','$pagecount','$feedback','$friend','$stow'); ";
  281. $this->dsql->ExecuteNoneQuery("DELETE FROM `#@__member_tj` WHERE mid='$mid' ");
  282. $this->dsql->ExecuteNoneQuery($inquery);
  283. }
  284. /**
  285. * 重置会员信息
  286. *
  287. * @return void
  288. */
  289. function ResetUser()
  290. {
  291. $this->fields = '';
  292. $this->M_ID = 0;
  293. $this->M_LoginID = '';
  294. $this->M_Rank = 0;
  295. $this->M_Face = "";
  296. $this->M_Money = 0;
  297. $this->M_UserMoney = 0;
  298. $this->M_UserName = "";
  299. $this->M_LoginTime = 0;
  300. $this->M_MbType = '';
  301. $this->M_Scores = 0;
  302. $this->M_Spacesta = -2;
  303. $this->M_UpTime = 0;
  304. $this->M_ExpTime = 0;
  305. $this->M_JoinTime = 0;
  306. $this->M_HasDay = 0;
  307. DropCookie('DedeUserID');
  308. DropCookie('DedeLoginTime');
  309. }
  310. /**
  311. * 获取整数值
  312. *
  313. * @access public
  314. * @param string $fnum 处理的数值
  315. * @return string
  316. */
  317. function GetNum($fnum)
  318. {
  319. $fnum = preg_replace("/[^0-9\.]/", '', $fnum);
  320. return $fnum;
  321. }
  322. /**
  323. * 会员登录,把登录密码转为指定长度md5数据
  324. *
  325. * @access public
  326. * @param string $pwd 需要加密的密码
  327. * @return string
  328. */
  329. function GetEncodePwd($pwd)
  330. {
  331. global $cfg_mb_pwdtype;
  332. if (empty($cfg_mb_pwdtype)) $cfg_mb_pwdtype = '32';
  333. switch ($cfg_mb_pwdtype) {
  334. case 'l16':
  335. return substr(md5($pwd), 0, 16);
  336. case 'r16':
  337. return substr(md5($pwd), 16, 16);
  338. case 'm16':
  339. return substr(md5($pwd), 8, 16);
  340. default:
  341. return md5($pwd);
  342. }
  343. }
  344. /**
  345. * 会员登录,把数据库密码转为特定长度,如果数据库密码是明文,本程序不支持
  346. *
  347. * @access public
  348. * @param string
  349. * @return string
  350. */
  351. function GetShortPwd($dbpwd)
  352. {
  353. global $cfg_mb_pwdtype;
  354. if (empty($cfg_mb_pwdtype)) $cfg_mb_pwdtype = '32';
  355. $dbpwd = trim($dbpwd);
  356. if (strlen($dbpwd) == 16) {
  357. return $dbpwd;
  358. } else {
  359. switch ($cfg_mb_pwdtype) {
  360. case 'l16':
  361. return substr($dbpwd, 0, 16);
  362. case 'r16':
  363. return substr($dbpwd, 16, 16);
  364. case 'm16':
  365. return substr($dbpwd, 8, 16);
  366. default:
  367. return $dbpwd;
  368. }
  369. }
  370. }
  371. /**
  372. * 投稿是否被限制
  373. *
  374. * @return array
  375. */
  376. function IsSendLimited()
  377. {
  378. $arr = $this->dsql->GetOne("SELECT COUNT(*) as dd FROM `#@__arctiny` WHERE mid='{$this->M_ID}'");
  379. if (is_array($arr)) {
  380. if ($this->M_SendMax < 0) {
  381. return false;
  382. }
  383. if ($arr['dd'] >= $this->M_SendMax) {
  384. return true;
  385. } else {
  386. return false;
  387. }
  388. } else {
  389. return true;
  390. }
  391. }
  392. /**
  393. * 检查会员是否合法
  394. *
  395. * @access public
  396. * @param string $loginuser 登录会员名
  397. * @param string $loginpwd 会员密码
  398. * @return string
  399. */
  400. function CheckUser(&$loginuser, $loginpwd)
  401. {
  402. //检测会员名的合法性
  403. $rs = CheckUserID($loginuser, '会员名', FALSE);
  404. //会员名不正确时返回验证错误,原登录名通过引用返回错误提示信息
  405. if ($rs != 'ok') {
  406. $loginuser = $rs;
  407. return '0';
  408. }
  409. //matt=10是管理员关连的前台帐号,为了安全起见,这个帐号只能从后台登录,不能直接从前台登录
  410. $row = $this->dsql->GetOne("SELECT mid,matt,pwd,pwd_new,logintime FROM `#@__member` WHERE userid LIKE '$loginuser' ");
  411. if (is_array($row)) {
  412. if (!empty($row['pwd_new']) && !password_verify($loginpwd, $row['pwd_new'])) {
  413. $this->loginError($loginuser);
  414. return -1;
  415. } else if (!empty($row['pwd']) && $this->GetShortPwd($row['pwd']) != $this->GetEncodePwd($loginpwd)) {
  416. $this->loginError($loginuser);
  417. return -1;
  418. } else {
  419. if (empty($row['pwd_new']) && function_exists('password_hash')) {
  420. //升级密码
  421. $newpwd = password_hash($loginpwd, PASSWORD_BCRYPT);
  422. $inquery = "UPDATE `#@__member` SET pwd='',pwd_new='{$newpwd}' WHERE mid='".$row['mid']."'";
  423. $this->dsql->ExecuteNoneQuery($inquery);
  424. }
  425. //管理员帐号不允许从前台登录
  426. if ($row['matt'] == 10) {
  427. return -2;
  428. } else {
  429. $this->PutLoginInfo($row['mid'], $row['logintime']);
  430. return 1;
  431. }
  432. }
  433. } else {
  434. return 0;
  435. }
  436. }
  437. /**
  438. * 是否需要验证码
  439. *
  440. * @param mixed $loginuser
  441. * @return bool
  442. */
  443. function isNeedCheckCode($loginuser)
  444. {
  445. $num = $this->getLoginError($loginuser);
  446. return $num >= 3 ? true : false;
  447. }
  448. /**
  449. * 1分钟以内登录错误的次数
  450. *
  451. * @param mixed $loginuser
  452. * @return int 登录错误次数
  453. */
  454. function getLoginError($loginuser)
  455. {
  456. $rs = CheckUserID($loginuser, '会员名', FALSE);
  457. //会员名不正确时返回验证错误,原登录名通过引用返回错误提示信息
  458. if ($rs != 'ok') {
  459. return -1;
  460. }
  461. if (!TableHasField("#@__member", "loginerr")) {
  462. return 0;
  463. }
  464. $row = $this->dsql->GetOne("SELECT loginerr,logintime FROM `#@__member` WHERE userid LIKE '$loginuser'");
  465. if (is_array($row)) {
  466. //1分钟内如果输错3次则需要验证码
  467. return (time() - (int)$row['logintime']) < 60 ? (int)$row['loginerr'] : 0;
  468. } else {
  469. return -1;
  470. }
  471. }
  472. /**
  473. * 记录登录错误
  474. *
  475. * @return void
  476. */
  477. function loginError($loginuser)
  478. {
  479. $rs = CheckUserID($loginuser, '会员名', FALSE);
  480. //会员名不正确时返回验证错误,原登录名通过引用返回错误提示信息
  481. if ($rs != 'ok') {
  482. return;
  483. }
  484. $loginip = GetIP();
  485. $inquery = "UPDATE `#@__member` SET loginip='$loginip',logintime='".time()."',loginerr=loginerr+1 WHERE userid='".$loginuser."'";
  486. $this->dsql->ExecuteNoneQuery($inquery);
  487. }
  488. /**
  489. * 保存会员cookie
  490. *
  491. * @access public
  492. * @param string $uid 会员id
  493. * @param string $logintime 登录限制时间
  494. * @return void
  495. */
  496. function PutLoginInfo($uid, $logintime = 0)
  497. {
  498. global $cfg_login_adds;
  499. //登录添加积分(上一次登录时间必须大于两小时)
  500. if (time() - $logintime > 7200 && $cfg_login_adds > 0) {
  501. $this->dsql->ExecuteNoneQuery("UPDATE `#@__member` SET `scores`=`scores`+{$cfg_login_adds} WHERE mid='$uid' ");
  502. }
  503. $this->M_ID = $uid;
  504. $this->M_LoginTime = time();
  505. $loginip = GetIP();
  506. $inquery = "UPDATE `#@__member` SET loginip='$loginip',logintime='".$this->M_LoginTime."',loginerr=0 WHERE mid='".$uid."'";
  507. $this->dsql->ExecuteNoneQuery($inquery);
  508. if ($this->M_KeepTime > 0) {
  509. PutCookie('DedeUserID', $uid, $this->M_KeepTime);
  510. PutCookie('DedeLoginTime', $this->M_LoginTime, $this->M_KeepTime);
  511. } else {
  512. PutCookie('DedeUserID', $uid);
  513. PutCookie('DedeLoginTime', $this->M_LoginTime);
  514. }
  515. }
  516. function GetMemberTypeName()
  517. {
  518. if ($this->M_Rank == 0) {
  519. return '注册会员';
  520. } else {
  521. $row = $this->dsql->GetOne("SELECT membername FROM `#@__arcrank` WHERE `rank`='".$this->M_Rank."'");
  522. return $row['membername'];
  523. }
  524. }
  525. /**
  526. * 获得会员目前的状态
  527. *
  528. * @access public
  529. * @return string
  530. */
  531. function GetSta()
  532. {
  533. $sta = '';
  534. if ($this->M_Rank == 0) {
  535. $sta .= "您目前等级是:注册会员";
  536. } else {
  537. $row = $this->dsql->GetOne("SELECT membername FROM `#@__arcrank` WHERE `rank`='".$this->M_Rank."'");
  538. $sta .= "您目前等级是:".$row['membername'];
  539. $rs = $this->dsql->GetOne("SELECT id FROM `#@__admin` WHERE userid='".$this->M_LoginID."'");
  540. if (!is_array($rs)) {
  541. if ($this->M_Rank > 10 && $this->M_HasDay > 0) $sta .= ",剩余<span class='text-primary'>".$this->M_HasDay."</span>天";
  542. elseif ($this->M_Rank > 10) $sta .= ",<span class='text-danger'>会员已到期</span>";
  543. }
  544. }
  545. $sta .= ",积分<span class='text-primary'>{$this->M_Scores}</span>分,金币<span class='text-primary'>{$this->M_Money}</span>个,余额<span class='text-primary'>{$this->M_UserMoney}</span>元";
  546. return $sta;
  547. }
  548. //获取能够发布文档的栏目
  549. public static function GetEnabledChannels() {
  550. global $dsql;
  551. $result = array();
  552. $dsql->SetQuery("SELECT channeltype FROM `#@__arctype` GROUP BY channeltype");
  553. $dsql->Execute();
  554. $candoChannel = '';
  555. while ($row = $dsql->GetObject()) {
  556. $result[] = $row->channeltype;
  557. }
  558. return $result;
  559. }
  560. }//End Class
  561. ?>