├── README.md ├── admin ├── add.php ├── ajax.php ├── apidoc.md ├── assets │ └── js │ │ ├── encoder.js │ │ ├── login_pwd.js │ │ ├── login_qq.js │ │ ├── login_scan.js │ │ └── login_sms.js ├── download.php ├── head.php ├── imghost.php ├── index.php ├── list.php ├── log.php ├── login.php └── set.php ├── api.php ├── config.php ├── cron.php ├── includes ├── autoloader.php ├── common.php ├── functions.php └── lib │ ├── Logic.php │ ├── PdoHelper.php │ ├── WeiboLogin.php │ ├── WeiboTool.php │ └── mail │ ├── Aliyun.php │ ├── PHPMailer │ ├── Exception.php │ ├── PHPMailer.php │ └── SMTP.php │ └── Sendcloud.php ├── index.php └── install ├── index.php └── install.sql /README.md: -------------------------------------------------------------------------------- 1 | # 微博API系统 2 | 3 | 微博API是一款php开发的微博相关API接口管理系统。本程序可在后台添加微博账号,通过计划任务实现COOKIE保活,并提供热搜列表、视频解析等API接口调用。 4 | 5 | ### 功能特色 6 | 7 | - 添加账号支持密码登录、扫码登录、验证码登录与QQ快捷登录 8 | - 支持检测并自动刷新COOKIE状态(预估可以保活1个月) 9 | - 自带微博热搜列表、视频解析、用户信息等API接口 10 | - 后台有微博图床功能 11 | - 支持失效邮件提醒 12 | 13 | ### 使用方法 14 | 15 | - 部署环境要求`PHP` >= 7.1、`MySQL` >= 5.5 16 | - 上传后直接访问,按照提示安装,后台默认账号密码:admin/123456 17 | - 添加账号 18 | - 添加COOKIE检测定时任务 19 | 20 | - [接口文档](./admin/apidoc.md) 21 | 22 | -------------------------------------------------------------------------------- /admin/add.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 6 | 7 | $mod=isset($_GET['mod'])?$_GET['mod']:'pwd'; 8 | $id=isset($_GET['id'])?$_GET['id']:null; 9 | if($id){ 10 | $loginname=$DB->findColumn('account','loginname',['id'=>$id]); 11 | } 12 | ?> 13 |
14 |
15 | 16 |
17 |

18 | 添加/更新微博账号 19 |

20 |
21 |
22 | 25 |
26 | 27 | 29 |
30 |
31 |
帐号
32 | 33 |
34 |
35 |
密码
36 | 37 |
38 | 39 |
40 | 48 | 49 |
50 | 正在加载. 51 |
52 | 57 | 58 | 60 |
61 |
62 |
手机号
63 | 64 |
65 | 71 | 72 |
73 | 74 |
75 | 使用QQ手机版扫描二维码. 76 |
77 |
78 |
79 |
80 | 81 | 82 |
返回账号列表 83 |
84 |
85 |
86 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /admin/ajax.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 4 | $act=isset($_GET['act'])?daddslashes($_GET['act']):null; 5 | 6 | if(!checkRefererHost())exit('{"code":403}'); 7 | 8 | @header('Content-Type: application/json; charset=UTF-8'); 9 | 10 | switch($act){ 11 | case 'set': 12 | if(isset($_POST['opentype'])){ 13 | $_POST['opentype'] = implode(',',$_POST['opentype']); 14 | } 15 | foreach($_POST as $k=>$v){ 16 | saveSetting($k, $v); 17 | } 18 | exit('{"code":0,"msg":"succ"}'); 19 | break; 20 | 21 | case 'checkAccount': 22 | $id = intval($_POST['id']); 23 | try{ 24 | $result = \lib\Logic::checkAccount($id); 25 | }catch(Exception $e){ 26 | exit(json_encode(['code'=>-1, 'msg'=>$e->getMessage()])); 27 | } 28 | if($result == 2){ 29 | exit(json_encode(['code'=>0, 'msg'=>'账号COOKIE更新成功!'])); 30 | }elseif($result == 1){ 31 | exit(json_encode(['code'=>0, 'msg'=>'账号状态检测正常!'])); 32 | }else{ 33 | exit(json_encode(['code'=>-1, 'msg'=>'账号状态已失效,请点击更新按钮进行登录'])); 34 | } 35 | break; 36 | 37 | case 'deleteAccount': 38 | $id = intval($_POST['id']); 39 | $row = $DB->find('account', '*', ['id'=>$id]); 40 | if(!$row)exit('{"code":-1,"msg":"账号不存在"}'); 41 | $DB->delete('account', ['id'=>$id]); 42 | $DB->delete('log', ['aid'=>$id]); 43 | exit(json_encode(['code'=>0])); 44 | break; 45 | 46 | case 'weiboLogin': 47 | $login=new \lib\WeiboLogin(); 48 | if($_GET['do']=='getqrcode'){ 49 | $array=$login->getqrcode(); 50 | } 51 | if($_GET['do']=='qrlogin'){ 52 | $array=$login->qrlogin($_POST['qrid']); 53 | if($array['code'] == 0){ 54 | \lib\Logic::addAccount($array); 55 | } 56 | } 57 | if($_GET['do']=='getconfig'){ 58 | $array=$login->getconfig(); 59 | } 60 | if($_GET['do']=='login'){ 61 | $array=$login->login($_POST['user'],$_POST['pwd'],$_POST['rsakv'],$_POST['cid'],$_POST['csrf_token']); 62 | if($array['code'] == 0){ 63 | \lib\Logic::addAccount($array); 64 | } 65 | } 66 | if($_GET['do']=='verifycaptcha'){ 67 | $array=$login->verifycaptcha($_POST['key'], $_POST['lot_number'], $_POST['captcha_output'], $_POST['pass_token'], $_POST['gen_time']); 68 | } 69 | if($_GET['do']=='sendcode'){ 70 | $array=$login->sendcode($_POST['type'],$_POST['token'],$_POST['encrypt_mobile']); 71 | } 72 | if($_GET['do']=='confirmcode'){ 73 | $array=$login->confirmcode($_POST['type'],$_POST['token'],$_POST['encrypt_mobile'],$_POST['code']); 74 | } 75 | if($_GET['do']=='sendsms'){ 76 | $array=$login->sendsms($_POST['mobile'],$_POST['cid'],$_POST['csrf_token']); 77 | } 78 | if($_GET['do']=='smslogin'){ 79 | $array=$login->smslogin($_POST['user'],$_POST['code'],$_POST['csrf_token']); 80 | if($array['code'] == 0){ 81 | \lib\Logic::addAccount($array); 82 | } 83 | } 84 | if($_GET['do']=='qq_getqrcode'){ 85 | $array=$login->qq_getqrcode(); 86 | } 87 | if($_GET['do']=='qq_qrlogin'){ 88 | $array=$login->qq_qrlogin($_GET['qrsig']); 89 | } 90 | if($_GET['do']=='qq_connect'){ 91 | $array=$login->qq_connect($_POST['redirect_uri'],$_POST['crossidccode']); 92 | if($array['code'] == 0){ 93 | \lib\Logic::addAccount($array); 94 | } 95 | } 96 | echo json_encode($array); 97 | break; 98 | 99 | case 'upload': 100 | if(!isset($_FILES['file']))exit('{"code":-1,"msg":"请选择文件"}'); 101 | $file = $_FILES["file"]["tmp_name"]; 102 | if($_FILES['file']['error']>0 || $file == ""){ 103 | exit('{"code":-1,"msg":"文件损坏!"}'); 104 | } 105 | if($_FILES['file']['size']>10*1024*1024){ 106 | exit('{"code":-1,"msg":"文件最大10M"}'); 107 | } 108 | $result = weibotool_call('upload', [$file]); 109 | echo json_encode($result); 110 | break; 111 | 112 | default: 113 | exit('{"code":-4,"msg":"No Act"}'); 114 | break; 115 | } -------------------------------------------------------------------------------- /admin/apidoc.md: -------------------------------------------------------------------------------- 1 | # 微博API接口文档 2 | 3 | - [微博API接口文档](#微博api接口文档) 4 | - [获取微博COOKIE](#获取微博COOKIE) 5 | - [获取微博热搜列表](#获取微博热搜列表) 6 | - [解析微博视频](#解析微博视频) 7 | - [获取微博用户信息](#获取微博用户信息) 8 | 9 | 10 | ## 获取微博COOKIE 11 | 12 | 请求URL: 13 | 14 | > /api.php?act=getcookie 15 | 16 | 请求方式:POST 17 | 18 | 请求参数: 19 | 20 | | 参数名 | 必填 | 类型 | 描述 | 21 | | ------ | ---- | ------ | -------------------- | 22 | | key | 是 | string | 获取COOKIE密钥 | 23 | | uid | 否 | string | 用户ID(留空为随机) | 24 | 25 | 返回示例: 26 | 27 | ``` 28 | { 29 | "code":0, 30 | "uid":"123456", 31 | "nickname":"名称", 32 | "cookie":"SUB=..." 33 | } 34 | ``` 35 | 36 | 异常返回示例: 37 | 38 | ``` 39 | { 40 | "code":-1, 41 | "msg":"微博账号状态不正常" 42 | } 43 | ``` 44 | 45 | 返回参数说明: 46 | 47 | | 参数名 | 类型 | 描述 | 48 | | -------- | ------ | -------------------- | 49 | | code | int | 0 是成功,其他是失败 | 50 | | msg | string | 失败原因 | 51 | | uid | string | 用户ID | 52 | | nickname | string | 用户昵称 | 53 | | cookie | string | COOKIE内容 | 54 | 55 | ## 获取微博热搜列表 56 | 57 | 请求URL: 58 | 59 | > /api.php?act=gethotsearch 60 | 61 | 请求方式:POST 62 | 63 | 请求参数: 64 | 65 | | 参数名 | 必填 | 类型 | 描述 | 66 | | ------ | ---- | ------ | ----------- | 67 | | key | 是 | string | API接口密钥 | 68 | 69 | 返回示例: 70 | 71 | ``` 72 | { 73 | "code": 0, 74 | "data": [ 75 | { 76 | "rank": 1, 77 | "category": "动漫,作品衍生", 78 | "content": "天官赐福第二季开播", 79 | "time": 1697631213, 80 | "num": 1052196, 81 | "label": "新", 82 | "mid": "" 83 | }, 84 | { 85 | "rank": 2, 86 | "category": "电影", 87 | "content": "突然明白你好李焕英名字起的有多好", 88 | "time": 1697622338, 89 | "num": 1006787, 90 | "label": "热", 91 | "mid": "4957758824908712" 92 | }, 93 | ...... 94 | ] 95 | } 96 | ``` 97 | 98 | 返回参数说明: 99 | 100 | | 参数名 | 类型 | 描述 | 101 | | --------------- | ------ | -------------------- | 102 | | code | int | 0 是成功,其他是失败 | 103 | | msg | string | 失败原因 | 104 | | data | array | 热搜列表 | 105 | | data[].rank | int | 热搜排名 | 106 | | data[].category | string | 热搜分类 | 107 | | data[].content | string | 热搜内容 | 108 | | data[].time | int | 创建时间 | 109 | | data[].num | int | 话题数量 | 110 | | data[].label | string | 标签文字 | 111 | | data[].mid | string | 唯一ID | 112 | 113 | ## 解析微博视频 114 | 115 | 请求URL: 116 | 117 | > /api.php?act=parsevideo 118 | 119 | 请求方式:POST 120 | 121 | 请求参数: 122 | 123 | | 参数名 | 必填 | 类型 | 描述 | 124 | | ------ | ---- | ------ | ----------- | 125 | | key | 是 | string | API接口密钥 | 126 | | oid | 是 | string | 视频ID | 127 | 128 | 返回示例: 129 | 130 | ``` 131 | { 132 | "code": 0, 133 | "data": { 134 | "title": "中国空间站办起了国际画展", 135 | "author": "央视新闻", 136 | "author_id": 2656274875, 137 | "author_avatar": "//tvax3.sinaimg.cn/...", 138 | "urls": { 139 | "高清 1080P": "//f.video.weibocdn.com/...", 140 | "高清 720P": "//f.video.weibocdn.com/...", 141 | "标清 480P": "//f.video.weibocdn.com/...", 142 | "流畅 360P": "//f.video.weibocdn.com/..." 143 | }, 144 | "cover": "//wx4.sinaimg.cn/...", 145 | "time": 1697550667, 146 | "duration": "6:43" 147 | } 148 | } 149 | ``` 150 | 151 | 返回参数说明: 152 | 153 | | 参数名 | 类型 | 描述 | 154 | | ------------------ | ------ | -------------------- | 155 | | code | int | 0 是成功,其他是失败 | 156 | | msg | string | 失败原因 | 157 | | data.title | string | 视频标题 | 158 | | data.author | string | 视频作者 | 159 | | data.author_id | int | 视频作者ID | 160 | | data.author_avatar | string | 视频作者头像 | 161 | | data.urls | array | 视频播放链接 | 162 | | data.cover | string | 视频封面 | 163 | | data.time | int | 发表时间 | 164 | | data.duration | string | 视频长度 | 165 | 166 | ## 获取微博用户信息 167 | 168 | 请求URL: 169 | 170 | > /api.php?act=getuserinfo 171 | 172 | 请求方式:POST 173 | 174 | 请求参数: 175 | 176 | | 参数名 | 必填 | 类型 | 描述 | 177 | | ------ | ---- | ------ | ----------- | 178 | | key | 是 | string | API接口密钥 | 179 | | uid | 是 | string | 用户ID | 180 | 181 | 返回示例: 182 | 183 | ``` 184 | { 185 | "code": 0, 186 | "data": { 187 | "uid": "2656274875", 188 | "name": "央视新闻", 189 | "avatar": "//tvax3.sinaimg.cn/...", 190 | "gender": "m", 191 | "location": "北京", 192 | "description": "“央视新闻”是中央广播电视总台...", 193 | "domain": "cctvxinwen", 194 | "friends_count": 2743, 195 | "followers_count": 131851188, 196 | "statuses_count": 170371, 197 | "verified": true, 198 | "verified_reason": "中央广播电视总台央视新闻官方账号", 199 | "verified_type": 3, 200 | "is_muteuser": false 201 | } 202 | } 203 | ``` 204 | 205 | 返回参数说明: 206 | 207 | | 参数名 | 类型 | 描述 | 208 | | -------------------- | ------ | -------------------- | 209 | | code | int | 0 是成功,其他是失败 | 210 | | msg | string | 失败原因 | 211 | | data.uid | string | 用户ID | 212 | | data.name | string | 昵称 | 213 | | data.avatar | string | 头像 | 214 | | data.gender | string | 性别 | 215 | | data.location | string | 地址 | 216 | | data.description | string | 描述 | 217 | | data.domain | string | 自定义域名 | 218 | | data.friends_count | int | 关注数量 | 219 | | data.followers_count | int | 粉丝数量 | 220 | | data.statuses_count | int | 微博数量 | 221 | | data.verified | bool | 是否已认证 | 222 | | data.verified_reason | string | 认证身份 | 223 | | data.verified_type | int | 认证类型 | 224 | | data.is_muteuser | bool | 是否被禁言 | 225 | 226 | -------------------------------------------------------------------------------- /admin/assets/js/login_pwd.js: -------------------------------------------------------------------------------- 1 | var comm_data = { 2 | servertime:'', 3 | nonce:'', 4 | rsakv:'', 5 | pubkey:'', 6 | cid:'', 7 | csrf_token:'', 8 | } 9 | var ajax={ 10 | get: function(url, dataType, callback) { 11 | dataType = dataType || 'html'; 12 | $.ajax({ 13 | type: "GET", 14 | url: url, 15 | async: true, 16 | dataType: dataType, 17 | cache:false, 18 | success: function(data,status) { 19 | if (callback == null) { 20 | return; 21 | } 22 | callback(data); 23 | }, 24 | error: function(error) { 25 | alert('创建连接失败'); 26 | } 27 | }); 28 | }, 29 | post: function(url, parameter, dataType, callback) { 30 | dataType = dataType || 'html'; 31 | $.ajax({ 32 | type: "POST", 33 | url: url, 34 | async: true, 35 | dataType: dataType, 36 | data: parameter, 37 | cache:false, 38 | success: function(data,status) { 39 | if (callback == null) { 40 | return; 41 | } 42 | callback(data); 43 | }, 44 | error: function(error) { 45 | alert('创建连接失败'); 46 | } 47 | }); 48 | } 49 | } 50 | function invokeSettime(obj){ 51 | var countdown=60; 52 | settime(obj); 53 | function settime(obj) { 54 | if (countdown == 0) { 55 | $(obj).attr("data-lock", "false"); 56 | $(obj).attr("disabled",false); 57 | $(obj).text("获取验证码"); 58 | countdown = 60; 59 | return; 60 | } else { 61 | $(obj).attr("data-lock", "true"); 62 | $(obj).attr("disabled",true); 63 | $(obj).text(countdown + "秒后重试"); 64 | countdown--; 65 | } 66 | setTimeout(function() { settime(obj) } ,1000) 67 | } 68 | } 69 | function trim(str){ //去掉头尾空格 70 | return str.replace(/(^\s*)|(\s*$)/g, ""); 71 | } 72 | function encryptpwd(pwd){ 73 | return SinaEncrypt("".concat([comm_data.servertime,comm_data.nonce].join("\t"), "\n").concat(pwd), comm_data.pubkey); 74 | } 75 | function getconfig(){ 76 | var ii = layer.load(2, {shade: [0.1,'#fff']}); 77 | var getvcurl="ajax.php?act=weiboLogin&do=getconfig"; 78 | ajax.get(getvcurl, 'json', function(d) { 79 | layer.close(ii); 80 | if(d.code ==0){ 81 | var data = d.data; 82 | comm_data.servertime = data.servertime; 83 | comm_data.nonce = data.nonce; 84 | comm_data.rsakv = data.rsakv; 85 | comm_data.pubkey = data.pubkey; 86 | comm_data.csrf_token = d.csrf_token; 87 | }else{ 88 | layer.alert(d.msg, {icon: 2}); 89 | } 90 | }); 91 | } 92 | function login(user,pwd){ 93 | var ii = layer.msg('正在登录,请稍候...', {icon: 16,shade: 0.5,time: 15000}); 94 | var encpwd = encryptpwd(pwd); 95 | var loginurl="ajax.php?act=weiboLogin&do=login&r="+Math.random(1); 96 | ajax.post(loginurl, {user:user, pwd:encpwd, rsakv:comm_data.rsakv, cid:comm_data.cid, csrf_token:comm_data.csrf_token}, 'json', function(d) { 97 | layer.close(ii); 98 | if(d.code ==0){ 99 | $('#login').hide(); 100 | $('#submit').hide(); 101 | $('#security').hide(); 102 | $('#submit2').hide(); 103 | showresult(d); 104 | }else if(d.code ==1){ 105 | comm_data.cid = ''; 106 | $('#load').html("您已开启登录保护,请验证手机后登录:"+d.mobile); 107 | $('#load').show(); 108 | $('#submit').hide(); 109 | $('#code').val(""); 110 | $('#security').show(); 111 | $('#security').attr('type',d.type); 112 | $('#security').attr('token',d.token); 113 | $('#security').attr('encrypt_mobile',d.encrypt_mobile); 114 | }else if(d.code ==2){ 115 | comm_data.cid = d.cid; 116 | initGeetest4({ 117 | captchaId: '8b4a2bef633eb0264367b3ba9fa1dd3d', 118 | product: 'bind', 119 | hideSuccess: true 120 | },function (captcha) { 121 | captcha.onReady(function(){ 122 | captcha.showCaptcha(); 123 | }).onSuccess(function(){ 124 | var result = captcha.getValidate(); 125 | if (!result) { 126 | layer.closeAll(); 127 | return alert('请先完成验证'); 128 | } 129 | var verifyurl="ajax.php?act=weiboLogin&do=verifycaptcha&r="+Math.random(1); 130 | ajax.post(verifyurl, {key:comm_data.cid, lot_number:result.lot_number, captcha_output:result.captcha_output, pass_token:result.pass_token, gen_time:result.gen_time}, 'json', function(d) { 131 | if(d.code ==0){ 132 | login(user,pwd) 133 | }else{ 134 | layer.alert(d.msg, {icon: 2}); 135 | } 136 | }); 137 | }).onError(function(){ 138 | alert('验证码加载失败,请刷新页面重试'); 139 | }) 140 | }); 141 | }else{ 142 | comm_data.cid = ''; 143 | $('#load').html(d.msg); 144 | $('#load').show(); 145 | $('#submit').attr('do','submit'); 146 | $('#login').show(); 147 | } 148 | }); 149 | } 150 | function sendcode(type,token,encrypt_mobile){ 151 | var ii = layer.load(2, {shade: [0.1,'#fff']}); 152 | var loginurl="ajax.php?act=weiboLogin&do=sendcode&r="+Math.random(1); 153 | ajax.post(loginurl, {type:type, token:token, encrypt_mobile:encrypt_mobile}, 'json', function(d) { 154 | layer.close(ii); 155 | if(d.code ==0){ 156 | $('#smscode').focus(); 157 | invokeSettime("#sendcode"); 158 | layer.alert('验证码发送成功,请查收', {icon: 1}, function(){ layer.closeAll();$('#smscode').focus() }); 159 | }else{ 160 | layer.alert(d.msg, {icon: 2}); 161 | } 162 | }); 163 | } 164 | function confirmcode(type,token,encrypt_mobile,code){ 165 | var ii = layer.msg('正在验证,请稍等...', {icon: 16,shade: 0.5,time: 15000}); 166 | var loginurl="ajax.php?act=weiboLogin&do=confirmcode&r="+Math.random(1); 167 | ajax.post(loginurl, {type:type, token:token, encrypt_mobile:encrypt_mobile, code:code}, 'json', function(d) { 168 | layer.close(ii); 169 | if(d.code ==0){ 170 | $('#login').hide(); 171 | $('#submit').hide(); 172 | $('#security').hide(); 173 | $('#submit2').hide(); 174 | showresult(d); 175 | }else{ 176 | layer.alert(d.msg, {icon: 2}); 177 | $('#login').show(); 178 | } 179 | }); 180 | } 181 | function showresult(arr){ 182 | $('#load').html(' 微博账号添加成功!
'+decodeURIComponent(arr.nick)+'(UID:'+arr.uid+')'); 183 | $('#load').show(); 184 | } 185 | $(document).ready(function(){ 186 | $('#submit').click(function(){ 187 | var self=$(this); 188 | var user=trim($('#user').val()), 189 | pwd=trim($('#pwd').val()); 190 | if(user==''||pwd=='') { 191 | alert("请确保每项不能为空!"); 192 | return false; 193 | } 194 | if (self.attr("data-lock") === "true") return; 195 | else self.attr("data-lock", "true"); 196 | login(user,pwd); 197 | self.attr("data-lock", "false"); 198 | }); 199 | $('#submit2').click(function(){ 200 | var self=$(this); 201 | var code=trim($('#smscode').val()); 202 | if(code=='') { 203 | alert("验证码不能为空!"); 204 | return false; 205 | } 206 | if (self.attr("data-lock") === "true") return; 207 | else self.attr("data-lock", "true"); 208 | var type=$('#security').attr('type'), 209 | token=$('#security').attr('token'), 210 | encrypt_mobile=$('#security').attr('encrypt_mobile'); 211 | confirmcode(type,token,encrypt_mobile,code); 212 | self.attr("data-lock", "false"); 213 | }); 214 | $('#sendcode').click(function(){ 215 | var self=$(this); 216 | if (self.attr("data-lock") === "true") return; 217 | else self.attr("data-lock", "true"); 218 | var type=$('#security').attr('type'), 219 | token=$('#security').attr('token'), 220 | encrypt_mobile=$('#security').attr('encrypt_mobile'); 221 | sendcode(type,token,encrypt_mobile); 222 | self.attr("data-lock", "false"); 223 | }); 224 | getconfig(); 225 | }); -------------------------------------------------------------------------------- /admin/assets/js/login_qq.js: -------------------------------------------------------------------------------- 1 | var interval1,interval2; 2 | function showresult(arr){ 3 | $('#login').html(' 微博账号添加成功!
'+decodeURIComponent(arr.nick)+'(UID:'+arr.uid+')'); 4 | } 5 | function getqrpic(){ 6 | cleartime(); 7 | var getvcurl='ajax.php?act=weiboLogin&do=qq_getqrcode&r='+Math.random(1); 8 | $.get(getvcurl, function(d) { 9 | if(d.code ==0){ 10 | $('#qrimg').attr('qrsig',d.qrsig); 11 | $('#qrimg').attr('qrcode',d.qrcode); 12 | $('#qrcode').empty() 13 | $('#qrcode').qrcode({ 14 | text: d.qrcode, 15 | width: 150, 16 | height: 150, 17 | foreground: "#000000", 18 | background: "#ffffff", 19 | typeNumber: -1 20 | }); 21 | if( /Android|SymbianOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|Midp/i.test(navigator.userAgent)) { 22 | $('#mobile').show(); 23 | } 24 | interval1=setInterval(loginload,1000); 25 | interval2=setInterval(qrlogin,3000); 26 | }else{ 27 | alert(d.msg); 28 | } 29 | }, 'json'); 30 | } 31 | function qrlogin(){ 32 | if ($('#login').attr("data-lock") === "true") return; 33 | var qrsig=$('#qrimg').attr('qrsig'); 34 | var url = 'ajax.php?act=weiboLogin&do=qq_qrlogin&qrsig='+decodeURIComponent(qrsig)+'&r='+Math.random(1); 35 | $.get(url, function(d) { 36 | if(d.code ==0){ 37 | $('#login').attr("data-lock", "true"); 38 | $('#loginmsg').html('正在登录微博,请稍候...'); 39 | cleartime(); 40 | qqconnect(d.redirect_uri, d.crossidccode); 41 | }else if(d.code ==1){ 42 | getqrpic(); 43 | $('#loginmsg').html('请重新扫描二维码'); 44 | }else if(d.code ==2){ 45 | $('#loginmsg').html('使用QQ手机版扫描二维码'); 46 | }else if(d.code ==3){ 47 | $('#loginmsg').html('扫描成功,请在手机上确认授权登录'); 48 | }else{ 49 | cleartime(); 50 | $('#loginmsg').html(d.msg); 51 | } 52 | }, 'json'); 53 | } 54 | function qqconnect(redirect_uri, crossidccode){ 55 | $.ajax({ 56 | type : "POST", 57 | url : "ajax.php?act=weiboLogin&do=qq_connect", 58 | data : {redirect_uri:redirect_uri, crossidccode:crossidccode}, 59 | dataType : 'json', 60 | success : function(data) { 61 | if(data.code == 0){ 62 | showresult(data); 63 | $('#qrimg').hide(); 64 | $('#mobile').hide(); 65 | }else{ 66 | $('#loginmsg').html(data.msg); 67 | } 68 | } 69 | }); 70 | } 71 | function loginload(){ 72 | if ($('#login').attr("data-lock") === "true") return; 73 | var load=document.getElementById('loginload').innerHTML; 74 | var len=load.length; 75 | if(len>2){ 76 | load='.'; 77 | }else{ 78 | load+='.'; 79 | } 80 | document.getElementById('loginload').innerHTML=load; 81 | } 82 | function cleartime(){ 83 | clearInterval(interval1); 84 | clearInterval(interval2); 85 | } 86 | function mloginurl(){ 87 | var qrurl = $('#qrimg').attr('qrcode'); 88 | $('#loginmsg').html('跳转到QQ登录后请返回此页面'); 89 | var ua = window.navigator.userAgent.toLowerCase(); 90 | var is_ios = ua.indexOf('iphone')>-1 || ua.indexOf('ipad')>-1; 91 | var schemacallback = ''; 92 | if(is_ios){ 93 | schemacallback = 'weixin://'; 94 | }else if(ua.indexOf('ucbrowser')>-1){ 95 | schemacallback = 'ucweb://'; 96 | }else if(ua.indexOf('meizu')>-1){ 97 | schemacallback = 'mzbrowser://'; 98 | }else if(ua.indexOf('liebaofast')>-1){ 99 | schemacallback = 'lb://'; 100 | }else if(ua.indexOf('baidubrowser')>-1){ 101 | schemacallback = 'bdbrowser://'; 102 | }else if(ua.indexOf('baiduboxapp')>-1){ 103 | schemacallback = 'bdapp://'; 104 | }else if(ua.indexOf('mqqbrowser')>-1){ 105 | schemacallback = 'mqqbrowser://'; 106 | }else if(ua.indexOf('qihoobrowser')>-1){ 107 | schemacallback = 'qihoobrowser://'; 108 | }else if(ua.indexOf('chrome')>-1){ 109 | schemacallback = 'googlechrome://'; 110 | }else if(ua.indexOf('sogoumobilebrowser')>-1){ 111 | schemacallback = 'SogouMSE://'; 112 | }else if(ua.indexOf('xiaomi')>-1){ 113 | schemacallback = 'miuibrowser://'; 114 | }else{ 115 | schemacallback = 'googlechrome://'; 116 | } 117 | if(is_ios){ 118 | alert('跳转到QQ登录后请手动返回当前浏览器'); 119 | window.location.href='wtloginmqq3://ptlogin/qlogin?qrcode='+encodeURIComponent(qrurl)+'&schemacallback='+encodeURIComponent(schemacallback); 120 | }else{ 121 | window.location.href='wtloginmqq://ptlogin/qlogin?qrcode='+encodeURIComponent(qrurl)+'&schemacallback='+encodeURIComponent(schemacallback); 122 | } 123 | } 124 | $(document).ready(function(){ 125 | getqrpic(); 126 | }); -------------------------------------------------------------------------------- /admin/assets/js/login_scan.js: -------------------------------------------------------------------------------- 1 | var interval1,interval2; 2 | function getqrcode(){ 3 | if($('#qrimg').attr('lock') === 'true') return; 4 | cleartime(); 5 | var getvcurl='ajax.php?act=weiboLogin&do=getqrcode&r='+Math.random(1); 6 | $.get(getvcurl, function(d) { 7 | if(d.code ==0){ 8 | $('#qrimg').attr('qrid',d.qrid); 9 | $('#qrimg').attr('link',d.link); 10 | $('#qrimg').html(''); 11 | $('#login').show(); 12 | $('#loginmsg').html('请用最新版微博客户端扫码'); 13 | if( /Android|SymbianOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|Midp/i.test(navigator.userAgent)) { 14 | $('#mobile').show(); 15 | } 16 | interval1=setInterval(loginload,1000); 17 | interval2=setInterval(qrlogin,3000); 18 | }else{ 19 | alert(d.msg); 20 | } 21 | }, 'json'); 22 | } 23 | function qrlogin(){ 24 | var qrid=$('#qrimg').attr('qrid'); 25 | if(qrid=='')return; 26 | var loginurl="ajax.php?act=weiboLogin&do=qrlogin"; 27 | $.ajax({ 28 | type: "POST", 29 | url: loginurl, 30 | async: true, 31 | dataType: 'json', 32 | timeout: 15000, 33 | data: {qrid : qrid}, 34 | cache:false, 35 | success: function(data) { 36 | if(data.code ==0){ 37 | cleartime(); 38 | $('#qrimg').attr('lock','true'); 39 | $('#login').hide(); 40 | showresult(data) 41 | }else if(data.code ==1){ 42 | $('#loginmsg').html('请用最新版微博客户端扫码'); 43 | }else if(data.code ==2){ 44 | $('#loginmsg').html('成功扫描,请在手机点击确认以登录'); 45 | }else if(data.code ==3){ 46 | $('#loginmsg').html('该二维码已过期,请重新扫描'); 47 | getqrcode(); 48 | }else{ 49 | cleartime(); 50 | $('#loginmsg').html(data.msg); 51 | alert(data.msg); 52 | } 53 | }, 54 | error: function(){ 55 | cleartime(); 56 | alert('服务器错误'); 57 | } 58 | }); 59 | } 60 | function loginload(){ 61 | var load=document.getElementById('loginload').innerHTML; 62 | var len=load.length; 63 | if(len>2){ 64 | load='.'; 65 | }else{ 66 | load+='.'; 67 | } 68 | document.getElementById('loginload').innerHTML=load; 69 | } 70 | function cleartime(){ 71 | clearInterval(interval1); 72 | clearInterval(interval2); 73 | } 74 | function showresult(arr){ 75 | $('#load').html(' 微博账号添加成功!
'+decodeURIComponent(arr.nick)+'(UID:'+arr.uid+')'); 76 | } 77 | function mloginurl(){ 78 | var url = $('#qrimg').attr('link'); 79 | window.location.href='sinaweibo://browser?url='+encodeURIComponent(url); 80 | } 81 | $(document).ready(function(){ 82 | getqrcode(); 83 | }); -------------------------------------------------------------------------------- /admin/assets/js/login_sms.js: -------------------------------------------------------------------------------- 1 | var comm_data = { 2 | servertime:'', 3 | nonce:'', 4 | rsakv:'', 5 | pubkey:'', 6 | cid:'', 7 | csrf_token:'', 8 | smstoken:'' 9 | } 10 | var ajax={ 11 | get: function(url, dataType, callback) { 12 | dataType = dataType || 'html'; 13 | $.ajax({ 14 | type: "GET", 15 | url: url, 16 | async: true, 17 | dataType: dataType, 18 | cache:false, 19 | success: function(data,status) { 20 | if (callback == null) { 21 | return; 22 | } 23 | callback(data); 24 | }, 25 | error: function(error) { 26 | alert('创建连接失败'); 27 | } 28 | }); 29 | }, 30 | post: function(url, parameter, dataType, callback) { 31 | dataType = dataType || 'html'; 32 | $.ajax({ 33 | type: "POST", 34 | url: url, 35 | async: true, 36 | dataType: dataType, 37 | data: parameter, 38 | cache:false, 39 | success: function(data,status) { 40 | if (callback == null) { 41 | return; 42 | } 43 | callback(data); 44 | }, 45 | error: function(error) { 46 | alert('创建连接失败'); 47 | } 48 | }); 49 | } 50 | } 51 | function invokeSettime(obj){ 52 | var countdown=60; 53 | settime(obj); 54 | function settime(obj) { 55 | if (countdown == 0) { 56 | $(obj).attr("data-lock", "false"); 57 | $(obj).attr("disabled",false); 58 | $(obj).text("获取验证码"); 59 | countdown = 60; 60 | return; 61 | } else { 62 | $(obj).attr("data-lock", "true"); 63 | $(obj).attr("disabled",true); 64 | $(obj).text(countdown + "秒后重试"); 65 | countdown--; 66 | } 67 | setTimeout(function() { settime(obj) } ,1000) 68 | } 69 | } 70 | function trim(str){ //去掉头尾空格 71 | return str.replace(/(^\s*)|(\s*$)/g, ""); 72 | } 73 | function getconfig(){ 74 | var ii = layer.load(2, {shade: [0.1,'#fff']}); 75 | var getvcurl="ajax.php?act=weiboLogin&do=getconfig"; 76 | ajax.get(getvcurl, 'json', function(d) { 77 | layer.close(ii); 78 | if(d.code ==0){ 79 | var data = d.data; 80 | comm_data.servertime = data.servertime; 81 | comm_data.nonce = data.nonce; 82 | comm_data.rsakv = data.rsakv; 83 | comm_data.pubkey = data.pubkey; 84 | comm_data.csrf_token = d.csrf_token; 85 | }else{ 86 | layer.alert(d.msg, {icon: 2}); 87 | } 88 | }); 89 | } 90 | function login(user,code){ 91 | var ii = layer.msg('正在登录,请稍候...', {icon: 16,shade: 0.5,time: 15000}); 92 | var loginurl="ajax.php?act=weiboLogin&do=smslogin&r="+Math.random(1); 93 | ajax.post(loginurl, {user:user, code:code, csrf_token:comm_data.csrf_token}, 'json', function(d) { 94 | layer.close(ii); 95 | if(d.code ==0){ 96 | $('#login').hide(); 97 | $('#submit').hide(); 98 | showresult(d); 99 | }else{ 100 | $('#load').html(d.msg); 101 | $('#load').show(); 102 | $('#login').show(); 103 | } 104 | }); 105 | } 106 | function sendsms(mobile){ 107 | var ii = layer.load(2, {shade: [0.1,'#fff']}); 108 | var loginurl="ajax.php?act=weiboLogin&do=sendsms&r="+Math.random(1); 109 | ajax.post(loginurl, {mobile:mobile, cid:comm_data.cid, csrf_token:comm_data.csrf_token}, 'json', function(d) { 110 | layer.close(ii); 111 | if(d.code ==0){ 112 | $('#sms').show(); 113 | $('#submit').attr('do','smscode'); 114 | invokeSettime("#sendcode"); 115 | layer.alert('验证码发送成功,请查收', {icon: 1}, function(){ layer.closeAll();$('#sendcode').focus() }); 116 | }else if(d.code ==2){ 117 | comm_data.cid = d.cid; 118 | initGeetest4({ 119 | captchaId: '8b4a2bef633eb0264367b3ba9fa1dd3d', 120 | product: 'bind', 121 | hideSuccess: true 122 | },function (captcha) { 123 | captcha.onReady(function(){ 124 | captcha.showCaptcha(); 125 | }).onSuccess(function(){ 126 | var result = captcha.getValidate(); 127 | if (!result) { 128 | layer.closeAll(); 129 | return alert('请先完成验证'); 130 | } 131 | $('#validate_data').val(window.btoa(JSON.stringify(result))); 132 | var verifyurl="ajax.php?act=weiboLogin&do=verifycaptcha&r="+Math.random(1); 133 | ajax.post(verifyurl, {key:comm_data.cid, lot_number:result.lot_number, captcha_output:result.captcha_output, pass_token:result.pass_token, gen_time:result.gen_time}, 'json', function(d) { 134 | if(d.code ==0){ 135 | sendsms(mobile) 136 | }else{ 137 | layer.alert(d.msg, {icon: 2}); 138 | } 139 | }); 140 | }).onError(function(){ 141 | alert('验证码加载失败,请刷新页面重试'); 142 | }) 143 | }); 144 | }else{ 145 | layer.alert(d.msg, {icon: 2}); 146 | } 147 | }); 148 | } 149 | function showresult(arr){ 150 | $('#load').html(' 微博账号添加成功!
'+decodeURIComponent(arr.nick)+'(UID:'+arr.uid+')'); 151 | $('#load').show(); 152 | } 153 | $(document).ready(function(){ 154 | $('#submit').click(function(){ 155 | var self=$(this); 156 | var mobile=trim($('#mobile').val()), 157 | smscode=trim($('#smscode').val()); 158 | if(mobile=='') { 159 | alert("手机号不能为空!"); 160 | return false; 161 | } 162 | if (self.attr("data-lock") === "true") return; 163 | else self.attr("data-lock", "true"); 164 | if(self.attr('do') == 'smscode'){ 165 | if(smscode=='') { 166 | alert("验证码不能为空!"); 167 | return false; 168 | } 169 | login(mobile,smscode); 170 | }else{ 171 | sendsms(mobile); 172 | } 173 | self.attr("data-lock", "false"); 174 | }); 175 | $('#sendcode').click(function(){ 176 | var self=$(this); 177 | var mobile=trim($('#mobile').val()); 178 | if(mobile=='') { 179 | alert("手机号不能为空!"); 180 | return false; 181 | } 182 | if (self.attr("data-lock") === "true") return; 183 | else self.attr("data-lock", "true"); 184 | sendsms(mobile); 185 | self.attr("data-lock", "false"); 186 | }); 187 | getconfig(); 188 | }); -------------------------------------------------------------------------------- /admin/download.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 4 | 5 | $mod=isset($_GET['mod'])?$_GET['mod']:null; 6 | 7 | if($mod == 'faceimg'){ 8 | $uid = isset($_GET['uid'])?$_GET['uid']:null; 9 | 10 | $url = 'http://tp2.sinaimg.cn/'.$uid.'/180/'.time().'/1'; 11 | $imgurl = get_redirect_url($url, 'https://weibo.com/'); 12 | if($imgurl){ 13 | ob_clean(); 14 | $seconds_to_cache = 3600*24*7; 15 | header("Pragma: cache"); 16 | header("Cache-Control: max-age=$seconds_to_cache"); 17 | header("Content-Type: image/jpeg"); 18 | echo get_curl($imgurl, 0, 'https://weibo.com/'); 19 | } 20 | } -------------------------------------------------------------------------------- /admin/head.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <?php echo $title ?> 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 74 | -------------------------------------------------------------------------------- /admin/imghost.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 6 | ?> 7 | 19 |
20 |
21 |
22 |

23 | 微博图床 24 |

25 |
26 |
27 |
{{progress}}%
28 |
29 |
30 |
31 |
点击选择文件/Ctrl+V粘贴/拖拽到此处 32 | 33 |
34 |
35 | 36 |
37 |
38 | 44 |
45 |
46 | 47 |
48 |
    
49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /admin/index.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 6 | 7 | $count1 = $DB->getColumn("SELECT count(*) from weiboapi_account"); 8 | $count2 = $DB->getColumn("SELECT count(*) from weiboapi_account WHERE status=1"); 9 | $checktime = $conf['checktime']; 10 | if(!$checktime) $checktime = '未运行'; 11 | $mysqlversion=$DB->getColumn("select VERSION()"); 12 | 13 | ?> 14 |
15 |
16 |
17 |

后台管理首页

18 |
19 |
账号数量:共有 个微博账号,其中正常的有
20 |
检测任务:上次运行时间:  查看详情
21 | 22 |
23 |
24 | 25 |
26 |
27 |

服务器信息

28 |
29 |
    30 |
  • 31 | PHP 版本: 32 |
  • 33 |
  • 34 | MySQL 版本: 35 |
  • 36 |
  • 37 | WEB 软件: 38 |
  • 39 |
  • 40 | 操作系统: 41 |
  • 42 |
  • 43 | 服务器时间: 44 |
  • 45 |
46 |
47 |
48 |
-------------------------------------------------------------------------------- /admin/list.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 6 | ?> 7 | 15 |
16 |
17 | getColumn("SELECT count(*) from weiboapi_account WHERE{$sql}"); 22 | $con='包含 '.$_GET['kw'].' 的共有 '.$numrows.' 个记录'; 23 | $link='&my=search&kw='.$_GET['kw']; 24 | }else{ 25 | $numrows=$DB->getColumn("SELECT count(*) from weiboapi_account WHERE 1"); 26 | $sql=" 1"; 27 | $con='本站共有 '.$numrows.' 个账号'; 28 | } 29 | 30 | echo '
31 |
32 | 33 | 34 |
35 |   添加账号 36 |
'; 37 | echo $con; 38 | ?> 39 |
40 | 41 | 42 | 43 | query("SELECT * FROM weiboapi_account WHERE{$sql} order by id desc limit $offset,$pagesize"); 50 | while($res = $rs->fetch()) 51 | { 52 | $avatar = './download.php?mod=faceimg&uid='.$res['uid']; 53 | echo ''; 54 | } 55 | ?> 56 | 57 |
ID头像UID昵称更新时间上次使用状态操作
'.$res['id'].'Avatar'.$res['uid'].''.$res['nickname'].''.$res['refreshtime'].''.$res['usetime'].''.($res['status']==1?'正常':'离线').'更新 检测 日志 删除
58 |
59 | '; 61 | $first=1; 62 | $prev=$page-1; 63 | $next=$page+1; 64 | $last=$pages; 65 | if ($page>1) 66 | { 67 | echo '
  • 首页
  • '; 68 | echo '
  • «
  • '; 69 | } else { 70 | echo '
  • 首页
  • '; 71 | echo '
  • «
  • '; 72 | } 73 | $start=$page-10>1?$page-10:1; 74 | $end=$page+10<$pages?$page+10:$pages; 75 | for ($i=$start;$i<$page;$i++) 76 | echo '
  • '.$i .'
  • '; 77 | echo '
  • '.$page.'
  • '; 78 | for ($i=$page+1;$i<=$end;$i++) 79 | echo '
  • '.$i .'
  • '; 80 | echo ''; 81 | if ($page<$pages) 82 | { 83 | echo '
  • »
  • '; 84 | echo '
  • 尾页
  • '; 85 | } else { 86 | echo '
  • »
  • '; 87 | echo '
  • 尾页
  • '; 88 | } 89 | echo ''; 90 | ?> 91 |
    92 |
    93 | 94 | -------------------------------------------------------------------------------- /admin/log.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 6 | ?> 7 |
    8 |
    9 | getColumn("SELECT count(*) from weiboapi_log A LEFT JOIN weiboapi_account B ON A.aid=B.id WHERE{$sql}"); 18 | 19 | ?> 20 |
    21 | 22 | 23 | 24 | query("SELECT A.*,B.uid,B.nickname FROM weiboapi_log A LEFT JOIN weiboapi_account B ON A.aid=B.id WHERE{$sql} order by A.id desc limit $offset,$pagesize"); 31 | while($res = $rs->fetch()) 32 | { 33 | echo ''; 34 | } 35 | ?> 36 | 37 |
    IDUID昵称操作类型时间
    '.$res['id'].''.$res['uid'].''.$res['nickname'].''.$res['action'].''.$res['time'].'
    38 |
    39 | '; 41 | $first=1; 42 | $prev=$page-1; 43 | $next=$page+1; 44 | $last=$pages; 45 | if ($page>1) 46 | { 47 | echo '
  • 首页
  • '; 48 | echo '
  • «
  • '; 49 | } else { 50 | echo '
  • 首页
  • '; 51 | echo '
  • «
  • '; 52 | } 53 | $start=$page-10>1?$page-10:1; 54 | $end=$page+10<$pages?$page+10:$pages; 55 | for ($i=$start;$i<$page;$i++) 56 | echo '
  • '.$i .'
  • '; 57 | echo '
  • '.$page.'
  • '; 58 | for ($i=$page+1;$i<=$end;$i++) 59 | echo '
  • '.$i .'
  • '; 60 | echo ''; 61 | if ($page<$pages) 62 | { 63 | echo '
  • »
  • '; 64 | echo '
  • 尾页
  • '; 65 | } else { 66 | echo '
  • »
  • '; 67 | echo '
  • 尾页
  • '; 68 | } 69 | echo''; 70 | #分页 71 | ?> 72 |
    73 |
    74 | 75 | -------------------------------------------------------------------------------- /admin/login.php: -------------------------------------------------------------------------------- 1 | alert('登陆后台管理成功!');window.location.href='./';"); 15 | }else{ 16 | @header('Content-Type: text/html; charset=UTF-8'); 17 | exit(""); 18 | } 19 | }elseif(isset($_GET['logout'])){ 20 | setcookie("admin_token", "", time() - 604800); 21 | @header('Content-Type: text/html; charset=UTF-8'); 22 | exit(""); 23 | }elseif($islogin==1){ 24 | exit(""); 25 | } 26 | $title='用户登录'; 27 | include './head.php'; 28 | ?> 29 | 49 |
    50 |
    51 |
    52 |

    用户登录

    53 |
    54 |
    55 |
    56 | 57 | 58 |

    59 |
    60 | 61 | 62 |

    63 |
    64 |
    65 |
    66 |
    67 |
    68 |
    69 |
    70 |
    -------------------------------------------------------------------------------- /admin/set.php: -------------------------------------------------------------------------------- 1 | window.location.href='./login.php';"); 9 | ?> 10 |
    11 |
    12 | 15 | 19 |
    20 |

    计划任务说明

    21 |
    22 |

    定时执行计划任务可实现COOKIE检测与保活,避免频繁重复登录。

    将以下命令添加到计划任务定时执行,频率:1分钟1次

    23 |
  • php cron.php
  • 24 |
    25 |
    26 | 29 |
    30 |

    基础参数设置

    31 |
    32 |
    33 |
    34 | 35 |
    36 |

    37 |
    38 | 39 |
    获取COOKIE接口专用,不影响其他接口开关
    40 |

    41 |
    42 | 43 |
    44 |

    45 |
    46 | 47 |
    留空则不限制IP,多个IP用|隔开
    48 |

    49 |
    50 | 51 |
    52 |

    53 |
    54 |

    55 |
    56 |
    57 |
    58 |
    59 |
    60 |
    来自:'.$siteurl); 65 | if($result==1) 66 | showmsg('邮件发送成功!',1); 67 | else 68 | showmsg('邮件发送失败!'.$result,3); 69 | } 70 | else 71 | showmsg('您还未设置邮箱!',3); 72 | }elseif($mod=='notice'){ 73 | ?> 74 |
    75 |

    邮件提醒设置

    76 |
    77 |
    78 |
    79 | 80 |
    81 |

    82 |
    83 | 84 |
    85 |

    86 |
    87 |
    88 | 89 |
    90 |

    91 |
    92 | 93 |
    94 |

    95 |
    96 | 97 |
    98 |

    99 |
    100 | 101 |
    102 |

    103 |
    104 |
    105 |
    106 | 107 |
    108 |

    109 |
    110 | 111 |
    112 |

    113 |
    114 | 115 |
    116 |

    117 |
    118 |
    119 | 120 |
    121 |

    122 |
    123 |
    125 |
    126 |
    127 |
    128 | 132 |
    133 | 144 | 161 |
    162 |

    管理员账号设置

    163 |
    164 |
    165 |
    166 | 167 |
    168 |

    169 |
    170 | 171 |
    172 |

    173 |
    174 | 175 |
    176 |

    177 |
    178 | 179 |
    180 |

    181 |
    182 |

    183 |
    184 |
    185 |
    186 |
    187 |
    188 | 191 |
    192 |
    193 | 194 | -------------------------------------------------------------------------------- /api.php: -------------------------------------------------------------------------------- 1 | find('account', '*', ['uid'=>$uid]); 19 | if(!$account) exit('{"code":-1,"msg":"微博账号不存在"}'); 20 | if($account['status']!=1) exit('{"code":-1,"msg":"微博账号状态不正常"}'); 21 | $uid = $account['uid']; 22 | $nickname = $account['nickname']; 23 | $cookie = $account['cookie_weibo']; 24 | }else{ 25 | $account = $DB->getRow("SELECT * FROM weiboapi_account WHERE `status`=1 ORDER BY usetime ASC LIMIT 1"); 26 | if(!$account) exit('{"code":-1,"msg":"暂无可用的微博账号"}'); 27 | $uid = $account['uid']; 28 | $nickname = $account['nickname']; 29 | $cookie = $account['cookie_weibo']; 30 | } 31 | exit(json_encode(['code'=>0, 'uid'=>$uid, 'nickname'=>$nickname, 'cookie'=>$cookie])); 32 | break; 33 | case 'gethotsearch': //获取热搜列表 34 | if($key !== $conf['apikey'])exit('{"code":-1,"msg":"密钥错误"}'); 35 | $result = weibotool_call('hotline', [], 60); 36 | exit(json_encode($result)); 37 | break; 38 | case 'parsevideo': //解析微博视频 39 | $oid = isset($_POST['oid'])?trim($_POST['oid']):exit('{"code":-1,"msg":"视频ID不能为空"}'); 40 | if($key !== $conf['apikey'])exit('{"code":-1,"msg":"密钥错误"}'); 41 | $result = weibotool_call('parseVideo', [$oid], 3600); 42 | exit(json_encode($result)); 43 | break; 44 | case 'getuserinfo': //获取用户信息 45 | $uid = isset($_POST['uid'])?trim($_POST['uid']):exit('{"code":-1,"msg":"用户ID不能为空"}'); 46 | if($key !== $conf['apikey'])exit('{"code":-1,"msg":"密钥错误"}'); 47 | $result = weibotool_call('getUserInfo', [$uid], 3600); 48 | exit(json_encode($result)); 49 | break; 50 | default: 51 | exit('{"code":-4,"msg":"No Act"}'); 52 | break; 53 | } -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 'localhost', //数据库服务器 5 | 'port' => 3306, //数据库端口 6 | 'user' => '', //数据库用户名 7 | 'pwd' => '', //数据库密码 8 | 'dbname' => '', //数据库名 9 | 'prefix' => 'weiboapi_' //数据表前缀 10 | ); 11 | -------------------------------------------------------------------------------- /cron.php: -------------------------------------------------------------------------------- 1 | getAll("SELECT * FROM weiboapi_account WHERE status=1 AND (checktime<'$checktime' OR checktime IS NULL) ORDER BY checktime ASC"); 11 | if(count($list) == 0) exit("[OK] 暂无需要更新的COOKIE\n"); 12 | foreach($list as $row){ 13 | $nickname = $row['nickname']; 14 | $rescode = \lib\Logic::checkAccount($row['id']); 15 | if($rescode == 2){ 16 | echo "[OK] {$nickname} 账号COOKIE更新成功\n"; 17 | }elseif($rescode == 1){ 18 | echo "[OK] {$nickname} 账号状态检测正常\n"; 19 | }else{ 20 | echo "[Warn] {$nickname} 账号状态已失效\n"; 21 | } 22 | } 23 | 24 | if($conf['cache_time'] > 0 && $conf['cache_clean']!=date('Ymd')){ 25 | $DB->exec("TRUNCATE TABLE `weiboapi_cache`"); 26 | saveSetting('cache_clean', date('Ymd')); 27 | echo '[OK] 清空查询缓存成功!'."\n"; 28 | } 29 | 30 | saveSetting('checktime', date("Y-m-d H:i:s")); 31 | 32 | echo '[OK] '.date("Y-m-d H:i:s")."\n"; 33 | -------------------------------------------------------------------------------- /includes/autoloader.php: -------------------------------------------------------------------------------- 1 | 点此安装'; 19 | exit(); 20 | } 21 | 22 | include_once(SYSTEM_ROOT."autoloader.php"); 23 | Autoloader::register(); 24 | 25 | $DB = new \lib\PdoHelper($dbconfig); 26 | 27 | if($DB->query("select * from weiboapi_config where 1")==FALSE) 28 | { 29 | header('Content-type:text/html;charset=utf-8'); 30 | echo '你还没安装!点此安装'; 31 | exit(); 32 | } 33 | 34 | $conf = []; 35 | $result = $DB->getAll("SELECT * FROM weiboapi_config"); 36 | foreach($result as $row){ 37 | $conf[$row['k']] = $row['v']; 38 | } 39 | unset($result); 40 | 41 | define('SYS_KEY', $conf['syskey']); 42 | $password_hash='!@#%!s!0'; 43 | 44 | include_once(SYSTEM_ROOT."functions.php"); 45 | 46 | $scriptpath=str_replace('\\','/',$_SERVER['SCRIPT_NAME']); 47 | $sitepath = substr($scriptpath, 0, strrpos($scriptpath, '/')); 48 | $siteurl = (is_https() ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$sitepath.'/'; 49 | 50 | $clientip=real_ip($conf['ip_type']?$conf['ip_type']:0); 51 | if(isset($_COOKIE["admin_token"])) 52 | { 53 | $token=authcode(daddslashes($_COOKIE['admin_token']), 'DECODE', SYS_KEY); 54 | if($token){ 55 | list($user, $sid) = explode("\t", $token); 56 | $session=md5($conf['admin_user'].$conf['admin_pwd'].$password_hash); 57 | if($session===$sid) { 58 | $islogin=1; 59 | } 60 | } 61 | } 62 | 63 | if (!file_exists(ROOT.'install/install.lock') && file_exists(ROOT.'install/index.php')) { 64 | sysmsg('

    检测到无 install.lock 文件


    为什么必须建立 install.lock 文件?

    它是安装保护文件,如果检测不到它,就会认为站点还没安装,此时任何人都可以安装/重装你的网站。

    ');exit; 65 | } 66 | -------------------------------------------------------------------------------- /includes/functions.php: -------------------------------------------------------------------------------- 1 | =1 && isset($_SERVER['HTTP_CF_CONNECTING_IP']) && filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { 44 | $ip = $_SERVER['HTTP_CF_CONNECTING_IP']; 45 | } elseif ($type>=1 && isset($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { 46 | $ip = $_SERVER['HTTP_X_REAL_IP']; 47 | } 48 | return $ip; 49 | } 50 | function get_ip_city($ip) 51 | { 52 | $url = 'http://whois.pconline.com.cn/ipJson.jsp?json=true&ip='; 53 | $city = get_curl($url . $ip); 54 | $city = mb_convert_encoding($city, "UTF-8", "GB2312"); 55 | $city = json_decode($city, true); 56 | if ($city['city']) { 57 | $location = $city['pro'].$city['city']; 58 | } else { 59 | $location = $city['pro']; 60 | } 61 | if($location){ 62 | return $location; 63 | }else{ 64 | return false; 65 | } 66 | } 67 | function daddslashes($string) { 68 | if(is_array($string)) { 69 | foreach($string as $key => $val) { 70 | $string[$key] = daddslashes($val); 71 | } 72 | } else { 73 | $string = addslashes($string); 74 | } 75 | return $string; 76 | } 77 | 78 | function strexists($string, $find) { 79 | return !(strpos($string, $find) === FALSE); 80 | } 81 | 82 | function dstrpos($string, $arr) { 83 | if(empty($string)) return false; 84 | foreach((array)$arr as $v) { 85 | if(strpos($string, $v) !== false) { 86 | return true; 87 | } 88 | } 89 | return false; 90 | } 91 | 92 | function checkmobile() { 93 | $useragent = strtolower($_SERVER['HTTP_USER_AGENT']); 94 | $ualist = array('android', 'midp', 'nokia', 'mobile', 'iphone', 'ipod', 'blackberry', 'windows phone'); 95 | if((dstrpos($useragent, $ualist) || strexists($_SERVER['HTTP_ACCEPT'], "VND.WAP") || strexists($_SERVER['HTTP_VIA'],"wap"))) 96 | return true; 97 | else 98 | return false; 99 | } 100 | function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) { 101 | $ckey_length = 4; 102 | $key = md5($key); 103 | $keya = md5(substr($key, 0, 16)); 104 | $keyb = md5(substr($key, 16, 16)); 105 | $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; 106 | $cryptkey = $keya.md5($keya.$keyc); 107 | $key_length = strlen($cryptkey); 108 | $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; 109 | $string_length = strlen($string); 110 | $result = ''; 111 | $box = range(0, 255); 112 | $rndkey = array(); 113 | for($i = 0; $i <= 255; $i++) { 114 | $rndkey[$i] = ord($cryptkey[$i % $key_length]); 115 | } 116 | for($j = $i = 0; $i < 256; $i++) { 117 | $j = ($j + $box[$i] + $rndkey[$i]) % 256; 118 | $tmp = $box[$i]; 119 | $box[$i] = $box[$j]; 120 | $box[$j] = $tmp; 121 | } 122 | for($a = $j = $i = 0; $i < $string_length; $i++) { 123 | $a = ($a + 1) % 256; 124 | $j = ($j + $box[$a]) % 256; 125 | $tmp = $box[$a]; 126 | $box[$a] = $box[$j]; 127 | $box[$j] = $tmp; 128 | $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); 129 | } 130 | if($operation == 'DECODE') { 131 | if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { 132 | return substr($result, 26); 133 | } else { 134 | return ''; 135 | } 136 | } else { 137 | return $keyc.str_replace('=', '', base64_encode($result)); 138 | } 139 | } 140 | 141 | function random($length, $numeric = 0) { 142 | $seed = base_convert(md5(microtime().$_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35); 143 | $seed = $numeric ? (str_replace('0', '', $seed).'012340567890') : ($seed.'zZ'.strtoupper($seed)); 144 | $hash = ''; 145 | $max = strlen($seed) - 1; 146 | for($i = 0; $i < $length; $i++) { 147 | $hash .= $seed[mt_rand(0, $max)]; 148 | } 149 | return $hash; 150 | } 151 | function showmsg($content = '未知的异常',$type = 4,$back = false) 152 | { 153 | switch($type) 154 | { 155 | case 1: 156 | $panel="success"; 157 | break; 158 | case 2: 159 | $panel="info"; 160 | break; 161 | case 3: 162 | $panel="warning"; 163 | break; 164 | case 4: 165 | $panel="danger"; 166 | break; 167 | } 168 | 169 | echo '
    170 |
    171 |

    提示信息

    172 |
    173 |
    '; 174 | echo $content; 175 | 176 | if ($back) { 177 | echo '
    << 返回上一页'; 178 | } 179 | else 180 | echo '
    << 返回上一页'; 181 | 182 | echo '
    183 |
    '; 184 | exit; 185 | } 186 | function sysmsg($msg = '未知的异常',$title = '站点提示信息') { 187 | ?> 188 | 189 | 190 | 191 | 192 | 193 | <?php echo $title?> 194 | 197 | 198 | 199 | '.$title.''; 200 | echo $msg; ?> 201 | 202 | 203 | 0){ 256 | return substr($str, $start, $right-$start); 257 | }else{ 258 | return substr($str, $start); 259 | } 260 | } 261 | 262 | function send_mail($to, $sub, $msg) { 263 | global $conf; 264 | if($conf['mail_cloud']==1){ 265 | $mail = new \lib\mail\Sendcloud($conf['mail_apiuser'], $conf['mail_apikey']); 266 | return $mail->send($to, $sub, $msg, $conf['mail_name2'], $conf['sitename']); 267 | }elseif($conf['mail_cloud']==2){ 268 | try{ 269 | $mail = new \lib\mail\Aliyun($conf['mail_apiuser'], $conf['mail_apikey']); 270 | return $mail->send($to, $sub, $msg, $conf['mail_name2'], $conf['sitename']); 271 | } catch (Exception $e) { 272 | return $e->getMessage(); 273 | } 274 | }else{ 275 | if(!$conf['mail_name'] || !$conf['mail_port'] || !$conf['mail_smtp'] || !$conf['mail_pwd'])return false; 276 | $port = intval($conf['mail_port']); 277 | $mail = new \lib\mail\PHPMailer\PHPMailer(true); 278 | try{ 279 | $mail->SMTPDebug = 0; 280 | $mail->CharSet = 'UTF-8'; 281 | $mail->Timeout = 5; 282 | $mail->isSMTP(); 283 | $mail->Host = $conf['mail_smtp']; 284 | $mail->SMTPAuth = true; 285 | $mail->Username = $conf['mail_name']; 286 | $mail->Password = $conf['mail_pwd']; 287 | if($port == 587) $mail->SMTPSecure = 'tls'; 288 | else if($port >= 465) $mail->SMTPSecure = 'ssl'; 289 | else $mail->SMTPAutoTLS = false; 290 | $mail->Port = intval($conf['mail_port']); 291 | $mail->setFrom($conf['mail_name'], $conf['sitename']); 292 | $mail->addAddress($to); 293 | $mail->addReplyTo($conf['mail_name'], $conf['sitename']); 294 | $mail->isHTML(true); 295 | $mail->Subject = $sub; 296 | $mail->Body = $msg; 297 | $mail->send(); 298 | return true; 299 | } catch (Exception $e) { 300 | return $mail->ErrorInfo; 301 | } 302 | } 303 | } 304 | 305 | function jsonp_decode($jsonp, $assoc = false) 306 | { 307 | $jsonp = trim($jsonp); 308 | if(isset($jsonp[0]) && $jsonp[0] !== '[' && $jsonp[0] !== '{') { 309 | $begin = strpos($jsonp, '('); 310 | if(false !== $begin) 311 | { 312 | $end = strrpos($jsonp, ')'); 313 | if(false !== $end) 314 | { 315 | $jsonp = substr($jsonp, $begin + 1, $end - $begin - 1); 316 | } 317 | } 318 | } 319 | return json_decode($jsonp, $assoc); 320 | } 321 | 322 | function getSetting($k){ 323 | global $DB; 324 | return $DB->getColumn("SELECT v FROM weiboapi_config WHERE k=:k LIMIT 1", [':k'=>$k]); 325 | } 326 | function saveSetting($k, $v){ 327 | global $DB; 328 | return $DB->exec("REPLACE INTO weiboapi_config SET v=:v,k=:k", [':v'=>$v, ':k'=>$k]); 329 | } 330 | 331 | function weibotool_call_nocache($func, $args, $retry = 2){ 332 | global $DB; 333 | $retry--; 334 | $row = $DB->getRow("SELECT * FROM weiboapi_account WHERE `status`=1 ORDER BY usetime ASC LIMIT 1"); 335 | if($row){ 336 | $DB->update('account', ['usetime'=>'NOW()'], ['id'=>$row['id']]); 337 | $tool = new \lib\WeiboTool($row['cookie_weibo']); 338 | $result = call_user_func_array([$tool, $func], $args); 339 | if($tool->cookiefail){ 340 | \lib\Logic::checkAccount($row['id']); 341 | if($retry > 0){ 342 | $result = weibotool_call_nocache($func, $args, $retry); 343 | } 344 | } 345 | }else{ 346 | $result = ['code'=>-1, 'subcode'=>201, 'msg'=>'暂无可用的微博账号,请稍后再试']; 347 | } 348 | return $result; 349 | } 350 | 351 | function weibotool_call($func, $args, $cachetime = 0, $retry = 2){ 352 | global $DB; 353 | if($cachetime > 0){ 354 | $cache_key = md5($func.','.implode(',', $args)); 355 | $cache = $DB->find('cache', '*', ['key'=>$cache_key]); 356 | if($cache && time() - $cache['time'] < $cachetime){ 357 | $result = json_decode($cache['data'], true); 358 | $result['from'] = 'cache'; 359 | return $result; 360 | } 361 | } 362 | $result = weibotool_call_nocache($func, $args, $retry); 363 | if(isset($result['code']) && $result['code'] == 0 && $cachetime > 0){ 364 | $DB->exec("INSERT INTO `weiboapi_cache` (`key`,`data`,`time`) VALUES (:rkey, :rdata, :rtime) on duplicate key update `data`=:rdata,`time`=:rtime", [':rkey'=>$cache_key, ':rdata'=>json_encode($result), ':rtime'=>time()]); 365 | $result['from'] = 'online'; 366 | } 367 | return $result; 368 | } 369 | 370 | function get_redirect_url($url, $referer = null){ 371 | $url = $url; 372 | $ch=curl_init($url); 373 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 374 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 375 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 376 | curl_setopt($ch, CURLOPT_HEADER, false); 377 | if($referer){ 378 | curl_setopt($ch, CURLOPT_REFERER, $referer); 379 | } 380 | curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'); 381 | curl_setopt($ch, CURLOPT_TIMEOUT, 4); 382 | curl_exec($ch); 383 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 384 | if($httpCode == 301 || $httpCode == 302){ 385 | $redirect_url = curl_getinfo($ch, CURLINFO_REDIRECT_URL); 386 | } 387 | curl_close($ch); 388 | return $redirect_url; 389 | } -------------------------------------------------------------------------------- /includes/lib/Logic.php: -------------------------------------------------------------------------------- 1 | $v){ 15 | $cookie_login .= $k.'='.$v.'; '; 16 | } 17 | $cookie_login = substr($cookie_login, 0, -2); 18 | 19 | $cookie_weibo = ''; 20 | foreach($array['wbcookie'] as $k=>$v){ 21 | $cookie_weibo .= $k.'='.$v.'; '; 22 | } 23 | $cookie_weibo = substr($cookie_weibo, 0, -2); 24 | 25 | $data = ['nickname'=>$array['nick'], 'cookie_login'=>$cookie_login, 'cookie_weibo'=>$cookie_weibo, 'refreshtime'=>'NOW()', 'status'=>'1']; 26 | if($_POST['user']){ 27 | $data['loginname'] = $_POST['user']; 28 | } 29 | 30 | $aid = $DB->findColumn('account', 'id', ['uid'=>$array['uid']]); 31 | 32 | if($aid){ 33 | $DB->update('account', $data, ['id'=>$aid]); 34 | $DB->insert('log', ['aid'=>$aid, 'action'=>'更新账号', 'time'=>'NOW()']); 35 | }else{ 36 | $data['uid'] = $array['uid']; 37 | $data['addtime'] = 'NOW()'; 38 | $aid = $DB->insert('account', $data); 39 | $DB->insert('log', ['aid'=>$aid, 'action'=>'添加账号', 'time'=>'NOW()']); 40 | } 41 | } 42 | 43 | //检测账号状态 44 | public static function checkAccount($id){ 45 | global $DB,$conf; 46 | $row = $DB->find('account', '*', ['id'=>$id]); 47 | if(!$row) throw new Exception('账号不存在'); 48 | if($row['status'] == 0) return 0; 49 | 50 | $DB->update('account', ['checktime'=>'NOW()'], ['id'=>$id]); 51 | 52 | $tool = new WeiboTool($row['cookie_weibo']); 53 | if($tool->checkCookie()){ 54 | return 1; 55 | }else{ 56 | $login = new WeiboLogin(); 57 | $cookie=[]; 58 | $rows = explode(';', $row['cookie_login']); 59 | foreach ($rows as $val) { 60 | $val = trim($val); 61 | if(empty($val)) continue; 62 | $key = substr($val, 0, strpos($val, '=')); 63 | $cookie[$key]=substr($val, strpos($val, '=')+1); 64 | } 65 | $array = $login->cookielogin($cookie); 66 | if($array['code'] == 0){ 67 | self::addAccount($array); 68 | return 2; 69 | }else{ 70 | $DB->update('account', ['status'=>0], ['id'=>$id]); 71 | if($conf['mail_open'] == 1 && defined('IS_CRON')){ 72 | self::noticeFail($row); 73 | } 74 | return 0; 75 | } 76 | } 77 | } 78 | 79 | //账号状态失效通知 80 | private static function noticeFail($account){ 81 | global $DB,$conf; 82 | $mail_name = $conf['mail_recv']?$conf['mail_recv']:$conf['mail_name']; 83 | $mail_title = '微博账号:'.$account['nickname'].' 失效提醒'; 84 | $mail_content = '你在'.$conf['sitename'].'添加的微博账号:'.$account['nickname'].'(UID:'.$account['uid'].')已失效,请及时更新!

    '.date("Y-m-d H:i:s").'
    '; 85 | send_mail($mail_name,$mail_title,$mail_content); 86 | } 87 | } -------------------------------------------------------------------------------- /includes/lib/PdoHelper.php: -------------------------------------------------------------------------------- 1 | prefix = $dbconfig['prefix']; 20 | try { 21 | $this->db = new \PDO("mysql:host={$dbconfig['host']};dbname={$dbconfig['dbname']};port={$dbconfig['port']}",$dbconfig['user'],$dbconfig['pwd']); 22 | } catch (\Exception $e) { 23 | exit('链接数据库失败:' . $e->getMessage()); 24 | } 25 | $this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT); 26 | $this->db->exec("set sql_mode = ''"); 27 | $this->db->exec("set names utf8mb4"); 28 | } 29 | 30 | /** 31 | * 设置结果集方式 32 | * 33 | * @param string $_style 34 | */ 35 | public function setFetchStyle($_style) 36 | { 37 | $this->fetchStyle = $_style; 38 | } 39 | 40 | /** 41 | * 替换数据表前缀 42 | * @param $_sql 43 | * 44 | * @return mixed 45 | */ 46 | private function dealPrefix($_sql){ 47 | return $_sql; 48 | } 49 | 50 | private function _where($conditions){ 51 | $result = array( "_where" => " ","_bindParams" => array()); 52 | if(is_array($conditions) && !empty($conditions)){ 53 | $fieldss = array(); $sql = null; $join = array(); 54 | if(isset($conditions[0]) && $sql = $conditions[0]) unset($conditions[0]); 55 | foreach( $conditions as $key => $condition ){ 56 | if(substr($key, 0, 1) != ":"){ 57 | unset($conditions[$key]); 58 | $conditions[":".$key] = $condition; 59 | } 60 | $join[] = "`{$key}` = :{$key}"; 61 | } 62 | if(!$sql) $sql = join(" AND ",$join); 63 | 64 | $result["_where"] = " WHERE ". $sql; 65 | $result["_bindParams"] = $conditions; 66 | }elseif(!empty($conditions)){ 67 | $result["_where"] = " WHERE ". $conditions; 68 | } 69 | return $result; 70 | } 71 | 72 | private function _select($table, $fields = '*', $where = array(), $sort = null, $limit = null){ 73 | $sort = !empty($sort) ? ' ORDER BY '.$sort : ''; 74 | $fields = !empty($fields) ? $fields : '*'; 75 | if(is_array($fields)){ 76 | $fields = implode(',',$fields); 77 | } 78 | $conditions = $this->_where($where); 79 | 80 | $sql = ' FROM '.$this->prefix.$table.$conditions["_where"]; 81 | if(is_array($limit)){ 82 | $limit = ' LIMIT '.$limit[0].','.$limit[1]; 83 | }elseif(!empty($limit)){ 84 | $limit = ' LIMIT '.$limit; 85 | }else{ 86 | $limit = ''; 87 | } 88 | return array('sql'=>'SELECT '. $fields . $sql . $sort . $limit, 'bind'=>$conditions["_bindParams"]); 89 | } 90 | 91 | /** 92 | * 查询一条数据 93 | * @param string $table 94 | * @param string $fields 95 | * @param array $where 96 | * @param string $sort 97 | * @param int $limit 98 | * 99 | * @return array 100 | */ 101 | public function find($table, $fields = '*', $where = array(), $sort = null, $limit = null){ 102 | $sql_arr = $this->_select($table, $fields, $where, $sort, $limit); 103 | return $this->getRow($sql_arr['sql'], $sql_arr['bind']); 104 | } 105 | 106 | /** 107 | * 查询全部数据 108 | * @param string $table 109 | * @param string $fields 110 | * @param array $where 111 | * @param string $sort 112 | * @param int $limit 113 | * 114 | * @return array 115 | */ 116 | public function findAll($table, $fields = '*', $where = array(), $sort = null, $limit = null){ 117 | $sql_arr = $this->_select($table, $fields, $where, $sort, $limit); 118 | return $this->getAll($sql_arr['sql'], $sql_arr['bind']); 119 | } 120 | 121 | /** 122 | * 查询字段数据 123 | * @param string $table 124 | * @param string $fields 125 | * @param array $where 126 | * @param string $sort 127 | * 128 | * @return mixed 129 | */ 130 | public function findColumn($table, $fields, $where = array(), $sort = null){ 131 | $sql_arr = $this->_select($table, $fields, $where, $sort, 1); 132 | return $this->getColumn($sql_arr['sql'], $sql_arr['bind']); 133 | } 134 | 135 | /** 136 | * 插入数据 137 | * @param string $table 138 | * @param array $data 139 | * 140 | * @return int 141 | */ 142 | public function insert($table, $data){ 143 | $values = array(); 144 | foreach ($data as $k=>$v){ 145 | $keys[] = "`{$k}`"; 146 | if ($v == 'NOW()' || $v == 'CURDATE()' || $v == 'CURTIME()') { 147 | $marks[] = $v; 148 | }elseif ($v == '') { 149 | $marks[] = 'NULL'; 150 | }else{ 151 | $values[":".$k] = $v; 152 | $marks[] = ":".$k; 153 | } 154 | } 155 | $rowCount = $this->exec("INSERT INTO ".$this->prefix.$table." (".implode(', ', $keys).") VALUES (".implode(', ', $marks).")", $values); 156 | if($rowCount){ 157 | return $this->lastInsertId(); 158 | }else{ 159 | return false; 160 | } 161 | } 162 | 163 | /** 164 | * 更新数据 165 | * @param string $table 166 | * @param array $data 167 | * @param array $where 168 | * 169 | * @return int 170 | */ 171 | public function update($table, $data, $where){ 172 | if(is_array($data) && !empty($data)){ 173 | $values = array(); 174 | foreach ($data as $k=>$v){ 175 | if($v == 'NOW()' || $v == 'CURDATE()' || $v == 'CURTIME()'){ 176 | $setstr[] = "`{$k}` = ".$v; 177 | }elseif($v == ''){ 178 | $setstr[] = "`{$k}` = NULL"; 179 | }else{ 180 | $values[":M_UPDATE_".$k] = $v; 181 | $setstr[] = "`{$k}` = :M_UPDATE_".$k; 182 | } 183 | } 184 | $update = implode(', ', $setstr); 185 | }elseif(!empty($data)){ 186 | $update = $data; 187 | }else{ 188 | return false; 189 | } 190 | $conditions = $this->_where($where); 191 | $rowCount = $this->exec("UPDATE ".$this->prefix.$table." SET ".$update.$conditions["_where"], $conditions["_bindParams"] + $values); 192 | return $rowCount; 193 | } 194 | 195 | /** 196 | * 删除数据 197 | * @param string $table 198 | * @param array $where 199 | * 200 | * @return int 201 | */ 202 | public function delete($table, $where){ 203 | $conditions = $this->_where($where); 204 | $rowCount = $this->exec("DELETE FROM ".$this->prefix.$table.$conditions["_where"], $conditions["_bindParams"]); 205 | return $rowCount; 206 | } 207 | 208 | /** 209 | * 统计行数 210 | * @param string $table 211 | * @param array $where 212 | * 213 | * @return int 214 | */ 215 | public function count($table, $where){ 216 | $conditions = $this->_where($where); 217 | $count = $this->getColumn("SELECT COUNT(*) FROM ".$this->prefix.$table.$conditions["_where"], $conditions["_bindParams"]); 218 | return $count; 219 | } 220 | 221 | 222 | /** 223 | * 执行语句 224 | * @param string $_sql 225 | * @param array $_array 226 | * 227 | * @return int|bool 228 | */ 229 | public function exec($_sql, $_array = null) 230 | { 231 | $_sql = $this->dealPrefix($_sql); 232 | if (is_array($_array)) { 233 | $stmt = $this->db->prepare($_sql); 234 | if($stmt) { 235 | $result = $stmt->execute($_array); 236 | if($result!==false){ 237 | return $result; 238 | }else{ 239 | $this->errorInfo = $stmt->errorInfo(); 240 | return false; 241 | } 242 | }else{ 243 | $this->errorInfo = $this->db->errorInfo(); 244 | return false; 245 | } 246 | } else { 247 | $result = $this->db->exec($_sql); 248 | if($result!==false){ 249 | return $result; 250 | }else{ 251 | $this->errorInfo = $this->db->errorInfo(); 252 | return false; 253 | } 254 | } 255 | } 256 | 257 | /** 258 | * 获取PDOStatement 259 | * @param string $_sql 260 | * @param array $_array 261 | * 262 | * @return \PDOStatement 263 | */ 264 | public function query($_sql, $_array = null) 265 | { 266 | $_sql = $this->dealPrefix($_sql); 267 | if (is_array($_array)) { 268 | $stmt = $this->db->prepare($_sql); 269 | if($stmt) { 270 | if($stmt->execute($_array)){ 271 | return $stmt; 272 | }else{ 273 | $this->errorInfo = $stmt->errorInfo(); 274 | return false; 275 | } 276 | }else{ 277 | $this->errorInfo = $this->db->errorInfo(); 278 | return false; 279 | } 280 | } else { 281 | if($stmt = $this->db->query($_sql)){ 282 | return $stmt; 283 | }else{ 284 | $this->errorInfo = $this->db->errorInfo(); 285 | return false; 286 | } 287 | } 288 | } 289 | 290 | /** 291 | * 查询一条结果 292 | * 293 | * @param string $_sql string 294 | * @param array $_array array 295 | * 296 | * @return mixed 297 | */ 298 | public function getRow($_sql, $_array = null) 299 | { 300 | $stmt = $this->query($_sql, $_array); 301 | if($stmt) { 302 | return $stmt->fetch($this->fetchStyle); 303 | }else{ 304 | return false; 305 | } 306 | } 307 | 308 | /** 309 | * 获取所有结果 310 | * 311 | * @param string $_sql 312 | * @param array $_array 313 | * 314 | * @return array 315 | */ 316 | public function getAll($_sql, $_array = null) 317 | { 318 | $stmt = $this->query($_sql, $_array); 319 | if($stmt) { 320 | return $stmt->fetchAll($this->fetchStyle); 321 | }else{ 322 | return false; 323 | } 324 | } 325 | 326 | /** 327 | * 获取结果数 328 | * @param string $_sql 329 | * @param array $_array 330 | * 331 | * @return int 332 | */ 333 | public function getCount($_sql, $_array = null) 334 | { 335 | $stmt = $this->query($_sql, $_array); 336 | if($stmt) { 337 | return $stmt->rowCount(); 338 | }else{ 339 | return false; 340 | } 341 | } 342 | 343 | /** 344 | * 获取一个字段值 345 | * @param string $_sql 346 | * @param array $_array 347 | * 348 | * @return int 349 | */ 350 | public function getColumn($_sql, $_array = null) 351 | { 352 | $stmt = $this->query($_sql, $_array); 353 | if($stmt) { 354 | return $stmt->fetchColumn(); 355 | }else{ 356 | return false; 357 | } 358 | } 359 | 360 | /** 361 | * 返回最后插入行的ID 362 | * 363 | * @return int|\PDOStatement 364 | */ 365 | public function lastInsertId() 366 | { 367 | return $this->db->lastInsertId(); 368 | } 369 | 370 | /** 371 | * 返回错误信息 372 | * 373 | * @return string|\PDOStatement 374 | */ 375 | public function error() 376 | { 377 | $error = $this->errorInfo; 378 | if($error){ 379 | return '['.$error[1].']'.$error[2]; 380 | }else{ 381 | return null; 382 | } 383 | } 384 | 385 | //开启事务 386 | public function beginTransaction() 387 | { 388 | return $this->db->beginTransaction(); 389 | } 390 | 391 | //提交事务 392 | public function commit() 393 | { 394 | return $this->db->commit(); 395 | } 396 | 397 | //回滚事务 398 | public function rollBack() 399 | { 400 | return $this->db->rollBack(); 401 | } 402 | 403 | function __get($name) 404 | { 405 | return $this->$name; 406 | } 407 | 408 | function __destruct() 409 | { 410 | $this->db = null; 411 | } 412 | 413 | 414 | } -------------------------------------------------------------------------------- /includes/lib/WeiboLogin.php: -------------------------------------------------------------------------------- 1 | useragent = $_SERVER['HTTP_USER_AGENT']; 13 | } 14 | 15 | private function jsonp_decode($jsonp, $assoc = false) 16 | { 17 | $jsonp = trim($jsonp); 18 | if (isset($jsonp[0]) && $jsonp[0] !== '[' && $jsonp[0] !== '{') { 19 | $begin = strpos($jsonp, '('); 20 | if (false !== $begin) { 21 | $end = strrpos($jsonp, ')'); 22 | if (false !== $end) { 23 | $jsonp = substr($jsonp, $begin + 1, $end - $begin - 1); 24 | } 25 | } 26 | } 27 | return json_decode($jsonp, $assoc); 28 | } 29 | 30 | //获取扫码登录二维码 31 | public function getqrcode() 32 | { 33 | $url = 'https://passport.weibo.com/sso/v2/qrcode/image?entry=miniblog&size=180'; 34 | $data = $this->get_curl($url, 0, $this->referrer); 35 | $arr = json_decode($data, true); 36 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 37 | $imgurl = $arr['data']['image']; 38 | parse_str(parse_url($imgurl, PHP_URL_QUERY), $query_arr); 39 | $link = $query_arr['data']; 40 | return array('code' => 0, 'imgurl' => $arr['data']['image'], 'qrid' => $arr['data']['qrid'], 'link' => $link); 41 | } elseif (isset($arr['msg'])) { 42 | return array('code' => -1, 'msg' => '获取二维码失败,' . $arr['msg']); 43 | } else { 44 | return array('code' => -1, 'msg' => '获取二维码失败'); 45 | } 46 | } 47 | 48 | //扫码登录操作 49 | public function qrlogin($qrid) 50 | { 51 | if (empty($qrid)) return array('code' => -1, 'msg' => 'qrid不能为空'); 52 | $url = 'https://passport.weibo.com/sso/v2/qrcode/check?entry=miniblog&source=miniblog&url=https%3A%2F%2Fweibo.com%2F&qrid='.$qrid.'&disp=popup'; 53 | $data = $this->get_curl($url, 0, $this->referrer); 54 | $arr = json_decode($data, true); 55 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 56 | $login_url = $arr['data']['url']; 57 | $result = $this->login_getcookie($login_url); 58 | return $result; 59 | } elseif ($arr['retcode'] == 50114001) { 60 | return array('code' => 1, 'msg' => '请用最新版微博客户端扫码'); 61 | } elseif ($arr['retcode'] == 50114002) { 62 | return array('code' => 2, 'msg' => '成功扫描,请在手机点击确认以登录'); 63 | } elseif ($arr['retcode'] == 50114003 || $arr['retcode'] == 50114004) { 64 | return array('code' => 3, 'msg' => '该二维码已过期,请重新扫描'); 65 | } elseif (isset($arr['msg'])) { 66 | return array('code' => -1, 'msg' => $arr['msg']); 67 | } else { 68 | return array('code' => -1, 'msg' => '登录失败,原因未知'); 69 | } 70 | } 71 | 72 | //通用登录后获取cookie 73 | private function login_getcookie($url) 74 | { 75 | $host = parse_url($url, PHP_URL_HOST); 76 | $data = $this->get_curl($url, 0, $this->referrer, 0, 0, 1); 77 | if(preg_match("/Location: (.*?)\r\n/i", $data['header'], $match)){ 78 | $jump_url = $match[1]; 79 | if($host == 'login.sina.com.cn'){ 80 | $cookie=[]; 81 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 82 | foreach ($matchs[1] as $val) { 83 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 84 | $key = substr($val, 0, strpos($val, '=')); 85 | $cookie[$key]=substr($val, strpos($val, '=')+1); 86 | } 87 | 88 | $wbcookie = $this->get_sso_cookie($jump_url); 89 | }else{ 90 | $wbcookie=[]; 91 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 92 | foreach ($matchs[1] as $val) { 93 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 94 | $key = substr($val, 0, strpos($val, '=')); 95 | $wbcookie[$key]=substr($val, strpos($val, '=')+1); 96 | } 97 | 98 | $cookie = $this->get_sso_cookie($jump_url); 99 | } 100 | 101 | $info = $this->get_user_info($wbcookie); 102 | 103 | return array('code' => 0, 'cookie' => $cookie, 'wbcookie' => $wbcookie, 'uid' => $info['user']['idstr'], 'nick' => $info['user']['screen_name']); 104 | } else { 105 | return array('code' => -1, 'msg' => '登录成功,获取用户信息失败'); 106 | } 107 | } 108 | 109 | private function get_user_info($wbcookie){ 110 | $cookie_str = ''; 111 | foreach($wbcookie as $key=>$value){ 112 | $cookie_str .= $key.'='.$value.'; '; 113 | } 114 | $this->useragent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36'; 115 | $data = $this->get_curl('https://weibo.com/', 0, 0, $cookie_str); 116 | preg_match('!window\.\$CONFIG = (.*?);\}!',$data,$match); 117 | return json_decode($match[1], true); 118 | } 119 | 120 | private function get_sso_cookie($jump_url){ 121 | $data = $this->get_curl($jump_url, 0, $this->referrer, 0, 0, 1); 122 | $cookie=[]; 123 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 124 | foreach ($matchs[1] as $val) { 125 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 126 | $key = substr($val, 0, strpos($val, '=')); 127 | $cookie[$key]=substr($val, strpos($val, '=')+1); 128 | } 129 | return $cookie; 130 | } 131 | 132 | //获取登录配置 133 | public function getconfig() 134 | { 135 | $data = $this->get_curl($this->referrer, 0, 0, 0, 0, 1); 136 | if(preg_match('/X-CSRF-TOKEN=(.*?);/', $data['header'], $match)){ 137 | $csrf_token = $match[1]; 138 | }else{ 139 | return array('code' => -1, 'msg' => 'X-CSRF-TOKEN获取失败'); 140 | } 141 | $url = 'https://passport.weibo.com/sso/v2/web/config'; 142 | $post = 'entry=miniblog&source=miniblog'; 143 | $cookie = 'X-CSRF-TOKEN='.$csrf_token; 144 | $headers = ['X-CSRF-TOKEN: '.$csrf_token, 'X-Requested-With: XMLHttpRequest']; 145 | $data = $this->get_curl($url, $post, $this->referrer, $cookie, $headers); 146 | $arr = json_decode($data, true); 147 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 148 | return array('code' => 0, 'data' => $arr['data'], 'csrf_token' => $csrf_token); 149 | }elseif(isset($arr['msg'])){ 150 | return array('code' => -1, 'msg' => '获取登录配置失败,'.$arr['msg']); 151 | }else{ 152 | return array('code' => -1, 'msg' => '获取登录配置失败'); 153 | } 154 | } 155 | 156 | //密码登录 157 | public function login($user, $pwd, $rsakv, $cid, $csrf_token) 158 | { 159 | $url = 'https://passport.weibo.com/sso/v2/login'; 160 | $param = [ 161 | 'entry' => 'miniblog', 162 | 'source' => 'miniblog', 163 | 'type' => '1', 164 | 'url' => 'https://weibo.com/newlogin?tabtype=weibo&gid=102803&openLoginLayer=0&url=https%3A%2F%2Fweibo.com%2F', 165 | 'username' => $user, 166 | 'pass' => $pwd, 167 | 'cid' => $cid, 168 | 'pwencode' => 'rsa', 169 | 'rsakv' => $rsakv, 170 | 'disp' => 'popup', 171 | ]; 172 | if(empty($cid)){ 173 | unset($param['cid']); 174 | } 175 | $cookie = 'X-CSRF-TOKEN='.$csrf_token; 176 | $headers = ['X-CSRF-TOKEN: '.$csrf_token, 'X-Requested-With: XMLHttpRequest']; 177 | $data = $this->get_curl($url, http_build_query($param), $this->referrer, $cookie, $headers, 1); 178 | $arr = json_decode($data['body'], true); 179 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 180 | $wbcookie=[]; 181 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 182 | foreach ($matchs[1] as $val) { 183 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 184 | $key = substr($val, 0, strpos($val, '=')); 185 | $wbcookie[$key]=substr($val, strpos($val, '=')+1); 186 | } 187 | 188 | $jump_url = $arr['data']['location']; 189 | $cookie = $this->get_sso_cookie($jump_url); 190 | 191 | $info = $this->get_user_info($wbcookie); 192 | 193 | return array('code' => 0, 'cookie' => $cookie, 'wbcookie' => $wbcookie, 'uid' => $info['user']['idstr'], 'nick' => $info['user']['screen_name']); 194 | }elseif($arr['retcode'] == 2071 && isset($arr['data']['location'])){ 195 | $protection_url = $arr['data']['location']; 196 | $host = parse_url($protection_url, PHP_URL_HOST); 197 | parse_str(parse_url($protection_url, PHP_URL_QUERY), $query_arr); 198 | if($host == 'passport.weibo.cn'){ 199 | $token = $query_arr['id']; 200 | $this->get_curl($protection_url, 0, $this->referrer); 201 | $data2 = $this->get_curl('https://passport.weibo.cn/signin/secondverify/index?first_enter=1&c=', 0, $this->referrer, 'FID='.$token); 202 | preg_match('!\"maskMobile\":\"(.*?)\"!s', $data2, $match); 203 | if($match[0]){ 204 | return array('code' => 1, 'msg' => $arr['msg'], 'type'=>'1', 'token'=>$token, 'mobile'=>$match[1], 'encrypt_mobile'=>$match[1]); 205 | }else{ 206 | return array('code' => -1, 'msg' => '手机验证信息获取失败 '.$arr['msg']); 207 | } 208 | }else{ 209 | $token = $query_arr['token']; 210 | $data2 = $this->get_curl($protection_url, 0, $this->referrer); 211 | preg_match('!(.*?)!s', $data2, $match); 212 | if($match[0]){ 213 | return array('code' => 1, 'msg' => $arr['msg'], 'type'=>'0', 'token'=>$token, 'mobile'=>$match[2], 'encrypt_mobile'=>$match[1]); 214 | }else{ 215 | return array('code' => -1, 'msg' => '手机验证信息获取失败 '.$arr['msg']); 216 | } 217 | } 218 | }elseif($arr['retcode'] == 4049 || $arr['retcode'] == 2120){ 219 | return array('code' => 2, 'msg' => $arr['msg'], 'cid' => $arr['data']['mfa_id']); 220 | }elseif(isset($arr['msg'])){ 221 | return array('code' => -1, 'msg' => $arr['msg']); 222 | }else{ 223 | return array('code' => -1, 'msg' => '登录失败,原因未知'); 224 | } 225 | } 226 | 227 | public function verifycaptcha($key, $lot_number, $captcha_output, $pass_token, $gen_time){ 228 | $url = 'https://security.weibo.com/captcha/gt'; 229 | $param = [ 230 | 'key' => $key, 231 | 'lot_number' => $lot_number, 232 | 'captcha_output' => $captcha_output, 233 | 'pass_token' => $pass_token, 234 | 'gen_time' => $gen_time, 235 | ]; 236 | $data = $this->get_curl($url.'?'.http_build_query($param), 0, $this->referrer); 237 | $arr = json_decode($data, true); 238 | if (isset($arr['retcode']) && $arr['retcode'] == 100000) { 239 | return array('code' => 0); 240 | }else{ 241 | return array('code' => -1, 'msg' => '验证码验证失败 '.$arr['msg']); 242 | } 243 | } 244 | 245 | //登录异常-发送手机验证码 246 | public function sendcode($type, $token, $encrypt_mobile) 247 | { 248 | if($type == '1'){ 249 | $url = 'https://passport.weibo.cn/signin/secondverify/ajsend?number=1&mask_mobile='.$encrypt_mobile.'&msg_type=sms'; 250 | $referrer = 'https://passport.weibo.cn/signin/secondverify/index?first_enter=1&c='; 251 | $cookie = 'FID='.$token; 252 | $data = $this->get_curl($url, 0, $referrer, $cookie); 253 | $arr = json_decode($data, true); 254 | if (isset($arr['retcode']) && $arr['retcode'] == 100000) { 255 | return array('code' => 0, 'msg' => 'succ'); 256 | } elseif (isset($arr['msg'])) { 257 | return array('code' => -1, 'msg' => $arr['msg']); 258 | } else { 259 | return array('code' => -1, 'msg' => '获取验证码失败,原因未知'); 260 | } 261 | }else{ 262 | $url = 'https://passport.weibo.com/protection/mobile/sendcode?token='.$token; 263 | $post = 'encrypt_mobile='.$encrypt_mobile; 264 | $data = $this->get_curl($url, $post, $this->referrer); 265 | $arr = json_decode($data, true); 266 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 267 | return array('code' => 0, 'msg' => 'succ'); 268 | } elseif (isset($arr['msg'])) { 269 | return array('code' => -1, 'msg' => $arr['msg']); 270 | } else { 271 | return array('code' => -1, 'msg' => '获取验证码失败,原因未知'); 272 | } 273 | } 274 | } 275 | 276 | //登录异常-提交手机验证码 277 | public function confirmcode($type, $token, $encrypt_mobile, $code) 278 | { 279 | if($type == '1'){ 280 | $url = 'https://passport.weibo.cn/signin/secondverify/ajcheck?msg_type=sms&code='.$code; 281 | $referrer = 'https://passport.weibo.cn/signin/secondverify/check'; 282 | $cookie = 'FID='.$token; 283 | $data = $this->get_curl($url, 0, $referrer, $cookie); 284 | $arr = json_decode($data, true); 285 | if (isset($arr['retcode']) && $arr['retcode'] == 100000) { 286 | $result = $this->login_getcookie($arr['data']['url']); 287 | return $result; 288 | } elseif (isset($arr['msg'])) { 289 | return array('code' => -1, 'msg' => $arr['msg']); 290 | } else { 291 | return array('code' => -1, 'msg' => '验证失败,原因未知'); 292 | } 293 | }else{ 294 | $url = 'https://passport.weibo.com/protection/mobile/confirm?token='.$token; 295 | $post = 'encrypt_mobile='.$encrypt_mobile.'&code='.$code; 296 | $data = $this->get_curl($url, $post, $this->referrer); 297 | $arr = json_decode($data, true); 298 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 299 | $result = $this->login_getcookie($arr['data']['redirect_url']); 300 | return $result; 301 | } elseif (isset($arr['msg'])) { 302 | return array('code' => -1, 'msg' => $arr['msg']); 303 | } else { 304 | return array('code' => -1, 'msg' => '验证失败,原因未知'); 305 | } 306 | } 307 | } 308 | 309 | 310 | //短信登录-发送手机验证码 311 | public function sendsms($mobile, $cid, $csrf_token) 312 | { 313 | $url = 'https://passport.weibo.com/sso/v2/sms/send'; 314 | $post = 'entry=miniblog&mobile='.$mobile; 315 | if(!empty($cid)){ 316 | $post .= '&mfa_id='.$cid; 317 | } 318 | $cookie = 'X-CSRF-TOKEN='.$csrf_token; 319 | $headers = ['X-CSRF-TOKEN: '.$csrf_token, 'X-Requested-With: XMLHttpRequest']; 320 | $data = $this->get_curl($url, $post, $this->referrer, $cookie, $headers); 321 | $arr = json_decode($data, true); 322 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 323 | return array('code' => 0, 'msg' => 'succ'); 324 | } elseif (isset($arr['retcode']) && $arr['retcode'] == 0) { 325 | return array('code' => 2, 'msg' => $arr['msg'], 'cid' => $arr['data']['mfa_id']); 326 | } elseif (isset($arr['msg'])) { 327 | return array('code' => -1, 'msg' => $arr['msg']); 328 | } else { 329 | return array('code' => -1, 'msg' => '获取验证码失败,原因未知'); 330 | } 331 | } 332 | 333 | //手机验证码登录 334 | public function smslogin($user, $code, $csrf_token) 335 | { 336 | $url = 'https://passport.weibo.com/sso/v2/login'; 337 | $param = [ 338 | 'entry' => 'miniblog', 339 | 'source' => 'miniblog', 340 | 'type' => '2', 341 | 'url' => 'https://weibo.com/newlogin?tabtype=weibo&gid=102803&openLoginLayer=0&url=https%3A%2F%2Fweibo.com%2F', 342 | 'username' => $user, 343 | 'scode' => $code, 344 | 'disp' => 'popup', 345 | ]; 346 | $cookie = 'X-CSRF-TOKEN='.$csrf_token; 347 | $headers = ['X-CSRF-TOKEN: '.$csrf_token, 'X-Requested-With: XMLHttpRequest']; 348 | $data = $this->get_curl($url, http_build_query($param), $this->referrer, $cookie, $headers, 1); 349 | $arr = json_decode($data['body'], true); 350 | if (isset($arr['retcode']) && $arr['retcode'] == 20000000) { 351 | $wbcookie=[]; 352 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 353 | foreach ($matchs[1] as $val) { 354 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 355 | $key = substr($val, 0, strpos($val, '=')); 356 | $wbcookie[$key]=substr($val, strpos($val, '=')+1); 357 | } 358 | 359 | $jump_url = $arr['data']['location']; 360 | $cookie = $this->get_sso_cookie($jump_url); 361 | 362 | $info = $this->get_user_info($wbcookie); 363 | 364 | return array('code' => 0, 'cookie' => $cookie, 'wbcookie' => $wbcookie, 'uid' => $info['user']['idstr'], 'nick' => $info['user']['screen_name']); 365 | }elseif(isset($arr['msg'])){ 366 | return array('code' => -1, 'msg' => $arr['msg']); 367 | }else{ 368 | return array('code' => -1, 'msg' => '登录失败,原因未知'); 369 | } 370 | } 371 | 372 | public function cookielogin($cookie){ 373 | $cookies = ''; 374 | foreach($cookie as $key=>$value){ 375 | $cookies .= $key.'='.$value.'; '; 376 | } 377 | $url = 'https://login.sina.com.cn/sso/login.php?url=https%3A%2F%2Fwww.weibo.com%2F&_rand='.time().'&gateway=1&service=miniblog&entry=miniblog&useticket=1&returntype=TEXT&sudaref=&_client_version=0.6.33'; 378 | $data = $this->get_curl($url, 0, $this->referrer, $cookies, 0, 1); 379 | print_r($data); 380 | $arr = json_decode($data['body'], true); 381 | if (isset($arr['retcode']) && $arr['retcode'] == 0) { 382 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 383 | foreach ($matchs[1] as $val) { 384 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 385 | $key = substr($val, 0, strpos($val, '=')); 386 | $cookie[$key]=substr($val, strpos($val, '=')+1); 387 | } 388 | $ticket = $arr['ticket']; 389 | $wbcookie = $this->weibosso($ticket); 390 | if(!$wbcookie){ 391 | return array('code' => -1, 'msg' => $this->errmsg); 392 | } 393 | return array('code' => 0, 'cookie' => $cookie, 'wbcookie' => $wbcookie, 'uid' => $arr['uid'], 'nick' => $arr['nick']); 394 | } elseif (isset($arr['retcode'])) { 395 | return array('code' => -1, 'msg' => '登录失败,登录COOKIE已失效('.$arr['retcode'].')'); 396 | } else { 397 | return array('code' => -1, 'msg' => '登录失败,登录COOKIE已失效'); 398 | } 399 | } 400 | 401 | private function weibosso($ticket){ 402 | $ssosavestate = time()+2592000; 403 | $url = 'https://passport.weibo.com/wbsso/login?ticket='.$ticket.'&ssosavestate='.$ssosavestate.'&callback=sinaSSOController.doCrossDomainCallBack&scriptId=ssoscript0&client=ssologin.js(v1.4.2)'; 404 | $data = $this->get_curl($url, 0, $this->referrer, 0, 0, 1); 405 | $arr = $this->jsonp_decode($data['body'], true); 406 | if (isset($arr['result']) && $arr['result']==true) { 407 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 408 | $cookie = []; 409 | foreach ($matchs[1] as $val) { 410 | if(strpos($val, '=deleted') || substr($val,-1)=='=') continue; 411 | $key = substr($val, 0, strpos($val, '=')); 412 | $cookie[$key]=substr($val, strpos($val, '=')+1); 413 | } 414 | return $cookie; 415 | } elseif (!empty($arr['reason'])) { 416 | $this->errmsg = '登录成功,获取微博cookie失败('.$arr['reason'].')'; 417 | return false; 418 | } else { 419 | $this->errmsg = '登录成功,获取微博cookie失败'; 420 | return false; 421 | } 422 | } 423 | 424 | public function qq_getqrcode(){ 425 | //$url='https://ssl.ptlogin2.qq.com/ptqrshow?appid=716027609&e=2&l=M&s=4&d=72&v=4&t=0.2616844'.time().'&daid=383&pt_3rd_aid=101019034'; 426 | $url='https://xui.ptlogin2.qq.com/ssl/ptqrshow?s=8&e=0&appid=716027609&type=1&t=0.492909'.time().'&daid=383&pt_3rd_aid=101019034'; 427 | $refer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&pt_3rd_aid=101019034&pt_feedback_link=https%3A%2F%2Fsupport.qq.com%2Fproducts%2F77942%3FcustomInfo%3Dweibo.com.appid101019034&theme=2&verify_theme='; 428 | $data=$this->get_curl($url,0,$refer,0,0,1); 429 | preg_match('/qrsig=(.*?);/',$data['header'],$match); 430 | if($qrsig=$match[1]){ 431 | $arr = $this->jsonp_decode($data['body'], true); 432 | return array('code'=>0,'qrsig'=>$qrsig,'qrcode'=>$arr['qrcode']); 433 | } 434 | else{ 435 | return array('code'=>-1,'msg'=>'二维码获取失败'); 436 | } 437 | } 438 | 439 | public function qq_qrlogin($qrsig){ 440 | if(empty($qrsig))return array('code'=>-1,'msg'=>'qrsig不能为空'); 441 | $url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=4-1-'.time().'000&js_ver=22072900&js_type=1&login_sig=&pt_uistyle=40&aid=716027609&daid=383&pt_3rd_aid=101019034&'; 442 | $refer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&pt_3rd_aid=101019034&pt_feedback_link=https%3A%2F%2Fsupport.qq.com%2Fproducts%2F77942%3FcustomInfo%3Dweibo.com.appid101019034&theme=2&verify_theme='; 443 | $ret = $this->get_curl($url,0,$refer,'qrsig='.$qrsig.'; '); 444 | if(preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)){ 445 | $r=explode("','",str_replace("', '","','",$arr[1])); 446 | if($r[0]==0){ 447 | preg_match('/uin=(\d+)&/',$ret,$uin); 448 | $uin=$uin[1]; 449 | $data=$this->get_curl($r[2],0,$refer,0,0,1); 450 | if($data) { 451 | $cookie=''; 452 | preg_match_all('/Set-Cookie: (.*?);/i',$data['header'],$matchs); 453 | foreach ($matchs[1] as $val) { 454 | if(substr($val,-1)=='=')continue; 455 | $cookie.=$val.'; '; 456 | } 457 | preg_match('/p_skey=(.*?);/',$cookie,$pskey); 458 | $cookie = substr($cookie,0,-2); 459 | $data=$this->get_curl('https://passport.weibo.com/othersitebind/authorize?entry=miniblog&site=qq',0,0,0,0,1); 460 | if(preg_match('/crossidccode=(.*?);/',$data['header'],$match)){ 461 | $crossidccode = $match[1]; 462 | $url = 'https://graph.qq.com/oauth2.0/authorize'; 463 | $post = 'response_type=code&client_id=101019034&redirect_uri=https%3A%2F%2Fpassport.weibo.com%2Fothersitebind%2Fbind%3Fsite%3Dqq%26state%3D'.$crossidccode.'%26bentry%3Dminiblog%26wl%3D&scope=get_info%2Cget_user_info&state=&switch=&from_ptlogin=1&src=1&update_auth=1&openapi=80901010&g_tk='.$this->getGTK($pskey[1]).'&auth_time='.time().'304&ui=E4077228-8A59-4020-A957-B5830A9509D3'; 464 | $data=$this->get_curl($url,$post,0,$cookie,0,1); 465 | if(preg_match("/Location: (.*?)\r\n/i", $data['header'], $match)){ 466 | $redirect_uri = $match[1]; 467 | return array('code'=>0,'msg'=>'succ','uin'=>$uin,'redirect_uri'=>$redirect_uri,'crossidccode'=>$crossidccode); 468 | }else{ 469 | return array('code'=>-1,'uin'=>$uin,'msg'=>'登录QQ成功,回调网站失败!'); 470 | } 471 | }else{ 472 | return array('code'=>-1,'uin'=>$uin,'msg'=>'登录QQ成功,获取crossidccode失败!'); 473 | } 474 | }else{ 475 | return array('code'=>-1,'uin'=>$uin,'msg'=>'登录QQ成功,获取相关信息失败!'); 476 | } 477 | }elseif($r[0]==65){ 478 | return array('code'=>1,'msg'=>'二维码已失效。'); 479 | }elseif($r[0]==66){ 480 | return array('code'=>2,'msg'=>'二维码未失效。'); 481 | }elseif($r[0]==67){ 482 | return array('code'=>3,'msg'=>'正在验证二维码。'); 483 | }else{ 484 | return array('code'=>-1,'msg'=>$r[4]); 485 | } 486 | }else{ 487 | return array('code'=>-1,'msg'=>$ret); 488 | } 489 | } 490 | 491 | public function qq_connect($redirect_uri, $crossidccode){ 492 | if(empty($redirect_uri) || parse_url($redirect_uri, PHP_URL_HOST)!='passport.weibo.com')return array('code'=>-1,'msg'=>'回调地址错误'); 493 | if(empty($crossidccode))return array('code'=>-1,'msg'=>'crossidccode不能为空'); 494 | $data=$this->get_curl($redirect_uri,0,0,'crossidccode='.$crossidccode,0,1); 495 | preg_match("/Location: (.*?)\r\n/i", $data['header'], $match); 496 | if($login_url = $match[1]){ 497 | if(strpos($login_url, '/sso/login.php?')){ 498 | $result = $this->login_getcookie($login_url); 499 | return $result; 500 | }else{ 501 | return array('code'=>-1,'msg'=>'该QQ未绑定微博账号!'); 502 | } 503 | }else{ 504 | return array('code'=>-1,'msg'=>'登录QQ成功,获取微博登录信息失败!'); 505 | } 506 | } 507 | 508 | private function getqrtoken($qrsig){ 509 | $len = strlen($qrsig); 510 | $hash = 0; 511 | for($i = 0; $i < $len; $i++){ 512 | $hash += (($hash << 5) & 2147483647) + ord($qrsig[$i]) & 2147483647; 513 | $hash &= 2147483647; 514 | } 515 | return $hash & 2147483647; 516 | } 517 | private function getGTK($skey){ 518 | $len = strlen($skey); 519 | $hash = 5381; 520 | for ($i = 0; $i < $len; $i++) { 521 | $hash += ($hash << 5 & 2147483647) + ord($skey[$i]) & 2147483647; 522 | $hash &= 2147483647; 523 | } 524 | return $hash & 2147483647; 525 | } 526 | 527 | 528 | private function get_curl($url, $post = 0, $referer = 0, $cookie = 0, $headers = 0, $split = 0) 529 | { 530 | $ch = curl_init(); 531 | curl_setopt($ch, CURLOPT_URL, $url); 532 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 533 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 534 | $httpheader[] = "Accept: application/json"; 535 | $httpheader[] = "Accept-Encoding: gzip,deflate,sdch"; 536 | $httpheader[] = "Accept-Language: zh-CN,zh;q=0.8"; 537 | $httpheader[] = "Connection: close"; 538 | if($headers){ 539 | $httpheader = array_merge($httpheader, $headers); 540 | } 541 | curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader); 542 | //curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); 543 | if ($post) { 544 | curl_setopt($ch, CURLOPT_POST, 1); 545 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post); 546 | } 547 | if ($split) { 548 | curl_setopt($ch, CURLOPT_HEADER, TRUE); 549 | } 550 | if ($cookie) { 551 | curl_setopt($ch, CURLOPT_COOKIE, $cookie); 552 | } 553 | if ($referer) { 554 | curl_setopt($ch, CURLOPT_REFERER, $referer); 555 | } 556 | curl_setopt($ch, CURLOPT_USERAGENT, $this->useragent); 557 | curl_setopt($ch, CURLOPT_TIMEOUT, 10); 558 | curl_setopt($ch, CURLOPT_ENCODING, "gzip"); 559 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 560 | $ret = curl_exec($ch); 561 | if($split){ 562 | $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 563 | $header = substr($ret, 0, $headerSize); 564 | $body = substr($ret, $headerSize); 565 | $ret=array(); 566 | $ret['header']=$header; 567 | $ret['body']=$body; 568 | } 569 | curl_close($ch); 570 | return $ret; 571 | } 572 | } 573 | -------------------------------------------------------------------------------- /includes/lib/WeiboTool.php: -------------------------------------------------------------------------------- 1 | cookie = $cookie; 12 | } 13 | 14 | public function checkCookie(){ 15 | $url = 'https://weibo.com/ajax/statuses/config?type=push_active'; 16 | $data = $this->get_curl($url, 0, $this->referrer, $this->cookie); 17 | $arr = json_decode($data, true); 18 | if(isset($arr['ok']) && $arr['ok']==1){ 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | public function getBasicInfo(){ 25 | $url = 'https://weibo.com/ajax/setting/getBasicInfo'; 26 | $data = $this->get_curl($url, 0, $this->referrer, $this->cookie); 27 | $arr = json_decode($data, true); 28 | if(isset($arr['ok']) && $arr['ok']==1){ 29 | return ['code'=>0, 'data'=>$arr['data']]; 30 | }elseif(isset($arr['ok']) && $arr['ok']==-100){ 31 | $this->cookiefail = true; 32 | return ['code'=>-1, 'msg'=>'获取个人基本信息失败:COOKIE已失效']; 33 | }elseif(isset($arr['message'])){ 34 | return ['code'=>-1, 'msg'=>'获取个人基本信息失败:'.$arr['message']]; 35 | }else{ 36 | return ['code'=>-1, 'msg'=>'获取个人基本信息失败:接口请求失败']; 37 | } 38 | } 39 | 40 | public function hotline(){ 41 | $url = 'https://weibo.com/ajax/side/hotSearch'; 42 | $data = $this->get_curl($url, 0, $this->referrer, $this->cookie); 43 | $arr = json_decode($data, true); 44 | if(isset($arr['ok']) && $arr['ok']==1 && isset($arr['data']['realtime'])){ 45 | $list = []; 46 | foreach($arr['data']['realtime'] as $row){ 47 | if($row['is_ad']) continue; 48 | $list[] = ['rank'=>$row['realpos'], 'category'=>$row['category'], 'content'=>$row['word'], 'time'=>$row['onboard_time'], 'num'=>$row['num'], 'label'=>$row['label_name'], 'mid'=>$row['mid']]; 49 | } 50 | return ['code'=>0, 'data'=>$list]; 51 | }elseif(isset($arr['ok']) && $arr['ok']==-100){ 52 | $this->cookiefail = true; 53 | return ['code'=>-1, 'msg'=>'获取热搜列表失败:COOKIE已失效']; 54 | }elseif(isset($arr['message'])){ 55 | return ['code'=>-1, 'msg'=>'获取热搜列表失败:'.$arr['message']]; 56 | }else{ 57 | return ['code'=>-1, 'msg'=>'获取热搜列表失败:接口请求失败']; 58 | } 59 | } 60 | 61 | public function parseVideo($oid){ 62 | $page = '/tv/show/'.$oid; 63 | $url = 'https://weibo.com/tv/api/component?page='.urlencode($page); 64 | $post = 'data={"Component_Play_Playinfo":{"oid":"'.$oid.'"}}'; 65 | $referer = 'https://weibo.com/tv/show/'.$oid; 66 | $data = $this->get_curl($url, $post, $referer, $this->cookie); 67 | $arr = json_decode($data, true); 68 | if(isset($arr['code']) && $arr['code']=='100000'){ 69 | if(isset($arr['data']['Component_Play_Playinfo'])){ 70 | $info = $arr['data']['Component_Play_Playinfo']; 71 | $result = ['title'=>$info['title'], 'author'=>$info['author'], 'author_id'=>$info['user']['id'], 'author_avatar'=>$info['avatar'], 'urls'=>$info['urls'], 'cover'=>$info['cover_image'], 'time'=>$info['real_date'], 'duration'=>$info['duration']]; 72 | return ['code'=>0, 'data'=>$result]; 73 | }else{ 74 | return ['code'=>-1, 'msg'=>'解析视频失败:视频不存在']; 75 | } 76 | }elseif(isset($arr['msg'])){ 77 | return ['code'=>-1, 'msg'=>'解析视频失败:'.$arr['msg']]; 78 | }else{ 79 | return ['code'=>-1, 'msg'=>'解析视频失败:接口请求失败']; 80 | } 81 | } 82 | 83 | public function getUserInfo($uid){ 84 | $url = 'https://weibo.com/ajax/profile/info?uid='.$uid; 85 | $data = $this->get_curl($url, 0, $this->referrer, $this->cookie); 86 | $arr = json_decode($data, true); 87 | if(isset($arr['ok']) && $arr['ok']==1 && isset($arr['data']['user'])){ 88 | $info = $arr['data']['user']; 89 | $result = ['uid'=>$info['idstr'], 'name'=>$info['screen_name'], 'avatar'=>$info['avatar_hd'], 'gender'=>$info['gender'], 'location'=>$info['location'], 'description'=>$info['description'], 'domain'=>$info['domain'], 'friends_count'=>$info['friends_count'], 'followers_count'=>$info['followers_count'], 'statuses_count'=>$info['statuses_count'], 'verified'=>$info['verified'], 'verified_reason'=>$info['verified_reason'], 'verified_type'=>$info['verified_type'], 'is_muteuser'=>$info['is_muteuser']]; 90 | return ['code'=>0, 'data'=>$result]; 91 | }elseif(isset($arr['ok']) && $arr['ok']==-100){ 92 | $this->cookiefail = true; 93 | return ['code'=>-1, 'msg'=>'获取用户信息失败:COOKIE已失效']; 94 | }elseif(isset($arr['message'])){ 95 | return ['code'=>-1, 'msg'=>'获取用户信息失败:'.$arr['message']]; 96 | }else{ 97 | return ['code'=>-1, 'msg'=>'获取用户信息失败:接口请求失败']; 98 | } 99 | } 100 | 101 | public function upload($file_path){ 102 | $file_content = file_get_contents($file_path); 103 | $params = [ 104 | 'file_source' => '1', 105 | 'cs' => crc32($file_content), 106 | 'ent' => 'miniblog', 107 | 'appid' => '339644097', 108 | 'uid' => '', 109 | 'raw_md5' => md5_file($file_path), 110 | 'ori' => '1', 111 | 'mpos' => '1', 112 | 'pri' => '0', 113 | 'request_id' => self::getMillisecond(), 114 | 'file_size' => filesize($file_path) 115 | ]; 116 | $url = 'https://picupload.weibo.com/interface/upload.php?' . http_build_query($params); 117 | $data = $this->get_curl($url, $file_content, $this->referrer, $this->cookie); 118 | $arr = json_decode($data, true); 119 | if(isset($arr['ret']) && $arr['ret']==true){ 120 | $pid = $arr['pic']['pid']; 121 | return ['code'=>0, 'data'=>'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://fc.sinaimg.cn/large/'.$pid.'.jpg']; 122 | }else{ 123 | if($arr['errno'] == -1){ 124 | $this->cookiefail = true; 125 | return ['code'=>-1, 'msg'=>'上传失败,COOKIE已失效']; 126 | }else{ 127 | return ['code'=>-1, 'msg'=>'上传失败,请稍后再试']; 128 | } 129 | } 130 | return false; 131 | } 132 | 133 | static private function getMillisecond() { 134 | list($s1, $s2) = explode(' ', microtime()); 135 | return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); 136 | } 137 | 138 | private function get_curl($url, $post = 0, $referer = 0, $cookie = 0, $header = 0) 139 | { 140 | $ch = curl_init(); 141 | curl_setopt($ch, CURLOPT_URL, $url); 142 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 143 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 144 | $httpheader[] = "Accept: application/json"; 145 | $httpheader[] = "Accept-Encoding: gzip,deflate,sdch"; 146 | $httpheader[] = "Accept-Language: zh-CN,zh;q=0.8"; 147 | $httpheader[] = "Connection: close"; 148 | curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader); 149 | if ($post) { 150 | curl_setopt($ch, CURLOPT_POST, 1); 151 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post); 152 | } 153 | if ($header) { 154 | curl_setopt($ch, CURLOPT_HEADER, TRUE); 155 | } 156 | if ($cookie) { 157 | curl_setopt($ch, CURLOPT_COOKIE, $cookie); 158 | } 159 | if ($referer) { 160 | curl_setopt($ch, CURLOPT_REFERER, $referer); 161 | } 162 | curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'); 163 | curl_setopt($ch, CURLOPT_TIMEOUT, 10); 164 | curl_setopt($ch, CURLOPT_ENCODING, "gzip"); 165 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 166 | $ret = curl_exec($ch); 167 | curl_close($ch); 168 | return $ret; 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /includes/lib/mail/Aliyun.php: -------------------------------------------------------------------------------- 1 | AccessKeyId = $AccessKeyId; 13 | $this->AccessKeySecret = $AccessKeySecret; 14 | } 15 | private function aliyunSignature($parameters, $accessKeySecret, $method) 16 | { 17 | ksort($parameters); 18 | $canonicalizedQueryString = ''; 19 | foreach ($parameters as $key => $value) { 20 | if($value === null) continue; 21 | $canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value); 22 | } 23 | $stringToSign = $method . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1)); 24 | $signature = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&", true)); 25 | 26 | return $signature; 27 | } 28 | private function percentEncode($str) 29 | { 30 | $search = ['+', '*', '%7E']; 31 | $replace = ['%20', '%2A', '~']; 32 | return str_replace($search, $replace, urlencode($str)); 33 | } 34 | public function send($to, $sub, $msg, $from, $from_name) 35 | { 36 | if (empty($this->AccessKeyId) || empty($this->AccessKeySecret)) return false; 37 | $url = 'https://dm.aliyuncs.com/'; 38 | $data = array( 39 | 'Action' => 'SingleSendMail', 40 | 'AccountName' => $from, 41 | 'ReplyToAddress' => 'false', 42 | 'AddressType' => 1, 43 | 'ToAddress' => $to, 44 | 'FromAlias' => $from_name, 45 | 'Subject' => $sub, 46 | 'HtmlBody' => $msg, 47 | 'Format' => 'JSON', 48 | 'Version' => '2015-11-23', 49 | 'AccessKeyId' => $this->AccessKeyId, 50 | 'SignatureMethod' => 'HMAC-SHA1', 51 | 'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'), 52 | 'SignatureVersion' => '1.0', 53 | 'SignatureNonce' => random(8) 54 | ); 55 | $data['Signature'] = $this->aliyunSignature($data, $this->AccessKeySecret, 'POST'); 56 | $ch = curl_init($url); 57 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 58 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 59 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 60 | curl_setopt($ch, CURLOPT_TIMEOUT, 10); 61 | curl_setopt($ch, CURLOPT_POST, 1); 62 | curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); 63 | $json = curl_exec($ch); 64 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 65 | curl_close($ch); 66 | $arr = json_decode($json, true); 67 | if ($httpCode == 200) { 68 | return true; 69 | } else { 70 | return $arr['Message']; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /includes/lib/mail/PHPMailer/Exception.php: -------------------------------------------------------------------------------- 1 | ' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "
    \n"; } } -------------------------------------------------------------------------------- /includes/lib/mail/PHPMailer/SMTP.php: -------------------------------------------------------------------------------- 1 | '/[\d]{3} OK id=(.*)/', 'sendmail' => '/[\d]{3} 2\.0\.0 (.*) Message/', 'postfix' => '/[\d]{3} 2\.0\.0 Ok: queued as (.*)/', 'Microsoft_ESMTP' => '/[0-9]{3} 2\.[\d]\.0 (.*)@(?:.*) Queued mail for delivery/', 'Amazon_SES' => '/[\d]{3} Ok (.*)/', 'SendGrid' => '/[\d]{3} Ok: queued as (.*)/', 'CampaignMonitor' => '/[\d]{3} 2\.0\.0 OK:([a-zA-Z\d]{48})/', 'Haraka' => '/[\d]{3} Message Queued \((.*)\)/', 'ZoneMTA' => '/[\d]{3} Message queued as (.*)/', 'Mailjet' => '/[\d]{3} OK queued as (.*)/', ]; public static $xclient_allowed_attributes = [ 'NAME', 'ADDR', 'PORT', 'PROTO', 'HELO', 'LOGIN', 'DESTADDR', 'DESTPORT' ]; protected $last_smtp_transaction_id; protected $smtp_conn; protected $error = [ 'error' => '', 'detail' => '', 'smtp_code' => '', 'smtp_code_ex' => '', ]; protected $helo_rply; protected $server_caps; protected $last_reply = ''; protected function edebug($str, $level = 0) { if ($level > $this->do_debug) { return; } if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) { $this->Debugoutput->debug(rtrim($str, "\r\n")); return; } if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) { call_user_func($this->Debugoutput, $str, $level); return; } switch ($this->Debugoutput) { case 'error_log': error_log($str); break; case 'html': echo gmdate('Y-m-d H:i:s'), ' ', htmlentities( preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, 'UTF-8' ), "
    \n"; break; case 'echo': default: $str = preg_replace('/\r\n|\r/m', "\n", $str); echo gmdate('Y-m-d H:i:s'), "\t", trim( str_replace( "\n", "\n \t ", trim($str) ) ), "\n"; } } public function connect($host, $port = null, $timeout = 30, $options = []) { $this->setError(''); if ($this->connected()) { $this->setError('Already connected to a server'); return false; } if (empty($port)) { $port = self::DEFAULT_PORT; } $this->edebug( "Connection: opening to $host:$port, timeout=$timeout, options=" . (count($options) > 0 ? var_export($options, true) : 'array()'), self::DEBUG_CONNECTION ); $this->smtp_conn = $this->getSMTPConnection($host, $port, $timeout, $options); if ($this->smtp_conn === false) { return false; } $this->edebug('Connection: opened', self::DEBUG_CONNECTION); $this->last_reply = $this->get_lines(); $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); $responseCode = (int)substr($this->last_reply, 0, 3); if ($responseCode === 220) { return true; } if ($responseCode === 554) { $this->quit(); } $this->edebug('Connection: closing due to error', self::DEBUG_CONNECTION); $this->close(); return false; } protected function getSMTPConnection($host, $port = null, $timeout = 30, $options = []) { static $streamok; if (null === $streamok) { $streamok = function_exists('stream_socket_client'); } $errno = 0; $errstr = ''; if ($streamok) { $socket_context = stream_context_create($options); set_error_handler([$this, 'errorHandler']); $connection = stream_socket_client( $host . ':' . $port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $socket_context ); } else { $this->edebug( 'Connection: stream_socket_client not available, falling back to fsockopen', self::DEBUG_CONNECTION ); set_error_handler([$this, 'errorHandler']); $connection = fsockopen( $host, $port, $errno, $errstr, $timeout ); } restore_error_handler(); if (!is_resource($connection)) { $this->setError( 'Failed to connect to server', '', (string) $errno, $errstr ); $this->edebug( 'SMTP ERROR: ' . $this->error['error'] . ": $errstr ($errno)", self::DEBUG_CLIENT ); return false; } if (strpos(PHP_OS, 'WIN') !== 0) { $max = (int)ini_get('max_execution_time'); if (0 !== $max && $timeout > $max && strpos(ini_get('disable_functions'), 'set_time_limit') === false) { @set_time_limit($timeout); } stream_set_timeout($connection, $timeout, 0); } return $connection; } public function startTLS() { if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { return false; } $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; } set_error_handler([$this, 'errorHandler']); $crypto_ok = stream_socket_enable_crypto( $this->smtp_conn, true, $crypto_method ); restore_error_handler(); return (bool) $crypto_ok; } public function authenticate( $username, $password, $authtype = null, $OAuth = null ) { if (!$this->server_caps) { $this->setError('Authentication is not allowed before HELO/EHLO'); return false; } if (array_key_exists('EHLO', $this->server_caps)) { if (!array_key_exists('AUTH', $this->server_caps)) { $this->setError('Authentication is not allowed at this stage'); return false; } $this->edebug('Auth method requested: ' . ($authtype ?: 'UNSPECIFIED'), self::DEBUG_LOWLEVEL); $this->edebug( 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), self::DEBUG_LOWLEVEL ); if (null !== $authtype && !in_array($authtype, $this->server_caps['AUTH'], true)) { $this->edebug('Requested auth method not available: ' . $authtype, self::DEBUG_LOWLEVEL); $authtype = null; } if (empty($authtype)) { foreach (['CRAM-MD5', 'LOGIN', 'PLAIN', 'XOAUTH2'] as $method) { if (in_array($method, $this->server_caps['AUTH'], true)) { $authtype = $method; break; } } if (empty($authtype)) { $this->setError('No supported authentication methods found'); return false; } $this->edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL); } if (!in_array($authtype, $this->server_caps['AUTH'], true)) { $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); return false; } } elseif (empty($authtype)) { $authtype = 'LOGIN'; } switch ($authtype) { case 'PLAIN': if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { return false; } if ( !$this->sendCommand( 'User & Password', base64_encode("\0" . $username . "\0" . $password), 235 ) ) { return false; } break; case 'LOGIN': if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { return false; } if (!$this->sendCommand('Username', base64_encode($username), 334)) { return false; } if (!$this->sendCommand('Password', base64_encode($password), 235)) { return false; } break; case 'CRAM-MD5': if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { return false; } $challenge = base64_decode(substr($this->last_reply, 4)); $response = $username . ' ' . $this->hmac($challenge, $password); return $this->sendCommand('Username', base64_encode($response), 235); case 'XOAUTH2': if (null === $OAuth) { return false; } $oauth = $OAuth->getOauth64(); if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { return false; } break; default: $this->setError("Authentication method \"$authtype\" is not supported"); return false; } return true; } protected function hmac($data, $key) { if (function_exists('hash_hmac')) { return hash_hmac('md5', $data, $key); } $bytelen = 64; if (strlen($key) > $bytelen) { $key = pack('H*', md5($key)); } $key = str_pad($key, $bytelen, chr(0x00)); $ipad = str_pad('', $bytelen, chr(0x36)); $opad = str_pad('', $bytelen, chr(0x5c)); $k_ipad = $key ^ $ipad; $k_opad = $key ^ $opad; return md5($k_opad . pack('H*', md5($k_ipad . $data))); } public function connected() { if (is_resource($this->smtp_conn)) { $sock_status = stream_get_meta_data($this->smtp_conn); if ($sock_status['eof']) { $this->edebug( 'SMTP NOTICE: EOF caught while checking if connected', self::DEBUG_CLIENT ); $this->close(); return false; } return true; } return false; } public function close() { $this->server_caps = null; $this->helo_rply = null; if (is_resource($this->smtp_conn)) { fclose($this->smtp_conn); $this->smtp_conn = null; $this->edebug('Connection: closed', self::DEBUG_CONNECTION); } } public function data($msg_data) { if (!$this->sendCommand('DATA', 'DATA', 354)) { return false; } $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data)); $field = substr($lines[0], 0, strpos($lines[0], ':')); $in_headers = false; if (!empty($field) && strpos($field, ' ') === false) { $in_headers = true; } foreach ($lines as $line) { $lines_out = []; if ($in_headers && $line === '') { $in_headers = false; } while (isset($line[self::MAX_LINE_LENGTH])) { $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); if (!$pos) { $pos = self::MAX_LINE_LENGTH - 1; $lines_out[] = substr($line, 0, $pos); $line = substr($line, $pos); } else { $lines_out[] = substr($line, 0, $pos); $line = substr($line, $pos + 1); } if ($in_headers) { $line = "\t" . $line; } } $lines_out[] = $line; foreach ($lines_out as $line_out) { if (!empty($line_out) && $line_out[0] === '.') { $line_out = '.' . $line_out; } $this->client_send($line_out . static::LE, 'DATA'); } } $savetimelimit = $this->Timelimit; $this->Timelimit *= 2; $result = $this->sendCommand('DATA END', '.', 250); $this->recordLastTransactionID(); $this->Timelimit = $savetimelimit; return $result; } public function hello($host = '') { if ($this->sendHello('EHLO', $host)) { return true; } if (substr($this->helo_rply, 0, 3) == '421') { return false; } return $this->sendHello('HELO', $host); } protected function sendHello($hello, $host) { $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); $this->helo_rply = $this->last_reply; if ($noerror) { $this->parseHelloFields($hello); } else { $this->server_caps = null; } return $noerror; } protected function parseHelloFields($type) { $this->server_caps = []; $lines = explode("\n", $this->helo_rply); foreach ($lines as $n => $s) { $s = trim(substr($s, 4)); if (empty($s)) { continue; } $fields = explode(' ', $s); if (!empty($fields)) { if (!$n) { $name = $type; $fields = $fields[0]; } else { $name = array_shift($fields); switch ($name) { case 'SIZE': $fields = ($fields ? $fields[0] : 0); break; case 'AUTH': if (!is_array($fields)) { $fields = []; } break; default: $fields = true; } } $this->server_caps[$name] = $fields; } } } public function mail($from) { $useVerp = ($this->do_verp ? ' XVERP' : ''); return $this->sendCommand( 'MAIL FROM', 'MAIL FROM:<' . $from . '>' . $useVerp, 250 ); } public function quit($close_on_error = true) { $noerror = $this->sendCommand('QUIT', 'QUIT', 221); $err = $this->error; if ($noerror || $close_on_error) { $this->close(); $this->error = $err; } return $noerror; } public function recipient($address, $dsn = '') { if (empty($dsn)) { $rcpt = 'RCPT TO:<' . $address . '>'; } else { $dsn = strtoupper($dsn); $notify = []; if (strpos($dsn, 'NEVER') !== false) { $notify[] = 'NEVER'; } else { foreach (['SUCCESS', 'FAILURE', 'DELAY'] as $value) { if (strpos($dsn, $value) !== false) { $notify[] = $value; } } } $rcpt = 'RCPT TO:<' . $address . '> NOTIFY=' . implode(',', $notify); } return $this->sendCommand( 'RCPT TO', $rcpt, [250, 251] ); } public function xclient(array $vars) { $xclient_options = ""; foreach ($vars as $key => $value) { if (in_array($key, SMTP::$xclient_allowed_attributes)) { $xclient_options .= " {$key}={$value}"; } } if (!$xclient_options) { return true; } return $this->sendCommand('XCLIENT', 'XCLIENT' . $xclient_options, 250); } public function reset() { return $this->sendCommand('RSET', 'RSET', 250); } protected function sendCommand($command, $commandstring, $expect) { if (!$this->connected()) { $this->setError("Called $command without being connected"); return false; } if ((strpos($commandstring, "\n") !== false) || (strpos($commandstring, "\r") !== false)) { $this->setError("Command '$command' contained line breaks"); return false; } $this->client_send($commandstring . static::LE, $command); $this->last_reply = $this->get_lines(); $matches = []; if (preg_match('/^([\d]{3})[ -](?:([\d]\\.[\d]\\.[\d]{1,2}) )?/', $this->last_reply, $matches)) { $code = (int) $matches[1]; $code_ex = (count($matches) > 2 ? $matches[2] : null); $detail = preg_replace( "/{$code}[ -]" . ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . '/m', '', $this->last_reply ); } else { $code = (int) substr($this->last_reply, 0, 3); $code_ex = null; $detail = substr($this->last_reply, 4); } $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); if (!in_array($code, (array) $expect, true)) { $this->setError( "$command command failed", $detail, $code, $code_ex ); $this->edebug( 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, self::DEBUG_CLIENT ); return false; } if ($command !== 'RSET') { $this->setError(''); } return true; } public function sendAndMail($from) { return $this->sendCommand('SAML', "SAML FROM:$from", 250); } public function verify($name) { return $this->sendCommand('VRFY', "VRFY $name", [250, 251]); } public function noop() { return $this->sendCommand('NOOP', 'NOOP', 250); } public function turn() { $this->setError('The SMTP TURN command is not implemented'); $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); return false; } public function client_send($data, $command = '') { if ( self::DEBUG_LOWLEVEL > $this->do_debug && in_array($command, ['User & Password', 'Username', 'Password'], true) ) { $this->edebug('CLIENT -> SERVER: [credentials hidden]', self::DEBUG_CLIENT); } else { $this->edebug('CLIENT -> SERVER: ' . $data, self::DEBUG_CLIENT); } set_error_handler([$this, 'errorHandler']); $result = fwrite($this->smtp_conn, $data); restore_error_handler(); return $result; } public function getError() { return $this->error; } public function getServerExtList() { return $this->server_caps; } public function getServerExt($name) { if (!$this->server_caps) { $this->setError('No HELO/EHLO was sent'); return null; } if (!array_key_exists($name, $this->server_caps)) { if ('HELO' === $name) { return $this->server_caps['EHLO']; } if ('EHLO' === $name || array_key_exists('EHLO', $this->server_caps)) { return false; } $this->setError('HELO handshake was used; No information about server extensions available'); return null; } return $this->server_caps[$name]; } public function getLastReply() { return $this->last_reply; } protected function get_lines() { if (!is_resource($this->smtp_conn)) { return ''; } $data = ''; $endtime = 0; stream_set_timeout($this->smtp_conn, $this->Timeout); if ($this->Timelimit > 0) { $endtime = time() + $this->Timelimit; } $selR = [$this->smtp_conn]; $selW = null; while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { set_error_handler([$this, 'errorHandler']); $n = stream_select($selR, $selW, $selW, $this->Timelimit); restore_error_handler(); if ($n === false) { $message = $this->getError()['detail']; $this->edebug( 'SMTP -> get_lines(): select failed (' . $message . ')', self::DEBUG_LOWLEVEL ); if (stripos($message, 'interrupted system call') !== false) { $this->edebug( 'SMTP -> get_lines(): retrying stream_select', self::DEBUG_LOWLEVEL ); $this->setError(''); continue; } break; } if (!$n) { $this->edebug( 'SMTP -> get_lines(): select timed-out in (' . $this->Timelimit . ' sec)', self::DEBUG_LOWLEVEL ); break; } $str = @fgets($this->smtp_conn, self::MAX_REPLY_LENGTH); $this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL); $data .= $str; if (!isset($str[3]) || $str[3] === ' ' || $str[3] === "\r" || $str[3] === "\n") { break; } $info = stream_get_meta_data($this->smtp_conn); if ($info['timed_out']) { $this->edebug( 'SMTP -> get_lines(): stream timed-out (' . $this->Timeout . ' sec)', self::DEBUG_LOWLEVEL ); break; } if ($endtime && time() > $endtime) { $this->edebug( 'SMTP -> get_lines(): timelimit reached (' . $this->Timelimit . ' sec)', self::DEBUG_LOWLEVEL ); break; } } return $data; } public function setVerp($enabled = false) { $this->do_verp = $enabled; } public function getVerp() { return $this->do_verp; } protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') { $this->error = [ 'error' => $message, 'detail' => $detail, 'smtp_code' => $smtp_code, 'smtp_code_ex' => $smtp_code_ex, ]; } public function setDebugOutput($method = 'echo') { $this->Debugoutput = $method; } public function getDebugOutput() { return $this->Debugoutput; } public function setDebugLevel($level = 0) { $this->do_debug = $level; } public function getDebugLevel() { return $this->do_debug; } public function setTimeout($timeout = 0) { $this->Timeout = $timeout; } public function getTimeout() { return $this->Timeout; } protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0) { $notice = 'Connection failed.'; $this->setError( $notice, $errmsg, (string) $errno ); $this->edebug( "$notice Error #$errno: $errmsg [$errfile line $errline]", self::DEBUG_CONNECTION ); } protected function recordLastTransactionID() { $reply = $this->getLastReply(); if (empty($reply)) { $this->last_smtp_transaction_id = null; } else { $this->last_smtp_transaction_id = false; foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) { $matches = []; if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) { $this->last_smtp_transaction_id = trim($matches[1]); break; } } } return $this->last_smtp_transaction_id; } public function getLastTransactionID() { return $this->last_smtp_transaction_id; } } -------------------------------------------------------------------------------- /includes/lib/mail/Sendcloud.php: -------------------------------------------------------------------------------- 1 | apiUser = $apiUser; 10 | $this->apiKey = $apiKey; 11 | } 12 | public function send($to, $sub, $msg, $from, $from_name){ 13 | if(empty($this->apiUser)||empty($this->apiKey))return false; 14 | $url='http://api.sendcloud.net/apiv2/mail/send'; 15 | $data=array( 16 | 'apiUser' => $this->apiUser, 17 | 'apiKey' => $this->apiKey, 18 | 'from' => $from, 19 | 'fromName' => $from_name, 20 | 'to' => $to, 21 | 'subject' => $sub, 22 | 'html' => $msg); 23 | $ch=curl_init($url); 24 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 25 | curl_setopt($ch, CURLOPT_TIMEOUT, 10); 26 | curl_setopt($ch, CURLOPT_POST, 1); 27 | curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 28 | $json=curl_exec($ch); 29 | curl_close($ch); 30 | $arr=json_decode($json,true); 31 | if($arr['statusCode']==200){ 32 | return true; 33 | }else{ 34 | return implode("\n",$arr['message']); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | window.location.href='./admin/';"); 5 | -------------------------------------------------------------------------------- /install/index.php: -------------------------------------------------------------------------------- 1 | $host, 42 | 'port' => $port, 43 | 'user' => $user, 44 | 'pwd' => $pwd, 45 | 'dbname' => $database, 46 | 'dbqz' => $dbqz 47 | ); 48 | $config=" '{$host}', //数据库服务器 52 | 'port' => {$port}, //数据库端口 53 | 'user' => '{$user}', //数据库用户名 54 | 'pwd' => '{$pwd}', //数据库密码 55 | 'dbname' => '{$database}', //数据库名 56 | 'prefix' => '{$dbqz}' //数据表前缀 57 | ); 58 | "; 59 | } 60 | if(empty($errorMsg)){ 61 | try{ 62 | $DB=new PDO("mysql:host=".$dbconfig['host'].";dbname=".$dbconfig['dbname'].";port=".$dbconfig['port'],$dbconfig['user'],$dbconfig['pwd']); 63 | }catch(Exception $e){ 64 | if($e->getCode() == 2002){ 65 | $errorMsg='连接数据库失败:数据库地址填写错误!'; 66 | }elseif($e->getCode() == 1045){ 67 | $errorMsg='连接数据库失败:数据库用户名或密码填写错误!'; 68 | }elseif($e->getCode() == 1049){ 69 | $errorMsg='连接数据库失败:数据库名不存在!'; 70 | }else{ 71 | $errorMsg='连接数据库失败:'.$e->getMessage(); 72 | } 73 | } 74 | if(empty($errorMsg)){ 75 | $DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); 76 | $DB->exec("set sql_mode = ''"); 77 | $DB->exec("set names utf8"); 78 | $mysqlversion = $DB->query("select version()")->fetchColumn(); 79 | if(version_compare($mysqlversion, '5.5.3', '<')){ 80 | $errorMsg='MySQL数据库版本太低,需要MySQL 5.6或以上版本!'; 81 | } 82 | if(!$_GET['jump'] && !file_put_contents($databaseFile, $config)){ 83 | $errorMsg='保存失败,请确保网站根目录有写入权限'; 84 | } 85 | } 86 | } 87 | }elseif($step==4){ 88 | include '../config.php'; 89 | if(!$dbconfig['user']||!$dbconfig['pwd']||!$dbconfig['dbname']) { 90 | $errorMsg='请先填写好数据库并保存后再安装!'; 91 | }else{ 92 | try{ 93 | $DB=new PDO("mysql:host=".$dbconfig['host'].";dbname=".$dbconfig['dbname'].";port=".$dbconfig['port'],$dbconfig['user'],$dbconfig['pwd']); 94 | }catch(Exception $e){ 95 | $errorMsg='连接数据库失败:'.$e->getMessage(); 96 | } 97 | if(empty($errorMsg) && !$_GET['jump']){ 98 | $dbqz = $dbconfig['prefix']; 99 | $DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); 100 | $DB->exec("set sql_mode = ''"); 101 | $DB->exec("set names utf8"); 102 | $sqls=file_get_contents('install.sql'); 103 | $sqls=explode(';', $sqls); 104 | $sqls[]="INSERT INTO `".$dbqz."config` VALUES ('syskey', '".random(20)."')"; 105 | $sqls[]="INSERT INTO `".$dbqz."config` VALUES ('apikey', '".random(16)."')"; 106 | $sqls[]="INSERT INTO `".$dbqz."config` VALUES ('cookie_key', '".random(16)."')"; 107 | $success=0;$error=0;$errorMsg=null; 108 | foreach ($sqls as $value) { 109 | $value=trim($value); 110 | if(empty($value))continue; 111 | if($DB->exec($value)===false){ 112 | $error++; 113 | $dberror=$DB->errorInfo(); 114 | $errorMsg.=$dberror[2]."
    "; 115 | }else{ 116 | $success++; 117 | } 118 | } 119 | } 120 | if(empty($errorMsg)){ 121 | $lock_status = file_put_contents("install.lock",'安装锁'); 122 | $step = 5; 123 | } 124 | } 125 | } 126 | 127 | ?> 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 微博API - 安装程序 136 | 137 | 138 | 139 |

    140 |
    141 |
    142 |

    微博API - 安装程序

    143 |
    144 | 147 |
    MYSQL数据库信息配置
    148 |
    149 |
    150 |
    151 |
    152 | 153 |
    154 | 155 |
    156 |
    157 |
    158 | 159 |
    160 | 161 |
    162 |
    163 |
    164 | 165 |
    166 | 167 |
    168 |
    169 |
    170 | 171 |
    172 | 173 |
    174 |
    175 |
    176 | 177 |
    178 | 179 |
    180 |
    181 |
    182 |
    183 | 184 |
    185 |
    186 |
    187 |
    188 | (如果已事先填写好config.php相关数据库配置,请 点击此处 跳过这一步!) 189 |
    190 |
    191 |
    192 |
    193 |
    194 | 195 |
    保存数据库配置
    196 |
    197 | '.$errorMsg.'
    '; 200 | }else{ 201 | echo ''; 202 | if($DB->query("select * from ".$dbconfig['dbqz']."_config")){ 203 | ?> 204 |
    系统检测到你已安装过微博API
    205 |
    206 | 跳过安装数据表 207 |
    208 |
    209 | 强制全新安装 210 |
    211 | 212 | 215 | 218 |
    219 | 220 |
    安装数据表
    221 |
    222 | 223 | 224 | 225 |
    226 | 227 |
    安装完成
    228 |
    229 | 0){?> 230 |
      231 |
    • 1、系统已成功安装完毕!
    • 232 |
    • 2、后台地址:/admin/ 密码:123456
    • 233 |
    • 3、请及时修改后台管理员密码!
    • 234 |
    • 4、你的空间不支持本地文件读写,请自行在 /install/ 目录建立 install.lock 文件!
    • 235 |
    • 进入网站后台
    • 236 |
    237 |
    238 | 239 |
    安装环境检测
    240 |
    241 | 支持'; 245 | }else{ 246 | $check[2]='不支持'; 247 | $install=false; 248 | } 249 | if(class_exists("PDO")){ 250 | $check[0]='支持'; 251 | }else{ 252 | $check[0]='不支持'; 253 | $install=false; 254 | } 255 | if(is_writable($databaseFile)) { 256 | $check[1]='支持'; 257 | }else{ 258 | $check[1]='不支持'; 259 | } 260 | if(version_compare(PHP_VERSION,'7.1.0','<')){ 261 | $check[3]='不支持'; 262 | $install=false; 263 | }else{ 264 | $check[3]='支持'; 265 | } 266 | 267 | ?> 268 |
      269 |
    • PHP版本>=7.1
    • 270 |
    • PDO_MYSQL组件
    • 271 |
    • CURL组件
    • 272 |
    • 主目录写入权限
    • 273 |
    • 成功安装后安装文件就会锁定,如需重新安装,请手动删除install目录下install.lock配置文件!
    • 274 | 检测通过,下一步'; 276 | ?> 277 |
    278 |
    279 | 280 |
    281 | 284 |
    285 |
    286 |
    287 | 288 | 289 | -------------------------------------------------------------------------------- /install/install.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `weiboapi_config`; 2 | CREATE TABLE `weiboapi_config` ( 3 | `k` varchar(32) NOT NULL, 4 | `v` text NULL, 5 | PRIMARY KEY (`k`) 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 7 | 8 | INSERT INTO `weiboapi_config` VALUES ('admin_user', 'admin'); 9 | INSERT INTO `weiboapi_config` VALUES ('admin_pwd', '123456'); 10 | INSERT INTO `weiboapi_config` VALUES ('ip_type', '0'); 11 | INSERT INTO `weiboapi_config` VALUES ('white_list', ''); 12 | INSERT INTO `weiboapi_config` VALUES ('mail_open', '0'); 13 | INSERT INTO `weiboapi_config` VALUES ('mail_cloud', '0'); 14 | INSERT INTO `weiboapi_config` VALUES ('mail_smtp', 'smtp.qq.com'); 15 | INSERT INTO `weiboapi_config` VALUES ('mail_port', '465'); 16 | INSERT INTO `weiboapi_config` VALUES ('mail_name', ''); 17 | INSERT INTO `weiboapi_config` VALUES ('mail_pwd', ''); 18 | INSERT INTO `weiboapi_config` VALUES ('sitename', '微博API管理中心'); 19 | INSERT INTO `weiboapi_config` VALUES ('cache_time', '300'); 20 | INSERT INTO `weiboapi_config` VALUES ('cache_clean', ''); 21 | 22 | 23 | DROP TABLE IF EXISTS `weiboapi_account`; 24 | CREATE TABLE `weiboapi_account` ( 25 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 26 | `uid` varchar(15) NOT NULL, 27 | `nickname` varchar(150) NOT NULL, 28 | `loginname` varchar(100) DEFAULT NULL, 29 | `cookie_login` text DEFAULT NULL, 30 | `cookie_weibo` text DEFAULT NULL, 31 | `addtime` datetime DEFAULT NULL, 32 | `usetime` datetime DEFAULT NULL, 33 | `checktime` datetime DEFAULT NULL, 34 | `refreshtime` datetime DEFAULT NULL, 35 | `status` tinyint(1) NOT NULL DEFAULT 0, 36 | PRIMARY KEY (`id`), 37 | UNIQUE KEY `uid`(`uid`) 38 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 39 | 40 | DROP TABLE IF EXISTS `weiboapi_log`; 41 | CREATE TABLE `weiboapi_log` ( 42 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 43 | `aid` int(11) NOT NULL, 44 | `action` varchar(20) NOT NULL, 45 | `time` datetime NOT NULL, 46 | PRIMARY KEY (`id`), 47 | KEY `aid` (`aid`) 48 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 49 | 50 | DROP TABLE IF EXISTS `weiboapi_cache`; 51 | CREATE TABLE `weiboapi_cache` ( 52 | `key` varchar(32) NOT NULL, 53 | `data` mediumtext DEFAULT NULL, 54 | `time` int(11) NOT NULL, 55 | PRIMARY KEY (`key`) 56 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; --------------------------------------------------------------------------------