Files
wms-app/scripts/adjust_docx_whitespace.php
T
2026-08-17 13:12:07 +07:00

144 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
if ($argc !== 2) {
fwrite(STDERR, "Usage: php adjust_docx_whitespace.php <document.docx>\n");
exit(2);
}
$path = $argv[1];
$wordNs = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
$zip = new ZipArchive();
if ($zip->open($path) !== true) {
throw new RuntimeException("Cannot open DOCX: {$path}");
}
$documentXml = $zip->getFromName('word/document.xml');
if ($documentXml === false) {
throw new RuntimeException('word/document.xml is missing');
}
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = false;
if (!$doc->loadXML($documentXml)) {
throw new RuntimeException('word/document.xml is invalid');
}
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('w', $wordNs);
function attr(DOMElement $element, string $name, string $value, string $ns): void
{
$element->setAttributeNS($ns, 'w:' . $name, $value);
}
function child(DOMDocument $doc, DOMElement $parent, string $localName, string $ns): DOMElement
{
foreach ($parent->childNodes as $node) {
if ($node instanceof DOMElement && $node->namespaceURI === $ns && $node->localName === $localName) {
return $node;
}
}
$element = $doc->createElementNS($ns, 'w:' . $localName);
$parent->appendChild($element);
return $element;
}
foreach ($xpath->query('//w:body/w:p | //w:body/w:tbl//w:p') as $paragraph) {
if (!$paragraph instanceof DOMElement) {
continue;
}
$text = '';
foreach ($xpath->query('.//w:t', $paragraph) as $textNode) {
$text .= $textNode->textContent;
}
$text = trim(preg_replace('/\s+/u', ' ', $text) ?? '');
$pPrNode = $xpath->query('./w:pPr', $paragraph)->item(0);
if (!$pPrNode instanceof DOMElement) {
$pPrNode = $doc->createElementNS($wordNs, 'w:pPr');
$paragraph->insertBefore($pPrNode, $paragraph->firstChild);
}
$spacing = child($doc, $pPrNode, 'spacing', $wordNs);
$before = '0';
$after = '30';
$line = '320';
if ($text === '') {
$after = '20';
$line = '120';
} elseif (preg_match('/^[1-7]\.\s/u', $text)) {
$before = '120';
$after = '45';
$line = '330';
} elseif (preg_match('/^[1-7]\.\d\s/u', $text)) {
$before = '70';
$after = '30';
$line = '320';
} elseif (str_starts_with($text, '•')) {
$after = '15';
$line = '310';
} elseif (str_starts_with($text, 'วันที่ 5 มกราคม')) {
$before = '40';
$after = '100';
$line = '330';
} elseif (str_starts_with($text, 'เรื่อง') || str_starts_with($text, 'เรียน')) {
$after = '55';
$line = '330';
} elseif (str_starts_with($text, 'ลงชื่อ')) {
$before = '160';
$after = '10';
$line = '310';
} elseif (str_starts_with($text, '(') || str_starts_with($text, 'ตำแหน่ง') || str_starts_with($text, 'วันที่ _') || str_starts_with($text, 'ผู้มีอำนาจ')) {
$after = '10';
$line = '310';
} elseif (str_starts_with($text, 'บริษัท บี.อาร์.เอ็น.') || str_starts_with($text, 'เอกสารฉบับนี้') || str_starts_with($text, 'ผลส่งมอบประกอบ') || str_starts_with($text, 'การเปลี่ยนแปลง') || str_starts_with($text, 'จึงจัดทำ')) {
$after = '55';
$line = '330';
}
attr($spacing, 'before', $before, $wordNs);
attr($spacing, 'after', $after, $wordNs);
attr($spacing, 'line', $line, $wordNs);
attr($spacing, 'lineRule', 'auto', $wordNs);
}
foreach ($xpath->query('//w:sectPr/w:pgMar') as $margin) {
if (!$margin instanceof DOMElement) {
continue;
}
attr($margin, 'top', '850', $wordNs);
attr($margin, 'bottom', '850', $wordNs);
attr($margin, 'left', '1080', $wordNs);
attr($margin, 'right', '1080', $wordNs);
attr($margin, 'header', '400', $wordNs);
attr($margin, 'footer', '400', $wordNs);
}
foreach ($xpath->query('//w:tbl/w:tblPr') as $tableProperties) {
if (!$tableProperties instanceof DOMElement) {
continue;
}
$margins = child($doc, $tableProperties, 'tblCellMar', $wordNs);
foreach (['top' => '45', 'left' => '70', 'bottom' => '45', 'right' => '70'] as $side => $width) {
$edge = child($doc, $margins, $side, $wordNs);
attr($edge, 'w', $width, $wordNs);
attr($edge, 'type', 'dxa', $wordNs);
}
}
$updatedXml = $doc->saveXML();
if ($updatedXml === false) {
throw new RuntimeException('Cannot serialize adjusted document XML');
}
if (!$zip->addFromString('word/document.xml', $updatedXml)) {
throw new RuntimeException('Cannot update word/document.xml');
}
$zip->close();
echo $path . PHP_EOL;