diff --git a/app/admin/controller/SkuController.php b/app/admin/controller/SkuController.php index 8f420fe..0544f19 100644 --- a/app/admin/controller/SkuController.php +++ b/app/admin/controller/SkuController.php @@ -264,10 +264,8 @@ class SkuController extends BaseController return ''; } - // 1. 读取 docx - $phpWord = WordIOFactory::load($docxPath); + $phpWord = \PhpOffice\PhpWord\IOFactory::load($docxPath); - // 2. 导出 HTML $tmpDir = runtime_path('tmp/' . uniqid()); if (!is_dir($tmpDir)) { mkdir($tmpDir, 0755, true); @@ -275,48 +273,37 @@ class SkuController extends BaseController $tmpHtml = $tmpDir . '/index.html'; - $writer = WordIOFactory::createWriter($phpWord, 'HTML'); + $writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'HTML'); $writer->save($tmpHtml); $html = file_get_contents($tmpHtml); - // 3. 只取 body 内容(关键) - if (preg_match('/]*>(.*?)<\/body>/is', $html, $m)) { - $html = $m[1]; - } - - // 4. 清洗 Word 垃圾样式(关键) - $html = $this->cleanWordHtml($html); - - // 5. 处理图片并上传 OSS + // 1️⃣ 上传图片到 OSS $uploadService = new UploadService(); - $html = preg_replace_callback( '/]+src="([^"]+)"[^>]*>/i', - function ($matches) use ($tmpDir, $uploadService) { - $src = $matches[1]; + function ($m) use ($tmpDir, $uploadService) { + $src = $m[1]; - // Word 导出的是相对路径 if (!str_starts_with($src, 'http')) { - $localImg = $tmpDir . '/' . ltrim($src, '/'); + $localImg = $tmpDir . '/' . ltrim($src, './'); if (is_file($localImg)) { $ossUrl = $uploadService->uploadLocalFile([ - 'path' => $localImg, + 'path' => $localImg, 'scene' => 'desc' ]); - return preg_replace('/src="[^"]+"/', 'src="' . $ossUrl . '"', $matches[0]); + return preg_replace('/src="[^"]+"/', 'src="'.$ossUrl['file_url'].'"', $m[0]); } } - - return $matches[0]; + return $m[0]; }, $html ); - // 6. 清理临时目录 - $this->deleteDir($tmpDir); + // 2️⃣ 关键:HTML 清洗(适配 wangEditor) + $html = $this->cleanWordHtmlForWangEditor($html); - return trim($html); + return $html; } function deleteDir(string $dir): void @@ -325,28 +312,44 @@ class SkuController extends BaseController foreach (scandir($dir) as $file) { if ($file === '.' || $file === '..') continue; $path = $dir . '/' . $file; - is_dir($path) ? deleteDir($path) : @unlink($path); + is_dir($path) ? $this->deleteDir($path) : @unlink($path); } @rmdir($dir); } - function cleanWordHtml(string $html): string + function cleanWordHtmlForWangEditor(string $html): string { - // 移除 Office 命名空间、样式 - $html = preg_replace('/\s*mso-[^:]+:[^;"]+;?/i', '', $html); - $html = preg_replace('/\s*class="[^"]*"/i', '', $html); - $html = preg_replace('/\s*style="[^"]*"/i', '', $html); + // 1. 移除 Word 专属标签 + $html = preg_replace('/.*?<\/o:p>/is', '', $html); + $html = preg_replace('/<\/?xml[^>]*>/i', '', $html); + $html = preg_replace('/<\/?v:[^>]*>/i', '', $html); - // 移除多余标签 - $html = preg_replace('/<(\/?)(html|head|meta|link|span|font|xml|o:p)[^>]*>/i', '', $html); + // 2. 移除 class / style + $html = preg_replace('/\sclass="[^"]*"/i', '', $html); + $html = preg_replace('/\sstyle="[^"]*"/i', '', $html); - // 清理空段落 - $html = preg_replace('/

\s*<\/p>/i', '', $html); + // 3. 清理 span(保留内容) + while (preg_match('/]*>(.*?)<\/span>/is', $html)) { + $html = preg_replace('/]*>(.*?)<\/span>/is', '$1', $html); + } - // 规范段落 - $html = str_replace(['

', '

'], ["

", "

\n"], $html); + // 4. 转换 div → p + $html = preg_replace('/]*>/i', '

', $html); + $html = preg_replace('/<\/div>/i', '

', $html); - return $html; + // 5. img 只保留 src + $html = preg_replace('/]*src="([^"]+)"[^>]*>/i', '', $html); + + // 6. table 清洗 + $html = preg_replace('/]*>/i', '', $html); + $html = preg_replace('/]*>/i', '
', $html); + $html = preg_replace('/]*>/i', '', $html); + + // 7. 去除多余空白 + $html = preg_replace('/\s+/u', ' ', $html); + $html = str_replace(['

', '

'], '', $html); + + return trim($html); }