<?php
/**
 * QQ登录服务类
 * 提供QQ扫码登录功能
 */
class QzoneLoginService {
    private $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36';
    private $proxy = null;

    /**
     * 构造函数
     * @param array $proxy 代理配置 ['type' => 'socks5', 'host' => '', 'port' => 0, 'user' => '', 'pass' => '']
     */
    public function __construct($proxy = null) {
        $this->proxy = $proxy;
    }

    /**
     * 设置代理
     * @param array $proxy 代理配置
     */
    public function setProxy($proxy) {
        $this->proxy = $proxy;
    }

    /**
     * 执行curl请求（支持代理）
     */
    private function curlRequest($url, $options = []) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_TIMEOUT, $options['timeout'] ?? 10);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $options['connect_timeout'] ?? 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, $options['useragent'] ?? $this->ua);

        // 应用代理设置
        if (!empty($this->proxy) && isset($this->proxy['type']) && $this->proxy['type'] === 'socks5') {
            $proxyUrl = $this->proxy['host'] . ':' . $this->proxy['port'];
            if (!empty($this->proxy['user']) && !empty($this->proxy['pass'])) {
                $proxyUrl = $this->proxy['user'] . ':' . $this->proxy['pass'] . '@' . $this->proxy['host'] . ':' . $this->proxy['port'];
            }
            curl_setopt($ch, CURLOPT_PROXY, $proxyUrl);
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
        }

        if (!empty($options['referer'])) {
            curl_setopt($ch, CURLOPT_REFERER, $options['referer']);
        }
        if (!empty($options['cookie'])) {
            curl_setopt($ch, CURLOPT_COOKIE, $options['cookie']);
        }
        if (!empty($options['post'])) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $options['post']);
        }

        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }

    /**
     * 获取二维码图片
     */
    public function getqrpic() {
        $url = 'https://ssl.ptlogin2.qq.com/ptqrshow?appid=549000912&e=2&l=M&s=4&d=72&v=4&t=0.5409099' . time() . '&daid=5&pt_3rd_aid=0&u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone';
        $referer = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_no_auth=0';

        $response = $this->curlRequest($url, [
            'referer' => $referer,
            'timeout' => 10,
            'connect_timeout' => 5
        ]);

        if ($response) {
            // 正确拆分 HTTP 头与 body（第一个 \r\n\r\n 为界）
            $parts = explode("\r\n\r\n", $response, 2);
            $header = $parts[0] ?? '';
            $body = isset($parts[1]) ? $parts[1] : '';

            // 从响应头中提取qrsig
            preg_match('/qrsig=([^;]+);/', $header, $match);
            $qrsig = $match[1] ?? '';

            $image = base64_encode($body);
            return ['saveOK' => 0, 'qrsig' => $qrsig, 'image' => $image];
        }
        return ['saveOK' => -1, 'msg' => '获取二维码失败'];
    }

    /**
     * 扫码登录检测
     */
    public function qrlogin($qrsig) {
        if (empty($qrsig)) {
            return ['saveOK' => -1, 'msg' => 'qrsig不能为空'];
        }

        $url = 'https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptqrtoken=' . $this->getqrtoken($qrsig) . '&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-' . time() . '000&js_ver=23042119&js_type=1&login_sig=' . $qrsig . '&pt_uistyle=40&aid=549000912&daid=5&';
        $cookie = 'qrsig=' . $qrsig . '; ';

        $ret = $this->curlRequest($url, [
            'referer' => 'https://xui.ptlogin2.qq.com/',
            'cookie' => $cookie,
            'timeout' => 10,
            'connect_timeout' => 5
        ]);

        if (preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)) {
            $r = explode("','", str_replace("', '", "','", $arr[1]));
            if ($r[0] == 0) {
                // 登录成功
                preg_match('/uin=(\d+)&/', $ret, $uin);
                $uin = $uin[1] ?? '';
                preg_match('/skey=@(.{9});/', $ret, $skey);
                preg_match('/superkey=(.*?);/', $ret, $superkey);

                // 访问跳转URL获取pskey
                $data = $this->curlRequest($r[2], [
                    'timeout' => 10,
                    'connect_timeout' => 5
                ]);

                if ($data) {
                    preg_match("/p_skey=([^;]+);/", $data, $matchs);
                    $pskey = $matchs[1] ?? '';
                }

                if (!empty($skey[1]) && !empty($pskey) && !empty($uin)) {
                    return [
                        'saveOK' => 0,
                        'uin' => $uin,
                        'skey' => '@' . $skey[1],
                        'pskey' => $pskey,
                        'superkey' => $superkey[1] ?? '',
                        'nickname' => $r[5] ?? ''
                    ];
                } else {
                    return ['saveOK' => 6, 'msg' => '登录成功，获取相关信息失败！' . $r[2]];
                }
            } elseif ($r[0] == 65) {
                return ['saveOK' => 1, 'msg' => '二维码已失效。'];
            } elseif ($r[0] == 66) {
                return ['saveOK' => 2, 'msg' => '二维码未失效,请使用手机QQ扫码！'];
            } elseif ($r[0] == 67) {
                return ['saveOK' => 3, 'msg' => '正在验证二维码。'];
            } elseif ($r[0] == 10009) {
                return ['saveOK' => 6, 'msg' => '需要手机验证码才能登录，此次登录失败'];
            } else {
                return ['saveOK' => 6, 'msg' => $r[4] ?? '未知错误'];
            }
        }
        return ['saveOK' => 6, 'msg' => '网络错误'];
    }

    /**
     * 计算qrtoken
     */
    private function getqrtoken($qrsig) {
        $len = strlen($qrsig);
        $hash = 0;
        for ($i = 0; $i < $len; $i++) {
            $hash += (($hash << 5) & 2147483647) + ord($qrsig[$i]) & 2147483647;
            $hash &= 2147483647;
        }
        return $hash & 2147483647;
    }
}
