You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Woocommerce发送PDF门票代码评估及并发购买问题咨询

代码规范分析

整体代码逻辑清晰,但存在不少可以优化的点以及潜在bug:

  • 变量命名可读性:部分变量命名可以更语义化,比如$pdf_count可改为$total_required_tickets,$pdf_attachments改为$selected_ticket_paths,提升代码维护性。
  • 边界处理缺失:
    • 未检查Tickets和UsedTickets文件夹是否存在、是否有读写权限,若文件夹缺失会直接报错。
    • 未处理glob()返回空数组的情况(即Tickets文件夹无PDF),后续数组索引操作会触发致命错误。
    • 订单商品数量判断$order->get_item_count()冗余,即使订单无商品,后续循环也不会执行,反而可能误过滤有非目标商品的订单。
  • 索引计算bug:原代码中$pdf_files[ $pdf_count - $item->get_quantity() + $i % count( $pdf_files ) ]的括号位置错误,$i % count($pdf_files)会先运算,导致索引可能超出数组长度,正确写法应为$pdf_files[ ($pdf_count - $item->get_quantity() + $i) % count( $pdf_files ) ]。
  • 附件逻辑漏洞:无论文件移动是否成功,都将$new_path加入附件列表,若移动失败,该路径不存在会导致邮件附件缺失。
多用户并发下单的问题

会出现严重的重复发券或发券失败问题:
当多个用户同时下单时,两个请求会同时执行glob()获取相同的PDF文件列表;在第一个请求还未完成文件移动时,第二个请求已经选中了同一份PDF;最终导致两个订单发送同一张门票,第二个请求的rename()操作会因文件已被移走而失败,且邮件会添加无效的附件路径。

本质原因是代码没有实现原子性操作,选取文件和移动文件的过程未加锁,无法保证同一时间只有一个请求能操作某份PDF资源。

优化方案
  1. 修复索引计算bug
// 替换原索引计算代码
$index = ($pdf_count - $item->get_quantity() + $i) % count($pdf_files);
$pdf_path = $pdf_files[$index];
  1. 添加边界检查
$tickets_dir = get_template_directory() . '/Tickets/';
$used_dir = get_template_directory() . '/UsedTickets/';
// 检查文件夹是否存在
if (!is_dir($tickets_dir) || !is_dir($used_dir)) {
    error_log('Tickets或UsedTickets文件夹不存在');
    return $attachments;
}
$pdf_files = glob($tickets_dir . '*.pdf');
// 检查是否有可用PDF
if (empty($pdf_files)) {
    error_log('无可用PDF门票');
    return $attachments;
}
  1. 解决并发问题(文件锁方案)
    通过排他锁确保同一时间只有一个请求能操作门票文件:
$lock_file = $tickets_dir . 'ticket_lock.txt';
$lock_handle = fopen($lock_file, 'w');
// 尝试获取排他锁,失败则等待后重试
if (!flock($lock_handle, LOCK_EX | LOCK_NB)) {
    if (!flock($lock_handle, LOCK_EX)) {
        error_log('无法获取门票操作锁');
        fclose($lock_handle);
        return $attachments;
    }
}

// 此处执行选取PDF、移动文件的逻辑

// 操作完成后释放锁
flock($lock_handle, LOCK_UN);
fclose($lock_handle);
  1. 优化附件添加逻辑
    仅在文件移动成功时,才将路径加入附件:
if (rename($pdf_path, $new_path)) {
    error_log('PDF已移至UsedTickets文件夹: ' . $pdf_filename);
    $attachments[] = $new_path;
} else {
    error_log('移动PDF失败: ' . $pdf_filename);
}

内容的提问来源于stack exchange,提问作者Beze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 13:46:08