|
|
|
|
@ -439,49 +439,82 @@ class CourseController extends BaseController
|
|
|
|
|
$generate = !empty($all['generate']);
|
|
|
|
|
$path = config('filesystems.disks.public.root') . '/course_qrcode/' . $courseId . '.png';
|
|
|
|
|
$url = config('filesystems.disks.public.url') . '/course_qrcode/' . $courseId . '.png';
|
|
|
|
|
$debugFile = storage_path('logs/qrcode_debug.log');
|
|
|
|
|
$debug = function ($msg) use ($debugFile, $courseId) {
|
|
|
|
|
@file_put_contents(
|
|
|
|
|
$debugFile,
|
|
|
|
|
date('Y-m-d H:i:s') . " [{$courseId}] {$msg}\n",
|
|
|
|
|
FILE_APPEND
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
$debug('hit generate=' . ($generate ? '1' : '0') . ' sapi=' . PHP_SAPI);
|
|
|
|
|
|
|
|
|
|
// 已有文件直接返回,避免走微信/旧 OPcache 方法签名问题
|
|
|
|
|
// 已有文件直接返回
|
|
|
|
|
clearstatcache(true, $path);
|
|
|
|
|
if (is_file($path)) {
|
|
|
|
|
$debug('return existing file');
|
|
|
|
|
return $this->success($url);
|
|
|
|
|
}
|
|
|
|
|
if (!$generate) {
|
|
|
|
|
$debug('no file and generate=0');
|
|
|
|
|
return $this->success('');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$courseModel = new Course();
|
|
|
|
|
// 兼容 FPM OPcache 未刷新时旧方法只有 1 个参数(PHP8 多传参会直接 500)
|
|
|
|
|
$ref = new \ReflectionMethod($courseModel, 'getCourseQrcode');
|
|
|
|
|
if ($ref->getNumberOfParameters() >= 2) {
|
|
|
|
|
$result = $courseModel->getCourseQrcode($courseId, true);
|
|
|
|
|
} else {
|
|
|
|
|
$result = $courseModel->getCourseQrcode($courseId);
|
|
|
|
|
// 生成逻辑内联在控制器,避免模型 OPcache/签名不一致
|
|
|
|
|
$appId = (string) config('app.applet_appid');
|
|
|
|
|
$secret = (string) config('app.applet_secret');
|
|
|
|
|
if ($appId === '' || $secret === '') {
|
|
|
|
|
$debug('missing appid/secret');
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '二维码生成失败:未配置小程序 APPID/SECRET']);
|
|
|
|
|
}
|
|
|
|
|
clearstatcache(true, $path);
|
|
|
|
|
if (empty($result) && is_file($path)) {
|
|
|
|
|
$result = $url;
|
|
|
|
|
|
|
|
|
|
$debug('request wechat app_code');
|
|
|
|
|
$app = Factory::miniProgram([
|
|
|
|
|
'app_id' => $appId,
|
|
|
|
|
'secret' => $secret,
|
|
|
|
|
]);
|
|
|
|
|
$tmp = $app->app_code->get('packages/course/detail?id=' . $courseId, [
|
|
|
|
|
'env_version' => 'release',
|
|
|
|
|
]);
|
|
|
|
|
$content = $tmp instanceof \EasyWeChat\Kernel\Http\StreamResponse
|
|
|
|
|
? $tmp->getBodyContents()
|
|
|
|
|
: (string) $tmp;
|
|
|
|
|
$debug('wechat bytes=' . strlen($content));
|
|
|
|
|
|
|
|
|
|
if ($content === '' || strpos(ltrim($content), '{') === 0) {
|
|
|
|
|
$debug('invalid wechat body=' . substr($content, 0, 200));
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '二维码生成失败:微信接口返回异常']);
|
|
|
|
|
}
|
|
|
|
|
if (empty($result)) {
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '二维码生成失败,请检查微信配置或缓存后重试']);
|
|
|
|
|
|
|
|
|
|
$dir = dirname($path);
|
|
|
|
|
if (!is_dir($dir)) {
|
|
|
|
|
mkdir($dir, 0755, true);
|
|
|
|
|
}
|
|
|
|
|
return $this->success($result);
|
|
|
|
|
if (file_put_contents($path, $content) === false) {
|
|
|
|
|
$debug('write file failed');
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '二维码生成失败:写入文件失败']);
|
|
|
|
|
}
|
|
|
|
|
@chmod($path, 0644);
|
|
|
|
|
$debug('saved ok');
|
|
|
|
|
return $this->success($url);
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
\Log::error('courses/qrcode failed', [
|
|
|
|
|
'id' => $courseId,
|
|
|
|
|
'generate' => $generate,
|
|
|
|
|
'message' => $e->getMessage(),
|
|
|
|
|
'file' => $e->getFile(),
|
|
|
|
|
'line' => $e->getLine(),
|
|
|
|
|
]);
|
|
|
|
|
// 生成过程异常时,若磁盘已有文件仍返回成功
|
|
|
|
|
$safeMsg = preg_replace('/[^\x09\x0A\x0D\x20-\x7E\x{4e00}-\x{9fff}]/u', '?', $e->getMessage());
|
|
|
|
|
$debug('exception: ' . $safeMsg);
|
|
|
|
|
try {
|
|
|
|
|
\Log::error('courses/qrcode failed', [
|
|
|
|
|
'id' => $courseId,
|
|
|
|
|
'message' => $safeMsg,
|
|
|
|
|
]);
|
|
|
|
|
} catch (\Throwable $ignored) {
|
|
|
|
|
}
|
|
|
|
|
clearstatcache(true, $path);
|
|
|
|
|
if (is_file($path)) {
|
|
|
|
|
return $this->success($url);
|
|
|
|
|
}
|
|
|
|
|
return $this->fail([
|
|
|
|
|
ResponseCode::ERROR_BUSINESS,
|
|
|
|
|
'二维码生成失败: ' . $e->getMessage(),
|
|
|
|
|
'二维码生成失败: ' . ($safeMsg ?: '未知错误'),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|