基于thinkphp3.2的京东接口第三方类库

浏览:7436 发布日期:2015/10/13 分类:功能实现 关键字: 京东接口 jd-sdk 京东sdk
通过京东接口,实现商品信息的同步,商品的库存同步,订单获取,订单状态同步等功能,通过修改京东的SDK当做thinkphp的第三方类库,方便调用。
第一步:在http://jos.jd.com/申请成为开发者,这时候就有了用户的key和secret
第二步:开通 “京东宙斯-京东开放API服务”,然后去http://i.jcloud.com/ 去新建应用
第三步:新建应用里面要求填写回调地址,你可以填写自己电脑的本地地址,那么这个时候就只有你自己这台电脑可以测试http://localhost/admin.php?m=Admin&c=Jd&a=callback,点击保存,这个时候你的应用就是测试应用了,会分配App Key和App Secret给你
第四部:去https://code.jd.com/from201304_m/jos-php-sdk下载原生的PHP-SDK文件,自己可以去看看源码
改造源码步骤
首先我们必须有oauth认证登陆,我在Org/Util文件夹里面建了一个Jdsdk.class.php用于认证登陆授权<?php
namespace Org\Util;
class Jdsdk{
    const CSRF_TOKEN = 1;

    const CSRF_AUTHORIZE = 2;

    public $redirectUri;

    protected $authorizeUrl = 'https://oauth.jd.com/oauth/authorize';

    protected $tokenUrl = 'https://oauth.jd.com/oauth/token';

    protected $gatewayUrl='https://api.jd.com/routerjson';
    protected $apiVersion='2.0';

    public function __construct(){
        $config=C('JOS_CONFIG');
        $this->redirectUri=$config['REDIRECT_URI'];
        $this->appkey=$config['APP_KEY'];
        $this->secretKey=$config['SECRET_KEY'];
    }

    /**
     * 授权登录
     **/
    public function getAuthorizeUrl($redirectUri = null){
        $redirectUri || $redirectUri = $this->redirectUri;
        $param['response_type'] = 'code';
        $param['client_id'] = $this->appkey;
        $param['redirect_uri'] = $redirectUri;
        $param['state'] = $this->mkCsrf(self::CSRF_AUTHORIZE);
        $param['scope'] = 'read';
        return $this->authorizeUrl . '?' . http_build_query($param);
    }

    /**
     * 获取accessToken
     ***/
    public function fetchAccessToken($code, $redirectUri = null){
        $redirectUri || $redirectUri = $this->redirectUri;
        $param = array(
            'grant_type' => 'authorization_code',
            'client_id' => $this->appkey,
            'client_secret' => $this->secretKey,
            'code' => $code,
            'redirect_uri' => $redirectUri,
            'scope' => 'read',
            'state' => $this->mkCsrf(self::CSRF_TOKEN)
        );
        $json = $this->curl($this->tokenUrl, $param);
        $json = iconv('gbk', 'utf-8', $json);
        $json = json_decode($json);
        if (isset($json->code) && isset($json->error_description)) {
            throw new \Exception($json->error_description, intval($json->code));
        }
        return $json;
    }

    //获取商品列表信息
    //public function 

    //执行请求
    public function execute(JosRequest $request, $session = null){
        $result = new \stdClass();
        if ($this->checkRequest) {
            try {
                $request->check();
            } catch (Exception $e) {
                $result->code = $e->getCode();
                $result->zh_desc = "api请求参数验证失败";
                $result->en_desc = $e->getMessage();
                return $result;
            }
        }
        // 组装系统参数
        $sysParams['app_key'] = $this->appkey;
        $sysParams['v'] = $this->apiVersion;
        $sysParams['method'] = $request->getApiMethod();
        if ($session !== null) {
            $sysParams['access_token'] = $_SESSION['token']->access_token;
        }
        $sysParams['timestamp'] = date('Y-m-d H:i:s');
        
        // 获取业务参数
        $apiParams['360buy_param_json'] = $request->getAppJsonParams();
        // 签名
        $sysParams['sign'] = $this->generateSign(array_merge($sysParams, $apiParams));
        
        $requestUrl = $this->gatewayUrl . '?' . http_build_query($sysParams);
        //echo $requestUrl;die;
        // 发送http请求
        try {
            $resp = $this->curl($requestUrl, $apiParams);
        } catch (Exception $e) {
            $result->code = $e->getCode();
            $result->zh_desc = "curl发送http请求失败";
            $result->en_desc = $e->getMessage();
            return $result;
        }
        // 解析返回结果
        $respWellFormed = false;
        $respObject = self::jsonDecode($resp);
        
        if (null !== $respObject) {
            $respWellFormed = true;
            foreach ($respObject as $propKey => $propValue) {
                $respObject = $propValue;
            }
        }
        if (false === $respWellFormed) {
            $result->code = 1;
            $result->zh_desc = "api返回数据错误或程序无法解析返回参数";
            $result->en_desc = "HTTP_RESPONSE_NOT_WELL_FORMED";
            $result->resp = $resp;
            return $result;
        }
        return $respObject;
    }

    private static function jsonDecode($str)
    {
        // 特殊字符处理
        $str = str_replace([chr(0),chr(4),chr(15),chr(16),chr(19),chr(31),'\\v'], '\\t', $str);
        if (defined('JSON_BIGINT_AS_STRING')) {
            return json_decode($str, false, 512, JSON_BIGINT_AS_STRING);
        } else {
            return PhplutilsJSON::decode($str);
        }
    }

    /**
     * 签名
     *
     * @param $params 业务参数            
     * @return void
     */
    private function generateSign($params){
        if ($params != null) {
            ksort($params);
            $stringToBeSigned = $this->secretKey;
            foreach ($params as $k => $v) {
                $stringToBeSigned .= "$k$v";
            }
            unset($k, $v);
            $stringToBeSigned .= $this->secretKey;
        } else {
            $stringToBeSigned = $this->secretKey;
            $stringToBeSigned .= $this->secretKey;
        }
        return strtoupper(md5($stringToBeSigned));
    }

    /**
     * 重新生成csrf
     *
     * @param unknown $key            
     * @return string
     */
    public function mkCsrf($key){
        // TODO
        // $v = uniqid('', true);
        // $_SESSION['jos_' . $key] = $v;
        return '';
    }

    /**
     * 验证csrf正确性,单次验证
     *
     * @param unknown $key            
     * @param unknown $value            
     * @return boolean
     */
    public function checkCsrf($key, $value){
        // $v = $_SESSION['jos_' . $key];
        // $r = $v ? $v === $value : false;
        // unset($_SESSION['jos_' . $key]);
        // TODO
        return true;
    }

    //curl请求
    public function curl($url, $postFields = null){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // https 请求
        if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        
        if (is_array($postFields) && 0 < count($postFields)) {
            curl_setopt($ch, CURLOPT_POST, true);
            $postMultipart = false;
            foreach ($postFields as $k => $v) {
                if ('@' == substr($v, 0, 1)) {
                    $postMultipart = true;
                    break;
                }
            }
            unset($k, $v);
            if ($postMultipart) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
            } else {
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postFields));
            }
        }
        $reponse = curl_exec($ch);
        
        if (curl_errno($ch)) {
            throw new \Exception(curl_error($ch), 0);
        } else {
            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if (200 !== $httpStatusCode) {
                throw new \Exception($reponse, $httpStatusCode);
            }
        }
        curl_close($ch);
        return $reponse;
    }
}
然后写一个controller类<?php
// +----------------------------------------------------------------------
// | Author: 前度天下 <852997402@qq.com>
// +----------------------------------------------------------------------

namespace Admin\Controller;
use Think\Controller;

class JdController extends Controller {
    private $jos;
    private $jos_config;
    public function __construct() {
        $this->jos_config = C('JOS_CONFIG');   //这里的配置是写在配置文件中的
        $this->jos = new \Org\Util\Jdsdk();       //这里是jd的sdk改造后的类
        parent::__construct();
    }

    public function index() {
        if (isset($_SESSION['is_jd_success'])) {
            if ($_SESSION['is_jd_success'] == 1) {
                $status = 1;
            } elseif ($_SESSION['is_jd_success'] == 0) {
                $status = 0;
            }
            $this->assign("is_jd_success", $status);
        }
        //获取商品列表
        $this->goods = $this->getCateList();
        $this->assign("page", $_SESSION['page_num']);
        $this->display();
    }

        //获取商品列表
    public function getCateList($page = 1) {
        $obj = new \Org\Util\Jos\WareInfoByInfoRequest();
        $obj->setPage($page);
        $obj->setPageSize(18);
        $resp = $this->jos->execute($obj, $_SESSION['token']->access_token);
        //保存页码
        $rzt = $resp->total / 18;
        $_SESSION['page_num'] = ceil($rzt);
        $_SESSION['current_page'] = $page;
        return $resp->ware_infos;
    }

        //回调地址
    public function callback() {
        $code = I("code", "", "trim");
        $token = $this->jos->fetchAccessToken($code);
        if ($token->code != 0) {
            $_SESSION['is_jd_success'] = 0;
            $this->error("登录失败", U("Jd/index"));
        } else {
            $_SESSION['token'] = $token;
            $_SESSION['is_jd_success'] = 1;
            $this->success("登录成功", U("Jd/index"));
        }
    }
        //授权登录
    public function login() {
        $url = $this->jos->getAuthorizeUrl();
        header("location:" . $url);
    }
?>
下面是jd的配置文件写在config.php里面        //京东接口配置
    'JOS_CONFIG'=>array(
        'APP_KEY'=>'',
        'SECRET_KEY'=>'',
        'REDIRECT_URI'=>'http://localhost/admin.php?m=Admin&c=Jd&a=callback'
        ),
放一个登陆按钮在页面中,调用控制器的login方法,这个时候就是输入商家的账号和密码,同意授权就登陆成功了

附件中是我对js的sdk的部分改写,下载解压后将Jos文件夹一起放在Org/Util下面
下图中中文件名后缀带有.class.php是我修改了的文件,其他我没有用到就没有修改,修改方法很简单,下面告诉大家

比如:你想获取商品信息,这个时候先去京东的api文档看是哪个方法http://jos.jd.com/api/index.htm
文档中说用的是 360buy.wares.list.get 批量获取商品信息
然后去jos文件夹对所有文件进行全局搜索360buy.wares.list.get这个关键词,
会找到C:\wamp\www\ThinkPHP\Library\Org\Util\Jos\WareListRequest.php
这个时候改造步骤就开始了
先该文件名称WareListRequest.php换成WareListRequest.class.php
打开文件在头部加上命名空间
namespace Org\Util\Jos;
就可以了,接下来是调用
jd的调用输入参数时分为系统级别输入参数和应用级别输入参数,这里已经把系统级别的参数都绑定好了 所以不用管了,直接输入应用级别的参数

对应的就是类中的两个方法

想批量获取商品信息,在controller控制器中写一个方法
例如
function getGoodsList(){
$obj = new \Org\Util\Jos\WareListRequest();
$obj->setWareIds($id); //商品的id,用逗号分隔,最多不能超过10个
$obj->setFields('ware_id'); //需返回的字段列表。可选值:ware结构体中的所有字段;字段之间用“,”分隔
$resp = $this->jos->execute($obj, $_SESSION['token']->access_token); //这段代码所用的调用都需要加上的 都是一样的
print_r($resp);
}


可能有些地方我表达的不清楚,希望各位指出来,提出建议,希望大家有好的代码分享出来,玩过stackoverflow的都知道,国外的码农乐于分享,共同进步,一起分享
















附件 Jos.zip ( 42.28 KB 下载:250 次 )

评论( 相关
后面还有条评论,点击查看>>