PHP项目工资条如何生成加密文件推送员工

wen PHP项目 30

本文目录导读:

PHP项目工资条如何生成加密文件推送员工

  1. 整体架构方案
  2. 使用示例
  3. 安全性建议

我来为你提供一个完整的PHP工资条加密文件生成和推送方案。

整体架构方案

<?php
// 工资条加密处理类
class SalarySlipEncryptor {
    private $encryptionKey;
    private $cipher = 'aes-256-gcm';
    public function __construct($key) {
        $this->encryptionKey = hash('sha256', $key, true);
    }
    /**
     * 加密工资条数据
     */
    public function encrypt($data) {
        $iv = openssl_random_pseudo_bytes(12);
        $tag = '';
        $encrypted = openssl_encrypt(
            json_encode($data),
            $this->cipher,
            $this->encryptionKey,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            '',
            16
        );
        // 返回 base64 编码的加密数据
        return base64_encode($iv . $tag . $encrypted);
    }
    /**
     * 解密工资条数据
     */
    public function decrypt($encryptedData) {
        $data = base64_decode($encryptedData);
        $iv = substr($data, 0, 12);
        $tag = substr($data, 12, 16);
        $encrypted = substr($data, 28);
        $decrypted = openssl_decrypt(
            $encrypted,
            $this->cipher,
            $this->encryptionKey,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );
        return json_decode($decrypted, true);
    }
}
// 工资条生成器
class SalarySlipGenerator {
    private $db;
    private $encryptor;
    public function __construct($db, $encryptionKey) {
        $this->db = $db;
        $this->encryptor = new SalarySlipEncryptor($encryptionKey);
    }
    /**
     * 生成单个员工的工资条
     */
    public function generateSlip($employeeId, $year, $month) {
        // 获取员工工资数据
        $salaryData = $this->getSalaryData($employeeId, $year, $month);
        // 添加元数据
        $slipData = [
            'employee_id' => $employeeId,
            'employee_name' => $salaryData['name'],
            'department' => $salaryData['department'],
            'year' => $year,
            'month' => $month,
            'generated_at' => date('Y-m-d H:i:s'),
            'salary_details' => [
                'basic_salary' => $salaryData['basic_salary'],
                'performance_bonus' => $salaryData['performance_bonus'],
                'overtime_pay' => $salaryData['overtime_pay'],
                'allowance' => $salaryData['allowance'],
                'social_insurance' => $salaryData['social_insurance'],
                'housing_fund' => $salaryData['housing_fund'],
                'tax' => $salaryData['tax'],
                'deductions' => $salaryData['deductions'],
                'net_salary' => $salaryData['net_salary']
            ],
            'checksum' => $this->calculateChecksum($salaryData)
        ];
        // 加密工资条
        $encryptedSlip = $this->encryptor->encrypt($slipData);
        // 保存加密后的工资条
        $this->saveEncryptedSlip($employeeId, $year, $month, $encryptedSlip);
        return [
            'encrypted_data' => $encryptedSlip,
            'file_name' => "salary_{$employeeId}_{$year}{$month}.enc"
        ];
    }
    /**
     * 批量生成工资条
     */
    public function generateAllSlips($year, $month) {
        $employees = $this->getAllEmployees();
        $results = [];
        foreach ($employees as $employee) {
            try {
                $result = $this->generateSlip($employee['id'], $year, $month);
                $results[] = [
                    'employee_id' => $employee['id'],
                    'employee_name' => $employee['name'],
                    'status' => 'success',
                    'file_name' => $result['file_name']
                ];
            } catch (Exception $e) {
                $results[] = [
                    'employee_id' => $employee['id'],
                    'employee_name' => $employee['name'],
                    'status' => 'failed',
                    'error' => $e->getMessage()
                ];
            }
        }
        return $results;
    }
    /**
     * 生成加密文件
     */
    public function createEncryptedFile($employeeId, $year, $month, $outputDir) {
        $slipData = $this->generateSlip($employeeId, $year, $month);
        // 创建目录
        if (!is_dir($outputDir)) {
            mkdir($outputDir, 0755, true);
        }
        // 保存加密文件
        $filePath = $outputDir . '/' . $slipData['file_name'];
        file_put_contents($filePath, $slipData['encrypted_data']);
        // 保存元数据文件
        $metaData = [
            'employee_id' => $employeeId,
            'file_name' => $slipData['file_name'],
            'encrypted_at' => date('Y-m-d H:i:s'),
            'expires_at' => date('Y-m-d H:i:s', strtotime('+30 days'))
        ];
        $metaFilePath = $outputDir . '/' . pathinfo($filePath, PATHINFO_FILENAME) . '.meta';
        file_put_contents($metaFilePath, json_encode($metaData));
        return $filePath;
    }
    private function calculateChecksum($data) {
        return hash('sha256', json_encode($data));
    }
    private function getSalaryData($employeeId, $year, $month) {
        // 从数据库获取工资数据
        $stmt = $this->db->prepare("
            SELECT e.name, e.department, 
                   s.* 
            FROM salaries s 
            JOIN employees e ON s.employee_id = e.id 
            WHERE s.employee_id = ? AND s.year = ? AND s.month = ?
        ");
        $stmt->execute([$employeeId, $year, $month]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
    private function getAllEmployees() {
        // 获取所有在职员工
        $stmt = $this->db->query("SELECT id, name FROM employees WHERE status = 'active'");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    private function saveEncryptedSlip($employeeId, $year, $month, $encryptedData) {
        // 保存到数据库
        $stmt = $this->db->prepare("
            INSERT INTO encrypted_salary_slips 
            (employee_id, year, month, encrypted_data, created_at) 
            VALUES (?, ?, ?, ?, NOW())
            ON DUPLICATE KEY UPDATE encrypted_data = ?, updated_at = NOW()
        ");
        $stmt->execute([$employeeId, $year, $month, $encryptedData, $encryptedData]);
    }
}
// 邮件推送类
class SalarySlipMailer {
    private $mailer;
    private $smtpConfig;
    public function __construct($smtpConfig) {
        $this->smtpConfig = $smtpConfig;
        $this->initMailer();
    }
    private function initMailer() {
        // 使用PHPMailer或SwiftMailer
        $this->mailer = new PHPMailer\PHPMailer\PHPMailer();
        $this->mailer->isSMTP();
        $this->mailer->Host = $this->smtpConfig['host'];
        $this->mailer->SMTPAuth = true;
        $this->mailer->Username = $this->smtpConfig['username'];
        $this->mailer->Password = $this->smtpConfig['password'];
        $this->mailer->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
        $this->mailer->Port = $this->smtpConfig['port'];
        $this->mailer->setFrom($this->smtpConfig['from_email'], '薪资系统');
        $this->mailer->CharSet = 'UTF-8';
    }
    /**
     * 推送工资条到员工邮箱
     */
    public function sendSalarySlip($employee, $encryptedFilePath, $decryptKey) {
        try {
            $this->mailer->clearAddresses();
            $this->mailer->addAddress($employee['email'], $employee['name']);
            $this->mailer->Subject = "{$employee['name']},您的{$employee['month']}月工资条已生成";
            // 构建邮件内容
            $emailBody = $this->buildEmailContent($employee, $decryptKey);
            $this->mailer->isHTML(true);
            $this->mailer->Body = $emailBody;
            $this->mailer->AltBody = strip_tags($emailBody);
            // 添加加密附件
            $this->mailer->addAttachment(
                $encryptedFilePath,
                'salary_slip.enc'
            );
            // 添加解密说明附件
            $decryptGuidePath = $this->createDecryptGuide($decryptKey);
            $this->mailer->addAttachment(
                $decryptGuidePath,
                '解密说明.txt'
            );
            return $this->mailer->send();
        } catch (Exception $e) {
            throw new Exception("发送失败: " . $e->getMessage());
        }
    }
    /**
     * 批量推送工资条
     */
    public function batchSendSalarySlips($slipList) {
        $results = [];
        foreach ($slipList as $slip) {
            try {
                $sent = $this->sendSalarySlip(
                    $slip['employee'],
                    $slip['file_path'],
                    $slip['decrypt_key']
                );
                $results[] = [
                    'employee_id' => $slip['employee']['id'],
                    'status' => $sent ? 'success' : 'failed',
                    'sent_at' => date('Y-m-d H:i:s')
                ];
            } catch (Exception $e) {
                $results[] = [
                    'employee_id' => $slip['employee']['id'],
                    'status' => 'failed',
                    'error' => $e->getMessage()
                ];
            }
        }
        return $results;
    }
    private function buildEmailContent($employee, $decryptKey) {
        return "
        <html>
        <body style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;'>
            <h2 style='color: #333;'>尊敬的 {$employee['name']} 您好:</h2>
            <p style='color: #666; line-height: 1.6;'>
                {$employee['year']}年{$employee['month']}月的工资条已生成,请查收附件。
            </p>
            <div style='background-color: #f5f5f5; padding: 20px; border-radius: 5px; margin: 20px 0;'>
                <h3 style='color: #333; margin-top: 0;'>📁 文件说明</h3>
                <ul style='color: #666; line-height: 1.6;'>
                    <li>附件文件:salary_slip.enc(加密工资条文件)</li>
                    <li>文件格式:使用 AES-256-GCM 加密</li>
                    <li>有效期:30天</li>
                </ul>
                <h3 style='color: #333; margin-top: 20px;'>🔑 解密密钥</h3>
                <div style='background-color: #fff; padding: 15px; border: 2px dashed #999; text-align: center;'>
                    <p style='margin: 0; font-size: 18px; font-weight: bold; color: #d32f2f; letter-spacing: 2px;'>
                        {$decryptKey}
                    </p>
                    <p style='color: #999; font-size: 12px; margin: 5px 0 0;'>请妥善保管此密钥,不要告知他人</p>
                </div>
            </div>
            <div style='background-color: #fff3cd; padding: 15px; border-radius: 5px; margin: 20px 0;'>
                <h3 style='color: #856404; margin-top: 0;'>⚠️ 安全提示</h3>
                <ul style='color: #856404;'>
                    <li>请勿将解密密钥告诉他人</li>
                    <li>公司不会通过任何方式索取您的解密密钥</li>
                    <li>如发现异常,请立即联系HR部门</li>
                </ul>
            </div>
            <p style='color: #999; font-size: 12px;'>
                此邮件由系统自动发送,请勿回复。<br>
                如有问题请联系 HR 部门。
            </p>
        </body>
        </html>
        ";
    }
    private function createDecryptGuide($decryptKey) {
        $guideContent = "工资条文件解密指南\n";
        $guideContent .= "====================\n\n";
        $guideContent .= "1. 打开解密工具网页: https://your-company.com/decrypt\n";
        $guideContent .= "2. 上传附件中的 salary_slip.enc 文件\n";
        $guideContent .= "3. 输入您的个人解密密钥: {$decryptKey}\n";
        $guideContent .= "4. 点击"解密"按钮查看工资条\n\n";
        $guideContent .= "注意事项:\n";
        $guideContent .= "- 请妥善保管您的解密密钥\n";
        $guideContent .= "- 文件有效期为30天\n";
        $guideContent .= "- 如遇问题请联系IT部门\n";
        $tmpPath = tempnam(sys_get_temp_dir(), 'decrypt_guide_');
        file_put_contents($tmpPath, $guideContent);
        return $tmpPath;
    }
}

使用示例

<?php
// 配置文件
$config = [
    'db' => [
        'host' => 'localhost',
        'dbname' => 'salary_db',
        'username' => 'root',
        'password' => 'password'
    ],
    'encryption' => [
        'master_key' => 'your-master-encryption-key-here'
    ],
    'smtp' => [
        'host' => 'smtp.company.com',
        'port' => 587,
        'username' => 'noreply@company.com',
        'password' => 'smtp-password',
        'from_email' => 'noreply@company.com'
    ]
];
// 初始化
$db = new PDO(
    "mysql:host={$config['db']['host']};dbname={$config['db']['dbname']}",
    $config['db']['username'],
    $config['db']['password']
);
$generator = new SalarySlipGenerator($db, $config['encryption']['master_key']);
$mailer = new SalarySlipMailer($config['smtp']);
// 1. 生成工资条
$year = date('Y');
$month = date('m') - 1; // 上个月
echo "开始生成工资条...\n";
$results = $generator->generateAllSlips($year, $month);
// 2. 创建加密文件并推送
foreach ($results as $result) {
    if ($result['status'] === 'success') {
        // 创建加密文件
        $filePath = $generator->createEncryptedFile(
            $result['employee_id'],
            $year,
            $month,
            '/tmp/salary_slips/' . $year . $month
        );
        // 获取员工信息和解密密钥
        $employee = [
            'id' => $result['employee_id'],
            'name' => $result['employee_name'],
            'email' => getEmployeeEmail($result['employee_id']),
            'year' => $year,
            'month' => $month
        ];
        // 生成个人解密密钥
        $personalKey = generatePersonalKey($result['employee_id'], $year, $month);
        // 发送邮件
        $mailer->sendSalarySlip($employee, $filePath, $personalKey);
        echo "已发送: {$result['employee_name']}\n";
    }
}
// 辅助函数
function getEmployeeEmail($employeeId) {
    global $db;
    $stmt = $db->prepare("SELECT email FROM employees WHERE id = ?");
    $stmt->execute([$employeeId]);
    return $stmt->fetchColumn();
}
function generatePersonalKey($employeeId, $year, $month) {
    // 生成个人解密密钥
    $base = "{$employeeId}-{$year}-{$month}-personal-salt";
    return substr(hash('sha256', $base), 0, 16);
}

安全性建议

  1. 密钥管理

    • 主密钥定期更换
    • 个人密钥不存储,通过算法生成
    • 使用硬件安全模块(HSM)存储密钥
  2. 数据传输

    • 使用HTTPS传输
    • 邮件附件加密
    • 文件下载有限时链接
  3. 访问控制

    • 实施二次验证
    • IP白名单限制
    • 操作日志审计
  4. 合规性

    • 符合GDPR/KYCC要求
    • 数据保留期限限制
    • 定期安全审计

这个方案提供了完整的加密、生成、推送流程,确保工资条数据的安全性和隐私保护。

抱歉,评论功能暂时关闭!