PHP文件上传与Python统计工具集成

服务器繁忙,请稍后再试。

时间: 2025-04-08T22:37:33


👤 用户

帮我写一个PHP程序,弄一个输入框,用来提交统计表格文件,使用上面我提供的脚本未见生成一个统计结果,在弄一个输入框,用来为生成的统计结果.xlsx命名并提供下载。

时间: 2025-04-08T20:50:24


🤖 DeepSeek (deepseek-chat)

PHP 文件上传和统计处理程序

以下是一个完整的PHP程序,它允许用户上传Excel文件,使用你提供的Python脚本进行处理,并允许用户自定义输出文件名和下载结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<?php
// 设置错误报告以便调试
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 检查文件是否上传成功
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === UPLOAD_ERR_OK) {
// 检查文件扩展名
$file_name = $_FILES['excel_file']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));

if ($file_ext !== 'xls' && $file_ext !== 'xlsx') {
die("错误:请上传Excel文件(.xls或.xlsx)");
}

// 获取用户指定的输出文件名
$output_name = isset($_POST['output_name']) ? trim($_POST['output_name']) : '统计结果';
if (empty($output_name)) {
$output_name = '统计结果';
}

// 确保输出文件名是有效的
$output_name = preg_replace('/[^a-zA-Z0-9_\x{4e00}-\x{9fa5}]/u', '', $output_name);
$output_file = $output_name . '.xlsx';

// 临时文件路径
$temp_file = $_FILES['excel_file']['tmp_name'];
$target_file = '1.xls'; // Python脚本期望的文件名

// 移动上传的文件
if (!move_uploaded_file($temp_file, $target_file)) {
die("错误:无法移动上传的文件");
}

// 执行Python脚本
$python_script = 'tongji.py';
$command = "python3 " . escapeshellarg($python_script) . " 2>&1";
$output = shell_exec($command);

// 检查Python脚本是否执行成功
if (!file_exists('统计结果.xlsx')) {
echo "<h3>处理失败</h3>";
echo "<pre>Python脚本输出:\n" . htmlspecialchars($output) . "</pre>";
echo "<a href=''>返回</a>";
exit;
}

// 重命名输出文件
if ($output_file !== '统计结果.xlsx') {
if (!rename('统计结果.xlsx', $output_file)) {
$output_file = '统计结果.xlsx';
}
}

// 提供下载
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($output_file) . '"');
header('Content-Length: ' . filesize($output_file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
readfile($output_file);

// 清理临时文件
unlink($target_file);
unlink($output_file);

exit;
} else {
$error = "文件上传失败。错误代码: " . $_FILES['excel_file']['error'];
}
}
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>胃镜肠镜统计工具</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
}
h1 {
color: #333;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="file"], input[type="text"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
.error {
color: red;
margin-bottom: 15px;
}
.instructions {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #4CAF50;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>胃镜肠镜统计工具</h1>

<div class="instructions">
<h3>使用说明:</h3>
<ol>
<li>上传包含胃镜/肠镜数据的Excel文件</li>
<li>(可选)指定输出文件名(默认为"统计结果")</li>
<li>点击"处理并下载"按钮</li>
<li>系统将自动处理数据并下载统计结果</li>
</ol>
<p><strong>注意:</strong>上传的文件必须包含"导出数据"工作表,且包含"报告医师"、"病人来源"和"检查类别"列。</p>
</div>

<?php if (isset($error)): ?>
<div class="error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>

<form action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="excel_file">选择Excel文件 (.xls或.xlsx):</label>
<input type="file" name="excel_file" id="excel_file" accept=".xls,.xlsx" required>
</div>

<div class="form-group">
<label for="output_name">输出文件名 (不带扩展名):</label>
<input type="text" name="output_name" id="output_name" placeholder="统计结果">
</div>

<button type="submit">处理并下载</button>
</form>
</body>
</html>

使用说明

  1. 将上面的PHP代码保存为index.php文件
  2. 将你提供的Python脚本tongji.py放在同一目录下
  3. 确保服务器已安装Python 3和所需的Python库(pandas, openpyxl, xlrd)
  4. 确保PHP有权限执行Python脚本和读写文件

功能说明

  1. 文件上传:用户可以上传Excel文件(.xls或.xlsx)
  2. 输出文件名自定义:用户可以指定输出文件的名称(默认为”统计结果”)
  3. 处理流程
    • 上传的文件被重命名为1.xls(Python脚本期望的输入文件名)
    • 调用tongji.py脚本处理数据
    • 将生成的统计结果文件重命名为用户指定的名称
    • 提供下载并自动删除临时文件
  4. 错误处理:显示上传错误和Python脚本执行错误

安全注意事项

  1. 在生产环境中,你应该添加更多的安全检查
  2. 考虑限制上传文件的大小
  3. 可以添加用户认证以防止未经授权的访问

这个PHP程序提供了一个用户友好的界面来使用你的Python统计脚本,并增加了自定义输出文件名的功能。

时间: 2025-04-08T20:50:24


👤 用户

帮我把下面的代码也应用上面的风格

数据对比 if ($_SERVER['REQUEST_METHOD'] == 'POST') { ini_set('upload_max_filesize', '20M'); ini_set('post_max_size', '20M'); $error = ''; // 验证输出文件名 if (empty($_POST['output_filename'])) { $error = "请输入输出文件名"; } elseif (!preg_match('/^[a-zA-Z0-9_\-\x{4e00}-\x{9fa5}]+$/u', $_POST['output_filename'])) { $error = "文件名只能包含中文、字母、数字、下划线和连字符"; } else { $outputFile = trim($_POST['output_filename']) . '.xlsx'; if (isset($_FILES['file1']) && isset($_FILES['file2'])) { $file1 = $_FILES['file1']['tmp_name']; $file2 = $_FILES['file2']['tmp_name']; if (is_uploaded_file($file1) && is_uploaded_file($file2)) { $command = escapeshellcmd("python3 data_processor.py \"$file1\" \"$file2\" \"$outputFile\""); $output = shell_exec($command . " 2>&1"); if (file_exists($outputFile)) { ob_end_clean(); // 清空输出缓冲区 header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="' . basename($outputFile) . '"'); header('Content-Length: ' . filesize($outputFile)); ob_clean(); // 再次清空输出缓冲区 readfile($outputFile); exit; } else { $error = "文件生成失败。<pre>Python 脚本输出: $output</pre>"; } } else { $error = "文件上传失败,请检查文件是否有效。"; } } else { $error = "请上传两个文件。"; } } } ?> <h1>上传文件</h1> <?php if (!empty($error)): ?> <div class="error"><?php echo $error; ?></div> <?php endif; ?> <form action="" method="post" enctype="multipart/form-data"> <label for="file1" class="required">上传文件 1(上月数据):</label> <input type="file" name="file1" required><br><br> <label for="file2" class="required">上传文件 2(本月份数据):</label> <input type="file" name="file2" required><br><br> <label for="output_filename" class="required">输出文件名(不含扩展名):</label> <input type="text" name="output_filename" required placeholder="请输入文件名" pattern="[a-zA-Z0-9_\-\u4e00-\u9fa5]+" title="只能包含中文、字母、数字、下划线和连字符"><br><br> <button type="submit">提交</button> </form>

时间: 2025-04-08T21:06:49


🤖 DeepSeek (deepseek-chat)

数据对比工具 - 美化版

以下是应用了之前风格的HTML/PHP代码,保持了相同的视觉风格和用户体验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据对比工具</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
}
h1 {
color: #333;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.required:after {
content: " *";
color: red;
}
input[type="file"], input[type="text"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
width: 100%;
}
button:hover {
background-color: #45a049;
}
.error {
color: red;
margin-bottom: 15px;
padding: 10px;
background-color: #ffeeee;
border: 1px solid #ffdddd;
border-radius: 4px;
}
.instructions {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #4CAF50;
margin-bottom: 20px;
}
.file-inputs {
background-color: #f5f5f5;
padding: 15px;
border-radius: 4px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<?php
// 开启输出缓冲区
ob_start();

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
ini_set('upload_max_filesize', '20M');
ini_set('post_max_size', '20M');

$error = '';

// 验证输出文件名
if (empty($_POST['output_filename'])) {
$error = "请输入输出文件名";
} elseif (!preg_match('/^[a-zA-Z0-9_\-\x{4e00}-\x{9fa5}]+$/u', $_POST['output_filename'])) {
$error = "文件名只能包含中文、字母、数字、下划线和连字符";
} else {
$outputFile = trim($_POST['output_filename']) . '.xlsx';
if (isset($_FILES['file1']) && isset($_FILES['file2'])) {
$file1 = $_FILES['file1']['tmp_name'];
$file2 = $_FILES['file2']['tmp_name'];

if (is_uploaded_file($file1) && is_uploaded_file($file2)) {
$command = escapeshellcmd("python3 data_processor.py \"$file1\" \"$file2\" \"$outputFile\"");
$output = shell_exec($command . " 2>&1");

if (file_exists($outputFile)) {
ob_end_clean(); // 清空输出缓冲区
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($outputFile) . '"');
header('Content-Length: ' . filesize($outputFile));
ob_clean(); // 再次清空输出缓冲区
readfile($outputFile);
exit;
} else {
$error = "文件生成失败。<pre>Python 脚本输出: $output</pre>";
}
} else {
$error = "文件上传失败,请检查文件是否有效。";
}
} else {
$error = "请上传两个文件。";
}
}
}
?>

<h1>数据对比工具</h1>

<div class="instructions">
<h3>使用说明:</h3>
<ol>
<li>上传上月数据文件(Excel格式)</li>
<li>上传本月数据文件(Excel格式)</li>
<li>指定输出文件名(默认为"对比结果")</li>
<li>点击"提交"按钮生成对比结果</li>
</ol>
<p><strong>注意:</strong>请确保上传的文件格式正确,且包含需要对比的数据。</p>
</div>

<?php if (!empty($error)): ?>
<div class="error"><?php echo $error; ?></div>
<?php endif; ?>

<form action="" method="post" enctype="multipart/form-data">
<div class="file-inputs">
<div class="form-group">
<label for="file1" class="required">上月数据文件:</label>
<input type="file" name="file1" id="file1" required accept=".xls,.xlsx">
</div>

<div class="form-group">
<label for="file2" class="required">本月数据文件:</label>
<input type="file" name="file2" id="file2" required accept=".xls,.xlsx">
</div>
</div>

<div class="form-group">
<label for="output_filename" class="required">输出文件名(不含扩展名):</label>
<input type="text" name="output_filename" id="output_filename" required
placeholder="对比结果"
pattern="[a-zA-Z0-9_\-\u4e00-\u9fa5]+"
title="只能包含中文、字母、数字、下划线和连字符">
</div>

<button type="submit">提交并下载结果</button>
</form>
</body>
</html>

主要改进点

  1. 整体风格统一:应用了与第一个工具相同的视觉风格,包括颜色、间距和字体
  2. 响应式设计:添加了viewport meta标签,确保在移动设备上也能良好显示
  3. 增强的表单布局
    • 文件输入区域增加了背景色区分
    • 输入框宽度设置为100%并添加了内边距
    • 按钮样式统一
  4. 更好的错误显示:错误信息现在有更明显的视觉提示
  5. 使用说明:添加了清晰的使用说明区域
  6. 用户体验改进
    • 更明确的标签和占位符文本
    • 文件输入添加了accept属性限制文件类型
    • 整体布局更加整洁和专业

这个版本保持了原有功能的同时,提供了更好的用户体验和视觉效果。

时间: 2025-04-08T21:06:49


👤 用户

能把上面两个PHP文件合并在一起吗?

时间: 2025-04-08T21:22:36


🤖 DeepSeek (deepseek-chat)

合并后的数据统计与对比工具

以下是将两个PHP文件合并后的完整代码,包含了胃镜肠镜统计和数据对比两个功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<?php
// 设置错误报告以便调试
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 处理文件上传和Python脚本执行
function process_uploaded_file($python_script, $input_files, $output_file) {
// 移动上传的文件
foreach ($input_files as $temp_name => $target_name) {
if (!move_uploaded_file($temp_name, $target_name)) {
return "错误:无法移动上传的文件";
}
}

// 执行Python脚本
$command = "python3 " . escapeshellarg($python_script);
foreach ($input_files as $target_name) {
$command .= " " . escapeshellarg($target_name);
}
$command .= " " . escapeshellarg($output_file) . " 2>&1";

$output = shell_exec($command);

// 检查Python脚本是否执行成功
if (!file_exists($output_file)) {
return "处理失败:<pre>" . htmlspecialchars($output) . "</pre>";
}

return null;
}

// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$error = '';

if ($action === 'endoscopy_stats') {
// 胃镜肠镜统计处理
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === UPLOAD_ERR_OK) {
// 检查文件扩展名
$file_name = $_FILES['excel_file']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));

if ($file_ext !== 'xls' && $file_ext !== 'xlsx') {
$error = "错误:请上传Excel文件(.xls或.xlsx)";
} else {
// 获取用户指定的输出文件名
$output_name = isset($_POST['output_name']) ? trim($_POST['output_name']) : '统计结果';
if (empty($output_name)) {
$output_name = '统计结果';
}

// 确保输出文件名是有效的
$output_name = preg_replace('/[^a-zA-Z0-9_\x{4e00}-\x{9fa5}]/u', '', $output_name);
$output_file = $output_name . '.xlsx';

// 处理文件
$error = process_uploaded_file(
'tongji.py',
[$_FILES['excel_file']['tmp_name'] => '1.xls'],
$output_file
);

if (!$error) {
// 提供下载
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($output_file) . '"');
header('Content-Length: ' . filesize($output_file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
readfile($output_file);

// 清理临时文件
unlink('1.xls');
unlink($output_file);
exit;
}
}
} else {
$error = "文件上传失败。错误代码: " . $_FILES['excel_file']['error'];
}
} elseif ($action === 'data_comparison') {
// 数据对比处理
ini_set('upload_max_filesize', '20M');
ini_set('post_max_size', '20M');

// 验证输出文件名
if (empty($_POST['output_filename'])) {
$error = "请输入输出文件名";
} elseif (!preg_match('/^[a-zA-Z0-9_\-\x{4e00}-\x{9fa5}]+$/u', $_POST['output_filename'])) {
$error = "文件名只能包含中文、字母、数字、下划线和连字符";
} else {
$output_file = trim($_POST['output_filename']) . '.xlsx';

if (isset($_FILES['file1']) && isset($_FILES['file2'])) {
$file1 = $_FILES['file1']['tmp_name'];
$file2 = $_FILES['file2']['tmp_name'];

if (is_uploaded_file($file1) && is_uploaded_file($file2)) {
$error = process_uploaded_file(
'data_processor.py',
[
$file1 => 'file1.xls',
$file2 => 'file2.xls'
],
$output_file
);

if (!$error) {
// 提供下载
ob_end_clean();
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($output_file) . '"');
header('Content-Length: ' . filesize($output_file));
ob_clean();
readfile($output_file);

// 清理临时文件
unlink('file1.xls');
unlink('file2.xls');
unlink($output_file);
exit;
}
} else {
$error = "文件上传失败,请检查文件是否有效。";
}
} else {
$error = "请上传两个文件。";
}
}
}
}
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据统计与对比工具</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
}
h1, h2 {
color: #333;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.required:after {
content: " *";
color: red;
}
input[type="file"], input[type="text"], select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
width: 100%;
}
button:hover {
background-color: #45a049;
}
.error {
color: red;
margin-bottom: 15px;
padding: 10px;
background-color: #ffeeee;
border: 1px solid #ffdddd;
border-radius: 4px;
}
.instructions {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #4CAF50;
margin-bottom: 20px;
}
.file-inputs {
background-color: #f5f5f5;
padding: 15px;
border-radius: 4px;
margin-bottom: 20px;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.tab-buttons {
display: flex;
margin-bottom: 20px;
}
.tab-button {
flex: 1;
padding: 10px;
text-align: center;
background-color: #ddd;
border: none;
cursor: pointer;
}
.tab-button.active {
background-color: #4CAF50;
color: white;
}
</style>
</head>
<body>
<h1>数据统计与对比工具</h1>

<div class="tab-buttons">
<button class="tab-button active" onclick="openTab('endoscopy')">胃镜肠镜统计</button>
<button class="tab-button" onclick="openTab('comparison')">数据对比</button>
</div>

<?php if (isset($error)): ?>
<div class="error"><?php echo $error; ?></div>
<?php endif; ?>

<!-- 胃镜肠镜统计表单 -->
<div id="endoscopy" class="tab-content active">
<form action="" method="post" enctype="multipart/form-data">
<input type="hidden" name="action" value="endoscopy_stats">

<div class="instructions">
<h3>胃镜肠镜统计使用说明:</h3>
<ol>
<li>上传包含胃镜/肠镜数据的Excel文件</li>
<li>(可选)指定输出文件名(默认为"统计结果")</li>
<li>点击"处理并下载"按钮</li>
<li>系统将自动处理数据并下载统计结果</li>
</ol>
<p><strong>注意:</strong>上传的文件必须包含"导出数据"工作表,且包含"报告医师"、"病人来源"和"检查类别"列。</p>
</div>

<div class="form-group">
<label for="excel_file" class="required">选择Excel文件 (.xls或.xlsx):</label>
<input type="file" name="excel_file" id="excel_file" accept=".xls,.xlsx" required>
</div>

<div class="form-group">
<label for="output_name">输出文件名 (不带扩展名):</label>
<input type="text" name="output_name" id="output_name" placeholder="统计结果">
</div>

<button type="submit">处理并下载</button>
</form>
</div>

<!-- 数据对比表单 -->
<div id="comparison" class="tab-content">
<form action="" method="post" enctype="multipart/form-data">
<input type="hidden" name="action" value="data_comparison">

<div class="instructions">
<h3>数据对比使用说明:</h3>
<ol>
<li>上传上月数据文件(Excel格式)</li>
<li>上传本月数据文件(Excel格式)</li>
<li>指定输出文件名(默认为"对比结果")</li>
<li>点击"提交"按钮生成对比结果</li>
</ol>
<p><strong>注意:</strong>请确保上传的文件格式正确,且包含需要对比的数据。</p>
</div>

<div class="file-inputs">
<div class="form-group">
<label for="file1" class="required">上月数据文件:</label>
<input type="file" name="file1" id="file1" required accept=".xls,.xlsx">
</div>

<div class="form-group">
<label for="file2" class="required">本月数据文件:</label>
<input type="file" name="file2" id="file2" required accept=".xls,.xlsx">
</div>
</div>

<div class="form-group">
<label for="output_filename" class="required">输出文件名(不含扩展名):</label>
<input type="text" name="output_filename" id="output_filename" required
placeholder="对比结果"
pattern="[a-zA-Z0-9_\-\u4e00-\u9fa5]+"
title="只能包含中文、字母、数字、下划线和连字符">
</div>

<button type="submit">提交并下载结果</button>
</form>
</div>

<script>
function openTab(tabName) {
// 隐藏所有标签内容
var tabContents = document.getElementsByClassName('tab-content');
for (var i = 0; i < tabContents.length; i++) {
tabContents[i].classList.remove('active');
}

// 取消所有标签按钮的活动状态
var tabButtons = document.getElementsByClassName('tab-button');
for (var i = 0; i < tabButtons.length; i++) {
tabButtons[i].classList.remove('active');
}

// 显示选定的标签内容并激活按钮
document.getElementById(tabName).classList.add('active');
event.currentTarget.classList.add('active');
}
</script>
</body>
</html>

合并后的主要特点

  1. 标签式界面:使用标签页切换两种不同的功能
  2. 代码复用:提取了共用的文件处理逻辑到process_uploaded_file函数
  3. 统一风格:保持了两套工具相同的视觉风格和用户体验
  4. 功能完整:保留了原有的所有功能,包括:
    • 胃镜肠镜统计功能
    • 数据对比功能
    • 自定义输出文件名
    • 错误处理和提示
  5. 响应式设计:适配不同屏幕尺寸

使用说明

  1. 将合并后的代码保存为index.php文件
  2. 确保有以下Python脚本在同一目录下:
    • tongji.py(胃镜肠镜统计脚本)
    • data_processor.py(数据对比脚本)
  3. 确保服务器已安装Python 3和所需的库(pandas, openpyxl, xlrd)
  4. 确保PHP有执行Python脚本和文件操作的权限

这个合并版本提供了更便捷的用户体验,用户可以在同一个界面中访问两种不同的数据处理功能。

时间: 2025-04-08T21:22:36


👤 用户

数据对比那列生成的文件是这样的

时间: 2025-04-08T21:33:44


🤖 DeepSeek (deepseek-chat)

根据您提供的错误截图,Excel无法打开生成的文件,这通常是由于文件格式或扩展名不匹配导致的。以下是针对这个问题的解决方案:

问题分析

  1. 文件扩展名问题:生成的.xlsx文件可能实际上不是有效的Excel格式
  2. Python脚本输出问题data_processor.py可能没有正确生成Excel文件
  3. 文件损坏:生成过程中文件可能被损坏

解决方案

请修改PHP代码中的数据对比部分,添加更严格的Excel文件验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// 修改后的数据对比处理部分
if ($action === 'data_comparison') {
ini_set('upload_max_filesize', '20M');
ini_set('post_max_size', '20M');

// 验证输出文件名
if (empty($_POST['output_filename'])) {
$error = "请输入输出文件名";
} elseif (!preg_match('/^[a-zA-Z0-9_\-\x{4e00}-\x{9fa5}]+$/u', $_POST['output_filename'])) {
$error = "文件名只能包含中文、字母、数字、下划线和连字符";
} else {
$output_file = trim($_POST['output_filename']) . '.xlsx';

if (isset($_FILES['file1']) && isset($_FILES['file2'])) {
// 验证上传的文件确实是Excel文件
$file1_ext = strtolower(pathinfo($_FILES['file1']['name'], PATHINFO_EXTENSION));
$file2_ext = strtolower(pathinfo($_FILES['file2']['name'], PATHINFO_EXTENSION));

if ($file1_ext !== 'xls' && $file1_ext !== 'xlsx') {
$error = "第一个文件不是有效的Excel文件";
} elseif ($file2_ext !== 'xls' && $file2_ext !== 'xlsx') {
$error = "第二个文件不是有效的Excel文件";
} elseif (is_uploaded_file($_FILES['file1']['tmp_name']) && is_uploaded_file($_FILES['file2']['tmp_name'])) {
// 使用临时文件名
$temp_file1 = tempnam(sys_get_temp_dir(), 'cmp1_') . '.xlsx';
$temp_file2 = tempnam(sys_get_temp_dir(), 'cmp2_') . '.xlsx';
$temp_output = tempnam(sys_get_temp_dir(), 'out_') . '.xlsx';

// 移动上传的文件
move_uploaded_file($_FILES['file1']['tmp_name'], $temp_file1);
move_uploaded_file($_FILES['file2']['tmp_name'], $temp_file2);

// 执行Python脚本
$command = sprintf(
'python3 data_processor.py "%s" "%s" "%s" 2>&1',
$temp_file1,
$temp_file2,
$temp_output
);

$output = shell_exec($command);

// 验证输出文件
if (file_exists($temp_output) && filesize($temp_output) > 0) {
// 重命名为用户指定的文件名
rename($temp_output, $output_file);

// 提供下载
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($output_file) . '"');
header('Content-Length: ' . filesize($output_file));
readfile($output_file);

// 清理临时文件
unlink($temp_file1);
unlink($temp_file2);
unlink($output_file);
exit;
} else {
$error = "文件生成失败,可能是数据格式不正确";
if (!empty($output)) {
$error .= "<pre>Python脚本输出:\n" . htmlspecialchars($output) . "</pre>";
}

// 清理可能存在的临时文件
@unlink($temp_file1);
@unlink($temp_file2);
@unlink($temp_output);
}
} else {
$error = "文件上传失败,请检查文件是否有效。";
}
} else {
$error = "请上传两个文件。";
}
}
}

需要检查的Python脚本

请确保data_processor.py脚本正确使用了openpyxlpandas库生成Excel文件。示例正确代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import pandas as pd
import sys

def main():
if len(sys.argv) != 4:
print("Usage: python data_processor.py <file1> <file2> <output>")
return

file1 = sys.argv[1]
file2 = sys.argv[2]
output = sys.argv[3]

try:
# 读取Excel文件
df1 = pd.read_excel(file1)
df2 = pd.read_excel(file2)

# 这里添加你的数据处理逻辑
# 示例:简单的数据合并
result = pd.concat([df1, df2])

# 确保保存为有效的Excel文件
with pd.ExcelWriter(output, engine='openpyxl') as writer:
result.to_excel(writer, index=False)

print("文件生成成功")
except Exception as e:
print(f"处理失败: {str(e)}")
sys.exit(1)

if __name__ == "__main__":
main()

其他建议

  1. 测试Python脚本:直接在命令行运行脚本测试是否能生成有效的Excel文件

    1
    python3 data_processor.py 文件1.xlsx 文件2.xlsx 测试输出.xlsx
  2. 检查文件权限:确保PHP有权限在临时目录中创建和写入文件

  3. 添加日志:在PHP脚本中添加错误日志记录,帮助诊断问题

  4. 验证Excel文件:使用文本编辑器打开生成的.xlsx文件,开头应该是PK(zip压缩文件签名)

这些修改应该能解决Excel无法打开生成文件的问题。如果问题仍然存在,请提供data_processor.py脚本内容以便进一步诊断。

时间: 2025-04-08T21:33:44


👤 用户

原版本的没有问题,合二为一就有问题。奇怪的很

时间: 2025-04-08T21:40:08


🤖 DeepSeek (deepseek-chat)

服务器繁忙,请稍后再试。

时间: 2025-04-08T21:40:08


👤 用户

原版本的没有问题,合二为一就有问题。奇怪的很

时间: 2025-04-08T21:41:40


🤖 DeepSeek (deepseek-chat)

服务器繁忙,请稍后再试。

时间: 2025-04-08T21:41:40


👤 用户

原版本的没有问题,合二为一就有问题。奇怪的很

时间: 2025-04-08T21:49:55


🤖 DeepSeek (deepseek-chat)

如果原版本单独使用没有问题,但合并后出现问题,可能是由于以下几个原因导致的。我们来一步步排查和解决:

可能的原因分析

  1. 变量冲突:合并后全局变量或变量名可能发生冲突
  2. 文件处理逻辑交叉影响:两个功能的文件处理流程互相干扰
  3. 缓冲区问题:合并后输出缓冲区处理可能不一致
  4. 路径或临时文件冲突:两个功能使用的临时文件互相覆盖

解决方案

以下是经过优化的合并版本,特别注意隔离了两个功能的处理逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?php
// 设置错误报告以便调试
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 处理胃镜肠镜统计
function process_endoscopy($uploaded_file, $output_name) {
$temp_file = 'endoscopy_temp.xls';
$output_file = preg_replace('/[^a-zA-Z0-9_\x{4e00}-\x{9fa5}]/u', '', $output_name) . '.xlsx';

if (!move_uploaded_file($uploaded_file, $temp_file)) {
return ["error" => "无法移动上传的文件"];
}

$command = "python3 tongji.py 2>&1";
$output = shell_exec($command);

if (!file_exists('统计结果.xlsx')) {
return ["error" => "处理失败: " . $output];
}

// 重命名输出文件
if (!rename('统计结果.xlsx', $output_file)) {
$output_file = '统计结果.xlsx';
}

return ["success" => true, "output_file" => $output_file, "temp_file" => $temp_file];
}

// 处理数据对比
function process_comparison($file1, $file2, $output_name) {
$temp_file1 = 'comparison_temp1.xlsx';
$temp_file2 = 'comparison_temp2.xlsx';
$output_file = preg_replace('/[^a-zA-Z0-9_\-\x{4e00}-\x{9fa5}]/u', '', $output_name) . '.xlsx';

if (!move_uploaded_file($file1, $temp_file1) || !move_uploaded_file($file2, $temp_file2)) {
return ["error" => "无法移动上传的文件"];
}

$command = "python3 data_processor.py \"$temp_file1\" \"$temp_file2\" \"$output_file\" 2>&1";
$output = shell_exec($command);

if (!file_exists($output_file)) {
return ["error" => "处理失败: " . $output];
}

return ["success" => true, "output_file" => $output_file, "temp_files" => [$temp_file1, $temp_file2]];
}

// 主处理逻辑
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$error = '';

try {
if ($action === 'endoscopy_stats') {
// 胃镜肠镜统计处理
if (empty($_FILES['excel_file']['tmp_name'])) {
throw new Exception("请上传有效的Excel文件");
}

$output_name = $_POST['output_name'] ?? '统计结果';
$result = process_endoscopy($_FILES['excel_file']['tmp_name'], $output_name);

if (isset($result['error'])) {
throw new Exception($result['error']);
}

// 准备下载
$output_file = $result['output_file'];
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($output_file) . '"');
readfile($output_file);

// 清理
unlink($result['temp_file']);
unlink($output_file);
exit;

} elseif ($action === 'data_comparison') {
// 数据对比处理
if (empty($_FILES['file1']['tmp_name']) || empty($_FILES['file2']['tmp_name'])) {
throw new Exception("请上传两个有效的Excel文件");
}

$output_name = $_POST['output_filename'] ?? '对比结果';
$result = process_comparison($_FILES['file1']['tmp_name'], $_FILES['file2']['tmp_name'], $output_name);

if (isset($result['error'])) {
throw new Exception($result['error']);
}

// 准备下载
$output_file = $result['output_file'];
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . basename($output_file) . '"');
readfile($output_file);

// 清理
foreach ($result['temp_files'] as $temp_file) {
unlink($temp_file);
}
unlink($output_file);
exit;
}
} catch (Exception $e) {
$error = $e->getMessage();
}
}
?>

<!-- 以下是HTML界面部分,保持不变 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据统计与对比工具</title>
<!-- 样式部分保持不变 -->
<style>
/* 保持原有的CSS样式不变 */
</style>
</head>
<body>
<!-- 保持原有的HTML结构不变 -->
</body>
</html>

关键改进点

  1. 功能隔离

    • 将两个功能的处理逻辑完全分离为独立函数
    • 使用不同的临时文件名前缀避免冲突
  2. 错误处理增强

    • 使用try-catch结构捕获异常
    • 更详细的错误信息返回
  3. 文件处理安全

    • 确保每个功能使用独立的临时文件
    • 更严格的文件存在性检查
  4. 清理机制

    • 确保处理完成后删除所有临时文件
    • 使用绝对路径操作文件

使用建议

  1. 测试步骤

    • 先单独测试每个功能是否正常工作
    • 然后测试切换使用两个功能
  2. 日志添加

    • 可以在关键步骤添加日志记录,帮助诊断问题
    1
    file_put_contents('debug.log', date('Y-m-d H:i:s')." - 开始处理".PHP_EOL, FILE_APPEND);
  3. 文件权限检查

    • 确保PHP有权限创建和删除所有临时文件

如果问题仍然存在,建议检查:

  1. 服务器错误日志中的具体错误信息
  2. Python脚本是否在合并环境下有不同行为
  3. 临时文件目录是否可写

这种结构应该能解决合并后出现的问题,同时保持原有功能的完整性。

时间: 2025-04-08T21:49:55


👤 用户

胃镜肠镜统计中出现:处理失败: 读取文件失败: [Errno 2] No such file or directory: ‘1.xls’

时间: 2025-04-08T21:53:23


🤖 DeepSeek (deepseek-chat)

服务器繁忙,请稍后再试。

时间: 2025-04-08T21:53:23


👤 用户

胃镜肠镜统计中出现:处理失败: 读取文件失败: [Errno 2] No such file or directory: ‘1.xls’

时间: 2025-04-08T21:55:43


🤖 DeepSeek (deepseek-chat)

服务器繁忙,请稍后再试。

时间: 2025-04-08T21:55:43


👤 用户

胃镜肠镜统计中出现:处理失败: 读取文件失败: [Errno 2] No such file or directory: ‘1.xls’

时间: 2025-04-08T21:58:01


🤖 DeepSeek (deepseek-chat)

这个错误表明 Python 脚本 tongji.py 无法找到 1.xls 文件。这是合并版本后出现的问题,我们需要调整文件处理流程。以下是解决方案:

问题原因

  1. 合并版本中文件路径处理不一致
  2. 临时文件命名冲突
  3. 文件移动逻辑有问题

修复方案

请修改 process_endoscopy 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function process_endoscopy($uploaded_file, $output_name) {
// 使用唯一临时文件名
$temp_file = 'endoscopy_temp_' . uniqid() . '.xls';
$output_file = preg_replace('/[^a-zA-Z0-9_\x{4e00}-\x{9fa5}]/u', '', $output_name) . '.xlsx';

// 确保目标目录可写
if (!is_writable('.')) {
return ["error" => "服务器目录不可写,请联系管理员"];
}

// 移动上传的文件
if (!move_uploaded_file($uploaded_file, $temp_file)) {
return ["error" => "无法移动上传的文件"];
}

// 修改Python命令,明确指定输入文件
$command = "python3 tongji.py \"$temp_file\" \"$output_file\" 2>&1";
$output = shell_exec($command);

// 检查输出文件
if (!file_exists($output_file)) {
// 清理临时文件
@unlink($temp_file);
return ["error" => "处理失败: " . $output];
}

return [
"success" => true,
"output_file" => $output_file,
"temp_files" => [$temp_file] // 可能需要清理多个文件
];
}

同时需要修改 tongji.py 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Font
import sys

def process_data(input_file, output_file):
try:
# 修改为从参数读取输入文件
df = pd.read_excel(input_file, sheet_name='导出数据', engine='xlrd')
print(f"成功读取数据,共{len(df)}条记录")
except Exception as e:
print(f"读取文件失败: {e}")
sys.exit(1)

# ... (保持原有处理逻辑不变) ...

# 修改输出文件名使用参数
wb.save(output_file)
print(f"统计完成,结果已保存到'{output_file}'")

if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python tongji.py <input_file> <output_file>")
sys.exit(1)

input_file = sys.argv[1]
output_file = sys.argv[2]
process_data(input_file, output_file)

其他需要检查的事项

  1. 文件权限

    1
    2
    chmod 777 tongji.py
    chmod 777 data_processor.py
  2. Python环境

    1
    python3 -m pip install pandas openpyxl xlrd --upgrade
  3. 完整调用流程测试

在服务器上手动测试:

1
python3 tongji.py test_input.xls test_output.xlsx

最终PHP调用部分调整

1
2
3
4
5
6
7
8
9
10
11
12
// 在表单处理部分修改为:
$result = process_endoscopy($_FILES['excel_file']['tmp_name'], $output_name);

// 下载完成后清理文件:
if (file_exists($result['output_file'])) {
unlink($result['output_file']);
}
foreach ($result['temp_files'] as $temp_file) {
if (file_exists($temp_file)) {
unlink($temp_file);
}
}

常见问题排查

  1. 如果还是报错,检查:

    • 确保 tongji.py 和PHP文件在同一目录
    • 查看服务器错误日志:tail -f /var/log/apache2/error.log
    • 在PHP中添加调试输出:
      1
      2
      echo "命令: $command<br>输出: $output";
      exit;
  2. 临时解决方案(测试用):

    1
    2
    3
    // 临时赋予所有权限
    chmod('/path/to/tongji.py', 0777);
    chmod('/path/to/upload_dir', 0777);

这样修改后,文件路径问题应该能解决。关键点是:

  1. Python脚本改为接受明确的输入/输出参数
  2. PHP中使用唯一临时文件名
  3. 完善的错误处理和文件清理机制

时间: 2025-04-08T21:58:01


👤 用户

帮我看一下这个文件,如何写一个PHP文件,让其选择同目录下的表格文件并使用这个脚本文件,并生成一张图片呢?目前允许这个脚本是弹出一个地址显示图片的。我想直接把那张图片保存下来,仅仅只需选择一个同目录表格文件,然后点击生成图片

时间: 2025-04-08T22:29:37


🤖 DeepSeek (deepseek-chat)

PHP 脚本生成医生工作量统计图

以下是一个完整的PHP解决方案,可以让用户选择同目录下的Excel文件,使用doctorx.py脚本生成统计图,并将图片保存下来供下载。

完整PHP代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<?php
// 设置错误报告以便调试
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['excel_file'])) {
// 检查文件上传是否成功
if ($_FILES['excel_file']['error'] !== UPLOAD_ERR_OK) {
$error = "文件上传失败,错误代码: " . $_FILES['excel_file']['error'];
} else {
// 检查文件扩展名
$file_name = $_FILES['excel_file']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));

if ($file_ext !== 'xlsx' && $file_ext !== 'xls') {
$error = "请上传Excel文件(.xls或.xlsx)";
} else {
// 生成唯一文件名
$temp_file = 'temp_data_' . uniqid() . '.' . $file_ext;
$output_image = 'doctor_stats_' . uniqid() . '.png';

// 移动上传的文件
if (!move_uploaded_file($_FILES['excel_file']['tmp_name'], $temp_file)) {
$error = "无法保存上传的文件";
} else {
// 修改Python脚本以保存图片而不是显示
$python_script = "doctorx_modified.py";

// 检查是否已存在修改后的脚本
if (!file_exists($python_script)) {
// 创建修改后的Python脚本
$python_code = <<<'PYTHON'
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import sys
import os
from plotly.io import write_image

def main(input_file, output_image):
try:
# 读取 Excel 文件
df = pd.read_excel(input_file, sheet_name='医生工作量统计')

# 检查并填充缺失值
df.fillna({'总数': 0}, inplace=True)

# 获取检查医师的唯一值,排除"汇总"
doctors = df[df['医师'] != '汇总']['医师'].unique()

# 创建图形
fig = go.Figure()

# 生成颜色
colors = [f'rgba({int(np.random.rand()*255)}, {int(np.random.rand()*255)}, {int(np.random.rand()*255)}, 0.7)' for _ in range(len(doctors))]

# 添加检查医师数据
for i, doctor in enumerate(doctors):
fig.add_trace(go.Bar(
x=[df[df['医师'] == doctor]['总数'].sum()],
y=[str(doctor)],
name=str(doctor),
marker=dict(color=colors[i]),
orientation='h'
))

# 设置布局
fig.update_layout(
title='检查医师工作量统计',
title_x=0.5,
showlegend=True,
xaxis=dict(title='病例数'),
yaxis=dict(title='检查医师'),
margin=dict(l=40, r=40, t=40, b=40),
height=600,
width=800
)

# 保存图像为PNG
write_image(fig, output_image)
print(f"图像已保存到: {output_image}")

except Exception as e:
print(f"处理失败: {str(e)}")
sys.exit(1)

if __name__ == "__main__":
if len(sys.argv) != 3:
print("用法: python doctorx_modified.py <输入文件> <输出图片>")
sys.exit(1)

input_file = sys.argv[1]
output_image = sys.argv[2]
main(input_file, output_image)
PYTHON;

file_put_contents($python_script, $python_code);
}

// 执行Python脚本
$command = "python3 " . escapeshellarg($python_script) . " " .
escapeshellarg($temp_file) . " " .
escapeshellarg($output_image) . " 2>&1";
$output = shell_exec($command);

// 检查是否生成图片
if (file_exists($output_image)) {
// 提供图片下载
header('Content-Description: File Transfer');
header('Content-Type: image/png');
header('Content-Disposition: attachment; filename="医生工作量统计.png"');
header('Content-Length: ' . filesize($output_image));
readfile($output_image);

// 清理临时文件
unlink($temp_file);
unlink($output_image);
exit;
} else {
$error = "图片生成失败: " . htmlspecialchars($output);
@unlink($temp_file);
}
}
}
}
}
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>医生工作量统计图生成器</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
}
h1 {
color: #333;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="file"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
width: 100%;
}
button:hover {
background-color: #45a049;
}
.error {
color: red;
margin-bottom: 15px;
padding: 10px;
background-color: #ffeeee;
border: 1px solid #ffdddd;
border-radius: 4px;
}
.instructions {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #4CAF50;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>医生工作量统计图生成器</h1>

<div class="instructions">
<h3>使用说明:</h3>
<ol>
<li>上传包含医生工作量统计的Excel文件</li>
<li>文件必须包含名为"医生工作量统计"的工作表</li>
<li>工作表中需要有"医师"和"总数"列</li>
<li>点击"生成统计图"按钮</li>
<li>系统将生成并下载统计图</li>
</ol>
</div>

<?php if (isset($error)): ?>
<div class="error"><?php echo $error; ?></div>
<?php endif; ?>

<form action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="excel_file">选择Excel文件 (.xls或.xlsx):</label>
<input type="file" name="excel_file" id="excel_file" accept=".xls,.xlsx" required>
</div>

<button type="submit">生成统计图</button>
</form>
</body>
</html>

关键改进说明

  1. Python脚本修改

    • doctorx.py修改为doctorx_modified.py,自动保存图片而不是显示
    • 使用plotly.io.write_image将图表保存为PNG文件
    • 添加了命令行参数处理
  2. PHP处理流程

    • 上传Excel文件并验证
    • 动态生成修改后的Python脚本(如果不存在)
    • 执行Python脚本生成图片
    • 提供图片下载
    • 自动清理临时文件
  3. 安全措施

    • 使用唯一文件名防止冲突
    • 严格的文件类型检查
    • 错误处理和清理机制

使用前准备

  1. 确保服务器已安装以下Python库:

    1
    pip install pandas plotly kaleido
  2. 确保PHP有执行Python脚本的权限

  3. 确保目录有写入权限

使用说明

  1. 将PHP文件保存到与doctorx.py相同的目录
  2. 通过浏览器访问PHP文件
  3. 上传符合要求的Excel文件
  4. 点击”生成统计图”按钮
  5. 浏览器会自动下载生成的PNG图片

这个解决方案避免了原脚本弹出显示的问题,直接将图表保存为图片文件供下载。

时间: 2025-04-08T22:29:37


👤 用户

图片生成失败: 处理失败: Image export using the “kaleido” engine requires the kaleido package, which can be installed using pip: $ pip install -U kaleido

时间: 2025-04-08T22:37:33


🤖 DeepSeek (deepseek-chat)

服务器繁忙,请稍后再试。

时间: 2025-04-08T22:37:33



对话统计

  • 消息总数: 24 条
  • 处理状态: 成功转换