This commit is contained in:
wangjinlei
2024-12-31 10:28:40 +08:00
parent 145b0ab8a5
commit a54a837670
1179 changed files with 2686 additions and 230376 deletions

View File

@@ -37,6 +37,8 @@ use PhpOffice\PhpWord\Style\Paragraph;
*/
class Html
{
private const RGB_REGEXP = '/^\s*rgb\s*[(]\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*[)]\s*$/';
protected static $listIndex = 0;
protected static $xpath;
@@ -100,7 +102,7 @@ class Html
* parse Inline style of a node.
*
* @param DOMNode $node Node to check on attributes and to compile a style array
* @param array $styles is supplied, the inline style attributes are added to the already existing style
* @param array<string, mixed> $styles is supplied, the inline style attributes are added to the already existing style
*
* @return array
*/
@@ -109,7 +111,9 @@ class Html
if (XML_ELEMENT_NODE == $node->nodeType) {
$attributes = $node->attributes; // get all the attributes(eg: id, class)
$bidi = ($attributes['dir'] ?? '') === 'rtl';
$attributeDir = $attributes->getNamedItem('dir');
$attributeDirValue = $attributeDir ? $attributeDir->nodeValue : '';
$bidi = $attributeDirValue === 'rtl';
foreach ($attributes as $attribute) {
$val = $attribute->value;
switch (strtolower($attribute->name)) {
@@ -142,7 +146,7 @@ class Html
break;
case 'bgcolor':
// tables, rows, cells e.g. <tr bgColor="#FF0000">
$styles['bgColor'] = trim($val, '# ');
$styles['bgColor'] = self::convertRgb($val);
break;
case 'valign':
@@ -157,15 +161,15 @@ class Html
$attributeIdentifier = $attributes->getNamedItem('id');
if ($attributeIdentifier && self::$css) {
$styles = self::parseStyleDeclarations(self::$css->getStyle('#' . $attributeIdentifier->value), $styles);
$styles = self::parseStyleDeclarations(self::$css->getStyle('#' . $attributeIdentifier->nodeValue), $styles);
}
$attributeClass = $attributes->getNamedItem('class');
if ($attributeClass) {
if (self::$css) {
$styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->value), $styles);
$styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->nodeValue), $styles);
}
$styles['className'] = $attributeClass->value;
$styles['className'] = $attributeClass->nodeValue;
}
$attributeStyle = $attributes->getNamedItem('style');
@@ -323,10 +327,10 @@ class Html
return;
}
$inputType = $attributes->getNamedItem('type')->value;
$inputType = $attributes->getNamedItem('type')->nodeValue;
switch ($inputType) {
case 'checkbox':
$checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === 'true' ? true : false;
$checked = ($checked = $attributes->getNamedItem('checked')) && $checked->nodeValue === 'true' ? true : false;
$textrun = $element->addTextRun($styles['paragraph']);
$textrun->addFormField('checkbox')->setValue($checked);
@@ -421,8 +425,8 @@ class Html
}
$attributes = $node->attributes;
if ($attributes->getNamedItem('border') !== null) {
$border = (int) $attributes->getNamedItem('border')->value;
if ($attributes->getNamedItem('border')) {
$border = (int) $attributes->getNamedItem('border')->nodeValue;
$newElement->getStyle()->setBorderSize(Converter::pixelToTwip($border));
}
@@ -720,11 +724,11 @@ class Html
break;
case 'color':
$styles['color'] = trim($value, '#');
$styles['color'] = self::convertRgb($value);
break;
case 'background-color':
$styles['bgColor'] = trim($value, '#');
$styles['bgColor'] = self::convertRgb($value);
break;
case 'line-height':
@@ -898,12 +902,34 @@ class Html
break;
case 'width':
$width = $attribute->value;
// pt
if (false !== strpos($width, 'pt')) {
$width = Converter::pointToPixel((float) str_replace('pt', '', $width));
}
// px
if (false !== strpos($width, 'px')) {
$width = str_replace('px', '', $width);
}
$style['width'] = $width;
$style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX;
break;
case 'height':
$height = $attribute->value;
// pt
if (false !== strpos($height, 'pt')) {
$height = Converter::pointToPixel((float) str_replace('pt', '', $height));
}
// px
if (false !== strpos($height, 'px')) {
$height = str_replace('px', '', $height);
}
$style['height'] = $height;
$style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX;
@@ -1130,7 +1156,11 @@ class Html
}
$styles['font'] = self::parseInlineStyle($node, $styles['font']);
if (strpos($target, '#') === 0) {
if (empty($target)) {
$target = '#';
}
if (strpos($target, '#') === 0 && strlen($target) > 1) {
return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true);
}
@@ -1170,4 +1200,13 @@ class Html
// - line - that is a shape, has different behaviour
// - repeated text, e.g. underline "_", because of unpredictable line wrapping
}
private static function convertRgb(string $rgb): string
{
if (preg_match(self::RGB_REGEXP, $rgb, $matches) === 1) {
return sprintf('%02X%02X%02X', $matches[1], $matches[2], $matches[3]);
}
return trim($rgb, '# ');
}
}

View File

@@ -34,6 +34,9 @@ class PasswordEncoder
const ALGORITHM_MAC = 'MAC';
const ALGORITHM_HMAC = 'HMAC';
private const ALL_ONE_BITS = (PHP_INT_SIZE > 4) ? 0xFFFFFFFF : -1;
private const HIGH_ORDER_BIT = (PHP_INT_SIZE > 4) ? 0x80000000 : PHP_INT_MIN;
/**
* Mapping between algorithm name and algorithm ID.
*
@@ -128,7 +131,7 @@ class PasswordEncoder
// build low-order word and hig-order word and combine them
$combinedKey = self::buildCombinedKey($byteChars);
// build reversed hexadecimal string
$hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT);
$hex = str_pad(strtoupper(dechex($combinedKey & self::ALL_ONE_BITS)), 8, '0', \STR_PAD_LEFT);
$reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1];
$generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8');
@@ -232,10 +235,10 @@ class PasswordEncoder
*/
private static function int32($value)
{
$value = ($value & 0xFFFFFFFF);
$value = $value & self::ALL_ONE_BITS;
if ($value & 0x80000000) {
$value = -((~$value & 0xFFFFFFFF) + 1);
if ($value & self::HIGH_ORDER_BIT) {
$value = -((~$value & self::ALL_ONE_BITS) + 1);
}
return $value;

View File

@@ -61,7 +61,15 @@ class XMLReader
}
$zip = new ZipArchive();
$zip->open($zipFile);
$openStatus = $zip->open($zipFile);
if ($openStatus !== true) {
/**
* Throw an exception since making further calls on the ZipArchive would cause a fatal error.
* This prevents fatal errors on corrupt archives and attempts to open old "doc" files.
*/
throw new Exception("The archive failed to load with the following error code: $openStatus");
}
$content = $zip->getFromName(ltrim($xmlFile, '/'));
$zip->close();

View File

@@ -20,6 +20,7 @@ namespace PhpOffice\PhpWord\Shared;
use PclZip;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\Settings;
use Throwable;
/**
* ZipArchive wrapper.
@@ -162,13 +163,16 @@ class ZipArchive
* Close the active archive.
*
* @return bool
*
* @codeCoverageIgnore Can't find any test case. Uncomment when found.
*/
public function close()
{
if (!$this->usePclzip) {
if ($this->zip->close() === false) {
try {
$result = @$this->zip->close();
} catch (Throwable $e) {
$result = false;
}
if ($result === false) {
throw new Exception("Could not close zip file {$this->filename}: ");
}
}