Skip to content

Commit 8148c1a

Browse files
author
苏青安
committed
refactor(core): 适配改版后的微信账单解析,由CSV变更为Excel读取
BREAKING CHANGE: 需要额外安装 phpoffice/phpspreadsheet 以支持对 Excel 的解析
1 parent 6f969e1 commit 8148c1a

File tree

2 files changed

+36
-31
lines changed

2 files changed

+36
-31
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
}
1616
],
1717
"require": {
18-
"php": ">=8.1"
18+
"php": ">=8.1",
19+
"phpoffice/phpspreadsheet": "^4.5"
1920
}
2021
}

src/CsvExtractor.php

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Hejunjie\WechatBillParser;
44

5+
use PhpOffice\PhpSpreadsheet\IOFactory;
6+
57
class CsvExtractor
68
{
79

@@ -11,62 +13,64 @@ public function extract(string $zipPath, string $password): array
1113
if ($zip->open($zipPath) !== true) {
1214
throw new \RuntimeException("无法打开ZIP文件: $zipPath");
1315
}
14-
// 设置密码
1516
if (!$zip->setPassword($password)) {
1617
$zip->close();
1718
throw new \RuntimeException("ZIP密码设置失败");
1819
}
19-
// 获取第一个文件名(假设只有一个CSV文件)
2020
if ($zip->numFiles < 1) {
2121
$zip->close();
2222
throw new \RuntimeException("ZIP中无文件");
2323
}
24-
$filename = $zip->getNameIndex(1);
25-
// 临时目录
24+
$filename = null;
25+
for ($i = 0; $i < $zip->numFiles; $i++) {
26+
$name = $zip->getNameIndex($i);
27+
if (preg_match('/\.xlsx?$/i', $name)) {
28+
$filename = $name;
29+
break;
30+
}
31+
}
32+
if (!$filename) {
33+
$zip->close();
34+
throw new \RuntimeException("ZIP中没有找到 Excel 文件");
35+
}
2636
$tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'zip_extract_' . uniqid();
2737
if (!mkdir($tempDir, 0700) && !is_dir($tempDir)) {
2838
$zip->close();
2939
throw new \RuntimeException("创建临时目录失败: $tempDir");
3040
}
31-
// 解压第一个文件到临时目录
3241
if (!$zip->extractTo($tempDir, $filename)) {
3342
$zip->close();
3443
$this->deleteDir($tempDir);
3544
throw new \RuntimeException("解压失败");
3645
}
3746
$zip->close();
38-
$csvPath = $tempDir . DIRECTORY_SEPARATOR . $filename;
39-
if (!file_exists($csvPath)) {
47+
$excelPath = $tempDir . DIRECTORY_SEPARATOR . $filename;
48+
if (!file_exists($excelPath)) {
4049
$this->deleteDir($tempDir);
41-
throw new \RuntimeException("解压文件不存在: $csvPath");
50+
throw new \RuntimeException("解压文件不存在: $excelPath");
4251
}
43-
// 读取CSV内容到数组
52+
$spreadsheet = IOFactory::load($excelPath);
53+
$sheet = $spreadsheet->getActiveSheet();
4454
$rows = [];
45-
$real_name = '';
4655
$account = '';
47-
if (($handle = fopen($csvPath, 'r')) !== false) {
48-
$lineNumber = 0;
49-
while (($data = fgetcsv($handle)) !== false) {
50-
$lineNumber++;
51-
if ($lineNumber < 18) {
52-
switch ($lineNumber) {
53-
case 2:
54-
$account = $data[0];
55-
$account = str_replace('微信昵称:', '', $account);
56-
$account = str_replace('[', '', $account);
57-
$account = str_replace(']', '', $account);
58-
break;
59-
}
60-
continue;
56+
$real_name = '';
57+
$lineNumber = 0;
58+
foreach ($sheet->getRowIterator() as $row) {
59+
$lineNumber++;
60+
$cellIterator = $row->getCellIterator();
61+
$cellIterator->setIterateOnlyExistingCells(false);
62+
$data = [];
63+
foreach ($cellIterator as $cell) {
64+
$data[] = trim((string) $cell->getValue());
65+
}
66+
if ($lineNumber < 18) {
67+
if ($lineNumber === 2) {
68+
$account = str_replace(['微信昵称:', '[', ']'], '', $data[0]);
6169
}
62-
$rows[] = $data;
70+
continue;
6371
}
64-
fclose($handle);
65-
} else {
66-
$this->deleteDir($tempDir);
67-
throw new \RuntimeException("打开CSV文件失败");
72+
$rows[] = $data;
6873
}
69-
// 删除临时文件和目录
7074
$this->deleteDir($tempDir);
7175
return [
7276
'real_name' => $real_name,

0 commit comments

Comments
 (0)