1
This commit is contained in:
79
vendor/phpoffice/phpword/src/PhpWord/Shared/AbstractEnum.php
vendored
Normal file
79
vendor/phpoffice/phpword/src/PhpWord/Shared/AbstractEnum.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
|
||||
abstract class AbstractEnum
|
||||
{
|
||||
private static $constCacheArray;
|
||||
|
||||
private static function getConstants()
|
||||
{
|
||||
if (self::$constCacheArray == null) {
|
||||
self::$constCacheArray = [];
|
||||
}
|
||||
$calledClass = static::class;
|
||||
if (!array_key_exists($calledClass, self::$constCacheArray)) {
|
||||
$reflect = new ReflectionClass($calledClass);
|
||||
self::$constCacheArray[$calledClass] = $reflect->getConstants();
|
||||
}
|
||||
|
||||
return self::$constCacheArray[$calledClass];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all values for this enum.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function values()
|
||||
{
|
||||
return array_values(self::getConstants());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true the value is valid for this enum.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return bool true if value is valid
|
||||
*/
|
||||
public static function isValid($value)
|
||||
{
|
||||
$values = array_values(self::getConstants());
|
||||
|
||||
return in_array($value, $values, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the value passed is a valid value.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public static function validate($value): void
|
||||
{
|
||||
if (!self::isValid($value)) {
|
||||
$calledClass = static::class;
|
||||
$values = array_values(self::getConstants());
|
||||
|
||||
throw new InvalidArgumentException("$value is not a valid value for $calledClass, possible values are " . implode(', ', $values));
|
||||
}
|
||||
}
|
||||
}
|
||||
455
vendor/phpoffice/phpword/src/PhpWord/Shared/Converter.php
vendored
Normal file
455
vendor/phpoffice/phpword/src/PhpWord/Shared/Converter.php
vendored
Normal file
@@ -0,0 +1,455 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
/**
|
||||
* Common converter functions.
|
||||
*/
|
||||
class Converter
|
||||
{
|
||||
const INCH_TO_CM = 2.54;
|
||||
const INCH_TO_TWIP = 1440;
|
||||
const INCH_TO_PIXEL = 96;
|
||||
const INCH_TO_POINT = 72;
|
||||
const INCH_TO_PICA = 6;
|
||||
const PIXEL_TO_EMU = 9525;
|
||||
const DEGREE_TO_ANGLE = 60000;
|
||||
|
||||
/**
|
||||
* Convert centimeter to twip.
|
||||
*
|
||||
* @param float $centimeter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cmToTwip($centimeter = 1)
|
||||
{
|
||||
return $centimeter / self::INCH_TO_CM * self::INCH_TO_TWIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeter to inch.
|
||||
*
|
||||
* @param float $centimeter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cmToInch($centimeter = 1)
|
||||
{
|
||||
return $centimeter / self::INCH_TO_CM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeter to pixel.
|
||||
*
|
||||
* @param float $centimeter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cmToPixel($centimeter = 1)
|
||||
{
|
||||
return $centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeter to point.
|
||||
*
|
||||
* @param float $centimeter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cmToPoint($centimeter = 1)
|
||||
{
|
||||
return $centimeter / self::INCH_TO_CM * self::INCH_TO_POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeter to EMU.
|
||||
*
|
||||
* @param float $centimeter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cmToEmu($centimeter = 1)
|
||||
{
|
||||
return round($centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inch to twip.
|
||||
*
|
||||
* @param float $inch
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function inchToTwip($inch = 1)
|
||||
{
|
||||
return $inch * self::INCH_TO_TWIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inch to centimeter.
|
||||
*
|
||||
* @param float $inch
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function inchToCm($inch = 1)
|
||||
{
|
||||
return $inch * self::INCH_TO_CM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inch to pixel.
|
||||
*
|
||||
* @param float $inch
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function inchToPixel($inch = 1)
|
||||
{
|
||||
return $inch * self::INCH_TO_PIXEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inch to point.
|
||||
*
|
||||
* @param float $inch
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function inchToPoint($inch = 1)
|
||||
{
|
||||
return $inch * self::INCH_TO_POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inch to EMU.
|
||||
*
|
||||
* @param float $inch
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function inchToEmu($inch = 1)
|
||||
{
|
||||
return round($inch * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixel to twip.
|
||||
*
|
||||
* @param float $pixel
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pixelToTwip($pixel = 1)
|
||||
{
|
||||
return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_TWIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixel to centimeter.
|
||||
*
|
||||
* @param float $pixel
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pixelToCm($pixel = 1)
|
||||
{
|
||||
return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_CM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixel to point.
|
||||
*
|
||||
* @param float $pixel
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pixelToPoint($pixel = 1)
|
||||
{
|
||||
return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixel to EMU.
|
||||
*
|
||||
* @param float $pixel
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function pixelToEmu($pixel = 1)
|
||||
{
|
||||
return round($pixel * self::PIXEL_TO_EMU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert point to twip unit.
|
||||
*
|
||||
* @param float $point
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pointToTwip($point = 1)
|
||||
{
|
||||
return $point / self::INCH_TO_POINT * self::INCH_TO_TWIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert point to pixel.
|
||||
*
|
||||
* @param float $point
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pointToPixel($point = 1)
|
||||
{
|
||||
return $point / self::INCH_TO_POINT * self::INCH_TO_PIXEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert point to EMU.
|
||||
*
|
||||
* @param float $point
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pointToEmu($point = 1)
|
||||
{
|
||||
return round($point / self::INCH_TO_POINT * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert point to cm.
|
||||
*
|
||||
* @param float $point
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pointToCm($point = 1)
|
||||
{
|
||||
return $point / self::INCH_TO_POINT * self::INCH_TO_CM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert EMU to pixel.
|
||||
*
|
||||
* @param float $emu
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function emuToPixel($emu = 1)
|
||||
{
|
||||
return round($emu / self::PIXEL_TO_EMU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pica to point.
|
||||
*
|
||||
* @param float $pica
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function picaToPoint($pica = 1)
|
||||
{
|
||||
return $pica / self::INCH_TO_PICA * self::INCH_TO_POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert degree to angle.
|
||||
*
|
||||
* @param float $degree
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function degreeToAngle($degree = 1)
|
||||
{
|
||||
return (int) round($degree * self::DEGREE_TO_ANGLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert angle to degrees.
|
||||
*
|
||||
* @param float $angle
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function angleToDegree($angle = 1)
|
||||
{
|
||||
return round($angle / self::DEGREE_TO_ANGLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert colorname as string to RGB.
|
||||
*
|
||||
* @param string $value color name
|
||||
*
|
||||
* @return string color as hex RGB string, or original value if unknown
|
||||
*/
|
||||
public static function stringToRgb($value)
|
||||
{
|
||||
switch ($value) {
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW:
|
||||
return 'FFFF00';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGREEN:
|
||||
return '90EE90';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_CYAN:
|
||||
return '00FFFF';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_MAGENTA:
|
||||
return 'FF00FF';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLUE:
|
||||
return '0000FF';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_RED:
|
||||
return 'FF0000';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKBLUE:
|
||||
return '00008B';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKCYAN:
|
||||
return '008B8B';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN:
|
||||
return '006400';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA:
|
||||
return '8B008B';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKRED:
|
||||
return '8B0000';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKYELLOW:
|
||||
return '8B8B00';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGRAY:
|
||||
return 'A9A9A9';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGRAY:
|
||||
return 'D3D3D3';
|
||||
case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLACK:
|
||||
return '000000';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML hexadecimal to RGB.
|
||||
*
|
||||
* @param string $value HTML Color in hexadecimal
|
||||
*
|
||||
* @return array Value in RGB
|
||||
*/
|
||||
public static function htmlToRgb($value)
|
||||
{
|
||||
if ($value[0] == '#') {
|
||||
$value = substr($value, 1);
|
||||
} else {
|
||||
$value = self::stringToRgb($value);
|
||||
}
|
||||
|
||||
if (strlen($value) == 6) {
|
||||
[$red, $green, $blue] = [$value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]];
|
||||
} elseif (strlen($value) == 3) {
|
||||
[$red, $green, $blue] = [$value[0] . $value[0], $value[1] . $value[1], $value[2] . $value[2]];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$red = ctype_xdigit($red) ? hexdec($red) : 0;
|
||||
$green = ctype_xdigit($green) ? hexdec($green) : 0;
|
||||
$blue = ctype_xdigit($blue) ? hexdec($blue) : 0;
|
||||
|
||||
return [$red, $green, $blue];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in CSS format (eg. 10px, 10px, ...) to points.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cssToPoint($value)
|
||||
{
|
||||
if ($value == '0') {
|
||||
return 0;
|
||||
}
|
||||
$matches = [];
|
||||
if (preg_match('/^[+-]?([0-9]+\.?[0-9]*)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches)) {
|
||||
$size = $matches[1];
|
||||
$unit = $matches[2];
|
||||
|
||||
switch ($unit) {
|
||||
case 'pt':
|
||||
return $size;
|
||||
case 'px':
|
||||
return self::pixelToPoint($size);
|
||||
case 'cm':
|
||||
return self::cmToPoint($size);
|
||||
case 'mm':
|
||||
return self::cmToPoint($size / 10);
|
||||
case 'in':
|
||||
return self::inchToPoint($size);
|
||||
case 'pc':
|
||||
return self::picaToPoint($size);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in CSS format (eg. 10px, 10px, ...) to twips.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cssToTwip($value)
|
||||
{
|
||||
return self::pointToTwip(self::cssToPoint($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in CSS format (eg. 10px, 10px, ...) to pixel.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cssToPixel($value)
|
||||
{
|
||||
return self::pointToPixel(self::cssToPoint($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in CSS format (eg. 10px, 10px, ...) to cm.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cssToCm($value)
|
||||
{
|
||||
return self::pointToCm(self::cssToPoint($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in CSS format (eg. 10px, 10px, ...) to emu.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function cssToEmu($value)
|
||||
{
|
||||
return self::pointToEmu(self::cssToPoint($value));
|
||||
}
|
||||
}
|
||||
263
vendor/phpoffice/phpword/src/PhpWord/Shared/Drawing.php
vendored
Normal file
263
vendor/phpoffice/phpword/src/PhpWord/Shared/Drawing.php
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
/**
|
||||
* Drawing.
|
||||
*/
|
||||
class Drawing
|
||||
{
|
||||
const DPI_96 = 96;
|
||||
|
||||
/**
|
||||
* Convert pixels to EMU.
|
||||
*
|
||||
* @param int $pValue Value in pixels
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function pixelsToEmu($pValue = 0)
|
||||
{
|
||||
return round($pValue * 9525);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert EMU to pixels.
|
||||
*
|
||||
* @param int $pValue Value in EMU
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function emuToPixels($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return round($pValue / 9525);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixels to points.
|
||||
*
|
||||
* @param int $pValue Value in pixels
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pixelsToPoints($pValue = 0)
|
||||
{
|
||||
return $pValue * 0.67777777;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert points width to centimeters.
|
||||
*
|
||||
* @param int $pValue Value in points
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pointsToCentimeters($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (($pValue * 1.333333333) / self::DPI_96) * 2.54;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert points width to pixels.
|
||||
*
|
||||
* @param int $pValue Value in points
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pointsToPixels($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $pValue * 1.333333333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixels to centimeters.
|
||||
*
|
||||
* @param int $pValue Value in pixels
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pixelsToCentimeters($pValue = 0)
|
||||
{
|
||||
//return $pValue * 0.028;
|
||||
return ($pValue / self::DPI_96) * 2.54;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeters width to pixels.
|
||||
*
|
||||
* @param int $pValue Value in centimeters
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function centimetersToPixels($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($pValue / 2.54) * self::DPI_96;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert degrees to angle.
|
||||
*
|
||||
* @param int $pValue Degrees
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function degreesToAngle($pValue = 0)
|
||||
{
|
||||
return (int) round($pValue * 60000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert angle to degrees.
|
||||
*
|
||||
* @param int $pValue Angle
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function angleToDegrees($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return round($pValue / 60000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeters width to twips.
|
||||
*
|
||||
* @param int $pValue
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function centimetersToTwips($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $pValue * 566.928;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert twips width to centimeters.
|
||||
*
|
||||
* @param int $pValue
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function twipsToCentimeters($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $pValue / 566.928;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inches width to twips.
|
||||
*
|
||||
* @param int $pValue
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function inchesToTwips($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $pValue * 1440;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert twips width to inches.
|
||||
*
|
||||
* @param int $pValue
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function twipsToInches($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $pValue / 1440;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert twips width to pixels.
|
||||
*
|
||||
* @param int $pValue
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function twipsToPixels($pValue = 0)
|
||||
{
|
||||
if ($pValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return round($pValue / 15.873984);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML hexadecimal to RGB.
|
||||
*
|
||||
* @param string $pValue HTML Color in hexadecimal
|
||||
*
|
||||
* @return array|false Value in RGB
|
||||
*/
|
||||
public static function htmlToRGB($pValue)
|
||||
{
|
||||
if ($pValue[0] == '#') {
|
||||
$pValue = substr($pValue, 1);
|
||||
}
|
||||
|
||||
if (strlen($pValue) == 6) {
|
||||
[$colorR, $colorG, $colorB] = [$pValue[0] . $pValue[1], $pValue[2] . $pValue[3], $pValue[4] . $pValue[5]];
|
||||
} elseif (strlen($pValue) == 3) {
|
||||
[$colorR, $colorG, $colorB] = [$pValue[0] . $pValue[0], $pValue[1] . $pValue[1], $pValue[2] . $pValue[2]];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$colorR = hexdec($colorR);
|
||||
$colorG = hexdec($colorG);
|
||||
$colorB = hexdec($colorB);
|
||||
|
||||
return [$colorR, $colorG, $colorB];
|
||||
}
|
||||
}
|
||||
1111
vendor/phpoffice/phpword/src/PhpWord/Shared/Html.php
vendored
Normal file
1111
vendor/phpoffice/phpword/src/PhpWord/Shared/Html.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
243
vendor/phpoffice/phpword/src/PhpWord/Shared/Microsoft/PasswordEncoder.php
vendored
Normal file
243
vendor/phpoffice/phpword/src/PhpWord/Shared/Microsoft/PasswordEncoder.php
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared\Microsoft;
|
||||
|
||||
/**
|
||||
* Password encoder for microsoft office applications.
|
||||
*/
|
||||
class PasswordEncoder
|
||||
{
|
||||
const ALGORITHM_MD2 = 'MD2';
|
||||
const ALGORITHM_MD4 = 'MD4';
|
||||
const ALGORITHM_MD5 = 'MD5';
|
||||
const ALGORITHM_SHA_1 = 'SHA-1';
|
||||
const ALGORITHM_SHA_256 = 'SHA-256';
|
||||
const ALGORITHM_SHA_384 = 'SHA-384';
|
||||
const ALGORITHM_SHA_512 = 'SHA-512';
|
||||
const ALGORITHM_RIPEMD = 'RIPEMD';
|
||||
const ALGORITHM_RIPEMD_160 = 'RIPEMD-160';
|
||||
const ALGORITHM_MAC = 'MAC';
|
||||
const ALGORITHM_HMAC = 'HMAC';
|
||||
|
||||
/**
|
||||
* Mapping between algorithm name and algorithm ID.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx
|
||||
*/
|
||||
private static $algorithmMapping = [
|
||||
self::ALGORITHM_MD2 => [1, 'md2'],
|
||||
self::ALGORITHM_MD4 => [2, 'md4'],
|
||||
self::ALGORITHM_MD5 => [3, 'md5'],
|
||||
self::ALGORITHM_SHA_1 => [4, 'sha1'],
|
||||
self::ALGORITHM_MAC => [5, ''], // 'mac' -> not possible with hash()
|
||||
self::ALGORITHM_RIPEMD => [6, 'ripemd'],
|
||||
self::ALGORITHM_RIPEMD_160 => [7, 'ripemd160'],
|
||||
self::ALGORITHM_HMAC => [9, ''], //'hmac' -> not possible with hash()
|
||||
self::ALGORITHM_SHA_256 => [12, 'sha256'],
|
||||
self::ALGORITHM_SHA_384 => [13, 'sha384'],
|
||||
self::ALGORITHM_SHA_512 => [14, 'sha512'],
|
||||
];
|
||||
|
||||
private static $initialCodeArray = [
|
||||
0xE1F0,
|
||||
0x1D0F,
|
||||
0xCC9C,
|
||||
0x84C0,
|
||||
0x110C,
|
||||
0x0E10,
|
||||
0xF1CE,
|
||||
0x313E,
|
||||
0x1872,
|
||||
0xE139,
|
||||
0xD40F,
|
||||
0x84F9,
|
||||
0x280C,
|
||||
0xA96A,
|
||||
0x4EC3,
|
||||
];
|
||||
|
||||
private static $encryptionMatrix = [
|
||||
[0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09],
|
||||
[0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF],
|
||||
[0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0],
|
||||
[0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40],
|
||||
[0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5],
|
||||
[0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A],
|
||||
[0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9],
|
||||
[0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0],
|
||||
[0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC],
|
||||
[0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10],
|
||||
[0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168],
|
||||
[0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C],
|
||||
[0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD],
|
||||
[0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC],
|
||||
[0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4],
|
||||
];
|
||||
|
||||
private static $passwordMaxLength = 15;
|
||||
|
||||
/**
|
||||
* Create a hashed password that MS Word will be able to work with.
|
||||
*
|
||||
* @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/
|
||||
*
|
||||
* @param string $password
|
||||
* @param string $algorithmName
|
||||
* @param string $salt
|
||||
* @param int $spinCount
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000)
|
||||
{
|
||||
$origEncoding = mb_internal_encoding();
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
$password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password)));
|
||||
|
||||
// Get the single-byte values by iterating through the Unicode characters of the truncated password.
|
||||
// For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte.
|
||||
$passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8');
|
||||
$byteChars = [];
|
||||
|
||||
for ($i = 0; $i < mb_strlen($password); ++$i) {
|
||||
$byteChars[$i] = ord(substr($passUtf8, $i * 2, 1));
|
||||
|
||||
if ($byteChars[$i] == 0) {
|
||||
$byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
$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');
|
||||
|
||||
// Implementation Notes List:
|
||||
// Word requires that the initial hash of the password with the salt not be considered in the count.
|
||||
// The initial hash of salt + key is not included in the iteration count.
|
||||
$algorithm = self::getAlgorithm($algorithmName);
|
||||
$generatedKey = hash($algorithm, $salt . $generatedKey, true);
|
||||
|
||||
for ($i = 0; $i < $spinCount; ++$i) {
|
||||
$generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true);
|
||||
}
|
||||
$generatedKey = base64_encode($generatedKey);
|
||||
|
||||
mb_internal_encoding($origEncoding);
|
||||
|
||||
return $generatedKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get algorithm from self::$algorithmMapping.
|
||||
*
|
||||
* @param string $algorithmName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getAlgorithm($algorithmName)
|
||||
{
|
||||
$algorithm = self::$algorithmMapping[$algorithmName][1];
|
||||
if ($algorithm == '') {
|
||||
$algorithm = 'sha1';
|
||||
}
|
||||
|
||||
return $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm ID.
|
||||
*
|
||||
* @param string $algorithmName
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function getAlgorithmId($algorithmName)
|
||||
{
|
||||
return self::$algorithmMapping[$algorithmName][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build combined key from low-order word and high-order word.
|
||||
*
|
||||
* @param array $byteChars byte array representation of password
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function buildCombinedKey($byteChars)
|
||||
{
|
||||
$byteCharsLength = count($byteChars);
|
||||
// Compute the high-order word
|
||||
// Initialize from the initial code array (see above), depending on the passwords length.
|
||||
$highOrderWord = self::$initialCodeArray[$byteCharsLength - 1];
|
||||
|
||||
// For each character in the password:
|
||||
// For every bit in the character, starting with the least significant and progressing to (but excluding)
|
||||
// the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from
|
||||
// the Encryption Matrix
|
||||
for ($i = 0; $i < $byteCharsLength; ++$i) {
|
||||
$tmp = self::$passwordMaxLength - $byteCharsLength + $i;
|
||||
$matrixRow = self::$encryptionMatrix[$tmp];
|
||||
for ($intBit = 0; $intBit < 7; ++$intBit) {
|
||||
if (($byteChars[$i] & (0x0001 << $intBit)) != 0) {
|
||||
$highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute low-order word
|
||||
// Initialize with 0
|
||||
$lowOrderWord = 0;
|
||||
// For each character in the password, going backwards
|
||||
for ($i = $byteCharsLength - 1; $i >= 0; --$i) {
|
||||
// low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character
|
||||
$lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]);
|
||||
}
|
||||
// Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B.
|
||||
$lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B);
|
||||
|
||||
// Combine the Low and High Order Word
|
||||
return self::int32(($highOrderWord << 16) + $lowOrderWord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate behaviour of (signed) int32.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param int $value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function int32($value)
|
||||
{
|
||||
$value = ($value & 0xFFFFFFFF);
|
||||
|
||||
if ($value & 0x80000000) {
|
||||
$value = -((~$value & 0xFFFFFFFF) + 1);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
323
vendor/phpoffice/phpword/src/PhpWord/Shared/OLERead.php
vendored
Normal file
323
vendor/phpoffice/phpword/src/PhpWord/Shared/OLERead.php
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
* @copyright 2010-2018 PHPWord contributors
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
use PhpOffice\PhpWord\Exception\Exception;
|
||||
|
||||
defined('IDENTIFIER_OLE') ||
|
||||
define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
|
||||
|
||||
class OLERead
|
||||
{
|
||||
private $data = '';
|
||||
|
||||
// OLE identifier
|
||||
const IDENTIFIER_OLE = IDENTIFIER_OLE;
|
||||
|
||||
// Size of a sector = 512 bytes
|
||||
const BIG_BLOCK_SIZE = 0x200;
|
||||
|
||||
// Size of a short sector = 64 bytes
|
||||
const SMALL_BLOCK_SIZE = 0x40;
|
||||
|
||||
// Size of a directory entry always = 128 bytes
|
||||
const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
|
||||
|
||||
// Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
|
||||
const SMALL_BLOCK_THRESHOLD = 0x1000;
|
||||
|
||||
// header offsets
|
||||
const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
|
||||
const ROOT_START_BLOCK_POS = 0x30;
|
||||
const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
|
||||
const EXTENSION_BLOCK_POS = 0x44;
|
||||
const NUM_EXTENSION_BLOCK_POS = 0x48;
|
||||
const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
|
||||
|
||||
// property storage offsets (directory offsets)
|
||||
const SIZE_OF_NAME_POS = 0x40;
|
||||
const TYPE_POS = 0x42;
|
||||
const START_BLOCK_POS = 0x74;
|
||||
const SIZE_POS = 0x78;
|
||||
|
||||
public $wrkdocument = null;
|
||||
public $wrk1Table = null;
|
||||
public $wrkData = null;
|
||||
public $wrkObjectPool = null;
|
||||
public $summaryInformation = null;
|
||||
public $docSummaryInfos = null;
|
||||
|
||||
/**
|
||||
* Read the file
|
||||
*
|
||||
* @param $sFileName string Filename
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function read($sFileName)
|
||||
{
|
||||
// Check if file exists and is readable
|
||||
if (!is_readable($sFileName)) {
|
||||
throw new Exception('Could not open ' . $sFileName . ' for reading! File does not exist, or it is not readable.');
|
||||
}
|
||||
|
||||
// Get the file identifier
|
||||
// Don't bother reading the whole file until we know it's a valid OLE file
|
||||
$this->data = file_get_contents($sFileName, false, null, 0, 8);
|
||||
|
||||
// Check OLE identifier
|
||||
if ($this->data != self::IDENTIFIER_OLE) {
|
||||
throw new Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
|
||||
}
|
||||
|
||||
// Get the file data
|
||||
$this->data = file_get_contents($sFileName);
|
||||
|
||||
// Total number of sectors used for the SAT
|
||||
$this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
|
||||
|
||||
// SecID of the first sector of the directory stream
|
||||
$this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS);
|
||||
|
||||
// SecID of the first sector of the SSAT (or -2 if not extant)
|
||||
$this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
|
||||
|
||||
// SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
|
||||
$this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS);
|
||||
|
||||
// Total number of sectors used by MSAT
|
||||
$this->numExtensionBlocks = self::getInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
|
||||
|
||||
$bigBlockDepotBlocks = array();
|
||||
$pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
|
||||
|
||||
$bbdBlocks = $this->numBigBlockDepotBlocks;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->numExtensionBlocks != 0) {
|
||||
$bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
for ($i = 0; $i < $bbdBlocks; ++$i) {
|
||||
$bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
|
||||
$pos += 4;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
|
||||
$pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
|
||||
$blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
|
||||
|
||||
for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
|
||||
$bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
|
||||
$pos += 4;
|
||||
}
|
||||
|
||||
$bbdBlocks += $blocksToRead;
|
||||
if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
|
||||
$this->extensionBlock = self::getInt4d($this->data, $pos);
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$pos = 0;
|
||||
$this->bigBlockChain = '';
|
||||
$bbs = self::BIG_BLOCK_SIZE / 4;
|
||||
for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
|
||||
$pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
|
||||
|
||||
$this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs);
|
||||
$pos += 4 * $bbs;
|
||||
}
|
||||
|
||||
$pos = 0;
|
||||
$sbdBlock = $this->sbdStartBlock;
|
||||
$this->smallBlockChain = '';
|
||||
while ($sbdBlock != -2) {
|
||||
$pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
|
||||
|
||||
$this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);
|
||||
$pos += 4 * $bbs;
|
||||
|
||||
$sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4);
|
||||
}
|
||||
|
||||
// read the directory stream
|
||||
$block = $this->rootStartBlock;
|
||||
$this->entry = $this->readData($block);
|
||||
|
||||
$this->readPropertySets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract binary stream data
|
||||
*
|
||||
* @param mixed $stream
|
||||
* @return string
|
||||
*/
|
||||
public function getStream($stream)
|
||||
{
|
||||
if ($stream === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$streamData = '';
|
||||
|
||||
if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
|
||||
$rootdata = $this->readData($this->props[$this->rootentry]['startBlock']);
|
||||
|
||||
$block = $this->props[$stream]['startBlock'];
|
||||
|
||||
while ($block != -2) {
|
||||
$pos = $block * self::SMALL_BLOCK_SIZE;
|
||||
$streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
|
||||
|
||||
$block = self::getInt4d($this->smallBlockChain, $block * 4);
|
||||
}
|
||||
|
||||
return $streamData;
|
||||
}
|
||||
|
||||
$numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
|
||||
if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
|
||||
++$numBlocks;
|
||||
}
|
||||
|
||||
if ($numBlocks == 0) {
|
||||
return ''; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$block = $this->props[$stream]['startBlock'];
|
||||
|
||||
while ($block != -2) {
|
||||
$pos = ($block + 1) * self::BIG_BLOCK_SIZE;
|
||||
$streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
|
||||
$block = self::getInt4d($this->bigBlockChain, $block * 4);
|
||||
}
|
||||
|
||||
return $streamData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a standard stream (by joining sectors using information from SAT)
|
||||
*
|
||||
* @param int $blSectorId Sector ID where the stream starts
|
||||
* @return string Data for standard stream
|
||||
*/
|
||||
private function readData($blSectorId)
|
||||
{
|
||||
$block = $blSectorId;
|
||||
$data = '';
|
||||
|
||||
while ($block != -2) {
|
||||
$pos = ($block + 1) * self::BIG_BLOCK_SIZE;
|
||||
$data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
|
||||
$block = self::getInt4d($this->bigBlockChain, $block * 4);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read entries in the directory stream.
|
||||
*/
|
||||
private function readPropertySets()
|
||||
{
|
||||
$offset = 0;
|
||||
|
||||
// loop through entires, each entry is 128 bytes
|
||||
$entryLen = strlen($this->entry);
|
||||
while ($offset < $entryLen) {
|
||||
// entry data (128 bytes)
|
||||
$data = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
|
||||
|
||||
// size in bytes of name
|
||||
$nameSize = ord($data[self::SIZE_OF_NAME_POS]) | (ord($data[self::SIZE_OF_NAME_POS + 1]) << 8);
|
||||
|
||||
// type of entry
|
||||
$type = ord($data[self::TYPE_POS]);
|
||||
|
||||
// sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
|
||||
// sectorID of first sector of the short-stream container stream, if this entry is root entry
|
||||
$startBlock = self::getInt4d($data, self::START_BLOCK_POS);
|
||||
|
||||
$size = self::getInt4d($data, self::SIZE_POS);
|
||||
|
||||
$name = str_replace("\x00", '', substr($data, 0, $nameSize));
|
||||
|
||||
$this->props[] = array(
|
||||
'name' => $name,
|
||||
'type' => $type,
|
||||
'startBlock' => $startBlock,
|
||||
'size' => $size, );
|
||||
|
||||
// tmp helper to simplify checks
|
||||
$upName = strtoupper($name);
|
||||
|
||||
// Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
|
||||
// print_r($upName.PHP_EOL);
|
||||
if (($upName === 'WORDDOCUMENT')) {
|
||||
$this->wrkdocument = count($this->props) - 1;
|
||||
} elseif ($upName === '1TABLE') {
|
||||
$this->wrk1Table = count($this->props) - 1;
|
||||
} elseif ($upName === 'DATA') {
|
||||
$this->wrkData = count($this->props) - 1;
|
||||
} elseif ($upName === 'OBJECTPOOL') {
|
||||
$this->wrkObjectPoolelseif = count($this->props) - 1;
|
||||
} elseif ($upName === 'ROOT ENTRY' || $upName === 'R') {
|
||||
$this->rootentry = count($this->props) - 1;
|
||||
}
|
||||
|
||||
// Summary information
|
||||
if ($name == chr(5) . 'SummaryInformation') {
|
||||
$this->summaryInformation = count($this->props) - 1;
|
||||
}
|
||||
|
||||
// Additional Document Summary information
|
||||
if ($name == chr(5) . 'DocumentSummaryInformation') {
|
||||
$this->docSummaryInfos = count($this->props) - 1;
|
||||
}
|
||||
|
||||
$offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read 4 bytes of data at specified position
|
||||
*
|
||||
* @param string $data
|
||||
* @param int $pos
|
||||
* @return int
|
||||
*/
|
||||
private static function getInt4d($data, $pos)
|
||||
{
|
||||
// FIX: represent numbers correctly on 64-bit system
|
||||
// http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
|
||||
// Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
|
||||
$or24 = ord($data[$pos + 3]);
|
||||
if ($or24 >= 128) {
|
||||
// negative number
|
||||
$ord24 = -abs((256 - $or24) << 24);
|
||||
} else {
|
||||
$ord24 = ($or24 & 127) << 24;
|
||||
}
|
||||
|
||||
return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24;
|
||||
}
|
||||
}
|
||||
5392
vendor/phpoffice/phpword/src/PhpWord/Shared/PCLZip/pclzip.lib.php
vendored
Normal file
5392
vendor/phpoffice/phpword/src/PhpWord/Shared/PCLZip/pclzip.lib.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
252
vendor/phpoffice/phpword/src/PhpWord/Shared/Text.php
vendored
Normal file
252
vendor/phpoffice/phpword/src/PhpWord/Shared/Text.php
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
/**
|
||||
* Text.
|
||||
*/
|
||||
class Text
|
||||
{
|
||||
/**
|
||||
* Control characters array.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private static $controlCharacters = [];
|
||||
|
||||
/**
|
||||
* Build control characters array.
|
||||
*/
|
||||
private static function buildControlCharacters(): void
|
||||
{
|
||||
for ($i = 0; $i <= 19; ++$i) {
|
||||
if ($i != 9 && $i != 10 && $i != 13) {
|
||||
$find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
|
||||
$replace = chr($i);
|
||||
self::$controlCharacters[$find] = $replace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from PHP control character to OpenXML escaped control character.
|
||||
*
|
||||
* Excel 2007 team:
|
||||
* ----------------
|
||||
* That's correct, control characters are stored directly in the shared-strings table.
|
||||
* We do encode characters that cannot be represented in XML using the following escape sequence:
|
||||
* _xHHHH_ where H represents a hexadecimal character in the character's value...
|
||||
* So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
|
||||
* element or in the shared string <t> element.
|
||||
*
|
||||
* @param string $value Value to escape
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function controlCharacterPHP2OOXML($value = '')
|
||||
{
|
||||
if (empty(self::$controlCharacters)) {
|
||||
self::buildControlCharacters();
|
||||
}
|
||||
|
||||
return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a number formatted for being integrated in xml files.
|
||||
*
|
||||
* @param float $number
|
||||
* @param int $decimals
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function numberFormat($number, $decimals)
|
||||
{
|
||||
return number_format($number, $decimals, '.', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dec
|
||||
*
|
||||
* @see http://stackoverflow.com/a/7153133/2235790
|
||||
*
|
||||
* @author velcrow
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function chr($dec)
|
||||
{
|
||||
if ($dec <= 0x7F) {
|
||||
return chr($dec);
|
||||
}
|
||||
if ($dec <= 0x7FF) {
|
||||
return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128);
|
||||
}
|
||||
if ($dec <= 0xFFFF) {
|
||||
return chr(($dec >> 12) + 224) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);
|
||||
}
|
||||
if ($dec <= 0x1FFFFF) {
|
||||
return chr(($dec >> 18) + 240) . chr((($dec >> 12) & 63) + 128) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from OpenXML escaped control character to PHP control character.
|
||||
*
|
||||
* @param string $value Value to unescape
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function controlCharacterOOXML2PHP($value = '')
|
||||
{
|
||||
if (empty(self::$controlCharacters)) {
|
||||
self::buildControlCharacters();
|
||||
}
|
||||
|
||||
return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string contains UTF-8 data.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUTF8($value = '')
|
||||
{
|
||||
return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return UTF8 encoded value.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function toUTF8($value = '')
|
||||
{
|
||||
if (null !== $value && !self::isUTF8($value)) {
|
||||
$value = utf8_encode($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unicode from UTF8 text.
|
||||
*
|
||||
* The function is splitted to reduce cyclomatic complexity
|
||||
*
|
||||
* @param string $text UTF8 text
|
||||
*
|
||||
* @return string Unicode text
|
||||
*
|
||||
* @since 0.11.0
|
||||
*/
|
||||
public static function toUnicode($text)
|
||||
{
|
||||
return self::unicodeToEntities(self::utf8ToUnicode($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unicode array from UTF8 text.
|
||||
*
|
||||
* @param string $text UTF8 text
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 0.11.0
|
||||
* @see http://www.randomchaos.com/documents/?source=php_and_unicode
|
||||
*/
|
||||
public static function utf8ToUnicode($text)
|
||||
{
|
||||
$unicode = [];
|
||||
$values = [];
|
||||
$lookingFor = 1;
|
||||
|
||||
// Gets unicode for each character
|
||||
for ($i = 0; $i < strlen($text); ++$i) {
|
||||
$thisValue = ord($text[$i]);
|
||||
if ($thisValue < 128) {
|
||||
$unicode[] = $thisValue;
|
||||
} else {
|
||||
if (count($values) == 0) {
|
||||
$lookingFor = $thisValue < 224 ? 2 : 3;
|
||||
}
|
||||
$values[] = $thisValue;
|
||||
if (count($values) == $lookingFor) {
|
||||
if ($lookingFor == 3) {
|
||||
$number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64);
|
||||
} else {
|
||||
$number = (($values[0] % 32) * 64) + ($values[1] % 64);
|
||||
}
|
||||
$unicode[] = $number;
|
||||
$values = [];
|
||||
$lookingFor = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $unicode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns entites from unicode array.
|
||||
*
|
||||
* @param array $unicode
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 0.11.0
|
||||
* @see http://www.randomchaos.com/documents/?source=php_and_unicode
|
||||
*/
|
||||
private static function unicodeToEntities($unicode)
|
||||
{
|
||||
$entities = '';
|
||||
|
||||
foreach ($unicode as $value) {
|
||||
if ($value != 65279) {
|
||||
$entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return name without underscore for < 0.10.0 variable name compatibility.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function removeUnderscorePrefix($value)
|
||||
{
|
||||
if (null !== $value) {
|
||||
if (substr($value, 0, 1) == '_') {
|
||||
$value = substr($value, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
231
vendor/phpoffice/phpword/src/PhpWord/Shared/XMLReader.php
vendored
Normal file
231
vendor/phpoffice/phpword/src/PhpWord/Shared/XMLReader.php
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use DOMNodeList;
|
||||
use DOMXpath;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* XML Reader wrapper.
|
||||
*
|
||||
* @since 0.2.1
|
||||
*/
|
||||
class XMLReader
|
||||
{
|
||||
/**
|
||||
* DOMDocument object.
|
||||
*
|
||||
* @var DOMDocument
|
||||
*/
|
||||
private $dom;
|
||||
|
||||
/**
|
||||
* DOMXpath object.
|
||||
*
|
||||
* @var DOMXpath
|
||||
*/
|
||||
private $xpath;
|
||||
|
||||
/**
|
||||
* Get DOMDocument from ZipArchive.
|
||||
*
|
||||
* @param string $zipFile
|
||||
* @param string $xmlFile
|
||||
*
|
||||
* @return DOMDocument|false
|
||||
*/
|
||||
public function getDomFromZip($zipFile, $xmlFile)
|
||||
{
|
||||
if (file_exists($zipFile) === false) {
|
||||
throw new Exception('Cannot find archive file.');
|
||||
}
|
||||
|
||||
$zip = new ZipArchive();
|
||||
$zip->open($zipFile);
|
||||
$content = $zip->getFromName($xmlFile);
|
||||
$zip->close();
|
||||
|
||||
if ($content === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getDomFromString($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DOMDocument from content string.
|
||||
*
|
||||
* @param string $content
|
||||
*
|
||||
* @return DOMDocument
|
||||
*/
|
||||
public function getDomFromString($content)
|
||||
{
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$originalLibXMLEntityValue = libxml_disable_entity_loader(true);
|
||||
}
|
||||
$this->dom = new DOMDocument();
|
||||
$this->dom->loadXML($content);
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
libxml_disable_entity_loader($originalLibXMLEntityValue);
|
||||
}
|
||||
|
||||
return $this->dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get elements.
|
||||
*
|
||||
* @param string $path
|
||||
* @param DOMElement $contextNode
|
||||
*
|
||||
* @return DOMNodeList
|
||||
*/
|
||||
public function getElements($path, ?DOMElement $contextNode = null)
|
||||
{
|
||||
if ($this->dom === null) {
|
||||
return [];
|
||||
}
|
||||
if ($this->xpath === null) {
|
||||
$this->xpath = new DOMXpath($this->dom);
|
||||
}
|
||||
|
||||
if (null === $contextNode) {
|
||||
return $this->xpath->query($path);
|
||||
}
|
||||
|
||||
return $this->xpath->query($path, $contextNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the namespace with the DOMXPath object.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string $namespaceURI The URI of the namespace
|
||||
*
|
||||
* @return bool true on success or false on failure
|
||||
*/
|
||||
public function registerNamespace($prefix, $namespaceURI)
|
||||
{
|
||||
if ($this->dom === null) {
|
||||
throw new InvalidArgumentException('Dom needs to be loaded before registering a namespace');
|
||||
}
|
||||
if ($this->xpath === null) {
|
||||
$this->xpath = new DOMXpath($this->dom);
|
||||
}
|
||||
|
||||
return $this->xpath->registerNamespace($prefix, $namespaceURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get element.
|
||||
*
|
||||
* @param string $path
|
||||
* @param DOMElement $contextNode
|
||||
*
|
||||
* @return null|DOMElement
|
||||
*/
|
||||
public function getElement($path, ?DOMElement $contextNode = null)
|
||||
{
|
||||
$elements = $this->getElements($path, $contextNode);
|
||||
if ($elements->length > 0) {
|
||||
return $elements->item(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get element attribute.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param DOMElement $contextNode
|
||||
* @param string $path
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getAttribute($attribute, ?DOMElement $contextNode = null, $path = null)
|
||||
{
|
||||
$return = null;
|
||||
if ($path !== null) {
|
||||
$elements = $this->getElements($path, $contextNode);
|
||||
if ($elements->length > 0) {
|
||||
/** @var DOMElement $node Type hint */
|
||||
$node = $elements->item(0);
|
||||
$return = $node->getAttribute($attribute);
|
||||
}
|
||||
} else {
|
||||
if ($contextNode !== null) {
|
||||
$return = $contextNode->getAttribute($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
return ($return == '') ? null : $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get element value.
|
||||
*
|
||||
* @param string $path
|
||||
* @param DOMElement $contextNode
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getValue($path, ?DOMElement $contextNode = null)
|
||||
{
|
||||
$elements = $this->getElements($path, $contextNode);
|
||||
if ($elements->length > 0) {
|
||||
return $elements->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count elements.
|
||||
*
|
||||
* @param string $path
|
||||
* @param DOMElement $contextNode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countElements($path, ?DOMElement $contextNode = null)
|
||||
{
|
||||
$elements = $this->getElements($path, $contextNode);
|
||||
|
||||
return $elements->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element exists.
|
||||
*
|
||||
* @param string $path
|
||||
* @param DOMElement $contextNode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function elementExists($path, ?DOMElement $contextNode = null)
|
||||
{
|
||||
return $this->getElements($path, $contextNode)->length > 0;
|
||||
}
|
||||
}
|
||||
187
vendor/phpoffice/phpword/src/PhpWord/Shared/XMLWriter.php
vendored
Normal file
187
vendor/phpoffice/phpword/src/PhpWord/Shared/XMLWriter.php
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
use Exception;
|
||||
use ReturnTypeWillChange;
|
||||
|
||||
/**
|
||||
* XMLWriter.
|
||||
*
|
||||
* @method bool endElement()
|
||||
* @method mixed flush(bool $empty = null)
|
||||
* @method bool openMemory()
|
||||
* @method string outputMemory(bool $flush = null)
|
||||
* @method bool setIndent(bool $indent)
|
||||
* @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null)
|
||||
* @method bool startElement(string $name)
|
||||
* @method bool text(string $content)
|
||||
* @method bool writeCData(string $content)
|
||||
* @method bool writeComment(string $content)
|
||||
* @method bool writeElement(string $name, string $content = null)
|
||||
* @method bool writeRaw(string $content)
|
||||
*/
|
||||
class XMLWriter extends \XMLWriter
|
||||
{
|
||||
/** Temporary storage method */
|
||||
const STORAGE_MEMORY = 1;
|
||||
const STORAGE_DISK = 2;
|
||||
|
||||
/**
|
||||
* Temporary filename.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tempFileName = '';
|
||||
|
||||
/**
|
||||
* Create a new \PhpOffice\PhpWord\Shared\XMLWriter instance.
|
||||
*
|
||||
* @param int $pTemporaryStorage Temporary storage location
|
||||
* @param string $pTemporaryStorageDir Temporary storage folder
|
||||
* @param bool $compatibility
|
||||
*/
|
||||
public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageDir = null, $compatibility = false)
|
||||
{
|
||||
// Open temporary storage
|
||||
if ($pTemporaryStorage == self::STORAGE_MEMORY) {
|
||||
$this->openMemory();
|
||||
} else {
|
||||
if (!$pTemporaryStorageDir || !is_dir($pTemporaryStorageDir)) {
|
||||
$pTemporaryStorageDir = sys_get_temp_dir();
|
||||
}
|
||||
// Create temporary filename
|
||||
$this->tempFileName = @tempnam($pTemporaryStorageDir, 'xml');
|
||||
|
||||
// Open storage
|
||||
$this->openUri($this->tempFileName);
|
||||
}
|
||||
|
||||
if ($compatibility) {
|
||||
$this->setIndent(false);
|
||||
$this->setIndentString('');
|
||||
} else {
|
||||
$this->setIndent(true);
|
||||
$this->setIndentString(' ');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// Unlink temporary files
|
||||
if (empty($this->tempFileName)) {
|
||||
return;
|
||||
}
|
||||
if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) {
|
||||
throw new Exception('The file ' . $this->tempFileName . ' could not be deleted.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get written data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
if ($this->tempFileName == '') {
|
||||
return $this->outputMemory(true);
|
||||
}
|
||||
|
||||
$this->flush();
|
||||
|
||||
return file_get_contents($this->tempFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write simple element and attribute(s) block.
|
||||
*
|
||||
* There are two options:
|
||||
* 1. If the `$attributes` is an array, then it's an associative array of attributes
|
||||
* 2. If not, then it's a simple attribute-value pair
|
||||
*
|
||||
* @param string $element
|
||||
* @param array|string $attributes
|
||||
* @param string $value
|
||||
*/
|
||||
public function writeElementBlock($element, $attributes, $value = null): void
|
||||
{
|
||||
$this->startElement($element);
|
||||
if (!is_array($attributes)) {
|
||||
$attributes = [$attributes => $value];
|
||||
}
|
||||
foreach ($attributes as $attribute => $value) {
|
||||
$this->writeAttribute($attribute, $value);
|
||||
}
|
||||
$this->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write element if ...
|
||||
*
|
||||
* @param bool $condition
|
||||
* @param string $element
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function writeElementIf($condition, $element, $attribute = null, $value = null): void
|
||||
{
|
||||
if ($condition == true) {
|
||||
if (null === $attribute) {
|
||||
$this->writeElement($element, $value);
|
||||
} else {
|
||||
$this->startElement($element);
|
||||
$this->writeAttribute($attribute, $value);
|
||||
$this->endElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write attribute if ...
|
||||
*
|
||||
* @param bool $condition
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function writeAttributeIf($condition, $attribute, $value): void
|
||||
{
|
||||
if ($condition == true) {
|
||||
$this->writeAttribute($attribute, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function writeAttribute($name, $value)
|
||||
{
|
||||
if (is_float($value)) {
|
||||
$value = json_encode($value);
|
||||
}
|
||||
|
||||
return parent::writeAttribute($name, $value ?? '');
|
||||
}
|
||||
}
|
||||
419
vendor/phpoffice/phpword/src/PhpWord/Shared/ZipArchive.php
vendored
Normal file
419
vendor/phpoffice/phpword/src/PhpWord/Shared/ZipArchive.php
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @see https://github.com/PHPOffice/PHPWord
|
||||
*
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
use PclZip;
|
||||
use PhpOffice\PhpWord\Exception\Exception;
|
||||
use PhpOffice\PhpWord\Settings;
|
||||
|
||||
/**
|
||||
* ZipArchive wrapper.
|
||||
*
|
||||
* Wraps zip archive functionality of PHP ZipArchive and PCLZip. PHP ZipArchive
|
||||
* properties and methods are bypassed and used as the model for the PCLZip
|
||||
* emulation. Only needed PHP ZipArchive features are implemented.
|
||||
*
|
||||
* @method bool addFile(string $filename, string $localname = null)
|
||||
* @method bool addFromString(string $localname, string $contents)
|
||||
* @method string getNameIndex(int $index)
|
||||
* @method int locateName(string $name)
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class ZipArchive
|
||||
{
|
||||
/** @const int Flags for open method */
|
||||
const CREATE = 1; // Emulate \ZipArchive::CREATE
|
||||
const OVERWRITE = 8; // Emulate \ZipArchive::OVERWRITE
|
||||
|
||||
/**
|
||||
* Number of files (emulate ZipArchive::$numFiles).
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $numFiles = 0;
|
||||
|
||||
/**
|
||||
* Archive filename (emulate ZipArchive::$filename).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* Temporary storage directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tempDir;
|
||||
|
||||
/**
|
||||
* Internal zip archive object.
|
||||
*
|
||||
* @var PclZip|\ZipArchive
|
||||
*/
|
||||
private $zip;
|
||||
|
||||
/**
|
||||
* Use PCLZip (default behaviour).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $usePclzip = true;
|
||||
|
||||
/**
|
||||
* Create new instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->usePclzip = (Settings::getZipClass() != 'ZipArchive');
|
||||
if ($this->usePclzip) {
|
||||
if (!defined('PCLZIP_TEMPORARY_DIR')) {
|
||||
define('PCLZIP_TEMPORARY_DIR', Settings::getTempDir() . '/');
|
||||
}
|
||||
require_once 'PCLZip/pclzip.lib.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch function calls: pass to ZipArchive or PCLZip.
|
||||
*
|
||||
* `call_user_func_array` can only used for public function, hence the `public` in all `pcl...` methods
|
||||
*
|
||||
* @param mixed $function
|
||||
* @param mixed $args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($function, $args)
|
||||
{
|
||||
// Set object and function
|
||||
$zipFunction = $function;
|
||||
if (!$this->usePclzip) {
|
||||
$zipObject = $this->zip;
|
||||
} else {
|
||||
$zipObject = $this;
|
||||
$zipFunction = "pclzip{$zipFunction}";
|
||||
}
|
||||
|
||||
// Run function
|
||||
$result = false;
|
||||
if (method_exists($zipObject, $zipFunction)) {
|
||||
$result = @call_user_func_array([$zipObject, $zipFunction], $args);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a new zip archive.
|
||||
*
|
||||
* @param string $filename The file name of the ZIP archive to open
|
||||
* @param int $flags The mode to use to open the archive
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function open($filename, $flags = null)
|
||||
{
|
||||
$result = true;
|
||||
$this->filename = $filename;
|
||||
$this->tempDir = Settings::getTempDir();
|
||||
|
||||
if (!$this->usePclzip) {
|
||||
$zip = new \ZipArchive();
|
||||
|
||||
// PHP 8.1 compat - passing null as second arg to \ZipArchive::open() is deprecated
|
||||
// passing 0 achieves the same behaviour
|
||||
if ($flags === null) {
|
||||
$flags = 0;
|
||||
}
|
||||
|
||||
$result = $zip->open($this->filename, $flags);
|
||||
|
||||
// Scrutizer will report the property numFiles does not exist
|
||||
// See https://github.com/scrutinizer-ci/php-analyzer/issues/190
|
||||
$this->numFiles = $zip->numFiles;
|
||||
} else {
|
||||
$zip = new PclZip($this->filename);
|
||||
$zipContent = $zip->listContent();
|
||||
$this->numFiles = is_array($zipContent) ? count($zipContent) : 0;
|
||||
}
|
||||
$this->zip = $zip;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
throw new Exception("Could not close zip file {$this->filename}: ");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the archive contents (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $destination
|
||||
* @param array|string $entries
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public function extractTo($destination, $entries = null)
|
||||
{
|
||||
if (!is_dir($destination)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->usePclzip) {
|
||||
return $this->zip->extractTo($destination, $entries);
|
||||
}
|
||||
|
||||
return $this->pclzipExtractTo($destination, $entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract file from archive by given file name (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $filename Filename for the file in zip archive
|
||||
*
|
||||
* @return string $contents File string contents
|
||||
*/
|
||||
public function getFromName($filename)
|
||||
{
|
||||
if (!$this->usePclzip) {
|
||||
$contents = $this->zip->getFromName($filename);
|
||||
if ($contents === false) {
|
||||
$filename = substr($filename, 1);
|
||||
$contents = $this->zip->getFromName($filename);
|
||||
}
|
||||
} else {
|
||||
$contents = $this->pclzipGetFromName($filename);
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new file to the zip archive (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $filename Directory/Name of the file to add to the zip archive
|
||||
* @param string $localname Directory/Name of the file added to the zip
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function pclzipAddFile($filename, $localname = null)
|
||||
{
|
||||
/** @var PclZip $zip Type hint */
|
||||
$zip = $this->zip;
|
||||
|
||||
// Bugfix GH-261 https://github.com/PHPOffice/PHPWord/pull/261
|
||||
$realpathFilename = realpath($filename);
|
||||
if ($realpathFilename !== false) {
|
||||
$filename = $realpathFilename;
|
||||
}
|
||||
|
||||
$filenameParts = pathinfo($filename);
|
||||
$localnameParts = pathinfo($localname);
|
||||
|
||||
// To Rename the file while adding it to the zip we
|
||||
// need to create a temp file with the correct name
|
||||
$tempFile = false;
|
||||
if ($filenameParts['basename'] != $localnameParts['basename']) {
|
||||
$tempFile = true; // temp file created
|
||||
$temppath = $this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename'];
|
||||
copy($filename, $temppath);
|
||||
$filename = $temppath;
|
||||
$filenameParts = pathinfo($temppath);
|
||||
}
|
||||
|
||||
$pathRemoved = $filenameParts['dirname'];
|
||||
$pathAdded = $localnameParts['dirname'];
|
||||
|
||||
if (!$this->usePclzip) {
|
||||
$pathAdded = $pathAdded . '/' . ltrim(str_replace('\\', '/', substr($filename, strlen($pathRemoved))), '/');
|
||||
//$res = $zip->addFile($filename, $pathAdded);
|
||||
$res = $zip->addFromString($pathAdded, file_get_contents($filename)); // addFile can't use subfolders in some cases
|
||||
} else {
|
||||
$res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded);
|
||||
}
|
||||
|
||||
if ($tempFile) {
|
||||
// Remove temp file, if created
|
||||
unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']);
|
||||
}
|
||||
|
||||
return $res != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new file to the zip archive from a string of raw data (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $localname Directory/Name of the file to add to the zip archive
|
||||
* @param string $contents String of data to add to the zip archive
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function pclzipAddFromString($localname, $contents)
|
||||
{
|
||||
/** @var PclZip $zip Type hint */
|
||||
$zip = $this->zip;
|
||||
$filenameParts = pathinfo($localname);
|
||||
|
||||
// Write $contents to a temp file
|
||||
$handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'], 'wb');
|
||||
fwrite($handle, $contents);
|
||||
fclose($handle);
|
||||
|
||||
// Add temp file to zip
|
||||
$filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'];
|
||||
$pathRemoved = $this->tempDir;
|
||||
$pathAdded = $filenameParts['dirname'];
|
||||
|
||||
$res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded);
|
||||
|
||||
// Remove temp file
|
||||
@unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']);
|
||||
|
||||
return $res != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the archive contents (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $destination
|
||||
* @param array|string $entries
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public function pclzipExtractTo($destination, $entries = null)
|
||||
{
|
||||
/** @var PclZip $zip Type hint */
|
||||
$zip = $this->zip;
|
||||
|
||||
// Extract all files
|
||||
if (null === $entries) {
|
||||
$result = $zip->extract(PCLZIP_OPT_PATH, $destination);
|
||||
|
||||
return $result > 0;
|
||||
}
|
||||
|
||||
// Extract by entries
|
||||
if (!is_array($entries)) {
|
||||
$entries = [$entries];
|
||||
}
|
||||
foreach ($entries as $entry) {
|
||||
$entryIndex = $this->locateName($entry);
|
||||
$result = $zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination);
|
||||
if ($result <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract file from archive by given file name (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $filename Filename for the file in zip archive
|
||||
*
|
||||
* @return string $contents File string contents
|
||||
*/
|
||||
public function pclzipGetFromName($filename)
|
||||
{
|
||||
/** @var PclZip $zip Type hint */
|
||||
$zip = $this->zip;
|
||||
$listIndex = $this->pclzipLocateName($filename);
|
||||
$contents = false;
|
||||
|
||||
if ($listIndex !== false) {
|
||||
$extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING);
|
||||
} else {
|
||||
$filename = substr($filename, 1);
|
||||
$listIndex = $this->pclzipLocateName($filename);
|
||||
$extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING);
|
||||
}
|
||||
if ((is_array($extracted)) && ($extracted != 0)) {
|
||||
$contents = $extracted[0]['content'];
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of an entry using its index (emulate \ZipArchive).
|
||||
*
|
||||
* @param int $index
|
||||
*
|
||||
* @return bool|string
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public function pclzipGetNameIndex($index)
|
||||
{
|
||||
/** @var PclZip $zip Type hint */
|
||||
$zip = $this->zip;
|
||||
$list = $zip->listContent();
|
||||
if (isset($list[$index])) {
|
||||
return $list[$index]['filename'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the entry in the archive (emulate \ZipArchive).
|
||||
*
|
||||
* @param string $filename Filename for the file in zip archive
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function pclzipLocateName($filename)
|
||||
{
|
||||
/** @var PclZip $zip Type hint */
|
||||
$zip = $this->zip;
|
||||
$list = $zip->listContent();
|
||||
$listCount = count($list);
|
||||
$listIndex = -1;
|
||||
for ($i = 0; $i < $listCount; ++$i) {
|
||||
if (strtolower($list[$i]['filename']) == strtolower($filename) ||
|
||||
strtolower($list[$i]['stored_filename']) == strtolower($filename)) {
|
||||
$listIndex = $i;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ($listIndex > -1) ? $listIndex : false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user