本文目录导读:

我来为您提供一个完整的PHP后台任务进度条实现方案。
前端HTML页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">任务进度条</title>
<style>
.progress-container {
max-width: 600px;
margin: 100px auto;
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.progress-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.progress-percentage {
font-size: 16px;
color: #666;
font-weight: bold;
}
.progress-bar {
width: 100%;
height: 30px;
background: #e0e0e0;
border-radius: 15px;
overflow: hidden;
position: relative;
}
.progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, #4CAF50, #45a049);
border-radius: 15px;
transition: width 0.3s ease;
width: 0%;
}
.progress-status {
margin-top: 20px;
padding: 10px;
background: white;
border-radius: 5px;
border: 1px solid #ddd;
font-size: 14px;
color: #666;
height: 40px;
overflow: auto;
}
.btn-group {
margin-top: 20px;
text-align: center;
}
.btn {
padding: 10px 30px;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
margin: 0 10px;
transition: all 0.3s;
}
.btn-start {
background: #4CAF50;
color: white;
}
.btn-start:hover {
background: #45a049;
}
.btn-start:disabled {
background: #cccccc;
cursor: not-allowed;
}
.btn-cancel {
background: #f44336;
color: white;
}
.btn-cancel:hover {
background: #da190b;
}
</style>
</head>
<body>
<div class="progress-container">
<div class="progress-header">
<div class="progress-title">任务进度</div>
<div class="progress-percentage" id="progressText">0%</div>
</div>
<div class="progress-bar">
<div class="progress-bar-fill" id="progressBar"></div>
</div>
<div class="progress-status" id="statusText">
等待任务开始...
</div>
<div class="btn-group">
<button class="btn btn-start" id="startBtn" onclick="startTask()">
开始任务
</button>
<button class="btn btn-cancel" id="cancelBtn" onclick="cancelTask()" style="display:none">
取消任务
</button>
</div>
</div>
<script>
let progressInterval = null;
let taskId = null;
// 开始任务
function startTask() {
document.getElementById('startBtn').disabled = true;
document.getElementById('cancelBtn').style.display = 'inline-block';
// 创建新的任务
fetch('start_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'start',
task_name: 'example_task'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
taskId = data.task_id;
document.getElementById('statusText').textContent = '任务开始...';
startProgressPolling();
} else {
alert('任务启动失败: ' + data.message);
}
});
}
// 开始轮询进度
function startProgressPolling() {
// 清除旧的轮询
if (progressInterval) {
clearInterval(progressInterval);
}
// 每1秒轮询一次进度
progressInterval = setInterval(() => {
getProgress();
}, 1000);
}
// 获取进度
function getProgress() {
if (!taskId) return;
fetch(`get_progress.php?task_id=${taskId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
updateProgress(data.progress, data.status);
// 任务完成
if (data.progress >= 100) {
completeTask(data);
}
} else {
// 任务出错或不存在
errorTask(data);
}
})
.catch(error => {
console.error('获取进度失败:', error);
errorTask({message: '连接服务器失败'});
});
}
// 更新进度显示
function updateProgress(progress, status) {
document.getElementById('progressBar').style.width = progress + '%';
document.getElementById('progressText').textContent = progress + '%';
document.getElementById('statusText').textContent = status;
// 根据进度调整颜色
if (progress >= 100) {
document.getElementById('progressBar').style.background = '#4CAF50';
} else if (progress >= 70) {
document.getElementById('progressBar').style.background = '#ff9800';
} else if (progress >= 50) {
document.getElementById('progressBar').style.background = '#2196F3';
}
}
// 完成任务
function completeTask(data) {
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
document.getElementById('startBtn').disabled = false;
document.getElementById('cancelBtn').style.display = 'none';
document.getElementById('statusText').textContent = data.message || '任务完成!';
// 清理任务数据(可选)
setTimeout(() => {
fetch('cleanup_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ task_id: taskId })
});
}, 5000);
}
// 任务出错
function errorTask(data) {
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
document.getElementById('startBtn').disabled = false;
document.getElementById('cancelBtn').style.display = 'none';
document.getElementById('statusText').textContent = '错误: ' + data.message;
}
// 取消任务
function cancelTask() {
if (!taskId) return;
fetch('cancel_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ task_id: taskId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
document.getElementById('startBtn').disabled = false;
document.getElementById('cancelBtn').style.display = 'none';
document.getElementById('statusText').textContent = '任务已取消';
document.getElementById('progressBar').style.width = '0%';
document.getElementById('progressText').textContent = '0%';
} else {
alert('取消任务失败');
}
});
}
</script>
</body>
</html>
后台PHP文件
start_task.php (启动任务)
<?php
header('Content-Type: application/json');
// 关闭错误显示,避免干扰JSON输出
error_reporting(0);
ini_set('display_errors', 0);
// 启用会话
session_start();
// 修改: 实现真正的后台任务
function start_background_task($task_name) {
// 生成唯一任务ID
$task_id = uniqid('task_', true);
// 创建进度文件
$progress_file = __DIR__ . '/tasks/progress_' . $task_id . '.txt';
if (!file_exists(dirname($progress_file))) {
mkdir(dirname($progress_file), 0777, true);
}
// 初始化进度
$initial_data = json_encode([
'progress' => 0,
'status' => '任务已启动',
'start_time' => time(),
'cancelled' => false
]);
file_put_contents($progress_file, $initial_data);
// 使用PHP CLI执行后台任务
$script = __DIR__ . '/background_task.php';
$php_path = PHP_BINARY; // 获取PHP解释器路径
// 在Windows上使用start,在Linux上使用nohup
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
// Windows命令
$command = 'start /B ' . escapeshellarg($php_path) . ' ' .
escapeshellarg($script) . ' ' .
escapeshellarg($task_id) . ' ' .
escapeshellarg($task_name) . ' > NUL 2>&1';
pclose(popen($command, 'r'));
} else {
// Linux命令
$command = 'nohup ' . escapeshellarg($php_path) . ' ' .
escapeshellarg($script) . ' ' .
escapeshellarg($task_id) . ' ' .
escapeshellarg($task_name) . ' > /dev/null 2>&1 &';
exec($command);
}
return $task_id;
}
// 处理请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
if (isset($input['action']) && $input['action'] === 'start') {
$task_name = isset($input['task_name']) ? $input['task_name'] : 'default_task';
// 检查是否已有任务在运行
if (isset($_SESSION['current_task_id'])) {
$prev_task = $_SESSION['current_task_id'];
$progress_file = __DIR__ . '/tasks/progress_' . $prev_task . '.txt';
if (file_exists($progress_file)) {
$data = json_decode(file_get_contents($progress_file), true);
if ($data && $data['progress'] < 100 && !$data['cancelled']) {
echo json_encode([
'success' => false,
'message' => '已有任务在运行中'
]);
exit;
}
}
}
// 启动新的后台任务
$task_id = start_background_task($task_name);
// 保存当前任务ID到会话
$_SESSION['current_task_id'] = $task_id;
echo json_encode([
'success' => true,
'task_id' => $task_id,
'message' => '任务启动成功'
]);
} else {
echo json_encode([
'success' => false,
'message' => '无效的操作'
]);
}
} else {
echo json_encode([
'success' => false,
'message' => '无效的请求方法'
]);
}
?>
background_task.php (后台任务处理)
<?php
// 后台任务脚本
error_reporting(E_ALL);
ini_set('display_errors', 0);
set_time_limit(0); // 不限制执行时间
// 获取参数
$task_id = isset($argv[1]) ? $argv[1] : '';
$task_name = isset($argv[2]) ? $argv[2] : 'default_task';
if (empty($task_id)) {
exit('Invalid task ID');
}
// 进度文件路径
$progress_file = __DIR__ . '/tasks/progress_' . $task_id . '.txt';
// 模拟长时间任务(实际应用中这里会是真实的业务逻辑)
function perform_task($task_id, $task_name, $progress_file) {
// 模拟任务总步骤
$total_steps = 100;
for ($step = 1; $step <= $total_steps; $step++) {
// 检查是否取消
if (file_exists($progress_file)) {
$data = json_decode(file_get_contents($progress_file), true);
if ($data && isset($data['cancelled']) && $data['cancelled']) {
update_progress($progress_file, $step, '任务已取消', true);
return 'cancelled';
}
}
// 模拟工作
sleep(1); // 1秒处理一步,总共约100秒
// 更新进度
$progress = round(($step / $total_steps) * 100);
$status = "正在处理第 {$step} 步 / 共 {$total_steps} 步";
update_progress($progress_file, $progress, $status);
// 随机模拟一些错误情况(可选)
if ($step == 50 && rand(0, 100) < 5) { // 5%的概率在第50步出错
update_progress($progress_file, 50, '任务出错:模拟错误', true);
return 'error';
}
}
// 任务完成
update_progress($progress_file, 100, '任务完成!');
return 'completed';
}
// 更新进度
function update_progress($file, $progress, $status, $is_error = false) {
$data = [
'progress' => $progress,
'status' => $status,
'last_update' => time(),
'cancelled' => isset($is_error) && $is_error ? true : false,
'completed' => $progress >= 100 || ($is_error && $progress < 100)
];
if ($progress >= 100) {
$data['completed'] = true;
$data['message'] = '任务完成!';
}
file_put_contents($file, json_encode($data));
}
// 执行任务
$result = perform_task($task_id, $task_name, $progress_file);
// 记录任务结果
if ($result === 'completed') {
echo "Task completed successfully\n";
} else if ($result === 'cancelled') {
echo "Task cancelled\n";
} else {
echo "Task failed\n";
}
?>
get_progress.php (获取进度)
<?php
header('Content-Type: application/json');
session_start();
error_reporting(0);
ini_set('display_errors', 0);
// 获取任务ID
$task_id = isset($_GET['task_id']) ? $_GET['task_id'] : '';
if (empty($task_id)) {
echo json_encode(['success' => false, 'message' => '任务ID无效']);
exit;
}
// 读取进度文件
$progress_file = __DIR__ . '/tasks/progress_' . $task_id . '.txt';
if (!file_exists($progress_file)) {
echo json_encode([
'success' => false,
'message' => '任务不存在或已过期'
]);
exit;
}
$data = json_decode(file_get_contents($progress_file), true);
if (!$data) {
echo json_encode([
'success' => false,
'message' => '无法读取任务进度'
]);
exit;
}
// 返回进度信息
echo json_encode([
'success' => true,
'progress' => $data['progress'],
'status' => $data['status'],
'message' => isset($data['message']) ? $data['message'] : ''
]);
?>
cancel_task.php (取消任务)
<?php
header('Content-Type: application/json');
session_start();
error_reporting(0);
ini_set('display_errors', 0);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$task_id = isset($input['task_id']) ? $input['task_id'] : '';
if (empty($task_id)) {
echo json_encode(['success' => false, 'message' => '任务ID无效']);
exit;
}
// 更新任务状态为取消
$progress_file = __DIR__ . '/tasks/progress_' . $task_id . '.txt';
if (file_exists($progress_file)) {
$data = json_decode(file_get_contents($progress_file), true);
if ($data) {
$data['cancelled'] = true;
$data['status'] = '任务取消中...';
file_put_contents($progress_file, json_encode($data));
echo json_encode([
'success' => true,
'message' => '任务取消已触发'
]);
} else {
echo json_encode(['success' => false, 'message' => '任务数据无效']);
}
} else {
echo json_encode(['success' => false, 'message' => '任务不存在']);
}
} else {
echo json_encode(['success' => false, 'message' => '无效的请求方法']);
}
?>
cleanup_task.php (清理任务)
<?php
header('Content-Type: application/json');
error_reporting(0);
ini_set('display_errors', 0);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$task_id = isset($input['task_id']) ? $input['task_id'] : '';
if (!empty($task_id)) {
// 删除进度文件
$progress_file = __DIR__ . '/tasks/progress_' . $task_id . '.txt';
if (file_exists($progress_file)) {
unlink($progress_file);
// 可选的:删除其他相关文件
$log_file = __DIR__ . '/tasks/log_' . $task_id . '.txt';
if (file_exists($log_file)) {
unlink($log_file);
}
echo json_encode(['success' => true, 'message' => '任务数据已清理']);
} else {
echo json_encode(['success' => false, 'message' => '任务文件不存在']);
}
} else {
echo json_encode(['success' => false, 'message' => '任务ID无效']);
}
} else {
echo json_encode(['success' => false, 'message' => '无效的请求方法']);
}
?>
使用说明
-
创建目录结构:
mkdir -p /path/to/project/tasks chmod 755 /path/to/project/tasks
-
部署文件: 将所有PHP文件放在同一目录下,确保
tasks目录有正确权限。 -
安全建议:
- 添加身份验证
- 限制任务并发数
- 设置任务超时
- 清理过期任务文件
- 使用HTTPS传输
- 功能特点:
- ✅ 真正的后台任务执行
- ✅ 实时进度更新
- ✅ 任务取消功能
- ✅ 错误处理
- ✅ 跨平台兼容(Windows/Linux)
这个实现提供了一个完整的后台任务进度条方案,可以根据实际需求进行修改和扩展。