作者 karlet

feat:ok修改

<?php
namespace Jiaoyin;
class Auth
{
/**
* 加密解密字符串
* @param $string 明文 或 密文
* @param $operation DECODE表示解密,其它表示加密
* @param $key 密钥
* @param $expiry 密文有效期
* @author nish
*/
public static function authcode($string, $operation = 'DECODE', $key = 'fhjxs', $expiry = 0)
{
// 过滤特殊字符
if ($operation == 'DECODE') {
$string = str_replace('[a]', '+', $string);
$string = str_replace('[b]', '&', $string);
$string = str_replace('[c]', '/', $string);
}
// 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
$ckey_length = 4;
// 密匙
$key = md5($key ? $key : 'fhj');
// 密匙a会参与加解密
$keya = md5(substr($key, 0, 16));
// 密匙b会用来做数据完整性验证
$keyb = md5(substr($key, 16, 16));
// 密匙c用于变化生成的密文
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
// 参与运算的密匙
$cryptkey = $keya . md5($keya . $keyc);
$key_length = strlen($cryptkey);
// 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
// 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
// 产生密匙簿
for ($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
for ($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 核心加解密部分
for ($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
// 从密匙簿得出密匙进行异或,再转成字符
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if ($operation == 'DECODE') {
// substr($result, 0, 10) == 0 验证数据有效性
// substr($result, 0, 10) - time() > 0 验证数据有效性
// substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
// 验证数据有效性,请看未加密明文的格式
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
// 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
// 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
$ustr = $keyc . str_replace('=', '', base64_encode($result));
// 过滤特殊字符
$ustr = str_replace('+', '[a]', $ustr);
$ustr = str_replace('&', '[b]', $ustr);
$ustr = str_replace('/', '[c]', $ustr);
return $ustr;
}
}
}
\ No newline at end of file
... ...
... ... @@ -26,12 +26,17 @@ class Curl{
if(empty($url)){
return false;
}
if(count($param) > 0){
$url = $url.'?'.http_build_query($param);
}
$ch = curl_init();
$ch = self::curlSet($ch, $url, $header);
curl_setopt($ch, CURLOPT_POST, 1);
$opts=[];
$opts[CURLOPT_POST]=1;
$opts[CURLOPT_USERAGENT]="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.98 Safari/537.36";
if (!empty($header) && in_array('Content-Type:application/json', $header)) {
$opts[CURLOPT_POSTFIELDS]= json_encode($param);
} else {
$opts[CURLOPT_POSTFIELDS] = http_build_query($param);
}
curl_setopt_array($ch, $opts);
$output = curl_exec($ch);
if($output === false){
echo 'Curl error: ' . curl_error($ch);
... ...
<?php
namespace Jiaoyin;
/*
所有接口
*/
class OkApi
{
protected string $host = 'https://www.okx.com';
protected string $apikey = '';
protected string $secret = '';
protected string $apipwd = '';
protected string $nonce = '';
protected string $signature = '';
protected array $headers = [];
protected string $method = '';
protected array $param = [];
protected string $path = '';
protected array $options = [];
public function __construct($apikey = '', $secret = '', $apipwd = '', $host = '')
{
$this->apikey = $apikey;
$this->secret = $secret;
$this->apipwd = $apipwd;
if (!empty($host)) {
$this->host = $host;
}
}
// 核心认证过程
protected function auth()
{
$this->generateNonce();
$this->generateSignature();
$this->createHeaders();
}
// 生成时间戳
protected function generateNonce()
{
$this->nonce = gmdate('Y-m-d\TH:i:s\.000\Z');
}
// 生成签名
protected function generateSignature()
{
$body = '';
$path = $this->method . $this->path;
if (!empty($this->param)) {
if ($this->method == 'GET') {
$path .= '?' . http_build_query($this->param);
} else {
$body = json_encode($this->param);
}
}
$this->signature = base64_encode(hash_hmac('sha256', $this->nonce . $path . $body, $this->secret, true));
}
// 构建请求URL
private function createUrl($path): string
{
return $this->host . $path;
}
// 构建请求头
private function createHeaders(): array
{
$headers = [
'Content-Type' => 'application/json',
];
if (!empty($this->apikey) && !empty($this->secret)) {
$headers = array_merge($headers, [
'OK-ACCESS-KEY' => $this->apikey,
'OK-ACCESS-TIMESTAMP' => $this->nonce,
'OK-ACCESS-PASSPHRASE' => $this->apipwd,
'OK-ACCESS-SIGN' => $this->signature,
]);
}
$headers_array=[];
foreach ($headers as $key => $value){
$headers_array[]=$key.':'.$value;
}
$this->headers = $headers_array;
return $headers;
}
/*
* 公共请求接口
* $type 1: 需鉴权 2: 不需鉴权
* */
public function request($method, $path, $param,$type=1)
{
$this->method = strtoupper($method);
$this->path = $path;
$this->param = $param;
if($type==2){
$this->createHeaders();
}else{
if (empty($this->apikey) || empty($this->secret) || empty($this->apipwd)) {
return ['code' => -1, 'msg' => 'apikey, secret or apipwd is empty'];
}
$this->auth();
}
if (!in_array($this->method, ['GET', 'POST', 'DELETE'])) {
return ['code' => -1, 'msg' => 'Invalid HTTP method'];
}
$url = $this->createUrl($path);
switch ($this->method) {
case 'GET':
$data = Curl::httpGet($url, $this->param, $this->headers);
break;
case 'POST':
$data = Curl::httpPost($url, $this->param, $this->headers);
break;
case 'DELETE':
$data = Curl::httpDelete($url, $this->param, $this->headers);
break;
}
return json_decode($data, true);
}
/**
* 合约账户余额查询
*/
public function getBalance($param=[])
{
$path = '/api/v5/account/balance';
return $this->request('GET', $path, $param);
}
/**
* 资金账户余额查询
*/
public function getAssetBalance($param=[])
{
$path = '/api/v5/asset/balances';
return $this->request('GET', $path, $param);
}
/**
* 获取持仓信息
*/
public function getPositions($param)
{
$path = '/api/v5/account/positions';
return $this->request('GET', $path, $param);
}
/*
* 资金划转
* */
public function transfer($param)
{
$path = '/api/v5/asset/transfer';
return $this->request('POST', $path, $param);
}
/*
* 公共请求接口
* */
public function getTransferHistory($path,$param)
{
$path = '/api/v5/asset/bills';
return $this->request('GET', $path, $param);
}
}
... ...