Phalcon搭建多模块框架二十八:封装curl工具类并模拟api接口请求与响应

在开发中经常会需要写接口给别人调用或者调用别人的接口,通常使用http post发送json格式数据,响应也往往是json格式数据。除了必要的签名,有时候为了数据安全还需要对数据进行对称或非对称加密。这里我们只是模拟post请求发送和响应json格式数据。
这里写图片描述
1、在library/tools下创建HttpCurl.php工具类

<?php
/** 
 * @desc curl工具类 
 * @author zhaoyang 
 * @date 2018年6月13日 下午8:08:28 
 */
namespace Library\Tools;

class HttpCurl {

    // 句柄
    private $_ch;

    // 请求地址
    private $_url;

    // 是否做https验证
    private $_httpsVerify;

    // 连接过期时间
    private $_timeout;

    // 启用时是否将头文件的信息作为数据流输出
    private $_header;

    private $_option = [ ];

    private $_error = null;

    /** 
     * @desc 初始化 
     * @param string $url 地址
     * @param bool $httpsVerify 是否进行https验证
     * @param int $timeout 超时时间
     * @param bool $header 启用时是否将头文件的信息作为数据流输出
     * @author zhaoyang 
     * @date 2018年6月13日 下午9:00:53 
     */
    public function __construct(string $url, bool $httpsVerify = false, int $timeout = 30, bool $header = false) {
        $this->_url = $url;
        $this->_httpsVerify = $httpsVerify;
        $this->_timeout = $timeout;
        $this->_header = $header;
        $this->init();
    }

    /** 
     * @desc 基本初始化 
     * @author zhaoyang 
     * @date 2018年6月13日 下午8:13:37 
     */
    private function init() {
        $this->_ch = curl_init();
        // 让 cURL 自己判断使用哪个版本
        $this->_option[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_NONE;
        // 在HTTP请求中包含一个"User-Agent: "头的字符串
        $this->_option[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
        // 需要获取的 URL 地址
        $this->_option[CURLOPT_URL] = $this->_url;
        // 在尝试连接时等待的秒数。设置为0,则无限等待
        $this->_option[CURLOPT_CONNECTTIMEOUT] = $this->_timeout;
        // 允许 cURL 函数执行的最长秒数
        $this->_option[CURLOPT_TIMEOUT] = $this->_timeout;
        // 只获取页面内容,但不输出
        $this->_option[CURLOPT_RETURNTRANSFER] = true;
        // 发送所支持的编码类型,false发送所有
        $this->_option[CURLOPT_ENCODING] = false;
        // 启用时会将头文件的信息作为数据流输出
        $this->_option[CURLOPT_HEADER] = $this->_header;
        // cURL 验证对等证书
        $this->_option[CURLOPT_SSL_VERIFYPEER] = $this->_httpsVerify;
        // 服务器认证ssl
        $this->_option[CURLOPT_SSL_VERIFYHOST] = $this->_httpsVerify;
        // 追踪句柄的请求字符串
        $this->_option[CURLINFO_HEADER_OUT] = true;
    }

    /** 
     * @desc 设置option
     * @param string|array $option 选项
     * @param mixed $value 值
     * @return object $this 
     * @author zhaoyang 
     * @date 2018年6月13日 下午8:17:37 
     */
    public function setOption($option, $value = null) {
        if (is_array($option)) {
            $this->_option = $option + $this->_option;
        } else {
            $this->_option[$option] = $value;
        }
        return $this;
    }

    /** 
     * @desc 发送get请求 
     * @author zhaoyang 
     * @date 2018年6月13日 下午9:15:16 
     */
    public function execGet() {
        curl_setopt_array($this->_ch, $this->_option);
        $result = curl_exec($this->_ch);
        $this->_error = [ 
            'errno' => curl_errno($this->_ch),
            'error' => curl_error($this->_ch)
        ];
        curl_close($this->_ch);
        return $result;
    }

    /** 
     * @desc 发送post请求
     * @param array|string $requestData 要发送的数据
     * @param bool $json 是否发送json格式数据
     * @param int $jsonOptions json配置
     * @author zhaoyang 
     * @date 2018年6月13日 下午9:15:33 
     */
    public function execPost($requestData = null, bool $json = true, int $jsonOptions = null) {
        if ($requestData !== null) {
            if ($json) {
                $isString = is_string($requestData);
                (!$isString || ($isString && is_null(json_decode($requestData)))) && $requestData = json_encode($requestData, $jsonOptions);
                if (!isset($this->_option[CURLOPT_HTTPHEADER])) {
                    $this->_option[CURLOPT_HTTPHEADER] = [ 
                        'Content-Type: application/json; charset=utf-8',
                        'Accept: application/json',
                        'Content-Length:' . strlen($requestData)
                    ];
                }
            }
            $this->_option[CURLOPT_POSTFIELDS] = $requestData;
        }
        $this->_option[CURLOPT_POST] = true;
        curl_setopt_array($this->_ch, $this->_option);
        $result = curl_exec($this->_ch);
        $this->_error = [ 
            'errno' => curl_errno($this->_ch),
            'error' => curl_error($this->_ch)
        ];
        curl_close($this->_ch);
        return $result;
    }

    /** 
     * @desc 获取错误 
     * @return array 
     * @author zhaoyang 
     * @date 2018年6月13日 下午9:30:23 
     */
    public function getError() {
        return $this->_error;
    }
}

2、打开common/BaseController.php,添加

final protected function sendJson($responseData, int $status = 10000, int $jsonOptions = null, int $depth = 512){
        $responseData = [
            'status' => $status,
            'message' => $status == 10000 ? 'ok' : $responseData,
            'data' => $status == 10000 ? $responseData : ''
        ];
        return $this->response->setJsonContent($responseData, $jsonOptions, $depth)->send();
    }

完成的common/BaseController.php

<?php
/** 
 * @desc 控制器基类
 * @author zhaoyang 
 * @date 2018年5月8日 下午10:37:37 
 */
namespace Common;

use Phalcon\Mvc\Controller;
use Phalcon\Exception;

class BaseController extends Controller {

    /** 
     * @desc 获取get参数
     * @param string $name 参数名
     * @param string|array $filter 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
     * 当为false时,不使用默认过滤,当为字符串例如'string,trim'时采用参数过滤 ,当为数组例如['string','trim']时采用参数+默认过滤,当为null等其他值时时采用默认过滤
     * @param mixed $defaultValue 默认值
     * @param bool $noRecursive 不递归过滤
     * @return mixed
     * @author zhaoyang 
     * @date 2018年5月8日 下午10:38:50 
     */
    final protected function get(string $name = null, $filter = null, $defaultValue = null, bool $noRecursive = false) {
        $data = array_merge($this->request->getQuery(), $this->dispatcher->getParams());
        unset($data['_url']);
        return $this->sanitize($data, $name, $filter, $defaultValue, $noRecursive);
    }

    /** 
     * @desc 获取post参数
     * @param string $name 参数名
     * @param string|array $filter 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
     * 当为false时,不使用默认过滤,当为字符串'string,trim'时采用参数过滤 ,当为数组['string','trim']时采用参数+默认过滤,当为null等其他值时时采用默认过滤
     * @param mixed $defaultValue 默认值
     * @param bool $noRecursive 不递归过滤
     * @param bool $notAllowEmpty 不允许为空
     * @return mixed
     * @author zhaoyang 
     * @date 2018年5月9日 下午8:40:27 
     */
    final protected function post(string $name = null, $filter = null, $defaultValue = null, bool $noRecursive = false, bool $notAllowEmpty = false) {
        $data = $this->request->getPost();
        return $this->sanitize($data, $name, $filter, $defaultValue, $noRecursive);
    }

    /** 
     * @desc 获取post或者get参数
     * @param string $name 参数名
     * @param string|array $filter 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
     * 当为false时,不使用默认过滤,当为字符串例如'string,trim'时采用参数过滤 ,当为数组例如['string','trim']时采用参数+默认过滤,当为null等其他值时时采用默认过滤
     * @param mixed $defaultValue 默认值
     * @param bool $noRecursive 不递归过滤
     * @return mixed
     * @author zhaoyang 
     * @date 2018年5月9日 下午9:41:49 
     */
    final protected function request(string $name = null, $filter = null, $defaultValue = null, bool $noRecursive = false){
        if (isset($name) && $name !== '') {
            return $this->post($name, $filter, $defaultValue, $noRecursive) ?? $this->get($name, $filter, $defaultValue, $noRecursive);
        }
        return array_merge($this->post(null, $filter, $defaultValue, $noRecursive), $this->get(null, $filter, $defaultValue, $noRecursive));
    }

    /** 
     * @param string $name 参数名
     * @param string|array $filter 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
     * 当为false时,不使用默认过滤,当为字符串例如'string,trim'时采用参数过滤 ,当为数组例如['string','trim']时采用参数+默认过滤,当为null等其他值时时采用默认过滤
     * @param mixed $defaultValue 默认值
     * @param bool $noRecursive 不递归过滤
     * @return mixed
     * @author zhaoyang 
     * @date 2018年5月9日 下午10:43:11 
     */
    final protected function json(string $name = null, $filter = null, $defaultValue = null, bool $noRecursive = false){
        $data = $this->request->getJsonRawBody(true);
        if (!is_array($data)) {
            return [ ];
        }
        return $this->sanitize($data, $name, $filter, $defaultValue, $noRecursive);
    }

    /**
     * @param array $data 数据源
     * @param string $name 参数名
     * @param string|array $filter 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
     * 当为false时,不使用默认过滤,当为字符串例如'string,trim'时采用参数过滤 ,当为数组例如['string','trim']时采用参数+默认过滤,当为null等其他值时时采用默认过滤
     * @param mixed $defaultValue 默认值
     * @param bool $noRecursive 不递归过滤
     * @return mixed
     * @author zhaoyang
     * @date 2018年5月9日 下午8:20:15
     */
    final protected function sanitize(array $data, string $name = null, $filter = null, $defaultValue = null, bool $noRecursive = false){
        $nowFilter = null;
        if (is_string($filter) && !empty($filter)) {
            $nowFilter = explode(',', $filter);
        } else if ($filter !== false) {
            $defaultFilter = $this->config->services->filter->default_filter;
            $defaultFilter = isset($defaultFilter) ? explode(',', $defaultFilter) : [ ];
            if (is_array($filter)) {
                $defaultFilter = array_unique(array_merge($filter, $defaultFilter));
            }
            if (!empty($defaultFilter)) {
                $nowFilter = $defaultFilter;
            }
        }
        if (isset($name) && $name !== '') {
            if (isset($data[$name]) && $data[$name] !== '') {
                $data = $data[$name];
            } else {
                $data = $defaultValue;
            }
        }
        if (isset($nowFilter)) {
            $data = $this->filter->sanitize($data, $nowFilter, $noRecursive);
        }
        return $data;
    }

    /** 
     * @desc 转发到其他动作 
     * @param array|string $url  'App\Home\Controllers\forward/index/a/aaa?b=bbb' or 'forward/index/a/aaa?b=bbb' or 'index?b=bbb'
     * @param array|string $vars 参数 ['a'=>'aaa','b'=>'bbb'] or 'a=aaa&b=bbb'
     * @param sring $namespace 命名空间
     * @return void 
     * @author zhaoyang 
     * @date 2018年5月24日 下午5:11:26 
     */
    final protected function forward($url, $vars = null, $namespace = null) {
        if (is_array($url)) {
            $forward = $url;
        } else if (is_string($url)) {
            $forward = [ ];
            $lastbBackslash = strrpos($url, '\\');
            if ($lastbBackslash) {
                $namespace = substr($url, 0, $lastbBackslash);
            }
            if (!empty($namespace)) {
                $forward['namespace'] = $namespace;
            }
            $start = $lastbBackslash === false ? 0 : $lastbBackslash + 1;
            $rest = substr($url, $start);
            $restStrposRes = strpos($rest, '?');
            if($rest == '' || $restStrposRes === 0){
                throw new Exception('方法不能为空');
            }
            if($restStrposRes === false){
                $capname = $rest;
                $paramsString = null;
            }else {
                list ($capname, $paramsString) = explode('?', $rest, 2);
                $capname = trim($capname, '/');
                if (empty($capname)) {
                    throw new Exception('控制器或方法不能为空');
                }
            }
            $capnameArr = explode('/', $capname);
            $capnameArrCount = count($capnameArr);
            if ($capnameArrCount == 1) {
                $forward['action'] = $capnameArr[0];
            } else {
                $forward['controller'] = $capnameArr[0];
                $forward['action'] = $capnameArr[1];
                for ($i = 2; $i < $capnameArrCount; $i += 2) {
                    $forward['params'][$capnameArr[$i]] = $capnameArr[$i + 1] ?? null;
                }
            }
            if ($paramsString !== null) {
                parse_str($paramsString, $paramsArr);
                $forward['params'] = array_merge($forward['params'] ?? [ ], $paramsArr);
            }
        } else {
            throw new Exception('url只能为字符串或者数组');
        }
        if (is_string($vars)) {
            $vars = trim($vars, '?');
            parse_str($vars, $vars);
        }
        if (is_array($vars)) {
            $forward['params'] = array_merge($forward['params'] ?? [ ], $vars);
        }
        $this->dispatcher->forward($forward);
    }

    /** 
     * @desc 成功跳转
     * @param string $message 提示信息
     * @param string $jumpUrl 跳转地址
     * @param bool $redirect 是否使用response->redirect
     * @param bool $externalRedirect 是否跳转到外部地址 
     * @author zhaoyang 
     * @date 2018年6月9日 下午11:10:10 
     */
    final protected function success(string $message, string $jumpUrl = null, bool $redirect = false, bool $externalRedirect = false) {
        if (is_null($jumpUrl)) {
            $this->flashSession->success($message);
            echo '<script>history.go(-1);</script>';
            return false;
        } else if ($redirect || strpos($jumpUrl, '://') !== false) {
            $this->flashSession->success($message);
            return $this->response->redirect($jumpUrl, $externalRedirect);
        } else {
            $this->flash->success($message);
            return $this->forward($jumpUrl);
        }
    }

    /** 
     * @desc 失败跳转
     * @param string $message 提示信息
     * @param string $jumpUrl 跳转地址
     * @param bool $redirect 是否使用response->redirect
     * @param bool $externalRedirect 是否跳转到外部地址  
     * @author zhaoyang 
     * @date 2018年6月10日 上午12:10:16 
     */
    final protected function error(string $message, string $jumpUrl = null, bool $redirect = false, bool $externalRedirect = false) {
        if (is_null($jumpUrl)) {
            $this->flashSession->error($message);
            echo '<script>history.go(-1);</script>';
            return false;
        } else if ($redirect || strpos($jumpUrl, '://') !== false) {
            $this->flashSession->error($message);
            return $this->response->redirect($jumpUrl, $externalRedirect);
        } else {
            $this->flash->error($message);
            return $this->forward($jumpUrl);
        }
    }

    /** 
     * @desc 响应json数据 
     * @param string|array $responseData 数据或错误提示
     * @param int $status 返回状态
     * @param int $jsonOptions json选项
     * @param int $depth 处理数组深度
     * @return object 
     * @author zhaoyang 
     * @date 2018年6月13日 下午10:05:54 
     */
    final protected function sendJson($responseData, int $status = 10000, int $jsonOptions = null, int $depth = 512){
        $responseData = [
            'status' => $status,
            'message' => $status == 10000 ? 'ok' : $responseData,
            'data' => $status == 10000 ? $responseData : ''
        ];
        return $this->response->setJsonContent($responseData, $jsonOptions, $depth)->send();
    }
}

3、在home模块下创建HttpCurlController.php

<?php
namespace App\Home\Controllers;

use Common\BaseController;
use Library\Tools\HttpCurl;

class HttpCurlController extends BaseController {

    public function indexAction() {
        // 简化请求流程,不做签名和加密
        /* $requestData = [
            'a' => '10a',
            'b' => 15
        ]; */
        $requestData = [
            'a' => 10,
            'b' => 15
        ];
        $url = 'http://phalcon.com/admin/index/test';
        $httpCurl = new HttpCurl($url);
        $res = $httpCurl->execPost($requestData);
        if($res === false){
            var_dump($httpCurl->getError());
            exit;
        }
        var_dump($res, json_decode($res, true));
        exit;
    }
}

4、打开admin模块下IndexController.php控制器

<?php
namespace App\Admin\Controllers;

use Common\BaseController;
use Common\Validate;

class IndexController extends BaseController {

    public function indexAction() {
        echo __METHOD__, '<br>';
        var_dump($this->get());
        exit();
    }

    public function testAction() {
        // 忽略校验签名等
        $rules = [
            ['a', 'regex', 'a只能为小于9999的正整数', '/^[1-9]\d{0,3}$/', 1],
            ['b', 'regex', 'b只能为小于9999的正整数', '/^[1-9]\d{0,3}$/', 1]
        ];
        $data = $this->json();
        $validate = new Validate();
        $messages = $validate->addRules($rules)->validate($data);
        if($messages->count()){
            return $this->sendJson($messages->current()->getMessage(), 10001);
        }
        $sum = $data['a'] + $data['b'];
        $responseData = [
            'sum' => $sum
        ];
        return $this->sendJson($responseData);
    }
}

5、访问/httpcurl/index
这里写图片描述

这里只是简单的模拟怎么使用,实际开发中还需要做签名甚至数据加密,由于非对称加密耗性能,一般接第三方接口使用的比较多,公司多端通信可以使用对称加密。

猜你喜欢

转载自blog.csdn.net/u014691098/article/details/80699337
今日推荐