更新3.0
6
.env
@@ -1,5 +1,5 @@
|
||||
APP_DEBUG = false
|
||||
SYSTEM_SALT= YAdmin
|
||||
APP_DEBUG = true
|
||||
SYSTEM_SALT= admin
|
||||
|
||||
[APP]
|
||||
DEFAULT_TIMEZONE = Asia/Chongqing
|
||||
@@ -7,7 +7,7 @@ DEFAULT_TIMEZONE = Asia/Chongqing
|
||||
[DATABASE]
|
||||
TYPE = mysql
|
||||
HOSTNAME = 127.0.0.1
|
||||
DATABASE = www_dj_com
|
||||
DATABASE = www_abc_com
|
||||
USERNAME = 123456
|
||||
PASSWORD = 123456
|
||||
HOSTPORT = 3306
|
||||
|
||||
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
/.svn
|
||||
/.vscode
|
||||
runtime
|
||||
nginx.htaccess
|
||||
.env
|
||||
65
README.md
@@ -10,8 +10,18 @@
|
||||
|
||||
如有任何问题或建议,欢迎交流探讨! 😊
|
||||
|
||||
> **声明**:本项目由 Trae AI 辅助编写。由于本人时间有限,仅在空闲时维护。如遇使用问题,请优先自行排查,感谢理解!
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v3.0
|
||||
|
||||
- 新增 项目安装向导,简化部署流程
|
||||
- 新增 多网盘转存导入功能,支持夸克、阿里、百度、UC
|
||||
- 优化 解决部分数据导致的路由报错
|
||||
- 优化 AI重构转存功能,提升稳定性与效率
|
||||
|
||||
|
||||
### v2.1
|
||||
|
||||
- 增加网页全网搜功能
|
||||
@@ -20,7 +30,6 @@
|
||||
- 后台增加批量删除功能
|
||||
- 优化表格导入功能
|
||||
|
||||
注:如何更新见文件夹updateLog/24.11.4
|
||||
|
||||
### v2
|
||||
|
||||
@@ -33,53 +42,10 @@
|
||||
- 支持多网盘导入功能(目前仅夸克支持转存分享)
|
||||
- 增加资源分类功能
|
||||
|
||||
注:鉴于数据库改动大,最快升级方式:1、重新搭建新项目;2、旧项目后台导出资源表格;3、新项目导入这个表格
|
||||
## 搭建教程
|
||||
|
||||
## 后台安装教程
|
||||
[教程](https://tcn6g7hyxvir.feishu.cn/wiki/WYT4wZtrjijeswkI0RSc4ofTnah)
|
||||
|
||||
0、PHP(选择7.2,其它版本不兼容)
|
||||
|
||||
1、上传源码到服务器
|
||||
|
||||
2、设置网站运行目录public
|
||||
|
||||
3、设置thinkphp伪静态
|
||||
|
||||
4、导入数据库文件
|
||||
|
||||
5、修改.env文件数据库参数
|
||||
|
||||
后台地址:https://你的域名/qfadmin
|
||||
账号密码:admin 123456
|
||||
|
||||
## 常见问题
|
||||
|
||||
0、系统不再支持全部转存及每日更新,有能力者可自行修改使用
|
||||
|
||||
1、全部转存执行1分钟~5分钟后中断问题,修改超时限制
|
||||
该操作用时很长,请设置最大值86400 设置后需重启下服务
|
||||
宝塔设置教程 https://www.kancloud.cn/loveouu/bthelp/1541867
|
||||
|
||||
2、非7.2版本导致的报错,请自行解决,不要再问!!!不会就百度或者老老实实用7.2
|
||||
|
||||
3、nginx 404 Not Found 伪静态设置
|
||||
```shell
|
||||
location ~* (runtime|application)/{
|
||||
return 403;
|
||||
}
|
||||
location / {
|
||||
if (!-e $request_filename){
|
||||
rewrite ^(.*)$ /index.php?s=$1 last; break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4、网站经常打不开,出现500的情况,未具体找到原因,可能是因为服务器配置太低,分词功能占用内存过高导致的
|
||||
升级服务器配置或后台修改搜索模式改为“精准搜索”;
|
||||
|
||||
|
||||
5、全网搜的内容为临时分享资源,需要配置计划任务 每5分钟执行一次 即可
|
||||
https://XXXXX/api/other/delete_search
|
||||
|
||||
## 前台截图
|
||||
|
||||
@@ -96,13 +62,6 @@ https://XXXXX/api/other/delete_search
|
||||

|
||||
|
||||
|
||||
## 如何获取夸克网盘Cookie
|
||||
|
||||
登录夸克网盘后,按下F12,刷新页面
|
||||
|
||||

|
||||
|
||||
|
||||
# 免费交流社群
|
||||
|
||||
可以进交流群,一起交流学习,添加时请备注来源(如果项目对你有所帮助,也可以请我喝杯咖啡 ☕️ ~)
|
||||
|
||||
@@ -342,7 +342,6 @@ class Source extends QfShop
|
||||
|
||||
$this->excelField = $excelField;
|
||||
$this->exportExcelData($dataList);
|
||||
print_r(12);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,50 +361,7 @@ class Source extends QfShop
|
||||
|
||||
$source_category_id = input('source_category_id')??0;
|
||||
|
||||
$urls = input("urls");
|
||||
|
||||
$urls = explode("\n", $urls);
|
||||
|
||||
// 去掉数组元素中的空白字符
|
||||
$urls = array_map('trim', $urls);
|
||||
|
||||
// 过滤掉空值的数组元素
|
||||
$urls = array_filter($urls);
|
||||
|
||||
$allData = array_values(array_filter(array_map(function ($item) {
|
||||
// 提取 URL
|
||||
if (!preg_match('/https?:\/\/[^\s]+/', $item, $matches)) {
|
||||
return null; // 没有匹配到 URL,直接丢弃
|
||||
}
|
||||
|
||||
$url = trim($matches[0]);
|
||||
$code = '';
|
||||
|
||||
// 提取提取码(?pwd= 或 , 分割)
|
||||
if (preg_match('/\?pwd=([^,\s]+)/', $item, $pwdMatch)) {
|
||||
$code = trim($pwdMatch[1]);
|
||||
} elseif (preg_match('/,(.+)$/', $item, $commaMatch)) {
|
||||
$code = trim($commaMatch[1]);
|
||||
}
|
||||
|
||||
// 返回结果时,确保 title 保持为空字符串
|
||||
return [
|
||||
'url' => $url,
|
||||
'title' => '',
|
||||
'code' => $code
|
||||
];
|
||||
}, $urls)));
|
||||
|
||||
|
||||
// 去重,使用 'url' 字段来去重
|
||||
$uniqueUrls = [];
|
||||
$allData = array_filter($allData, function($item) use (&$uniqueUrls) {
|
||||
if (!in_array($item['url'], $uniqueUrls)) {
|
||||
$uniqueUrls[] = $item['url']; // 添加到已处理的 URL 列表
|
||||
return true; // 保留此项目
|
||||
}
|
||||
return false; // 去掉重复的项目
|
||||
});
|
||||
$allData = parsePanLinks(input("urls"));
|
||||
|
||||
$quarkPlugin = new QuarkPlugin();
|
||||
if(input("type")==2){
|
||||
@@ -416,7 +372,7 @@ class Source extends QfShop
|
||||
$res = $quarkPlugin->import($allData,$source_category_id);
|
||||
}
|
||||
|
||||
return jok('已提交任务,稍后查看结果2',$res);
|
||||
return jok('已提交任务,稍后查看结果2',$allData);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,10 +405,13 @@ class Source extends QfShop
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$quarkPlugin = new QuarkPlugin();
|
||||
$result = $quarkPlugin->getFiles(Config('qfshop.quark_cookie'));
|
||||
return jok('获取成功',$result);
|
||||
$result = $quarkPlugin->getFiles(input('type')??0,input('pdir_fid')??0);
|
||||
|
||||
if($result['code'] != 200){
|
||||
return jerr($result['message']);
|
||||
}
|
||||
return jok('获取成功',$result['data']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,246 @@ class Index extends QfShop
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return jok("Hello World!");
|
||||
// return jok("Hello World!");
|
||||
|
||||
$cookie = 'csrfToken=gKesaboeWtJkukG4VNGh5Ljk; BAIDUID=757FBF0C282638B49A59DC7E37C7702B:FG=1; BAIDUID_BFESS=757FBF0C282638B49A59DC7E37C7702B:FG=1; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1742787964; RT="z=1&dm=baidu.com&si=86a18d7d-4537-4b9b-ac36-06a756df3179&ss=m8mj80dn&sl=0&tt=0&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ul=261&hd=26a"; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1742794455; newlogin=1; ppfuid=FOCoIC3q5fKa8fgJnwzbE67EJ49BGJeplOzf+4l4EOvDuu2RXBRv6R3A1AZMa49I27C0gDDLrJyxcIIeAeEhD8JYsoLTpBiaCXhLqvzbzmvy3SeAW17tKgNq/Xx+RgOdb8TWCFe62MVrDTY6lMf2GrfqL8c87KLF2qFER3obJGmxOaJD7Qr04D9rET96PX99GEimjy3MrXEpSuItnI4KD2P5vWa8VVdqKPLBckQ0WyruzFB5pZ7L1GIDHy291nRZSc37WI7hn7N5DEkitWgHVHqxGUGRl1qke9+4QxQVI1jGgLbz7OSojK1zRbqBESR5Pdk2R9IA3lxxOVzA+Iw1TWLSgWjlFVG9Xmh1+20oPSbrzvDjYtVPmZ+9/6evcXmhcO1Y58MgLozKnaQIaLfWRIM4pp9u1B7t2Y8SxQH/XnrgZXt2Kg4R5SS0He7SlWGt42bJBOW2wZKr1YF6Z6VWTM5FjnYxYstXg/9EfB3EVmLB2thKqX6G/zUWgdr9REaklV1Uhhp5FAe6gNJIUptp7EMAaXYKm11G+JVPszQFdp9AJLcm4YSsYUXkaPI2Tl66J246cmjWQDTahAOINR5rXR5r/7VVI1RMZ8gb40q7az7vCK56XLooKT5a+rsFrf5Zu0yyCiiagElhrTEOtNdBJJq8eHwEHuFBni9ahSwpC7lbKkUwaKH69tf0DFV7hJROiLETSFloIVkHdy3+I2JUr1LsplAz0hMkWt/tE4tXVUV7QcTDTZWS/2mCoS/GV3N9awQ6iM6hs/BWjlgnEa1+5hYkkYOBBLZqDwzG9FQyZZJmSCAynpprqnVbhrjcNYdk5FKazXcZ/j40FJv+iLGBn3nkkgHlne61I8I7KhtQgInXjsNS9+mteGCT/vj/pEvkm+ZitcePbf21QMldRrlvw4uFnWmLU84Th29MqUuVR0ujl0ys3zTnxv/D47Q2VFyeFv12nptBFm2PISy0WmJ/Sy3ktTWpm7mcOABi5Gey1FBzkrq/nzqRQID/LRsJJW24e+1N4wlJzhNmFXMQ0YiYVdq7aHN89Oybut+xsc38J6I4Wd2rVi5xrH8hGqvd77OJuzH8X+tb0PV+Xnu3NL1fmqLIh+XcF6fnyPFPUxteQtbtLyi+gq5zowg1oFj8O/L9oVsoK22a9qUmM/HrJMRsLi1+J9aSd42+X78fDIZgkPh3epzLLvwRmnAbs5z/V+jl3P3gVnlwm9bfwhaFtnhFN2dHYAw7i4QhrXdzc77isXhbvkM5DsEwz5RTVSb4C+N+kIl81Iase/C16XVPKOj9XA==; BDUSS=jYwbDRJZG0yTi1VbDgtMWF6M1BGZ0k0ZG96dm9iOHJGczFMOUYtMFhwYlJmd2hvRVFBQUFBJCQAAAAAAAAAAAEAAAA63UdY2K~Yr8Dksru5~cjL0MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHy4GfR8uBnT; BDUSS_BFESS=jYwbDRJZG0yTi1VbDgtMWF6M1BGZ0k0ZG96dm9iOHJGczFMOUYtMFhwYlJmd2hvRVFBQUFBJCQAAAAAAAAAAAEAAAA63UdY2K~Yr8Dksru5~cjL0MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHy4GfR8uBnT; STOKEN=608a270497995724e6ed69015178372081331f404747f0a8492ee31de1184c41; PANPSC=6332961014215215224%3AAuI6D6iGxsvXU%2FMlrspYA1cS2d9ns3O5g0mIZdLHpdQGbqupDlB1gtH1%2BL8BUDk1coDRJu%2FbTp%2FiLaLUl0KD5De4ZdaW7CoOlL98c8Ccr9ch6uZoP3DwQ9YfJggg9xZJa6gjWHNi7jj6tFSlPcYsyyZWmuM7JILl4szUrnVKA5MNNiO7%2B4TS%2B1QskbZnP5EyWagh%2FyTVtumv9EBTj3cIccvsqRsDSpjMTItbmssa8FDJel1POICqciYu0WtaRbrkbSBvzd4TSG3wk8UVEJrJjetuQFScyIV%2FkrFWWqsgPEw%3D; Hm_lvt_182d6d59474cf78db37e0b2248640ea5=1742788120; ndut_fmt=6F438330EB0B4C594C515F276A3E73E3F2D3A8BB5A3C26DD1E721E98B58ED17B; Hm_lpvt_182d6d59474cf78db37e0b2248640ea5=1742795476; ab_sr=1.0.1_YTI3MjJmMjkwY2Y5MTJhMjc4MGJhNWU2ZGMwNTFiZWZiNmZhMTZkMWRlNWYyMzAxNTA1OTU2YTU4ZjU5M2ZiNWI5NDY2YjYwZWY3Yjc4YTY3MmNiMWVlNWNkNzE2ZGI2YzJmYTY1YTgwM2M1ZDJlYTk1YjAxZTcyMmNkNWRkNzliM2RiOGMzYzUxYmMwZTU4OTJiZmRmNjhiMDIzZDc1OWRhMGIyNGNkMDJhOTMzZjllYmQxMDUzY2ZjYzU4MjVk';
|
||||
// $cookie = '';
|
||||
$network = new \netdisk\pan\BaiduWork($cookie);
|
||||
$bdstoken = $network->getBdstoken();
|
||||
$network->setBdstoken($bdstoken);
|
||||
|
||||
// 验证提取码
|
||||
// $linkUrl = "https://pan.baidu.com/s/11ioAjAwdwzI3BEvP5c62bw"; // 分享链接
|
||||
// $passCode = "him8"; // 4位提取码
|
||||
|
||||
$linkUrl = "https://pan.baidu.com/s/1HU99KPtdJEpKnYnYLnQ37Q"; // 分享链接
|
||||
$passCode = "ruwf"; // 4位提取码
|
||||
|
||||
// $linkUrl = "https://pan.baidu.com/s/1f03pM6dvtZPGA1bA0DH9AQ"; // 分享链接
|
||||
// $passCode = "a9oa"; // 4位提取码
|
||||
|
||||
// 先判断是否有提取码
|
||||
if (!empty($passCode)) {
|
||||
// 验证提取码
|
||||
$randsk = $network->verifyPassCode($linkUrl, $passCode);
|
||||
if (is_numeric($randsk)) {
|
||||
return jerr($network->getErrorMessage($randsk));
|
||||
}
|
||||
// 验证成功,更新 cookie
|
||||
$network->updateBdclnd($randsk);
|
||||
}
|
||||
|
||||
// 获取转存参数
|
||||
$transferParams = $network->getTransferParams($linkUrl);
|
||||
if (is_numeric($transferParams)) {
|
||||
return jerr($network->getErrorMessage($transferParams));
|
||||
}
|
||||
// 解析返回的参数
|
||||
list($shareId, $userId, $fsIds, $fileNames, $isDirs) = $transferParams;
|
||||
|
||||
$folderName = ''; // 自定义保存目录名
|
||||
// 检查目录名是否包含非法字符
|
||||
$invalidChars = ['<', '>', '|', '*', '?', '\\', ':'];
|
||||
foreach ($invalidChars as $char) {
|
||||
if (strpos($folderName, $char) !== false) {
|
||||
return jerr('转存目录名有非法字符,不能包含:< > | * ? \\ :');
|
||||
}
|
||||
}
|
||||
|
||||
// 先检查目录是否存在,不存在再创建
|
||||
$dirList = $network->getDirList('/' . $folderName);
|
||||
// 如果返回的是错误码,说明目录不存在,需要创建
|
||||
if (is_numeric($dirList)) {
|
||||
$createResult = $network->createDir($folderName);
|
||||
if ($createResult !== 0) {
|
||||
return jerr($network->getErrorMessage($createResult));
|
||||
}
|
||||
}
|
||||
|
||||
// 执行文件转存
|
||||
$transferResult = $network->transferFile([$shareId, $userId, $fsIds], $folderName);
|
||||
if ($transferResult !== 0) {
|
||||
return jerr($network->getErrorMessage($transferResult));
|
||||
}
|
||||
|
||||
// 转存成功后,获取目录中的文件列表
|
||||
$dirList = $network->getDirList('/' . $folderName);
|
||||
if (is_numeric($dirList)) {
|
||||
return jerr($network->getErrorMessage($dirList));
|
||||
}
|
||||
|
||||
// 找到刚刚转存的所有文件
|
||||
$targetFiles = [];
|
||||
$fsIdList = [];
|
||||
$filePaths = [];
|
||||
$adFilePaths = []; // 用于存储包含广告的文件路径
|
||||
$allFilesAreAds = true; // 假设所有文件都是广告
|
||||
|
||||
foreach ($dirList as $file) {
|
||||
if (in_array($file['server_filename'], $fileNames)) {
|
||||
$targetFiles[] = $file;
|
||||
$fsIdList[] = $file['fs_id'];
|
||||
$filePath = '/' . $folderName . '/' . $file['server_filename'];
|
||||
$filePaths[] = $filePath;
|
||||
|
||||
// 检查文件名是否包含广告内容
|
||||
$containsAd = $this->containsAdKeywords($file['server_filename']);
|
||||
|
||||
// 如果是目录,需要检查目录内的文件
|
||||
if ($file['isdir'] == 1) {
|
||||
// 获取子目录内容
|
||||
$subDirList = $network->getDirList($filePath);
|
||||
if (!is_numeric($subDirList)) {
|
||||
foreach ($subDirList as $subFile) {
|
||||
// 检查子文件是否包含广告关键词
|
||||
if ($this->containsAdKeywords($subFile['server_filename'])) {
|
||||
// 将包含广告的子文件添加到待删除列表
|
||||
$adFilePaths[] = $filePath . '/' . $subFile['server_filename'];
|
||||
} else {
|
||||
// 只要有一个文件不是广告,就将标志设为false
|
||||
$allFilesAreAds = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果是文件,直接判断
|
||||
if ($containsAd) {
|
||||
$adFilePaths[] = $filePath;
|
||||
} else {
|
||||
$allFilesAreAds = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($targetFiles)) {
|
||||
return jerr('找不到刚转存的文件');
|
||||
}
|
||||
|
||||
// 如果所有文件都是广告,删除整个转存的内容
|
||||
if ($allFilesAreAds && !empty($targetFiles)) {
|
||||
// 删除所有转存的文件
|
||||
$deleteResult = $network->batchDeleteFiles($filePaths);
|
||||
if ($deleteResult['errno'] === 0) {
|
||||
return jok('所有转存的文件都包含广告内容,已全部删除', [
|
||||
'deletedCount' => $deleteResult['deletedCount'],
|
||||
'paths' => $deleteResult['paths']
|
||||
]);
|
||||
} else {
|
||||
return jerr('删除广告文件失败: ' . $deleteResult['message']);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有部分文件是广告,只删除广告文件
|
||||
if (!empty($adFilePaths)) {
|
||||
$deleteResult = $network->batchDeleteFiles($adFilePaths);
|
||||
// 删除后更新文件列表
|
||||
if ($deleteResult['errno'] === 0) {
|
||||
// 从fsIdList和filePaths中移除已删除的广告文件
|
||||
foreach ($adFilePaths as $adPath) {
|
||||
$key = array_search($adPath, $filePaths);
|
||||
if ($key !== false) {
|
||||
unset($filePaths[$key]);
|
||||
unset($fsIdList[$key]);
|
||||
}
|
||||
}
|
||||
// 重新索引数组
|
||||
$filePaths = array_values($filePaths);
|
||||
$fsIdList = array_values($fsIdList);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果删除广告后没有文件了,返回提示
|
||||
if (empty($fsIdList)) {
|
||||
return jok('所有有效文件都包含广告内容,已全部删除');
|
||||
}
|
||||
|
||||
// 创建分享
|
||||
$expiry = 0; // 0为永久
|
||||
$password = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 4); // 随机4位提取码
|
||||
$shareLink = $network->createShare(implode(',', $fsIdList), $expiry, $password);
|
||||
|
||||
if (is_numeric($shareLink)) {
|
||||
return jerr($network->getErrorMessage($shareLink));
|
||||
}
|
||||
|
||||
// 转存成功
|
||||
return jok("文件转存成功", [
|
||||
'fileNames' => $fileNames,
|
||||
'fileCount' => count($fsIdList),
|
||||
'folderName' => $folderName,
|
||||
'shareLink' => $shareLink,
|
||||
'password' => $password,
|
||||
'filePaths' => $filePaths,
|
||||
'removedAdFiles' => $adFilePaths
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件名是否包含广告关键词
|
||||
* @param string $filename 文件名
|
||||
* @return bool 是否包含广告关键词
|
||||
*/
|
||||
private function containsAdKeywords($filename)
|
||||
{
|
||||
$banned = Config('qfshop.quark_banned') ?? ''; // 如果出现这些字样就删除
|
||||
|
||||
// 广告关键词列表
|
||||
$adKeywords = [];
|
||||
if (!empty($banned)) {
|
||||
$adKeywords = array_map('trim', explode(',', $banned));
|
||||
}
|
||||
|
||||
// 转为小写进行比较
|
||||
$lowercaseFilename = mb_strtolower($filename);
|
||||
|
||||
foreach ($adKeywords as $keyword) {
|
||||
if (mb_strpos($lowercaseFilename, mb_strtolower($keyword)) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFiles()
|
||||
{
|
||||
$cookie = 'csrfToken=gKesaboeWtJkukG4VNGh5Ljk; BAIDUID=757FBF0C282638B49A59DC7E37C7702B:FG=1; BAIDUID_BFESS=757FBF0C282638B49A59DC7E37C7702B:FG=1; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1742787964; RT="z=1&dm=baidu.com&si=86a18d7d-4537-4b9b-ac36-06a756df3179&ss=m8mj80dn&sl=0&tt=0&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ul=261&hd=26a"; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1742794455; newlogin=1; ppfuid=FOCoIC3q5fKa8fgJnwzbE67EJ49BGJeplOzf+4l4EOvDuu2RXBRv6R3A1AZMa49I27C0gDDLrJyxcIIeAeEhD8JYsoLTpBiaCXhLqvzbzmvy3SeAW17tKgNq/Xx+RgOdb8TWCFe62MVrDTY6lMf2GrfqL8c87KLF2qFER3obJGmxOaJD7Qr04D9rET96PX99GEimjy3MrXEpSuItnI4KD2P5vWa8VVdqKPLBckQ0WyruzFB5pZ7L1GIDHy291nRZSc37WI7hn7N5DEkitWgHVHqxGUGRl1qke9+4QxQVI1jGgLbz7OSojK1zRbqBESR5Pdk2R9IA3lxxOVzA+Iw1TWLSgWjlFVG9Xmh1+20oPSbrzvDjYtVPmZ+9/6evcXmhcO1Y58MgLozKnaQIaLfWRIM4pp9u1B7t2Y8SxQH/XnrgZXt2Kg4R5SS0He7SlWGt42bJBOW2wZKr1YF6Z6VWTM5FjnYxYstXg/9EfB3EVmLB2thKqX6G/zUWgdr9REaklV1Uhhp5FAe6gNJIUptp7EMAaXYKm11G+JVPszQFdp9AJLcm4YSsYUXkaPI2Tl66J246cmjWQDTahAOINR5rXR5r/7VVI1RMZ8gb40q7az7vCK56XLooKT5a+rsFrf5Zu0yyCiiagElhrTEOtNdBJJq8eHwEHuFBni9ahSwpC7lbKkUwaKH69tf0DFV7hJROiLETSFloIVkHdy3+I2JUr1LsplAz0hMkWt/tE4tXVUV7QcTDTZWS/2mCoS/GV3N9awQ6iM6hs/BWjlgnEa1+5hYkkYOBBLZqDwzG9FQyZZJmSCAynpprqnVbhrjcNYdk5FKazXcZ/j40FJv+iLGBn3nkkgHlne61I8I7KhtQgInXjsNS9+mteGCT/vj/pEvkm+ZitcePbf21QMldRrlvw4uFnWmLU84Th29MqUuVR0ujl0ys3zTnxv/D47Q2VFyeFv12nptBFm2PISy0WmJ/Sy3ktTWpm7mcOABi5Gey1FBzkrq/nzqRQID/LRsJJW24e+1N4wlJzhNmFXMQ0YiYVdq7aHN89Oybut+xsc38J6I4Wd2rVi5xrH8hGqvd77OJuzH8X+tb0PV+Xnu3NL1fmqLIh+XcF6fnyPFPUxteQtbtLyi+gq5zowg1oFj8O/L9oVsoK22a9qUmM/HrJMRsLi1+J9aSd42+X78fDIZgkPh3epzLLvwRmnAbs5z/V+jl3P3gVnlwm9bfwhaFtnhFN2dHYAw7i4QhrXdzc77isXhbvkM5DsEwz5RTVSb4C+N+kIl81Iase/C16XVPKOj9XA==; BDUSS=jYwbDRJZG0yTi1VbDgtMWF6M1BGZ0k0ZG96dm9iOHJGczFMOUYtMFhwYlJmd2hvRVFBQUFBJCQAAAAAAAAAAAEAAAA63UdY2K~Yr8Dksru5~cjL0MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHy4GfR8uBnT; BDUSS_BFESS=jYwbDRJZG0yTi1VbDgtMWF6M1BGZ0k0ZG96dm9iOHJGczFMOUYtMFhwYlJmd2hvRVFBQUFBJCQAAAAAAAAAAAEAAAA63UdY2K~Yr8Dksru5~cjL0MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHy4GfR8uBnT; STOKEN=608a270497995724e6ed69015178372081331f404747f0a8492ee31de1184c41; PANPSC=6332961014215215224%3AAuI6D6iGxsvXU%2FMlrspYA1cS2d9ns3O5g0mIZdLHpdQGbqupDlB1gtH1%2BL8BUDk1coDRJu%2FbTp%2FiLaLUl0KD5De4ZdaW7CoOlL98c8Ccr9ch6uZoP3DwQ9YfJggg9xZJa6gjWHNi7jj6tFSlPcYsyyZWmuM7JILl4szUrnVKA5MNNiO7%2B4TS%2B1QskbZnP5EyWagh%2FyTVtumv9EBTj3cIccvsqRsDSpjMTItbmssa8FDJel1POICqciYu0WtaRbrkbSBvzd4TSG3wk8UVEJrJjetuQFScyIV%2FkrFWWqsgPEw%3D; Hm_lvt_182d6d59474cf78db37e0b2248640ea5=1742788120; ndut_fmt=6F438330EB0B4C594C515F276A3E73E3F2D3A8BB5A3C26DD1E721E98B58ED17B; Hm_lpvt_182d6d59474cf78db37e0b2248640ea5=1742795476; ab_sr=1.0.1_YTI3MjJmMjkwY2Y5MTJhMjc4MGJhNWU2ZGMwNTFiZWZiNmZhMTZkMWRlNWYyMzAxNTA1OTU2YTU4ZjU5M2ZiNWI5NDY2YjYwZWY3Yjc4YTY3MmNiMWVlNWNkNzE2ZGI2YzJmYTY1YTgwM2M1ZDJlYTk1YjAxZTcyMmNkNWRkNzliM2RiOGMzYzUxYmMwZTU4OTJiZmRmNjhiMDIzZDc1OWRhMGIyNGNkMDJhOTMzZjllYmQxMDUzY2ZjYzU4MjVk';
|
||||
// $cookie = '';
|
||||
$network = new \netdisk\pan\BaiduWork($cookie);
|
||||
|
||||
$res = $network->getDirList('/');
|
||||
|
||||
return jok('获取成功',$res);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$cookie = 'csrfToken=gKesaboeWtJkukG4VNGh5Ljk; BAIDUID=757FBF0C282638B49A59DC7E37C7702B:FG=1; BAIDUID_BFESS=757FBF0C282638B49A59DC7E37C7702B:FG=1; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1742787964; RT="z=1&dm=baidu.com&si=86a18d7d-4537-4b9b-ac36-06a756df3179&ss=m8mj80dn&sl=0&tt=0&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ul=261&hd=26a"; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1742794455; newlogin=1; ppfuid=FOCoIC3q5fKa8fgJnwzbE67EJ49BGJeplOzf+4l4EOvDuu2RXBRv6R3A1AZMa49I27C0gDDLrJyxcIIeAeEhD8JYsoLTpBiaCXhLqvzbzmvy3SeAW17tKgNq/Xx+RgOdb8TWCFe62MVrDTY6lMf2GrfqL8c87KLF2qFER3obJGmxOaJD7Qr04D9rET96PX99GEimjy3MrXEpSuItnI4KD2P5vWa8VVdqKPLBckQ0WyruzFB5pZ7L1GIDHy291nRZSc37WI7hn7N5DEkitWgHVHqxGUGRl1qke9+4QxQVI1jGgLbz7OSojK1zRbqBESR5Pdk2R9IA3lxxOVzA+Iw1TWLSgWjlFVG9Xmh1+20oPSbrzvDjYtVPmZ+9/6evcXmhcO1Y58MgLozKnaQIaLfWRIM4pp9u1B7t2Y8SxQH/XnrgZXt2Kg4R5SS0He7SlWGt42bJBOW2wZKr1YF6Z6VWTM5FjnYxYstXg/9EfB3EVmLB2thKqX6G/zUWgdr9REaklV1Uhhp5FAe6gNJIUptp7EMAaXYKm11G+JVPszQFdp9AJLcm4YSsYUXkaPI2Tl66J246cmjWQDTahAOINR5rXR5r/7VVI1RMZ8gb40q7az7vCK56XLooKT5a+rsFrf5Zu0yyCiiagElhrTEOtNdBJJq8eHwEHuFBni9ahSwpC7lbKkUwaKH69tf0DFV7hJROiLETSFloIVkHdy3+I2JUr1LsplAz0hMkWt/tE4tXVUV7QcTDTZWS/2mCoS/GV3N9awQ6iM6hs/BWjlgnEa1+5hYkkYOBBLZqDwzG9FQyZZJmSCAynpprqnVbhrjcNYdk5FKazXcZ/j40FJv+iLGBn3nkkgHlne61I8I7KhtQgInXjsNS9+mteGCT/vj/pEvkm+ZitcePbf21QMldRrlvw4uFnWmLU84Th29MqUuVR0ujl0ys3zTnxv/D47Q2VFyeFv12nptBFm2PISy0WmJ/Sy3ktTWpm7mcOABi5Gey1FBzkrq/nzqRQID/LRsJJW24e+1N4wlJzhNmFXMQ0YiYVdq7aHN89Oybut+xsc38J6I4Wd2rVi5xrH8hGqvd77OJuzH8X+tb0PV+Xnu3NL1fmqLIh+XcF6fnyPFPUxteQtbtLyi+gq5zowg1oFj8O/L9oVsoK22a9qUmM/HrJMRsLi1+J9aSd42+X78fDIZgkPh3epzLLvwRmnAbs5z/V+jl3P3gVnlwm9bfwhaFtnhFN2dHYAw7i4QhrXdzc77isXhbvkM5DsEwz5RTVSb4C+N+kIl81Iase/C16XVPKOj9XA==; BDUSS=jYwbDRJZG0yTi1VbDgtMWF6M1BGZ0k0ZG96dm9iOHJGczFMOUYtMFhwYlJmd2hvRVFBQUFBJCQAAAAAAAAAAAEAAAA63UdY2K~Yr8Dksru5~cjL0MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHy4GfR8uBnT; BDUSS_BFESS=jYwbDRJZG0yTi1VbDgtMWF6M1BGZ0k0ZG96dm9iOHJGczFMOUYtMFhwYlJmd2hvRVFBQUFBJCQAAAAAAAAAAAEAAAA63UdY2K~Yr8Dksru5~cjL0MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHy4GfR8uBnT; STOKEN=608a270497995724e6ed69015178372081331f404747f0a8492ee31de1184c41; PANPSC=6332961014215215224%3AAuI6D6iGxsvXU%2FMlrspYA1cS2d9ns3O5g0mIZdLHpdQGbqupDlB1gtH1%2BL8BUDk1coDRJu%2FbTp%2FiLaLUl0KD5De4ZdaW7CoOlL98c8Ccr9ch6uZoP3DwQ9YfJggg9xZJa6gjWHNi7jj6tFSlPcYsyyZWmuM7JILl4szUrnVKA5MNNiO7%2B4TS%2B1QskbZnP5EyWagh%2FyTVtumv9EBTj3cIccvsqRsDSpjMTItbmssa8FDJel1POICqciYu0WtaRbrkbSBvzd4TSG3wk8UVEJrJjetuQFScyIV%2FkrFWWqsgPEw%3D; Hm_lvt_182d6d59474cf78db37e0b2248640ea5=1742788120; ndut_fmt=6F438330EB0B4C594C515F276A3E73E3F2D3A8BB5A3C26DD1E721E98B58ED17B; Hm_lpvt_182d6d59474cf78db37e0b2248640ea5=1742795476; ab_sr=1.0.1_YTI3MjJmMjkwY2Y5MTJhMjc4MGJhNWU2ZGMwNTFiZWZiNmZhMTZkMWRlNWYyMzAxNTA1OTU2YTU4ZjU5M2ZiNWI5NDY2YjYwZWY3Yjc4YTY3MmNiMWVlNWNkNzE2ZGI2YzJmYTY1YTgwM2M1ZDJlYTk1YjAxZTcyMmNkNWRkNzliM2RiOGMzYzUxYmMwZTU4OTJiZmRmNjhiMDIzZDc1OWRhMGIyNGNkMDJhOTMzZjllYmQxMDUzY2ZjYzU4MjVk';
|
||||
// $cookie = '';
|
||||
$network = new \netdisk\pan\BaiduWork($cookie);
|
||||
$bdstoken = $network->getBdstoken();
|
||||
$network->setBdstoken($bdstoken);
|
||||
|
||||
// 使用固定的文件路径数组
|
||||
$filePaths = [
|
||||
"//1",
|
||||
"//2"
|
||||
];
|
||||
|
||||
// 调用批量删除方法
|
||||
$result = $network->batchDeleteFiles($filePaths);
|
||||
|
||||
if ($result['errno'] === 0) {
|
||||
return jok('文件删除成功', [
|
||||
'deletedCount' => $result['deletedCount'],
|
||||
'paths' => $result['paths']
|
||||
]);
|
||||
} else {
|
||||
return jerr($result['message']);
|
||||
}
|
||||
}
|
||||
|
||||
public function search() {
|
||||
$fc = new VicWord();
|
||||
$keywords = input('keywords');
|
||||
|
||||
@@ -5,703 +5,48 @@ namespace app\api\controller;
|
||||
use think\App;
|
||||
use think\facade\Cache;
|
||||
use app\api\QfShop;
|
||||
use app\model\Source as SourceModel;
|
||||
|
||||
class Open extends QfShop
|
||||
{
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->url = "";
|
||||
$this->is_type = 0;
|
||||
$this->cookie = ""; //夸克登录凭证
|
||||
$this->Authorization = ""; //阿里登录凭证
|
||||
$this->expired_type = 1; //1分享永久 2临时
|
||||
$this->to_pdir_fid = ""; //存入目标文件
|
||||
$this->ad_fid = "";
|
||||
$this->code = ""; //提取码
|
||||
$this->isType = 0; //等于1时仅校验是否有效并提取资源信息
|
||||
$this->urlHeader = array(
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9',
|
||||
'content-type: application/json;charset=UTF-8',
|
||||
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'sec-ch-ua-mobile: ?0',
|
||||
'sec-ch-ua-platform: "Windows"',
|
||||
'sec-fetch-dest: empty',
|
||||
'sec-fetch-mode: cors',
|
||||
'sec-fetch-site: same-site',
|
||||
'Referer: https://pan.quark.cn/',
|
||||
'Referrer-Policy: strict-origin-when-cross-origin',
|
||||
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return jok('Hello World');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取夸克网盘文件夹
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getFiles()
|
||||
{
|
||||
$this->cookie = input('cookie')??'';
|
||||
$urlData = [];
|
||||
$queryParams = [
|
||||
'pr' => 'ucpro',
|
||||
'fr' => 'pc',
|
||||
'uc_param_str' => '',
|
||||
'pdir_fid' => 0,
|
||||
'_page' => 1,
|
||||
'_size' => 50,
|
||||
'_fetch_total' => 1,
|
||||
'_fetch_sub_dirs' => 0,
|
||||
'_sort' => 'file_type:asc,updated_at:desc',
|
||||
];
|
||||
|
||||
$this->urlHeader[] = 'cookie: ' . $this->cookie;
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']=='require login [guest]'?'夸克未登录,请检查cookie':$res['message']);
|
||||
}
|
||||
|
||||
return jok('获取成功',$res['data']['list']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一键转存并分享资源
|
||||
*
|
||||
* type 0 夸克 1阿里
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function transfer()
|
||||
{
|
||||
$url = input("url");
|
||||
$this->code = input('code')??'';
|
||||
$this->isType = input('isType')??0;
|
||||
|
||||
if($this->isType != 1){ //直接入口就不用cookie 防止账号异常
|
||||
$this->cookie = input('cookie')??'';
|
||||
$this->Authorization = input('Authorization')??'';
|
||||
}
|
||||
|
||||
$this->expired_type = input('expired_type')??1;
|
||||
$this->to_pdir_fid = input('to_pdir_fid')??"";
|
||||
$this->ad_fid = input('ad_fid')??"";
|
||||
|
||||
if (strpos($url, '?entry=') !== false) {
|
||||
$entry = preg_match('/\?entry=([^&]+)/', $url, $matches) ? $matches[1] : '';
|
||||
$url = preg_match('/.*(?=\?entry=)/', $url, $matches) ? $matches[0] : '';
|
||||
}
|
||||
|
||||
$substring = strstr($url, 's/');
|
||||
if ($substring !== false) {
|
||||
$pwd_id = substr($substring, 2); // 去除 's/' 部分
|
||||
} else {
|
||||
return jerr("资源地址格式有误");
|
||||
}
|
||||
|
||||
$this->urlHeader[] = 'cookie: ' . $this->cookie;
|
||||
|
||||
$patterns = [
|
||||
'pan.quark.cn' => 0,
|
||||
'www.alipan.com' => 1,
|
||||
'www.aliyundrive.com' => 1,
|
||||
// 'pan.baidu.com' => 2,
|
||||
'drive.uc.cn' => 3,
|
||||
// 'pan.xunlei.com' => 4,
|
||||
$urlData = [
|
||||
'expired_type' => input('expired_type')??1, // 1正式资源 2临时资源
|
||||
'url' => input("url")?? '',
|
||||
'code' => input('code')??'',
|
||||
'isType' => input('isType')??0,
|
||||
];
|
||||
|
||||
$url_type = -1; // 默认值为 -1
|
||||
foreach ($patterns as $pattern => $type) {
|
||||
if (strpos($url, $pattern) !== false) {
|
||||
$url_type = $type;
|
||||
break; // 一旦匹配成功,退出循环
|
||||
}
|
||||
}
|
||||
|
||||
$this->url = $url;
|
||||
|
||||
if ($url_type == 0) {
|
||||
//夸克
|
||||
if(empty($this->cookie) && $this->isType==0){
|
||||
jerr("参数有误");
|
||||
}
|
||||
$this->transferQuark(strtok($pwd_id, '#'));
|
||||
} else if($url_type == 1){
|
||||
//阿里
|
||||
$this->transferAlipan($pwd_id);
|
||||
} else if($url_type == 3){
|
||||
//UC
|
||||
$this->transferUc($pwd_id);
|
||||
} else {
|
||||
return jerr("资源地址格式有误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 夸克 - 一键转存并分享资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function transferQuark($pwd_id){
|
||||
//获取要转存夸克资源的stoken
|
||||
$infoData = $this->getStoken($pwd_id);
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $infoData['title'];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok('检验成功', $urls);
|
||||
}
|
||||
|
||||
|
||||
$stoken = $infoData['stoken'];
|
||||
|
||||
|
||||
//获取要转存夸克资源的详细内容
|
||||
$detail = $this->getShare($pwd_id,$stoken);
|
||||
|
||||
$fid_list = [];
|
||||
$fid_token_list = [];
|
||||
$title = $detail['share']['title']; //资源名称
|
||||
foreach ($detail['list'] as $key => $value) {
|
||||
$fid_list[] = $value['fid'];
|
||||
$fid_token_list[] = $value['share_fid_token'];
|
||||
if(empty($urlData['url'])){
|
||||
return jerr('资源地址不能为空');
|
||||
}
|
||||
|
||||
//转存资源到指定文件夹
|
||||
$task_id = $this->getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list);
|
||||
$transfer = new \netdisk\Transfer();
|
||||
$res = $transfer->transfer($urlData);
|
||||
|
||||
//转存后根据task_id获取转存到自己网盘后的信息
|
||||
$retry_index = 0;
|
||||
$myData = '';
|
||||
while ($myData=='' || $myData['status'] != 2) {
|
||||
$myData = $this->getShareTask($task_id, $retry_index);
|
||||
$retry_index++;
|
||||
// 可以添加一个最大重试次数的限制,防止无限循环
|
||||
if ($retry_index > 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
//删除转存后可能有的广告
|
||||
$banned = Config('qfshop.quark_banned')??''; //如果出现这些字样就删除
|
||||
if(!empty($banned)){
|
||||
$bannedList = explode(',', $banned);
|
||||
$pdir_fid = $myData['save_as']['save_as_top_fids'][0];
|
||||
$dellist = [];
|
||||
$plist = $this->getPdirFid($pdir_fid);
|
||||
if(!empty($plist)){
|
||||
foreach ($plist as $key => $value) {
|
||||
// 检查$value['file_name']是否包含$bannedList中的任何一项
|
||||
$contains = false;
|
||||
foreach ($bannedList as $item) {
|
||||
if (strpos($value['file_name'], $item) !== false) {
|
||||
$contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($contains) {
|
||||
$dellist[] = $value['fid'];
|
||||
}
|
||||
}
|
||||
if(count($plist) === count($dellist)){
|
||||
//要删除的资源数如果和原数据资源数一样 就全部删除并终止下面的分享
|
||||
$this->deletepdirFid([$pdir_fid]);
|
||||
return jerr("资源内容为空");
|
||||
}else{
|
||||
if (!empty($dellist)) {
|
||||
$this->deletepdirFid($dellist);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
$shareFid = $myData['save_as']['save_as_top_fids'];
|
||||
//分享资源并拿到更新后的task_id
|
||||
$task_id = $this->getShareBtn($myData['save_as']['save_as_top_fids'],$title);
|
||||
|
||||
//根据task_id拿到share_id
|
||||
$retry_index = 0;
|
||||
$myData = '';
|
||||
while ($myData=='' || $myData['status'] != 2) {
|
||||
$myData = $this->getShareTask($task_id, $retry_index);
|
||||
$retry_index++;
|
||||
// 可以添加一个最大重试次数的限制,防止无限循环
|
||||
if ($retry_index > 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//根据share_id 获取到分享链接
|
||||
$share = $this->getSharePassword($myData['share_id']);
|
||||
// $share['fid'] = $share['first_file']['fid'];
|
||||
$share['fid'] = (is_array($shareFid) && count($shareFid) > 1) ? $shareFid : $share['first_file']['fid'];
|
||||
|
||||
return jok('转存成功', $share);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里 - 一键转存并分享资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function transferAlipan($share_id)
|
||||
{
|
||||
$data = [];
|
||||
$infos = $this->getAlipan1($share_id);
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $infos['share_name'];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok('检验成功', $urls);
|
||||
}else{
|
||||
return jerr('阿里暂不支持转存');
|
||||
}
|
||||
|
||||
|
||||
//通过分享id获取file_id
|
||||
$file_infos = $infos['file_infos'];
|
||||
|
||||
//通过分享id获取X-Share-Token
|
||||
$share_token = $this->getAlipan2($share_id);
|
||||
|
||||
$data3['requests'] = [];
|
||||
$data3['resource'] = 'file';
|
||||
|
||||
foreach ($file_infos as $key=>$value) {
|
||||
$data3['requests'][$key]['body']['auto_rename'] = true;
|
||||
$data3['requests'][$key]['body']['file_id'] = $value['file_id'];
|
||||
$data3['requests'][$key]['body']['share_id'] = $share_id;
|
||||
$data3['requests'][$key]['body']['to_drive_id'] = '2008425230';
|
||||
$data3['requests'][$key]['body']['to_parent_file_id'] = '66a20824c3846d890f6542c6aac2c79822d2a64f';
|
||||
$data3['requests'][$key]['headers']['Content-Type'] = 'application/json';
|
||||
$data3['requests'][$key]['id'] = $key.'';
|
||||
$data3['requests'][$key]['method'] = 'POST';
|
||||
$data3['requests'][$key]['url'] = '/file/copy';
|
||||
}
|
||||
|
||||
//保存
|
||||
$responses = $this->getAlipan3($data3,$share_token);
|
||||
$data4['drive_id'] = '2008425230';
|
||||
$data4['expiration'] = '';
|
||||
$data4['share_pwd'] = '';
|
||||
$data4['file_id_list'] = [];
|
||||
|
||||
foreach ($responses as $key=>$value){
|
||||
$data4['file_id_list'][] = $value['body']['file_id'];
|
||||
}
|
||||
|
||||
//分享
|
||||
$share = $this->getAlipan4($data4);
|
||||
|
||||
$data['share_url'] = $share['share_url'];
|
||||
$data['title'] = $share['share_title'];
|
||||
|
||||
return jok('转存成功', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* UC- 一键转存并分享资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function transferUc($pwd_id){
|
||||
$infoData = $this->getStokenUc($pwd_id);
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $infoData['title'];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok('检验成功', $urls);
|
||||
}else{
|
||||
return jerr('UC暂不支持转存');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取要转存资源的stoken
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getStoken($pwd_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'passcode' => '',
|
||||
'pwd_id' => $pwd_id,
|
||||
);
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc&uc_param_str=", "POST",json_encode($urlData), $this->urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
if($res['code'] !== 200){
|
||||
return jerr($res['message']);
|
||||
}
|
||||
$data = $res['data'];
|
||||
return $data;
|
||||
|
||||
$isSave = input('isSave')??0;
|
||||
if($isSave == 1){
|
||||
$data = [
|
||||
"title" => $res['data']['title'],
|
||||
"url" => $res['data']['share_url'],
|
||||
"is_type" => determineIsType($res['data']['share_url']),
|
||||
"code" => $res['data']['code'] ?? $urlData['code'] ?? '',
|
||||
"is_time" => $urlData['expired_type']==2 ? 1 : 0,
|
||||
"update_time" => time(),
|
||||
"create_time" => time(),
|
||||
"fid" => is_array($res['data']['fid'] ?? '') ? json_encode($res['data']['fid']) : ($res['data']['fid'] ?? '')
|
||||
];
|
||||
$SourceModel = new SourceModel();
|
||||
$SourceModel->insertGetId($data);
|
||||
}
|
||||
return jok("获取成功",$res['data']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取要转存资源的详细内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShare($pwd_id,$stoken)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => "",
|
||||
"pwd_id" => $pwd_id,
|
||||
"stoken" => $stoken,
|
||||
"pdir_fid" => "0",
|
||||
"force" => "0",
|
||||
"_page" => "1",
|
||||
"_size" => "100",
|
||||
"_fetch_banner" => "1",
|
||||
"_fetch_share" => "1",
|
||||
"_fetch_total" => "1",
|
||||
"_sort" => "file_type:asc,updated_at:desc"
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']);
|
||||
}
|
||||
return $res['data'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转存资源到指定文件夹
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list)
|
||||
{
|
||||
$to_pdir_fid = $this->to_pdir_fid??"";
|
||||
$urlData = array(
|
||||
'fid_list' => $fid_list,
|
||||
'fid_token_list' => $fid_token_list,
|
||||
'to_pdir_fid' => $to_pdir_fid,
|
||||
'pwd_id' => $pwd_id,
|
||||
'stoken' => $stoken,
|
||||
'pdir_fid' => "0",
|
||||
'scene' => "link",
|
||||
);
|
||||
$queryParams = [
|
||||
"entry" => "update_share",
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/save", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']=='require login [guest]'?'夸克未登录,请检查cookie':$res['message']);
|
||||
}
|
||||
return $res['data']['task_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 分享资源拿到task_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareBtn($fid_list,$title)
|
||||
{
|
||||
if(!empty($this->ad_fid)){
|
||||
$fid_list[] = $this->ad_fid;
|
||||
}
|
||||
$urlData = array(
|
||||
'fid_list' => $fid_list,
|
||||
'expired_type' => $this->expired_type,
|
||||
'title' => $title,
|
||||
'url_type' => 1,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']);
|
||||
}
|
||||
return $res['data']['task_id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据task_id拿到自己的资源信息
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareTask($task_id,$retry_index)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => "",
|
||||
"task_id" => $task_id,
|
||||
"retry_index" => $retry_index
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/task", "GET", json_encode($urlData), $this->urlHeader, $queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']);
|
||||
}
|
||||
return $res['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据share_id 获取到分享链接
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getSharePassword($share_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'share_id' => $share_id,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/password", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']);
|
||||
}
|
||||
return $res['data'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deletepdirFid($filelist)
|
||||
{
|
||||
$urlData = array(
|
||||
'action_type' => 2,
|
||||
'exclude_fids' => [],
|
||||
'filelist' => $filelist,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/delete", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取夸克网盘指定文件夹内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getPdirFid($pdir_fid)
|
||||
{
|
||||
$urlData = [];
|
||||
$queryParams = [
|
||||
'pr' => 'ucpro',
|
||||
'fr' => 'pc',
|
||||
'uc_param_str' => '',
|
||||
'pdir_fid' => $pdir_fid,
|
||||
'_page' => 1,
|
||||
'_size' => 200,
|
||||
'_fetch_total' => 1,
|
||||
'_fetch_sub_dirs' => 0,
|
||||
'_sort' => 'file_type:asc,updated_at:desc',
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return [];
|
||||
}
|
||||
return $res['data']['list'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 阿里-0-通过分享id获取file_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan1($share_id)
|
||||
{
|
||||
$urlData = [
|
||||
'share_id' => $share_id,
|
||||
];
|
||||
$urlHeader = array(
|
||||
'Content-Type: application/json',
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v3/share_link/get_share_by_anonymous", "POST", json_encode($urlData),$urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if(!isset($res['file_infos'])){
|
||||
return jerr($res['message']??'转存失败1');
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-0-通过分享id获取X-Share-Token
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan2($share_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'share_id' => $share_id,
|
||||
);
|
||||
$urlHeader = array(
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Encoding: gzip, deflate, br, zstd',
|
||||
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'Authorization: '.$this->Authorization,
|
||||
'Content-Type: application/json',
|
||||
'Origin: https://www.alipan.com',
|
||||
'Priority: u=1, i',
|
||||
'Referer: https://www.alipan.com/',
|
||||
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'Sec-Ch-Ua-Mobile: ?0',
|
||||
'Sec-Ch-Ua-Platform: "Windows"',
|
||||
'Sec-Fetch-Dest: empty',
|
||||
'Sec-Fetch-Mode: cors',
|
||||
'Sec-Fetch-Site: same-site',
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
|
||||
'X-Canary: client=web,app=share,version=v2.3.1'
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/v2/share_link/get_share_token", "POST", json_encode($urlData), $urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if(!isset($res['share_token'])){
|
||||
return jerr($res['message']??'转存失败2');
|
||||
}
|
||||
return $res['share_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-1-保存
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan3($urlData,$share_token)
|
||||
{
|
||||
$urlHeader = array(
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Encoding: gzip, deflate, br, zstd',
|
||||
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'Authorization: '.$this->Authorization,
|
||||
'Content-Type: application/json',
|
||||
'Origin: https://www.alipan.com',
|
||||
'Priority: u=1, i',
|
||||
'Referer: https://www.alipan.com/',
|
||||
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'Sec-Ch-Ua-Mobile: ?0',
|
||||
'Sec-Ch-Ua-Platform: "Windows"',
|
||||
'Sec-Fetch-Dest: empty',
|
||||
'Sec-Fetch-Mode: cors',
|
||||
'Sec-Fetch-Site: same-site',
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
|
||||
'X-Canary: client=web,app=share,version=v2.3.1',
|
||||
'X-Share-Token: '.$share_token
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v4/batch", "POST", json_encode($urlData), $urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if(!isset($res['responses'])){
|
||||
return jerr($res['message']??'转存失败3');
|
||||
}
|
||||
return $res['responses'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-2-分享
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan4($urlData)
|
||||
{
|
||||
$urlHeader = array(
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'Authorization: '.$this->Authorization,
|
||||
'Content-Type: application/json',
|
||||
'Origin: https://www.alipan.com',
|
||||
'Priority: u=1, i',
|
||||
'Referer: https://www.alipan.com/',
|
||||
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'Sec-Ch-Ua-Mobile: ?0',
|
||||
'Sec-Ch-Ua-Platform: "Windows"',
|
||||
'Sec-Fetch-Dest: empty',
|
||||
'Sec-Fetch-Mode: cors',
|
||||
'Sec-Fetch-Site: same-site',
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
|
||||
'X-Canary: client=web,app=share,version=v2.3.1'
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v2/share_link/create", "POST", json_encode($urlData), $urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
return jerr($res);
|
||||
if(!isset($res['share_url'])){
|
||||
return jerr($res['message']??'转存失败4');
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* UC 00000
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getStokenUc($pwd_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'passcode' => '',
|
||||
'pwd_id' => $pwd_id,
|
||||
);
|
||||
$urlHeader = array(
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9',
|
||||
'content-type: application/json;charset=UTF-8',
|
||||
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'sec-ch-ua-mobile: ?0',
|
||||
'sec-ch-ua-platform: "Windows"',
|
||||
'sec-fetch-dest: empty',
|
||||
'sec-fetch-mode: cors',
|
||||
'sec-fetch-site: same-site',
|
||||
'Referer: https://drive.uc.cn/',
|
||||
'Referrer-Policy: strict-origin-when-cross-origin',
|
||||
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
);
|
||||
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share/sharepage/token?pr=UCBrowser&fr=pc", "POST",json_encode($urlData),$urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr($res['message']);
|
||||
}
|
||||
$data = $res['data'];
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ class Other extends QfShop
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SourceModel();
|
||||
$this->cookie = Config('qfshop.quark_cookie');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,14 +24,9 @@ class Other extends QfShop
|
||||
*/
|
||||
public function all_search($param='')
|
||||
{
|
||||
if(empty($param)){
|
||||
$searchdata = input('post.');
|
||||
if (empty($searchdata['title'])) {
|
||||
return jerr("请输入要看的内容");
|
||||
}
|
||||
$title = $searchdata['title'];
|
||||
}else{
|
||||
$title = $param;
|
||||
$title = $param ?: input('post.title', '');
|
||||
if (empty($title)) {
|
||||
return jerr("请输入要看的内容");
|
||||
}
|
||||
|
||||
$map[] = ['status', '=', 1];
|
||||
@@ -42,29 +36,17 @@ class Other extends QfShop
|
||||
|
||||
$urls = $this->model->where($map)->field('source_id as id, title, url,is_time')->order('update_time', 'desc')->limit(5)->select()->toArray();
|
||||
if (!empty($urls)) {
|
||||
|
||||
// 获取所有需要更新的ID
|
||||
$ids = [];
|
||||
foreach ($urls as $item) {
|
||||
$ids[] = $item['id'];
|
||||
}
|
||||
|
||||
// 更新数据库中的 update_time 字段
|
||||
if (!empty($ids)) {
|
||||
$this->model->whereIn('source_id', $ids)->update(['update_time' => time()]);
|
||||
}
|
||||
|
||||
$ids = array_column($urls, 'id');
|
||||
$this->model->whereIn('source_id', $ids)->update(['update_time' => time()]);
|
||||
return !empty($param) ? $urls : jok('临时资源获取成功', $urls);
|
||||
}
|
||||
|
||||
|
||||
//同一个搜索内容锁机
|
||||
if (Cache::has($title)) {
|
||||
//同一个搜索内容锁机
|
||||
if (Cache::has($title)) {
|
||||
// 检查缓存中是否已有结果
|
||||
return !empty($param) ? Cache::get($title) : jok('临时资源获取成功', Cache::get($title));
|
||||
}
|
||||
|
||||
|
||||
// 检查是否有正在处理的请求
|
||||
if (Cache::has($title . '_processing')) {
|
||||
// 如果当前正在处理相同关键词的请求,等待结果
|
||||
@@ -89,41 +71,19 @@ class Other extends QfShop
|
||||
$num_total = 2; //最多想要几条结果
|
||||
$num_success = 0;
|
||||
|
||||
// 处理第2个源
|
||||
foreach (source2($title) as $value) {
|
||||
// 定义源的顺序
|
||||
$sources = ['source2', 'source4', 'source5', 'source3', 'source1'];
|
||||
|
||||
foreach ($sources as $source) {
|
||||
if ($num_success >= $num_total) {
|
||||
break; // 有效结果数量已达到,则跳出循环
|
||||
break;
|
||||
}
|
||||
// 如果 URL 不存在则新增 $value
|
||||
if (!$this->urlExists($searchList, $value['url'])) {
|
||||
$searchList[] = $value;
|
||||
$this->processUrl($value, $num_success, $datas);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 处理第4个源
|
||||
if ($num_success < $num_total) {
|
||||
foreach (source4($title) as $value) {
|
||||
|
||||
foreach ($source($title) as $value) {
|
||||
if ($num_success >= $num_total) {
|
||||
break; // 有效结果数量已达到,则跳出循环
|
||||
break;
|
||||
}
|
||||
// 如果 URL 不存在则新增 $value
|
||||
if (!$this->urlExists($searchList, $value['url'])) {
|
||||
$searchList[] = $value;
|
||||
$this->processUrl($value, $num_success, $datas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理第5个源
|
||||
if ($num_success < $num_total) {
|
||||
foreach (source5($title) as $value) {
|
||||
if ($num_success >= $num_total) {
|
||||
break; // 有效结果数量已达到,则跳出循环
|
||||
}
|
||||
// 如果 URL 不存在则新增 $value
|
||||
|
||||
if (!$this->urlExists($searchList, $value['url'])) {
|
||||
$searchList[] = $value;
|
||||
$this->processUrl($value, $num_success, $datas);
|
||||
@@ -131,36 +91,6 @@ class Other extends QfShop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理第3个源
|
||||
if ($num_success < $num_total) {
|
||||
foreach (source3($title) as $value) {
|
||||
if ($num_success >= $num_total) {
|
||||
break; // 有效结果数量已达到,则跳出循环
|
||||
}
|
||||
// 如果 URL 不存在则新增 $value
|
||||
if (!$this->urlExists($searchList, $value['url'])) {
|
||||
$searchList[] = $value;
|
||||
$this->processUrl($value, $num_success, $datas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理第1个源 第一个源放最后
|
||||
if ($num_success < $num_total) {
|
||||
foreach (source1($title) as $value) {
|
||||
if ($num_success >= $num_total) {
|
||||
break; // 有效结果数量已达到,则跳出循环
|
||||
}
|
||||
// 如果 URL 不存在则新增 $value
|
||||
if (!$this->urlExists($searchList, $value['url'])) {
|
||||
$searchList[] = $value;
|
||||
$this->processUrl($value, $num_success, $datas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache::set($title, $datas, 60); // 缓存结果60秒
|
||||
Cache::delete($title . '_processing'); // 解锁
|
||||
|
||||
@@ -201,15 +131,14 @@ class Other extends QfShop
|
||||
$pwd_id = substr($substring, 2); // 去除 's/' 部分
|
||||
|
||||
$urlData = array(
|
||||
'cookie' => $this->cookie,
|
||||
'url' => $value['url'],
|
||||
'expired_type' => 2,
|
||||
'to_pdir_fid' => '', //存入目标文件
|
||||
'ad_fid' => '', //分享时带上这个文件
|
||||
);
|
||||
$res = curlHelper(Request::domain()."/api/open/transfer", "POST", $urlData)['body'];
|
||||
$res = json_decode($res, true);
|
||||
|
||||
|
||||
$transfer = new \netdisk\Transfer();
|
||||
$res = $transfer->transfer($urlData);
|
||||
|
||||
if($res['code'] !== 200){
|
||||
return; // 模拟 continue 行为
|
||||
}
|
||||
@@ -247,40 +176,15 @@ class Other extends QfShop
|
||||
$this->model->where($map)->chunk(100, function ($order) {
|
||||
foreach ($order as $value) {
|
||||
$deles = $value->toArray();
|
||||
// $filelist = [];
|
||||
// $filelist[] = $deles['fid'];
|
||||
|
||||
$fid = $deles['fid'];
|
||||
|
||||
// 尝试解码,如果是有效的 JSON 数组则使用,否则转为单元素数组
|
||||
$filelist = (is_string($fid) && ($decodedFid = json_decode($fid, true)) && is_array($decodedFid)) ? $decodedFid : (array)$fid;
|
||||
|
||||
|
||||
$urlData = array(
|
||||
'action_type' => 2,
|
||||
'exclude_fids' => [],
|
||||
'filelist' => $filelist,
|
||||
);
|
||||
$urlHeader = array(
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9',
|
||||
'content-type: application/json;charset=UTF-8',
|
||||
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'sec-ch-ua-mobile: ?0',
|
||||
'sec-ch-ua-platform: "Windows"',
|
||||
'sec-fetch-dest: empty',
|
||||
'sec-fetch-mode: cors',
|
||||
'sec-fetch-site: same-site',
|
||||
'Referer: https://pan.quark.cn/',
|
||||
'Referrer-Policy: strict-origin-when-cross-origin',
|
||||
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'cookie: '.$this->cookie,
|
||||
);
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/delete?pr=ucpro&fr=pc&uc_param_str=", "POST", json_encode($urlData), $urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] == 200){
|
||||
$this->model->where('fid', $deles['fid'])->delete();
|
||||
}
|
||||
|
||||
$this->model->where('fid', $deles['fid'])->delete();
|
||||
$transfer = new \netdisk\Transfer();
|
||||
$transfer->deletepdirFid($deles['is_type'],$filelist);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,14 @@ function jok($message = 'success', $data = null)
|
||||
}
|
||||
die;
|
||||
}
|
||||
function jok2($message = 'success', $data = null)
|
||||
{
|
||||
if ($data) {
|
||||
return ["code" => 200, "message" => $message, 'data' => $data];
|
||||
} else {
|
||||
return ["code" => 200, "message" => $message, 'data' => $data??''];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 输出错误JSON
|
||||
*
|
||||
@@ -30,6 +38,10 @@ function jerr($message = 'error', $code = 500)
|
||||
echo json_encode(["code" => $code, "message" => $message]);
|
||||
die;
|
||||
}
|
||||
function jerr2($message = 'error', $code = 500)
|
||||
{
|
||||
return ["code" => $code, "message" => $message];
|
||||
}
|
||||
/**
|
||||
* 密码+盐 加密
|
||||
*
|
||||
@@ -789,6 +801,85 @@ function determineIsType($url) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析网盘分享链接
|
||||
*
|
||||
* @param string $input 输入的链接文本,可以是多行
|
||||
* @return array 解析后的链接数组,每个元素包含url、title和code
|
||||
*/
|
||||
function parsePanLinks($input)
|
||||
{
|
||||
// 分割多行输入
|
||||
$links = explode("\n", $input);
|
||||
|
||||
// 去掉数组元素中的空白字符
|
||||
$links = array_map('trim', $links);
|
||||
|
||||
// 过滤掉空值的数组元素
|
||||
$links = array_filter($links);
|
||||
|
||||
$parsedLinks = array_values(array_filter(array_map(function ($item) {
|
||||
// 统一处理百度网盘分享格式,同时匹配两种格式
|
||||
if (preg_match('/链接:?\s*(https?:\/\/[^\s]+)\s*提取码:?\s*([a-zA-Z0-9]{4})/i', $item, $matches)) {
|
||||
$url = trim($matches[1]);
|
||||
$code = trim($matches[2]);
|
||||
// 确保URL中包含提取码
|
||||
if (!empty($code) && strpos($url, '?pwd=') === false) {
|
||||
$url .= (strpos($url, '?') === false ? '?' : '&') . 'pwd=' . $code;
|
||||
}
|
||||
return [
|
||||
'url' => $url,
|
||||
'title' => '',
|
||||
'code' => $code
|
||||
];
|
||||
}
|
||||
|
||||
// 提取 URL
|
||||
if (!preg_match('/https?:\/\/[^\s]+/', $item, $matches)) {
|
||||
return null; // 没有匹配到 URL,直接丢弃
|
||||
}
|
||||
|
||||
$url = trim($matches[0]);
|
||||
$code = '';
|
||||
|
||||
// 提取提取码(?pwd= 或 , 分割)
|
||||
if (preg_match('/\?pwd=([^,\s&]+)/', $item, $pwdMatch)) {
|
||||
$code = trim($pwdMatch[1]);
|
||||
} elseif (preg_match('/,\s*([a-zA-Z0-9]{4})\s*$/', $item, $commaMatch)) {
|
||||
$code = trim($commaMatch[1]);
|
||||
// 添加提取码到URL
|
||||
if (!empty($code)) {
|
||||
$url .= (strpos($url, '?') === false ? '?' : '&') . 'pwd=' . $code;
|
||||
}
|
||||
} elseif (preg_match('/提取码:?\s*([a-zA-Z0-9]{4})/i', $item, $codeMatch)) {
|
||||
$code = trim($codeMatch[1]);
|
||||
// 添加提取码到URL
|
||||
if (!empty($code)) {
|
||||
$url .= (strpos($url, '?') === false ? '?' : '&') . 'pwd=' . $code;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果时,确保 title 保持为空字符串
|
||||
return [
|
||||
'url' => $url,
|
||||
'title' => '',
|
||||
'code' => $code
|
||||
];
|
||||
}, $links)));
|
||||
|
||||
// 去重,使用 'url' 字段来去重
|
||||
$uniqueUrls = [];
|
||||
$result = array_filter($parsedLinks, function($item) use (&$uniqueUrls) {
|
||||
if (!in_array($item['url'], $uniqueUrls)) {
|
||||
$uniqueUrls[] = $item['url']; // 添加到已处理的 URL 列表
|
||||
return true; // 保留此项目
|
||||
}
|
||||
return false; // 去掉重复的项目
|
||||
});
|
||||
|
||||
return array_values($result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 网络资源搜索源一
|
||||
|
||||
@@ -60,6 +60,9 @@ class Source extends QfShop
|
||||
*/
|
||||
public function getDetail(array $data)
|
||||
{
|
||||
if(empty($data['id'])){
|
||||
return jerr('参数错误');
|
||||
}
|
||||
$map[] = ['status', '=', 1];
|
||||
$map[] = ['is_delete', '=', 0];
|
||||
$map[] = ['source_id', '=', $data['id']];
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
{/volist}
|
||||
<div style="height: 120px;"></div>
|
||||
</el-menu>
|
||||
<div class="version">资源管理系统<br> Version 1.0.0</div>
|
||||
<div class="version">资源管理系统<br> Version 3.0.0</div>
|
||||
</el-aside>
|
||||
{else}
|
||||
<div style="position: absolute;top: -72px;left: 0;width: 160px;background-color: #ffffff;box-shadow: 0 0 12px 0 rgb(47 75 168 / 6%);border-radius: 12px;">
|
||||
|
||||
@@ -10,27 +10,181 @@
|
||||
</style>
|
||||
{include file="common/header"/}
|
||||
<el-card class="box-card" shadow="never">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>目前仅支持夸克</span>
|
||||
</div>
|
||||
<div class="text item">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>设置夸克cookie</span>
|
||||
</div>
|
||||
<div style="font-size:14px;color:#666;">
|
||||
<el-form :model="form">
|
||||
<el-form-item>
|
||||
<el-input style="width: 100%;" v-model="form.cookie" placeholder="夸克云盘网页版的cookie"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<p>Tips:夸克云盘网页版的cookie,不懂如何获取请百度;填写并保存后才能使用下面功能</p>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane label="夸克网盘" name="0">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>夸克网盘</span>
|
||||
</div>
|
||||
<div style="font-size:14px;color:#666;">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="设置cookie">
|
||||
<el-input style="width: 100%;" v-model="form.quark_cookie" placeholder="请输入">
|
||||
<el-button slot="prepend" @click="getFile(0)">账号检测</el-button>
|
||||
</el-input>
|
||||
<span class="f_tips">cookie修改后,请保存后再选择转存目录和检测</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认转存目录">
|
||||
<el-input style="width: 100%" v-model="form.quark_file" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.quark_file" :props="quark_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="临时资源目录">
|
||||
<el-input style="width: 100%" v-model="form.quark_file_time" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.quark_file_time" :props="quark_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="阿里云盘" name="1">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>阿里云盘</span>
|
||||
</div>
|
||||
<div style="font-size:14px;color:#666;">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="设置Token">
|
||||
<el-input style="width: 100%;" v-model="form.Authorization" placeholder="请输入">
|
||||
<el-button slot="prepend" @click="getFile(1)">账号检测</el-button>
|
||||
</el-input>
|
||||
<span class="f_tips">token修改后,请保存后再选择转存目录和检测</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认转存目录">
|
||||
<el-input style="width: 100%" v-model="form.ali_file" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.ali_file" :props="ali_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="临时资源目录">
|
||||
<el-input style="width: 100%" v-model="form.ali_file_time" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.ali_file_time" :props="ali_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<p>Tips:转存目录不能为空,为空将无法转存; <font color=orangered>阿里网盘禁止香港及海外服务器调用分享接口</font></p>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="百度网盘" name="2">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>百度网盘</span>
|
||||
</div>
|
||||
<div style="font-size:14px;color:#666;">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="设置cookie">
|
||||
<el-input style="width: 100%;" v-model="form.baidu_cookie" placeholder="请输入">
|
||||
<el-button slot="prepend" @click="getFile(2)">账号检测</el-button>
|
||||
</el-input>
|
||||
<span class="f_tips">cookie修改后,请保存后再选择转存目录和检测</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认转存目录">
|
||||
<el-input style="width: 100%;" v-model="form.baidu_file" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.baidu_file" :props="baidu_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="临时资源目录">
|
||||
<el-input style="width: 100%;" v-model="form.baidu_file_time" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.baidu_file_time" :props="baidu_props" ></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="UC网盘" name="3">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>UC网盘</span>
|
||||
</div>
|
||||
<div style="font-size:14px;color:#666;">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="设置cookie">
|
||||
<el-input style="width: 100%;" v-model="form.uc_cookie" placeholder="请输入">
|
||||
<el-button slot="prepend" @click="getFile(3)">账号检测</el-button>
|
||||
</el-input>
|
||||
<span class="f_tips">cookie修改后,请保存后再选择转存目录和检测</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认转存目录">
|
||||
<el-input style="width: 100%" v-model="form.uc_file" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.uc_file" :props="uc_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="临时资源目录">
|
||||
<el-input style="width: 100%" v-model="form.uc_file_time" placeholder="请输入或选择">
|
||||
<div slot="prepend" style="position: relative;">
|
||||
<p>请选择</p>
|
||||
<el-cascader style="opacity: 0; height: 38px; position: absolute;inset: 0;" v-model="form.uc_file_time" :props="uc_props"></el-cascader>
|
||||
</div>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="迅雷云盘" name="4">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>迅雷云盘</span>
|
||||
</div>
|
||||
<div style="font-size:14px;color:#666;">
|
||||
<p>Tips:<font color=orangered>迅雷云盘暂不支持</font></p>
|
||||
<el-form :model="form">
|
||||
<el-form-item label="设置cookie">
|
||||
<el-input style="width: 100%;" v-model="form.xunlei_cookie" placeholder="请输入">
|
||||
</el-input>
|
||||
<span class="f_tips">cookie修改后,请保存后再选择转存目录和检测</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认转存目录">
|
||||
<el-input style="width: 100%" v-model="form.xunlei_file" placeholder="请输入或选择">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="临时资源目录">
|
||||
<el-input style="width: 100%" v-model="form.xunlei_file_time" placeholder="请输入或选择">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
{include file="common/footer"/}
|
||||
<script>
|
||||
@@ -38,16 +192,140 @@
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
activeName: '0',
|
||||
configKeys: ['quark_cookie', 'quark_file', 'quark_file_time','baidu_cookie', 'baidu_file', 'baidu_file_time','Authorization', 'ali_file', 'ali_file_time','uc_cookie', 'uc_file', 'uc_file_time','xunlei_cookie', 'xunlei_file', 'xunlei_file_time'],
|
||||
form: {
|
||||
cookie: '',
|
||||
quark_file: ''
|
||||
},
|
||||
quark_files: [],
|
||||
quark_props: {
|
||||
lazy: true,
|
||||
emitPath: false,
|
||||
checkStrictly: true,
|
||||
lazyLoad (node, resolve) {
|
||||
const { level, value } = node;
|
||||
let that = this;
|
||||
axios.post('/admin/source/getFiles', Object.assign({
|
||||
type: 0,
|
||||
pdir_fid: value || 0
|
||||
}, PostBase))
|
||||
.then(function (res) {
|
||||
if (res.data.code == 200) {
|
||||
// 只显示文件夹
|
||||
const nodes = (res.data.data || [])
|
||||
.map(item => ({
|
||||
value: item.fid,
|
||||
label: item.file_name,
|
||||
disabled: !item.dir,
|
||||
}));
|
||||
resolve(nodes);
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
resolve([]);
|
||||
});
|
||||
}
|
||||
},
|
||||
baidu_props: {
|
||||
lazy: true,
|
||||
emitPath: false,
|
||||
checkStrictly: true,
|
||||
lazyLoad (node, resolve) {
|
||||
const { level, value } = node;
|
||||
let that = this;
|
||||
axios.post('/admin/source/getFiles', Object.assign({
|
||||
type: 2,
|
||||
pdir_fid: value || 0
|
||||
}, PostBase))
|
||||
.then(function (res) {
|
||||
if (res.data.code == 200) {
|
||||
// 只显示文件夹
|
||||
const nodes = (res.data.data || [])
|
||||
.map(item => ({
|
||||
value: item.path,
|
||||
label: item.server_filename,
|
||||
disabled: !item.isdir,
|
||||
}));
|
||||
resolve(nodes);
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
resolve([]);
|
||||
});
|
||||
}
|
||||
},
|
||||
ali_props: {
|
||||
lazy: true,
|
||||
emitPath: false,
|
||||
checkStrictly: true,
|
||||
lazyLoad (node, resolve) {
|
||||
const { level, value } = node;
|
||||
let that = this;
|
||||
axios.post('/admin/source/getFiles', Object.assign({
|
||||
type: 1,
|
||||
pdir_fid: value || 0
|
||||
}, PostBase))
|
||||
.then(function (res) {
|
||||
if (res.data.code == 200) {
|
||||
// 只显示文件夹
|
||||
const nodes = (res.data.data || [])
|
||||
.map(item => ({
|
||||
value: item.file_id,
|
||||
label: item.name,
|
||||
disabled: item.type!='folder',
|
||||
}));
|
||||
resolve(nodes);
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
resolve([]);
|
||||
});
|
||||
}
|
||||
},
|
||||
uc_props: {
|
||||
lazy: true,
|
||||
emitPath: false,
|
||||
checkStrictly: true,
|
||||
lazyLoad (node, resolve) {
|
||||
const { level, value } = node;
|
||||
let that = this;
|
||||
axios.post('/admin/source/getFiles', Object.assign({
|
||||
type: 3,
|
||||
pdir_fid: value || 0
|
||||
}, PostBase))
|
||||
.then(function (res) {
|
||||
if (res.data.code == 200) {
|
||||
// 只显示文件夹
|
||||
const nodes = (res.data.data || [])
|
||||
.map(item => ({
|
||||
value: item.fid,
|
||||
label: item.file_name,
|
||||
disabled: !item.dir,
|
||||
}));
|
||||
resolve(nodes);
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
resolve([]);
|
||||
});
|
||||
}
|
||||
},
|
||||
file: '',
|
||||
files: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getData();
|
||||
// this.getFile()
|
||||
},
|
||||
methods: {
|
||||
getData(){
|
||||
@@ -56,11 +334,8 @@
|
||||
.then(function (response) {
|
||||
if (response.data.code == 200) {
|
||||
for (let item of response.data.data) {
|
||||
if(item.conf_key === 'quark_cookie'){
|
||||
that.form.cookie = item.conf_value
|
||||
}
|
||||
if(item.conf_key === 'quark_file'){
|
||||
that.file = item.conf_value
|
||||
if (that.configKeys.includes(item.conf_key)) {
|
||||
that.$set(that.form, item.conf_key, item.conf_value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -73,16 +348,13 @@
|
||||
},
|
||||
onSubmit(){
|
||||
let that = this
|
||||
axios.post('/admin/conf/updateBaseConfig', Object.assign({}, PostBase, {
|
||||
quark_cookie: that.form.cookie
|
||||
}))
|
||||
axios.post('/admin/conf/updateBaseConfig', Object.assign({}, PostBase, that.form))
|
||||
.then(function (response) {
|
||||
if (response.data.code == 200) {
|
||||
that.$message({
|
||||
message: response.data.message,
|
||||
type: 'success'
|
||||
});
|
||||
that.getFile()
|
||||
} else {
|
||||
that.$message.error(response.data.message);
|
||||
}
|
||||
@@ -93,12 +365,14 @@
|
||||
});
|
||||
},
|
||||
|
||||
getFile(){
|
||||
getFile(type){
|
||||
let that = this
|
||||
axios.post('/admin/source/getFiles', Object.assign({}, PostBase))
|
||||
axios.post('/admin/source/getFiles', Object.assign({
|
||||
type
|
||||
}, PostBase))
|
||||
.then(function (res) {
|
||||
if (res.data.code == 200) {
|
||||
that.files = res.data || []
|
||||
that.$message.success("已登录,cookie可用");
|
||||
} else {
|
||||
that.$message.error(res.data.message);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加资源</el-button>
|
||||
<el-button icon="el-icon-delete" size="small" @click="postMultDelete" plain>批量删除</el-button>
|
||||
<el-button icon="el-icon-document-copy" size="small" @click="getExport" plain>导出资源</el-button>
|
||||
<el-button icon="el-icon-plus" size="small" @click="ImportShow" plain>夸克导入专用</el-button>
|
||||
<el-button icon="el-icon-plus" size="small" @click="ImportShow" plain>表格导入</el-button>
|
||||
<el-button icon="el-icon-plus" size="small" @click="ImportBatch" plain>批量导入</el-button>
|
||||
</el-form-item>
|
||||
<div style="float:right">
|
||||
@@ -167,9 +167,9 @@
|
||||
<el-radio-button :label="2">转存分享导入</el-radio-button>
|
||||
</el-radio-group>
|
||||
<p style="color: #999;" v-if='Batchform.type==1'>直接导入:链接校验有效后直接入库;Tips:该功能不会检测是否重复;</p>
|
||||
<p style="color: #999;" v-else-if='Batchform.type==2'>将资源转存到自己网盘后分享入库(<font color=orangered>此功能仅支持夸克</font>)Tips:该功能不会检测是否重复;</p>
|
||||
<span style="color: #999;" v-if='Batchform.type==1'>支持<font color=orangered>夸克、阿里、UC</font>的网盘资源(一次最多可以上传500条资源)</span>
|
||||
<span style="color: #999;" v-else-if='Batchform.type==2'>目前仅支持<font color=orangered>夸克</font>的网盘资源(一次最多可以上传500条资源)</span>
|
||||
<p style="color: #999;" v-else-if='Batchform.type==2'>将资源转存到自己网盘后分享入库;Tips:该功能不会检测是否重复;</p>
|
||||
<span style="color: #999;" v-if='Batchform.type==1'>支持<font color=orangered>夸克、阿里、UC、百度</font>的网盘资源(一次最多可以上传500条资源)</span>
|
||||
<span style="color: #999;" v-else-if='Batchform.type==2'>支持<font color=orangered>夸克、阿里、UC、百度</font>的网盘资源(一次最多可以上传500条资源)</span>
|
||||
</el-form-item>
|
||||
<el-form-item prop="source_category_id" label="资源分类" label-width="70px" v-if="Batchform.type">
|
||||
<el-select size="medium" v-model="Batchform.source_category_id" placeholder="请选择分类" clearable>
|
||||
@@ -187,7 +187,8 @@
|
||||
一条资源一行
|
||||
https://pan.quark.cn/s/xxxxxxxx
|
||||
https://www.alipan.com/s/xxxxxxxxx
|
||||
https://drive.uc.cn/s/xxxxxxxxxxx"
|
||||
https://drive.uc.cn/s/xxxxxxxxxxx
|
||||
https://pan.baidu.com/s/xxxxxx?pwd=xxxx"
|
||||
v-model="Batchform.urls"
|
||||
rows="20"
|
||||
show-word-limit
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"name": "hamm/y-admin",
|
||||
"description": "Fast build your php project",
|
||||
"type": "project",
|
||||
"keywords": [
|
||||
"YAdmin"
|
||||
],
|
||||
"homepage": "https://www.baidu.com/",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "",
|
||||
"email": "admin@qq.cn"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1.0",
|
||||
"topthink/framework": "^6.0.0",
|
||||
"topthink/think-orm": "^2.0",
|
||||
"topthink/think-multi-app": "^1.0",
|
||||
"topthink/think-view": "^1.0",
|
||||
"alibabacloud/client": "^1.5",
|
||||
"phpoffice/phpexcel": "^1.8",
|
||||
"overtrue/wechat": "~4.0",
|
||||
"jaeger/querylist": "^4.2",
|
||||
"topthink/think-queue": "3.0",
|
||||
"topthink/think-filesystem": "1.0.1",
|
||||
"lizhichao/word": "^2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "^4.2",
|
||||
"topthink/think-trace": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"app\\": "app"
|
||||
},
|
||||
"psr-0": {
|
||||
"": "extend/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"allow-plugins": {
|
||||
"easywechat-composer/easywechat-composer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@php think service:discover",
|
||||
"@php think vendor:publish"
|
||||
]
|
||||
}
|
||||
}
|
||||
4187
composer.lock
generated
122
extend/netdisk/Transfer.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
namespace netdisk;
|
||||
|
||||
class Transfer
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// 原 Open 类的构造函数内容
|
||||
$this->url = ""; // 资源地址
|
||||
$this->expired_type = 1; //有效期 1分享永久 2临时
|
||||
$this->ad_fid = ""; //夸克专用 - 分享时带上这个文件的fid
|
||||
$this->code = ""; //分享码
|
||||
$this->isType = 0; //0 转存并分享后的资源信息 1直接获取资源信息
|
||||
}
|
||||
|
||||
public function getFiles($type=0,$pdir_fid=0)
|
||||
{
|
||||
if($type == 1){
|
||||
//阿里
|
||||
$pan = new \netdisk\pan\AlipanPan();
|
||||
return $pan->getFiles($pdir_fid);
|
||||
} else if($type == 2){
|
||||
//百度网盘
|
||||
$pan = new \netdisk\pan\BaiduPan();
|
||||
return $pan->getFiles($pdir_fid);
|
||||
} else if($type == 3){
|
||||
//UC
|
||||
$pan = new \netdisk\pan\UcPan();
|
||||
return $pan->getFiles($pdir_fid);
|
||||
} else {
|
||||
//夸克
|
||||
$pan = new \netdisk\pan\QuarkPan();
|
||||
return $pan->getFiles($pdir_fid);
|
||||
}
|
||||
}
|
||||
|
||||
public function transfer($urlData = [])
|
||||
{
|
||||
$url = $urlData['url']??'';
|
||||
$config = [
|
||||
'isType' => $urlData['isType'] ?? input('isType') ?? 0,
|
||||
'url' => $url,
|
||||
'code' => $urlData['code'] ?? input('code') ?? '',
|
||||
'expired_type' => $urlData['expired_type'] ?? input('expired_type') ?? 1,
|
||||
'ad_fid' => $urlData['ad_fid'] ?? input('ad_fid') ?? "",
|
||||
'stoken' => $urlData['stoken'] ?? '',
|
||||
];
|
||||
|
||||
if (strpos($url, '?entry=') !== false) {
|
||||
$entry = preg_match('/\?entry=([^&]+)/', $url, $matches) ? $matches[1] : '';
|
||||
$url = preg_match('/.*(?=\?entry=)/', $url, $matches) ? $matches[0] : '';
|
||||
}
|
||||
|
||||
$substring = strstr($url, 's/');
|
||||
if ($substring !== false) {
|
||||
$pwd_id = substr($substring, 2); // 去除 's/' 部分
|
||||
} else {
|
||||
return jerr2("资源地址格式有误");
|
||||
}
|
||||
|
||||
$patterns = [
|
||||
'pan.quark.cn' => 0,
|
||||
'www.alipan.com' => 1,
|
||||
'www.aliyundrive.com' => 1,
|
||||
'pan.baidu.com' => 2,
|
||||
'drive.uc.cn' => 3,
|
||||
// 'pan.xunlei.com' => 4,
|
||||
];
|
||||
|
||||
$url_type = -1; // 默认值为 -1
|
||||
foreach ($patterns as $pattern => $type) {
|
||||
if (strpos($url, $pattern) !== false) {
|
||||
$url_type = $type;
|
||||
break; // 一旦匹配成功,退出循环
|
||||
}
|
||||
}
|
||||
|
||||
$this->url = $url;
|
||||
|
||||
if ($url_type == 0) {
|
||||
//夸克
|
||||
$pan = new \netdisk\pan\QuarkPan($config);
|
||||
return $pan->transfer(strtok($pwd_id, '#'));
|
||||
} else if($url_type == 1){
|
||||
//阿里
|
||||
$pan = new \netdisk\pan\AlipanPan($config);
|
||||
return $pan->transfer(strtok($pwd_id, '#'));
|
||||
} else if($url_type == 2){
|
||||
//百度网盘
|
||||
$pan = new \netdisk\pan\BaiduPan($config);
|
||||
return $pan->transfer(strtok($pwd_id, '#'));
|
||||
} else if($url_type == 3){
|
||||
//UC
|
||||
$pan = new \netdisk\pan\UcPan($config);
|
||||
return $pan->transfer(strtok($pwd_id, '#'));
|
||||
} else {
|
||||
return jerr2("资源地址格式有误");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function deletepdirFid($type=0,$filelist)
|
||||
{
|
||||
if($type == 1){
|
||||
//阿里
|
||||
$pan = new \netdisk\pan\AlipanPan();
|
||||
return $pan->deletepdirFid($filelist);
|
||||
} else if($type == 2){
|
||||
//百度网盘
|
||||
$pan = new \netdisk\pan\BaiduPan();
|
||||
return $pan->deletepdirFid($filelist);
|
||||
} else if($type == 3){
|
||||
//UC
|
||||
$pan = new \netdisk\pan\UcPan();
|
||||
return $pan->deletepdirFid(filelist);
|
||||
} else {
|
||||
//夸克
|
||||
$pan = new \netdisk\pan\QuarkPan();
|
||||
return $pan->deletepdirFid($filelist);
|
||||
}
|
||||
}
|
||||
}
|
||||
308
extend/netdisk/pan/AlipanPan.php
Normal file
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
namespace netdisk\pan;
|
||||
|
||||
class AlipanPan extends BasePan
|
||||
{
|
||||
public function __construct($config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->urlHeader = [
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||
'Authorization: ',
|
||||
'Content-Type: application/json',
|
||||
'Origin: https://www.alipan.com',
|
||||
'Priority: u=1, i',
|
||||
'Referer: https://www.alipan.com/',
|
||||
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'Sec-Ch-Ua-Mobile: ?0',
|
||||
'Sec-Ch-Ua-Platform: "Windows"',
|
||||
'Sec-Fetch-Dest: empty',
|
||||
'Sec-Fetch-Mode: cors',
|
||||
'Sec-Fetch-Site: same-site',
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
|
||||
'X-Canary: client=web,app=share,version=v2.3.1'
|
||||
];
|
||||
}
|
||||
|
||||
public function getFiles($pdir_fid=0)
|
||||
{
|
||||
$tokenFile = __DIR__ . '/access_token.json';
|
||||
$access_token = $this->manageAccessToken($tokenFile);
|
||||
if(empty($access_token)){
|
||||
return jerr2('登录状态异常,获取access_token失败');
|
||||
}
|
||||
foreach ($this->urlHeader as &$header) {
|
||||
if (str_starts_with($header, 'Authorization: ')) {
|
||||
$header = 'Authorization: Bearer ' . $access_token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($pdir_fid === 0){
|
||||
$pdir_fid = 'root';
|
||||
}
|
||||
|
||||
$urlData = array(
|
||||
'all' => false,
|
||||
'drive_id' => '2008425230',
|
||||
'fields' => "*",
|
||||
'limit' => 100,
|
||||
'order_by' => "updated_at",
|
||||
'order_direction' => "DESC",
|
||||
'parent_file_id' => $pdir_fid,
|
||||
'url_expire_sec' => 14400,
|
||||
);
|
||||
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v3/file/list", "POST", json_encode($urlData),$this->urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if(!empty($res['message'])){
|
||||
return jerr2($res['message']);
|
||||
}
|
||||
return jok2('获取成功',$res['items']);
|
||||
}
|
||||
|
||||
public function transfer($share_id)
|
||||
{
|
||||
$tokenFile = __DIR__ . '/access_token.json';
|
||||
$access_token = $this->manageAccessToken($tokenFile);
|
||||
if(empty($access_token)){
|
||||
return jerr2('登录状态异常,获取access_token失败');
|
||||
}
|
||||
foreach ($this->urlHeader as &$header) {
|
||||
if (str_starts_with($header, 'Authorization: ')) {
|
||||
$header = 'Authorization: Bearer ' . $access_token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$data = [];
|
||||
$res = $this->getAlipan1($share_id);
|
||||
if(!isset($res['file_infos'])){
|
||||
return jerr2($res['message']);
|
||||
}
|
||||
$infos = $res;
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $infos['share_name'];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok2('检验成功', $urls);
|
||||
}
|
||||
|
||||
//通过分享id获取file_id
|
||||
$file_infos = $infos['file_infos'];
|
||||
//通过分享id获取X-Share-Token
|
||||
$res = $this->getAlipan2($share_id);
|
||||
if(!isset($res['share_token'])){
|
||||
return jerr2($res['message']);
|
||||
}
|
||||
$share_token = $res['share_token'];
|
||||
|
||||
$to_pdir_fid = Config('qfshop.ali_file'); //默认存储路径
|
||||
if($this->expired_type == 2){
|
||||
$to_pdir_fid = Config('qfshop.ali_file_time'); //临时资源路径
|
||||
}
|
||||
|
||||
$data3['requests'] = [];
|
||||
$data3['resource'] = 'file';
|
||||
|
||||
foreach ($file_infos as $key=>$value) {
|
||||
$data3['requests'][$key]['body']['auto_rename'] = true;
|
||||
$data3['requests'][$key]['body']['file_id'] = $value['file_id'];
|
||||
$data3['requests'][$key]['body']['share_id'] = $share_id;
|
||||
$data3['requests'][$key]['body']['to_drive_id'] = '2008425230';
|
||||
$data3['requests'][$key]['body']['to_parent_file_id'] = $to_pdir_fid;
|
||||
$data3['requests'][$key]['headers']['Content-Type'] = 'application/json';
|
||||
$data3['requests'][$key]['id'] = $key.'';
|
||||
$data3['requests'][$key]['method'] = 'POST';
|
||||
$data3['requests'][$key]['url'] = '/file/copy';
|
||||
}
|
||||
|
||||
//保存
|
||||
$res = $this->getAlipan3($data3,$share_token);
|
||||
if (!isset($res['responses'])) {
|
||||
return jerr2($res['message'] ?? '请求失败,无响应数据');
|
||||
}
|
||||
|
||||
$response = $res['responses'][0];
|
||||
$body = $response['body'];
|
||||
if (isset($body['code'])) {
|
||||
return jerr2($body['message'] ?? '请求失败');
|
||||
}
|
||||
|
||||
$responses = $res['responses'];
|
||||
|
||||
$data4['drive_id'] = '2008425230';
|
||||
$data4['expiration'] = '';
|
||||
$data4['share_pwd'] = '';
|
||||
$data4['file_id_list'] = [];
|
||||
|
||||
foreach ($responses as $key=>$value){
|
||||
$data4['file_id_list'][] = $value['body']['file_id'];
|
||||
}
|
||||
|
||||
//分享
|
||||
$res = $this->getAlipan4($data4);
|
||||
if(!isset($res['share_url'])){
|
||||
return jerr2($res['message']??'转存失败4');
|
||||
}
|
||||
$share = $res;
|
||||
|
||||
$data['share_url'] = $share['share_url'];
|
||||
$data['title'] = $share['share_title'];
|
||||
$data['fid'] = $share['file_id_list'];
|
||||
|
||||
return jok2('转存成功', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-0-通过分享id获取file_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan1($share_id)
|
||||
{
|
||||
$urlData = [
|
||||
'share_id' => $share_id,
|
||||
];
|
||||
$urlHeader = array(
|
||||
'Content-Type: application/json',
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v3/share_link/get_share_by_anonymous", "POST", json_encode($urlData),$urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-0-通过分享id获取X-Share-Token
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan2($share_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'share_id' => $share_id,
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/v2/share_link/get_share_token", "POST", json_encode($urlData), $this->urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-1-保存
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan3($urlData,$share_token)
|
||||
{
|
||||
$urlHeader= $this->urlHeader;
|
||||
$urlHeader[] = 'X-Share-Token: '.$share_token;
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v4/batch", "POST", json_encode($urlData), $urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里-2-分享
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAlipan4($urlData)
|
||||
{
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v2/share_link/create", "POST", json_encode($urlData), $this->urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 管理 access_token
|
||||
* @param string $tokenFile token文件路径
|
||||
* @return string access_token
|
||||
*/
|
||||
private function manageAccessToken($tokenFile)
|
||||
{
|
||||
$tokenData = [];
|
||||
$currentRefreshToken = Config('qfshop.Authorization');
|
||||
|
||||
// 检查文件是否存在
|
||||
if (file_exists($tokenFile)) {
|
||||
$tokenData = json_decode(file_get_contents($tokenFile), true);
|
||||
|
||||
// 检查token是否存在且未过期且不为空,且refresh_token未改变
|
||||
if (isset($tokenData['access_token'])
|
||||
&& isset($tokenData['expires_at'])
|
||||
&& isset($tokenData['refresh_token'])
|
||||
&& !empty($tokenData['access_token'])
|
||||
&& time() < $tokenData['expires_at']
|
||||
&& $tokenData['refresh_token'] === $currentRefreshToken
|
||||
) {
|
||||
return $tokenData['access_token'];
|
||||
}
|
||||
}
|
||||
|
||||
// 获取新的token
|
||||
$newToken = $this->getNewAccessToken();
|
||||
|
||||
// 保存新token
|
||||
$tokenData = [
|
||||
'access_token' => $newToken,
|
||||
'refresh_token' => $currentRefreshToken,
|
||||
'expires_at' => time() + 3600
|
||||
];
|
||||
|
||||
file_put_contents($tokenFile, json_encode($tokenData));
|
||||
|
||||
return $newToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新的access_token
|
||||
* @return string
|
||||
*/
|
||||
private function getNewAccessToken()
|
||||
{
|
||||
$urlData = [
|
||||
'refresh_token' => Config('qfshop.Authorization'),
|
||||
];
|
||||
$urlHeader = array(
|
||||
'Content-Type: application/json',
|
||||
);
|
||||
$res = curlHelper("https://api.aliyundrive.com/token/refresh", "POST", json_encode($urlData),$urlHeader)['body'];
|
||||
$res = json_decode($res, true);
|
||||
return $res['access_token']??'';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deletepdirFid($filelist)
|
||||
{
|
||||
$urlData['requests'] = [];
|
||||
$urlData['resource'] = 'file';
|
||||
|
||||
foreach ($filelist as $key=>$value) {
|
||||
$urlData['requests'][$key]['body']['file_id'] = $value??'';
|
||||
$urlData['requests'][$key]['body']['drive_id'] = '2008425230';
|
||||
$urlData['requests'][$key]['headers']['Content-Type'] = 'application/json';
|
||||
$urlData['requests'][$key]['id'] = $value??'';
|
||||
$urlData['requests'][$key]['method'] = 'POST';
|
||||
$urlData['requests'][$key]['url'] = '/recyclebin/trash';
|
||||
}
|
||||
|
||||
$tokenFile = __DIR__ . '/access_token.json';
|
||||
$access_token = $this->manageAccessToken($tokenFile);
|
||||
if(empty($access_token)){
|
||||
return jerr2('登录状态异常,获取access_token失败');
|
||||
}
|
||||
foreach ($this->urlHeader as &$header) {
|
||||
if (str_starts_with($header, 'Authorization: ')) {
|
||||
$header = 'Authorization: Bearer ' . $access_token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$res = curlHelper("https://api.aliyundrive.com/adrive/v4/batch", "POST", json_encode($urlData), $this->urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
}
|
||||
244
extend/netdisk/pan/BaiduPan.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
namespace netdisk\pan;
|
||||
|
||||
class BaiduPan extends BasePan
|
||||
{
|
||||
|
||||
public function getFiles($pdir_fid=0)
|
||||
{
|
||||
if($pdir_fid === 0){
|
||||
$pdir_fid = '/';
|
||||
}
|
||||
$cookie = Config('qfshop.baidu_cookie');
|
||||
$network = new \netdisk\pan\BaiduWork($cookie);
|
||||
|
||||
$res = $network->getDirList($pdir_fid);
|
||||
|
||||
return jok2('获取成功',$res);
|
||||
}
|
||||
|
||||
public function transfer($pwd_id)
|
||||
{
|
||||
$cookie = Config('qfshop.baidu_cookie');
|
||||
$network = new \netdisk\pan\BaiduWork($cookie);
|
||||
|
||||
$bdstoken = $network->getBdstoken();
|
||||
$network->setBdstoken($bdstoken);
|
||||
|
||||
$urlParts = parse_url($this->url);
|
||||
$linkUrl = $urlParts['scheme'] . '://' . $urlParts['host'] . $urlParts['path']; // 分享链接
|
||||
$passCode = $this->code; // 4位提取码
|
||||
|
||||
|
||||
// 先判断是否有提取码
|
||||
if (!empty($passCode)) {
|
||||
// 验证提取码
|
||||
$randsk = $network->verifyPassCode($linkUrl, $passCode);
|
||||
if (is_numeric($randsk)) {
|
||||
return jerr2($network->getErrorMessage($randsk));
|
||||
}
|
||||
// 验证成功,更新 cookie
|
||||
$network->updateBdclnd($randsk);
|
||||
}
|
||||
|
||||
// 获取转存参数
|
||||
$transferParams = $network->getTransferParams($linkUrl);
|
||||
if (is_numeric($transferParams)) {
|
||||
return jerr2($network->getErrorMessage($transferParams));
|
||||
}
|
||||
|
||||
// 解析返回的参数
|
||||
list($shareId, $userId, $fsIds, $fileNames, $isDirs) = $transferParams;
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $fileNames[0];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok2('检验成功', $urls);
|
||||
}
|
||||
|
||||
$folderName = Config('qfshop.baidu_file'); //默认存储路径
|
||||
if($this->expired_type == 2){
|
||||
$folderName = Config('qfshop.baidu_file_time'); //临时资源路径
|
||||
}
|
||||
|
||||
if(empty($folderName)){
|
||||
$folderName = '/心悦转存文件'; // 未设置时默认目录
|
||||
}
|
||||
|
||||
// 检查目录名是否包含非法字符
|
||||
$invalidChars = ['<', '>', '|', '*', '?', '\\', ':'];
|
||||
foreach ($invalidChars as $char) {
|
||||
if (strpos($folderName, $char) !== false) {
|
||||
return jerr2('转存目录名有非法字符,不能包含:< > | * ? \\ :');
|
||||
}
|
||||
}
|
||||
|
||||
// 先检查目录是否存在,不存在再创建
|
||||
$dirList = $network->getDirList($folderName);
|
||||
// 如果返回的是错误码,说明目录不存在,需要创建
|
||||
if (is_numeric($dirList)) {
|
||||
$createResult = $network->createDir($folderName);
|
||||
if ($createResult !== 0) {
|
||||
return jerr2($network->getErrorMessage($createResult));
|
||||
}
|
||||
}
|
||||
|
||||
// 执行文件转存
|
||||
$transferResult = $network->transferFile([$shareId, $userId, $fsIds], $folderName);
|
||||
if ($transferResult !== 0) {
|
||||
return jerr2($network->getErrorMessage($transferResult));
|
||||
}
|
||||
|
||||
// 转存成功后,获取目录中的文件列表
|
||||
$dirList = $network->getDirList('/' . $folderName);
|
||||
if (is_numeric($dirList)) {
|
||||
return jerr2($network->getErrorMessage($dirList));
|
||||
}
|
||||
|
||||
// 找到刚刚转存的所有文件
|
||||
$targetFiles = [];
|
||||
$fsIdList = [];
|
||||
$filePaths = [];
|
||||
$adFilePaths = []; // 用于存储包含广告的文件路径
|
||||
$allFilesAreAds = true; // 假设所有文件都是广告
|
||||
|
||||
foreach ($dirList as $file) {
|
||||
if (in_array($file['server_filename'], $fileNames)) {
|
||||
$targetFiles[] = $file;
|
||||
$fsIdList[] = $file['fs_id'];
|
||||
$filePath = '/' . $folderName . '/' . $file['server_filename'];
|
||||
$filePaths[] = $filePath;
|
||||
|
||||
// 检查文件名是否包含广告内容
|
||||
$containsAd = $this->containsAdKeywords($file['server_filename']);
|
||||
|
||||
// 如果是目录,需要检查目录内的文件
|
||||
if ($file['isdir'] == 1) {
|
||||
// 获取子目录内容
|
||||
$subDirList = $network->getDirList($filePath);
|
||||
if (!is_numeric($subDirList)) {
|
||||
foreach ($subDirList as $subFile) {
|
||||
// 检查子文件是否包含广告关键词
|
||||
if ($this->containsAdKeywords($subFile['server_filename'])) {
|
||||
// 将包含广告的子文件添加到待删除列表
|
||||
$adFilePaths[] = $filePath . '/' . $subFile['server_filename'];
|
||||
} else {
|
||||
// 只要有一个文件不是广告,就将标志设为false
|
||||
$allFilesAreAds = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果是文件,直接判断
|
||||
if ($containsAd) {
|
||||
$adFilePaths[] = $filePath;
|
||||
} else {
|
||||
$allFilesAreAds = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($targetFiles)) {
|
||||
return jerr2('分享失败,找不到刚转存的文件');
|
||||
}
|
||||
|
||||
// 如果所有文件都是广告,删除整个转存的内容
|
||||
if ($allFilesAreAds && !empty($targetFiles)) {
|
||||
// 删除所有转存的文件
|
||||
$deleteResult = $network->batchDeleteFiles($filePaths);
|
||||
if ($deleteResult['errno'] === 0) {
|
||||
return jerr2('资源内容为空或所有转存的文件都包含广告内容,已全部删除');
|
||||
} else {
|
||||
// return jerr2('删除广告文件失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有部分文件是广告,只删除广告文件
|
||||
if (!empty($adFilePaths)) {
|
||||
$deleteResult = $network->batchDeleteFiles($adFilePaths);
|
||||
// 删除后更新文件列表
|
||||
if ($deleteResult['errno'] === 0) {
|
||||
// 从fsIdList和filePaths中移除已删除的广告文件
|
||||
foreach ($adFilePaths as $adPath) {
|
||||
$key = array_search($adPath, $filePaths);
|
||||
if ($key !== false) {
|
||||
unset($filePaths[$key]);
|
||||
unset($fsIdList[$key]);
|
||||
}
|
||||
}
|
||||
// 重新索引数组
|
||||
$filePaths = array_values($filePaths);
|
||||
$fsIdList = array_values($fsIdList);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果删除广告后没有文件了,返回提示
|
||||
if (empty($fsIdList)) {
|
||||
return jerr2('资源内容为空或所有转存的文件都包含广告内容,已全部删除');
|
||||
}
|
||||
|
||||
// 创建分享
|
||||
$expiry = 0; // 0为永久
|
||||
$password = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 4); // 随机4位提取码
|
||||
$shareLink = $network->createShare(implode(',', $fsIdList), $expiry, $password);
|
||||
|
||||
if (is_numeric($shareLink)) {
|
||||
return jerr2($network->getErrorMessage($shareLink));
|
||||
}
|
||||
|
||||
if(!empty($password)){
|
||||
$shareLink = $shareLink. '?pwd='. $password;
|
||||
}
|
||||
// 转存成功
|
||||
return jok2("文件转存成功", [
|
||||
'title' => $fileNames[0],
|
||||
'share_url' => $shareLink,
|
||||
'fid' => $filePaths,
|
||||
'code' => $password,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查文件名是否包含广告关键词
|
||||
* @param string $filename 文件名
|
||||
* @return bool 是否包含广告关键词
|
||||
*/
|
||||
private function containsAdKeywords($filename)
|
||||
{
|
||||
$banned = Config('qfshop.quark_banned') ?? ''; // 如果出现这些字样就删除
|
||||
|
||||
// 广告关键词列表
|
||||
$adKeywords = [];
|
||||
if (!empty($banned)) {
|
||||
$adKeywords = array_map('trim', explode(',', $banned));
|
||||
}
|
||||
|
||||
// 转为小写进行比较
|
||||
$lowercaseFilename = mb_strtolower($filename);
|
||||
|
||||
foreach ($adKeywords as $keyword) {
|
||||
if (mb_strpos($lowercaseFilename, mb_strtolower($keyword)) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deletepdirFid($filePaths)
|
||||
{
|
||||
$cookie = Config('qfshop.baidu_cookie');
|
||||
$network = new \netdisk\pan\BaiduWork($cookie);
|
||||
|
||||
// 调用批量删除方法
|
||||
$result = $network->batchDeleteFiles($filePaths);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
414
extend/netdisk/pan/BaiduWork.php
Normal file
@@ -0,0 +1,414 @@
|
||||
<?php
|
||||
namespace netdisk\pan;
|
||||
|
||||
class BaiduWork
|
||||
{
|
||||
protected $errorCodes = [
|
||||
-1 => '链接错误,链接失效或缺少提取码',
|
||||
-4 => '转存失败,无效登录。请退出账号在其他地方的登录',
|
||||
-6 => '转存失败,请用浏览器无痕模式获取 Cookie 后再试',
|
||||
-7 => '转存失败,转存文件夹名有非法字符,不能包含 < > | * ? \\ :,请改正目录名后重试',
|
||||
-8 => '转存失败,目录中已有同名文件或文件夹存在',
|
||||
-9 => '链接错误,提取码错误',
|
||||
-10 => '转存失败,容量不足',
|
||||
-12 => '链接错误,提取码错误',
|
||||
-62 => '转存失败,链接访问次数过多,请手动转存或稍后再试',
|
||||
0 => '转存成功',
|
||||
2 => '转存失败,目标目录不存在',
|
||||
4 => '转存失败,目录中存在同名文件',
|
||||
12 => '转存失败,转存文件数超过限制',
|
||||
20 => '转存失败,容量不足',
|
||||
105 => '链接错误,所访问的页面不存在'
|
||||
];
|
||||
|
||||
public function getErrorMessage($code)
|
||||
{
|
||||
return $this->errorCodes[$code] ?? "未知错误(错误码:{$code})";
|
||||
}
|
||||
|
||||
protected $session;
|
||||
protected $headers;
|
||||
protected $bdstoken;
|
||||
protected $baseUrl;
|
||||
protected $cookie;
|
||||
|
||||
public function __construct($cookie = '')
|
||||
{
|
||||
$this->cookie = $cookie??'';
|
||||
$this->headers = [
|
||||
'Host: pan.baidu.com',
|
||||
'Connection: keep-alive',
|
||||
'Upgrade-Insecure-Requests: 1',
|
||||
'Sec-Fetch-Dest: document',
|
||||
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
||||
'Sec-Fetch-Site: same-site',
|
||||
'Sec-Fetch-Mode: navigate',
|
||||
'Referer: https://pan.baidu.com',
|
||||
'Accept-Encoding: gzip, deflate, br',
|
||||
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7,en-GB;q=0.6,ru;q=0.5',
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
|
||||
'Cookie: ' . $cookie
|
||||
];
|
||||
$this->bdstoken = '';
|
||||
$this->baseUrl = 'https://pan.baidu.com';
|
||||
}
|
||||
|
||||
public function getBdstoken()
|
||||
{
|
||||
$url = $this->baseUrl . '/api/gettemplatevariable';
|
||||
$params = [
|
||||
'clienttype' => '0',
|
||||
'app_id' => '38824127',
|
||||
'web' => '1',
|
||||
'fields' => '["bdstoken","token","uk","isdocuser","servertime"]'
|
||||
];
|
||||
|
||||
$res = $this->request('GET', $url, $params);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['result']['bdstoken'];
|
||||
}
|
||||
|
||||
public function getDirList($folderName)
|
||||
{
|
||||
$url = $this->baseUrl . '/api/list';
|
||||
$params = [
|
||||
'order' => 'time',
|
||||
'desc' => '1',
|
||||
'showempty' => '0',
|
||||
'web' => '1',
|
||||
'page' => '1',
|
||||
'num' => '1000',
|
||||
'dir' => $folderName,
|
||||
'bdstoken' => $this->bdstoken
|
||||
];
|
||||
|
||||
// print_r($params);
|
||||
// die;
|
||||
$res = $this->request('GET', $url, $params);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['list'];
|
||||
}
|
||||
|
||||
public function createDir($folderName)
|
||||
{
|
||||
$url = $this->baseUrl . '/api/create';
|
||||
$params = [
|
||||
'a' => 'commit',
|
||||
'bdstoken' => $this->bdstoken
|
||||
];
|
||||
$data = [
|
||||
'path' => $folderName,
|
||||
'isdir' => '1',
|
||||
'block_list' => '[]'
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
public function verifyPassCode($linkUrl, $passCode)
|
||||
{
|
||||
$url = $this->baseUrl . '/share/verify';
|
||||
$params = [
|
||||
'surl' => substr($linkUrl, 25, 23),
|
||||
'bdstoken' => $this->bdstoken,
|
||||
't' => round(microtime(true) * 1000),
|
||||
'channel' => 'chunlei',
|
||||
'web' => '1',
|
||||
'clienttype' => '0'
|
||||
];
|
||||
$data = [
|
||||
'pwd' => $passCode,
|
||||
'vcode' => '',
|
||||
'vcode_str' => ''
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['randsk'];
|
||||
}
|
||||
|
||||
public function updateBdclnd($randsk)
|
||||
{
|
||||
$this->cookie = $this->updateCookie($randsk, $this->cookie);
|
||||
|
||||
// 更新 headers 中的 cookie
|
||||
foreach ($this->headers as &$header) {
|
||||
if (strpos($header, 'Cookie:') === 0) {
|
||||
$header = 'Cookie: ' . $this->cookie;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTransferParams($url)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
|
||||
// 允许跳转
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new \Exception(curl_error($ch));
|
||||
}
|
||||
|
||||
// 直接返回原始响应内容,不做 json 解析
|
||||
return $this->parseResponse($response);
|
||||
}
|
||||
|
||||
public function transferFile($paramsList, $folderName)
|
||||
{
|
||||
$url = $this->baseUrl . '/share/transfer';
|
||||
$params = [
|
||||
'shareid' => $paramsList[0],
|
||||
'from' => $paramsList[1],
|
||||
'bdstoken' => $this->bdstoken,
|
||||
'channel' => 'chunlei',
|
||||
'web' => '1',
|
||||
'clienttype' => '0'
|
||||
];
|
||||
$data = [
|
||||
'fsidlist' => '[' . implode(',', $paramsList[2]) . ']',
|
||||
'path' => '/' . $folderName
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
public function createShare($fsId, $expiry, $password)
|
||||
{
|
||||
$url = $this->baseUrl . '/share/set';
|
||||
$params = [
|
||||
'channel' => 'chunlei',
|
||||
'bdstoken' => $this->bdstoken,
|
||||
'clienttype' => '0',
|
||||
'app_id' => '250528',
|
||||
'web' => '1'
|
||||
];
|
||||
$data = [
|
||||
'period' => $expiry,
|
||||
'pwd' => $password,
|
||||
'eflag_disable' => 'true',
|
||||
'channel_list' => '[]',
|
||||
'schannel' => '4',
|
||||
'fid_list' => '[' . $fsId . ']'
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['link'];
|
||||
}
|
||||
|
||||
public function setBdstoken($token)
|
||||
{
|
||||
$this->bdstoken = $token;
|
||||
}
|
||||
|
||||
protected function request($method, $url, $params = [], $data = null, $retry = 3)
|
||||
{
|
||||
while ($retry > 0) {
|
||||
try {
|
||||
$ch = curl_init();
|
||||
if ($method === 'GET' && !empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
|
||||
|
||||
if ($method === 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
if (!empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
}
|
||||
if (!empty($data)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||
}
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new \Exception(curl_error($ch));
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
} catch (\Exception $e) {
|
||||
$retry--;
|
||||
if ($retry <= 0) {
|
||||
throw $e;
|
||||
}
|
||||
usleep(rand(1000000, 2000000)); // 1-2秒随机延迟
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateCookie($bdclnd, $cookie)
|
||||
{
|
||||
// 拆分 cookie 字符串到数组
|
||||
$cookiePairs = array_filter(explode(';', $cookie));
|
||||
$cookiesDict = [];
|
||||
|
||||
// 将 cookie 键值对转换为关联数组
|
||||
foreach ($cookiePairs as $pair) {
|
||||
$parts = explode('=', trim($pair), 2);
|
||||
if (count($parts) == 2) {
|
||||
$cookiesDict[$parts[0]] = $parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
// 更新或添加 BDCLND 值
|
||||
$cookiesDict['BDCLND'] = $bdclnd;
|
||||
|
||||
// 重新构建 cookie 字符串
|
||||
$cookieParts = [];
|
||||
foreach ($cookiesDict as $key => $value) {
|
||||
$cookieParts[] = $key . '=' . $value;
|
||||
}
|
||||
|
||||
return implode('; ', $cookieParts);
|
||||
}
|
||||
|
||||
protected function parseResponse($response)
|
||||
{
|
||||
// 预定义正则表达式
|
||||
$patterns = [
|
||||
'shareid' => '/"shareid":(\d+?),"/',
|
||||
'user_id' => '/"share_uk":"(\d+?)","/',
|
||||
'fs_id' => '/"fs_id":(\d+?),"/',
|
||||
'server_filename' => '/"server_filename":"(.+?)","/',
|
||||
'isdir' => '/"isdir":(\d+?),"/'
|
||||
];
|
||||
|
||||
// 提取所有需要的参数
|
||||
$results = [];
|
||||
foreach ($patterns as $key => $pattern) {
|
||||
preg_match_all($pattern, $response, $matches);
|
||||
$results[$key] = $matches[1] ?? [];
|
||||
}
|
||||
|
||||
// 验证是否获取到所有必要参数
|
||||
if (empty($results['shareid']) || empty($results['user_id']) ||
|
||||
empty($results['fs_id']) || empty($results['server_filename']) ||
|
||||
empty($results['isdir'])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 返回格式化的结果
|
||||
return [
|
||||
$results['shareid'][0], // shareid
|
||||
$results['user_id'][0], // user_id
|
||||
$results['fs_id'], // fs_id 列表
|
||||
array_unique($results['server_filename']), // 文件名列表(去重)
|
||||
$results['isdir'] // 是否为目录
|
||||
];
|
||||
}
|
||||
|
||||
public function deleteFile($filePath)
|
||||
{
|
||||
$url = $this->baseUrl . '/api/filemanager';
|
||||
$params = [
|
||||
'async' => '2',
|
||||
'onnest' => 'fail',
|
||||
'opera' => 'delete',
|
||||
'bdstoken' => $this->bdstoken,
|
||||
'newVerify' => '1',
|
||||
'clienttype' => '0',
|
||||
'app_id' => '250528',
|
||||
'web' => '1'
|
||||
];
|
||||
|
||||
// 支持单个路径字符串或路径数组
|
||||
if (!is_array($filePath)) {
|
||||
$filePath = [$filePath];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'filelist' => json_encode($filePath)
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除文件
|
||||
* @param array|string $filePaths 文件路径数组或单个文件路径
|
||||
* @return array 删除结果
|
||||
*/
|
||||
public function batchDeleteFiles($filePaths)
|
||||
{
|
||||
// 如果是字符串,转换为数组处理
|
||||
if (!is_array($filePaths)) {
|
||||
$filePaths = [$filePaths];
|
||||
}
|
||||
|
||||
// 处理每个路径
|
||||
$processedPaths = [];
|
||||
foreach ($filePaths as $path) {
|
||||
if (empty($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 防止删除根目录
|
||||
if ($path === '/' || $path === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 确保路径以斜杠开头
|
||||
if (substr($path, 0, 1) !== '/') {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
|
||||
$processedPaths[] = $path;
|
||||
}
|
||||
|
||||
if (empty($processedPaths)) {
|
||||
return [
|
||||
'errno' => -100,
|
||||
'message' => '没有有效的文件路径可删除'
|
||||
];
|
||||
}
|
||||
|
||||
// 调用删除方法
|
||||
$result = $this->deleteFile($processedPaths);
|
||||
|
||||
return [
|
||||
'errno' => $result,
|
||||
'message' => $this->getErrorMessage($result),
|
||||
'deletedCount' => count($processedPaths),
|
||||
'paths' => $processedPaths
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
25
extend/netdisk/pan/BasePan.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace netdisk\pan;
|
||||
|
||||
abstract class BasePan
|
||||
{
|
||||
protected $urlHeader;
|
||||
protected $code;
|
||||
protected $url;
|
||||
protected $isType;
|
||||
protected $expired_type;
|
||||
protected $ad_fid;
|
||||
protected $stoken;
|
||||
|
||||
public function __construct($config = [])
|
||||
{
|
||||
$this->code = $config['code'] ?? '';
|
||||
$this->url = $config['url'] ?? '';
|
||||
$this->isType = $config['isType'] ?? 0;
|
||||
$this->expired_type = $config['expired_type'] ?? 1;
|
||||
$this->ad_fid = $config['ad_fid'] ?? '';
|
||||
$this->stoken = $config['stoken'] ?? '';
|
||||
}
|
||||
|
||||
abstract public function transfer($share_id);
|
||||
}
|
||||
361
extend/netdisk/pan/QuarkPan.php
Normal file
@@ -0,0 +1,361 @@
|
||||
<?php
|
||||
namespace netdisk\pan;
|
||||
|
||||
class QuarkPan extends BasePan
|
||||
{
|
||||
public function __construct($config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->urlHeader = [
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9',
|
||||
'content-type: application/json;charset=UTF-8',
|
||||
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'sec-ch-ua-mobile: ?0',
|
||||
'sec-ch-ua-platform: "Windows"',
|
||||
'sec-fetch-dest: empty',
|
||||
'sec-fetch-mode: cors',
|
||||
'sec-fetch-site: same-site',
|
||||
'Referer: https://pan.quark.cn/',
|
||||
'Referrer-Policy: strict-origin-when-cross-origin',
|
||||
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'cookie: ' . Config('qfshop.quark_cookie')
|
||||
];
|
||||
}
|
||||
|
||||
public function getFiles($pdir_fid=0)
|
||||
{
|
||||
// 原 getFiles 方法内容
|
||||
$urlData = [];
|
||||
$queryParams = [
|
||||
'pr' => 'ucpro',
|
||||
'fr' => 'pc',
|
||||
'uc_param_str' => '',
|
||||
'pdir_fid' => $pdir_fid,
|
||||
'_page' => 1,
|
||||
'_size' => 50,
|
||||
'_fetch_total' => 1,
|
||||
'_fetch_sub_dirs' => 0,
|
||||
'_sort' => 'file_type:asc,updated_at:desc',
|
||||
];
|
||||
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr2($res['message']=='require login [guest]'?'夸克未登录,请检查cookie':$res['message']);
|
||||
}
|
||||
|
||||
return jok2('获取成功',$res['data']['list']);
|
||||
}
|
||||
|
||||
public function transfer($pwd_id)
|
||||
{
|
||||
if(empty($this->stoken)){
|
||||
//获取要转存夸克资源的stoken
|
||||
$res = $this->getStoken($pwd_id);
|
||||
if($res['status'] !== 200) return jerr2($res['message']);
|
||||
$infoData = $res['data'];
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $infoData['title'];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok2('检验成功', $urls);
|
||||
}
|
||||
$stoken = $infoData['stoken'];
|
||||
$stoken = str_replace(' ', '+', $stoken);
|
||||
}else{
|
||||
$stoken = str_replace(' ', '+', $this->stoken);
|
||||
}
|
||||
|
||||
//获取要转存夸克资源的详细内容
|
||||
$res = $this->getShare($pwd_id,$stoken);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$detail = $res['data'];
|
||||
|
||||
$fid_list = [];
|
||||
$fid_token_list = [];
|
||||
$title = $detail['share']['title']; //资源名称
|
||||
foreach ($detail['list'] as $key => $value) {
|
||||
$fid_list[] = $value['fid'];
|
||||
$fid_token_list[] = $value['share_fid_token'];
|
||||
}
|
||||
|
||||
//转存资源到指定文件夹
|
||||
$res = $this->getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$task_id = $res['data']['task_id'];
|
||||
|
||||
//转存后根据task_id获取转存到自己网盘后的信息
|
||||
$retry_index = 0;
|
||||
$myData = '';
|
||||
while ($myData=='' || $myData['status'] != 2) {
|
||||
$res = $this->getShareTask($task_id, $retry_index);
|
||||
if($res['message']== 'capacity limit[{0}]'){
|
||||
return jerr2('容量不足');
|
||||
}
|
||||
if($res['status']!== 200) {
|
||||
return jerr2($res['message']);
|
||||
}
|
||||
$myData = $res['data'];
|
||||
$retry_index++;
|
||||
// 可以添加一个最大重试次数的限制,防止无限循环
|
||||
if ($retry_index > 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
//删除转存后可能有的广告
|
||||
$banned = Config('qfshop.quark_banned')??''; //如果出现这些字样就删除
|
||||
if(!empty($banned)){
|
||||
$bannedList = explode(',', $banned);
|
||||
$pdir_fid = $myData['save_as']['save_as_top_fids'][0];
|
||||
$dellist = [];
|
||||
$plist = $this->getPdirFid($pdir_fid);
|
||||
if(!empty($plist)){
|
||||
foreach ($plist as $key => $value) {
|
||||
// 检查$value['file_name']是否包含$bannedList中的任何一项
|
||||
$contains = false;
|
||||
foreach ($bannedList as $item) {
|
||||
if (strpos($value['file_name'], $item) !== false) {
|
||||
$contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($contains) {
|
||||
$dellist[] = $value['fid'];
|
||||
}
|
||||
}
|
||||
if(count($plist) === count($dellist)){
|
||||
//要删除的资源数如果和原数据资源数一样 就全部删除并终止下面的分享
|
||||
$this->deletepdirFid([$pdir_fid]);
|
||||
return jerr2("资源内容为空");
|
||||
}else{
|
||||
if (!empty($dellist)) {
|
||||
$this->deletepdirFid($dellist);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
$shareFid = $myData['save_as']['save_as_top_fids'];
|
||||
//分享资源并拿到更新后的task_id
|
||||
$res = $this->getShareBtn($myData['save_as']['save_as_top_fids'],$title);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$task_id = $res['data']['task_id'];
|
||||
|
||||
//根据task_id拿到share_id
|
||||
$retry_index = 0;
|
||||
$myData = '';
|
||||
while ($myData=='' || $myData['status'] != 2) {
|
||||
$res = $this->getShareTask($task_id, $retry_index);
|
||||
if($res['status']!== 200) continue;
|
||||
$myData = $res['data'];
|
||||
$retry_index++;
|
||||
// 可以添加一个最大重试次数的限制,防止无限循环
|
||||
if ($retry_index > 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//根据share_id 获取到分享链接
|
||||
$res = $this->getSharePassword($myData['share_id']);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$share = $res['data'];
|
||||
// $share['fid'] = $share['first_file']['fid'];
|
||||
$share['fid'] = (is_array($shareFid) && count($shareFid) > 1) ? $shareFid : $share['first_file']['fid'];
|
||||
|
||||
return jok2('转存成功', $share);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取要转存资源的stoken
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getStoken($pwd_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'passcode' => '',
|
||||
'pwd_id' => $pwd_id,
|
||||
);
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc&uc_param_str=", "POST",json_encode($urlData), $this->urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取要转存资源的详细内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShare($pwd_id,$stoken)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => "",
|
||||
"pwd_id" => $pwd_id,
|
||||
"stoken" => $stoken,
|
||||
"pdir_fid" => "0",
|
||||
"force" => "0",
|
||||
"_page" => "1",
|
||||
"_size" => "100",
|
||||
"_fetch_banner" => "1",
|
||||
"_fetch_share" => "1",
|
||||
"_fetch_total" => "1",
|
||||
"_sort" => "file_type:asc,updated_at:desc"
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转存资源到指定文件夹
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list)
|
||||
{
|
||||
$to_pdir_fid = Config('qfshop.quark_file'); //默认存储路径
|
||||
if($this->expired_type == 2){
|
||||
$to_pdir_fid = Config('qfshop.quark_file_time'); //临时资源路径
|
||||
}
|
||||
$urlData = array(
|
||||
'fid_list' => $fid_list,
|
||||
'fid_token_list' => $fid_token_list,
|
||||
'to_pdir_fid' => $to_pdir_fid,
|
||||
'pwd_id' => $pwd_id,
|
||||
'stoken' => $stoken,
|
||||
'pdir_fid' => "0",
|
||||
'scene' => "link",
|
||||
);
|
||||
$queryParams = [
|
||||
"entry" => "update_share",
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/save", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分享资源拿到task_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareBtn($fid_list,$title)
|
||||
{
|
||||
if(!empty($this->ad_fid)){
|
||||
$fid_list[] = $this->ad_fid;
|
||||
}
|
||||
$urlData = array(
|
||||
'fid_list' => $fid_list,
|
||||
'expired_type' => $this->expired_type,
|
||||
'title' => $title,
|
||||
'url_type' => 1,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据task_id拿到自己的资源信息
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareTask($task_id,$retry_index)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => "",
|
||||
"task_id" => $task_id,
|
||||
"retry_index" => $retry_index
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/task", "GET", json_encode($urlData), $this->urlHeader, $queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据share_id 获取到分享链接
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getSharePassword($share_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'share_id' => $share_id,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/password", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deletepdirFid($filelist)
|
||||
{
|
||||
$urlData = array(
|
||||
'action_type' => 2,
|
||||
'exclude_fids' => [],
|
||||
'filelist' => $filelist,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => ""
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/delete", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取夸克网盘指定文件夹内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getPdirFid($pdir_fid)
|
||||
{
|
||||
$urlData = [];
|
||||
$queryParams = [
|
||||
'pr' => 'ucpro',
|
||||
'fr' => 'pc',
|
||||
'uc_param_str' => '',
|
||||
'pdir_fid' => $pdir_fid,
|
||||
'_page' => 1,
|
||||
'_size' => 200,
|
||||
'_fetch_total' => 1,
|
||||
'_fetch_sub_dirs' => 0,
|
||||
'_sort' => 'file_type:asc,updated_at:desc',
|
||||
];
|
||||
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return [];
|
||||
}
|
||||
return $res['data']['list'];
|
||||
}
|
||||
}
|
||||
348
extend/netdisk/pan/UcPan.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
namespace netdisk\pan;
|
||||
|
||||
class UcPan extends BasePan
|
||||
{
|
||||
public function __construct($config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->urlHeader = [
|
||||
'Accept: application/json, text/plain, */*',
|
||||
'Accept-Language: zh-CN,zh;q=0.9',
|
||||
'content-type: application/json;charset=UTF-8',
|
||||
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||
'sec-ch-ua-mobile: ?0',
|
||||
'sec-ch-ua-platform: "Windows"',
|
||||
'sec-fetch-dest: empty',
|
||||
'sec-fetch-mode: cors',
|
||||
'sec-fetch-site: same-site',
|
||||
'Referer: https://drive.uc.cn/',
|
||||
'Referrer-Policy: strict-origin-when-cross-origin',
|
||||
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'cookie: ' . Config('qfshop.uc_cookie')
|
||||
];
|
||||
}
|
||||
|
||||
public function getFiles($pdir_fid=0)
|
||||
{
|
||||
// 原 getFiles 方法内容
|
||||
$urlData = [];
|
||||
$queryParams = [
|
||||
'pr' => 'UCBrowser',
|
||||
'fr' => 'pc',
|
||||
'pdir_fid' => $pdir_fid,
|
||||
'_page' => 1,
|
||||
'_size' => 50,
|
||||
'_fetch_total' => 1,
|
||||
'_fetch_sub_dirs' => 0,
|
||||
'_sort' => 'file_type:asc,updated_at:desc',
|
||||
];
|
||||
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return jerr2($res['message']=='require login [guest]'?'UC未登录,请检查cookie':$res['message']);
|
||||
}
|
||||
|
||||
return jok2('获取成功',$res['data']['list']);
|
||||
}
|
||||
|
||||
public function transfer($pwd_id)
|
||||
{
|
||||
//获取要转存UC资源的stoken
|
||||
$res = $this->getStoken($pwd_id);
|
||||
if($res['status'] !== 200) return jerr2($res['message']);
|
||||
$infoData = $res['data'];
|
||||
|
||||
if($this->isType == 1){
|
||||
$urls['title'] = $infoData['token_info']['title'];
|
||||
$urls['share_url'] = $this->url;
|
||||
return jok2('检验成功', $urls);
|
||||
}
|
||||
$stoken = $infoData['token_info']['stoken'];
|
||||
$stoken = str_replace(' ', '+', $stoken);
|
||||
|
||||
//获取要转存UC资源的详细内容
|
||||
$res = $this->getShare($pwd_id,$stoken);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$detail = $res['data'];
|
||||
|
||||
$fid_list = [];
|
||||
$fid_token_list = [];
|
||||
$title = $detail['share']['title']; //资源名称
|
||||
foreach ($detail['list'] as $key => $value) {
|
||||
$fid_list[] = $value['fid'];
|
||||
$fid_token_list[] = $value['share_fid_token'];
|
||||
}
|
||||
|
||||
//转存资源到指定文件夹
|
||||
$res = $this->getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$task_id = $res['data']['task_id'];
|
||||
|
||||
//转存后根据task_id获取转存到自己网盘后的信息
|
||||
$retry_index = 0;
|
||||
$myData = '';
|
||||
while ($myData=='' || $myData['status'] != 2) {
|
||||
$res = $this->getShareTask($task_id, $retry_index);
|
||||
if($res['message']== 'capacity limit[{0}]'){
|
||||
return jerr2('容量不足');
|
||||
}
|
||||
if($res['status']!== 200) {
|
||||
return jerr2($res['message']);
|
||||
}
|
||||
$myData = $res['data'];
|
||||
$retry_index++;
|
||||
// 可以添加一个最大重试次数的限制,防止无限循环
|
||||
if ($retry_index > 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
//删除转存后可能有的广告
|
||||
$banned = Config('qfshop.quark_banned')??''; //如果出现这些字样就删除
|
||||
if(!empty($banned)){
|
||||
$bannedList = explode(',', $banned);
|
||||
$pdir_fid = $myData['save_as']['save_as_top_fids'][0];
|
||||
$dellist = [];
|
||||
$plist = $this->getPdirFid($pdir_fid);
|
||||
if(!empty($plist)){
|
||||
foreach ($plist as $key => $value) {
|
||||
// 检查$value['file_name']是否包含$bannedList中的任何一项
|
||||
$contains = false;
|
||||
foreach ($bannedList as $item) {
|
||||
if (strpos($value['file_name'], $item) !== false) {
|
||||
$contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($contains) {
|
||||
$dellist[] = $value['fid'];
|
||||
}
|
||||
}
|
||||
if(count($plist) === count($dellist)){
|
||||
//要删除的资源数如果和原数据资源数一样 就全部删除并终止下面的分享
|
||||
$this->deletepdirFid([$pdir_fid]);
|
||||
return jerr2("资源内容为空");
|
||||
}else{
|
||||
if (!empty($dellist)) {
|
||||
$this->deletepdirFid($dellist);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
$shareFid = $myData['save_as']['save_as_top_fids'];
|
||||
//分享资源并拿到更新后的task_id
|
||||
$res = $this->getShareBtn($myData['save_as']['save_as_top_fids'],$title);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$task_id = $res['data']['task_id'];
|
||||
|
||||
//根据task_id拿到share_id
|
||||
$retry_index = 0;
|
||||
$myData = '';
|
||||
while ($myData=='' || $myData['status'] != 2) {
|
||||
$res = $this->getShareTask($task_id, $retry_index);
|
||||
if($res['status']!== 200) continue;
|
||||
$myData = $res['data'];
|
||||
$retry_index++;
|
||||
// 可以添加一个最大重试次数的限制,防止无限循环
|
||||
if ($retry_index > 50) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//根据share_id 获取到分享链接
|
||||
$res = $this->getSharePassword($myData['share_id']);
|
||||
if($res['status']!== 200) return jerr2($res['message']);
|
||||
$share = $res['data'];
|
||||
// $share['fid'] = $share['first_file']['fid'];
|
||||
$share['fid'] = (is_array($shareFid) && count($shareFid) > 1) ? $shareFid : $share['first_file']['fid'];
|
||||
|
||||
return jok2('转存成功', $share);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取要转存资源的stoken
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getStoken($pwd_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'passcode' => '',
|
||||
'pwd_id' => $pwd_id,
|
||||
);
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share/sharepage/v2/detail?pr=UCBrowser&fr=pc", "POST",json_encode($urlData), $this->urlHeader)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取要转存资源的详细内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShare($pwd_id,$stoken)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "UCBrowser",
|
||||
"fr" => "pc",
|
||||
"pwd_id" => $pwd_id,
|
||||
"stoken" => $stoken,
|
||||
"pdir_fid" => "0",
|
||||
"force" => "0",
|
||||
"_page" => "1",
|
||||
"_size" => "100",
|
||||
"_fetch_banner" => "1",
|
||||
"_fetch_share" => "1",
|
||||
"_fetch_total" => "1",
|
||||
"_sort" => "file_type:asc,updated_at:desc"
|
||||
];
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share/sharepage/detail", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转存资源到指定文件夹
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list)
|
||||
{
|
||||
$to_pdir_fid = Config('qfshop.uc_file'); //默认存储路径
|
||||
if($this->expired_type == 2){
|
||||
$to_pdir_fid = Config('qfshop.uc_file_time'); //临时资源路径
|
||||
}
|
||||
$urlData = array(
|
||||
'fid_list' => $fid_list,
|
||||
'fid_token_list' => $fid_token_list,
|
||||
'to_pdir_fid' => $to_pdir_fid,
|
||||
'pwd_id' => $pwd_id,
|
||||
'stoken' => $stoken,
|
||||
'pdir_fid' => "0",
|
||||
'scene' => "link",
|
||||
);
|
||||
$queryParams = [
|
||||
"entry" => "update_share",
|
||||
"pr" => "UCBrowser",
|
||||
"fr" => "pc",
|
||||
];
|
||||
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share/sharepage/save", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分享资源拿到task_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareBtn($fid_list,$title)
|
||||
{
|
||||
if(!empty($this->ad_fid)){
|
||||
$fid_list[] = $this->ad_fid;
|
||||
}
|
||||
$urlData = array(
|
||||
'fid_list' => $fid_list,
|
||||
'expired_type' => $this->expired_type,
|
||||
'title' => $title,
|
||||
'url_type' => 1,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "UCBrowser",
|
||||
"fr" => "pc",
|
||||
];
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据task_id拿到自己的资源信息
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getShareTask($task_id,$retry_index)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "UCBrowser",
|
||||
"fr" => "pc",
|
||||
"task_id" => $task_id,
|
||||
"retry_index" => $retry_index
|
||||
];
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/task", "GET", json_encode($urlData), $this->urlHeader, $queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据share_id 获取到分享链接
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getSharePassword($share_id)
|
||||
{
|
||||
$urlData = array(
|
||||
'share_id' => $share_id,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "UCBrowser",
|
||||
"fr" => "pc",
|
||||
];
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share/password", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
return json_decode($res, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deletepdirFid($filelist)
|
||||
{
|
||||
$urlData = array(
|
||||
'action_type' => 2,
|
||||
'exclude_fids' => [],
|
||||
'filelist' => $filelist,
|
||||
);
|
||||
$queryParams = [
|
||||
"pr" => "UCBrowser",
|
||||
"fr" => "pc",
|
||||
];
|
||||
curlHelper("https://pc-api.uc.cn/1/clouddrive/file/delete", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取夸克网盘指定文件夹内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getPdirFid($pdir_fid)
|
||||
{
|
||||
$urlData = [];
|
||||
$queryParams = [
|
||||
'pr' => 'UCBrowser',
|
||||
'fr' => 'pc',
|
||||
'pdir_fid' => $pdir_fid,
|
||||
'_page' => 1,
|
||||
'_size' => 200,
|
||||
'_fetch_total' => 1,
|
||||
'_fetch_sub_dirs' => 0,
|
||||
'_sort' => 'file_type:asc,updated_at:desc',
|
||||
];
|
||||
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] !== 200){
|
||||
return [];
|
||||
}
|
||||
return $res['data']['list'];
|
||||
}
|
||||
}
|
||||
1
extend/netdisk/pan/access_token.json
Normal file
@@ -0,0 +1 @@
|
||||
{"access_token":"","refresh_token":"","expires_at":1743155645}
|
||||
@@ -23,19 +23,10 @@ class QuarkPlugin
|
||||
$this->source_category_id = 0;
|
||||
}
|
||||
|
||||
public function getFiles($quark_cookie)
|
||||
public function getFiles($type=0,$pdir_fid=0)
|
||||
{
|
||||
$urlData = [
|
||||
'cookie' => $quark_cookie ?? '',
|
||||
];
|
||||
$res = curlHelper(Request::domain() . "/api/open/getFiles", "POST", $urlData)['body'];
|
||||
$res = json_decode($res, true);
|
||||
|
||||
if ($res['code'] !== 200) {
|
||||
return jerr($res['message']);
|
||||
}
|
||||
|
||||
return $res['data'];
|
||||
$transfer = new \netdisk\Transfer();
|
||||
return $transfer->getFiles($type,$pdir_fid);
|
||||
}
|
||||
|
||||
public function import($allData, $source_category_id)
|
||||
@@ -68,6 +59,10 @@ class QuarkPlugin
|
||||
|
||||
public function transferAll($source_category_id, $day = 0)
|
||||
{
|
||||
if(empty($this->url)){
|
||||
return jerr('未配置转存接口地址');
|
||||
}
|
||||
|
||||
@set_time_limit(999999);
|
||||
|
||||
$this->source_category_id = $source_category_id;
|
||||
@@ -133,17 +128,14 @@ class QuarkPlugin
|
||||
}
|
||||
|
||||
$urlData = [
|
||||
'cookie' => Config('qfshop.quark_cookie') ?? '',
|
||||
'Authorization' => Config('qfshop.Authorization') ?? '',
|
||||
'expired_type' => 1, // 1正式资源 2临时资源
|
||||
'to_pdir_fid' => '', //存入目标文件
|
||||
'url' => $url,
|
||||
'code' => $value['code'] ?? '',
|
||||
'isType' => $isType
|
||||
];
|
||||
|
||||
$res = curlHelper(Request::domain() . "/api/open/transfer", "POST", $urlData)['body'];
|
||||
$res = json_decode($res, true);
|
||||
$transfer = new \netdisk\Transfer();
|
||||
$res = $transfer->transfer($urlData);
|
||||
|
||||
if ($res['code'] !== 200) {
|
||||
if (!empty($logId)) {
|
||||
@@ -159,7 +151,7 @@ class QuarkPlugin
|
||||
"title" => $title,
|
||||
"url" => $res['data']['share_url'],
|
||||
"is_type" => determineIsType($res['data']['share_url']),
|
||||
"code" => $value['code'] ?? '',
|
||||
"code" => $res['data']['code'] ?? $value['code'] ?? '',
|
||||
"source_category_id" => $source_category_id,
|
||||
"update_time" => time(),
|
||||
"create_time" => time(),
|
||||
|
||||
412
extend/util/Network.php
Normal file
@@ -0,0 +1,412 @@
|
||||
<?php
|
||||
namespace util;
|
||||
|
||||
class Network
|
||||
{
|
||||
protected $errorCodes = [
|
||||
-1 => '链接错误,链接失效或缺少提取码',
|
||||
-4 => '转存失败,无效登录。请退出账号在其他地方的登录',
|
||||
-6 => '转存失败,请用浏览器无痕模式获取 Cookie 后再试',
|
||||
-7 => '转存失败,转存文件夹名有非法字符,不能包含 < > | * ? \\ :,请改正目录名后重试',
|
||||
-8 => '转存失败,目录中已有同名文件或文件夹存在',
|
||||
-9 => '链接错误,提取码错误',
|
||||
-10 => '转存失败,容量不足',
|
||||
-12 => '链接错误,提取码错误',
|
||||
-62 => '转存失败,链接访问次数过多,请手动转存或稍后再试',
|
||||
0 => '转存成功',
|
||||
2 => '转存失败,目标目录不存在',
|
||||
4 => '转存失败,目录中存在同名文件',
|
||||
12 => '转存失败,转存文件数超过限制',
|
||||
20 => '转存失败,容量不足',
|
||||
105 => '链接错误,所访问的页面不存在'
|
||||
];
|
||||
|
||||
public function getErrorMessage($code)
|
||||
{
|
||||
return $this->errorCodes[$code] ?? "未知错误(错误码:{$code})";
|
||||
}
|
||||
|
||||
protected $session;
|
||||
protected $headers;
|
||||
protected $bdstoken;
|
||||
protected $baseUrl;
|
||||
protected $cookie;
|
||||
|
||||
public function __construct($cookie = '')
|
||||
{
|
||||
$this->cookie = $cookie??'';
|
||||
$this->headers = [
|
||||
'Host: pan.baidu.com',
|
||||
'Connection: keep-alive',
|
||||
'Upgrade-Insecure-Requests: 1',
|
||||
'Sec-Fetch-Dest: document',
|
||||
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
||||
'Sec-Fetch-Site: same-site',
|
||||
'Sec-Fetch-Mode: navigate',
|
||||
'Referer: https://pan.baidu.com',
|
||||
'Accept-Encoding: gzip, deflate, br',
|
||||
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7,en-GB;q=0.6,ru;q=0.5',
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
|
||||
'Cookie: ' . $cookie
|
||||
];
|
||||
$this->bdstoken = '';
|
||||
$this->baseUrl = 'https://pan.baidu.com';
|
||||
}
|
||||
|
||||
public function getBdstoken()
|
||||
{
|
||||
$url = $this->baseUrl . '/api/gettemplatevariable';
|
||||
$params = [
|
||||
'clienttype' => '0',
|
||||
'app_id' => '38824127',
|
||||
'web' => '1',
|
||||
'fields' => '["bdstoken","token","uk","isdocuser","servertime"]'
|
||||
];
|
||||
|
||||
$res = $this->request('GET', $url, $params);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['result']['bdstoken'];
|
||||
}
|
||||
|
||||
public function getDirList($folderName)
|
||||
{
|
||||
$url = $this->baseUrl . '/api/list';
|
||||
$params = [
|
||||
'order' => 'time',
|
||||
'desc' => '1',
|
||||
'showempty' => '0',
|
||||
'web' => '1',
|
||||
'page' => '1',
|
||||
'num' => '1000',
|
||||
'dir' => $folderName,
|
||||
'bdstoken' => $this->bdstoken
|
||||
];
|
||||
|
||||
$res = $this->request('GET', $url, $params);
|
||||
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['list'];
|
||||
}
|
||||
|
||||
public function createDir($folderName)
|
||||
{
|
||||
$url = $this->baseUrl . '/api/create';
|
||||
$params = [
|
||||
'a' => 'commit',
|
||||
'bdstoken' => $this->bdstoken
|
||||
];
|
||||
$data = [
|
||||
'path' => $folderName,
|
||||
'isdir' => '1',
|
||||
'block_list' => '[]'
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
public function verifyPassCode($linkUrl, $passCode)
|
||||
{
|
||||
$url = $this->baseUrl . '/share/verify';
|
||||
$params = [
|
||||
'surl' => substr($linkUrl, 25, 23),
|
||||
'bdstoken' => $this->bdstoken,
|
||||
't' => round(microtime(true) * 1000),
|
||||
'channel' => 'chunlei',
|
||||
'web' => '1',
|
||||
'clienttype' => '0'
|
||||
];
|
||||
$data = [
|
||||
'pwd' => $passCode,
|
||||
'vcode' => '',
|
||||
'vcode_str' => ''
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['randsk'];
|
||||
}
|
||||
|
||||
public function updateBdclnd($randsk)
|
||||
{
|
||||
$this->cookie = $this->updateCookie($randsk, $this->cookie);
|
||||
|
||||
// 更新 headers 中的 cookie
|
||||
foreach ($this->headers as &$header) {
|
||||
if (strpos($header, 'Cookie:') === 0) {
|
||||
$header = 'Cookie: ' . $this->cookie;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTransferParams($url)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
|
||||
// 允许跳转
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new \Exception(curl_error($ch));
|
||||
}
|
||||
|
||||
// 直接返回原始响应内容,不做 json 解析
|
||||
return $this->parseResponse($response);
|
||||
}
|
||||
|
||||
public function transferFile($paramsList, $folderName)
|
||||
{
|
||||
$url = $this->baseUrl . '/share/transfer';
|
||||
$params = [
|
||||
'shareid' => $paramsList[0],
|
||||
'from' => $paramsList[1],
|
||||
'bdstoken' => $this->bdstoken,
|
||||
'channel' => 'chunlei',
|
||||
'web' => '1',
|
||||
'clienttype' => '0'
|
||||
];
|
||||
$data = [
|
||||
'fsidlist' => '[' . implode(',', $paramsList[2]) . ']',
|
||||
'path' => '/' . $folderName
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
public function createShare($fsId, $expiry, $password)
|
||||
{
|
||||
$url = $this->baseUrl . '/share/set';
|
||||
$params = [
|
||||
'channel' => 'chunlei',
|
||||
'bdstoken' => $this->bdstoken,
|
||||
'clienttype' => '0',
|
||||
'app_id' => '250528',
|
||||
'web' => '1'
|
||||
];
|
||||
$data = [
|
||||
'period' => $expiry,
|
||||
'pwd' => $password,
|
||||
'eflag_disable' => 'true',
|
||||
'channel_list' => '[]',
|
||||
'schannel' => '4',
|
||||
'fid_list' => '[' . $fsId . ']'
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
if ($res['errno'] != 0) {
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
return $res['link'];
|
||||
}
|
||||
|
||||
public function setBdstoken($token)
|
||||
{
|
||||
$this->bdstoken = $token;
|
||||
}
|
||||
|
||||
protected function request($method, $url, $params = [], $data = null, $retry = 3)
|
||||
{
|
||||
while ($retry > 0) {
|
||||
try {
|
||||
$ch = curl_init();
|
||||
if ($method === 'GET' && !empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
|
||||
|
||||
if ($method === 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
if (!empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
}
|
||||
if (!empty($data)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||
}
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new \Exception(curl_error($ch));
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
} catch (\Exception $e) {
|
||||
$retry--;
|
||||
if ($retry <= 0) {
|
||||
throw $e;
|
||||
}
|
||||
usleep(rand(1000000, 2000000)); // 1-2秒随机延迟
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateCookie($bdclnd, $cookie)
|
||||
{
|
||||
// 拆分 cookie 字符串到数组
|
||||
$cookiePairs = array_filter(explode(';', $cookie));
|
||||
$cookiesDict = [];
|
||||
|
||||
// 将 cookie 键值对转换为关联数组
|
||||
foreach ($cookiePairs as $pair) {
|
||||
$parts = explode('=', trim($pair), 2);
|
||||
if (count($parts) == 2) {
|
||||
$cookiesDict[$parts[0]] = $parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
// 更新或添加 BDCLND 值
|
||||
$cookiesDict['BDCLND'] = $bdclnd;
|
||||
|
||||
// 重新构建 cookie 字符串
|
||||
$cookieParts = [];
|
||||
foreach ($cookiesDict as $key => $value) {
|
||||
$cookieParts[] = $key . '=' . $value;
|
||||
}
|
||||
|
||||
return implode('; ', $cookieParts);
|
||||
}
|
||||
|
||||
protected function parseResponse($response)
|
||||
{
|
||||
// 预定义正则表达式
|
||||
$patterns = [
|
||||
'shareid' => '/"shareid":(\d+?),"/',
|
||||
'user_id' => '/"share_uk":"(\d+?)","/',
|
||||
'fs_id' => '/"fs_id":(\d+?),"/',
|
||||
'server_filename' => '/"server_filename":"(.+?)","/',
|
||||
'isdir' => '/"isdir":(\d+?),"/'
|
||||
];
|
||||
|
||||
// 提取所有需要的参数
|
||||
$results = [];
|
||||
foreach ($patterns as $key => $pattern) {
|
||||
preg_match_all($pattern, $response, $matches);
|
||||
$results[$key] = $matches[1] ?? [];
|
||||
}
|
||||
|
||||
// 验证是否获取到所有必要参数
|
||||
if (empty($results['shareid']) || empty($results['user_id']) ||
|
||||
empty($results['fs_id']) || empty($results['server_filename']) ||
|
||||
empty($results['isdir'])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 返回格式化的结果
|
||||
return [
|
||||
$results['shareid'][0], // shareid
|
||||
$results['user_id'][0], // user_id
|
||||
$results['fs_id'], // fs_id 列表
|
||||
array_unique($results['server_filename']), // 文件名列表(去重)
|
||||
$results['isdir'] // 是否为目录
|
||||
];
|
||||
}
|
||||
|
||||
public function deleteFile($filePath)
|
||||
{
|
||||
$url = $this->baseUrl . '/api/filemanager';
|
||||
$params = [
|
||||
'async' => '2',
|
||||
'onnest' => 'fail',
|
||||
'opera' => 'delete',
|
||||
'bdstoken' => $this->bdstoken,
|
||||
'newVerify' => '1',
|
||||
'clienttype' => '0',
|
||||
'app_id' => '250528',
|
||||
'web' => '1'
|
||||
];
|
||||
|
||||
// 支持单个路径字符串或路径数组
|
||||
if (!is_array($filePath)) {
|
||||
$filePath = [$filePath];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'filelist' => json_encode($filePath)
|
||||
];
|
||||
|
||||
$res = $this->request('POST', $url, $params, $data);
|
||||
return $res['errno'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除文件
|
||||
* @param array|string $filePaths 文件路径数组或单个文件路径
|
||||
* @return array 删除结果
|
||||
*/
|
||||
public function batchDeleteFiles($filePaths)
|
||||
{
|
||||
// 如果是字符串,转换为数组处理
|
||||
if (!is_array($filePaths)) {
|
||||
$filePaths = [$filePaths];
|
||||
}
|
||||
|
||||
// 处理每个路径
|
||||
$processedPaths = [];
|
||||
foreach ($filePaths as $path) {
|
||||
if (empty($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 防止删除根目录
|
||||
if ($path === '/' || $path === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 确保路径以斜杠开头
|
||||
if (substr($path, 0, 1) !== '/') {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
|
||||
$processedPaths[] = $path;
|
||||
}
|
||||
|
||||
if (empty($processedPaths)) {
|
||||
return [
|
||||
'errno' => -100,
|
||||
'message' => '没有有效的文件路径可删除'
|
||||
];
|
||||
}
|
||||
|
||||
// 调用删除方法
|
||||
$result = $this->deleteFile($processedPaths);
|
||||
|
||||
return [
|
||||
'errno' => $result,
|
||||
'message' => $this->getErrorMessage($result),
|
||||
'deletedCount' => count($processedPaths),
|
||||
'paths' => $processedPaths
|
||||
];
|
||||
}
|
||||
}
|
||||
211
extend/util/Operations.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
namespace util;
|
||||
|
||||
class Operations
|
||||
{
|
||||
protected $network;
|
||||
protected $cookie;
|
||||
protected $folderName;
|
||||
protected $linkList;
|
||||
protected $linkListOrg;
|
||||
protected $totalTaskCount;
|
||||
protected $completedTaskCount;
|
||||
protected $running;
|
||||
protected $customMode;
|
||||
protected $checkMode;
|
||||
protected $dirListAll;
|
||||
|
||||
const SAVE_LIMIT = 1000;
|
||||
const DELAY_SECONDS = 0.1;
|
||||
const INVALID_CHARS = ['<', '>', '|', '*', '?', '\\', ':'];
|
||||
|
||||
public function __construct($cookie = '')
|
||||
{
|
||||
$this->network = new Network($cookie);
|
||||
$this->cookie = $cookie;
|
||||
$this->completedTaskCount = 0;
|
||||
$this->running = true;
|
||||
}
|
||||
|
||||
public function save($links, $folderName = '', $customMode = false, $checkMode = false)
|
||||
{
|
||||
try {
|
||||
$this->prepareRun($folderName, $customMode, $checkMode);
|
||||
$this->setupSave($links);
|
||||
$this->handleInput();
|
||||
$this->handleBdstoken();
|
||||
$this->handleCreateDir($this->folderName);
|
||||
$this->handleProcessSave();
|
||||
return ['code' => 0, 'msg' => '转存完成'];
|
||||
} catch (\Exception $e) {
|
||||
return ['code' => -1, 'msg' => '程序出现未预料错误: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
protected function prepareRun($folderName, $customMode, $checkMode)
|
||||
{
|
||||
$this->folderName = trim($folderName);
|
||||
$this->customMode = $customMode;
|
||||
$this->checkMode = $checkMode;
|
||||
$this->completedTaskCount = 0;
|
||||
}
|
||||
|
||||
protected function setupSave($links)
|
||||
{
|
||||
$this->linkList = array_filter(array_map(function($link) {
|
||||
return $this->normalizeLink($link . ' ');
|
||||
}, explode("\n", $links)));
|
||||
|
||||
$this->linkListOrg = array_unique(array_filter(explode("\n", $links)));
|
||||
$this->totalTaskCount = count($this->linkList);
|
||||
}
|
||||
|
||||
protected function handleInput()
|
||||
{
|
||||
if ($this->totalTaskCount == 0) {
|
||||
throw new \Exception('无有效链接。');
|
||||
}
|
||||
if ($this->totalTaskCount > self::SAVE_LIMIT) {
|
||||
throw new \Exception("批量转存一次不能超过 " . self::SAVE_LIMIT . ",当前链接数:" . $this->totalTaskCount);
|
||||
}
|
||||
if (!preg_match('/^[\x00-\x7F]+$/', $this->cookie) || strpos($this->cookie, 'BAIDUID') === false) {
|
||||
throw new \Exception('百度网盘 cookie 输入不正确。');
|
||||
}
|
||||
foreach (self::INVALID_CHARS as $char) {
|
||||
if (strpos($this->folderName, $char) !== false) {
|
||||
throw new \Exception('转存目录名有非法字符,不能包含:< > | * ? \ :');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleBdstoken()
|
||||
{
|
||||
$bdstoken = $this->network->getBdstoken();
|
||||
if (is_numeric($bdstoken)) {
|
||||
throw new \Exception("没获取到 bdstoken 参数,错误代码:" . $bdstoken);
|
||||
}
|
||||
$this->network->setBdstoken($bdstoken);
|
||||
}
|
||||
|
||||
protected function handleCreateDir($folderName)
|
||||
{
|
||||
if (!empty($folderName)) {
|
||||
$result = $this->network->getDirList("/{$folderName}");
|
||||
if (is_numeric($result)) {
|
||||
$returnCode = $this->network->createDir($folderName);
|
||||
if ($returnCode !== 0) {
|
||||
throw new \Exception("创建目录失败,错误代码:" . $returnCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleProcessSave()
|
||||
{
|
||||
$results = [];
|
||||
foreach ($this->linkList as $urlCode) {
|
||||
$result = $this->processSave($urlCode);
|
||||
$results[] = $result;
|
||||
usleep(self::DELAY_SECONDS * 1000000);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
protected function processSave($urlCode)
|
||||
{
|
||||
if (strpos($urlCode, 'https://pan.baidu.com/') === false) {
|
||||
return ['status' => 'error', 'message' => "不支持的链接:{$urlCode}"];
|
||||
}
|
||||
|
||||
list($url, $code) = $this->parseUrlAndCode($urlCode);
|
||||
$result = $this->verifyLink($url, $code);
|
||||
|
||||
if ($this->checkMode) {
|
||||
return $this->checkOnly($result, $urlCode);
|
||||
}
|
||||
|
||||
return $this->saveFile($result, $urlCode, $this->folderName);
|
||||
}
|
||||
|
||||
protected function normalizeLink($link)
|
||||
{
|
||||
if (empty($link)) return '';
|
||||
|
||||
$link = trim($link);
|
||||
if (preg_match('/https:\/\/pan\.baidu\.com\/s\/[a-zA-Z0-9_-]+/', $link, $matches)) {
|
||||
return $matches[0];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function parseUrlAndCode($urlCode)
|
||||
{
|
||||
$parts = explode(' ', trim($urlCode));
|
||||
$url = $parts[0];
|
||||
$code = isset($parts[1]) ? $parts[1] : '';
|
||||
return [$url, $code];
|
||||
}
|
||||
|
||||
protected function verifyLink($url, $password)
|
||||
{
|
||||
if ($password) {
|
||||
$bdclnd = $this->network->verifyPassCode($url, $password);
|
||||
if (is_numeric($bdclnd)) {
|
||||
return $bdclnd;
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->network->getTransferParams($url);
|
||||
return $this->parseResponse($response);
|
||||
}
|
||||
|
||||
protected function parseResponse($html)
|
||||
{
|
||||
// 实现解析响应的逻辑
|
||||
// 返回解析后的参数数组或错误代码
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function checkOnly($result, $urlCode)
|
||||
{
|
||||
if (is_array($result)) {
|
||||
return ['status' => 'success', 'message' => "链接有效:{$urlCode}"];
|
||||
}
|
||||
return ['status' => 'error', 'message' => "链接无效:{$urlCode}"];
|
||||
}
|
||||
|
||||
protected function saveFile($result, $urlCode, $folderName)
|
||||
{
|
||||
if (!is_array($result)) {
|
||||
return ['status' => 'error', 'message' => "转存失败:{$urlCode}"];
|
||||
}
|
||||
|
||||
if ($this->customMode) {
|
||||
$folderName = $this->createUserDir($folderName);
|
||||
}
|
||||
|
||||
$transferResult = $this->network->transferFile($result, $folderName);
|
||||
|
||||
if ($transferResult === 0) {
|
||||
return ['status' => 'success', 'message' => "转存成功:{$urlCode} 到 {$folderName}"];
|
||||
}
|
||||
|
||||
return ['status' => 'error', 'message' => "转存失败,错误代码({$transferResult}):{$urlCode}"];
|
||||
}
|
||||
|
||||
protected function createUserDir($baseFolderName)
|
||||
{
|
||||
if (empty($baseFolderName)) {
|
||||
throw new \Exception('必须输入转存目录');
|
||||
}
|
||||
|
||||
$customFolder = $this->completedTaskCount + 1;
|
||||
$folderName = $baseFolderName . '/' . $customFolder;
|
||||
|
||||
// 替换非法字符
|
||||
$folderName = str_replace(self::INVALID_CHARS, '_', $folderName);
|
||||
|
||||
$this->handleCreateDir($folderName);
|
||||
return $folderName;
|
||||
}
|
||||
}
|
||||
219
extend/util/network.py
Normal file
@@ -0,0 +1,219 @@
|
||||
"""
|
||||
所有和网络请求相关函数。
|
||||
|
||||
:author: assassing
|
||||
:contact: https://github.com/hxz393
|
||||
:copyright: Copyright 2024, hxz393. 保留所有权利。
|
||||
"""
|
||||
import time
|
||||
from typing import Union, List, Any
|
||||
|
||||
import requests
|
||||
from retrying import retry
|
||||
|
||||
from src.constants import HEADERS, BASE_URL
|
||||
|
||||
|
||||
class Network:
|
||||
"""
|
||||
网络请求相关类。
|
||||
注意,此类函数用 retry 来处理网络问题,达到重试次数则由主函数来捕获异常,中断运行。只要请求能返回数据,都可以正确处理。
|
||||
请求地址没有取全参数(params),只留关键参数。
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化会话、请求头和 bdstoken。
|
||||
"""
|
||||
self.s = requests.Session()
|
||||
self.headers = HEADERS
|
||||
self.bdstoken = ''
|
||||
# 忽略证书验证警告
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=2000)
|
||||
def get_bdstoken(self) -> Union[str, int]:
|
||||
"""
|
||||
获取 bdstoken,用于创建、转存等操作,是所有其他请求的先决条件。
|
||||
获取到的 token 在整个会话中通用。
|
||||
|
||||
:return: 获取成功返回 bdstoken,获取失败返回错误代码
|
||||
"""
|
||||
url = f'{BASE_URL}/api/gettemplatevariable'
|
||||
params = {
|
||||
'clienttype': '0',
|
||||
'app_id': '38824127',
|
||||
'web': '1',
|
||||
'fields': '["bdstoken","token","uk","isdocuser","servertime"]'
|
||||
}
|
||||
|
||||
r = self.s.get(url=url, params=params, headers=self.headers, timeout=10, allow_redirects=False, verify=False)
|
||||
if r.json()['errno'] != 0:
|
||||
return r.json()['errno']
|
||||
|
||||
return r.json()['result']['bdstoken']
|
||||
|
||||
@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=2000)
|
||||
def get_dir_list(self, folder_name: str) -> Union[List[Any], int]:
|
||||
"""
|
||||
获取指定目录下的文件或目录列表。
|
||||
用于创建目录前,检查目录是否已存在;
|
||||
用于批量分享时,生成任务列表。
|
||||
|
||||
:param folder_name: 指定要获取列表的目录名
|
||||
:return: 获取成功时返回文件列表,获取失败时返回错误代码
|
||||
"""
|
||||
url = f'{BASE_URL}/api/list'
|
||||
params = {
|
||||
'order': 'time',
|
||||
'desc': '1',
|
||||
'showempty': '0',
|
||||
'web': '1',
|
||||
'page': '1',
|
||||
'num': '1000',
|
||||
'dir': folder_name,
|
||||
'bdstoken': self.bdstoken
|
||||
}
|
||||
|
||||
r = self.s.get(url=url, params=params, headers=self.headers, timeout=15, allow_redirects=False, verify=False)
|
||||
if r.json()['errno'] != 0:
|
||||
return r.json()['errno']
|
||||
|
||||
return r.json()['list']
|
||||
|
||||
@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=2000)
|
||||
def create_dir(self, folder_name: str) -> int:
|
||||
"""
|
||||
新建指定目录。
|
||||
用于批量转存前,建立缺失的目标目录。
|
||||
|
||||
:param folder_name: 指定要建立的目录名
|
||||
:return: 获取请求返回的代码,成功时返回 0
|
||||
"""
|
||||
url = f'{BASE_URL}/api/create'
|
||||
params = {
|
||||
'a': 'commit',
|
||||
'bdstoken': self.bdstoken
|
||||
}
|
||||
data = {
|
||||
'path': folder_name,
|
||||
'isdir': '1',
|
||||
'block_list': '[]',
|
||||
}
|
||||
|
||||
r = self.s.post(url=url, params=params, headers=self.headers, data=data, timeout=15, allow_redirects=False, verify=False)
|
||||
|
||||
return r.json()['errno']
|
||||
|
||||
@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=2000)
|
||||
def verify_pass_code(self, link_url: str, pass_code: str) -> Union[str, int]:
|
||||
"""
|
||||
验证提取码是否正确。
|
||||
如果正确,则会返回转存所必须的 randsk,也就是 bdclnd 参数。
|
||||
|
||||
:param link_url: 网盘地址
|
||||
:param pass_code: 提取码
|
||||
:return: 成功时返回 randsk 字符串,失败时返回错误代码
|
||||
"""
|
||||
url = f'{BASE_URL}/share/verify'
|
||||
params = {
|
||||
# 可放心用暴力切片
|
||||
'surl': link_url[25:48],
|
||||
'bdstoken': self.bdstoken,
|
||||
# 当前时间的毫秒级时间戳
|
||||
't': str(int(round(time.time() * 1000))),
|
||||
# 下面是不明所以的固定参数
|
||||
'channel': 'chunlei',
|
||||
'web': '1',
|
||||
'clienttype': '0'
|
||||
}
|
||||
data = {
|
||||
'pwd': pass_code,
|
||||
# 并没有发现下面两个参数的用途
|
||||
'vcode': '',
|
||||
'vcode_str': ''
|
||||
}
|
||||
|
||||
r = self.s.post(url=url, params=params, headers=self.headers, data=data, timeout=10, allow_redirects=False, verify=False)
|
||||
if r.json()['errno'] != 0:
|
||||
return r.json()['errno']
|
||||
|
||||
return r.json()['randsk']
|
||||
|
||||
@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=2000)
|
||||
def get_transfer_params(self, url: str) -> str:
|
||||
"""
|
||||
更新 bdclnd 到 cookie 后,再次请求网盘链接,获取响应内容。
|
||||
请求需要允许跳转。
|
||||
请求不再需要提取码。
|
||||
|
||||
:param url: 网盘地址
|
||||
:return: 返回原始请求内容,丢给 parse_response 函数取处理
|
||||
"""
|
||||
r = self.s.get(url=url, headers=self.headers, timeout=15, verify=False)
|
||||
|
||||
return r.content.decode("utf-8")
|
||||
|
||||
@retry(stop_max_attempt_number=5, wait_random_min=1000, wait_random_max=2000)
|
||||
def transfer_file(self, params_list: List[str], folder_name: str) -> int:
|
||||
"""
|
||||
转存百度网盘文件。
|
||||
|
||||
:param params_list: 带有 shareid、share_uk 和 fs_id 的列表
|
||||
:param folder_name: 转存目标目录
|
||||
:return: 返回转存请求结果代码
|
||||
"""
|
||||
url = f'{BASE_URL}/share/transfer'
|
||||
params = {
|
||||
# shareid 是文件 id
|
||||
'shareid': params_list[0],
|
||||
# share_uk 猜是分享者的 id
|
||||
'from': params_list[1],
|
||||
'bdstoken': self.bdstoken,
|
||||
'channel': 'chunlei',
|
||||
'web': '1',
|
||||
'clienttype': '0'
|
||||
}
|
||||
data = {
|
||||
# 针对一个分享链接带有多个分享文件的情况,转换一下列表格式
|
||||
'fsidlist': f"[{','.join(params_list[2])}]",
|
||||
# 目标目录为空,则直接等于根目录 '/'
|
||||
'path': f'/{folder_name}'
|
||||
}
|
||||
|
||||
r = self.s.post(url=url, params=params, headers=self.headers, data=data, timeout=30, allow_redirects=False, verify=False)
|
||||
|
||||
return r.json()['errno']
|
||||
|
||||
@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=2000)
|
||||
def create_share(self, fs_id: int, expiry: str, password: str) -> Union[str, int]:
|
||||
"""
|
||||
生成百度网盘分享链接。
|
||||
|
||||
:param fs_id: 文件或目录独一无二的 id
|
||||
:param expiry: 自定义失效时长
|
||||
:param password: 自定义提取码
|
||||
:return: 成功时返回生成的分享链接,失败时返回错误代码
|
||||
"""
|
||||
url = f'{BASE_URL}/share/set'
|
||||
params = {
|
||||
'channel': 'chunlei',
|
||||
'bdstoken': self.bdstoken,
|
||||
'clienttype': '0',
|
||||
'app_id': '250528',
|
||||
'web': '1'
|
||||
}
|
||||
data = {
|
||||
'period': expiry,
|
||||
'pwd': password,
|
||||
'eflag_disable': 'true',
|
||||
'channel_list': '[]',
|
||||
'schannel': '4',
|
||||
'fid_list': f'[{fs_id}]'
|
||||
}
|
||||
|
||||
r = self.s.post(url=url, params=params, headers=self.headers, data=data, timeout=15, allow_redirects=False, verify=False)
|
||||
if r.json()['errno'] != 0:
|
||||
return r.json()['errno']
|
||||
|
||||
return r.json()['link']
|
||||
327
extend/util/operations.py
Normal file
@@ -0,0 +1,327 @@
|
||||
"""
|
||||
主要功能实现逻辑,包括批量转存和分享。
|
||||
|
||||
:author: assassing
|
||||
:contact: https://github.com/hxz393
|
||||
:copyright: Copyright 2024, hxz393. 保留所有权利。
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from typing import Union, List, Dict, Any
|
||||
|
||||
import ttkbootstrap as ttk
|
||||
|
||||
from src.constants import EXP_MAP, DELAY_SECONDS, INVALID_CHARS, ERROR_CODES, SAVE_LIMIT, COLOR_MAP
|
||||
from src.network import Network
|
||||
from src.ui import CustomDialog
|
||||
from src.utils import thread_it, write_config, parse_response, normalize_link, parse_url_and_code, update_cookie, generate_code
|
||||
|
||||
|
||||
class Operations:
|
||||
"""
|
||||
包括主功能实现流程,涉及部分对 UI 的操作。
|
||||
日志文字不额外提取到映射字典,方便定位错误。
|
||||
|
||||
:param root: 主窗口
|
||||
"""
|
||||
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.network = Network()
|
||||
|
||||
def save(self) -> None:
|
||||
"""
|
||||
转存主函数,流程为:
|
||||
1.获取用户输入,更新按钮和标签状态;
|
||||
2.检查用户输入,有问题则终止并发送日志;
|
||||
3.获取 bdstoken,如果获取失败则终止;
|
||||
4.获取根目录文件列表,建立转存目录;
|
||||
5.批量转存链接。先验证链接有效性,再转存文件,插入结果到日志框。
|
||||
"""
|
||||
try:
|
||||
self.prepare_run()
|
||||
self.setup_save()
|
||||
self.handle_input()
|
||||
self.handle_bdstoken()
|
||||
self.handle_create_dir(folder_name=self.folder_name)
|
||||
self.handle_process_save()
|
||||
except Exception as e:
|
||||
self.insert_logs(f'程序出现未预料错误,信息如下:\n{e}\n{traceback.format_exc()}')
|
||||
finally:
|
||||
self.network.s.close()
|
||||
self.change_status('stopped')
|
||||
|
||||
def share(self) -> None:
|
||||
"""
|
||||
分享主函数,流程为:
|
||||
0.弹出设置窗口,设置分享参数;
|
||||
1.获取用户输入,更新按钮和标签状态;
|
||||
2.检查用户输入,有问题则终止并发送日志;
|
||||
3.获取 bdstoken,如果获取失败则终止;
|
||||
4.获取目标目录文件列表,如果为空则终止;
|
||||
5.批量分享文件。先向链接框插入文件名,再创建分享,插入结果到日志框。
|
||||
"""
|
||||
try:
|
||||
# 创建对话框实例,如果对话框没有返回输入值,则忽略
|
||||
self.dialog_result = CustomDialog(self.root)
|
||||
if self.dialog_result.result:
|
||||
self.prepare_run()
|
||||
self.handle_input(task_count_check=False)
|
||||
self.handle_bdstoken()
|
||||
self.handle_list_dir()
|
||||
self.setup_share()
|
||||
self.handle_process_share()
|
||||
except Exception as e:
|
||||
self.insert_logs(f'程序出现未预料错误,信息如下:\n{e}\n{traceback.format_exc()}')
|
||||
finally:
|
||||
self.network.s.close()
|
||||
self.change_status('stopped')
|
||||
|
||||
def prepare_run(self) -> None:
|
||||
"""获取变量,准备运行。转存和分享共用逻辑"""
|
||||
# 从用户输入获取变量
|
||||
self.cookie = "".join(self.root.entry_cookie.get().split())
|
||||
self.folder_name = "".join(self.root.entry_folder_name.get().split())
|
||||
self.network.s.trust_env = self.root.var_trust_env.get()
|
||||
self.custom_mode = self.root.var_custom_mode.get()
|
||||
self.check_mode = self.root.var_check_mode.get()
|
||||
|
||||
# 更新 cookie、初始化任务总数、更改状态、写入配置文件
|
||||
self.completed_task_count = 0
|
||||
self.network.headers['Cookie'] = self.cookie
|
||||
self.change_status('init')
|
||||
write_config(f'{self.cookie}\n{self.folder_name}')
|
||||
|
||||
def setup_save(self) -> None:
|
||||
"""准备链接,更新状态"""
|
||||
# 从文本链接控件获取全部链接,清洗并标准化链接。注意链接后拼接一个空格,是为了后面能统一处理带与不带提取码的链接
|
||||
raw_links = self.root.text_links.get(1.0, ttk.END).splitlines()
|
||||
self.link_list = [normalize_link(f'{link} ') for link in raw_links if link]
|
||||
self.link_list_org = list(dict.fromkeys(link for link in raw_links if link))
|
||||
# 更新任务总数和状态
|
||||
self.total_task_count = len(self.link_list)
|
||||
self.change_status('running')
|
||||
|
||||
def setup_share(self) -> None:
|
||||
"""准备参数,更新状态"""
|
||||
# 从设置对话框获取参数变量
|
||||
self.expiry, self.password, self.random_password = self.dialog_result.result
|
||||
# 更新任务总数和状态
|
||||
self.total_task_count = len(self.dir_list_all)
|
||||
self.change_status('sharing')
|
||||
|
||||
def handle_input(self, task_count_check: bool = True) -> None:
|
||||
"""输入检查,如链接数限制和 cookie 格式"""
|
||||
# 转存时才检查输入链接数量
|
||||
if task_count_check:
|
||||
self.check_condition(self.total_task_count == 0,
|
||||
message='无有效链接。')
|
||||
self.check_condition(self.total_task_count > SAVE_LIMIT,
|
||||
message=f'批量转存一次不能超过 {SAVE_LIMIT},当前链接数:{self.total_task_count}')
|
||||
|
||||
# cookie 带非 ascii 字符,或不包含 BAIDUID 时,铁定不对
|
||||
self.check_condition(not self.cookie.isascii() or self.cookie.find('BAIDUID') == -1,
|
||||
message='百度网盘 cookie 输入不正确,请查看使用帮助。')
|
||||
# 非法字符由官方规定的。符号 / 可以使用,作为子目录的分隔符
|
||||
self.check_condition(any(char in self.folder_name for char in INVALID_CHARS),
|
||||
message=r'转存目录名有非法字符,不能包含:< > | * ? \ :')
|
||||
|
||||
def handle_bdstoken(self) -> None:
|
||||
"""获取 bdstoken 相关逻辑"""
|
||||
self.network.bdstoken = self.network.get_bdstoken()
|
||||
self.check_condition(isinstance(self.network.bdstoken, int),
|
||||
message=f'没获取到 bdstoken 参数,错误代码:{self.network.bdstoken}')
|
||||
|
||||
def handle_list_dir(self) -> None:
|
||||
"""获取目标目录下的文件和目录列表"""
|
||||
self.dir_list_all = self.network.get_dir_list(f'/{self.folder_name}')
|
||||
self.check_condition(isinstance(self.dir_list_all, int) or not self.dir_list_all,
|
||||
message=f'目录 {self.folder_name} 中没获取到任何内容,请求返回:{self.dir_list_all}')
|
||||
|
||||
def handle_create_dir(self, folder_name: str) -> None:
|
||||
"""新建目录。如果目录已存在则不新建,否则会建立一个带时间戳的空目录"""
|
||||
result = self.network.get_dir_list(f'/{folder_name}')
|
||||
# 如果 result 为错误代码数字,代表目标目录不存在
|
||||
if self.folder_name and isinstance(result, int):
|
||||
return_code = self.network.create_dir(folder_name)
|
||||
self.check_condition(return_code != 0,
|
||||
message=f'创建目录失败,错误代码:{return_code}')
|
||||
|
||||
def handle_process_save(self) -> None:
|
||||
"""执行批量转存"""
|
||||
for url_code in self.link_list:
|
||||
self.process_save(url_code)
|
||||
|
||||
def handle_process_share(self) -> None:
|
||||
"""执行批量分享"""
|
||||
for info in self.dir_list_all:
|
||||
self.process_share(info)
|
||||
|
||||
def process_save(self, url_code: str) -> None:
|
||||
"""执行转存操作并记录结果"""
|
||||
# 跳过非网盘链接
|
||||
if 'https://pan.baidu.com/' not in url_code:
|
||||
self.insert_logs(f'不支持的链接:{url_code}')
|
||||
else:
|
||||
# 执行转存过程,通过简单的循环判断是否要暂停
|
||||
self.pause_detection(url_code)
|
||||
|
||||
# 处理完毕一个链接,更新状态栏任务计数
|
||||
self.change_status('update')
|
||||
|
||||
def process_share(self, info: Dict[str, Any]) -> None:
|
||||
"""执行分享操作并记录结果"""
|
||||
# 插入要分享的文件或文件夹到链接输入框,对文件夹加入 "/" 标记来区别
|
||||
is_dir = "/" if info["isdir"] == 1 else ""
|
||||
filename = f"{info['server_filename']}{is_dir}"
|
||||
msg = f'目录:{filename}' if is_dir else f'文件:{filename}'
|
||||
self.insert_logs(msg, alt=True)
|
||||
|
||||
# 处理提取码
|
||||
password = self.password if not self.random_password else generate_code()
|
||||
|
||||
# 发送创建分享请求
|
||||
r = self.network.create_share(info['fs_id'], EXP_MAP[self.expiry], password)
|
||||
if isinstance(r, str):
|
||||
result = f'分享成功:{r}?pwd={password} {msg}'
|
||||
else:
|
||||
result = f'分享失败:错误代码({r}) {msg}'
|
||||
|
||||
# 记录日志,更改状态
|
||||
self.insert_logs(result)
|
||||
self.change_status('update')
|
||||
|
||||
# noinspection PyArgumentList
|
||||
def change_status(self, status: str) -> None:
|
||||
"""运行状态变化更新函数"""
|
||||
if status == 'init':
|
||||
self.root.label_status.config(text='准备就绪!', font=('', 10), bootstyle='primary', cursor="arrow")
|
||||
self.root.label_status.unbind("<Button-1>")
|
||||
self.root.text_logs.config(fg=COLOR_MAP['text'])
|
||||
self.root.text_logs.delete(1.0, ttk.END)
|
||||
elif status == 'running':
|
||||
self.running = True
|
||||
self.root.bottom_share.config(state="disabled")
|
||||
self.root.bottom_save.config(text='点击暂停', bootstyle='danger', command=lambda: self.change_status('paused'))
|
||||
elif status == 'paused':
|
||||
self.running = False
|
||||
self.root.bottom_save.config(text='点击继续', bootstyle='success', command=lambda: self.change_status('running'))
|
||||
elif status == 'update':
|
||||
self.completed_task_count += 1
|
||||
self.root.label_status.config(text=f'总进度:{self.completed_task_count}/{self.total_task_count}', bootstyle='success')
|
||||
elif status == 'sharing':
|
||||
self.root.text_links.delete(1.0, ttk.END)
|
||||
self.root.bottom_share.config(state="disabled")
|
||||
self.root.bottom_save.config(state="disabled")
|
||||
elif status == 'error':
|
||||
self.root.label_status.config(text='发生错误:', bootstyle='danger')
|
||||
else:
|
||||
self.running = False
|
||||
self.root.bottom_save.config(text='批量转存', state="normal", bootstyle='primary', command=lambda: thread_it(self.save, ))
|
||||
self.root.bottom_share.config(state="normal")
|
||||
|
||||
def check_condition(self, condition: bool, message: str) -> None:
|
||||
"""
|
||||
用户输入或函数返回检查。
|
||||
如果条件 condition 为 True,表示错误不可恢复,中断当前任务流程。
|
||||
单个链接处理出错,应该直接调用 insert_logs 函数记录错误,不中断任务。
|
||||
|
||||
:param condition: 条件表达式
|
||||
:param message: 插入到日志框的内容
|
||||
"""
|
||||
if condition:
|
||||
self.change_status('error')
|
||||
self.insert_logs(message)
|
||||
sys.exit()
|
||||
|
||||
def insert_logs(self, message: str, alt: bool = False) -> None:
|
||||
"""
|
||||
在文本框末尾插入内容
|
||||
|
||||
:param message: 插入到日志框的内容
|
||||
:param alt: 如果为 True,插入到链接输入框,用于批量分享时记录文件名
|
||||
"""
|
||||
text_box = self.root.text_links if alt else self.root.text_logs
|
||||
text_box.insert('end', f'{message}\n')
|
||||
text_box.see(ttk.END)
|
||||
|
||||
def pause_detection(self, url_code: str) -> None:
|
||||
"""循环检测暂停逻辑,每个转存任务开始时都会检测"""
|
||||
# 只要 self.running 状态没变,会一直等待。而状态变化由用户点击按钮控制
|
||||
while not self.running:
|
||||
time.sleep(DELAY_SECONDS)
|
||||
|
||||
# 执行验证链接和转存文件
|
||||
self.verify_and_save(url_code)
|
||||
# 转存完毕等待一小段时间。如果要转存超过 1000 个链接,可以增加 DELAY_SECONDS 到 3 以上。
|
||||
time.sleep(DELAY_SECONDS)
|
||||
|
||||
def verify_and_save(self, url_code: str) -> None:
|
||||
"""验证链接和转存文件"""
|
||||
# 验证链接是否有效,返回的数字为错误代码,反之返回参数列表
|
||||
result = self.verify_link(*parse_url_and_code(url_code))
|
||||
# 如果开启检查模式,插入检查结果,然后结束
|
||||
if self.check_mode:
|
||||
self.check_only(result, url_code)
|
||||
else:
|
||||
self.save_file(result, url_code, self.folder_name)
|
||||
|
||||
def verify_link(self, url: str, password: str) -> Union[List[str], int]:
|
||||
"""验证链接有效性,验证通过返回转存所需参数列表"""
|
||||
# 对于有提取码的链接先验证提取码,试图获取更新 bdclnd
|
||||
if password:
|
||||
bdclnd = self.network.verify_pass_code(url, password)
|
||||
# 如果 bdclnd 是错误代码,直接返回
|
||||
if isinstance(bdclnd, int):
|
||||
return bdclnd
|
||||
|
||||
# 更新 bdclnd 到 cookie
|
||||
self.network.headers['Cookie'] = update_cookie(bdclnd, self.network.headers['Cookie'])
|
||||
|
||||
# 直接访问没有提取码的链接,或更新 bdclnd 后再次访问,获取转存必须的 3 个参数
|
||||
response = self.network.get_transfer_params(url)
|
||||
# 这里不考虑网络异常了,假设请求一定会返回页面内容,对其进行解析
|
||||
return parse_response(response)
|
||||
|
||||
def check_only(self, result: Union[List[str], int], url_code: str) -> None:
|
||||
"""开启检查模式时,只管判断返回值类型,并输出结果到日志"""
|
||||
if isinstance(result, list):
|
||||
self.insert_logs(f'链接有效:{url_code} {"目录" if result[4] == ["1"] else "文件"}:{result[3]}')
|
||||
else:
|
||||
self.insert_logs(f'链接无效:{url_code} 原因:{ERROR_CODES.get(result, f"错误代码({result})")}')
|
||||
|
||||
def creat_user_dir(self, folder_name: str) -> str:
|
||||
"""建立用户指定目录,返回完整路径。目录名从原始输入取,函数为 custom_mode 专用"""
|
||||
self.check_condition(not folder_name, message='必须输入转存目录')
|
||||
# 对原始输入进行分割
|
||||
link_org_sep = self.link_list_org[self.completed_task_count].split()
|
||||
# 建立自定义目录,如果没有指定则用行数代替
|
||||
custom_folder = link_org_sep[0]
|
||||
folder_name = f'{folder_name}/{custom_folder}' if 'pan.baidu.com' not in custom_folder else f'{folder_name}/{self.completed_task_count + 1}'
|
||||
# 此处用替换处理目标目录名非法字符,不报错了
|
||||
folder_name = folder_name.translate(str.maketrans({char: '_' for char in INVALID_CHARS}))
|
||||
self.handle_create_dir(folder_name)
|
||||
|
||||
return folder_name
|
||||
|
||||
def save_file(self, result: Union[List[str], int], url_code: str, folder_name: str) -> None:
|
||||
"""转存文件。返回结果为列表时,执行转存文件,否则跳过转存"""
|
||||
file_info = ""
|
||||
if isinstance(result, list):
|
||||
file_info = f'{"目录" if result[4] == ["1"] else "文件"}:{result[3]}'
|
||||
# 如果开启安全转存模式,对每个转存链接建立目录
|
||||
if self.custom_mode:
|
||||
folder_name = self.creat_user_dir(folder_name)
|
||||
result = self.network.transfer_file(result, folder_name)
|
||||
file_info = f'{file_info} 转存到:{folder_name}'
|
||||
# 改在这里检查链接重复,在日志中查找。链接有出现过不转存,直接赋值结果为错误代码 4
|
||||
elif url_code in self.root.text_logs.get('1.0', 'end'):
|
||||
result = 4
|
||||
# 正常转存
|
||||
else:
|
||||
result = self.network.transfer_file(result, folder_name)
|
||||
|
||||
# 最后插入转存结果到日志框
|
||||
self.insert_logs(f'{ERROR_CODES.get(result, f"转存失败,错误代码({result})")}:{url_code} {file_info}')
|
||||
161
extend/util/utils.py
Normal file
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
通用的工具函数,主要是一些静态函数。
|
||||
|
||||
:author: assassing
|
||||
:contact: https://github.com/hxz393
|
||||
:copyright: Copyright 2024, hxz393. 保留所有权利。
|
||||
"""
|
||||
import atexit
|
||||
import base64
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import tempfile
|
||||
import threading
|
||||
import zlib
|
||||
from typing import Any, Union, Tuple, Callable, List, Optional
|
||||
|
||||
from src.constants import CONFIG_PATH, ICON_BASE64
|
||||
|
||||
# 预编译正则表达式
|
||||
SHARE_ID_REGEX = re.compile(r'"shareid":(\d+?),"')
|
||||
USER_ID_REGEX = re.compile(r'"share_uk":"(\d+?)","')
|
||||
FS_ID_REGEX = re.compile(r'"fs_id":(\d+?),"')
|
||||
SERVER_FILENAME_REGEX = re.compile(r'"server_filename":"(.+?)","')
|
||||
ISDIR_REGEX = re.compile(r'"isdir":(\d+?),"')
|
||||
|
||||
|
||||
def thread_it(func: Callable, *args: Tuple[Any, ...]) -> None:
|
||||
"""
|
||||
多线程防止转存时主界面卡死。
|
||||
|
||||
:param func: 要调用的函数
|
||||
:param args: 函数参数
|
||||
:return: 无返回值
|
||||
"""
|
||||
t = threading.Thread(target=func, args=args)
|
||||
t.start()
|
||||
|
||||
|
||||
def write_config(config: str) -> None:
|
||||
"""
|
||||
写入配置文件,点击批量转存或分享按钮时才运行。
|
||||
|
||||
:param config: 配置文件内容,以换行转义字符 '\n' 拼接多个配置到一行字符串
|
||||
:return: 无返回值
|
||||
"""
|
||||
with open(CONFIG_PATH, 'w') as f:
|
||||
f.write(config)
|
||||
|
||||
|
||||
def read_config() -> Optional[List[str]]:
|
||||
"""
|
||||
读取配置文件,在 UI 初始化完毕后执行。
|
||||
|
||||
:return: 读取成功时返回配置列表,一个元素一个配置。配置文件不存在时返回 None,什么也不会发生
|
||||
"""
|
||||
if os.path.exists(CONFIG_PATH):
|
||||
with open(CONFIG_PATH) as f:
|
||||
config = f.read().splitlines()
|
||||
return config
|
||||
|
||||
|
||||
def create_icon() -> str:
|
||||
"""
|
||||
从 base64 编码中生成临时图标,在程序结束时自动删除。
|
||||
好处是打包时不用导入资源文件。
|
||||
|
||||
:return: 返回图标文件路径
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix='.ico') as temp_file:
|
||||
temp_file.write(zlib.decompress(base64.b64decode(ICON_BASE64)))
|
||||
|
||||
ico_path = temp_file.name
|
||||
# 显式声明程序退出时,删除临时图标文件,避免在个别系统平台自动删除失败
|
||||
atexit.register(os.remove, ico_path)
|
||||
return ico_path
|
||||
|
||||
|
||||
def normalize_link(url_code: str) -> str:
|
||||
"""
|
||||
预处理链接至标准格式。
|
||||
|
||||
:param url_code: 需要处理的的原始链接格式
|
||||
:return: 返回标准格式:链接+空格+提取码
|
||||
"""
|
||||
# 升级旧链接格式
|
||||
normalized = url_code.replace("share/init?surl=", "s/1")
|
||||
# 替换掉 ?pwd= 或 &pwd= 为空格
|
||||
normalized = re.sub(r'[?&]pwd=', ' ', normalized)
|
||||
# 替换掉提取码字样为空格
|
||||
normalized = re.sub(r'提取码*[::]', ' ', normalized)
|
||||
# 替换 http 为 https,顺便处理掉开头没用的文字
|
||||
normalized = re.sub(r'^.*?(https?://)', 'https://', normalized)
|
||||
# 替换连续的空格
|
||||
normalized = re.sub(r'\s+', ' ', normalized)
|
||||
return normalized
|
||||
|
||||
|
||||
def parse_url_and_code(url_code: str) -> Tuple[str, str]:
|
||||
"""
|
||||
以空格分割出 URL 和提取码。
|
||||
|
||||
:param url_code: 输入的标准链接格式
|
||||
:return: 链接和提取码
|
||||
"""
|
||||
# 不会分割失败
|
||||
url, code = map(str.strip, url_code.split(' ', 1))
|
||||
# 暴力切片,如果输入链接不是以提取码结尾,会得到错误提取码
|
||||
return url[:47], code[-4:]
|
||||
|
||||
|
||||
def parse_response(response: str) -> Union[List[str], int]:
|
||||
"""
|
||||
验证提取码通过后,再次访问网盘地址,此函数解析返回的页面源码并提取所需要参数。
|
||||
shareid_list 和 user_id_list 只有一个值,fs_id_list 需要完整返回
|
||||
|
||||
:param response: 响应内容
|
||||
:return: 没有获取到足够参数时,返回错误代码 -1;否则返回三个参数的列表
|
||||
"""
|
||||
shareid_list = SHARE_ID_REGEX.findall(response)
|
||||
user_id_list = USER_ID_REGEX.findall(response)
|
||||
fs_id_list = FS_ID_REGEX.findall(response)
|
||||
server_filename_list = SERVER_FILENAME_REGEX.findall(response)
|
||||
isdir_list = ISDIR_REGEX.findall(response)
|
||||
if not all([shareid_list, user_id_list, fs_id_list, server_filename_list, isdir_list]):
|
||||
return -1
|
||||
|
||||
return [shareid_list[0], user_id_list[0], fs_id_list, list(dict.fromkeys(server_filename_list)), isdir_list]
|
||||
|
||||
|
||||
def update_cookie(bdclnd: str, cookie: str) -> str:
|
||||
"""
|
||||
更新 cookie 字符串,以包含新的 BDCLND 值。
|
||||
|
||||
:param bdclnd: 新的 BDCLND 值
|
||||
:param cookie: 当前的 cookie 字符串
|
||||
:return: 返回新 cookie 字符串
|
||||
"""
|
||||
# 拆分 cookie 字符串到字典。先用 ; 分割成列表,再用 = 分割出键和值
|
||||
cookies_dict = dict(map(lambda item: item.split('=', 1), filter(None, cookie.split(';'))))
|
||||
# 在 cookie 字典中,更新或添加 BDCLND 的值
|
||||
cookies_dict['BDCLND'] = bdclnd
|
||||
# 从更新后的字典重新构建 cookie 字符串
|
||||
updated_cookie = ';'.join([f'{key}={value}' for key, value in cookies_dict.items()])
|
||||
|
||||
return updated_cookie
|
||||
|
||||
|
||||
def generate_code() -> str:
|
||||
"""
|
||||
生成一个四位的随机提取码,包含大小写字母和数字。
|
||||
|
||||
:return: 随机提取码
|
||||
"""
|
||||
# 包含大小写字母和数字
|
||||
characters = string.ascii_letters + string.digits
|
||||
# 随机选择四个字符
|
||||
code = ''.join(random.choice(characters) for _ in range(4))
|
||||
|
||||
return code
|
||||
@@ -12,6 +12,17 @@
|
||||
// [ 应用入口文件 ]
|
||||
namespace think;
|
||||
|
||||
// 检测PHP环境
|
||||
if(version_compare(PHP_VERSION,'7.2.0','<')) die('require 7.2.0 < PHP <= 7.3.0 !');
|
||||
if(version_compare(PHP_VERSION,'7.3.0','>')) die('require 7.2.0 < PHP <= 7.3.0 !');
|
||||
|
||||
// 检测是否是新安装
|
||||
if(file_exists("./install") && !file_exists("./install/install.lock")){
|
||||
$url=$_SERVER['HTTP_HOST'].trim($_SERVER['SCRIPT_NAME'],'index.php').'install/index.php';
|
||||
header("Location:http://$url");
|
||||
die;
|
||||
}
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// 执行HTTP应用并响应
|
||||
|
||||
BIN
public/install/.DS_Store
vendored
Normal file
27
public/install/config.ini.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
if(!defined('HAIZAN_VERSION')) die('what do you want?');
|
||||
return array(
|
||||
//数据库类型
|
||||
'DB_TYPE' => 'mysql',
|
||||
//服务器
|
||||
'DB_HOST'=>'#DB_HOST#',
|
||||
//数据库名
|
||||
'DB_NAME'=>'#DB_NAME#',
|
||||
//数据库用户名
|
||||
'DB_USER'=>'#DB_USER#',
|
||||
//数据库用户密码
|
||||
'DB_PWD'=> '#DB_PWD#',
|
||||
//数据库库表前缀
|
||||
'DB_PREFIX'=>'#DB_PREFIX#',
|
||||
// 端口
|
||||
'DB_PORT'=> '#DB_PORT#',
|
||||
|
||||
//Cookie前缀 避免冲突
|
||||
'COOKIE_PREFIX' => '#COOKIE_PREFIX#',
|
||||
// 缓存前缀
|
||||
'DATA_CACHE_PREFIX' => '#DATA_CACHE_PREFIX#',
|
||||
// session 前缀
|
||||
'SESSION_PREFIX' => '#SESSION_PREFIX#',
|
||||
//authcode加密函数密钥
|
||||
"AUTHCODE" => '#AUTHCODE#',
|
||||
);
|
||||
39
public/install/config.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
return array(
|
||||
/* ------系统------ */
|
||||
//系统名称
|
||||
'name'=>'心悦搜索管理系统',
|
||||
//系统版本
|
||||
'version'=>'1.0',
|
||||
//系统powered
|
||||
'powered'=>'后台管理系统',
|
||||
//系统脚部信息
|
||||
'footerInfo'=> '',
|
||||
|
||||
|
||||
/* ------配置------ */
|
||||
'php'=> '7.2.0', //最低要求
|
||||
'php_t'=> '7.2.5', //推荐配置
|
||||
|
||||
/* ------站点------ */
|
||||
//数据库文件
|
||||
'sqlFileName'=>'data.sql',
|
||||
//初始化商品文件
|
||||
'sqlFileGoods'=>'goods.sql',
|
||||
//数据库名
|
||||
'dbName' => '',
|
||||
//数据库表前缀
|
||||
'dbPrefix' => 'qf_',
|
||||
//站点名称
|
||||
'siteName' => '',
|
||||
//需要读写权限的目录
|
||||
'dirAccess' => array(
|
||||
'/',
|
||||
'../uploads',
|
||||
),
|
||||
/* ------写入数据库完成后处理的文件------ */
|
||||
'handleFile' => 'main.php',
|
||||
/* ------安装验证/生成文件;非云平台安装有效------ */
|
||||
'installFile' => './install.lock',
|
||||
'alreadyInstallInfo' => '你已经安装过该系统,如果想重新安装,请先删除站点install目录下的 install.lock 文件,然后再尝试安装!',
|
||||
);
|
||||
@@ -31,12 +31,7 @@ CREATE TABLE `qf_access` (
|
||||
`access_createtime` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
|
||||
`access_updatetime` int(11) NOT NULL DEFAULT 0 COMMENT '修改时间',
|
||||
PRIMARY KEY (`access_id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '授权信息表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of qf_access
|
||||
-- ----------------------------
|
||||
INSERT INTO `qf_access` VALUES (1, 1, 'e87d3ab11608533d4ee0cb05a21aee6f8e44865c100000e87d3ab11608533d4ee0cb05a21aee6f8e44865c', 'admin', '127.0.0.1', 0, 1726298717, 1726303168);
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '授权信息表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for qf_admin
|
||||
@@ -62,12 +57,7 @@ CREATE TABLE `qf_admin` (
|
||||
INDEX `admin_name`(`admin_name`) USING BTREE,
|
||||
INDEX `admin_password`(`admin_password`) USING BTREE,
|
||||
INDEX `admin_account`(`admin_account`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of qf_admin
|
||||
-- ----------------------------
|
||||
INSERT INTO `qf_admin` VALUES (1, 'admin', 'b806edc1a9e170c683c73e9ea486bbc9ffc07eb5', 'BuVf', '超级管理员', '', '超级管理员', '', 0.00, 1, '127.0.0.1', 0, 0, 1726303168);
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for qf_attach
|
||||
@@ -128,7 +118,7 @@ CREATE TABLE `qf_conf` (
|
||||
-- ----------------------------
|
||||
-- Records of qf_conf
|
||||
-- ----------------------------
|
||||
INSERT INTO `qf_conf` VALUES (1, 'app_name', '资源管理系统', '网站名称', '', 0, 0, NULL, 0, 1, 99, 1, 0, 1725411498);
|
||||
INSERT INTO `qf_conf` VALUES (1, 'app_name', '', '网站名称', '', 0, 0, NULL, 0, 1, 99, 1, 0, 1725411498);
|
||||
INSERT INTO `qf_conf` VALUES (2, 'upload_max_file', '4097152', '最大文件上传限制', '', 0, 0, NULL, 2, 1, 0, 1, 0, 1617352067);
|
||||
INSERT INTO `qf_conf` VALUES (3, 'upload_file_type', 'csv,xlsx', '允许文件上传类型', '', 0, 0, NULL, 2, 1, 0, 1, 0, 1617351959);
|
||||
INSERT INTO `qf_conf` VALUES (4, 'upload_max_image', '2097152', '最大图片上传限制', '', 0, 0, NULL, 2, 1, 0, 1, 0, 1617351961);
|
||||
@@ -137,17 +127,17 @@ INSERT INTO `qf_conf` VALUES (21, 'logo', '', '网站LOGO', '方形LOGO,最佳
|
||||
INSERT INTO `qf_conf` VALUES (22, 'quark_cookie', '', '夸克Cookie', '', 0, 0, NULL, 4, 1, 0, 1, 1712114435, 1712114652);
|
||||
INSERT INTO `qf_conf` VALUES (23, 'qcode', '', '群二维码', '前台加入群聊开关;有图显示按钮,无图不显示', 0, 4, NULL, 3, 1, 80, 1, 1712451616, 1725326400);
|
||||
INSERT INTO `qf_conf` VALUES (24, 'app_description', '', 'SEO描述', '', 0, 1, NULL, 9, 1, 996, 1, 1712451778, 1725411481);
|
||||
INSERT INTO `qf_conf` VALUES (25, 'quark_banned', '失效,年会员,空间容量,微信,微信群,全网资源,影视资源,扫码,最新资源,公众号,IMG_,资源汇总,緑铯粢源,.url,网盘推广,大额优惠券,资源文档,dy8.xyz,妙妙屋,资源合集,kkdm', '广告词', '出现这些词的资源,转存时删除;格式如:影视资源,年会员', 0, 1, NULL, 4, 1, 0, 1, 1714035639, 1723795683);
|
||||
INSERT INTO `qf_conf` VALUES (25, 'quark_banned', '失效,年会员,空间容量,微信,微信群,全网资源,影视资源,扫码,最新资源,公众号,IMG_,资源汇总,緑铯粢源,.url,网盘推广,大额优惠券,资源文档,dy8.xyz,妙妙屋,资源合集,kkdm', '广告词', '出现这些词的资源,转存时删除;格式如:影视资源,年会员', 0, 1, NULL, 4, 1, 999, 1, 1714035639, 1723795683);
|
||||
INSERT INTO `qf_conf` VALUES (26, 'Authorization', '', '阿里Authorization', '此版本用不着', 0, 0, NULL, 4, 1, 0, 1, 1722010465, 1722010465);
|
||||
INSERT INTO `qf_conf` VALUES (27, 'mp4_online', '0', '在线观看资源', '此版本用不着', 0, 2, '开启=>1\n关闭=>0', 4, 1, 0, 1, 1723014926, 1723014926);
|
||||
INSERT INTO `qf_conf` VALUES (28, 'search_type', '1', '搜索模式', '精准搜索:只有查包含关键词的;模糊搜索:关键词顺序可乱但必须都包含;分词搜索:只要满足其中一个字就会搜索到', 0, 2, '精准搜索=>0\n模糊搜索=>1\n分词搜索=>2', 1, 1, 0, 1, 1724493746, 1724494058);
|
||||
INSERT INTO `qf_conf` VALUES (29, 'app_keywords', 'XXX,XXX,XXXX', 'SEO关键词', '网站关键词,有利于对整站的SEO优化', 0, 1, NULL, 9, 1, 998, 1, 1725006403, 1725411476);
|
||||
INSERT INTO `qf_conf` VALUES (30, 'app_title', 'XXXXXXXXXXXX', 'SEO标题', '', 0, 0, NULL, 9, 1, 999, 1, 1725006679, 1725325013);
|
||||
INSERT INTO `qf_conf` VALUES (31, 'app_subname', 'Hello World', '网站宣传语', '免费分享百万级网盘资源,致力打造顶尖网盘搜索引擎,让您畅享资源无忧!', 0, 0, NULL, 0, 1, 94, 1, 1725006792, 1725006869);
|
||||
INSERT INTO `qf_conf` VALUES (29, 'app_keywords', '', 'SEO关键词', '网站关键词,有利于对整站的SEO优化', 0, 1, NULL, 9, 1, 998, 1, 1725006403, 1725411476);
|
||||
INSERT INTO `qf_conf` VALUES (30, 'app_title', '', 'SEO标题', '', 0, 0, NULL, 9, 1, 999, 1, 1725006679, 1725325013);
|
||||
INSERT INTO `qf_conf` VALUES (31, 'app_subname', '', '网站宣传语', '免费分享百万级网盘资源,致力打造顶尖网盘搜索引擎,让您畅享资源无忧!', 0, 0, NULL, 0, 1, 94, 1, 1725006792, 1725006869);
|
||||
INSERT INTO `qf_conf` VALUES (32, 'home_bg', '', '大图背景', '', 0, 4, '', 3, 1, 75, 1, 1725007588, 1725007613);
|
||||
INSERT INTO `qf_conf` VALUES (33, 'home_background', NULL, '背景颜色', '默认:#fafafa', 0, 7, NULL, 3, 1, 74, 1, 1725007770, 1725027349);
|
||||
INSERT INTO `qf_conf` VALUES (34, 'footer_dec', '声明:本站是网盘索引系统,所有内容均来自互联网所提供的公开引用资源,未提供资源上传、存储服务。', '底部介绍', '示例:声明:本站是网盘索引系统,所有内容均来自互联网所提供的公开引用资源,未提供资源上传、存储服务。', 0, 1, NULL, 0, 1, 90, 1, 1725025185, 1725325534);
|
||||
INSERT INTO `qf_conf` VALUES (35, 'footer_copyright', '© 2024 心悦 Powered by <a href=\"https://github.com/675061370/xinyue-search/\" target=\"_blank\">心悦</a>', '底部版权', '示例:© 2024 心悦 Powered by <a href=\"https://github.com/675061370/xinyue-search/\" target=\"_blank\">心悦</a>', 0, 1, NULL, 0, 1, 89, 1, 1725025262, 1725325624);
|
||||
INSERT INTO `qf_conf` VALUES (34, 'footer_dec', '', '底部介绍','示例:声明:本站是网盘索引系统,所有内容均来自互联网所提供的公开引用资源,未提供资源上传、存储服务。', 0, 1, NULL, 0, 1, 90, 1, 1725025185, 1725325534);
|
||||
INSERT INTO `qf_conf` VALUES (35, 'footer_copyright', '', '底部版权','示例:© 2024 心悦搜剧 Powered by <a href=\"https://www.xinyuedh.com/\" target=\"_blank\">心悦导航</a>', 0, 1, NULL, 0, 1, 89, 1, 1725025262, 1725325624);
|
||||
INSERT INTO `qf_conf` VALUES (36, 'home_color', NULL, '文字颜色', '默认文字颜色:#000000', 0, 7, NULL, 3, 1, 73, 1, 1725027432, 1725027445);
|
||||
INSERT INTO `qf_conf` VALUES (37, 'home_theme', NULL, '主题色', '默认:#1e80ff', 0, 7, NULL, 3, 1, 72, 1, 1725027499, 1725027504);
|
||||
INSERT INTO `qf_conf` VALUES (38, 'other_background', NULL, '其它元素背景', '搜索框及其它元素北背景色 默认:#ffffff', 0, 7, NULL, 3, 1, 71, 1, 1725028468, 1725028478);
|
||||
@@ -157,7 +147,7 @@ INSERT INTO `qf_conf` VALUES (41, 'home_css', '', '自定义CSS', '直接写css
|
||||
INSERT INTO `qf_conf` VALUES (42, 'seo_statistics', '', '统计代码', '直接填写统计代码即可,如51LA: <script charset=\"UTF-8\" id=\"XXXXX\" src=\"//sdk.51.la/js-sdk-pro.min.js\"></script> <script>LA.init({id:\"XXXXX\",ck:\"XXXX\",hashMode:true})</script>', 0, 1, NULL, 9, 1, 995, 1, 1725325341, 1725411486);
|
||||
INSERT INTO `qf_conf` VALUES (43, 'app_icon', '', '网站icon', '', 0, 4, NULL, 0, 1, 92, 1, 1725326071, 1725326071);
|
||||
INSERT INTO `qf_conf` VALUES (44, 'app_demand', '0', '提交需求', '前台是否开启此功能 ; 默认开启', 0, 2, '开启=>0\n关闭=>1', 3, 1, 81, 1, 1725326640, 1725326707);
|
||||
INSERT INTO `qf_conf` VALUES (45, 'app_links', '<a href=\"https://github.com/675061370/xinyue-search/\" target=\"_blank\">更多资源</a>', '顶部其他外链', '一行一个外链(a标签):<a href=\"https://github.com/675061370/xinyue-search/\" target=\"_blank\">更多资源</a>', 0, 1, NULL, 3, 1, 80, 1, 1725326838, 1725326838);
|
||||
INSERT INTO `qf_conf` VALUES (45, 'app_links', '', '顶部其他外链', '一行一个外链(a标签):<a href=\"https://www.xinyuedh.com/\" target=\"_blank\">更多资源</a>', 0, 1, NULL, 3, 1, 80, 1, 1725326838, 1725326838);
|
||||
INSERT INTO `qf_conf` VALUES (46, 'app_name_hide', '0', '隐藏网站名称', '默认显示:logo包含文字的可以隐藏网站名称', 0, 2, '显示=>0\n隐藏=>1', 0, 1, 98, 1, 1725411632, 1725411763);
|
||||
INSERT INTO `qf_conf` VALUES (47, 'ranking_m_num', '6', '移动端限制数量', '释:移动端最多显示数量', 0, 0, NULL, 3, 1, 77, 1, 1725412329, 1725412329);
|
||||
INSERT INTO `qf_conf` VALUES (48, 'search_tips', '', '未搜索提示词', '为空时默认:未找到,可换个关键词尝试哦~', 0, 0, NULL, 1, 1, 0, 1, 1726108804, 1726108804);
|
||||
@@ -165,6 +155,20 @@ INSERT INTO `qf_conf` VALUES (49, 'search_bg', '', '未搜索提示图', '', 0,
|
||||
INSERT INTO `qf_conf` VALUES (50, 'home_new', '1', '最新列表', '仅无图模式有效', 0, 2, '开启=>0\n关闭=>1', 3, 1, 79, 1, 1726299605, 1726299605);
|
||||
INSERT INTO `qf_conf` VALUES (51, 'home_new_img', '', '最新图标', '', 0, 4, NULL, 3, 1, 79, 1, 1726302688, 1726302688);
|
||||
INSERT INTO `qf_conf` VALUES (52, 'is_quan', '0', '全网搜', '', 0, 2, '关闭=>0\n开启=>1', 1, 1, 1, 1, 1729928547, 1729928547);
|
||||
INSERT INTO `qf_conf` VALUES ('53', 'baidu_cookie', '', '百度Cookie', '', '0', '0', NULL, '4', '1', '89', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('54', 'quark_file', '', '夸克默认转存目录', '', '0', '0', NULL, '4', '1', '98', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('55', 'quark_file_time', '', '夸克临时资源目录', '', '0', '0', NULL, '4', '1', '97', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('56', 'baidu_file', '', '百度默认转存目录', '', '0', '0', NULL, '4', '1', '88', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('57', 'baidu_file_time', '', '百度临时资源目录', '', '0', '0', NULL, '4', '1', '87', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('58', 'ali_file', '', '阿里默认转存目录', '', '0', '0', NULL, '4', '1', '78', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('59', 'ali_file_time', '', '阿里临时资源目录', '', '0', '0', NULL, '4', '1', '77', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('60', 'uc_cookie', '', 'UcCookie', '', '0', '0', NULL, '4', '1', '69', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('61', 'uc_file', '', 'UC默认转存目录', '', '0', '0', NULL, '4', '1', '68', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('62', 'uc_file_time', '', 'UC临时资源目录', '', '0', '0', NULL, '4', '1', '67', '1', '1743145595', '1743145595');
|
||||
INSERT INTO `qf_conf` VALUES ('63', 'xunlei_cookie', '', '迅雷Cookie', '', '0', '0', NULL, '4', '1', '59', '1', '1743149794', '1743149794');
|
||||
INSERT INTO `qf_conf` VALUES ('64', 'xunlei_file', '', '迅雷默认转存目录', '', '0', '0', NULL, '4', '1', '58', '1', '1743149819', '1743149819');
|
||||
INSERT INTO `qf_conf` VALUES ('65', 'xunlei_file_time', '', '迅雷临时资源目录', '', '0', '0', NULL, '4', '1', '57', '1', '1743149860', '1743149860');
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
381
public/install/index.php
Normal file
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
header("Content-type: text/html; charset=utf-8");
|
||||
//开启session
|
||||
session_start();
|
||||
//配置信息
|
||||
$config = include './config.php';
|
||||
if(empty($config)){
|
||||
exit(get_tip_html('安装配置信息不存在,无法继续安装!'));
|
||||
}
|
||||
//安装环境验证,获取相应判断信息
|
||||
define('INSTALLTYPE', 'HOST');
|
||||
//本地
|
||||
require './localhost.php';
|
||||
|
||||
//限制最大的执行时间
|
||||
set_time_limit(1000);
|
||||
//php版本
|
||||
$phpversion = phpversion();
|
||||
//数据库文件
|
||||
if(!file_exists('./'.$config['sqlFileName'])){
|
||||
exit(get_tip_html('数据库文件不存在,无法继续安装!'));
|
||||
}
|
||||
//写入数据库完成后处理的文件
|
||||
if (!file_exists('./'.$config['handleFile'])) {
|
||||
exit(get_tip_html('处理文件不存在,无法继续安装!'));
|
||||
}
|
||||
//设置报错级别并返回当前级别。
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
//安装步骤
|
||||
$steps = array(
|
||||
'1' => '安装许可协议',
|
||||
'2' => '运行环境检测',
|
||||
'3' => '安装参数设置',
|
||||
'4' => '安装详细过程',
|
||||
'5' => '安装完成',
|
||||
);
|
||||
$step = isset($_GET['step']) ? $_GET['step'] : 1;
|
||||
//当前安装步骤
|
||||
$step_html = '';
|
||||
foreach ($steps as $key => $value) {
|
||||
$current = $key == $step? 'current':'';
|
||||
$step_html .= '<li class="'.$current.'"><em>'.$key.'</em>'.$value.'</li>';
|
||||
}
|
||||
//安装页面
|
||||
switch ($step) {
|
||||
//安装许可协议
|
||||
case '1':
|
||||
$license = file_get_contents('./license.txt');
|
||||
include ("./templates/1.php");
|
||||
break;
|
||||
//运行环境检测
|
||||
case '2':
|
||||
$server = array(
|
||||
//操作系统
|
||||
'os' => php_uname(),
|
||||
//PHP版本
|
||||
'php' => $phpversion,
|
||||
);
|
||||
$error = 0;
|
||||
//php版本
|
||||
if ($phpversion>=$config['php']) {
|
||||
$server['php'] = '<span class="correct_span">√</span> 支持';
|
||||
} else {
|
||||
$server['php'] = '<span class="correct_span error_span">√</span> '.$phpversion;
|
||||
$error++;
|
||||
}
|
||||
//上传限制
|
||||
if (ini_get('file_uploads')) {
|
||||
$server['uploadSize'] = '<span class="correct_span">√</span> ' . ini_get('upload_max_filesize');
|
||||
} else {
|
||||
$server['uploadSize'] = '<span class="correct_span error_span">√</span>禁止上传';
|
||||
}
|
||||
//session
|
||||
if (function_exists('session_start')) {
|
||||
$server['session'] = '<span class="correct_span">√</span> 支持';
|
||||
} else {
|
||||
$server['session'] = '<span class="correct_span error_span">√</span> 不支持';
|
||||
$error++;
|
||||
}
|
||||
|
||||
|
||||
//需要读写权限的目录
|
||||
$folder = $config['dirAccess'];
|
||||
$install_path = str_replace('\\','/',getcwd()).'/';
|
||||
$site_path = str_replace('Install/', '', $install_path);
|
||||
include ("./templates/2.php");
|
||||
$_SESSION['INSTALLSTATUS'] = $error == 0?'SUCCESS':$error;
|
||||
break;
|
||||
//安装参数设置
|
||||
case '3':
|
||||
verify(3);
|
||||
//测试数据库链接
|
||||
if (isset($_GET['testdbpwd'])) {
|
||||
empty($_POST['dbhost'])?alert(0,'数据库服务器地址不能为空!','dbhost'):'';
|
||||
empty($_POST['dbuser'])?alert(0,'数据库用户名不能为空!','dbuser'):'';
|
||||
empty($_POST['dbname'])?alert(0,'数据库名不能为空!','dbname'):'';
|
||||
empty($_POST['dbport'])?alert(0,'数据库端口不能为空!','dbport'):'';
|
||||
$dbHost = $_POST['dbhost'] . ':' . $_POST['dbport'];
|
||||
$mysqli = new mysqli($dbHost, $_POST['dbuser'], $_POST['dbpw']);
|
||||
if(!$mysqli->server_info) {
|
||||
alert(0,'数据库链接失败!','dbpw');
|
||||
}else{
|
||||
alert(1,'数据库链接成功!','dbpw');
|
||||
}
|
||||
$mysqli->close();
|
||||
}
|
||||
//域名+路径
|
||||
$domain = empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
|
||||
if ((int) $_SERVER['SERVER_PORT'] != 80) {
|
||||
$domain .= ":" . $_SERVER['SERVER_PORT'];
|
||||
}
|
||||
$scriptName = !empty($_SERVER["REQUEST_URI"]) ? $scriptName = $_SERVER["REQUEST_URI"] : $scriptName = $_SERVER["PHP_SELF"];
|
||||
$rootpath = preg_replace("/\/(I|i)nstall\/index\.php(.*)$/", "", $scriptName);
|
||||
$domain = $domain . $rootpath;
|
||||
include ("./templates/3.php");
|
||||
break;
|
||||
//安装详细过程
|
||||
case '4':
|
||||
if (!isset($_GET['install'])){
|
||||
switch (INSTALLTYPE){
|
||||
case 'SAE':
|
||||
// 服务器地址
|
||||
$_POST['dbhost'] = SAE_MYSQL_HOST_M;
|
||||
// 端口
|
||||
$_POST['dbport'] = SAE_MYSQL_PORT;
|
||||
// 数据库名
|
||||
$_POST['dbname'] = SAE_MYSQL_DB;
|
||||
// 用户名
|
||||
$_POST['dbuser'] = SAE_MYSQL_USER;
|
||||
// 密码
|
||||
$_POST['dbpw'] = SAE_MYSQL_PASS;
|
||||
break;
|
||||
case 'BAE':
|
||||
// 服务器地址
|
||||
$_POST['dbhost'] = HTTP_BAE_ENV_ADDR_SQL_IP;
|
||||
// 端口
|
||||
$_POST['dbport'] = HTTP_BAE_ENV_ADDR_SQL_PORT;
|
||||
// 用户名
|
||||
$_POST['dbuser'] = HTTP_BAE_ENV_SK;
|
||||
// 密码
|
||||
$_POST['dbpw'] = SAE_MYSQL_PASS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
verify(4);
|
||||
if (intval($_GET['install'])) {
|
||||
dataVerify();
|
||||
//关闭特殊字符提交处理到数据库
|
||||
//设置时区
|
||||
date_default_timezone_set('PRC');
|
||||
//当前进行的数据库操作
|
||||
$n = intval($_GET['n']);
|
||||
$arr = array();
|
||||
//数据库服务器地址
|
||||
$dbHost = trim($_POST['dbhost']);
|
||||
//数据库端口
|
||||
$dbPort = trim($_POST['dbport']);
|
||||
//数据库名
|
||||
$dbName = trim($_POST['dbname']);
|
||||
$dbHost = empty($dbPort) || $dbPort == 3306 ? $dbHost : $dbHost . ':' . $dbPort;
|
||||
//数据库用户名
|
||||
$dbUser = trim($_POST['dbuser']);
|
||||
//数据库密码
|
||||
$dbPwd = trim($_POST['dbpw']);
|
||||
//表前缀
|
||||
$dbPrefix = empty($_POST['dbprefix']) ? 'db_' : trim($_POST['dbprefix']);
|
||||
//链接数据库
|
||||
$mysqli = new mysqli($dbHost, $dbUser, $dbPwd);
|
||||
//导入政采商品
|
||||
$sitegoods = trim($_POST['sitegoods']);
|
||||
// 获取错误信息
|
||||
$error=$mysqli->connect_error;
|
||||
if (!is_null($error)) {
|
||||
alert(0,'数据库链接失败!');
|
||||
}
|
||||
// 设置字符集
|
||||
$mysqli->query("SET NAMES 'utf8'");
|
||||
if ($mysqli->server_info < 5.0) {
|
||||
alert(0,'请将您的mysql升级到5.0以上');
|
||||
}
|
||||
// 创建数据库并选中
|
||||
if(!$mysqli->select_db($dbName)){
|
||||
$create_sql='CREATE DATABASE IF NOT EXISTS '.$dbName.' DEFAULT CHARACTER SET utf8;';
|
||||
$mysqli->query($create_sql) or alert(0,'创建数据库失败');
|
||||
$mysqli->select_db($dbName);
|
||||
}
|
||||
|
||||
// 导入sql数据并创建表
|
||||
$sqldata = file_get_contents('./'.$config['sqlFileName']);
|
||||
if(empty($sqldata)){
|
||||
alert(0,'数据库文件不能为空!');
|
||||
}
|
||||
$sql_array=preg_split("/;[\r\n]+/", str_replace($config['dbPrefix'],$dbPrefix,$sqldata));
|
||||
|
||||
$counts = count($sql_array);
|
||||
|
||||
for ($i = $n; $i < $counts; $i++) {
|
||||
$sql = trim($sql_array[$i]);
|
||||
if (strstr($sql, 'CREATE TABLE')) {
|
||||
preg_match('/CREATE TABLE `([^ ]*)`/', $sql, $matches);
|
||||
$mysqli->query($sql_array[$i]);
|
||||
$info = '<li><span class="correct_span">√</span>创建数据表' . $matches[1] . ',完成!<span style="float: right;">'.date('Y-m-d H:i:s').'</span></li> ';
|
||||
$i++;
|
||||
alert(1,$info,$i);
|
||||
}else{
|
||||
if(!empty($sql)){
|
||||
$mysqli->query($sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//处理
|
||||
$data = include './'.$config['handleFile'];
|
||||
$_SESSION['INSTALLOK'] = $data['status']?1:0;
|
||||
alert($data['status'],$data['info']);
|
||||
}
|
||||
include ("./templates/4.php");
|
||||
break;
|
||||
//安装完成
|
||||
case '5':
|
||||
verify(5);
|
||||
include ("./templates/5.php");
|
||||
//安装完成,生成.lock文件
|
||||
if(isset($_SESSION['INSTALLOK']) && $_SESSION['INSTALLOK'] == 1){
|
||||
filewrite($config['installFile']);
|
||||
}
|
||||
unset($_SESSION);
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误提示html
|
||||
*/
|
||||
function get_tip_html($info){
|
||||
return '<div>'.$info.'</div>';
|
||||
}
|
||||
//返回提示信息
|
||||
function alert($status,$info,$type = 0){
|
||||
exit(json_encode(array('status'=>$status,'info'=>$info,'type'=>$type)));
|
||||
}
|
||||
function verify($step = 3){
|
||||
if($step >= 3){
|
||||
//未运行环境检测,跳转到安装许可协议页面
|
||||
if(!isset($_SESSION['INSTALLSTATUS'])){
|
||||
header('location:./index.php');
|
||||
exit();
|
||||
}
|
||||
//运行环境检测存在错误,返回运行环境检测
|
||||
if($_SESSION['INSTALLSTATUS'] != 'SUCCESS'){
|
||||
header('location:./index.php?step=2');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
if($step == 4){
|
||||
//未提交数据
|
||||
if(empty($_POST)){
|
||||
header('location:./index.php?step=3');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
if($step >= 5){
|
||||
//数据库未写入完成
|
||||
if(!isset($_SESSION['INSTALLOK'])){
|
||||
header('location:./index.php?step=4');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
function dataVerify(){
|
||||
empty($_POST['dbhost'])?alert(0,'数据库服务器不能为空!'):'';
|
||||
empty($_POST['dbport'])?alert(0,'数据库端口不能为空!'):'';
|
||||
empty($_POST['dbuser'])?alert(0,'数据库用户名不能为空!'):'';
|
||||
empty($_POST['dbname'])?alert(0,'数据库名不能为空!'):'';
|
||||
empty($_POST['dbprefix'])?alert(0,'数据库表前缀不能为空!'):'';
|
||||
empty($_POST['manager'])?alert(0,'管理员帐号不能为空!'):'';
|
||||
empty($_POST['manager_pwd'])?alert(0,'管理员密码不能为空!'):'';
|
||||
}
|
||||
/**
|
||||
* 判断目录是否可写
|
||||
*/
|
||||
function testwrite($d) {
|
||||
$tfile = "_test.txt";
|
||||
$fp = fopen($d . "/" . $tfile, "w");
|
||||
if (!$fp) {
|
||||
return false;
|
||||
}
|
||||
fclose($fp);
|
||||
$rs = unlink($d . "/" . $tfile);
|
||||
if ($rs) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 创建目录
|
||||
*/
|
||||
function dir_create($path, $mode = 0777) {
|
||||
if (is_dir($path)) {
|
||||
return TRUE;
|
||||
}
|
||||
mkdir($path, $mode, true);
|
||||
chmod($path, $mode);
|
||||
}
|
||||
/**
|
||||
* 数据库语句解析
|
||||
* @param $sql 数据库
|
||||
* @param $newTablePre 新的前缀
|
||||
* @param $oldTablePre 旧的前缀
|
||||
*/
|
||||
function sql_split($sql, $newTablePre, $oldTablePre) {
|
||||
//前缀替换
|
||||
if ($newTablePre != $oldTablePre){
|
||||
$sql = str_replace($oldTablePre, $newTablePre, $sql);
|
||||
}
|
||||
$sql = preg_replace("/TYPE=(InnoDB|MyISAM|MEMORY)( DEFAULT CHARSET=[^; ]+)?/", "ENGINE=\\1 DEFAULT CHARSET=utf8", $sql);
|
||||
|
||||
$sql = str_replace("\r", "\n", $sql);
|
||||
$ret = array();
|
||||
$queriesarray = explode(";\n", trim($sql));
|
||||
unset($sql);
|
||||
foreach ($queriesarray as $k=>$query) {
|
||||
$ret[$k] = '';
|
||||
$queries = explode("\n", trim($query));
|
||||
$queries = array_filter($queries);
|
||||
foreach ($queries as $query) {
|
||||
$str1 = substr($query, 0, 1);
|
||||
if ($str1 != '#' && $str1 != '-')
|
||||
$ret[$k] .= $query;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
/**
|
||||
* 产生随机字符串
|
||||
* 产生一个指定长度的随机字符串,并返回给用户
|
||||
* @access public
|
||||
* @param int $len 产生字符串的位数
|
||||
* @return string
|
||||
*/
|
||||
function genRandomString($len = 6) {
|
||||
$chars = array(
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
|
||||
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
|
||||
"w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
|
||||
"S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
|
||||
"3", "4", "5", "6", "7", "8", "9", '!', '@', '#', '$',
|
||||
'%', '^', '&', '*', '(', ')'
|
||||
);
|
||||
$charsLen = count($chars) - 1;
|
||||
shuffle($chars); // 将数组打乱
|
||||
$output = "";
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$output .= $chars[mt_rand(0, $charsLen)];
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
/**
|
||||
* 获取客户端IP地址
|
||||
* @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
|
||||
* @return mixed
|
||||
*/
|
||||
function get_client_ip($type = 0) {
|
||||
$type = $type ? 1 : 0;
|
||||
static $ip = NULL;
|
||||
if ($ip !== NULL) return $ip[$type];
|
||||
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||
$pos = array_search('unknown',$arr);
|
||||
if(false !== $pos) unset($arr[$pos]);
|
||||
$ip = trim($arr[0]);
|
||||
}elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
// IP地址合法验证
|
||||
$long = sprintf("%u",ip2long($ip));
|
||||
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
|
||||
return $ip[$type];
|
||||
}
|
||||
0
public/install/install.lock
Normal file
14
public/install/license.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
请您在使用前仔细阅读如下条款。包括免除或者限制作者责任的免责条款及对用户的权利限制。您的安装使用行为将视为对本《用户许可协议》的接受,并同意接受本《用户许可协议》各项条款的约束。
|
||||
|
||||
一、安装和使用:
|
||||
您必须保证在不进行非法活动,不违反国家相关政策法规的前提下使用本软件。
|
||||
|
||||
二:郑重声明:
|
||||
1、任何个人或组织不得在未经授权的情况下删除、修改、拷贝本软件及其他副本上一切关于版权的信息。
|
||||
|
||||
三、免责声明:
|
||||
本软件并无附带任何形式的明示的或暗示的保证,包括任何关于本软件的适用性, 无侵犯知识产权或适合作某一特定用途的保证。
|
||||
在任何情况下,对于因使用本软件或无法使用本软件而导致的任何损害赔偿,作者均无须承担法律责任。作者不保证本软件所包含的资料,文字、图形、链接或其它事项的准确性或完整性。
|
||||
所有由用户自己制作、下载、使用的第三方信息数据和插件所引起的一切版权问题或纠纷,本软件概不承担任何责任。
|
||||
|
||||
版权所有 (c) 2024-2025,系统保留所有权利。
|
||||
10
public/install/localhost.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
//检测是否已经安装
|
||||
if(file_exists($config['installFile'])){
|
||||
exit(get_tip_html($config['alreadyInstallInfo']));
|
||||
}
|
||||
|
||||
//写入文件
|
||||
function filewrite($file){
|
||||
@touch($file);
|
||||
}
|
||||
46
public/install/main.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
$username = trim($_POST['manager']);
|
||||
$password = trim($_POST['manager_pwd']);
|
||||
//网站名称
|
||||
$site_name = addslashes(trim($_POST['sitename']));
|
||||
|
||||
//更新配置信息
|
||||
$mysqli->query("UPDATE `{$dbPrefix}conf` SET `conf_value` = '$site_name' WHERE conf_key='app_name'");
|
||||
|
||||
if(INSTALLTYPE == 'HOST'){
|
||||
$db_str=<<<php
|
||||
APP_DEBUG = true
|
||||
SYSTEM_SALT= {$site_name}
|
||||
|
||||
[APP]
|
||||
DEFAULT_TIMEZONE = Asia/Chongqing
|
||||
|
||||
[DATABASE]
|
||||
TYPE = mysql
|
||||
HOSTNAME = {$dbHost}
|
||||
DATABASE = {$dbName}
|
||||
USERNAME = {$dbUser}
|
||||
PASSWORD = {$dbPwd}
|
||||
HOSTPORT = {$dbPort}
|
||||
CHARSET = utf8mb4
|
||||
DEBUG = false
|
||||
PREFIX = {$dbPrefix}
|
||||
|
||||
[LANG]
|
||||
default_lang = zh-cn
|
||||
php;
|
||||
// 创建数据库链接配置文件
|
||||
file_put_contents('../../.env', $db_str);
|
||||
}
|
||||
|
||||
//插入管理员
|
||||
//生成随机认证码
|
||||
$salt = genRandomString(4);
|
||||
$time = time();
|
||||
$ip = get_client_ip();
|
||||
$password = sha1($password . $salt . $password . $salt);
|
||||
$url = "insert into `{$dbPrefix}admin` VALUES (1,'{$username}', '{$password}', '{$salt}', '超级管理员','','超级管理员','',0.00,1,'127.0.0.1',0,'{$time}','{$time}')";
|
||||
$mysqli->query($url);
|
||||
|
||||
$mysqli->close();
|
||||
return array('status'=>2,'info'=>'成功添加管理员<br />成功写入配置文件<br>安装完成...');
|
||||
118
public/install/sae.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
//设置storage的domain
|
||||
if($_GET['step'] == 0){
|
||||
if(empty($_POST['storagedomain'])){
|
||||
$step_html = '<li class="current"><em>0</em>Storage设置</li>';
|
||||
include './templates/0.php';
|
||||
exit;
|
||||
} else {
|
||||
$_SESSION['STORAGEDOMAIN'] = $_POST['storagedomain'];
|
||||
if(!empty($_SESSION['STORAGEDOMAIN'])){
|
||||
header('location:./index.php?step=1');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!isset($_SESSION['STORAGEDOMAIN']) || empty($_SESSION['STORAGEDOMAIN'])){
|
||||
header('location:./index.php?step=0');
|
||||
exit;
|
||||
}
|
||||
$config['uploaddir'] = $_SESSION['STORAGEDOMAIN'];
|
||||
//测试该该storage是否有效!
|
||||
if(!filewrite($config['uploaddir'].'/install_file.lock')){
|
||||
exit(get_tip_html('该storage无效!'));
|
||||
} else{
|
||||
file_delete($config['uploaddir'].'/install_file.lock');
|
||||
}
|
||||
|
||||
define('SAESTOR_INSTALL_NAME', $config['uploaddir'].'/saestor_'. $_SERVER['HTTP_APPVERSION'] . '_install.lock');
|
||||
$config['alreadySaeInstallInfo'] = "版本" . $_SERVER['HTTP_APPVERSION'] . "已完成安装!请删除网站根目录下的install目录!<br />如果需要重新安装,请先删除storage内的 saestor_" . $_SERVER['HTTP_APPVERSION'] . "_install.lock 文件";
|
||||
if(fileExists(SAESTOR_INSTALL_NAME)){
|
||||
exit(get_tip_html($config['alreadySaeInstallInfo']));
|
||||
}
|
||||
if(!is_storage){
|
||||
exit(get_tip_html('请开启storage服务!'));
|
||||
}
|
||||
if(!is_mc){
|
||||
exit(get_tip_html('请开启memcahce服务!'));
|
||||
}
|
||||
if(!is_mysql){
|
||||
exit(get_tip_html('请开启mysql服务!'));
|
||||
}
|
||||
if(!is_kv){
|
||||
exit(get_tip_html('请开启KV数据库服务!'));
|
||||
}
|
||||
|
||||
//SaeStorage
|
||||
function SaeStorage(){
|
||||
static $SaeStorage = array();
|
||||
if(!isset($SaeStorage['SaeStorage'])){
|
||||
$SaeStorage['SaeStorage'] = new SaeStorage();
|
||||
}
|
||||
return $SaeStorage['SaeStorage'];
|
||||
}
|
||||
//domain 路径
|
||||
function file_getdomainfilepath($filename){
|
||||
$arr=explode('/',ltrim($filename,'./'));
|
||||
if($arr[count($arr)-1] == ''){
|
||||
unset($arr[count($arr)-1]);
|
||||
}
|
||||
$domain=array_shift($arr);
|
||||
$filePath=implode('/',$arr);
|
||||
return array('domain'=>$domain,'filepath'=>$filePath);
|
||||
}
|
||||
//检查文件是否存在
|
||||
function fileExists($filename){
|
||||
$arr=file_getdomainfilepath($filename);
|
||||
return SaeStorage()->fileExists($arr['domain'], $arr['filepath']);
|
||||
}
|
||||
//写入文件
|
||||
function filewrite($file = ''){
|
||||
$file = empty($file) ? SAESTOR_INSTALL_NAME:$file;
|
||||
$arr=file_getdomainfilepath($file);
|
||||
SaeStorage()->write($arr['domain'], $arr['filepath'],'1');
|
||||
}
|
||||
//删除文件
|
||||
function file_delete($filename){
|
||||
$arr=file_getdomainfilepath($filename);
|
||||
return SaeStorage()->delete($arr['domain'], $arr['filepath']);
|
||||
}
|
||||
|
||||
//判断是否开启storage
|
||||
function is_storage() {
|
||||
$s = new SaeStorage();
|
||||
if (!$s->write(SAESTOR_NAME, 'is_storage', '1')) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
//判断是否开启memcahce
|
||||
function is_mc() {
|
||||
$mmc = @memcache_init();
|
||||
if ($mmc) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
//判断是否开启mysql
|
||||
function is_mysql() {
|
||||
$mysql = @new SaeMysql();
|
||||
$sql = "select database()";
|
||||
$data = @$mysql->getData($sql);
|
||||
if ($data) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
//判断是否开启KV数据库
|
||||
function is_kv(){
|
||||
$kv=new SaeKV();
|
||||
if($kv->init()){
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
BIN
public/install/templates/.DS_Store
vendored
Normal file
10
public/install/templates/1.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php require './templates/header.php';?>
|
||||
<div class="section">
|
||||
<div class="main">
|
||||
<pre class="pact"><?php echo $license;?></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<a href="./index.php?step=2" class="btn">接 受</a>
|
||||
</div>
|
||||
<?php require './templates/footer.php';?>
|
||||
78
public/install/templates/2.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php require './templates/header.php';?>
|
||||
<div class="section">
|
||||
<div class="main server">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="td1">环境检测</td>
|
||||
<td class="td1" width="25%">推荐配置</td>
|
||||
<td class="td1" width="25%">当前状态</td>
|
||||
<td class="td1" width="25%">最低要求</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作系统</td>
|
||||
<td>类UNIX</td>
|
||||
<td><span class="correct_span">√</span> <?php echo $server['os']; ?></td>
|
||||
<td>不限制</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PHP版本</td>
|
||||
<td><?php echo $config['php_t']; ?></td>
|
||||
<td><?php echo $server['php']; ?></td>
|
||||
<td><?php echo $config['php']; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>附件上传</td>
|
||||
<td>>2M</td>
|
||||
<td><?php echo $server['uploadSize']; ?></td>
|
||||
<td>不限制</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>session</td>
|
||||
<td>开启</td>
|
||||
<td><?php echo $server['session']; ?></td>
|
||||
<td>开启</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php if(INSTALLTYPE == 'HOST'){ ?>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="td1">目录、文件权限检查</td>
|
||||
<td class="td1" width="25%">写入</td>
|
||||
<td class="td1" width="25%">读取</td>
|
||||
</tr>
|
||||
<?php
|
||||
foreach($folder as $dir){
|
||||
$Testdir = $site_path.$dir;
|
||||
dir_create($Testdir);
|
||||
if(TestWrite($Testdir)){
|
||||
$w = '<span class="correct_span">√</span>可写 ';
|
||||
}else{
|
||||
$w = '<span class="correct_span error_span">√</span>不可写 ';
|
||||
$error++;
|
||||
}
|
||||
if(is_readable($Testdir)){
|
||||
$r = '<span class="correct_span">√</span>可读' ;
|
||||
}else{
|
||||
$r = '<span class="correct_span error_span">√</span>不可读';
|
||||
$error++;
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo $dir; ?></td>
|
||||
<td><?php echo $w; ?></td>
|
||||
<td><?php echo $r; ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<a href="./index.php?step=2" class="btn">重新检测</a>
|
||||
<?php if(empty($error)){ ?>
|
||||
<a href="./index.php?step=3" class="btn">下一步</a>
|
||||
<?php } else { ?>
|
||||
<button href="#" class="btn error" disabled>当前有误</button>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php require './templates/footer.php';?>
|
||||
264
public/install/templates/3.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php require './templates/header.php';?>
|
||||
<form id="J_install_form" action="index.php?step=4" method="post">
|
||||
<div class="section">
|
||||
<div class="main server">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="td1" width="100">数据库信息</td>
|
||||
<td class="td1" width="200"> </td>
|
||||
<td class="td1"> </td>
|
||||
</tr>
|
||||
<?php if(INSTALLTYPE == 'HOST'){?>
|
||||
<tr>
|
||||
<td class="tar">数据库服务器:</td>
|
||||
<td><input type="text" name="dbhost" id="dbhost" value="127.0.0.1" class="input"></td>
|
||||
<td><div id="J_install_tip_dbhost"><span class="gray">数据库服务器地址,一般为localhost</span></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">数据库端口:</td>
|
||||
<td><input type="text" name="dbport" id="dbport" value="3306" class="input"></td>
|
||||
<td><div id="J_install_tip_dbport"><span class="gray">数据库服务器端口,一般为3306</span></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">数据库用户名:</td>
|
||||
<td><input type="text" name="dbuser" id="dbuser" value="" class="input"></td>
|
||||
<td><div id="J_install_tip_dbuser"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">数据库密码:</td>
|
||||
<td><input type="text" name="dbpw" id="dbpw" value="" class="input" autoComplete="off"></td>
|
||||
<td><div id="J_install_tip_dbpw"></div></td>
|
||||
</tr>
|
||||
<?php }?>
|
||||
<? if(INSTALLTYPE == 'HOST' || INSTALLTYPE == 'BAE'){ ?>
|
||||
<tr>
|
||||
<td class="tar">数据库名:</td>
|
||||
<td><input type="text" name="dbname" id="dbname" value="<?php echo $config['dbName'] ?>" class="input"></td>
|
||||
<td><div id="J_install_tip_dbname"></div></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
<tr>
|
||||
<td class="tar">数据库表前缀:</td>
|
||||
<td><input type="text" name="dbprefix" id="dbprefix" value="<?php echo $config['dbPrefix'] ?>" class="input"></td>
|
||||
<td><div id="J_install_tip_dbprefix"><span class="gray">建议使用默认</span></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">测试数据库连接:</td>
|
||||
<td><button type="button" class="btn" onclick="TestDbPwd()">测试连接</button></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="td1" width="100">网站信息</td>
|
||||
<td class="td1" width="200"> </td>
|
||||
<td class="td1"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">网站名称:</td>
|
||||
<td><input type="text" name="sitename" value="<?php echo $config['siteName'] ?>" class="input"></td>
|
||||
<td><div id="J_install_tip_sitename"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">管理员帐号:</td>
|
||||
<td><input type="text" name="manager" value="" class="input"></td>
|
||||
<td><div id="J_install_tip_manager"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">密码:</td>
|
||||
<td><input type="text" name="manager_pwd" id="J_manager_pwd" class="input" autoComplete="off"></td>
|
||||
<td><div id="J_install_tip_manager_pwd"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tar">重复密码:</td>
|
||||
<td><input type="text" name="manager_ckpwd" class="input" autoComplete="off"></td>
|
||||
<td><div id="J_install_tip_manager_ckpwd"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="J_response_tips" style="display:none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<a href="./index.php?step=2" class="btn">上一步</a>
|
||||
<button type="submit" class="btn btn_submit J_install_btn">创建数据</button>
|
||||
</div>
|
||||
</form>
|
||||
<script src="./templates/js/jquery.js"></script>
|
||||
<script src="./templates/js/validate.js"></script>
|
||||
<script>
|
||||
function TestDbPwd(){
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType:'json',
|
||||
url: "./index.php?step=3&testdbpwd=1",
|
||||
data: {'dbhost':$('#dbhost').val(),'dbuser':$('#dbuser').val(),'dbpw':$('#dbpw').val(),'dbname':$('#dbname').val(),'dbport':$('#dbport').val()},
|
||||
success: function(data){
|
||||
if(data.status != 1){
|
||||
$('#'+ data.type).focus();
|
||||
}
|
||||
alert(data.info);
|
||||
},
|
||||
error:function(){
|
||||
alert('数据库链接配置失败');
|
||||
$('#dbpw').focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
$(function(){
|
||||
//聚焦时默认提示
|
||||
var focus_tips = {
|
||||
dbhost : '数据库服务器地址,一般为localhost',
|
||||
dbport : '数据库服务器端口,一般为3306',
|
||||
dbuser : '请输入数据库用户名',
|
||||
dbpw : '请输入数据库密码',
|
||||
dbname : '请输入数据库名',
|
||||
dbprefix : '建议使用默认,同一数据库安装多个时需修改',
|
||||
manager : '创始人帐号,拥有站点后台所有管理权限',
|
||||
manager_pwd : '请输入管理员密码',
|
||||
manager_ckpwd : '请再次输入管理员密码',
|
||||
sitename : '请再次输入网站名称',
|
||||
sitekeywords : '',
|
||||
siteinfo : '',
|
||||
manager_email : ''
|
||||
};
|
||||
|
||||
|
||||
var install_form = $("#J_install_form"),
|
||||
response_tips = $('#J_response_tips'); //后端返回提示
|
||||
|
||||
install_form.validate({
|
||||
//debug : true,
|
||||
//onsubmit : false,
|
||||
errorPlacement: function(error, element) {
|
||||
//错误提示容器
|
||||
$('#J_install_tip_'+ element[0].name).html(error);
|
||||
},
|
||||
errorElement: 'span',
|
||||
errorClass : 'tips_error',
|
||||
validClass : 'tips_error',
|
||||
onkeyup : false,
|
||||
focusInvalid : false,
|
||||
rules: {
|
||||
dbhost: {
|
||||
required : true
|
||||
},
|
||||
dbport:{
|
||||
required : true
|
||||
},
|
||||
dbuser: {
|
||||
required : true
|
||||
},
|
||||
dbname: {
|
||||
required : true
|
||||
},
|
||||
dbprefix : {
|
||||
required : true
|
||||
},
|
||||
manager: {
|
||||
required : true
|
||||
},
|
||||
manager_pwd: {
|
||||
required : true,
|
||||
minlength : 6
|
||||
},
|
||||
sitename: {
|
||||
required : true,
|
||||
},
|
||||
manager_ckpwd: {
|
||||
required : true,
|
||||
equalTo : '#J_manager_pwd'
|
||||
},
|
||||
manager_email: {
|
||||
required : true,
|
||||
email : true
|
||||
}
|
||||
},
|
||||
highlight : false,
|
||||
unhighlight : function(element, errorClass, validClass) {
|
||||
var tip_elem = $('#J_install_tip_'+ element.name);
|
||||
|
||||
tip_elem.html('<span class="'+ validClass +'" data-text="text"><span>');
|
||||
|
||||
},
|
||||
onfocusin : function(element){
|
||||
var name = element.name;
|
||||
$('#J_install_tip_'+ name).html('<span data-text="text">'+ focus_tips[name] +'</span>');
|
||||
$(element).parents('tr').addClass('current');
|
||||
},
|
||||
onfocusout : function(element){
|
||||
var _this = this;
|
||||
$(element).parents('tr').removeClass('current');
|
||||
|
||||
if(element.name === 'email') {
|
||||
//邮箱匹配点击后,延时处理
|
||||
setTimeout(function(){
|
||||
_this.element(element);
|
||||
}, 150);
|
||||
}else{
|
||||
|
||||
_this.element(element);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
messages: {
|
||||
dbhost: {
|
||||
required : '数据库服务器地址不能为空'
|
||||
},
|
||||
dbport:{
|
||||
required : '数据库服务器端口不能为空'
|
||||
},
|
||||
dbuser: {
|
||||
required : '数据库用户名不能为空'
|
||||
},
|
||||
dbname: {
|
||||
required : '数据库名不能为空'
|
||||
},
|
||||
dbprefix : {
|
||||
required : '数据库表前缀不能为空'
|
||||
},
|
||||
sitename : {
|
||||
required : '请再次输入网站名称'
|
||||
},
|
||||
manager: {
|
||||
required : '管理员帐号不能为空'
|
||||
},
|
||||
manager_pwd: {
|
||||
required : '密码不能为空',
|
||||
minlength : '密码至少6位'
|
||||
},
|
||||
manager_ckpwd: {
|
||||
required : '请再次输入管理员密码',
|
||||
equalTo : '两次输入的密码不一致。请重新输入'
|
||||
},
|
||||
manager_email: {
|
||||
required : 'Email不能为空',
|
||||
email : '请输入正确的电子邮箱地址'
|
||||
}
|
||||
},
|
||||
submitHandler:function(form) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType:'json',
|
||||
url: "./index.php?step=3&testdbpwd=1",
|
||||
data: {'dbhost':$('#dbhost').val(),'dbuser':$('#dbuser').val(),'dbpw':$('#dbpw').val(),'dbname':$('#dbname').val(),'dbport':$('#dbport').val()},
|
||||
success: function(data){
|
||||
if(data.status != 1){
|
||||
alert(data.info);
|
||||
$('#'+ data.type).focus();
|
||||
return;
|
||||
}
|
||||
form.submit();
|
||||
return true;
|
||||
},
|
||||
error:function(){
|
||||
alert('数据库链接配置失败');
|
||||
$('#dbpw').focus();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php require './templates/footer.php';?>
|
||||
48
public/install/templates/4.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php require './templates/header.php';?>
|
||||
<div class="section">
|
||||
<div class="main install">
|
||||
<ul id="loginner"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<a href="javascript:;" class="btn_old" id="installloading">
|
||||
<img src="templates/images/loading.gif" align="absmiddle"> 正在安装...
|
||||
</a>
|
||||
</div>
|
||||
<script src="./templates/js/jquery.js"></script>
|
||||
<script type="text/javascript">
|
||||
var n=0;
|
||||
var data = <?php echo json_encode($_POST);?>;
|
||||
$.ajaxSetup ({ cache: false });
|
||||
function reloads(n) {
|
||||
var url = "./index.php?step=4&install=1&n="+n;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: function(data){
|
||||
$('#loginner').append(data.info);
|
||||
if(data.status == 1){
|
||||
reloads(data.type);
|
||||
}
|
||||
if(data.status == 0){
|
||||
$('#installloading').removeClass('btn_old').addClass('btn').html('继续安装').unbind('click').click(function(){
|
||||
reloads(0);
|
||||
});
|
||||
alert('安装已停止!');
|
||||
}
|
||||
if(data.status == 2){
|
||||
$('#installloading').removeClass('btn_old').addClass('btn').attr('href','./index.php?step=5').html('安装完成');
|
||||
setTimeout(function(){
|
||||
window.location.href='./index.php?step=5';
|
||||
},5000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
$(function(){
|
||||
reloads(n);
|
||||
})
|
||||
</script>
|
||||
<?php require './templates/footer.php';?>
|
||||
20
public/install/templates/5.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php require './templates/header.php';?>
|
||||
<div class="section">
|
||||
<div class="main">
|
||||
<div class="success_tip cc">
|
||||
<a href="../qfadmin">安装完成,进入后台管理</a>
|
||||
<?php if(INSTALLTYPE == 'HOST'){ ?>
|
||||
<p><?php echo $config['alreadyInstallInfo']?><p>
|
||||
<?php } else if(INSTALLTYPE == 'SAE'){ ?>
|
||||
<p><?php echo $config['alreadySaeInstallInfo']?><p>
|
||||
<?php } else if(INSTALLTYPE == 'BAE'){ ?>
|
||||
<p><?php echo $config['alreadyBaeInstallInfo']?><p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<a href="../index" class="btn">进入前台</a>
|
||||
<a href="../qfadmin" class="btn">进入后台</a>
|
||||
</div>
|
||||
<?php require './templates/footer.php';?>
|
||||
219
public/install/templates/css/install.css
Normal file
@@ -0,0 +1,219 @@
|
||||
/* 初始化 */
|
||||
html{-webkit-text-size-adjust:none;overflow-y:scroll;}
|
||||
body,input,button,select,textarea{font:12px/1.5 Microsoft YaHei,Tahoma,Helvetica,'SimSun',sans-serif;color:#444;}
|
||||
html,body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,th,td{margin:0;padding:0;border:none}
|
||||
body{background:url(../images/bg.png);}
|
||||
td,th,div {word-break:break-all;word-wrap:break-word;}
|
||||
address,cite,dfn,em,var{font-style:normal;font-weight:normal}
|
||||
table{empty-cells:show;border-spacing:0;}
|
||||
ul,ol,li{list-style:none}
|
||||
ul li,ol li{list-style:none;}
|
||||
img{border:none;}
|
||||
label{cursor:pointer;}
|
||||
a{text-decoration:none;}
|
||||
a:hover{text-decoration:underline;}
|
||||
button,input,select,textarea{font-size:100%;}
|
||||
hr{display:block;clear:both;*margin-top:-8px !important;*margin-bottom:-8px !important;}
|
||||
/* input select textarea */
|
||||
input[type="checkbox"]{vertical-align:middle; margin-top:0;}
|
||||
input,textarea{padding:6px;border-radius: 4px;font-size: 100%;line-height: 16px\9;*line-height: 18px;*vertical-align: -2px;background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s;margin-right: 3px;}
|
||||
textarea{resize:none;min-height:60px;line-height: 15px;}
|
||||
textarea:focus,input:focus,select:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6)}
|
||||
select{height: 30px;line-height: 30px;background-color: #fff;border: 1px solid #ccc;display: inline-block;padding: 6px;color: #555;margin-top: -2px;padding-top: 4px;*margin-top: -8px;vertical-align: middle;-webkit-border-radius: 4px;-moz-border-radius: 4px;border-radius: 4px;font-size: 100%;}
|
||||
|
||||
/* 基础样式 */
|
||||
.clearfix {_zoom: 1;}
|
||||
.clearfix:after {content: ".";display: block;visibility: hidden;clear: both;height: 0px;}
|
||||
|
||||
.wrap{margin:90px auto 0;box-shadow:0 0 20px #3F3F3F;width:980px;background-color:#fff;border-radius: 6px;overflow: hidden;}
|
||||
/* 头部样式 */
|
||||
.header{height:80px;padding: 0 5px;box-shadow:0 3px 3px #ddd;position:relative;color:#fff;background:#133ab3;}
|
||||
.header-title{float:left;font-size: 40px;line-height: 80px;}
|
||||
.header-install{float: left;margin-top: 26px;font-size: 20px; padding-left: 20px;}
|
||||
.header-version{float: right;margin-top: 50px;}
|
||||
|
||||
/* 步骤 */
|
||||
.step{border-bottom:1px solid #dce1e5;height:60px;}
|
||||
.step li{float:left;height:59px;line-height:60px;width:20%;text-align:center;font-size:14px;color:#6f7885;font-weight:700;}
|
||||
.step li em{width:32px;height:32px;text-align:center;line-height:32px;display:inline-block;background:#999999;border-radius: 50%;font-size:20px;color:#fff;font-family:Microsoft Yahei;margin-right:10px;vertical-align:-1px}
|
||||
.step li.current{background-position:right -106px;background-repeat:no-repeat;color:#246ea5;}
|
||||
.step li.current em{background:#133ab3}
|
||||
.step li.on{background-position:0 -176px;}
|
||||
.step li.on em{background-position:-70px -70px;}
|
||||
|
||||
.pact {box-shadow: 5px 5px 5px #f7f7f7 inset;height: 350px;padding: 20px 20px; white-space: pre-wrap; overflow: hidden;display: block;overflow-y: scroll;margin: 0 auto;font-size: 12px;line-height: 1.5;outline: none;}
|
||||
/* 服务器检测/信息输入 */
|
||||
.server{padding:20px 20px 0 65px;}
|
||||
.server table{margin-bottom:20px;}
|
||||
.server td{padding:3px 5px;}
|
||||
.server .td1{color:#417b9d;font-weight:700;}
|
||||
.server .input{border:1px solid;border-color:#e3e9ef;padding:3px;width:200px;}
|
||||
.server .input:hover,
|
||||
.server .input:focus{border:1px solid #0e85d5;outline:none;}
|
||||
.gray{color:#bbb;}
|
||||
.server tr:hover .gray{color:#333;}
|
||||
|
||||
/* 正确错误 */
|
||||
.correct_span,
|
||||
.error_span{display:block;float:left;width:20px;height:16px;text-indent:-2000em;margin-top: 2px;overflow:hidden;background:url(../images/icon.png) no-repeat;margin-right:5px;}
|
||||
.error_span{background-position:0 -23px;}
|
||||
/* 成功提示 */
|
||||
.success_tip{background:#fff url(../images/complete.png) 210px center no-repeat;font-size: 14px;padding:50px 80px 50px 300px;line-height:2;}
|
||||
.success_tip a{color:#0166a5;text-decoration:none;font-size: 20px;font-weight: 700;}
|
||||
.success_tip a:hover{text-decoration:underline;}
|
||||
|
||||
/*
|
||||
===================
|
||||
操作提示
|
||||
>> tips 普通
|
||||
>> tips_error 错误
|
||||
>> tips_success 正确
|
||||
>> tips_loading 加载中
|
||||
使用方法
|
||||
可独立样式使用,亦可与tips组装,例:
|
||||
<div class="tips"><span class="tips_error">错误内容</span></div>
|
||||
|
||||
可在外出包裹 tips_block 对错误提示进行块级效果展示
|
||||
===================
|
||||
*/
|
||||
.tips,.tips_block span{line-height:25px;padding:0 6px;}
|
||||
.tips{border:1px solid #faebd2;background:#ffffe9;color:#666;}
|
||||
.tips_error,.tips_success{color:#cc3333;padding-left:16px;background:url(../images/tips_system.png) -20px 2px no-repeat;display:inline-block;line-height:18px;}
|
||||
.tips_success{color:#008800;background-position:0 -19px;}
|
||||
.tips_loading{color:#cc3333;color:#333333;display:inline-block;line-height:20px;}
|
||||
/* 数据表写入 */
|
||||
.install{ box-shadow:5px 5px 5px #f7f7f7 inset;border:1px solid #bdbcbc;width:900px;height:350px;padding:10px;overflow:hidden;display:block;overflow-y:scroll;margin:25px auto;font-size:12px;margin-bottom:22px;outline:none}
|
||||
.install ul{line-height:1.8;}
|
||||
/* loading */
|
||||
.loading{border-radius: 16px;width: 100px;height: 30px;line-height: 30px;text-align: center;background:#000;background-color: rgba(0, 0, 0, 0.5);color: white;position: fixed;_position:absolute;left: 50%;margin-left: -50px;top: 50%;margin-top:-15px;}
|
||||
.loading span{background:url(../images/pop_loading.gif) 0 center no-repeat;padding-left:24px;}
|
||||
/* 按钮 */
|
||||
.btn-box{padding: 10px;text-align: center;border-top: 1px solid #ccc;}
|
||||
.btn,.btn_old{display:inline-block;width:100px;height:30px;background:#133ab3;font:bold 14px/30px Arial,"Microsoft Yahei",Simsun;text-decoration:none;color:#fff;margin:0 5px;border:0 none;cursor:pointer;vertical-align:top;}
|
||||
.btn:hover{background-position:0 -30px;text-decoration:none;}
|
||||
.btn.error{background-position: 0 -60px;color: #DF0000;}
|
||||
.btn_old,.btn_old:hover{background-position:0 -60px;color:#999 !important;cursor:default;text-decoration:none;}
|
||||
/* 底部 */
|
||||
.footer{text-align:center;padding:15px 0 50px;color:#999999;}
|
||||
.footer a{color:#999;text-decoration:none;}
|
||||
|
||||
body {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
margin: 50px auto 0;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
|
||||
width: 1000px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 90px;
|
||||
padding: 0 30px;
|
||||
box-shadow: 0 2px 10px rgba(19, 58, 179, 0.1);
|
||||
position: relative;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #133ab3, #1e56ff);
|
||||
}
|
||||
|
||||
.header-title {
|
||||
float: left;
|
||||
font-size: 42px;
|
||||
line-height: 90px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.header-install {
|
||||
float: left;
|
||||
margin-top: 30px;
|
||||
font-size: 22px;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.step {
|
||||
border-bottom: 1px solid #eef0f5;
|
||||
height: 70px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.step li {
|
||||
float: left;
|
||||
height: 69px;
|
||||
line-height: 70px;
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
color: #6f7885;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.step li em {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
display: inline-block;
|
||||
background: #e0e6ed;
|
||||
border-radius: 50%;
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
margin-right: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.step li.current {
|
||||
color: #133ab3;
|
||||
}
|
||||
|
||||
.step li.current em {
|
||||
background: #133ab3;
|
||||
box-shadow: 0 2px 10px rgba(19, 58, 179, 0.2);
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
background: #133ab3;
|
||||
font: 600 15px/40px "Microsoft Yahei";
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
margin: 0 8px;
|
||||
border: 0 none;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #1e56ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 10px rgba(19, 58, 179, 0.2);
|
||||
}
|
||||
|
||||
/* 输入框样式优化 */
|
||||
input, textarea {
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
background-color: #fff;
|
||||
border: 1px solid #dce1e5;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
input:focus, textarea:focus {
|
||||
border-color: #133ab3;
|
||||
box-shadow: 0 0 0 2px rgba(19, 58, 179, 0.1);
|
||||
}
|
||||
|
||||
.btn.error{
|
||||
color: #999999;
|
||||
background: #eeeeee;
|
||||
}
|
||||
4
public/install/templates/footer.php
Normal file
@@ -0,0 +1,4 @@
|
||||
</div>
|
||||
<div class="footer"> <?php echo $config['footerInfo'];?> </div>
|
||||
</body>
|
||||
</html>
|
||||
18
public/install/templates/header.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title><?php echo $config['name'].' '.$config['version']; ?> - <?php echo $config['powered']; ?></title>
|
||||
<link rel="stylesheet" href="./templates/css/install.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="header">
|
||||
<div class="header-install"><?php echo $config['name']; ?>-安装向导</div>
|
||||
<div class="header-version">版本:<?php echo $config['version'];?></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<ul>
|
||||
<?php echo $step_html;?>
|
||||
</ul>
|
||||
</div>
|
||||
BIN
public/install/templates/images/bg.png
Normal file
|
After Width: | Height: | Size: 129 B |
BIN
public/install/templates/images/btn.png
Normal file
|
After Width: | Height: | Size: 666 B |
BIN
public/install/templates/images/complete.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
public/install/templates/images/header.png
Normal file
|
After Width: | Height: | Size: 460 B |
BIN
public/install/templates/images/icon.png
Normal file
|
After Width: | Height: | Size: 711 B |
BIN
public/install/templates/images/ignore.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
public/install/templates/images/loading.gif
Normal file
|
After Width: | Height: | Size: 875 B |
BIN
public/install/templates/images/pop_loading.gif
Normal file
|
After Width: | Height: | Size: 723 B |
BIN
public/install/templates/images/step.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/install/templates/images/tips_system.png
Normal file
|
After Width: | Height: | Size: 494 B |
2
public/install/templates/js/jquery.js
vendored
Normal file
1246
public/install/templates/js/validate.js
Normal file
@@ -1,8 +0,0 @@
|
||||
更新方式
|
||||
1、app文件夹整包上传覆盖
|
||||
2、替换 public\static\index\css\app.css和public\static\index\css\m.css
|
||||
3、执行sql语句
|
||||
INSERT INTO `qf_conf` VALUES (52, 'is_quan', '0', '全网搜', '', 0, 2, '关闭=>0\n开启=>1', 1, 1, 1, 1, 1729928547, 1729928547);
|
||||
|
||||
如何对接微信对话功能
|
||||
详情见 app\api\controller\Chatbot.php
|
||||