PAYATHON 2026

opencart 结账时出现 Internal server error

支付老李

明确结论

Undefined variable: class 通常只是 PHP Notice,本身不会直接导致 HTTP 500。出现 Internal Server Error,一般有两种原因:

  1. 项目或服务器将 PHP Notice 转换成了异常,导致模板渲染中断;
  2. 同一请求中还发生了更严重的 PHP Fatal Error、支付扩展异常或 IIS/FastCGI 错误,只是当前日志先记录了这条 Notice。

错误出现在 common/success.tpl,问题很可能发生在支付完成后渲染订单成功页面时,未必与提交信用卡信息的请求有关。先检查第 32 行如何使用 $class,再对照 PHP、Web 服务器和支付接口日志,找到真正导致 500 的错误。

为什么会出现 Undefined variable: class

OpenCart 的 .tpl 模板变量通常由对应的 Controller 传入。例如,模板中有以下代码:

<div class="<?php echo $class; ?>">

如果 Controller 没有定义 $class,PHP 就会报告:

Undefined variable: class

常见原因有:

  • 自定义主题的 success.tpl 使用了 $class,但对应的 Controller 没有传入;
  • OpenCart 核心文件已经更新,主题仍是旧版本;
  • 安装或更新支付扩展、OCMOD、VQMod 后,Controller 与模板不再匹配;
  • 模板变量名称写错;
  • $class 只在某个条件分支中定义,而当前结账流程没有进入该分支;
  • PHP 或错误处理配置发生变化,原本被忽略的 Notice 现在会被转换成异常。

PHP 原生的未定义变量 Notice 通常不会终止程序。不过,如果项目包含类似下面的错误处理逻辑,Notice 就可能被升级为异常:

set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

这种情况下,访问未定义的 $class 可能中断请求,最终返回 HTTP 500。

第一步:检查 success.tpl 第 32 行

打开日志指定的模板:

catalog/view/theme/customTheme/template/common/success.tpl

查看第 32 行及其附近代码,确认 $class 用在哪里。例如:

<div class="<?php echo $class; ?>">

或者:

<?php if ($class) { ?>
    ...
<?php } ?>

如果 $class 只是可选的 CSS 类,可以先提供一个安全的默认值:

<div class="<?php echo isset($class) ? htmlspecialchars($class, ENT_QUOTES, 'UTF-8') : ''; ?>">

条件判断可以改成:

<?php if (!empty($class)) { ?>
    <div class="<?php echo htmlspecialchars($class, ENT_QUOTES, 'UTF-8'); ?>">
<?php } ?>

这样可以消除未定义变量,但只能算防御性修复。还要查清 $class 原本应该由哪里提供,以免掩盖主题或扩展不兼容的问题。

第二步:在 Controller 中正确传入变量

如果模板确实需要 $class,应在负责渲染成功页面的 Controller 中定义它。

不同 OpenCart 版本使用的 Controller 写法可能不同,不能直接混用。

较新的 .tpl 架构通常写成:

$data['class'] = 'checkout-success';

渲染模板时再传入 $data:

$this->response->setOutput(
    $this->load->view('common/success', $data)
);

较早版本可能使用:

$this->data['class'] = 'checkout-success';

具体写法应与当前项目中同一个 Controller 的其他模板变量保持一致。如果文件一直使用 $data[...],就不要改成 $this->data[...]。

如果第 32 行的 $class 本来就是误写,实际应该使用 $column_left、$content_top 或其他布局变量,就应修正变量名,而不是随意给 $class 赋空值。

第三步:切换到默认主题验证

临时切换到与当前 OpenCart 版本配套的默认主题,然后重新执行一次测试订单。

  • 如果默认主题正常,问题基本出在 customTheme、主题修改记录或主题依赖的扩展中。
  • 如果默认主题仍然返回 500,应继续检查支付扩展、Controller、服务器配置和完整错误日志。

也可以直接比较以下两个文件:

catalog/view/theme/customTheme/template/common/success.tpl
catalog/view/theme/default/template/common/success.tpl

重点检查自定义主题是否额外使用了 $class,或者缺少默认模板所需的变量和判断。

除非已经确认两个模板属于相互兼容的 OpenCart 版本,否则不要直接用默认模板覆盖自定义模板。不同版本的模板结构可能并不一致。

第四步:查找真正导致 HTTP 500 的错误

日志中的 Notice 未必是根因。应按照同一请求的发生时间检查:

  • OpenCart 错误日志;
  • PHP error log;
  • IIS 日志和 Failed Request Tracing;
  • FastCGI 相关日志;
  • 信用卡支付扩展自身的日志;
  • 浏览器开发者工具中失败请求的响应内容。

打开浏览器开发者工具的 Network 面板,重新执行测试支付并找到返回 500 的请求,确认失败的到底是:

  • 支付信息提交接口;
  • 支付网关回调接口;
  • 订单确认接口;
  • checkout/success 页面请求。

如果失败的是 AJAX 请求,前端显示 “Internal server error” 的位置可能与后端实际报错的位置不同。

临时调试时可以提高 PHP 日志级别,但不要直接在生产页面显示错误:

log_errors = On
display_errors = Off
error_reporting = E_ALL

修改配置后是否需要重启 IIS、PHP-FPM 或 FastCGI,取决于当前的服务器部署方式。

重点搜索同一时间附近出现的以下错误:

PHP Fatal error
Uncaught Exception
Uncaught Error
Allowed memory size exhausted
Maximum execution time exceeded
FastCGI
Premature end of script

这些错误比 PHP Notice 更可能直接导致 HTTP 500。

第五步:检查最近发生的变化

如果项目之前运行正常,后来突然失败,通常说明代码或运行环境发生了变化。重点核对:

  • PHP 版本是否升级;
  • OpenCart 核心文件是否更新;
  • 自定义主题是否更新;
  • 支付扩展是否更新,或配置是否被修改;
  • OCMOD/VQMod 缓存是否重新生成;
  • 服务器错误级别或自定义错误处理器是否改变;
  • 支付网关的证书、密钥、API 地址是否变化;
  • 文件是否只上传了一部分,造成 Controller 与模板版本不一致。

如果使用 OCMOD,还要检查修改缓存中的实际文件,不能只看源文件。某个扩展可能已经动态修改了 success.tpl 或对应的 Controller。

建议的修复顺序

先备份相关文件,再按以下顺序处理:

  1. 检查 success.tpl 第 32 行,确认 $class 的具体用途;
  2. 对可选变量增加 isset() 或 empty() 判断;
  3. 如果变量必不可少,在对应的 Controller 中明确赋值;
  4. 使用默认主题复测,排除自定义主题不兼容;
  5. 刷新 OCMOD/VQMod 和主题缓存;
  6. 根据失败请求的准确时间,查找 PHP Fatal Error 或支付扩展异常;
  7. 在测试环境完成一笔完整支付,确认订单状态、扣款结果和成功页面都正常。

如果 $class 只是一个可选样式类,模板可以改为:

<?php
$safeClass = isset($class)
    ? htmlspecialchars($class, ENT_QUOTES, 'UTF-8')
    : '';
?>

<div class="<?php echo $safeClass; ?>">
    ...
</div>

如果页面根本不需要这个变量,更合适的做法是删除对 $class 的引用,改用固定、明确的类名:

<div class="checkout-success">
    ...
</div>

注意事项

不要因为页面报错就立刻重复提交信用卡付款。有时付款已经成功,只是成功页面渲染失败,重复提交可能造成重复扣款。每次复测前,都应先到 OpenCart 后台和支付网关核对订单及交易状态。

修复 $class 后,如果 HTTP 500 依然存在,说明这条 Notice 只是伴随错误。接下来应以失败请求对应的 PHP Fatal Error、异常堆栈或 IIS/FastCGI 日志为准,继续排查支付模块和服务器环境。

备注:内容仅供参考。