<?php
//https://ciyon.local.ciy.cn/ajax/api/v1.transfer
//https://ciyon.local.ciy.cn/ajax/api/v1.query
namespace web\api;

class v1 {
    public static function json_transfer() {
        global $db;
        $post = new \ciy\post();
        $api = self::verifyapi($db, $post);
        if (is_string($api))
            return errjson($api);
        $thirdno = $post->get('thirdno');
        $notifyurl = $post->get('notifyurl');
        $amount = $post->getint('amount');
        $csql = new \ciy\sql('ap_transfer');
        $csql->where('thirdno', $thirdno);
        $chkrow = $db->getone($csql);
        if (is_array($chkrow))
            return errjson('单号已存在');
        //检查thirdno是否存在，等幂下单
        $updata = array();
        $updata['amount'] = $amount;
        $updata['thirdno'] = $thirdno;
        $updata['notifyurl'] = $notifyurl;
        $updata['retimes'] = 0;
        $updata['uptimes'] = 0;
        $updata['nexttimes'] = MAXTIMES;
        $updata['addtimes'] = time();
        $updata['signature'] = '';
        $updata['orderstatus'] = 10;
        $updata['apiid'] = $api['id'];
        if (isset($api['sign'])) {
            //验证签名
            $addtimes = $post->getint('timestamp');
            if (abs(time() - $addtimes) > 300) {
                return errjson('签名已过期，请检查timestamp时间戳是否与北京时间一致');
            }
            $updata['addtimes'] = $addtimes;
            $waitsignstr = 'amount=' . $updata['amount'] . ',addtimes=' . $addtimes;
            $retsign = self::verifysign($api['pubkey'], $waitsignstr, $api['sign']);
            if (is_string($retsign))
                return errjson($retsign);
            $updata['signature'] = $api['sign'];
            $updata['orderstatus'] = 20;
        }

        try {
            $db->begin();
            $csql = new \ciy\sql('ap_transfer');
            if ($db->insert($csql, $updata) === false)
                throw new \Exception('新增失败:' . $db->error);
            $id = $db->insert_id();
            $db->commit();
        } catch (\Exception $ex) {
            $db->rollback();
            savelogfile('err_db', $ex->getMessage());
            return errjson($ex->getMessage());
        }
        $ret['newid'] = $id;
        return succjson($ret);
    }
    public static function json_query() {
        global $db;
        $post = new \ciy\post();
        $api = self::verifyapi($db, $post);
        if (is_string($api))
            return errjson($api);
        $thirdno = $post->get('thirdno');
        $csql = new \ciy\sql('ap_transfer');
        $csql->where('thirdno', $thirdno);
        $row = $db->getone($csql);
        if (!is_array($row))
            return errjson('单号不存在');
        $ret = array();
        $ret['data'] = $row;
        return succjson($ret);
    }
    static function verifyapi($db, &$post) {
        global $db;
        $hash = $post->get('hash');
        if (empty($hash))
            return 'hash不存在';
        unset($post->post['hash']);
        $sign = $post->get('sign');
        if (!empty($sign))
            unset($post->post['sign']);
        $appid = $post->getint('appid');
        if ($appid <= 0)
            return 'appid不合法';
        $timestamp = $post->getdate('timestamp');
        if (abs(time() - $timestamp) > 600) {
            return 'timestamp与服务器相差超过10分钟，服务器时间:' . date('Y-m-d H:i:s');
        }

        $csql = new \ciy\sql('ap_api');
        $csql->where('id', $appid);
        $apirow = $db->getone($csql);
        if (!is_array($apirow)) {
            return 'appid不存在';
        }
        if (empty($apirow['apisecret']))
            return '经检测，您的api接入不符合要求，已经暂停接入，请调整代码后重置ApiKey';

        $hashstr = '';
        ksort($post->post);
        foreach ($post->post as $key => $value) {
            $hashstr .= $key . '=' . $value . '&';
        }
        $hashstr = substr($hashstr, 0, -1) . $apirow['apisecret'];
        if ($hash != sha256($hashstr)) {
            return 'hash验证错误';
        }
        $ip = getip();
        if (!empty($apirow['ips'])) {
            $ips = explode("\n", $apirow['ips']);
            if (!in_array($ip, $ips)) {
                return 'ip不在白名单内';
            }
        }
        if (!empty($sign)) {
            if (empty($apirow['pubkey']))
                return '未安装数字证书';
            $apirow['sign'] = $sign;
        }
        return $apirow;
    }
    static function verifysign($pubkey, $data, $sign) {
        $signbin = hex2bin($sign);
        if ($signbin === false) {
            return '签名格式错误';
        }
        $hashbin = hex2bin(hash('sha256', $data));
        if (strpos($pubkey, '-----BEGIN RSA PUBLIC KEY-----') === false && strpos($pubkey, '-----BEGIN PUBLIC KEY-----') === false)
            $pubkey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($pubkey, 64, "\n") . "\n-----END PUBLIC KEY-----";

        $result = openssl_verify($hashbin, $signbin, $pubkey, OPENSSL_ALGO_SHA256);
        if ($result === 0) {
            return '数字证书验签失败';
        } else if ($result !== 1) {
            return '数字证书验签错误:' . openssl_error_string();
        }
        return true;
    }
}
