我来帮您设计一个基于PHP的简历筛选系统架构和实现方案。

系统架构设计
数据库设计
-- 简历表
CREATE TABLE `resumes` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`email` VARCHAR(100),
`phone` VARCHAR(20),
`education` TEXT, -- JSON格式存储教育经历
`experience` TEXT, -- JSON格式存储工作经历
`skills` TEXT, -- JSON格式存储技能
`file_path` VARCHAR(255),
`content` TEXT, -- 解析后的文本内容
`status` TINYINT DEFAULT 0, -- 0:未筛选 1:通过 2:未通过
`score` INT DEFAULT 0,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 关键词规则表
CREATE TABLE `keywords` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`category` VARCHAR(50), -- 技能/学历/经验
`word` VARCHAR(100),
`weight` INT DEFAULT 1, -- 权重
`is_required` TINYINT DEFAULT 0 -- 是否必须
);
核心PHP实现
<?php
// ResumeFilter.php
class ResumeFilter {
private $db;
private $keywords = [];
private $threshold = 60; // 通过阈值
public function __construct($db) {
$this->db = $db;
$this->loadKeywords();
}
// 加载筛选规则
private function loadKeywords() {
$result = $this->db->query("SELECT * FROM keywords");
while($row = $result->fetch_assoc()) {
$this->keywords[$row['category']][] = $row;
}
}
// 简历解析
public function parseResume($file) {
$content = '';
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
switch(strtolower($ext)) {
case 'pdf':
$content = $this->parsePDF($file['tmp_name']);
break;
case 'doc':
case 'docx':
$content = $this->parseWord($file['tmp_name']);
break;
case 'txt':
$content = file_get_contents($file['tmp_name']);
break;
}
return $this->extractInfo($content);
}
// 解析PDF (需要安装pdfparser)
private function parsePDF($filePath) {
require_once 'vendor/autoload.php';
$parser = new \Smalot\PdfParser\Parser();
$pdf = $parser->parseFile($filePath);
return $pdf->getText();
}
// 解析Word文档
private function parseWord($filePath) {
$phpWord = \PhpOffice\PhpWord\IOFactory::load($filePath);
$content = '';
foreach($phpWord->getSections() as $section) {
foreach($section->getElements() as $element) {
if(method_exists($element, 'getText')) {
$content .= $element->getText();
}
}
}
return $content;
}
// 提取关键信息
private function extractInfo($content) {
$info = [
'skills' => [],
'education' => [],
'experience' => [],
'content' => $content
];
// 提取技能
$skillKeywords = ['PHP', 'JavaScript', 'Python', 'Java', 'MySQL', 'Linux', 'Docker'];
foreach($skillKeywords as $skill) {
if(stripos($content, $skill) !== false) {
$info['skills'][] = $skill;
}
}
// 提取教育信息
preg_match('/(?:本科|硕士|博士|大专)?\s*(?:毕业于)?\s*([\x{4e00}-\x{9fa5}]+(?:大学|学院))/u', $content, $matches);
if(!empty($matches[1])) {
$info['education'][] = $matches[1];
}
// 提取工作年限
preg_match('/(\d+)\s*年\s*(?:工作经验|从业经验|工作经历)/', $content, $matches);
if(!empty($matches[1])) {
$info['experience'][] = $matches[1] . '年';
}
return $info;
}
// 评分算法
public function calculateScore($resumeInfo) {
$score = 0;
$maxScore = 0;
foreach($this->keywords as $category => $keywords) {
foreach($keywords as $keyword) {
$maxScore += $keyword['weight'];
if($this->matchKeyword($resumeInfo['content'], $keyword['word'])) {
$score += $keyword['weight'];
}
}
}
return $maxScore > 0 ? round(($score / $maxScore) * 100) : 0;
}
// 关键词匹配
private function matchKeyword($content, $word) {
return stripos($content, $word) !== false;
}
// 执行筛选
public function filter($resumeId) {
$resume = $this->db->query("SELECT * FROM resumes WHERE id = $resumeId")->fetch_assoc();
if(!$resume) return false;
$resumeInfo = json_decode($resume['content'], true);
$score = $this->calculateScore($resumeInfo);
$status = $score >= $this->threshold ? 1 : 2;
$this->db->query("UPDATE resumes SET score = $score, status = $status WHERE id = $resumeId");
return [
'id' => $resumeId,
'score' => $score,
'status' => $status,
'passed' => $status == 1
];
}
// 批量筛选
public function batchFilter($limit = 100) {
$results = [];
$resumes = $this->db->query("SELECT id FROM resumes WHERE status = 0 LIMIT $limit");
while($resume = $resumes->fetch_assoc()) {
$results[] = $this->filter($resume['id']);
}
return $results;
}
}
RESTful API接口
<?php
// api/resume.php
class ResumeAPI {
private $filter;
public function __construct($filter) {
$this->filter = $filter;
}
// 上传简历
public function upload() {
if(!isset($_FILES['resume'])) {
return ['error' => 'No file uploaded'];
}
$file = $_FILES['resume'];
$allowedTypes = ['pdf', 'doc', 'docx', 'txt'];
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
if(!in_array($ext, $allowedTypes)) {
return ['error' => 'Invalid file type'];
}
// 解析简历
$resumeInfo = $this->filter->parseResume($file);
// 保存到数据库
$name = $resumeInfo['name'] ?? pathinfo($file['name'], PATHINFO_FILENAME);
$content = json_encode($resumeInfo);
$stmt = $this->filter->db->prepare("INSERT INTO resumes (name, content, file_path) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $name, $content, $file['name']);
$stmt->execute();
return ['id' => $stmt->insert_id, 'message' => 'Upload successful'];
}
// 查看筛选结果
public function status($id) {
$resume = $this->filter->db->query("SELECT * FROM resumes WHERE id = $id")->fetch_assoc();
if(!$resume) {
return ['error' => 'Resume not found'];
}
return [
'id' => $resume['id'],
'name' => $resume['name'],
'score' => $resume['score'],
'status' => $resume['status'] == 1 ? '通过' : ($resume['status'] == 2 ? '未通过' : '待筛选'),
'created_at' => $resume['created_at']
];
}
}
前端展示示例
<!-- upload.html -->
<!DOCTYPE html>
<html>
<head>简历筛选系统</title>
<style>
.container { max-width: 800px; margin: 0 auto; padding: 20px; }
.result { margin-top: 20px; border: 1px solid #ddd; padding: 10px; }
.passed { border-color: green; background: #f0fff0; }
.failed { border-color: red; background: #fff0f0; }
</style>
</head>
<body>
<div class="container">
<h1>简历筛选系统</h1>
<form action="api/upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="resume" accept=".pdf,.doc,.docx,.txt" required>
<button type="submit">上传并筛选</button>
</form>
<div id="result"></div>
</div>
<script>
document.querySelector('form').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('/api/resume.php?action=upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if(data.error) {
alert(data.error);
return;
}
// 轮询筛选结果
checkStatus(data.id);
});
});
function checkStatus(id) {
fetch(`/api/resume.php?action=status&id=${id}`)
.then(response => response.json())
.then(data => {
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = `
<div class="result ${data.status === '通过' ? 'passed' : 'failed'}">
<h3>${data.name}</h3>
<p>得分:${data.score}</p>
<p>状态:${data.status}</p>
<p>上传时间:${data.created_at}</p>
</div>
`;
});
}
</script>
</body>
</html>
配置与运行
composer.json:
{
"require": {
"smalot/pdfparser": "^2.0",
"phpoffice/phpword": "^0.18"
}
}
启动命令:
# 安装依赖 composer install # 启动服务 (PHP内置服务器) php -S localhost:8000
核心特性
- 多格式支持: PDF、Word、TXT文件解析
- 智能评分: 基于关键词权重计算
- 规则可配置: 通过数据库管理筛选规则
- 批量处理: 支持大量简历同时筛选
- API接口: 便于与其他系统集成
这个系统可以根据您的具体需求进行扩展,比如增加机器学习模型、添加更多解析规则、优化评分算法等。