完善第三方签署
This commit is contained in:
+55
-18
@@ -17,25 +17,39 @@ public static class DocxTemplateProcessor
|
||||
/// </summary>
|
||||
public static List<string> ExtractVariableCodes(byte[] docx)
|
||||
{
|
||||
using var input = new MemoryStream(docx);
|
||||
using var archive = new global::System.IO.Compression.ZipArchive(
|
||||
input,
|
||||
global::System.IO.Compression.ZipArchiveMode.Read);
|
||||
var codes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => IsWordTextXml(entry.FullName)))
|
||||
ValidateDocxHeader(docx);
|
||||
try
|
||||
{
|
||||
using var stream = entry.Open();
|
||||
var document = global::System.Xml.Linq.XDocument.Load(stream);
|
||||
foreach (var paragraph in document.Descendants(WordNamespace + "p"))
|
||||
{
|
||||
var text = string.Concat(paragraph.Descendants(WordNamespace + "t").Select(node => node.Value));
|
||||
foreach (global::System.Text.RegularExpressions.Match match in PlaceholderRegex.Matches(text))
|
||||
codes.Add(match.Groups["code"].Value.Trim());
|
||||
}
|
||||
}
|
||||
using var input = new MemoryStream(docx);
|
||||
using var archive = new global::System.IO.Compression.ZipArchive(
|
||||
input,
|
||||
global::System.IO.Compression.ZipArchiveMode.Read);
|
||||
if (archive.GetEntry("word/document.xml") == null)
|
||||
throw Oops.Bah("上传文件不是有效的 DOCX 文档,请使用 Word 或 WPS 另存为“Word 文档(*.docx)”后重新上传");
|
||||
|
||||
return codes.OrderBy(code => code).ToList();
|
||||
var codes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var entry in archive.Entries.Where(entry => IsWordTextXml(entry.FullName)))
|
||||
{
|
||||
using var stream = entry.Open();
|
||||
var document = global::System.Xml.Linq.XDocument.Load(stream);
|
||||
foreach (var paragraph in document.Descendants(WordNamespace + "p"))
|
||||
{
|
||||
var text = string.Concat(paragraph.Descendants(WordNamespace + "t").Select(node => node.Value));
|
||||
foreach (global::System.Text.RegularExpressions.Match match in PlaceholderRegex.Matches(text))
|
||||
codes.Add(match.Groups["code"].Value.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
return codes.OrderBy(code => code).ToList();
|
||||
}
|
||||
catch (global::System.IO.InvalidDataException)
|
||||
{
|
||||
throw Oops.Bah("DOCX 文件结构已经损坏或上传不完整,请重新另存为 DOCX 后上传");
|
||||
}
|
||||
catch (global::System.Xml.XmlException)
|
||||
{
|
||||
throw Oops.Bah("DOCX 文件内部内容损坏,Word 可以尝试修复该文件;请修复并重新另存为 DOCX 后上传");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,6 +57,7 @@ public static class DocxTemplateProcessor
|
||||
/// </summary>
|
||||
public static byte[] Render(byte[] docx, IReadOnlyDictionary<string, string> values)
|
||||
{
|
||||
ValidateDocxHeader(docx);
|
||||
using var input = new MemoryStream(docx);
|
||||
using var archive = new global::System.IO.Compression.ZipArchive(
|
||||
input,
|
||||
@@ -157,4 +172,26 @@ public static class DocxTemplateProcessor
|
||||
|| entryName.StartsWith("word/footer", StringComparison.OrdinalIgnoreCase))
|
||||
&& entryName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据文件头识别真实格式,避免只修改扩展名的旧版 DOC 在解压时变成系统异常。
|
||||
/// </summary>
|
||||
private static void ValidateDocxHeader(byte[] docx)
|
||||
{
|
||||
if (docx == null || docx.Length < 4)
|
||||
throw Oops.Bah("上传的 DOCX 文件为空或上传不完整,请重新选择文件上传");
|
||||
|
||||
// 旧版 Word 97-2003 二进制 DOC 使用 OLE Compound File 文件头:D0 CF 11 E0。
|
||||
if (docx[0] == 0xD0
|
||||
&& docx[1] == 0xCF
|
||||
&& docx[2] == 0x11
|
||||
&& docx[3] == 0xE0)
|
||||
{
|
||||
throw Oops.Bah("上传文件实际是旧版 DOC 格式,不能直接修改后缀名;请使用 Word 或 WPS 另存为“Word 文档(*.docx)”后重新上传");
|
||||
}
|
||||
|
||||
// DOCX 是 Open XML ZIP 包,正常文件以 PK 开头。
|
||||
if (docx[0] != 0x50 || docx[1] != 0x4B)
|
||||
throw Oops.Bah("上传文件的真实格式不是 DOCX,请使用 Word 或 WPS 另存为“Word 文档(*.docx)”后重新上传");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user