Skip to content

Commit 9c9ad92

Browse files
author
Taois
committed
feat: 添加php标准
1 parent 3066e1f commit 9c9ad92

21 files changed

+2822
-47
lines changed

spider/php/B站_DZ.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ public function detailContent($ids) {
205205
return ['list' => [$vod]];
206206
}
207207

208-
public function playContent($flag, $id, $vipFlags = []) {
208+
public function playerContent($flag, $id, $vipFlags = []) {
209209
if (strpos($id, '_') !== false) {
210210
list($avid, $cid) = explode('_', $id);
211211
} else {

spider/php/PHP写源(道长).pdf

352 KB
Binary file not shown.

spider/php/config.php

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
// ==================
99
// 1. 生成 sites
1010
// ==================
11+
// 动态获取服务器地址
12+
$isHttps = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] === 'on' || $_SERVER['HTTPS'] == 1))
13+
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
14+
$scheme = $isHttps ? 'https://' : 'http://';
15+
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_ADDR'] ?? '127.0.0.1';
16+
17+
// 处理路径(适配子目录部署)
18+
$path = dirname($_SERVER['SCRIPT_NAME']);
19+
if ($path === '/' || $path === '\\') {
20+
$path = '';
21+
}
22+
$path = str_replace('\\', '/', $path); // 统一转为 /
23+
24+
$baseUrl = $scheme . $host . $path;
25+
1126
$dir = __DIR__;
1227
$self = basename(__FILE__);
1328
$files = scandir($dir);
@@ -29,17 +44,30 @@
2944
"key" => "php_" . $filename,
3045
"name" => $filename . "(PHP)",
3146
"type" => 4,
32-
"api" => "http://127.0.0.1:9980/" . $filename . ".php",
47+
"api" => $baseUrl . "/" . $filename . ".php",
3348
"searchable" => 1,
3449
"quickSearch" => 1,
3550
"changeable" => 0
3651
];
3752
}
3853

3954
// ==================
40-
// 2. 尝试加载 ../drpy-node/index.json
55+
// 2. 尝试加载 index.json (同级) 或 ../drpy-node/index.json 或 ../../drpy-node/index.json
4156
// ==================
42-
$indexJsonPath = realpath($dir . '/../drpy-node/index.json');
57+
$possiblePaths = [
58+
$dir . '/index.json',
59+
$dir . '/../drpy-node/index.json',
60+
$dir . '/../../drpy-node/index.json'
61+
];
62+
63+
$indexJsonPath = false;
64+
foreach ($possiblePaths as $path) {
65+
$realPath = realpath($path);
66+
if ($realPath && is_file($realPath)) {
67+
$indexJsonPath = $realPath;
68+
break;
69+
}
70+
}
4371

4472
if ($indexJsonPath && is_file($indexJsonPath)) {
4573
$content = file_get_contents($indexJsonPath);
@@ -52,7 +80,7 @@
5280

5381
echo json_encode(
5482
$json,
55-
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
83+
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
5684
);
5785
exit;
5886
}
@@ -63,5 +91,6 @@
6391
// ==================
6492
echo json_encode(
6593
["sites" => $sites],
66-
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
94+
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
6795
);
96+

spider/php/index.json

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
{
2+
"parses": [
3+
{
4+
"name": "J1",
5+
"url": "https://kalbim.xatut.top/kalbim2025/781718/play/video_player.php?url=",
6+
"type": 1,
7+
"header": {
8+
"User-Agent": "Mozilla/5.0"
9+
}
10+
},
11+
{
12+
"name": "J2",
13+
"url": "http://sspa8.top:8100/api/?key=1060089351&url=",
14+
"type": 1,
15+
"header": {
16+
"User-Agent": "Mozilla/5.0"
17+
}
18+
},
19+
{
20+
"name": "J芒果4k",
21+
"url": "http://mg.itufm.top/mg.php?url=",
22+
"type": 1,
23+
"header": {
24+
"User-Agent": "Mozilla/5.0"
25+
}
26+
},
27+
{
28+
"name": "W花旗",
29+
"url": "https://www.huaqi.live/?url=",
30+
"type": 0,
31+
"header": {
32+
"User-Agent": "Mozilla/5.0"
33+
}
34+
},
35+
{
36+
"name": "W冰豆",
37+
"url": "https://bd.jx.cn/?url=",
38+
"type": 0,
39+
"header": {
40+
"User-Agent": "Mozilla/5.0"
41+
}
42+
},
43+
{
44+
"name": "W盘古",
45+
"url": "https://www.playm3u8.cn/jiexi.php?url=",
46+
"type": 0,
47+
"header": {
48+
"User-Agent": "Mozilla/5.0"
49+
}
50+
},
51+
{
52+
"name": "W1",
53+
"url": "https://jx.xymp4.cc/?url=",
54+
"type": 0,
55+
"header": {
56+
"User-Agent": "Mozilla/5.0"
57+
}
58+
},
59+
{
60+
"name": "W3",
61+
"url": "https://yparse.ik9.cc/index.php?url=",
62+
"type": 0,
63+
"header": {
64+
"User-Agent": "Mozilla/5.0"
65+
}
66+
},
67+
{
68+
"name": "W4",
69+
"url": "https://jiexi.site/?url=",
70+
"type": 0,
71+
"header": {
72+
"User-Agent": "Mozilla/5.0"
73+
}
74+
},
75+
{
76+
"name": "W5",
77+
"url": "https://jx.m3u8.tv/jiexi/?url=",
78+
"type": 0,
79+
"header": {
80+
"User-Agent": "Mozilla/5.0"
81+
}
82+
},
83+
{
84+
"name": "W7",
85+
"url": "https://www.pangujiexi.com/jiexi/?url=",
86+
"type": 0,
87+
"header": {
88+
"User-Agent": "Mozilla/5.0"
89+
}
90+
},
91+
{
92+
"name": "W8",
93+
"url": "https://www.pouyun.com/?url=",
94+
"type": 0,
95+
"header": {
96+
"User-Agent": "Mozilla/5.0"
97+
}
98+
},
99+
{
100+
"name": "W9",
101+
"url": "https://jx.xmflv.com/?url=",
102+
"type": 0,
103+
"header": {
104+
"User-Agent": "Mozilla/5.0"
105+
}
106+
},
107+
{
108+
"name": "Wa",
109+
"url": "https://jx.xmflv.cc/?url=",
110+
"type": 0,
111+
"header": {
112+
"User-Agent": "Mozilla/5.0"
113+
}
114+
},
115+
{
116+
"name": "Wb",
117+
"url": "https://jx.yparse.com/index.php?url=",
118+
"type": 0,
119+
"header": {
120+
"User-Agent": "Mozilla/5.0"
121+
}
122+
},
123+
{
124+
"name": "Wc",
125+
"url": "https://www.8090g.cn/?url=",
126+
"type": 0,
127+
"header": {
128+
"User-Agent": "Mozilla/5.0"
129+
}
130+
},
131+
{
132+
"name": "Wz",
133+
"url": "https://www.ckplayer.vip/jiexi/?url=",
134+
"type": 0,
135+
"header": {
136+
"User-Agent": "Mozilla/5.0"
137+
}
138+
}
139+
],
140+
"lives": []
141+
}

spider/php/readme.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# PHP Spider 开发与维护指南 (DZ 风格)
2+
3+
本文档总结了基于 `spider.php` 框架开发、调试、转换 PHP 爬虫源的核心经验与最佳实践。旨在帮助开发者快速上手,并作为后续开发的参考手册。
4+
5+
## 1. 核心架构与工具
6+
7+
### 1.1 基础框架 (`spider.php`)
8+
所有源必须包含 `spider.php` 并继承 `BaseSpider` 类(通常在源文件中定义为 `class Spider extends BaseSpider`)。
9+
核心方法包括:
10+
- `init()`: 初始化(可选)。
11+
- `homeContent($filter)`: 获取首页分类与筛选配置。
12+
- `categoryContent($tid, $pg, $filter, $extend)`: 获取分类列表数据。
13+
- `detailContent($ids)`: 获取视频详情与播放列表。
14+
- `searchContent($key, $quick, $pg)`: 搜索视频。
15+
- `playerContent($flag, $id, $vipFlags)`: 解析真实播放链接。
16+
17+
### 1.2 测试工具 (`test_runner.php`)
18+
用于本地验证源的接口功能。
19+
**用法**: `php test_runner.php [源文件路径]`
20+
**测试流程**:
21+
1. **首页测试**: 检查分类是否获取成功,筛选条件是否解析。
22+
2. **分类测试**: 选取第一个分类,获取第一页数据,检查 `vod_id``vod_name`
23+
3. **详情测试**: 使用分类接口返回的 `vod_id`,检查详情信息及播放列表解析。
24+
4. **搜索测试**: 使用分类接口获取的名称进行搜索验证。
25+
5. **播放测试**: 选取第一个播放源,尝试解析播放链接。
26+
27+
---
28+
29+
## 2. 开发最佳实践
30+
31+
### 2.1 分页标准化 (`$this->pageResult`)
32+
不要手动拼接复杂的 JSON 返回结构。使用框架内置的辅助方法 `$this->pageResult`
33+
34+
**推荐写法**:
35+
```php
36+
$videos = [];
37+
foreach ($items as $item) {
38+
$videos[] = [
39+
'vod_id' => $item['id'],
40+
'vod_name' => $item['name'],
41+
'vod_pic' => $item['pic'],
42+
'vod_remarks' => $item['remarks']
43+
];
44+
}
45+
return $this->pageResult($videos, $page, $total, $pageSize);
46+
```
47+
48+
### 2.2 数据传递技巧 (`vod_id` 组合)
49+
有时 `categoryContent``detailContent` 需要传递额外参数(如 `typeId`),但 `vod_id` 只能是字符串。
50+
**技巧**: 使用分隔符组合参数。
51+
```php
52+
// 在 categoryContent 中
53+
'vod_id' => $id . '*' . $typeId
54+
55+
// 在 detailContent 中
56+
$parts = explode('*', $ids[0]);
57+
$id = $parts[0];
58+
$typeId = $parts[1] ?? '';
59+
```
60+
61+
### 2.3 HTML 解析 (DOMDocument)
62+
处理 HTML 页面时,推荐使用 `DOMDocument` + `DOMXPath`,比正则更稳定。
63+
**IDE 爆红修复**:
64+
IDE 经常提示 `getAttribute` 方法不存在,因为 DOMNode 不一定是 Element。
65+
**正确写法**:
66+
```php
67+
$node = $xpath->query('//img')->item(0);
68+
if ($node instanceof DOMElement) { // 加上类型检查
69+
$pic = $node->getAttribute('src');
70+
}
71+
```
72+
73+
### 2.4 加密与解密 (JS -> PHP 转换)
74+
遇到 JS 源使用了加密(如 RSA, AES),需要用 PHP 的 `openssl` 扩展对应实现。
75+
76+
**案例:RSA 分块解密 (参考 `LingDu_DZ.php`)**
77+
PHP 的 `openssl_private_decrypt` 有长度限制(通常 117 或 128 字节)。如果密文过长,必须**分块解密**
78+
79+
```php
80+
private function rsaDecrypt($data) {
81+
$decoded = base64_decode($data);
82+
$keyRes = openssl_pkey_get_private($this->privateKey);
83+
$details = openssl_pkey_get_details($keyRes);
84+
$keySize = ceil($details['bits'] / 8); // e.g., 128 bytes
85+
86+
$result = '';
87+
$chunks = str_split($decoded, $keySize); // 按密钥长度分块
88+
89+
foreach ($chunks as $chunk) {
90+
if (openssl_private_decrypt($chunk, $decrypted, $this->privateKey, OPENSSL_PKCS1_PADDING)) {
91+
$result .= $decrypted;
92+
}
93+
}
94+
return $result;
95+
}
96+
```
97+
98+
### 2.5 播放链接解析 (二次解析)
99+
有些源的播放链接不是直接的 mp4/m3u8,需要再次请求 API。
100+
`playerContent` 中:
101+
1. 解析传入的 `$id` (可能是 JSON 字符串)。
102+
2. 请求解密接口获取初步 URL。
103+
3. 如果需要,进行二次请求(如 `analysisMovieUrl`)获取最终直链。
104+
105+
---
106+
107+
## 3. JS 源转 PHP 流程
108+
109+
1. **分析 JS 逻辑**:
110+
- 寻找网络请求部分 (`req`, `request`, `fetch`)。
111+
- 分析 Headers 构造(特别是 `token`, `deviceId`, `sign` 等字段)。
112+
- 识别加密算法(搜索 `RSA`, `AES`, `MD5`, `Base64`)。
113+
114+
2. **PHP 实现**:
115+
- **Headers**: 复制 User-Agent 等固定头,动态生成 Token。
116+
- **Crypto**: 将 JS 的 crypto-js 逻辑映射到 PHP `openssl_*``hash_*` 函数。
117+
- **Random**: JS `Math.random()` -> PHP `mt_rand() / mt_getrandmax()`.
118+
119+
3. **接口映射**:
120+
- JS `home()` -> PHP `homeContent()`
121+
- JS `category()` -> PHP `categoryContent()`
122+
- JS `detail()` -> PHP `detailContent()`
123+
- JS `play()` -> PHP `playerContent()`
124+
- JS `search()` -> PHP `searchContent()`
125+
126+
---
127+
128+
## 4. 调试常见问题
129+
130+
| 问题现象 | 可能原因 | 解决方案 |
131+
| :--- | :--- | :--- |
132+
| `test_runner` 报错 "Class 'Spider' not found" | 文件名命名问题或未定义类 | 检查类名是否为 `Spider`,文件名是否正确。 |
133+
| `vod_play_url` 为空 | 解密失败或解析逻辑错误 | 检查 RSA 密钥格式;检查是否需要分块解密;打印中间变量调试。 |
134+
| IDE 提示 `Call to undefined method` | DOM 操作未做类型检查 | 添加 `instanceof DOMElement` 判断。 |
135+
| 返回数据结构臃肿 | 手动构建了复杂的 JSON | 改用 `$this->pageResult` 简化代码。 |
136+
| 接口超时或 403 | Headers 缺失或 Token 过期 | 检查 `getHeaders()` 方法,确保 `deviceId`/`token` 生成逻辑正确。 |
137+
138+
---
139+
140+
## 5. 经验沉淀 (Core Memory)
141+
142+
- **腾腾.php**: 修复了 `DOMElement` 类型检查缺失导致的 IDE 报错。
143+
- **yjm 系列**: 将复杂的分类/搜索返回重构为 `$this->pageResult`
144+
- **零度影视 (LingDu_DZ)**:
145+
- 实现了完整的 JS -> PHP 转换。
146+
- **关键点**: `deviceId` 自动生成、RSA 大数据分块解密、播放链接二次解析。
147+
148+
---
149+
150+
*本文档由 Trae AI 生成,用于记录开发经验以供后续快速恢复上下文。*

0 commit comments

Comments
 (0)