摘要:一,为项目搭建数据库设计数据库的小技巧一个对象,一张表一张表,一个主键表名用数据库名做前缀字段名用表名做前缀前缀后面加缩写容易看懂的前提下数据表的关系处理二,为项目写接口文档用户登录举例判断数据库中是否有此用户参数必选类型说明时间戳用于确定
一,为api项目搭建数据库
一个对象,一张表
一张表,一个主键
表名用 数据库名 做前缀
字段名用 表名 做前缀
前缀后面加 缩写 (容易看懂的前提下)
数据表的关系处理
二,为api项目写接口文档用户登录举例
# 判断数据库中是否有此用户
postwww.test.com/apiapi.test.com
参数 | 必选 | 类型 | 说明 |
---|---|---|---|
time | true | int | 时间戳 (用于确定接口的访问时间) |
token | true | string | 确定访问者身份 (MD5(USER_MD5(time)_USER)) |
username | true | string | 只接受邮箱 |
password | true | string | 用户密码 |
{ "ret": 200, // 返回结果状态。200:接口正常请求并返回/40*:服务端的数据有误/500:服务器运行错误 "data": { "user_id": "27", // 用户id "user_tag": "1" // 用户身份 }, "msg": "" // 401:用户名不存在!/402:手机号不存在!/403:密码不正确! }三,配置URL
· api.test.com ===> www.test.com/index.php/api
打开 httpd-vhosts.conf 添加 ServerAlias api.test.com
配置 host 文件 127.0.0.1 api.test.com
新建User.php文件,路径 G:tp5/application/api/controller/User.php
"; echo $id; } }
修改 config.php (开启路由)
// 是否开启路由
"url_route_on" => true,
// 域名部署
"url_domain_deploy" => true,
配置路由规则 route.php
www.test.com/index.php/api Route::domain("api","api");四,接口安全
接口被大规模调用消耗系统资源,影响系统的正常访问,甚至系统瘫痪
解决方案: 获取 timestamp (时间戳), 设置接口失效时间
接口数据被黑客篡改(伪造请求)
解决方案: 对参数加密, 生成 token , 判断 token 是否正确
数据被黑客截取
解决方案: 使用 https , 用证书对数据进行加密, 即使数据被截取, 对黑客也没有意义
time
时间戳, 用于判断请求是否超时, 设置为30秒
token
其他参数加密而来, 保证数据不被篡改
敏感信息加密传输
接收加密过的用户密码, 用户密码永不返回五,开发前准备工作(参数过滤)
最好使用 https, 所有信息都会被加密
使用 common.php 统一处理参数过滤 G:tp5/application/api/controller/Common.php
array(......); protected function _initialize() { parent::_initialize(); $this->request = Request::instance(); $this->check_time($this->request->only(["time"])); $this->check_token($this->request->param()); $this->params=$this->check_params($this->request->except(["time","token"])); }
自定义返回信息函数 G:tp5/application/api/controller/Common.php
/** * api 数据返回 * @param [int] $code [结果码 200:正常/4**数据问题/5**服务器问题] * @param [string] $msg [接口要返回的提示信息] * @param [array] $data [接口要返回的数据] * @return [string] [最终的json数据] */ public function return_msg($code, $msg = "", $data = []) { /*********** 组合数据 ***********/ $return_data["code"] = $code; $return_data["msg"] = $msg; $return_data["data"] = $data; /*********** 返回信息并终止脚本 ***********/ echo json_encode($return_data);die; }
验证 time G:tp5/application/api/controller/Common.php
/** * 验证请求是否超时 * @param [array] $arr [包含时间戳的参数数组] * @return [json] [检测结果] */ public function check_time($arr) { if (!isset($arr["time"]) || intval($arr["time"]) <= 1) { $this->return_msg(400, "时间戳不正确!"); } if (time() - intval($arr["time"]) > 60) { $this->return_msg(400, "请求超时!"); } }
验证token G:tp5/application/api/controller/Common.php
/** * 验证token(防止篡改数据) * @param [array] $arr [全部请求参数] * @return [json] [token验证结果] */ public function check_token($arr) { /*********** api传过来的token ***********/ if (!isset($arr["token"]) || empty($arr["token"])) { $this->return_msg(400, "token不能为空!"); } $app_token = $arr["token"]; // api传过来的token /*********** 服务器端生成token ***********/ unset($arr["token"]); $service_token = ""; foreach ($arr as $key => $value) { $service_token .= md5($value); } $service_token = md5("api_" . $service_token . "_api"); // 服务器端即时生成的token /*********** 对比token,返回结果 ***********/ if ($app_token !== $service_token) { $this->return_msg(400, "token值不正确!"); } }
为每个接口配置验证规则 G:tp5/application/api/controller/Common.php 如
protected $rules = array( "User" => array( "login" => array( "user_name" => ["require", "chsDash", "max" => 20], "user_pwd" => "require|length:32", ), ), );
验证参数 G:tp5/application/api/controller/Common.php
/** * 验证参数 参数过滤 * @param [array] $arr [除time和token外的所有参数] * @return [return] [合格的参数数组] */ public function check_params($arr) { /*********** 获取参数的验证规则 ***********/ $rule = $this->rules[$this->request->controller()][$this->request->action()]; /*********** 验证参数并返回错误 ***********/ $this->validater = new Validate($rule); if (!$this->validater->check($arr)) { $this->return_msg(400, $this->validater->getError()); } /*********** 如果正常,通过验证 ***********/ return $arr; }五,获取验证码
验证码原理
生成及发送
点击获取验证码
发送邮箱号到后台
后台生成邮箱验证码
用session保存验证码及邮箱
发送邮件
验证
获取用户输入的验证码及邮箱
取出session保存的内容
对比验证
返回信息, 结束
配置路由 G:tp5/application/route.php
注意: get方式没有参数名, 所以要注意参数的顺序, 对号入座.
// 获取验证码 Route::get("code/:time/:token/:username/:is_exist","code/get_code");
参数过滤 G:tp5/application/api/controller/Common.php
在common.php里简单过滤, 具体验证放在code.php里
"Code" => array( "get_code" => array( "username" => "require", "is_exist" => "require|number|length:1", ), ),
检测用户名 G:tp5/application/api/controller/Code.php
namespace appapicontroller; use phpmailerphpmailer; use submailmessagexsend; class Code extends Common { public function get_code() { $username = $this->params["username"]; $exist = $this->params["is_exist"]; $username_type = $this->check_username($username); // 检查用户名, 决定用下面哪那个函数 switch ($username_type) { case "phone": $this->get_code_by_username($username, "phone", $exist); // 通过手机获取验证码 break; case "email": $this->get_code_by_username($username, "email", $exist); // 通过邮箱获取验证码 break; } } }
在 Common.php中写一个判断用户名类型的函数
public function check_username($username) { /*********** 判断是否为邮箱 ***********/ $is_email = Validate::is($username, "email") ? 1 : 0; /*********** 判断是否为手机 ***********/ $is_phone = preg_match("/^1[34578]d{9}$/", $username) ? 4 : 2; /*********** 最终结果 ***********/ $flag = $is_email + $is_phone; switch ($flag) { /*********** not phone not email ***********/ case 2: $this->return_msg(400, "邮箱或手机号不正确!"); break; /*********** is email not phone ***********/ case 3: return "email"; break; /*********** is phone not email ***********/ case 4: return "phone"; break; } }
通过用户名(手机/邮箱)获取验证码 G:tp5/application/api/controller/Code.php
public function get_code_by_username($username, $type, $exist) { if ($type == "phone") { $type_name = "手机"; } else { $type_name = "邮箱"; } /*********** 检测手机号/邮箱是否存在 ***********/ $this->check_exist($username, $type, $exist); /*********** 检查验证码请求频率 30秒一次 ***********/ if (session("?" . $username . "_last_send_time")) { if (time() - session($username . "_last_send_time") < 30) { $this->return_msg(400, $type_name . "验证码,每30秒只能发送一次!"); } } /*********** 生成验证码 ***********/ $code = $this->make_code(6); /*********** 使用session存储验证码, 方便比对, md5加密 ***********/ $md5_code = md5($username . "_" . md5($code)); session($username . "_code", $md5_code); /*********** 使用session存储验证码的发送时间 ***********/ session($username . "_last_send_time", time()); /*********** 发送验证码 ***********/ if ($type == "phone") { $this->send_code_to_phone($username, $code); } else { $this->send_code_to_email($username, $code); } }
判断用户名(手机/邮箱)在数据库中是否应该存在(因为要分两种情况1,注册 2,修改)
当我们注册的时候数据库里不能有,当我们修改的时候数据库里必须有
G:tp5/application/api/controller/Common.php
public function check_exist($value, $type, $exist) { $type_num = $type == "phone" ? 2 : 4; $flag = $type_num + $exist; $phone_res = db("user")->where("user_phone", $value)->find(); $email_res = db("user")->where("user_email", $value)->find(); switch ($flag) { /*********** 2+0 phone need no exist ***********/ case 2: if ($phone_res) { $this->return_msg(400, "此手机号已被占用!"); } break; /*********** 2+1 phone need exist ***********/ case 3: if (!$phone_res) { $this->return_msg(400, "此手机号不存在!"); } break; /*********** 4+0 email need no exist ***********/ case 4: if ($email_res) { $this->return_msg(400, "此邮箱已被占用!"); } break; /*********** 4+1 email need exist ***********/ case 5: if (!$email_res) { $this->return_msg(400, "此邮箱不存在!"); } break; } }
在 Code.php 中生成验证码
public function make_code($num) { $max = pow(10, $num) - 1; $min = pow(10, $num - 1); return rand($min, $max); }
只介绍邮箱发送验证码
开启邮箱smtp
php 开启php_openssl
G:tp5/application/api/controller/Code.php
public function send_code_to_email($email, $code) { $toemail = $email; $mail = new PHPMailer(); $mail->isSMTP(); $mail->CharSet = "utf8"; // 设置字符集 $mail->Host = "smtp.qq.com"; // smtp服务器 $mail->SMTPAuth = true; $mail->Username = "123456789@qq.com"; $mail->Password = "asd1151sad51dsa"; // 自己设置的smtp密码, 与登录密码无关 $mail->SMTPSecure = "ssl"; $mail->Port = 465; $mail->setFrom("123456789@qq.com", "接口测试"); $mail->addAddress($toemail, "test"); $mail->addReplyTo("123456789@qq.com", "lee"); $mail->Subject = "您有新的验证码!"; // 邮件标题 $mail->Body = "这是一个测试邮件,您的验证码是$code,验证码的有效期为1分钟,本邮件请勿回复!"; // 邮件内容 if (!$mail->send()) { $this->return_msg(400, $mail->ErrorInfo); } else { $this->return_msg(200, "验证码已经发送成功,请注意查收!"); } }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/26035.html
摘要:分享一个版本的查询天气接口。那就用聚合数据的天气接口吧,也是免费的,不过聚合数据的接口申请相对繁琐。注册一个聚合数据的账号实名认证你的账号申请你需要的接口申请验证你的接口申请地址虽然是繁琐了很多,不过返回的信息确是非常的丰富。 分享一个php版本的查询天气接口。免费查询天气的接口有很多,比如百度的apistore的天气api接口,我本来想采用这个接口的,可惜今天百度apistore死活...
摘要:的关联应用参考的多对多关联文档,给大家简单介绍一下我在项目应用中的实现。数据表根据绘制的图我们可以确定,订单票据的数据表实现需要三张表,订单表是数据库关键字因此不能作为表名,票据表,中间表。 TP5的关联应用 参考TP5的多对多关联文档,给大家简单介绍一下我在项目应用中的实现。 ER图讲解多对多关系 showImg(https://segmentfault.com/img/bV7to2...
摘要:因公司业务需要需要给客户接入支付宝支付自己以前只做过网页版支付宝支付。添加功能完后我的应用列表就会显示添加的应用,即支付宝支付。最后别忘了在异步方法返回一个,否则支付宝会以为没支付成功,小时内每个几分钟就调一次异步接口。 因公司业务需要,需要给客户接入支付宝支付,自己以前只做过网页版支付宝支付。折腾了3天,踩了很多坑,终于搞定了,现在记录一下,分享给大家.一、首先必须通知客户先申请支付...
摘要:因公司业务需要需要给客户接入支付宝支付自己以前只做过网页版支付宝支付。添加功能完后我的应用列表就会显示添加的应用,即支付宝支付。最后别忘了在异步方法返回一个,否则支付宝会以为没支付成功,小时内每个几分钟就调一次异步接口。 因公司业务需要,需要给客户接入支付宝支付,自己以前只做过网页版支付宝支付。折腾了3天,踩了很多坑,终于搞定了,现在记录一下,分享给大家.一、首先必须通知客户先申请支付...
摘要:现在我就用框架来进行实战下在实际业务中是如何优雅的使用异常的场景描述选择一个比较简单的业务场景,以登录模块为例,用户在移动端进行登录时,需要进行登录,注册,忘记密码,获取手机验证码等接口。 前言 刚开始接触PHP的时候没有意识到异常的重要性,有时候出问题很难精确的找到问题点,正确的处理异常也是一门学问 异常的类别 PHP7异常做了很多变动,异常类 Exception 和错误类 Erro...
阅读 709·2021-09-28 09:35
阅读 2568·2019-08-29 11:25
阅读 2132·2019-08-23 18:36
阅读 1797·2019-08-23 16:31
阅读 2037·2019-08-23 14:50
阅读 3074·2019-08-23 13:55
阅读 3237·2019-08-23 12:49
阅读 2038·2019-08-23 11:46