nextwind /src/service/user/srv/PwFindPassword.php

Language PHP Lines 323
MD5 Hash 61ea7d80809103bd5778ce7d790c0d1d
Repository https://github.com/cuijinquan/nextwind.git View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
<?php
Wind::import('LIB:utility.PwMail');
Wind::import('SRV:user.dm.PwUserInfoDm');
/**
 * 用户找回密码服务
 *
 * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
 * @copyright ©2003-2103 phpwind.com
 * @license http://www.phpwind.com
 * @version $Id: PwFindPassword.php 24177 2013-01-22 10:36:09Z xiaoxia.xuxx $
 * @package src.service.user.srv
 */
class PwFindPassword {
	/* @var $byMobileNum int 用手机找回密码可以使用的次数限制 */
	private $byMobileNum = 5;
	/* @var $byEmaialNum int 用邮箱找回密码可以使用的次数限制 */
	private $byEmailNum = 5;
	/* @var $spaceDay int 达到次数上限的时候相隔下次可以使用的时间间隔(单位:天)*/
	private $spaceDay = 1;
	private $info = array();
	
	const WAY_EMAIL = 'email';
	const WAY_MOBILE = 'mobile';
	
	/**
	 * 构造函数
	 *
	 * @param string $username
	 */
	public function __construct($username) {
		/* @var $userDs PwUser */
		$userDs = Wekit::load('user.PwUser');
		$info = $userDs->getUserByName($username, PwUser::FETCH_MAIN | PwUser::FETCH_DATA | PwUser::FETCH_INFO);
		if (!$info) {
			$info = $this->_getWindid()->getUser($username, 2);
			if (!$info) return;
			Wind::import('SRV:user.srv.PwRegisterService');
			$registerService = new PwRegisterService();
			$info = $registerService->sysUser($info['uid']);
			if ($info) {
				$info = array_merge($info, $this->_getUserDs()->getUserByUid($info['uid'], PwUser::FETCH_INFO));
			}
		}
		$this->info = $info;
	}
	
	/**
	 * 检查邮箱是否正确
	 *
	 * @param string $email 邮箱
	 * @return boolean|PwError
	 */
	public function checkEmail($email) {
		if (!$this->info) return new PwError('USER:illegal.request');
		if ($this->info['email'] != $email) {
			return new PwError('USER:findpwd.error.email');
		}
		if (true !== ($check = $this->allowFindBy(self::WAY_EMAIL))) return $check;
		return true;
	}
	
	/**
	 * 发送重置邮件
	 *
	 * @param string $state 加密串
	 * @return boolean
	 */
	public function sendResetEmail($state) {
		if (true !== ($check = $this->allowFindBy(self::WAY_EMAIL))) return $check;
		//TODO 产生激活码的方法
		$code = substr(md5(Pw::getTime()), mt_rand(1, 8), 8);
		$url = WindUrlHelper::createUrl('u/findPwd/resetpwd', array('code' => $code, '_statu' => $state));
		list($title, $content) = $this->_buildTitleAndContent($this->info['username'], $url);
		/* @var $activeCodeDs PwUserActiveCode */
		$activeCodeDs = Wekit::load('user.PwUserActiveCode');
		$activeCodeDs->addActiveCode($this->info['uid'], $this->info['email'], $code, Pw::getTime(), PwUserActiveCode::RESETPWD);
		$mail = new PwMail();
		$mail->sendMail($this->info['email'], $title, $content);
		return true;
	}

	/**
	 * 重置的邮箱验证码是否有效
	 *
	 * @param string $email 重置的email地址
	 * @param string $code  重置码
	 * @return PwError|boolean
	 */
	public function checkResetEmail($email, $code) {
		if (empty($this->info) || $this->info['email'] != $email) {
			return new PwError('USER:illegal.request');
		}
		/* @var $activeCodeDs PwUserActiveCode */
		$activeCodeDs = Wekit::load('user.PwUserActiveCode');
		$info = $activeCodeDs->getInfoByUid($this->info['uid'], PwUserActiveCode::RESETPWD);
		if (!$info || $info['email'] != $email || $info['code'] != $code) return new PwError("USER:findpwd.email.code.expired");
		/*找回密码:验证码不需要过期及验证机制*/
		if ($info['active_time'] > 0 ) return new PwError('USER:findpwd.email.code.expired');
		/*$validTime = $this->activeCodeValidTime * 3600;
		if (($info['send_time'] + $validTime) < Pw::getTime()) return new PwError('USER:active.email.overtime');*/
//		$activeCodeDs->activeCode($this->info['uid'], Pw::getTime());
		return true;
	}
	
	/**
	 * 获得信息的标题和内容
	 *
	 * @param string $titleKey   标题key
	 * @param string $contentKey 内容key
	 * @param string $username 用户名
	 * @param string $url 链接地址
	 * @return array
	 */
	private function _buildTitleAndContent($username, $url = '') {
		$search = array('{username}', '{sitename}');
		$replace = array($username, Wekit::C('site', 'info.name'));
		$title = str_replace($search, $replace, Wekit::C('login', 'resetpwd.mail.title'));
		$search[] = '{time}';
		$search[] = '{url}';
		$replace[] = Pw::time2str(Pw::getTime(), 'Y-m-d H:i:s');
		$replace[] = $url ? sprintf('<a href="%s">%s</a>', $url, $url) : '';
		$content = str_replace($search, $replace, Wekit::C('login', 'resetpwd.mail.content'));
		return array($title, $content);
	}
	
	/**
	 * 获得邮箱的模糊显示
	 *
	 * @return string
	 */
	public function getFuzzyEmail() {
		$email = $this->info['email'];
		$info = explode('@', $email);
		$info[0] = $info[0][0] . str_repeat('*', strlen($info[0]) - 1);
		return implode('@', $info);
	}
	
	/**
	 * 获得email链接地址
	 *
	 * @return string
	 */
	public function getEmailUrl() {
		$email = $this->info['email'];
		$info = explode('@', $email);
		return 'http://mail.' . $info[1];
	}
	
	/**
	 * 是否可以使用邮箱找回密码
	 *
	 * @return boolean
	 */
	public function allowFindByMail() {
		if (false === $this->isBindMail()) return new PwError('USER:findpwd.notbind.email');
		return $this->allowFindBy(self::WAY_EMAIL);
	}
	
	/**
	 * 是否可以使用手机号码找回密码
	 *
	 * @return boolean
	 */
	public function allowFindByMobile() {
		if (false === $this->isBindMobile()) return new PwError('USER:findpwd.notbind.mobile');
		return $this->allowFindBy(self::WAY_MOBILE);
	}
	
	/**
	 * 是否绑定email
	 *
	 * @return boolean
	 */
	public function isBindMail() {
		return $this->info['email'] ? true : false;
	}
	
	
	/**
	 * 是否绑定手机号码
	 *
	 * @return boolean
	 */
	public function isBindMobile() {
		return $this->info['mobile'] ? true : false;
	}
	
	/**
	 * 判断当天通过邮箱找回密码是否已经超过次数限制
	 *
	 * @return boolean
	 */
	public function isOverByMail() {
		return $this->allowFindBy(self::WAY_EMAIL) instanceof PwError ? true : false;
	}
	
	/**
	 * 判断当天通过手机找回密码是否已经超过次数限制
	 *
	 * @return boolean
	 */
	public function isOverByMobile() {
		return $this->allowFindBy(self::WAY_MOBILE) instanceof PwError ? true : false;
	}
	
	/**
	 * 更改成功
	 *
	 * @param string $type
	 * @return boolean
	 */
	public function success($type) {
		//更新找回密码验证码
		/* @var $activeCodeDs PwUserActiveCode */
		$activeCodeDs = Wekit::load('user.PwUserActiveCode');
		$activeCodeDs->activeCode($this->info['uid'], Pw::getTime());
		return $this->setRecode($type);
	}
	
	/**
	 * 创建找回密码的唯一标识
	 *
	 * @param string $username 需要找回密码的用户名
	 * @param string $way 找回方式标识
	 * @param string $value 找回方式对应的值
	 * @return string
	 */
	public static function createFindPwdIdentify($username, $way, $value) {
		$code = Pw::encrypt($username . '|' . $way . '|' . $value, Wekit::C('site', 'hash') . '___findpwd');
		return rawurlencode($code);
	}
	
	/**
	 * 解析找回密码的标识
	 *
	 * @param string $identify
	 * @return array array($username, $way, $value)
	 */
	public static function parserFindPwdIdentify($identify) {
		return explode("|", Pw::decrypt(rawurldecode($identify), Wekit::C('site', 'hash') . '___findpwd'));
	}
	
	/**
	 * 根据方式获取对应的用户字段
	 *
	 * @param string $way
	 * @return string
	 */
	public static function getField($way) {
		return $way == self::WAY_MOBILE ? 'mobile' : 'email';
	}
	
	/**
	 * 获得尝试错误记录
	 *
	 * 在findpwd中保存格式为:0000-00-00:num|0000-00-00:num
	 * 0000-00-00:最后更新该记录的时间
	 * num : 最后更新记录的时候此种方式已经尝试的次数
	 * |: 在|左侧的,是用“邮箱”方式找回的记录,在|右侧,是用“手机”方式找回的记录
	 * @param string $type 找回类型
	 * @return boolean|PwError
	 */
	private function allowFindBy($type = self::WAY_EMAIL) {
		$findPwd = $this->info['findpwd'];
		if (!$findPwd) return true;
		$typeCode = $type == self::WAY_MOBILE ? 0 : 1;
		$recodes = explode('|', $findPwd);
		if (empty($recodes[$typeCode])) return true;
		$tryNum = $type == self::WAY_MOBILE ? $this->byMobileNum : $this->byEmailNum;
		list($time, $num) = explode(':', $recodes[$typeCode]);
		if (($time != Pw::time2str(Pw::getTime(), 'Y-m-d')) || $num < $tryNum) return true;
		return new PwError('USER:findpwd.over.limit.' . $type);
	}
	
	/**
	 * 设置重新找回记录
	 *
	 * 在findpwd中保存格式为:0000-00-00:num|0000-00-00:num
	 * 0000-00-00:最后更新该记录的时间
	 * num : 最后更新记录的时候此种方式已经尝试的次数
	 * |: 在|左侧的,是用“邮箱”方式找回的记录,在|右侧,是用“手机”方式找回的记录
	 * @param string $type
	 * @return true
	 */
	public function setRecode($type = self::WAY_EMAIL) {
		$findPwd = $this->info['findpwd'];
		$recodes = array(0 => '', 1 => '');
		$typeCode = $type == self::WAY_MOBILE ? 0 : 1;
		$tryTime = $type == self::WAY_MOBILE ? $this->byMobileNum : $this->byEmailNum;
		/*如果重来没有尝试找回过密码*/
		if (!$findPwd) {
			$recodes[$typeCode] = Pw::time2str(Pw::getTime(), 'Y-m-d') . ':1';
		} else {
			list($recodes[0], $recodes[1]) = explode('|', $findPwd);
			/*如果该方式的找回密码方式没有尝试过*/
			if (!($recode = $recodes[$typeCode])) {
				$recodes[$typeCode] = Pw::time2str(Pw::getTime(), 'Y-m-d') . ':1';
			/*如果该方式的找回密码方式尝试过*/
			} else {
				list($time, $num) = explode(':', $recode);
				/*如果该方式的上次找回密码不是在今天发生,那么这是今天第一次找回密码*/
				if (($time != Pw::time2str(Pw::getTime(), 'Y-m-d'))) {
					$recodes[$typeCode] = Pw::time2str(Pw::getTime(), 'Y-m-d') . ':1';
				/*如果今天不是第一次尝试找回密码,并且今天尝试找回密码的次数已经超过规定次数,抛出错误*/
				} elseif ($num >= $tryTime) {
					return new PwError('USER:findpwd.over.limit.' . $type);
				/*否则记录今天找回密码的次数*/
				} else {
					$recodes[$typeCode] = $time . ':' . ($num + 1);
				}
			}
		}
		/* @var $userDs PwUser */
		$userDs = Wekit::load('user.PwUser');
		$userdm = new PwUserInfoDm($this->info['uid']);
		$userdm->setFindpwd(implode('|', $recodes));
		return $userDs->editUser($userdm, PwUser::FETCH_DATA);
	}
	
	protected function _getWindid() {
		return WindidApi::api('user');
	}
}
Back to Top