time_stamp = date('Y-m-d H:i:s', time());//时间 yyyyMMddhhmmss // $this->params_base['IMEI'] = '0000';//设备串号(移动终端设备串号,默认0000) // $this->params_base['apiVersion'] = $this->api_version;//接口版本号(服务端向下版本兼容控制),默认值为1 // $this->params_base['SIGN'] = md5($this->params_base['IMEI']."&".$this->client_id."&".$this->params_base['timeStamp']); // echo $this->params_base['IMEI']."&".$this->client_id."&".$this->params_base['timeStamp']; // 设定default时产生 //加载redis $this->redis = Redis::getInstance()->getConnect(); //从redis中拿参数..这些参数来自于数据库ims_superdesk_jd_vop_configs表..然后设置默认的时候存到了redis zjh 2018年8月17日 14:22:06 $key = 'superdesk_jd_vop_' . 'web_jd_vop_configs_manage' . ':' . 17; $api_conf = $this->redis->get($key); if (!empty($api_conf)) { $api_conf = json_decode($api_conf, true); $this->client_id = $api_conf['client_id']; $this->client_secret = $api_conf['client_secret']; $this->username = $api_conf['username']; $this->password = $api_conf['password']; } else { $api_conf = JdConfig::create()->where('is_default',1)->get()->toArray(); if(!empty($api_conf)){ $this->client_id = $api_conf['client_id']; $this->client_secret = $api_conf['client_secret']; $this->username = $api_conf['username']; $this->password = $api_conf['password']; } else { //手动配置 201998 $this->client_id = 'nuAeRH1KFlSeiIrfPYTZ'; $this->client_secret = 'ioyqcauADf0v3ayE73I5'; $this->username = '中航物业员工福利'; $this->password = 'avic-s'; } } } function init_access_token() { global $_W; /******************************************************* redis *********************************************************/ $table__key = 'superdesk_jd_vop_' . 'sdk_access_token' . ':' . 17; $colunm_key = 'jd_vop_access_token'; //microtime_format('Y-m-d H:i:s.x',microtime()) $result = $this->redis->hget($table__key, $colunm_key); $result = json_decode($result, true); // echo json_encode($result,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); if (empty($result) || empty($result['result'])) { $result = $this->access_token(); $this->redis->hset($table__key, $colunm_key, $result); $result = json_decode($result, true); } if (intval(floatval($result['result']['time']) / 1000) + intval($result['result']['expires_in']) <= time()) { $result = $this->refresh_token($result['result']['refresh_token']); $this->redis->hset($table__key, $colunm_key, $result); // BUG 当要去刷时 $result 变回字符串 $result = json_decode($result, true); } $this->access_token = $result['result']['access_token']; // echo $this->access_token; // echo "
"; // echo date('Y-m-d H:i:s', floatval($result['result']['time']) / 1000); // echo "
"; // echo "
"; /******************************************************* redis *********************************************************/ } /** * 签名,生成规则如下: * 1. 按照以下顺序将字符串拼接起来 * client_secret+timestamp+client_id+username+password+grant_type+scope+client_secret * 其中 * client_secret的值是京东分配的 * username使用原文 * password需要md5加密后的 * 2. 将上述拼接的字符串使用MD5加密,加密后的值再转为大写 */ function create_sign() { $sign_str = $this->client_secret . $this->time_stamp . $this->client_id . $this->username . md5($this->password) . $this->grant_type . $this->scope . $this->client_secret; $sign_md5 = md5($sign_str); $sign_result = strtoupper($sign_md5); return $sign_result; } /** * TODO 已测 1.3 获取Access Token * HTTPS请求方式:POST * * @return string */ function access_token_url() { return $this->host . $this->edition . "/oauth2/accessToken"; } function access_token() { $params = array(); $params['grant_type'] = $this->grant_type;//该值固定为access_token $params['client_id'] = $this->client_id; $params['client_secret'] = $this->client_secret; $params['timestamp'] = $this->time_stamp; $params['username'] = $this->username; $params['password'] = md5($this->password); $params['scope'] = $this->scope;//非必须 申请权限。(目前推荐为空。为以后扩展用) $params['sign'] = $this->create_sign(); $response = $this->post($this->access_token_url(), $params, true); // { // "success": true, // "resultMessage": "", // "resultCode": "0000", // "result": { // "uid": "6165718786", // "refresh_token_expires": 1525071742348, // "time": 1509346942348, // "expires_in": 86400, // "refresh_token": "A23k88ryXJx9QJBay7QEmdPcM0GoJk8uidR2pIjy", // "access_token": "NIwoLn95BLs0ZdKLyawIiuFPM" // } // } return $response; } /** * TODO 已测 1.4 使用Refresh Token 刷新 Access Token * HTTPS请求方式:POST * * @return string */ function refresh_token_url() { return $this->host . $this->edition . "/oauth2/refreshToken"; } function refresh_token($refresh_token) { $params = array(); $params['refresh_token'] = $refresh_token; $params['client_id'] = $this->client_id; $params['client_secret'] = $this->client_secret; $response = $this->post($this->refresh_token_url(), $params, true); // { // "success": true, // "resultMessage": "", // "resultCode": "0000", // "result": { // "uid": "6165718786", // "refresh_token_expires": 1525077000000, // "time": 1509352200000, // "expires_in": 86400, // "refresh_token": "lhC8Btoft3GovRWad71v7b2RZ0ZQ45wQWjNmn46j", // "access_token": "yEZ3Ut9m1Np4XAGm8Qaq0f9s2" // } // } return $response; } //======================Other End======================== /** * GET wrappwer for oAuthRequest. * * @return mixed */ function get($url, $parameters = array()) { $response = $this->oAuthRequest($url, 'GET', $parameters); if ($this->format === 'json' && $this->decode_json) { return json_decode($response, true); } return $response; } /** * POST wreapper for oAuthRequest. * * @return mixed */ function post($url, $parameters = array(), $multi = false) { $response = $this->oAuthRequest($url, 'POST', $parameters, $multi); if ($this->format === 'json' && $this->decode_json) { return json_decode($response, true); } return $response; } /** * Format and sign an OAuth / API request * * @return string * @ignore */ function oAuthRequest($url, $method, $params, $multi = false) { if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) { $url = "{$this->host}/{$this->edition}/{$url}"; } else { $url = $url . '?client_id=' . $this->client_id . '&client_secret=' . $this->client_secret; } $parameters = array_merge_recursive($this->params_base, $params); // TODO jd_vop_api_logs switch ($method) { case 'GET' : $url = $url . http_build_query($parameters); return $this->http($url, 'GET'); case 'PUT' : $headers = array(); if (!$multi && (is_array($parameters) || is_object($parameters))) { if ($this->format === 'json' && $this->decode_json) { $body = json_encode($parameters); if ($this->debug) { echo '============= BODY ============='; echo '
'; echo $body; echo '
'; echo '============= BODY ============='; echo '
'; } } else { $body = http_build_query($parameters); } } else { $body = self::build_http_query_multi($parameters); $headers [] = "Content-Type: multipart/form-data; boundary=" . self::$boundary; } return $this->http($url, 'PUT', $body, $headers); case 'DELETE' : if (!empty($parameters)) { $url = $url . '&' . http_build_query($parameters); } return $this->http($url, 'DELETE'); default : $headers = array(); if (!$multi && (is_array($parameters) || is_object($parameters))) { if ($this->format === 'json' && $this->decode_json) { $body = json_encode($parameters); if ($this->debug) { echo '============= BODY ============='; echo '
'; echo $body; echo '
'; echo '============= BODY ============='; echo '
'; } } else { $body = http_build_query($parameters); } } else { $body = self::build_http_query_multi($parameters); $headers [] = "Content-Type: multipart/form-data; boundary=" . self::$boundary; } return $this->http($url, $method, $body, $headers); } } /** * Make an HTTP request * * @return string API results * @ignore */ function http($url, $method, $postfields = NULL, $headers = array()) { $this->http_info = array(); $ci = curl_init(); /* Curl settings */ curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent); curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout); curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ci, CURLOPT_ENCODING, ""); curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); // curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader')); curl_setopt($ci, CURLOPT_HEADER, FALSE); switch ($method) { case 'GET': curl_setopt($ci, CURLOPT_HTTPGET, TRUE); if (!empty($postfields)) { curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); $this->postdata = $postfields; } break; case 'POST': curl_setopt($ci, CURLOPT_POST, TRUE); if ($this->format === 'json') { $headers [] = "Content-Type: application/json;"; } if (!empty($postfields)) { curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); $this->postdata = $postfields; } break; case 'PUT': curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'PUT'); $headers [] = "Content-Type: application/json;"; if (!empty($postfields)) { curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); $this->postdata = $postfields; } break; case 'DELETE': curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE'); if (!empty($postfields)) { $url = "{$url}?{$postfields}"; echo $url; echo '
'; } else { $url = $url; } break; } // $headers[] = "API-RemoteIP: " . $_SERVER['REMOTE_ADDR']; curl_setopt($ci, CURLOPT_URL, $url); curl_setopt($ci, CURLOPT_HTTPHEADER, $headers); curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE); $response = curl_exec($ci); $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE); $this->http_info = array_merge($this->http_info, curl_getinfo($ci)); $this->url = $url; if ($this->debug) { echo "=====post data======\r\n"; echo '
'; var_dump($postfields); echo '
'; echo '=====info=====' . "\r\n"; echo '
'; print_r(curl_getinfo($ci)); echo '
'; echo '=====$response=====' . "\r\n"; echo '
'; print_r($response); echo '
'; } $code = curl_getinfo($ci); $response = json_decode($response, true); if (!$response) {// TODO 暂时修正京东返回空的问题 $response = array(); } $response['code'] = $code['http_code']; $___url___ = str_replace($this->host . $this->edition, '', $url); $log_data = array(); $log_data['url'] = $url; $log_data['api'] = substr($___url___, 0, strpos($___url___, '?')); $log_data['method'] = $method; $log_data['post_fields'] = $postfields; $log_data['curl_info'] = json_encode(curl_getinfo($ci), JSON_UNESCAPED_UNICODE); $log_data['success'] = isset($response['success']) ? $response['success'] : "exit0"; $log_data['resultMessage'] = isset($response['resultMessage']) ? $response['resultMessage'] : "exit0"; $log_data['resultCode'] = isset($response['resultCode']) ? $response['resultCode'] : "exit0"; $log_data['result'] = isset($response['result']) ? json_encode($response['result'], JSON_UNESCAPED_UNICODE) : ""; /************************** 2019年12月31日 09:42:42 zjh 改数据库为文件 *************************************/ // $this->_logsModel->insert($log_data);// TODO 屏蔽测试 //日志记录 Logger::getInstance()->info('京东请求日志:' . json_encode($log_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); /************************** 2019年12月31日 09:42:42 zjh 改数据库为文件 *************************************/ if (!empty($response['status']) && $response['status'] == 'Unauthorized.') { /* header("Location:".site_url("Login/logout")); exit();*/ $response['status'] = 'Unauthorized.'; } $response = json_encode($response); curl_close($ci); return $response; } /** * 处理多媒体数据内容 * * @ignore */ public static function build_http_query_multi($params) { if (!$params) return ''; uksort($params, 'strcmp'); $pairs = array(); self::$boundary = $boundary = uniqid('------------------'); $MPboundary = '--' . $boundary; $endMPboundary = $MPboundary . '--'; $multipartbody = ''; foreach ($params as $parameter => $value) { if (in_array($parameter, array('pic', 'image', 'Filedata')) && $value{0} == '@') { $url = ltrim($value, '@'); $content = file_get_contents($url); $array = explode('?', basename($url)); $filename = $array[0]; $multipartbody .= $MPboundary . "\r\n"; $multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . '"; filename="' . $filename . '"' . "\r\n"; $multipartbody .= "Content-Type: image/unknown\r\n\r\n"; $multipartbody .= $content . "\r\n"; } else { $multipartbody .= $MPboundary . "\r\n"; $multipartbody .= 'content-disposition: form-data; name="' . $parameter . "\"\r\n\r\n"; $multipartbody .= $value . "\r\n"; } } $multipartbody .= $endMPboundary; return $multipartbody; } /***********************************************************************************************************************/ /**************** 以下处理业务逻辑 *******************/ /** * TODO 已测 3.5 商品上下架状态接口 * HTTPS请求方式:POST * * @return string */ function api_product_sku_state_url() { return $this->host . $this->edition . "/api/product/skuState"; } function api_product_sku_state($sku) { $params = array(); $params['token'] = $this->access_token; //授权时获取的access token $params['sku'] = $sku;//商品编号,支持批量,以,分隔 (最高支持100个商品)1为上架,0为下架 $response = $this->post($this->api_product_sku_state_url(), $params, true); // 参见:3.5 获取商品上下架状态接口.json return $response; } /** * TODO 待测 6.2 批量获取库存接口(建议订单详情页、下单使用) * HTTPS请求方式:POST * * @return string */ function api_stock_get_new_stock_by_id_url() { return $this->host . $this->edition . "/api/stock/getNewStockById"; } function api_stock_get_new_stock_by_id($skuNums/*商品和数量 [{skuId: 569172,num:101}]*/, $area/*格式:1_0_0 (分别代表1、2、3级地址)*/) { $params = array(); $params['token'] = $this->access_token; $params['skuNums'] = $skuNums;//商品和数量 [{skuId: 569172,num:101}] $params['area'] = $area;//格式:1_0_0 (分别代表1、2、3级地址) $response = $this->post($this->api_stock_get_new_stock_by_id_url(), $params, true); //参数名称 意义  //areaId 配送地址id //desc 描述 //skuId 商品编号 //stockStateId 库存状态编号 33,39,40,36,34 //StockStateDesc 库存状态描述 //33 有货 现货-下单立即发货 //39 有货 在途-正在内部配货,预计2~6天到达本仓库 //40 有货 可配货-下单后从有货仓库配货 //36 预订 //34 无货 //remainNum 剩余数量 -1未知;当库存小于5时展示真实库存数量 // 参见:6.2 批量获取库存接口(建议订单详情页、下单使用).json return $response; } /** * TODO 待测 5.2 批量查询协议价价格 * HTTPS请求方式:POST * * @return string */ function api_price_get_price_url() { return $this->host . $this->edition . "/api/price/getPrice"; } function api_price_get_price($sku) { // $start = microtime(true); $params = array(); $params['token'] = $this->access_token;//授权时获取的access token $params['sku'] = $sku;//商品编号,请以,分割。例如:J_129408,J_129409(最高支持100个商品) $response = $this->post($this->api_price_get_price_url(), $params, true); // 参见:5.2 批量查询协议价价格.json // $end = microtime(true); // echo 'api_price_get_price 耗时'.round($end - $start,4).'秒'; // echo '
'; return $response; } }