1
This commit is contained in:
@@ -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, '# ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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}: ");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user