需求分析
- 用戶使用手機號 + 短信驗證碼實現(xiàn)快速登錄系統(tǒng)
- 用戶不存在,則自動創(chuàng)建用戶帳號
- 每次登錄需要更新最后登陸時間
- 如果配置為單點登陸,則每次登陸都生成一個新的 TOKEN(用戶身份標識)

功能流程圖
接口地址: http://127.0.0.1:20081/user/login
請求方式: POST
請求參數(shù):
| 參數(shù)名 | 必選 | 類型 | 說明 |
|---|---|---|---|
| user_mobile | 是 | string | 手機號 |
| code | 是 | string | 短信驗證碼 |
返回示例:
{
"status": "1",
"item": {
"user_token": "fa630cac17ebdfb115e13c3de8857a5a"
}
}
返回參數(shù)說明:
| 參數(shù)名 | 說明 |
|---|---|
| user_token | 用戶身份標識 |
創(chuàng)建接口
- 在
/app/controllers目錄下創(chuàng)建控件器文件UserController.php,添加代碼:
<?php
class UserController extends BaseController
{
/**
* 用戶登陸
* @throws Exception
*/
public function loginAction()
{
// 驗證請求方法是否是POST
$this->isPost();
}
}
以上代碼,創(chuàng)建了登陸接口,并驗證了請求方式必須為 POST。
- 打開
/app/config/config.php, 在authentication.exclude添加元素user/login。將登陸接口排除身份認證。如:
// 身份認證配置
'authentication' => [
'enable' => 1, // 身份認證: 0 關閉, 1 激活
'single' => 0, // 單點登錄: 0 允許多個客戶端同時登錄; 1 同一時間,只請允許最后登錄設備使用
// 身份認證排除頁面
'exclude' => [
'index/index',
'user/login',
'sms/send',
]
],
請求參數(shù)驗證
- 手機號必填,且必須為11位有效手機號
- 4位數(shù)字有效短信驗證碼
- 為控制器
UserController創(chuàng)建驗證類XValidationUser, 并為loginAction()創(chuàng)建對應的驗證函數(shù)login(),如:
// 檢測是否為空
use Phalcon\Validation\Validator\PresenceOf;
// 正則表達式驗證
use Phalcon\Validation\Validator\Regex;
// 數(shù)字字符
use Phalcon\Validation\Validator\Digit;
// 介于二者之間,minimum<=x<=maximum
use Phalcon\Validation\Validator\Between;
/**
*
* 用戶參數(shù)驗證
*/
class XValidationUser
{
/**
* 登錄參數(shù)驗證
* @param $params
* @return bool
* @throws Exception
*/
public static function login($params)
{
$validation = new XValidation();
$validation->add('user_mobile', new PresenceOf(['message' => '缺少手機號碼']));
$validation->add('user_mobile', new Regex(['message' => '無效手機號碼', 'pattern' => '/^1[34578]{1}\d{9}$/']));
$validation->add('code', new PresenceOf(['message' => '缺少短信驗證碼']));
$validation->add('code', new Digit(['message' => '無效短信驗證碼']));
$validation->add('code', new Between(['message' => '無效短信驗證碼', 'minimum' => 1000, 'maximum' => 9999]));
$validation->add('code', new XValidatorCode(['message' => '無效短信驗證碼', 'with' => 'user_mobile']));
return $validation->valid($params);
}
}
以上
PresenceOf,Regex,Digit,Between為Phalcon內置驗證器,分別驗證必填參數(shù),手機號格式, 驗證碼是否為數(shù)字和是否在1000到9999之間(4位數(shù)字驗證)。
XValidatorCode為自定議短信驗證碼驗證器。
- 在
/app/library/SMS.php中添加函數(shù)validate(),添加以下代碼:
/**
* 驗證短信驗證碼
* 只有最后一次發(fā)送的驗證碼才有效
* 驗證碼有效時間5分鐘
* @param $mobile
* @param $code
* @return bool
*/
public function validate($mobile, $code)
{
$codes = $this->getCacheCodes($mobile);
if (count($codes) == 0) {
return false;
}
$lastCode = end($codes);
// 只有最后一次發(fā)送的驗證碼才有效
if ($lastCode['code'] != $code) {
return false;
}
// 驗證碼有效時間5分鐘
if ($this->config['valid_time'] > 0 && time() - $lastCode['time'] > $this->config['valid_time']) {
return false;
}
// 驗證碼已被驗證,自動失效
if (isset($lastCode['verified']) && $lastCode['verified'] == 1) {
return false;
}
// 通過驗證后,將驗證在碼狀態(tài)設置為已驗證
$codes[count($codes) - 1]['verified'] = 1;
// 更新緩存
XMemcache::instance('sms')->set($mobile, $codes);
return true;
}
- 檢測提交的手機號和驗證碼是否與緩存數(shù)據(jù)一致,是否已被驗證,是否過期等。
- 若通過驗證,還會將驗證在碼狀態(tài)設置為已驗證,防止重復使用。
- 創(chuàng)建短信驗證碼自定義驗證器,在
/app/library/目錄中新建XValidatorCode.php文件, 插入代碼 :
<?php
use Phalcon\Validation,
Phalcon\Validation\Validator,
Phalcon\Validation\ValidatorInterface,
Phalcon\Validation\Message;
class XValidatorCode extends Validator implements ValidatorInterface
{
/**
* @param Validation $validation
* @param $attribute
* @return bool
*/
public function validate(Validation $validation, $attribute)
{
$value = $validation->getValue($attribute);
$mobile = $validation->getValue($this->getOption('with'));
if (!SMS::instance()->validate($mobile, $value)) {
$message = $this->getOption('message');
if (!$message) {
$message = '短信驗證碼錯誤';
}
$validation->appendMessage(new Message($message, $attribute, 'Code'));
return false;
}
return true;
}
}
調用方法:
new XValidatorCode(['message' => '無效短信驗證碼', 'with' => 'user_mobile'],
數(shù)據(jù)庫連接
- 配置數(shù)據(jù)庫連接參數(shù),打開
/app/config/config.ini, 添加:
[database]
adapter = Mysql
host = localhost
username = root
password = 123456
dbname = demo
charset = utf8
port = 3306
prefix = dm_
請根據(jù)自己數(shù)據(jù)庫設置,自行更改對應參數(shù)
- 創(chuàng)建連接,打開
/app/public/index.php, 找到$di = new Phalcon\Di\FactoryDefault();, 在下面添加以下代碼:
// 設置數(shù)據(jù)庫服務
$di->set(
"db",
function () {
$config = Config::instance()->get('database', 'ini');
$config['options'] = [
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
PDO::ATTR_CASE => PDO::CASE_LOWER, // 強制列名小寫。
PDO::ATTR_ORACLE_NULLS => PDO::NULL_TO_STRING, // 將 NULL 轉換成空字符串。
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 僅僅返回以鍵值作為下標的查詢的結果集,名稱相同的數(shù)據(jù)只返回一個。
];
return new \Phalcon\Db\Adapter\Pdo\Mysql($config);
}
);
設置數(shù)據(jù)庫服務, 并設置PDO默認屬性:
- 指定數(shù)據(jù)庫編碼為UTF-8
- 強制指定列名小寫
- 將結果集中NULL轉換為空字符串
- 僅僅返回以鍵值作為下標的查詢的結果集,名稱相同的數(shù)據(jù)只返回一個
經(jīng)過上面的簡單操作,我們就可以在 Controller 中使用 $this->db 或模型來操作數(shù)據(jù)庫了。官方文檔
To be continued......