<?php


$this->weixin = $this->get_cache('weixin'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); // 配置

// 获取微信表名
function weixin_wxtable($name, $wxid = WEIXIN_MORE_ID) {
    $prefix = $wxid > 1 ? 'more_'.$wxid.'_' : '';
    if ($name != 'weixin') {
        $name = 'weixin_'.$name;
    }
    return $prefix.$name;
}

// 获取access_token
function weixin_get_access_token($data = []) {

    if (is_array($data) && $data) {
        $config = $data;
    } elseif ($data == 'update') {
        // 重写写入
        $config = \Phpcmf\Service::C()->weixin['account'];
    } else {
        $cache_data = \Phpcmf\Service::L('cache')->get_auth_data('weixin_access_token_'.WEIXIN_MORE_ID, 1, 2200);
        if (is_array($cache_data)) {
            if ($cache_data['endtime'] && $cache_data['endtime'] > SYS_TIME && $cache_data['access_token']) {
                return dr_return_data(1, $cache_data['access_token']);
            } elseif (!\Phpcmf\Service::C()->weixin['account']) {
                return dr_return_data(0, '未配置微信接入参数');
            }
        }
        $config = \Phpcmf\Service::C()->weixin['account'];
    }
    if (!$config['appid'] || !$config['appsecret']) {
        return dr_return_data(0, 'appid或者appsecret没填写');
    }

    $result = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$config['appid'].'&secret='.$config['appsecret']);
    if (!$result['code']) {
        return dr_return_data(0, 'AccessToken：'.$result['msg']);
    } elseif (!$result['data']['access_token']) {
        return dr_return_data(0, 'AccessToken为空，请重试');
    }

    $result['data']['endtime'] = SYS_TIME + 2360;
    $rt = \Phpcmf\Service::L('cache')->set_auth_data('weixin_access_token_'.WEIXIN_MORE_ID, $result['data'], 1);
    if (!$rt) {
        return dr_return_data(0, 'AccessToken：/cache/authcode/目录不可写，文件写入失败');
    }

    return dr_return_data(1, $result['data']['access_token']);
}

// 小程序获取access_token
function xcx_get_access_token($data = []) {

    if (is_array($data) && $data) {
        $config = $data;
    } elseif ($data == 'update') {
        // 重写写入
        $config = \Phpcmf\Service::C()->weixin['xcx'];
    } else {
        $cache_data = \Phpcmf\Service::L('cache')->get_auth_data('xcx_access_token_'.WEIXIN_MORE_ID, 1, 2200);
        if (is_array($cache_data)) {
            if ($cache_data['endtime'] && $cache_data['endtime'] > SYS_TIME && $cache_data['access_token']) {
                return dr_return_data(1, $cache_data['access_token']);
            } elseif (!\Phpcmf\Service::C()->weixin['xcx']) {
                return dr_return_data(0, '未配置小程序接入参数');
            }
        }
        $config = \Phpcmf\Service::C()->weixin['xcx'];
    }
    if (!$config['appid'] || !$config['appsecret']) {
        return dr_return_data(0, 'appid或者appsecret没填写');
    }

    $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $config['appid'] . '&secret=' . $config['appsecret'] . '';
    $result = wx_get_https_json_data($url);
    if (!$result['code']) {
        return dr_return_data(0, 'AccessToken：'.$result['msg']);
    } elseif (!$result['data']['access_token']) {
        return dr_return_data(0, 'AccessToken为空，请重试');
    }

    $result['data']['endtime'] = SYS_TIME + 2360;
    $rt = \Phpcmf\Service::L('cache')->set_auth_data('xcx_access_token_'.WEIXIN_MORE_ID, $result['data'], 1);
    if (!$rt) {
        return dr_return_data(0, 'AccessToken：/cache/authcode/目录不可写，文件写入失败');
    }

    return dr_return_data(1, $result['data']['access_token']);
}

function ihttp_request($url, $post = '', $extra = array(), $timeout = 60) {
    $urlset = parse_url($url);
    if (empty($urlset['path'])) {
        $urlset['path'] = '/';
    }
    if (!empty($urlset['query'])) {
        $urlset['query'] = "?{$urlset['query']}";
    }
    if (empty($urlset['port'])) {
        $urlset['port'] = $urlset['scheme'] == 'https' ? '443' : '80';
    }
    if (strexists($url, 'https://') && !extension_loaded('openssl')) {
        if (!extension_loaded("openssl")) {
            return dr_return_data(0, ' 请开启您PHP环境的openssl');
        }
    }
    if (function_exists('curl_init') && function_exists('curl_exec')) {
        $ch = curl_init();
        if (!empty($extra['ip'])) {
            $extra['Host'] = $urlset['host'];
            $urlset['host'] = $extra['ip'];
            unset($extra['ip']);
        }
        curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . ($urlset['port'] == '80' ? '' : ':' . $urlset['port']) . $urlset['path'] . $urlset['query']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        //@curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
        if ($post) {
            if (is_array($post)) {
                $filepost = false;
                foreach ($post as $name => &$value) {
                    if (version_compare(phpversion(), '5.6') >= 0 && substr($value, 0, 1) == '@') {
                        $value = new CURLFile(ltrim($value, '@'));
                        if (version_compare(phpversion(), '7.4.3') == 0) {
                            return dr_return_data(0, ' 本功能无法在php7.4.3中运行，请升级到php7.4.3以后的版本');
                        }
                    }
                    if ((is_string($value) && substr($value, 0, 1) == '@') || (class_exists('CURLFile') && $value instanceof CURLFile)) {
                        $filepost = true;
                    }
                }
                if (!$filepost) {
                    $post = http_build_query($post);
                }
            }
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        }
        if (!empty($GLOBALS['_W']['config']['setting']['proxy'])) {
            $urls = parse_url($GLOBALS['_W']['config']['setting']['proxy']['host']);
            if (!empty($urls['host'])) {
                curl_setopt($ch, CURLOPT_PROXY, "{$urls['host']}:{$urls['port']}");
                $proxytype = 'CURLPROXY_' . strtoupper($urls['scheme']);
                if (!empty($urls['scheme']) && defined($proxytype)) {
                    curl_setopt($ch, CURLOPT_PROXYTYPE, constant($proxytype));
                } else {
                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
                    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
                }
                if (!empty($GLOBALS['_W']['config']['setting']['proxy']['auth'])) {
                    curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['_W']['config']['setting']['proxy']['auth']);
                }
            }
        }
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSLVERSION, 1);
        if (defined('CURL_SSLVERSION_TLSv1')) {
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
        }
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
        if (!empty($extra) && is_array($extra)) {
            $headers = array();
            foreach ($extra as $opt => $value) {
                if (strexists($opt, 'CURLOPT_')) {
                    curl_setopt($ch, constant($opt), $value);
                } elseif (is_numeric($opt)) {
                    curl_setopt($ch, $opt, $value);
                } else {
                    $headers[] = "{$opt}: {$value}";
                }
            }
            if (!empty($headers)) {
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            }
        }
        $data = curl_exec($ch);
        $status = curl_getinfo($ch);
        $errno = curl_errno($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if ($errno || empty($data)) {
            return dr_return_data(0, '同步出错：'.$error);
        } else {
            return ihttp_response_parse($data);
        }
    }
    $method = empty($post) ? 'GET' : 'POST';
    $fdata = "{$method} {$urlset['path']}{$urlset['query']} HTTP/1.1\r\n";
    $fdata .= "Host: {$urlset['host']}\r\n";
    if (function_exists('gzdecode')) {
        $fdata .= "Accept-Encoding: gzip, deflate\r\n";
    }
    $fdata .= "Connection: close\r\n";
    if (!empty($extra) && is_array($extra)) {
        foreach ($extra as $opt => $value) {
            if (!strexists($opt, 'CURLOPT_')) {
                $fdata .= "{$opt}: {$value}\r\n";
            }
        }
    }
    $body = '';
    if ($post) {
        if (is_array($post)) {
            $body = http_build_query($post);
        } else {
            $body = urlencode($post);
        }
        $fdata .= 'Content-Length: ' . strlen($body) . "\r\n\r\n{$body}";
    } else {
        $fdata .= "\r\n";
    }
    if ($urlset['scheme'] == 'https') {
        $fp = fsockopen('ssl://' . $urlset['host'], $urlset['port'], $errno, $error);
    } else {
        $fp = fsockopen($urlset['host'], $urlset['port'], $errno, $error);
    }
    stream_set_blocking($fp, true);
    stream_set_timeout($fp, $timeout);
    if (!$fp) {
        return dr_return_data(0, '同步出错：'.$error);
    } else {
        fwrite($fp, $fdata);
        $content = '';
        while (!feof($fp))
            $content .= fgets($fp, 512);
        fclose($fp);
        return ihttp_response_parse($content, true);
    }
}


function ihttp_response_parse($data, $chunked = false) {
    $rlt = array();
    $headermeta = explode('HTTP/', $data);
    if (count($headermeta) > 2) {
        $data = 'HTTP/' . array_pop($headermeta);
    }
    $pos = strpos($data, "\r\n\r\n");
    $split1[0] = substr($data, 0, $pos);
    $split1[1] = substr($data, $pos + 4, strlen($data));

    $split2 = explode("\r\n", $split1[0], 2);
    preg_match('/^(\S+) (\S+) (.*)$/', $split2[0], $matches);
    $rlt['code'] = $matches[2];
    $rlt['status'] = $matches[3];
    $rlt['responseline'] = $split2[0];
    $header = explode("\r\n", $split2[1]);
    $isgzip = false;
    $ischunk = false;
    foreach ($header as $v) {
        $pos = strpos($v, ':');
        $key = substr($v, 0, $pos);
        $value = trim(substr($v, $pos + 1));
        if (is_array($rlt['headers'][$key])) {
            $rlt['headers'][$key][] = $value;
        } elseif (!empty($rlt['headers'][$key])) {
            $temp = $rlt['headers'][$key];
            unset($rlt['headers'][$key]);
            $rlt['headers'][$key][] = $temp;
            $rlt['headers'][$key][] = $value;
        } else {
            $rlt['headers'][$key] = $value;
        }
        if(!$isgzip && strtolower($key) == 'content-encoding' && strtolower($value) == 'gzip') {
            $isgzip = true;
        }
        if(!$ischunk && strtolower($key) == 'transfer-encoding' && strtolower($value) == 'chunked') {
            $ischunk = true;
        }
    }
    if($chunked && $ischunk) {
        $rlt['content'] = ihttp_response_parse_unchunk($split1[1]);
    } else {
        $rlt['content'] = $split1[1];
    }
    if($isgzip && function_exists('gzdecode')) {
        $rlt['content'] = gzdecode($rlt['content']);
    }

    $rlt['meta'] = $data;
    if($rlt['code'] == '100') {
        return ihttp_response_parse($rlt['content']);
    }


    $data = json_decode($rlt['content'], true);
    if (!$data) {
        if($rlt['code'] != '200' && $rlt['status']) {
            return dr_return_data(0, $rlt['status']);
        }
        return dr_return_data(0, $rlt['content'].'不是一个有效的json数据');
    } elseif (isset($data['errcode']) && $data['errcode']) {
        return dr_return_data(0, '错误代码（'.dr_weixin_error_msg($data['errcode']).'）：'.$data['errmsg']);
    }

    return dr_return_data(1, 'ok', $data);
}

function strexists($string, $find) {
    return !(strpos($string, $find) === FALSE);
}




/**
 *
 * 通过code从工作平台获取openid机器access_token
 * @param string $code 微信跳转回来带上的code
 *
 * @return openid
 */
function weixin_GetOpenidFromMp($code)
{
    $url = weixin_CreateOauthUrlForOpenid($code);
    //初始化curl
    $ch = curl_init();
    //设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

    //运行curl，结果以jason形式返回
    $res = curl_exec($ch);
    curl_close($ch);
    //取出openid
    $data = json_decode($res,true);
    $openid = $data['openid'];
    return $openid;
}

/**
 *
 * 构造获取code的url连接
 * @param string $redirectUrl 微信服务器回跳的url，需要url编码
 *
 * @return 返回构造好的url
 */
function weixin_CreateOauthUrlForCode($redirectUrl)
{

    $wx = \Phpcmf\Service::C()->get_cache('weixin'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); // 配置
    $urlObj["appid"] = $wx['account']['appid'];
    $urlObj["redirect_uri"] = "$redirectUrl";
    $urlObj["response_type"] = "code";
    $urlObj["scope"] = "snsapi_base";
    $urlObj["state"] = "STATE"."#wechat_redirect";
    $bizString = weixin_ToUrlParams($urlObj);
    return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
}


/**
 *
 * 构造获取open和access_toke的url地址
 * @param string $code，微信跳转带回的code
 *
 * @return 请求的url
 */
function weixin_CreateOauthUrlForOpenid($code)
{
    $wx = \Phpcmf\Service::C()->get_cache('weixin'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); // 配置
    $urlObj["appid"] = $wx['account']['appid'];
    $urlObj["secret"] = $wx['account']['appsecret'];
    $urlObj["code"] = $code;
    $urlObj["grant_type"] = "authorization_code";
    $bizString = weixin_ToUrlParams($urlObj);
    return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}

/**
 *
 * 拼接签名字符串
 * @param array $urlObj
 *
 * @return 返回已经拼接好的字符串
 */
function weixin_ToUrlParams($urlObj)
{
    $buff = "";
    foreach ($urlObj as $k => $v)
    {
        if($k != "sign"){
            $buff .= $k . "=" . $v . "&";
        }
    }

    $buff = trim($buff, "&");
    return $buff;
}

// 从url获取json数据
function wx_get_https_json_data($url, $ct = 0) {

    if (!$url) {
        return dr_return_data(0, 'url为空');
    }

    $response = dr_catcher_data($url);
    $data = json_decode($response, true);
    if (!$data) {
        return dr_return_data(0, var_export($response, true).' 不是一个有效的json数据');
    } elseif (isset($data['errcode']) && $data['errcode']) {
        if ($data['errcode'] == '40001' && $ct == 0 && strpos($url, 'access_token=')) {
            // 重新获取token
            list($a, $b) = explode('access_token=', $url);
            if (strpos($b, '&') !== false) {
                list($b) = explode('&', $b);
            }
            $rt = weixin_get_access_token('update');
            if ($rt['code']) {
                return wx_get_https_json_data(str_replace($b,  $rt['msg'], $url), 1);
            }
        }
        return dr_return_data(0, '错误代码（'.$data['errcode'].'）：'.$data['errmsg']);
    }

    return dr_return_data(1, 'ok', $data);
}

// 从url获取json数据
function wx_post_https_json_data($url, $param = [], $ct = 0) {
    $rt = dr_post_json_data($url, json_encode($param, JSON_UNESCAPED_UNICODE));
    if ($rt['code']) {
        if (isset($rt['data']['errcode']) && $rt['data']['errcode']) {
            if ($rt['data']['errcode'] == '40001' && $ct == 0 && strpos($url, 'access_token=')) {
                // 重新获取token
                list($a, $b) = explode('access_token=', $url);
                if (strpos($b, '&') !== false) {
                    list($b) = explode('&', $b);
                }
                $rt = weixin_get_access_token('update');
                if ($rt['code']) {
                    return wx_post_https_json_data(str_replace($b,  $rt['msg'], $url), $param, 1);
                }
            }
            return dr_return_data(0, '错误代码（'.dr_weixin_error_msg($rt['data']['errcode']).'）：'.$rt['data']['errmsg']);
        }
    }
    return $rt;
}

// 微信端的错误码转
function dr_weixin_error_msg($code) {
    if ($code == '40001') {
        // 清除掉token
        \Phpcmf\Service::L('cache')->del_auth_data('weixin_access_token_'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : ''), 1);
    }
    return $code;
}
