admin/app/common/modules/yop/sdk/YopClient3.php

683 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\common\modules\yop\sdk;
use app\common\modules\yop\sdk\YopRequest;
use app\common\modules\yop\sdk\YopResponse;
use app\common\modules\yop\sdk\Util\YopSignUtils;
use app\common\modules\yop\sdk\Util\HttpRequest;
use app\common\modules\yop\sdk\Util\BlowfishEncrypter;
use app\common\modules\yop\sdk\Util\AESEncrypter;
use app\common\modules\yop\sdk\Util\StringUtils;
use app\common\modules\yop\sdk\Util\HttpUtils;
use app\common\modules\yop\sdk\Util\Base64Url;
class YopClient3
{
public function __construct()
{
}
/**
* @param $methodOrUri
* @param $YopRequest
* @param $encode_data
* @return array
*/
public static function SignRsaParameter($methodOrUri, $YopRequest)
{
$appKey = $YopRequest->{$YopRequest->Config->APP_KEY};
if (empty($appKey)) {
$appKey = $YopRequest->Config->CUSTOMER_NO;
$YopRequest->removeParam($YopRequest->Config->APP_KEY);
}
if (empty($appKey)) {
error_log("appKey 与 customerNo 不能同时为空");
}
date_default_timezone_set('PRC');
$dataTime = new \DateTime();
//$timestamp=$dataTime->format('c'); // Returns ISO8601 in proper format
$timestamp = $dataTime->format(\DateTime::ISO8601); // Works the same since const ISO8601 = "Y-m-d\TH:i:sO"
//$timestamp = "2016-02-25T08:57:48Z";
//$requestId = YopClient3::uuid();//Returns like 1225c695-cfb8-4ebb-aaaa-80da344e8352
$requestId="123456";
$headers = array();
$headers['x-yop-request-id'] = $requestId;
$headers['x-yop-date'] = $timestamp;
$protocolVersion = "yop-auth-v2";
$EXPIRED_SECONDS = "1800";
$authString = $protocolVersion . "/" . $appKey . "/" . $timestamp . "/" . $EXPIRED_SECONDS;
$headersToSignSet = array();
array_push($headersToSignSet, "x-yop-request-id");
array_push($headersToSignSet, "x-yop-date");
$appKey = $YopRequest->{$YopRequest->Config->APP_KEY};
if (StringUtils::isBlank($YopRequest->Config->CUSTOMER_NO)) {
$headers['x-yop-appkey'] = $appKey;
array_push($headersToSignSet, "x-yop-appkey");
} else {
$headers['x-yop-customerid'] = $appKey;
array_push($headersToSignSet, "x-yop-customerid");
}
// Formatting the URL with signing protocol.
$canonicalURI = HttpUtils::getCanonicalURIPath($methodOrUri);
// Formatting the query string with signing protocol.
$canonicalQueryString = YopClient3::getCanonicalQueryString($YopRequest, true);
// Sorted the headers should be signed from the request.
$headersToSign = YopClient3::getHeadersToSign($headers, $headersToSignSet);
// Formatting the headers from the request based on signing protocol.
$canonicalHeader = YopClient3::getCanonicalHeaders($headersToSign);
$signedHeaders = "";
if ($headersToSignSet != null) {
foreach ($headersToSign as $key => $value) {
$signedHeaders .= strlen($signedHeaders) == 0 ? "" : ";";
$signedHeaders .= $key;
}
$signedHeaders = strtolower($signedHeaders);
}
$canonicalRequest = $authString . "\n" . "POST" . "\n" . $canonicalURI . "\n" . $canonicalQueryString . "\n" . $canonicalHeader;
// Signing the canonical request using key with sha-256 algorithm.
if (empty($YopRequest->secretKey)) {
error_log("secretKey must be specified");
}
extension_loaded('openssl') or die('php需要openssl扩展支持');
$private_key = $YopRequest->secretKey;
$private_key = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($private_key, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
/* 提取私钥 */
$privateKey = openssl_pkey_get_private($private_key);
($privateKey) or die('密钥不可用');
$signToBase64 = "";
openssl_sign($canonicalRequest, $encode_data, $privateKey, "SHA256");
openssl_free_key($privateKey);
$signToBase64 = Base64Url::encode($encode_data);
$signToBase64 .= '$SHA256';
$headers['Authorization'] = "YOP-RSA2048-SHA256 " . $protocolVersion . "/" . $appKey . "/" . $timestamp . "/" . $EXPIRED_SECONDS . "/" . $signedHeaders . "/" . $signToBase64;
return $headers;
}
public function __set($name, $value)
{
// TODO: Implement __set() method.
$this->$name = $value;
}
public function __get($name)
{
// TODO: Implement __get() method.
return $this->$name;
}
static public function get($methodOrUri, $YopRequest){
$content = YopClient3::getForString($methodOrUri, $YopRequest);
$response = YopClient3::unmarshal($content);
YopClient3::handleRsaResult($YopRequest, $response, $content);
return $response;
}
static public function getForString($methodOrUri, $YopRequest){
$serverUrl = YopClient3::richRequest($methodOrUri, $YopRequest);
YopClient::signAndEncrypt($YopRequest);
$YopRequest->absoluteURL = $serverUrl;
$YopRequest->encoding();
$serverUrl .= (strpos($serverUrl,'?') === false ?'?':'&') . $YopRequest->toQueryString();
$response = YopClient3::getRestTemplate($serverUrl,$YopRequest,"GET");
return $response;
}
public static function post($methodOrUri, $YopRequest)
{
$content = YopClient3::postString($methodOrUri, $YopRequest);
$response = YopClient3::unmarshal($content);
YopClient3::handleRsaResult($YopRequest, $response, $content);
return $response;
}
/**
* @param $methodOrUri
* @param $YopRequest
* @return type
*/
public static function postString($methodOrUri, $YopRequest)
{
$serverUrl = YopClient3::richRequest($methodOrUri, $YopRequest);
$YopRequest->absoluteURL = $serverUrl;
$headers = self::SignRsaParameter($methodOrUri, $YopRequest);
$response = YopClient3::getRestTemplate($serverUrl, $YopRequest, "POST", $headers);
// echo $response;
return $response;
}
/**
* @param $YopRequest
* @param $forSignature
* @return string
*/
public static function getCanonicalQueryString($YopRequest, $forSignature)
{
$ArrayList = array();
$StrQuery = "";
foreach ($YopRequest->paramMap as $k => $v) {
if ($forSignature && strcasecmp($k, "Authorization") == 0) {
continue;
}
array_push($ArrayList, $k . "=" . rawurlencode($v));
}
sort($ArrayList);
foreach ($ArrayList as $kv) {
$StrQuery .= strlen($StrQuery) == 0 ? "" : "&";
$StrQuery .= $kv;
}
return $StrQuery;
}
/**
* @param $headers
* @param $headersToSign
* @return arry
*/
public static function getHeadersToSign($headers, $headersToSign)
{
$ret = array();
if ($headersToSign != null) {
$tempSet = array();
foreach ($headersToSign as $header) {
array_push($tempSet, strtolower(trim($header)));
}
$headersToSign = $tempSet;
}
foreach ($headers as $key => $value) {
if ($value != null && !empty($value)) {
if (($headersToSign == null && isDefaultHeaderToSign($key)) || ($headersToSign != null && in_array(strtolower($key), $headersToSign) && $key != "Authorization")) {
$ret[$key] = $value;
}
}
}
ksort($ret);
return $ret;
}
/**
* @param $header
* @return bool
*/
public static function isDefaultHeaderToSign($header)
{
$header = strtolower(trim($header));
$defaultHeadersToSign = array();
array_push($defaultHeadersToSign, "host");
array_push($defaultHeadersToSign, "content-length");
array_push($defaultHeadersToSign, "content-type");
array_push($defaultHeadersToSign, "content-md5");
return strpos($header, "x-yop-") == 0 || in_array($defaultHeadersToSign, $header);
}
/**
* @param $headers
* @return string
*/
public static function getCanonicalHeaders($headers)
{
if (empty($headers)) {
return "";
}
$headerStrings = array();
foreach ($headers as $key => $value) {
if ($key == null) {
continue;
}
if ($value == null) {
$value = "";
}
$key = HttpUtils::normalize(strtolower(trim($key)));
$value = HttpUtils::normalize(trim($value));
array_push($headerStrings, $key . ':' . $value);
}
sort($headerStrings);
$StrQuery = "";
foreach ($headerStrings as $kv) {
$StrQuery .= strlen($StrQuery) == 0 ? "" : "\n";
$StrQuery .= $kv;
}
return $StrQuery;
}
/**
* @param $methodOrUri
* @param $YopRequest
* @return YopResponse
*/
static public function upload($methodOrUri, $YopRequest)
{
$content = YopClient3::uploadForString($methodOrUri, $YopRequest);
$content = json_encode($content);
$response = YopClient3::unmarshal($content);
YopClient3::handleResult($YopRequest, $response, $content);
return $response;
}
static public function uploadForString($methodOrUri, $YopRequest)
{
$serverUrl = YopClient3::richRequest($methodOrUri, $YopRequest);
//$alternate = file_get_contents($YopRequest->getParam("_file"));
//YopClient3::signAndEncrypt($YopRequest);
$strTemp = $YopRequest->getParam("_file");
$YopRequest->removeParam("_file");
$headers = self::SignRsaParameter($methodOrUri, $YopRequest);
$YopRequest->addParam("_file",$strTemp);
//$YopRequest->addParam("_file",str_replace('file:','@',$strTemp));PUT
// Create a CURLFile object
//$cfile = curl_file_create($file);
//echo $YopRequest->getParam("_file");
$YopRequest->absoluteURL = $serverUrl;
$response = YopClient3::getRestTemplate($serverUrl, $YopRequest, "PUT",$headers);
return $response;
}
public static function unmarshal($content)
{
$jsoncontent= json_decode($content,true);
/*
*
{
"state" : "FAILURE",
"ts" : 1469523373843,
"error" : {
"code" : "U000001",
"message" : "会员不存在"
}
* */
$YopResponse = new YopResponse();
if (!empty($jsoncontent['state'])) {
$YopResponse->state = $jsoncontent['state'];
}
if (!empty($jsoncontent['error'])) {
if (is_array($jsoncontent['error'])) {
foreach ($jsoncontent['error'] as $k => $v) {
if (!is_array($v)) {
$YopResponse->error .= (empty($YopResponse->error) ? '' : ',') . '"' . $k . '" : "' . $v . '"';
} else {
$YopResponse->error .= (empty($YopResponse->error) ? '' : ',') . '"' . $k . '" : "' . json_encode($v, JSON_UNESCAPED_UNICODE) . '"';
foreach ($v as $vk => $vv) {
}
}
}
} else {
$YopResponse->error = $jsoncontent['error'];
}
}
if (!empty($jsoncontent['result'])) {
$YopResponse->result = $jsoncontent['result'];
}
if (!empty($jsoncontent['ts'])) {
$YopResponse->ts = $jsoncontent['ts'];
}
if (!empty($jsoncontent['sign'])) {
$YopResponse->sign = $jsoncontent['sign'];
}
if (!empty($jsoncontent['stringResult'])) {
$YopResponse->stringResult = $jsoncontent['stringResult'];
}
if (!empty($jsoncontent['format'])) {
$YopResponse->format = $jsoncontent['format'];
}
if (!empty($jsoncontent['validSign'])) {
$YopResponse->validSign = $jsoncontent['validSign'];
}
return $YopResponse;
}
public static function getRestTemplate($serverUrl, $YopRequest, $method, $headers)
{
$YopRequest->encoding();
if ($method == "GET") {
return HttpRequest::curl_request($serverUrl, '', $YopRequest->Config->connectTimeout, true);
} elseif ($method == "PUT") {
//$YopRequest->addParam("_file", $YopRequest->ImagePath);
return HttpRequest::curl_request($serverUrl, $YopRequest->paramMap, $YopRequest->Config->connectTimeout, true, true,$headers);
}
return HttpRequest::curl_request($serverUrl, $YopRequest->paramMap, $YopRequest->Config->connectTimeout, false, false, $headers);
}
static public function signAndEncrypt($YopRequest)
{
if (empty($YopRequest->method)) {
error_log("method must be specified");
}
if (empty($YopRequest->secretKey)) {
error_log("secretKey must be specified");
}
$appKey = $YopRequest->{$YopRequest->Config->APP_KEY};
if (empty($appKey)) {
$appKey = $YopRequest->Config->CUSTOMER_NO;
$YopRequest->removeParam($YopRequest->Config->APP_KEY);
}
if (empty($appKey)) {
error_log("appKey 与 customerNo 不能同时为空");
}
$signValue = YopSignUtils::sign($YopRequest->paramMap, $YopRequest->ignoreSignParams, $YopRequest->secretKey, $YopRequest->signAlg);
$YopRequest->addParam($YopRequest->Config->SIGN, $signValue);
if ($YopRequest->isRest) {
$YopRequest->removeParam($YopRequest->Config->METHOD);
$YopRequest->removeParam($YopRequest->Config->VERSION);
}
if ($YopRequest->encrypt) {
YopClient::encrypt($YopRequest);
}
}
static public function encrypt($YopRequest)
{
$builder = $YopRequest->paramMap;
foreach ($builder as $k => $v) {
if ($YopRequest->Config->ispublicedKey($k)) {
unset($builder[$k]);
} else {
$YopRequest->removeParam($k);
}
}
if (!empty($builder)) {
$encryptBody = "";
foreach ($builder as $k => $v) {
$encryptBody .= strlen($encryptBody) == 0 ? "" : "&";
$encryptBody .= $k . "=" . urlencode($v);
}
}
if (empty($encryptBody)) {
$YopRequest->addParam($YopRequest->Config->ENCRYPT, true);
} else {
if (!empty($YopRequest->{$YopRequest->Config->APP_KEY})) {
$encrypt = AESEncrypter::encode($encryptBody, $YopRequest->secretKey);
$YopRequest->addParam($YopRequest->Config->ENCRYPT, $encrypt);
} else {
$encrypt = BlowfishEncrypter::encode($encryptBody, $YopRequest->secretKey);
$YopRequest->addParam($YopRequest->Config->ENCRYPT, $encrypt);
}
}
}
static public function decrypt($YopRequest, $strResult)
{
if (!empty($strResult) && $YopRequest->{$YopRequest->Config->ENCRYPT}) {
if (!empty($YopRequest->{$YopRequest->Config->APP_KEY})) {
$strResult = AESEncrypter::decode($strResult, $YopRequest->secretKey);
} else {
$strResult = BlowfishEncrypter::decode($strResult, $YopRequest->secretKey);
}
}
return $strResult;
}
static public function richRequest($methodOrUri, $YopRequest)
{
if (strpos($methodOrUri, $YopRequest->Config->serverRoot)) {
$methodOrUri = substr($methodOrUri, strlen($YopRequest->Config->serverRoot) + 1);
}
$isRest = (strpos($methodOrUri, "/rest/") == 0) ? true : false;
$YopRequest->isRest = $isRest;
$serverUrl = $YopRequest->serverRoot;
if ($isRest) {
$serverUrl .= $methodOrUri;
preg_match('@/rest/v([^/]+)/@i', $methodOrUri, $version);
if (!empty($version)) {
$version = $version[1];
if (!empty($version)) {
$YopRequest->setVersion($version);
}
}
} else {
$serverUrl .= "/command?" . $YopRequest->Config->METHOD . "=" . $methodOrUri;
}
$YopRequest->setMethod($methodOrUri);
return $serverUrl;
}
public static function handleResult($YopRequest, $YopResponse, $content)
{
$YopResponse->format = $YopRequest->format;
$ziped = '';
if (strtoupper($YopResponse->state) == 'SUCCESS') {
$strResult = self::getBizResult($content, $YopRequest->format);
if (!empty($ziped) && $YopResponse->error == '') {
if ($YopRequest->encrypt) {
$decryptResult = self::decrypt($YopRequest, trim($ziped));
$YopResponse->stringResult = $decryptResult;
$YopResponse->result = $decryptResult;
} else {
$YopResponse->stringResult = $strResult;
}
}
}
if ($YopRequest->signRet && !empty($YopRequest->sign)) {
$signStr = $YopResponse->state . $ziped . $YopResponse->ts;
$YopResponse->validSign = YopSignUtils::isValidResult($signStr, $YopRequest->secretKey, $YopRequest->signAlg, $YopResponse->sign);
} else {
$YopResponse->validSign = true;
}
}
public static function handleRsaResult($YopRequest, $YopResponse, $content)
{
$YopResponse->format = $YopRequest->format;
$ziped = '';
if (strtoupper($YopResponse->state) == 'SUCCESS') {
$strResult =YopClient3::getBizResult($content, $YopRequest->format);
$ziped =$strResult;
if (!empty($ziped) && empty($YopResponse->error)) {
$YopResponse->stringResult = $strResult;
}
}
$YopResponse->validSign= YopClient3::isValidRsaResult($ziped, $YopResponse->sign,$YopRequest->yopPublicKey);
}
/**
* 对业务结果签名进行校验
*/
public static function isValidRsaResult($result, $sign,$public_key)
{
$sb = "";
if ($result == null || empty($result)) {
$sb = "";
} else {
$sb .= trim($result);
}
$public_key = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($public_key, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$pu_key = openssl_pkey_get_public($public_key);
$sb= preg_replace("/[\s]{2,}/","",$sb);
$sb= str_replace(PHP_EOL,"",$sb);
$sb= str_replace(" ","",$sb);
$res = openssl_verify($sb,Base64Url::decode(substr($sign,0,-7)), $pu_key,"SHA256"); //验证
openssl_free_key($pu_key);
if ($res == 1) {
return true;
} else {
return false;
}
}
private static function getBizResult($content, $format)
{
if (empty($format)) {
return $content;
}
switch ($format) {
case 'json':
//preg_match('@"result" :(.+),"ts"@i', $content, $jsonStr);
$result = strstr($content, '"result"');
$length = strlen('"result"');
$result = substr($result, $length+3);
$result = substr($result,0,strrpos($result,'"ts"'));
$result = substr($result,0,strlen($result)-4);
return $result;
default:
//preg_match('@</state>(.+)<ts>@i', $content, $xmlStr);
$result = strstr($content, '"</state>"');
$length = strlen('</state>');
$result = substr($result, $length+4);
$result = substr($result,0,strrpos($result,'"ts"'));
$result = substr($result, 0, -2);
return $result;
}
}
private static function uuid($prefix = '')
{
$chars = md5(uniqid(mt_rand(), true));
$uuid = substr($chars, 0, 8) . '-';
$uuid .= substr($chars, 8, 4) . '-';
$uuid .= substr($chars, 12, 4) . '-';
$uuid .= substr($chars, 16, 4) . '-';
$uuid .= substr($chars, 20, 12);
return $prefix . $uuid;
}
}