【栏目分类】

返回上级

【最新文章】

【本类热门】

赚了吗联盟

【当前位置】:惠省一派 >> 技术分享 >> 正文

  • 转载一篇关于tp5的开发介绍的文章
  • 2020-11-02 23:15:35

  • 如何用PHP开发API接口

    >做过 API 的人应该了解,其实开发 API 比开发 WEB 更简洁,但可能逻辑更复杂,因为 API 其实就是数据输出,不用呈现页面,所以也就不存在 MVC(API 只有 M 和 C)

    >1、和 WEB 开发一样,首先需要一些相关的参数,这些参数,都会由客户端传过来,也许是 GET 也许是 POST,这个需要开发团队相互之间约定好,或者制定统一规范。

    >2、有了参数,根据应用需求,完成数据处理,例如:任务进度更新、APP内购、一局游戏结束数据提交等等

    >3、数据逻辑处理完之后,返回客户端所需要用到的相关数据,例如:任务状态、内购结果、玩家信息等等

    >数据怎么返给客户端?

    >直接输出的形式,如:JSON、xml、TEXT 等等。

    >4、客户端获取到你返回的数据后,在客户端本地和用户进行交互

    什么是接口?接口用来做什么?

    >接口通过上面的简单介绍,可以理解为API就是就是通道,负责一个程序和其他软件的沟通,本质是预先定义的函数。

    >接口将数据给客户端,由客户端渲染在页面上,大部分的逻辑都是在服务端进行判断和验证.客户端只需要管请求API的这个人有没有权限?

    >那我们如何验证请求这个API是否有权限.这个时候就需要了解 token 验证的思想。

    什么是OAuth?

    >OAuth是一个授权的标准,目前最新的版本是2.0

    >那什么是 OAuth呢?我们举个栗子~

    >有一个网站提供了一个url接口,这个接口我们只给通过认证的用户的使用。给出 了这样一条接口:http://www.xxx.com/api.php?username=admin&;password=admin
    很容易就会发现暴露出来的几点问题!


    >这条API一但被其他人知道,就容易被无限制的盗刷,无法控制这个接口的使用时间,而且通过地址传输的是明文很不安全。

    >那如何能避免这种问题呢?

    >我们可以设置一个授权层,用户不能直接通过账号密码去登录,只能通过授权层来获取一个 令牌(Token) , 通过获取的Token来与我们服务端进行其他接口的验证.

    如何实现授权层,完成Token的生成及其验证

    >我们来想一想,用户什么时候获取Token?什么时候需要Token呢?

    >在第一次访问接口的时候 我们不可能平白无故的捏造出一个Token.我们需要在用户请求登录接口成功后返回一个Token,Token里保存了用户的信息

    >咦.这和我们开发混排的web站的时候一样啊.登录成功将信息存入Session,我们参考一下之前的代码

    public

    function

    login

    ()



    {    // 判断是否为post请求,如果为post请求就是登录请求 为get就是访问登录页面

        if

    (Request()->isPost()) {        // 获取数据库中数据 如果获取到则是存在这条记录

            $res = \think\Db::table('admin'

    )->where('u_name'

    , input('post.u_name'

    ))->where('u_password'

    , md5(input('post.u_password'

    )))->find();        // 存在就返回数据集 所以判断是否存在此数据集

            if

    (!$res) {            // 登录失败

                $this

    ->error('账号或密码错误 请检查后 再次输入'

    );        } else

    {            // 登录成功,将登录后的数据存入session 在Base类中用于判断是否登录的条件

                session('admin.admin_id'

    , $res['id'

    ]);            session('admin.admin_name'

    , $res['u_name'

    ]);            $this

    ->success('登录成功'

    , 'admin/entry/index'

    );        }    }    return

    $this

    ->fetch();}>此时我们只需要改写 else部分的代码!

    >将存入session的代码 改成存入数据库或者缓存系统的代码即可.我们将Key返回给用户即可,下次请求的时候 用户根据这个Key查询它的Value,获取用户信息进行操作.

    >那么来了一个问题!为什么不能继续存入Session了.

    >session是基于cookie的,cookie是由浏览器来接受处理的,当然听App端的小伙伴说App也可以处理Cookie,但是没有Token运用的稳定.

    >现在我们改写代码,改成下面样子:

    public

    function

    login

    ()



    {    // 判断是否为post请求,如果为post请求就是登录请求 为get就是访问登录页面

        if

    (Request()->isPost()) {        // 获取数据库中数据 如果获取到则是存在这条记录

            $res = \think\Db::table('admin'

    )->where('u_name'

    , input('post.u_name'

    ))->where('u_password'

    , md5(input('post.u_password'

    )))->find();        // 存在就返回数据集 所以判断是否存在此数据集

            if

    (!$res) {            // 登录失败

                return

    json(['code'

    =>400

    ,'msg'

    =>'登录失败'

    ,'data'

    =>[]]);        } else

    {            // 登录成功,将登录后的数据存入session 在Base类中用于判断是否登录的条件

                $token = md5(microtime()); // 这里的生成算法只作用于Demo

                cache($token,$res['id'

    ],24

    *60

    *7

    );            return

    json(['code'

    =>200

    ,'msg'

    =>'登录成功'

    ,'data'

    =>['Token'

    =>$token]]);        }    }}>通过两个代码对比发现:

    • 缺少了View的部分,直接将数据转为Json格式返回给客户端.
    • >原本的Session存储变为了Cache存储.

    >通过这个登录的小栗子,希望大家能了解什么是接口.后面的课程会更加精彩!

    Restful Api思想

    >网络应用程序,随着时代的变迁.之前的网页都是前后端混排的.

    >现在随着前端设备层出不穷,为了统一接口 于是便有了Restful Api

    >这套规范总结: 就是用URL定位资源,用HTTP描述操作。

    >那如何理解这段话呢?

    >我们通过一个小栗子实现。我们要做一个相册的功能 那如何用Restful定义url

    动作URI行为
    GET/photos显示相册内容列表
    GET/photos/create相片上传页面
    POST/photos上传相片操作
    GET/photos/{id}通过ID查看相片
    GET/photos/{id}/edit通过ID编辑相片页面
    PUT/PATCH/photos/{id}通过ID上传相片操作
    DELETE/photos/{id}通过ID删除相片
    >通过上面定义路由的方式就是Restful 思想。

    API开发- 让异常显示的更加优雅

    >作为程序员难免会出点小BUG!哪如何捕获呢。在APP上出现bug通常会出现闪退,和无法解析错误一直加载.

    >有一个想法。将错误也变成json格式.code码定义为500 如果移动端发现错误为500的话 就温柔提醒.并且服务端保存错误信息.供开发者修改.

    >首先修改配置项 application/config.php

    // 异常处理handle类 留空使用 \think\exception\Handle

    'exception_handle'

          => '\app\common\exception\Http'

    ,>原本是留空的 现在改为我们自定义的控制器

    >创建一个Http控制器 继承thinkexceptionHandle类 重写 render方法. 这里注意一点 最好不要用框架里的一些方法了.这个文件的启动顺序大于一些方法.



    namespace

    app

    \common

    \exception

    ;use

    app

    \api

    \controller

    \Log

    ;use

    Exception

    ;use

    think

    \exception

    \Handle

    ;use

    think

    \exception

    \HttpException

    ;class

    Http

    extends

    Handle



    {    public

    function

    render

    (\Exception $e)

       

    {        // 只要有错误就返回错误json

            $arr = [            'code'

    => 500

    ,            'msg'

    => $e->getMessage(),            'data'

    => 'URL : http://'

    .$_SERVER['SERVER_NAME'

    ].':'

    .$_SERVER["SERVER_PORT"

    ].$_SERVER["REQUEST_URI"

    ]        ];        $error_info = json_encode($arr, 512

    ) . PHP_EOL;        echo

    $error_info;        if

    (!is_dir('../runtime/errorlog/'

    )) mkdir('../runtime/errorlog/'

    , 0777

    , true

    );        file_put_contents('../runtime/errorlog/'

    . date('Ymd'

    , time()) . '.txt'

    , $error_info, FILE_APPEND);        exit

    ;    }}>这样就能将原本的报错页面变成可识别的json串.并且将错误的日志记录在 runtime/errorlog 目录下。


    如何接收客户端上传的数据

    >上传的接收方法有很多.

    >TP5 已经帮我们封装好了 FILE文件上传。我们可以直接调用它的方法即可.

    >下面有file文件上传的demo:

    public

    function

    upload

    ()



    {    // 获取表单上传文件 例如上传了001.jpg

        $file = request()->file('image'

    );    // 移动到框架应用根目录/public/uploads/ 目录下

        if

    ($file){        $info = $file->move(ROOT_PATH . 'public'

    . DS . 'uploads'

    );        if

    ($info){            // 成功上传后 获取上传信息

                // 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg

                $path =  $info->getSaveName();            return

    json(['code'

    =>200

    ,'msg'

    =>'上传成功'

    ,'data'

    =>['path'

    =>$path]]);        }else

    {            return

    json(['code'

    =>400

    ,'msg'

    =>'上传失败'

    ]);        }    }}>当然还有另外一种方式上传文件到服务器 那就是直接发送文件流:

    public

    function

    byteUpload

    ()



    {    // 生成的文件格式

        $filename = md5(microtime().mt_rand(10000

    ,99999

    )) . '.jpeg'

    ;    // 通过POST接收文件 , 将文件的字节流放在file参数内传入即可

        $byte = $_POST['file'

    ];    $dir = ROOT_PATH . 'public'

    . DS . 'uploads'

    . DS . date('Ymd'

    );    $path = $dir . DS . $filename;    is_dir($dir) || mkdir($dir, 0777

    , true

    );    if

    ($byte) {        // 将字节流写入文件

            file_put_contents($path, $byte);//写入文件中!

        } else

    {        return

    false

    ;    }    // 上传成功后 返回文件路径 如果失败则返回false

        return

    $path;}>PS:本例子只是用来演示 不能直接用于API需要修改返回的格式为json .

    >这种方式也是最好理解的一种,直接把文件通过字节的方式传入.我们后台直接保存即可.

    APP接入支付宝支付

    >对于没有接入过支付的小伙伴,我先说几句!

    >不要畏惧接触第三方,第三方的调用可以说是相对比较简单的,他们会把大部分的逻辑封装在sdk中,我们只要调用接口.一般正规的第三方接口都会有说明文档。也不要畏惧读文档,耐下心来仔细看一篇.其实也就是那么回事

    >我们现在开始给自己的APP接入支付宝

    • 首先我们了解下支付宝的支付接口调用原理
    sequenceDiagramparticipant 用户participant 商户客户端participant 支付宝客户端participant 支付宝服务端participant 商户服务端用户->>

    商户客户端: 1

    . 使用支付宝付款商户客户端-->>

    商户服务端: 2

    . 请求客户服务端,返回签名后的订单信息商户服务端-->>

    商户客户端: 3

    .返回签名后的订单信息商户客户端->>

    支付宝客户端: 4

    .由移动端去调用支付宝接口支付宝客户端->>

    支付宝服务端: 5

    .支付请求支付宝服务端->>

    支付宝服务端:

    6

    .支付完成支付宝服务端->>

    支付宝客户端:

    7

    .返回同步支付结果支付宝客户端->>

    商户客户端:

    8

    .接口返回支付结果商户客户端-->>

    商户服务端:

    9

    .同步支付结果返回服务端,解析支付结果商户服务端-->>

    商户客户端:

    10

    .返回最终结果商户客户端->>

    用户:

    11

    .显示结果支付宝服务端-->>

    商户服务端:

    12

    .异步发送支付结果商户服务端-->>

    支付宝服务端:

    13

    .接收响应(支付宝确认支付)>其中虚线的就是我们要处理的步骤 我们下面将一步一步来介绍如何操作

    • 首先我们先要去申请支付应用,获取APPid、rsaPrivateKey 、alipayrsaPublicKey>怎么开通应用?这一步骤还是看官方手册吧!官方的手册才是最详细的 手册地址

      >请确保账号有开通APP支付的权限,下面我们来配置一下开发环境,在我们创建的支付应用管理页面里面

      应用网关填写你服务器的域名:http://www.webhuang.cn
      授权回调地址填写支付宝给你异步回调的地址
      >后面还有接口加密方式要填写,我们可以通过下载支付宝官方提供的工具生成公钥和私钥。这里官方手册也说的很详细了.

      >官方生成签名工具地址:下载地址

      >生成秘钥的格式按照地址中的图生成即可,最后将生成的应用公钥上传到平台即可。

    • >将SDK下载放置在TP5的vendor目录下的alipay文件夹(可根据实际使用框架技术进行实际调整)。

      >SDK下载地址:下载地址

    • >用户点击付款按钮的时候,客户端会请求我们,我们需要返回一个签名的信息给客户端,再由客户端通过支付宝SDK传给支付宝的服务端

      //vendor();为TP5框架的方法,作用:导入第三方框架类库

      vendor('alipay.aop.AopClient'

      );vendor('alipay.aop.request.AlipayTradeAppPayRequest'

      );//实例化支付接口

      $aop = new

      \AopClient();$aop->gatewayUrl = "https://openapi.alipay.com/gateway.do"

      ; //支付宝网关

      $aop->appId = “应用ID,填写你的APPID”;$aop->rsaPrivateKey = "商户私钥,您的原始格式RSA私钥()"

      ;$aop->alipayrsaPublicKey = "支付宝公钥"

      ;$aop->apiVersion = '1.0'

      ;$aop->signType = "签名方式,如 RSA2 "

      ;$aop->postCharset = 'UTF-8'

      ;$aop->format = "json"

      ;//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay

      $appRequest = new

      \AlipayTradeAppPayRequest();//SDK已经封装掉了公共参数,这里只需要传入业务参数

      $bizcontent = json_encode([    'body'

      => '余额充值'

      , //订单描述

          'subject'

      => '充值'

      , //订单标题

          'timeout_express'

      => '30m'

      ,    'out_trade_no'

      => ‘20170125

      test01’, //商户网站唯一订单号

          'total_amount'

      => '0.01'

      , //订单总金额

          'product_code'

      => 'QUICK_MSECURITY_PAY'

      , //固定值

      ]);$appRequest->setNotifyUrl($url); //设置异步通知地址

      $appRequest->setBizContent($bizcontent);//这里和普通的接口调用不同,使用的是sdkExecute

      $response = $aop->sdkExecute($appRequest);echo

      $response;//就是orderString 可以直接给客户端请求,无需再做处理。

    >通过上面的代码就可以生成一个签名的订单信息,供客户端去调用支付宝,发起支付请求。

    • 当用户支付成功,会异步的向我们服务器请求一条接口,只有我们返回 success 支付宝才认可已经付款成功,不然就会一直请求.返回fail 则说明我们不承认这次请求。
        /**    * 接收支付宝推送的支付结果,并按照其要求返回需求内容    */

        public

    function

    rebackPayResult

    ()



    {        vendor('alipay.aop.AopClient'

    );        vendor('alipay.aop.request.AlipayTradeAppPayRequest'

    );        $conf = config('alipay'

    );        $data = $_POST;        $aop = new

    \AopClient;        $aop->alipayrsaPublicKey = $conf['alipayrsaPublicKey'

    ];        $flag = $aop->rsaCheckV1($data, NULL

    , "RSA2"

    );        //当支付宝回调回来,先根据订单号查询一下订单状态,如果支付已经成功,直接return success ,就不用再往下执行了,防止支付宝那边回调出错,不停的异步调用接口

            $recharge_info = (new

    InternalLogic())->getOrderInfoByOrdersId($data['out_trade_no'

    ]);        if

    ($recharge_info['status'

    ] == 1

    ) {            echo

    'success'

    ;            die

    ;        }        if

    ($flag){            //验证成功

                //这里可以做一下你自己的订单逻辑处理

                if

    ($data['trade_status'

    ] == 'TRADE_SUCCESS'

    ){                try

                    {                    $alipay_result = (new

    InternalLogic())->storeOrdersStatusAndEvent($data['out_trade_no'

    ],1

    ,'支付宝'

    ,'收到支付宝回执'

    , $recharge_info['uid'

    ]);                    if

    ($alipay_result) {                        echo

    'success'

    ;die

    ;                    } else

    {                        echo

    'fail'

    ;die

    ;                    }                }                catch

    (\Exception

    $e)                {                    echo

    "fail"

    ;                }            }else

    {                echo

    "fail"

    ;            }        } else

    {            //验证失败

                echo

    "fail"

    ;        }        //$flag返回是的布尔值,true或者false,可以根据这个判断是否支付成功

        }>这样一次支付的流程就走完了.其中代码为学习的思路。如果要在实战项目中使用,请仔细检查代码的强壮性!

  • 作者:e4snake 浏览:55 评论:0

【相关文章】

【用户评论】

ICP备案:申请备案中... | 管理员信箱:xssoft#qq.com | 版本:XSCMS 1.0
本站数据来自于网络,如有问题请告知,我们将尽快处理
页面执行时间: 0.1719秒  20次数据查询