From 0dc9ca86f794ea85a95f97093f5afd956b53108c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 16 Dec 2025 14:34:09 +0800 Subject: [PATCH] =?UTF-8?q?word=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/SkuController.php | 112 ++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/app/admin/controller/SkuController.php b/app/admin/controller/SkuController.php index 4079c74..bffb8cf 100644 --- a/app/admin/controller/SkuController.php +++ b/app/admin/controller/SkuController.php @@ -255,13 +255,121 @@ class SkuController extends BaseController return true; } + /** + * docx 转 HTML(富文本可用,图片上传 OSS) + */ + function docxToHtmlWithImages(string $docxPath): string + { + if (!is_file($docxPath)) { + return ''; + } + + // 1. 加载 docx + $phpWord = WordIOFactory::load($docxPath, 'Word2007'); + + // 2. 临时目录(非常重要) + $tmpDir = runtime_path('tmp/' . uniqid()); + if (!is_dir($tmpDir)) { + mkdir($tmpDir, 0755, true); + } + + $tmpHtml = $tmpDir . '/index.html'; + + // 3. 导出 HTML + $writer = WordIOFactory::createWriter($phpWord, 'HTML'); + $writer->save($tmpHtml); + + $html = file_get_contents($tmpHtml); + + // 4. 清洗 Word 垃圾 HTML(关键) + $html = $this->cleanWordHtml($html); + + $uploadService = new UploadService(); + + // 5. 处理图片 + $html = preg_replace_callback( + '/]+src="([^"]+)"[^>]*>/i', + function ($matches) use ($tmpDir, $uploadService) { + $src = $matches[1]; + + // 只处理本地图片 + if (preg_match('#^(http|https|data:)#i', $src)) { + return $matches[0]; + } + + $localImg = realpath($tmpDir . '/' . $src); + if (!$localImg || !is_file($localImg)) { + return $matches[0]; + } + + // 上传 OSS + $ossUrl = $uploadService->uploadLocalFile([ + 'path' => $localImg, + 'scene' => 'desc' + ]); + + return str_replace($src, $ossUrl, $matches[0]); + }, + $html + ); + + // 6. 清理临时目录 + $this->deleteDir($tmpDir); + + return trim($html); + } + + function deleteDir(string $dir) + { + if (!is_dir($dir)) return; + foreach (scandir($dir) as $file) { + if ($file === '.' || $file === '..') continue; + $path = $dir . '/' . $file; + is_dir($path) ? $this->deleteDir($path) : unlink($path); + } + rmdir($dir); + } + + function cleanWordHtml(string $html): string + { + // 删除 Word 注释 + $html = preg_replace('//', '', $html); + + // 删除 style / meta / link + $html = preg_replace('/<(style|meta|link)[^>]*>.*?<\/\1>/is', '', $html); + + // 删除 xml 标签 + $html = preg_replace('/.*?<\/xml>/is', '', $html); + + // 删除 mso-xxx 样式 + $html = preg_replace('/\s*mso-[^:]+:[^;"]+;?/i', '', $html); + + // 清理 class="Mso..." + $html = preg_replace('/class="Mso[^"]*"/i', '', $html); + + // 删除空 span + $html = preg_replace('/]*>\s*<\/span>/i', '', $html); + + // 删除 Office 条件注释 + $html = preg_replace('/.*?/is', '', $html); + + // 只保留 body 内容 + if (preg_match('/]*>(.*?)<\/body>/is', $html, $m)) { + $html = $m[1]; + } + + return $html; + } + + + /** * docx 转 HTML(自动上传图片到 OSS) * * @param string $docxPath docx 文件绝对路径 * @return string HTML */ - function docxToHtmlWithImages(string $docxPath): string + /*function docxToHtmlWithImages(string $docxPath): string { if (!is_file($docxPath)) { return ''; @@ -307,7 +415,7 @@ class SkuController extends BaseController @unlink($tmpHtml); return $html; - } + }*/ private function extractImages($sheet): array {