<?php
/**
* 名称:4399存档接口
* 出处:https://www.yowal.cn/
* 时间:2023年05月26日
*/
class StoreUtils {

    private $raw_data;
    private $current_byte;

    function __construct($rd = "") {
        $this->current_byte = 0;
        $this->raw_data = base64_decode(str_replace(' ','+', $rd));//你post/get传递可能会把+号替换成空格,所以这里直接把空格替换成+号即可
    }

    public function uncompress() {
        $this->current_byte = 0;
        $this->raw_data = zlib_decode($this->raw_data);
    }

    private function read() {
        return ord($this->raw_data[$this->current_byte++]);
    }

    private function readUInt29() {
        $b = $this->read() & 255;
        if ($b < 128) {
            return $b;
        }
        $value = ($b & 127) << 7;
        $b = $this->read() & 255;
        if ($b < 128) {
            return ($value | $b);
        }
        $value = ($value | ($b & 127)) << 7;
        $b = $this->read() & 255;
        if ($b < 128) {
            return ($value | $b);
        }
        $value = ($value | ($b & 127)) << 8;
        $b = $this->read() & 255;
        return ($value | $b);
    }

    private function readUnsignedShort() {
        $c1 = $this->read();
        $c2 = $this->read();
        return (($c1 << 8) + ($c2 << 0));
    }

    private function readUTF($length) {
        $utflen = $length ? $length : $this->readUnsignedShort();
        if ($utflen == 0) {
            return "";
        }
        $val = substr($this->raw_data, $this->current_byte, $utflen);
        $this->current_byte += $utflen;
        return $val;
    } 

    private function readString() {
        $ref = $this->readUInt29();
        if (($ref & 1) == 0) {
            return "";
        }
        $len = ($ref >> 1);
        $str = $this->readUTF($len);
        return $str;
    }

    public function readObject() {
        $type = $this->read();
        if ($type == 6) {
            return $this->readString();
        }
        return "";
    }

    // 下面是写数据 
    public function compress() {
        $this->raw_data = zlib_encode($this->raw_data, ZLIB_ENCODING_DEFLATE, 9);
    }

    private function write($val) {
        $this->raw_data .= pack("c", $val);
    }

    private function writeUInt29($v) {
        if ($v < 128) {
            $this->write($v);
        } else if ($v < 16384) {
            $this->write((($v >> 7) & 127) | 128);
            $this->write($v & 127);
        } else if ($v < 2097152) {
            $this->write((($v >> 14) & 127) | 128);
            $this->write((($v >> 7) & 127) | 128);
            $this->write($v & 127);
        } else if ($v < 0x40000000) {
            $this->write((($v >> 22) & 127) | 128);
            $this->write((($v >> 15) & 127) | 128);
            $this->write((($v >> 8) & 127) | 128);
            $this->write($v & 255);
        }
    }

    private function writeUTF($v) {
        $len = strlen($v);
        $this->writeUInt29(($len << 1) | 1);
        $this->raw_data .= $v;
    }

    public function writeObject($val) {
        $this->write(0x06);
        $this->writeUTF($val);
    }

    public function getBase64() {
        return base64_encode($this->raw_data);
    }
}


class GameUtils {

    private $gameID;
    private $sessionId;
    private $userinfo;

    // 默认是造梦西游3的游戏ID 可以通过抓包抓到
    function __construct($rd = "100015389") {
        $this->gameID = $rd;
    }

    private function formatData($arry) {
        $ret = "";
        foreach ($arry as $key => $value) {
            $ret .= $key."=".urlencode($value)."&";
        }
        return substr($ret, 0, strlen($ret) - 1);
    }

    private function curl_get($url, $post = 0, $cookie = 0, $header = false, $content_type = "application/x-www-form-urlencoded", $split = false) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        $httpheader[] = "Content-Type:".$content_type;
        curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 
        if ($post) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        }
        if ($header) {
            curl_setopt($ch, CURLOPT_HEADER, TRUE);
        }
        if ($cookie) {
            curl_setopt($ch, CURLOPT_COOKIE, $cookie);
        }
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $ret = curl_exec($ch);
        if ($split) {
            $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
            $header = substr($ret, 0, $headerSize);
            $body = substr($ret, $headerSize);
            $ret = array();
            $ret['header'] = $header;
            $ret['body'] = $body;
        }
        curl_close($ch);
        return $ret;
    }

    private function getSubStr($str, $leftStr, $rightStr){
        $left = strpos($str, $leftStr);
        $right = strpos($str, $rightStr, $left);
        if ($left < 0 || $right < $left) return "";
        return substr($str, $left + strlen($leftStr), $right - $left - strlen($leftStr));
    }

    public function checkCaptcha($username) {
        $response = $this->curl_get("https://ptlogin.4399.com/ptlogin/verify.do?username=".urlencode($username)."&appId=www_home&t=".time()."&inputWidth=iptw2");
        if ($response != "0") {
            $this->$sessionId = $this->getSubStr($response,"UniLoginChangPIC('","');");
            return true;
        }
        $this->$sessionId = "";
        return false;
    }

    //返回的是Base64编码
    public function getCaptcha($isOcr = false) {
        $response = $this->curl_get("http://ptlogin.4399.com/ptlogin/captcha.do?captchaId=".$this->$sessionId);
        $ImageBase64 = base64_encode($response);
        if (!$response) return $ImageBase64;
        $post_data = json_encode(array('ImageBase64' => $ImageBase64),JSON_UNESCAPED_SLASHES);
        $response = $this->curl_get("https://ocr.yowal.cn/identify_GeneralCAPTCHA", $post_data, 0, 0,"application/json");
        $json = json_decode($response, true);
        return $json["result"];
    }


    public function login($username, $password, $captcha = "") {
        $post_data = array();
        $post_data["username"] = $username;
        $post_data["password"] = $password;
        $post_data["sec"] = 0;
        $post_data["appId"] = "www_home";
        $post_data["inputCaptcha"] = $captcha;
        $post_data["sessionId"] = $this->$sessionId;
        $response = $this->curl_get("https://ptlogin.4399.com/ptlogin/login.do?v=1", $this->formatData($post_data), 0, true);
        preg_match_all('/Set-Cookie: (.*);/iU', $response, $matchs);
        foreach ($matchs[1] as $val) {
            $cookie.=$val.'; ';
        }
        $this->$userinfo = array();
        if (strpos($cookie, 'Pauth') !== false) {
            $this->$userinfo['result'] = true;
            $this->$userinfo['cookie'] = $cookie;
            $this->$userinfo['user'] = $username;
            $this->$userinfo['uid'] = $this->getSubStr($cookie,"Pauth=","|");
            $this->$userinfo['nick'] = urldecode($this->getSubStr($cookie,"Pnick=",";"));
            return $this->$userinfo;
        }
        $this->$userinfo['result'] = false;
        $this->$userinfo['error'] = $this->getSubStr($response,"errorCallback('","')");
        return $this->$userinfo;
    }

    private function saveKey() {
        $hash = md5(md5($this->gameID."LPislKLodlLKKOSNlSDOAADLKADJAOADALAklsd".$this->gameID));
        return substr($hash, 4, 16);
    }

    private function getVerify($str) {
        return md5(md5(md5("SDALPlsldlnSLWPElsdslSE".$str."PKslsO")));
    }

    //返回解析后的存档列表
    public function get_list($isarry = true) {
        $post_data = array();
        $post_data["uid"] = $this->$userinfo['uid'];
        $post_data["gameid"] = $this->gameID;
        $post_data["token"] = "";
        $post_data["gamekey"] = $this->saveKey();
        $post_data["verify"] = $this->getVerify($post_data["gamekey"].$this->$userinfo['uid'].$this->gameID.$post_data["token"]);
        $response = $this->curl_get("https://save.api.4399.com/?ac=get_list", $this->formatData($post_data), $this->$userinfo['cookie']);
        return json_decode($response, $isarry);
    }

    //返回解析后的存档数据
    public function get_store($index = 0, $isarry = true) {
        $post_data = array();
        $post_data["index"] = $index;
        $post_data["session"] = -1;
        $post_data["uid"] = $this->$userinfo['uid'];
        $post_data["gameid"] = $this->gameID;
        $post_data["token"] = "";
        $post_data["gamekey"] = $this->saveKey();
        $post_data["verify"] = $this->getVerify($index.$post_data["gamekey"].$this->$userinfo['uid'].$this->gameID.$post_data["token"]);
        $response = $this->curl_get("https://save.api.4399.com/?ac=get", $this->formatData($post_data), $this->$userinfo['cookie']);
        return json_decode($response, $isarry);
    }

    //返回 1 为保存成功
    public function save_store($index = 0, $title, $store) {
        $post_data = array();
        $post_data["session"] = -1;
        $post_data["index"] = $index;
        $post_data["uid"] = $this->$userinfo['uid'];
        $post_data["gameid"] = $this->gameID;
        $post_data["title"] = $title;
        $post_data["data"] = $store;
        $post_data["token"] = "";
        $post_data["gamekey"] = $this->saveKey();
        $post_data["verify"] = $this->getVerify($index.$post_data["gamekey"].$store.$title.$this->$userinfo['uid'].$this->gameID.$post_data["token"]);
        $response = $this->curl_get("https://save.api.4399.com/?ac=save", $this->formatData($post_data), $this->$userinfo['cookie']);
        return $response;
    }
}

$username = "填写账号";
$password = "填写密码";

$game = new GameUtils();
if ($game->checkCaptcha($username)) {
    $captcha = $game->getCaptcha(true);//这个识别不准,建议自己写前端,让用户自己填
    echo "识别出验证码:".$captcha. "\n";
}

$userinfo = $game->login($username,$password, $captcha);
if ($userinfo['result'] == false) {
    die("登录失败:".$userinfo['error']);
}
echo "昵称:".$userinfo['nick']." | UID:".$userinfo['uid']. "\n";

$json_list = $game->get_list();
foreach ($json_list as $obj) {
    echo "index:".$obj['index'] ." | ";
    echo "title:".$obj['title'] ." | ";
    echo "datetime:".$obj['datetime'] ." | ";
    echo "status:".$obj['status'] ."\n";
}

//下面读取存档
$json_store = $game->get_store(2);
$reader = new StoreUtils($json_store['data']);
$reader->uncompress();
$decocedData = $reader->readObject();
echo $decocedData;

//修改代码后就可以这样取需要保存的数据
//$writer = new StoreUtils();
//$writer->writeObject($decocedData);
//$writer->compress();

//echo $game->save_store(3,"极品猴子",$writer->getBase64());
//echo $writer->getBase64() == $json_store['data'] ? "数据相同" : "数据不同";//这里编码数据后看看是否和原始的相同
?>

这是一份用php写的 4399 swf小游戏存档接口的源码,功能齐全,可登录,可获取存档数据,保存存档,本源码仅供学习和交流,请勿用于非法用途

最后修改:2023 年 05 月 29 日
如果觉得我的文章对你有用,请随意赞赏