uploadFile($config['bucket'], $objectKey, $localFullPath); return true; } catch (\Throwable $e) { Log::write('[OSS uploadLocalFileToOss] ' . $e->getMessage() . ' | objectKey=' . $objectKey . ' | local=' . $localFullPath, 'error'); return false; } } /** * 删除 OSS 对象 */ public static function deleteOssObject(string $objectKeyOrUrl): bool { if (!self::isOssEnabled()) { return false; } $config = self::getOssConfig(); $objectKey = self::normalizeOssObjectKey($objectKeyOrUrl); if ($objectKey === '') { return false; } try { $ossClient = new OssClient( $config['accessKeyId'], $config['accessKeySecret'], $config['endpoint'] ); $ossClient->deleteObject($config['bucket'], $objectKey); return true; } catch (\Throwable $e) { return false; } } /** * 把相对路径拼接为完整 OSS URL;已是 http(s) 则原样返回 * 路径$taskInfo['image_url'] = '/uploads/Product/img2img-20260317152818-69b902924548d.png' * Common::ossFullUrl((string)$taskInfo['image_url']); */ public static function ossFullUrl(string $path): string { $path = trim($path); if ($path === '' || stripos($path, 'http://') === 0 || stripos($path, 'https://') === 0) { return $path; } $config = self::getOssConfig(); $host = trim((string)($config['host'] ?? '')); if ($host === '') { return $path; } if (stripos($host, 'http://') !== 0 && stripos($host, 'https://') !== 0) { $host = 'https://' . $host; } return rtrim($host, '/') . '/' . ltrim($path, '/'); } /** * product_template.chinese_description 入库:多页为 JSON 数组字符串,避免数组被写成 "Array"。 * * @param mixed $raw 前端数组、合法 JSON 数组字符串、或历史单段纯文本 */ public static function encodeChineseDescriptionForDb($raw): string { if (is_array($raw)) { return json_encode($raw, JSON_UNESCAPED_UNICODE) ?: '[]'; } if ($raw === null || $raw === '') { return ''; } if (!is_string($raw)) { return ''; } $trimmed = trim($raw); if ($trimmed === '') { return ''; } $decoded = json_decode($trimmed, true); if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { return json_encode($decoded, JSON_UNESCAPED_UNICODE) ?: $trimmed; } return $raw; } /** * 读出给前端:合法 JSON 数组则转 array,否则保持原字符串。 * * @return array|string */ public static function decodeChineseDescriptionForApi($stored) { if ($stored === null || $stored === '') { return []; } if (!is_string($stored)) { return $stored; } $decoded = json_decode($stored, true); if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { return $decoded; } return $stored; } public function _initialize() { if (isset($_SERVER['HTTP_ORIGIN'])) { header('Access-Control-Expose-Headers: __token__');//跨域让客户端获取到 } //跨域检测 check_cors_request(); if (!isset($_COOKIE['PHPSESSID'])) { Config::set('session.id', $this->request->server("HTTP_SID")); } parent::_initialize(); } /** * 加载初始化 * * @ApiParams (name="version", type="string", required=true, description="版本号") * @ApiParams (name="lng", type="string", required=true, description="经度") * @ApiParams (name="lat", type="string", required=true, description="纬度") */ public function init() { if ($version = $this->request->request('version')) { $lng = $this->request->request('lng'); $lat = $this->request->request('lat'); //配置信息 $upload = Config::get('upload'); //如果非服务端中转模式需要修改为中转 if ($upload['storage'] != 'local' && isset($upload['uploadmode']) && $upload['uploadmode'] != 'server') { //临时修改上传模式为服务端中转 set_addon_config($upload['storage'], ["uploadmode" => "server"], false); $upload = \app\common\model\Config::upload(); // 上传信息配置后 Hook::listen("upload_config_init", $upload); $upload = Config::set('upload', array_merge(Config::get('upload'), $upload)); } $upload['cdnurl'] = $upload['cdnurl'] ? $upload['cdnurl'] : cdnurl('', true); $upload['uploadurl'] = preg_match("/^((?:[a-z]+:)?\/\/)(.*)/i", $upload['uploadurl']) ? $upload['uploadurl'] : url($upload['storage'] == 'local' ? '/api/common/upload' : $upload['uploadurl'], '', false, true); $content = [ 'citydata' => Area::getCityFromLngLat($lng, $lat), 'versiondata' => Version::check($version), 'uploaddata' => $upload, 'coverdata' => Config::get("cover"), ]; $this->success('', $content); } else { $this->error(__('Invalid parameters')); } } /** * 上传文件 * @ApiMethod (POST) * @ApiParams (name="file", type="file", required=true, description="文件流") */ public function upload() { Config::set('default_return_type', 'json'); //必须设定cdnurl为空,否则cdnurl函数计算错误 Config::set('upload.cdnurl', ''); $chunkid = $this->request->post("chunkid"); if ($chunkid) { if (!Config::get('upload.chunking')) { $this->error(__('Chunk file disabled')); } $action = $this->request->post("action"); $chunkindex = $this->request->post("chunkindex/d"); $chunkcount = $this->request->post("chunkcount/d"); $filename = $this->request->post("filename"); $method = $this->request->method(true); if ($action == 'merge') { $attachment = null; //合并分片文件 try { $upload = new Upload(); $attachment = $upload->merge($chunkid, $chunkcount, $filename); } catch (UploadException $e) { $this->error($e->getMessage()); } $this->success(__('Uploaded successful'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]); } elseif ($method == 'clean') { //删除冗余的分片文件 try { $upload = new Upload(); $upload->clean($chunkid); } catch (UploadException $e) { $this->error($e->getMessage()); } $this->success(); } else { //上传分片文件 //默认普通上传文件 $file = $this->request->file('file'); try { $upload = new Upload($file); $upload->chunk($chunkid, $chunkindex, $chunkcount); } catch (UploadException $e) { $this->error($e->getMessage()); } $this->success(); } } else { $attachment = null; //默认普通上传文件 $file = $this->request->file('file'); try { $upload = new Upload($file); $attachment = $upload->upload(); } catch (UploadException $e) { $this->error($e->getMessage()); } catch (\Exception $e) { $this->error($e->getMessage()); } $this->success(__('Uploaded successful'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]); } } /** * 验证码 * @ApiParams (name="id", type="string", required=true, description="要生成验证码的标识") * @return \think\Response */ public function captcha($id = "") { \think\Config::set([ 'captcha' => array_merge(config('captcha'), [ 'fontSize' => 44, 'imageH' => 150, 'imageW' => 350, ]) ]); $captcha = new Captcha((array)Config::get('captcha')); return $captcha->entry($id); } }