Restful API登录和注册实战开发
本地开发环境
使用本地apache和mysql,配置www.api.com虚拟主机。
接口项目需求
- 用户登录
- 用户注册
确认项目需求要素
- 资源路径(/users)
- HTTP动词(POST)
- 状态码(200,204,400,401,403,404,405,500)
- 错误处理(输出JSON格式错误信息)
- 返回结果(输出JSON数组或JSON对象)
数据库设计
用户登录和注册业务逻辑设计
lib/db.php(连接数据库)
1 <?php 2 // 链接数据库 3 $pdo=new PDO("mysql:host=localhost;dbname=api","root",""); 4 // 设置字符集编码 5 $pdo->exec("set names utf8"); 6 return $pdo; 7 ?>
lib/ErrorCode.php
1 <?php 2 /** 3 * 错误码 4 */ 5 class ErrorCode 6 { 7 const USERNAME_CANNOT_EMPTY=1;//用户名不能为空 8 const PASSWORD_CANNOT_EMPTY=2;//密码不能为空 9 const USERNAME_EXISTS=3;//用户名已存在 10 const REGISTER_FAIL=4;//注册失败 11 const LOGIN_USERNAME_CANNOT_EMPTY=5;//登录用户名为空 12 const LOGIN_PASSWORD_CANNOT_EMPTY=6;//登录密码不能为空 13 const LOGIN_FAIL=7;//登录失败 14 } 15 ?>
lib/User.php
1 <?php 2 // 导入错误码类 3 require_once __DIR__."/ErrorCode.php"; 4 /** 5 * 实现用户注册的业务逻辑设计 6 */ 7 class User 8 { 9 //属性 10 private $_db;//存储pdo 11 /** 12 * 属性赋值 13 * @param [type] $_db [description] 14 */ 15 public function __construct($_db) 16 { 17 $this->_db=$_db; 18 } 19 /** 20 * 登录的方法 21 * @param [type] $username 登录用户名 22 * @param [type] $password 登录密码 23 * @return array [description] 24 */ 25 public function login($username,$password) 26 { 27 // 1.检测是否能接收到数据 28 // echo $username.$password; 29 // 判断登录的用户名是否为空 30 if (empty($username)) { 31 throw new Exception("用户名为空",ErrorCode::LOGIN_USERNAME_CANNOT_EMPTY); 32 } 33 // 判断登录密码是否为空 34 if (empty($password)) { 35 throw new Exception("密码为空",ErrorCode::LOGIN_PASSWORD_CANNOT_EMPTY); 36 } 37 $sql="select * from users where username=:username and password=:password"; 38 // 密码加密 39 $password=$this->_md5($password); 40 // 预处理 41 $list1=$this->_db->prepare($sql); 42 // 绑定参数 43 $list1->bindParam("username",$username); 44 $list1->bindParam("password",$password); 45 // 执行 46 $list1->execute(); 47 // 获取结果集 48 $user=$list1->fetch(PDO::FETCH_ASSOC); 49 if (empty($user)) { 50 throw new Exception("登录的用户名或密码有误",ErrorCode::LOGIN_FAIL); 51 } 52 return $user; 53 } 54 /** 55 * 注册方法 56 * @param [type] $username [注册用户名] 57 * @param [type] $password 注册密码 58 * @return array 返回注册成功后的数据 59 */ 60 public function register($username,$password) 61 { 62 // 1.测试是否调用成功 63 // echo "this is register"; 64 // 2.测试$_db属性是否赋值成功 65 // echo "<pre>"; 66 // var_dump($this->_db); 67 // 3.测试是否接收到$username和$password 68 // echo $username.$password; 69 // 4.把接收到的$username和$password写入到users库 70 // 判断注册的用户名是否为空 71 if (empty($username)) { 72 // 如果用户名为空抛出异常, 第一个参数返回信息,第二个参数为状态码(ErrorCode类里的USERNAME_CONNOT_EMPTY静态属性) 73 throw new Exception("用户名不能为空",ErrorCode::USERNAME_CANNOT_EMPTY); 74 } 75 // 判断密码是否为空 76 if (empty($password)) { 77 throw new Exception("密码不能为空",ErrorCode::PASSWORD_CANNOT_EMPTY); 78 } 79 // 判断注册的用户名是否已存在 80 if ($this->isUsernameExists($username)) { 81 throw new Exception("用户名已经注册",ErrorCode::USERNAME_EXISTS); 82 } 83 // 入库 84 $sql="insert into users (username,password,created_at)values(:username,:password,:created_at)"; 85 // 处理接收到的数据 86 $created_at=time(); 87 $password=$this->_md5($password); 88 // 返回预处理 89 $list=$this->_db->prepare($sql); 90 // 绑定参数 91 $list->bindParam("username",$username); 92 $list->bindParam("password",$password); 93 $list->bindParam("created_at",$created_at); 94 // 判断执行是否成功 95 if (!$list->execute()) { 96 throw new Exception("注册失败",ErrorCode::REGISTER_FAIL); 97 } 98 // 返回数据 99 return [ 100 'user_id'=>$this->_db->lastInsertId(), 101 'username'=>$username, 102 'created_at'=>$created_at 103 ]; 104 105 } 106 /** 107 * 检测用户名是否已存在的方法 108 * @param [type] $username [description] 109 * @return boolean [description] 110 */ 111 public function isUsernameExists($username) 112 { 113 $extists=false; 114 115 $sql="select * from users where username=:username"; 116 // 返回预处理 117 $sm=$this->_db->prepare($sql); 118 //绑定参数 119 $sm->bindParam("username",$username); 120 //执行 121 $sm->execute(); 122 // 获取结果 123 $res=$sm->fetch(PDO::FETCH_ASSOC); 124 return !empty($res); 125 } 126 /** 127 * md5加密密码 128 * @param [type] $string [description] 129 * @return [type] [description] 130 */ 131 public function _md5($string) 132 { 133 return md5($string); 134 } 135 } 136 137 ?>
index.php
1 <?php 2 // 导入User.php 3 require __DIR__."/lib/User.php"; 4 // 导入db.php 5 require __DIR__."/lib/db.php"; 6 7 // 实例化User类 $pdo传入连接库 8 $user=new User($pdo); 9 // 调用注册方法 实现注册业务逻辑操作 10 // echo "<pre>"; 11 // print_r($user->register("admin6","1213")); 12 13 // 调用登录的方法 实现登录的业务逻辑操作 14 // $user->login("admin3","1213"); 15 // 检测是否实现登录业务逻辑操作 16 echo "<pre>"; 17 // print_r($user->login("admin4","1213")); 18 ?>
初始化参数和完善用户登录及注册API
restful/.htaccess(用于重写index.php)
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php/$1 [L]
restful/index.php
1 <?php 2 //restful的入口文件里导入用户注册的业务逻辑类 3 require __DIR__."/../lib/User.php"; 4 //导入链接数据库的业务类 5 require __DIR__."/../lib/db.php"; 6 7 /** 8 * 实现用户注册API 接口参数完善 9 */ 10 class Restful 11 { 12 // 设置私有成员属性 13 private $_user;//User类的对象 14 private $_requestMethod;//接口的请求方法 http动词集合 15 private $_resourceName;//接口的请求资源路径 请求资源路径集合 16 private $_allowResource=['users'];//接口允许的请求资源路径 17 private $_allowRequestMethod=['GET','POST','PUT','DELETE'];//接口允许请求方法 18 //状态码 19 private $_statusCode=[ 20 200=>'OK', 21 204=>'NO CONTENT', 22 400=>'Bad Request',//请求出了问题 23 401=>'request auth is valid',//请求没有授权 24 403=>'forbiden',//服务器禁止访问 25 404=>"Not Fond",//找不到服务器 26 405=>'methis is not allowed',//请求方式不允许 27 500=>'server Interval error',//服务器未知错误 28 ]; 29 /** 30 * 属性赋值 31 * @param User $_user User类约束 user实例化的对象 32 */ 33 public function __construct(User $_user) 34 { 35 $this->_user=$_user; 36 } 37 /** 38 * run 方法 完善用户注册的参数 39 * 资源路径 http动词 返回码 返回错误码 返回的响应数据 40 * @return [type] [description] 41 */ 42 public function run() 43 { 44 try { 45 // 调用初始化请求方法 46 $this->_setupRequestMethod(); 47 // 初始化请求资源路径 48 $this->_setupResource(); 49 //规定请求资源路径 返回响应数据 50 if ($this->_resourceName=="users") { 51 return $this->_json($this->_headerUser()); 52 } 53 } catch (Exception $e) { 54 // getMessage()获取错误信息 getCode() 获取错误码 55 $this->_json(['error'=>$e->getMessage()],$e->getCode()); 56 } 57 } 58 /** 59 * 初始化请求方法 60 * @return [type] [description] 61 */ 62 public function _setupRequestMethod() 63 { 64 // echo "<pre>"; 65 // print_r($_SERVER); 66 // 赋值请求方式 67 $this->_requestMethod=$_SERVER['REQUEST_METHOD']; 68 // 判断接口的请求方法是否存在于允许的请求方法内 69 if (!in_array($this->_requestMethod,$this->_allowRequestMethod)) { 70 throw new Exception("请求方法不允许",405); 71 } 72 } 73 /** 74 * 初始化请求资源路径 75 * @return [type] [description] 76 */ 77 public function _setupResource() 78 { 79 // echo "<pre>"; 80 // print_r($_SERVER); 81 // 获取请求资源路径 82 $path=$_SERVER['PATH_INFO']; 83 // echo $path; 84 //转换为数组 85 $param=explode("/",$path); 86 // print_r($param); 87 // 请求资源路径 88 $this->_resourceName=$param[1]; 89 if (!in_array($this->_resourceName, $this->_allowResource)) { 90 throw new Exception("请求资源路径不允许", 400); 91 } 92 } 93 /** 94 * 返回调用接口的数据(获取客户端提交的数据) 95 * @return json 返回调用接口的json格式数据 96 */ 97 public function _headerUser() 98 { 99 //判断请求的方式是否为post 100 if ($this->_requestMethod!="POST") { 101 throw new Exception("请求方式不允许",405); 102 } 103 //获取客户端提交的数据 104 $body=$this->_getBodyParams(); 105 106 // 获取请求资源路径 107 $path=$_SERVER['PATH_INFO']; 108 //转换为数组 109 $param=explode("/",$path); 110 // 判断是登录还是注册 111 if ($param[2]=="register") { 112 // 判断用户名不能为空 113 if (empty($body['username'])) { 114 throw new Exception("用户名不能为空",400); 115 } 116 // 判断密码不能为空 117 if (empty($body['password'])) { 118 throw new Exception("密码不能为空",400); 119 } 120 121 //返回调用接口的json数据 122 return $this->_user->register($body['username'],$body['password']); 123 }elseif ($param[2]=="login") { 124 // 判断用户名为空 125 if (empty($body['username'])) { 126 throw new Exception("用户名为空",400); 127 } 128 // 判断密码为空 129 if (empty($body['password'])) { 130 throw new Exception("密码为空",400); 131 } 132 //返回登录调用接口的json数据 133 return $this->_user->login($body['username'],$body['password']); 134 }else{ 135 throw new Exception("请求资源路径不允许",400); 136 } 137 138 139 } 140 /** 141 * 获取客户端提交的数据 142 * @return array 获取客户端提交的数据(username,password) 143 */ 144 public function _getBodyParams() 145 { 146 $raw=file_get_contents('php://input'); 147 if (empty($raw)) { 148 throw new Exception("请求参数有误",400); 149 } 150 // 把客户端传递的json格式数据转换为数组格式 151 return json_decode($raw,true); 152 } 153 /** 154 * 转换响应数据(响应的状态码)的格式 155 * @param array $array 具体错误信息 156 * @param integer $code 具体的相应状态码 157 * @return [type] [description] 158 */ 159 public function _json($array,$code=0) 160 { 161 if ($code >0 && $code !== 200 && $code != 204) { 162 //把状态码写入到响应头里 163 header("HTTP/1.1 $code"); 164 } 165 header("Content-type:application/json;charset=utf-8"); 166 //把响应体转换为json格式输出 JSON_UNESCAPED_UNICODE 转义参数 防止有特殊字符和空格出现 167 echo json_encode($array,JSON_UNESCAPED_UNICODE); 168 } 169 } 170 171 // 实例化USer 172 $user=new User($pdo); 173 // 调用Restful类的run方法 174 $Restful=new Restful($user); 175 $Restful->run(); 176 177 ?>
注:if语句也可以换成switch语句
2020-04-07