This commit is contained in:
2026-07-23 10:37:26 +08:00
parent 090abf48fa
commit 40add876cd
3503 changed files with 838201 additions and 5 deletions
+47
View File
@@ -0,0 +1,47 @@
<?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
*/
declare(strict_types=1);
namespace PhpOffice\PhpWord;
class Autoloader
{
/** @const string */
const NAMESPACE_PREFIX = 'PhpOffice\\PhpWord\\';
public static function register(): void
{
spl_autoload_register([new self(), 'autoload']);
}
public static function autoload(string $class): void
{
$prefixLength = strlen(self::NAMESPACE_PREFIX);
if (0 === strncmp(self::NAMESPACE_PREFIX, $class, $prefixLength)) {
$file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength));
$file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');
if (!$file) {
return;
}
if (file_exists($file)) {
/** @noinspection PhpIncludeInspection Dynamic includes */
require_once $file;
}
}
}
}
@@ -0,0 +1,93 @@
<?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\Collection;
/**
* Collection abstract class.
*
* @since 0.10.0
*
* @template T
*/
abstract class AbstractCollection
{
/**
* Items.
*
* @var T[]
*/
private $items = [];
/**
* Get items.
*
* @return T[]
*/
public function getItems(): array
{
return $this->items;
}
/**
* Get item by index.
*
* @return ?T
*/
public function getItem(int $index)
{
if (array_key_exists($index, $this->items)) {
return $this->items[$index];
}
return null;
}
/**
* Set item.
*
* @param ?T $item
*/
public function setItem(int $index, $item): void
{
if (array_key_exists($index, $this->items)) {
$this->items[$index] = $item;
}
}
/**
* Add new item.
*
* @param T $item
*/
public function addItem($item): int
{
$index = $this->countItems();
$this->items[$index] = $item;
return $index;
}
/**
* Get item count.
*/
public function countItems(): int
{
return count($this->items);
}
}
@@ -0,0 +1,32 @@
<?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\Collection;
use PhpOffice\PhpWord\Element\Bookmark;
/**
* Bookmarks collection.
*
* @since 0.12.0
*
* @extends AbstractCollection<Bookmark>
*/
class Bookmarks extends AbstractCollection
{
}
@@ -0,0 +1,32 @@
<?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\Collection;
use PhpOffice\PhpWord\Element\Chart;
/**
* Charts collection.
*
* @since 0.12.0
*
* @extends AbstractCollection<Chart>
*/
class Charts extends AbstractCollection
{
}
@@ -0,0 +1,32 @@
<?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\Collection;
use PhpOffice\PhpWord\Element\Comment;
/**
* Comments collection.
*
* @since 0.12.0
*
* @extends AbstractCollection<Comment>
*/
class Comments extends AbstractCollection
{
}
@@ -0,0 +1,32 @@
<?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\Collection;
use PhpOffice\PhpWord\Element\Endnote;
/**
* Endnotes collection.
*
* @since 0.10.0
*
* @extends AbstractCollection<Endnote>
*/
class Endnotes extends AbstractCollection
{
}
@@ -0,0 +1,32 @@
<?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\Collection;
use PhpOffice\PhpWord\Element\Footnote;
/**
* Footnotes collection.
*
* @since 0.10.0
*
* @extends AbstractCollection<Footnote>
*/
class Footnotes extends AbstractCollection
{
}
@@ -0,0 +1,32 @@
<?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\Collection;
use PhpOffice\PhpWord\Element\Title;
/**
* Titles collection.
*
* @since 0.10.0
*
* @extends AbstractCollection<Title>
*/
class Titles extends AbstractCollection
{
}
@@ -0,0 +1,185 @@
<?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\ComplexType;
use InvalidArgumentException;
use PhpOffice\PhpWord\SimpleType\NumberFormat;
/**
* Footnote properties.
*
* @see http://www.datypic.com/sc/ooxml/e-w_footnotePr-1.html
*/
final class FootnoteProperties
{
const RESTART_NUMBER_CONTINUOUS = 'continuous';
const RESTART_NUMBER_EACH_SECTION = 'eachSect';
const RESTART_NUMBER_EACH_PAGE = 'eachPage';
const POSITION_PAGE_BOTTOM = 'pageBottom';
const POSITION_BENEATH_TEXT = 'beneathText';
const POSITION_SECTION_END = 'sectEnd';
const POSITION_DOC_END = 'docEnd';
/**
* Footnote Positioning Location.
*
* @var string
*/
private $pos;
/**
* Footnote Numbering Format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat.
*
* @var string
*/
private $numFmt;
/**
* Footnote and Endnote Numbering Starting Value.
*
* @var float
*/
private $numStart;
/**
* Footnote and Endnote Numbering Restart Location.
*
* @var string
*/
private $numRestart;
/**
* Get the Footnote Positioning Location.
*
* @return string
*/
public function getPos()
{
return $this->pos;
}
/**
* Set the Footnote Positioning Location (pageBottom, beneathText, sectEnd, docEnd).
*
* @param string $pos
*
* @return self
*/
public function setPos($pos)
{
$position = [
self::POSITION_PAGE_BOTTOM,
self::POSITION_BENEATH_TEXT,
self::POSITION_SECTION_END,
self::POSITION_DOC_END,
];
if (in_array($pos, $position)) {
$this->pos = $pos;
} else {
throw new InvalidArgumentException('Invalid value, on of ' . implode(', ', $position) . ' possible');
}
return $this;
}
/**
* Get the Footnote Numbering Format.
*
* @return string
*/
public function getNumFmt()
{
return $this->numFmt;
}
/**
* Set the Footnote Numbering Format.
*
* @param string $numFmt One of NumberFormat
*
* @return self
*/
public function setNumFmt($numFmt)
{
NumberFormat::validate($numFmt);
$this->numFmt = $numFmt;
return $this;
}
/**
* Get the Footnote Numbering Format.
*
* @return float
*/
public function getNumStart()
{
return $this->numStart;
}
/**
* Set the Footnote Numbering Format.
*
* @param float $numStart
*
* @return self
*/
public function setNumStart($numStart)
{
$this->numStart = $numStart;
return $this;
}
/**
* Get the Footnote and Endnote Numbering Starting Value.
*
* @return string
*/
public function getNumRestart()
{
return $this->numRestart;
}
/**
* Set the Footnote and Endnote Numbering Starting Value (continuous, eachSect, eachPage).
*
* @param string $numRestart
*
* @return self
*/
public function setNumRestart($numRestart)
{
$restartNumbers = [
self::RESTART_NUMBER_CONTINUOUS,
self::RESTART_NUMBER_EACH_SECTION,
self::RESTART_NUMBER_EACH_PAGE,
];
if (in_array($numRestart, $restartNumbers)) {
$this->numRestart = $numRestart;
} else {
throw new InvalidArgumentException('Invalid value, on of ' . implode(', ', $restartNumbers) . ' possible');
}
return $this;
}
}
@@ -0,0 +1,109 @@
<?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\ComplexType;
use InvalidArgumentException;
/**
* Spelling and Grammatical Checking State.
*
* @see http://www.datypic.com/sc/ooxml/e-w_proofState-1.html
*/
final class ProofState
{
/**
* Check Completed.
*/
const CLEAN = 'clean';
/**
* Check Not Completed.
*/
const DIRTY = 'dirty';
/**
* Spell Checking State.
*
* @var string
*/
private $spelling;
/**
* Grammatical Checking State.
*
* @var string
*/
private $grammar;
/**
* Set the Spell Checking State (dirty or clean).
*
* @param string $spelling
*
* @return self
*/
public function setSpelling($spelling)
{
if ($spelling == self::CLEAN || $spelling == self::DIRTY) {
$this->spelling = $spelling;
} else {
throw new InvalidArgumentException('Invalid value, dirty or clean possible');
}
return $this;
}
/**
* Get the Spell Checking State.
*
* @return string
*/
public function getSpelling()
{
return $this->spelling;
}
/**
* Set the Grammatical Checking State (dirty or clean).
*
* @param string $grammar
*
* @return self
*/
public function setGrammar($grammar)
{
if ($grammar == self::CLEAN || $grammar == self::DIRTY) {
$this->grammar = $grammar;
} else {
throw new InvalidArgumentException('Invalid value, dirty or clean possible');
}
return $this;
}
/**
* Get the Grammatical Checking State.
*
* @return string
*/
public function getGrammar()
{
return $this->grammar;
}
}
@@ -0,0 +1,188 @@
<?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\ComplexType;
use InvalidArgumentException;
/**
* Ruby properties.
*
* @see https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.rubyproperties?view=openxml-3.0.1
*/
class RubyProperties
{
const ALIGNMENT_CENTER = 'center';
const ALIGNMENT_DISTRIBUTE_LETTER = 'distributeLetter';
const ALIGNMENT_DISTRIBUTE_SPACE = 'distributeSpace';
const ALIGNMENT_LEFT = 'left';
const ALIGNMENT_RIGHT = 'right';
const ALIGNMENT_RIGHT_VERTICAL = 'rightVertical';
/**
* Ruby alignment (w:rubyAlign).
*
* @var string
*/
private $alignment;
/**
* Ruby font face size (w:hps).
*
* @var float
*/
private $fontFaceSize;
/**
* Ruby font points above base text (w:hpsRaise).
*
* @var float
*/
private $fontPointsAboveText;
/**
* Ruby font size for base text (w:hpsBaseText).
*
* @var float
*/
private $baseTextFontSize;
/**
* Ruby type/language id (w:lid).
*
* @var string
*/
private $languageId;
/**
* Create a new RubyProperties object.
*/
public function __construct()
{
// these defaults came from opening a new Word doc, adding some ruby text to some
// Japanese text, and copying out the defaults.
$this->alignment = self::ALIGNMENT_DISTRIBUTE_SPACE;
$this->fontFaceSize = 12;
$this->fontPointsAboveText = 22;
$this->languageId = 'ja-JP';
$this->baseTextFontSize = 24;
}
/**
* Get the ruby alignment.
*/
public function getAlignment(): string
{
return $this->alignment;
}
/**
* Set the Ruby Alignment (center, distributeLetter, distributeSpace, left, right, rightVertical).
*/
public function setAlignment(string $alignment): self
{
$alignmentTypes = [
self::ALIGNMENT_CENTER,
self::ALIGNMENT_DISTRIBUTE_LETTER,
self::ALIGNMENT_DISTRIBUTE_SPACE,
self::ALIGNMENT_LEFT,
self::ALIGNMENT_RIGHT,
self::ALIGNMENT_RIGHT_VERTICAL,
];
if (in_array($alignment, $alignmentTypes)) {
$this->alignment = $alignment;
} else {
throw new InvalidArgumentException('Invalid value, alignments of ' . implode(', ', $alignmentTypes) . ' possible');
}
return $this;
}
/**
* Get the ruby font face size.
*/
public function getFontFaceSize(): float
{
return $this->fontFaceSize;
}
/**
* Set the ruby font face size.
*/
public function setFontFaceSize(float $size): self
{
$this->fontFaceSize = $size;
return $this;
}
/**
* Get the ruby font points above base text.
*/
public function getFontPointsAboveBaseText(): float
{
return $this->fontPointsAboveText;
}
/**
* Set the ruby font points above base text.
*/
public function setFontPointsAboveBaseText(float $size): self
{
$this->fontPointsAboveText = $size;
return $this;
}
/**
* Get the ruby font size for base text.
*/
public function getFontSizeForBaseText(): float
{
return $this->baseTextFontSize;
}
/**
* Set the ruby font size for base text.
*/
public function setFontSizeForBaseText(float $size): self
{
$this->baseTextFontSize = $size;
return $this;
}
/**
* Get the ruby language id.
*/
public function getLanguageId(): string
{
return $this->languageId;
}
/**
* Set the ruby language id.
*/
public function setLanguageId(string $langId): self
{
$this->languageId = $langId;
return $this;
}
}
@@ -0,0 +1,60 @@
<?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\ComplexType;
use PhpOffice\PhpWord\SimpleType\TblWidth as TblWidthSimpleType;
/**
* @see http://www.datypic.com/sc/ooxml/t-w_CT_TblWidth.html
*/
final class TblWidth
{
/** @var string */
private $type;
/** @var int */
private $value;
/**
* @param int $value If omitted, then its value shall be assumed to be 0
* @param string $type If omitted, then its value shall be assumed to be dxa
*/
public function __construct($value = 0, $type = TblWidthSimpleType::TWIP)
{
$this->value = $value;
TblWidthSimpleType::validate($type);
$this->type = $type;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return int
*/
public function getValue()
{
return $this->value;
}
}
@@ -0,0 +1,167 @@
<?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\ComplexType;
/**
* Visibility of Annotation Types.
*
* @see http://www.datypic.com/sc/ooxml/e-w_revisionView-1.html
*/
final class TrackChangesView
{
/**
* Display Visual Indicator Of Markup Area.
*
* @var bool
*/
private $markup;
/**
* Display Comments.
*
* @var bool
*/
private $comments;
/**
* Display Content Revisions.
*
* @var bool
*/
private $insDel;
/**
* Display Formatting Revisions.
*
* @var bool
*/
private $formatting;
/**
* Display Ink Annotations.
*
* @var bool
*/
private $inkAnnotations;
/**
* Get Display Visual Indicator Of Markup Area.
*
* @return bool True if markup is shown
*/
public function hasMarkup()
{
return $this->markup;
}
/**
* Set Display Visual Indicator Of Markup Area.
*
* @param ?bool $markup
* Set to true to show markup
*/
public function setMarkup($markup): void
{
$this->markup = $markup === null ? true : $markup;
}
/**
* Get Display Comments.
*
* @return bool True if comments are shown
*/
public function hasComments()
{
return $this->comments;
}
/**
* Set Display Comments.
*
* @param ?bool $comments
* Set to true to show comments
*/
public function setComments($comments): void
{
$this->comments = $comments === null ? true : $comments;
}
/**
* Get Display Content Revisions.
*
* @return bool True if content revisions are shown
*/
public function hasInsDel()
{
return $this->insDel;
}
/**
* Set Display Content Revisions.
*
* @param ?bool $insDel
* Set to true to show content revisions
*/
public function setInsDel($insDel): void
{
$this->insDel = $insDel === null ? true : $insDel;
}
/**
* Get Display Formatting Revisions.
*
* @return bool True if formatting revisions are shown
*/
public function hasFormatting()
{
return $this->formatting;
}
/**
* Set Display Formatting Revisions.
*
* @param null|bool $formatting
* Set to true to show formatting revisions
*/
public function setFormatting($formatting = null): void
{
$this->formatting = $formatting === null ? true : $formatting;
}
/**
* Get Display Ink Annotations.
*
* @return bool True if ink annotations are shown
*/
public function hasInkAnnotations()
{
return $this->inkAnnotations;
}
/**
* Set Display Ink Annotations.
*
* @param ?bool $inkAnnotations
* Set to true to show ink annotations
*/
public function setInkAnnotations($inkAnnotations): void
{
$this->inkAnnotations = $inkAnnotations === null ? true : $inkAnnotations;
}
}
@@ -0,0 +1,293 @@
<?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\Element;
use BadMethodCallException;
use PhpOffice\Math\Math;
use ReflectionClass;
/**
* Container abstract class.
*
* @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null)
* @method TextRun addTextRun(mixed $pStyle = null)
* @method Bookmark addBookmark(string $name)
* @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null, boolean $internal = false)
* @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null)
* @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null)
* @method ListItem addListItem(string $txt, int $depth = 0, mixed $font = null, mixed $list = null, mixed $para = null)
* @method ListItemRun addListItemRun(int $depth = 0, mixed $listStyle = null, mixed $pStyle = null)
* @method Footnote addFootnote(mixed $pStyle = null)
* @method Endnote addEndnote(mixed $pStyle = null)
* @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null)
* @method Title addTitle(mixed $text, int $depth = 1, int $pageNumber = null)
* @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9)
* @method PageBreak addPageBreak()
* @method Table addTable(mixed $style = null)
* @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false, $name = null)
* @method OLEObject addOLEObject(string $source, mixed $style = null)
* @method TextBox addTextBox(mixed $style = null)
* @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null)
* @method Line addLine(mixed $lineStyle = null)
* @method Shape addShape(string $type, mixed $style = null)
* @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null)
* @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)
* @method SDT addSDT(string $type)
* @method Formula addFormula(Math $math)
* @method Ruby addRuby(TextRun $baseText, TextRun $rubyText, \PhpOffice\PhpWord\ComplexType\RubyProperties $properties)
* @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead
*
* @since 0.10.0
*/
abstract class AbstractContainer extends AbstractElement
{
/**
* Elements collection.
*
* @var AbstractElement[]
*/
protected $elements = [];
/**
* Container type Section|Header|Footer|Footnote|Endnote|Cell|TextRun|TextBox|ListItemRun|TrackChange.
*
* @var string
*/
protected $container;
/**
* Magic method to catch all 'addElement' variation.
*
* This removes addText, addTextRun, etc. When adding new element, we have to
* add the model in the class docblock with `@method`.
*
* Warning: This makes capitalization matters, e.g. addCheckbox or addcheckbox won't work.
*
* @param mixed $function
* @param mixed $args
*
* @return AbstractElement
*/
public function __call($function, $args)
{
$elements = [
'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak',
'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'OLEObject',
'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
'Chart', 'FormField', 'SDT', 'Comment',
'Formula', 'Ruby',
];
$functions = [];
foreach ($elements as $element) {
$functions['add' . strtolower($element)] = $element == 'Object' ? 'OLEObject' : $element;
}
// Run valid `add` command
$function = strtolower($function);
if (isset($functions[$function])) {
$element = $functions[$function];
// Special case for TextBreak
// @todo Remove the `$count` parameter in 1.0.0 to make this element similiar to other elements?
if ($element == 'TextBreak') {
[$count, $fontStyle, $paragraphStyle] = array_pad($args, 3, null);
if ($count === null) {
$count = 1;
}
for ($i = 1; $i <= $count; ++$i) {
$this->addElement($element, $fontStyle, $paragraphStyle);
}
} else {
// All other elements
array_unshift($args, $element); // Prepend element name to the beginning of args array
return call_user_func_array([$this, 'addElement'], $args);
}
}
return null;
}
/**
* Add element.
*
* Each element has different number of parameters passed
*
* @param string $elementName
*
* @return AbstractElement
*/
protected function addElement($elementName)
{
$elementClass = __NAMESPACE__ . '\\' . $elementName;
$this->checkValidity($elementName);
// Get arguments
$args = func_get_args();
$withoutP = in_array($this->container, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field']);
if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) {
$args[3] = null; // Remove paragraph style for texts in textrun
}
// Create element using reflection
$reflection = new ReflectionClass($elementClass);
$elementArgs = $args;
array_shift($elementArgs); // Shift the $elementName off the beginning of array
/** @var AbstractElement $element Type hint */
$element = $reflection->newInstanceArgs($elementArgs);
// Set parent container
$element->setParentContainer($this);
$element->setElementIndex($this->countElements() + 1);
$element->setElementId();
$this->elements[] = $element;
return $element;
}
/**
* Get all elements.
*
* @return AbstractElement[]
*/
public function getElements()
{
return $this->elements;
}
/**
* Returns the element at the requested position.
*
* @param int $index
*
* @return null|AbstractElement
*/
public function getElement($index)
{
if (array_key_exists($index, $this->elements)) {
return $this->elements[$index];
}
return null;
}
/**
* Removes the element at requested index.
*
* @param AbstractElement|int $toRemove
*/
public function removeElement($toRemove): void
{
if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) {
unset($this->elements[$toRemove]);
} elseif ($toRemove instanceof AbstractElement) {
foreach ($this->elements as $key => $element) {
if ($element->getElementId() === $toRemove->getElementId()) {
unset($this->elements[$key]);
return;
}
}
}
}
/**
* Count elements.
*
* @return int
*/
public function countElements()
{
return count($this->elements);
}
/**
* Check if a method is allowed for the current container.
*
* @param string $method
*
* @return bool
*/
private function checkValidity($method)
{
$generalContainers = [
'Section', 'Header', 'Footer', 'Footnote', 'Endnote', 'Cell', 'TextRun', 'TextBox', 'ListItemRun', 'TrackChange',
];
$validContainers = [
'Text' => $generalContainers,
'Bookmark' => $generalContainers,
'Link' => $generalContainers,
'TextBreak' => $generalContainers,
'Image' => $generalContainers,
'OLEObject' => $generalContainers,
'Field' => $generalContainers,
'Line' => $generalContainers,
'Shape' => $generalContainers,
'FormField' => $generalContainers,
'SDT' => $generalContainers,
'TrackChange' => $generalContainers,
'TextRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange', 'ListItemRun'],
'ListItem' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'],
'ListItemRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'],
'Table' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'],
'CheckBox' => ['Section', 'Header', 'Footer', 'Cell', 'TextRun'],
'TextBox' => ['Section', 'Header', 'Footer', 'Cell'],
'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'],
'Endnote' => ['Section', 'TextRun', 'Cell'],
'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'],
'Title' => ['Section', 'Cell', 'Header'],
'TOC' => ['Section'],
'PageBreak' => ['Section'],
'Chart' => ['Section', 'Cell'],
];
// Special condition, e.g. preservetext can only exists in cell when
// the cell is located in header or footer
$validSubcontainers = [
'PreserveText' => [['Cell'], ['Header', 'Footer', 'Section']],
'Footnote' => [['Cell', 'TextRun'], ['Section']],
'Endnote' => [['Cell', 'TextRun'], ['Section']],
];
// Check if a method is valid for current container
if (isset($validContainers[$method])) {
if (!in_array($this->container, $validContainers[$method])) {
throw new BadMethodCallException("Cannot add {$method} in {$this->container}.");
}
}
// Check if a method is valid for current container, located in other container
if (isset($validSubcontainers[$method])) {
$rules = $validSubcontainers[$method];
$containers = $rules[0];
$allowedDocParts = $rules[1];
foreach ($containers as $container) {
if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) {
throw new BadMethodCallException("Cannot add {$method} in {$this->container}.");
}
}
}
return true;
}
}
@@ -0,0 +1,544 @@
<?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\Element;
use DateTime;
use InvalidArgumentException;
use PhpOffice\PhpWord\Collection\Comments;
use PhpOffice\PhpWord\Media;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Style;
/**
* Element abstract class.
*
* @since 0.10.0
*/
abstract class AbstractElement
{
/**
* PhpWord object.
*
* @var ?PhpWord
*/
protected $phpWord;
/**
* Section Id.
*
* @var int
*/
protected $sectionId;
/**
* Document part type: Section|Header|Footer|Footnote|Endnote.
*
* Used by textrun and cell container to determine where the element is
* located because it will affect the availability of other element,
* e.g. footnote will not be available when $docPart is header or footer.
*
* @var string
*/
protected $docPart = 'Section';
/**
* Document part Id.
*
* For header and footer, this will be = ($sectionId - 1) * 3 + $index
* because the max number of header/footer in every page is 3, i.e.
* AUTO, FIRST, and EVEN (AUTO = ODD)
*
* @var int
*/
protected $docPartId = 1;
/**
* Index of element in the elements collection (start with 1).
*
* @var int
*/
protected $elementIndex = 1;
/**
* Unique Id for element.
*
* @var string
*/
protected $elementId;
/**
* Relation Id.
*
* @var int
*/
protected $relationId;
/**
* Depth of table container nested level; Primarily used for RTF writer/reader.
*
* 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc.
*
* @var int
*/
private $nestedLevel = 0;
/**
* A reference to the parent.
*
* @var null|AbstractElement
*/
private $parent;
/**
* changed element info.
*
* @var TrackChange
*/
private $trackChange;
/**
* Parent container type.
*
* @var string
*/
private $parentContainer;
/**
* Has media relation flag; true for Link, Image, and Object.
*
* @var bool
*/
protected $mediaRelation = false;
/**
* Is part of collection; true for Title, Footnote, Endnote, Chart, and Comment.
*
* @var bool
*/
protected $collectionRelation = false;
/**
* The start position for the linked comments.
*
* @var Comments
*/
protected $commentsRangeStart;
/**
* The end position for the linked comments.
*
* @var Comments
*/
protected $commentsRangeEnd;
/**
* Get PhpWord.
*/
public function getPhpWord(): ?PhpWord
{
return $this->phpWord;
}
/**
* Set PhpWord as reference.
*/
public function setPhpWord(?PhpWord $phpWord = null): void
{
$this->phpWord = $phpWord;
}
/**
* Get section number.
*
* @return int
*/
public function getSectionId()
{
return $this->sectionId;
}
/**
* Set doc part.
*
* @param string $docPart
* @param int $docPartId
*/
public function setDocPart($docPart, $docPartId = 1): void
{
$this->docPart = $docPart;
$this->docPartId = $docPartId;
}
/**
* Get doc part.
*
* @return string
*/
public function getDocPart()
{
return $this->docPart;
}
/**
* Get doc part Id.
*
* @return int
*/
public function getDocPartId()
{
return $this->docPartId;
}
/**
* Return media element (image, object, link) container name.
*
* @return string section|headerx|footerx|footnote|endnote
*/
private function getMediaPart()
{
$mediaPart = $this->docPart;
if ($mediaPart == 'Header' || $mediaPart == 'Footer') {
$mediaPart .= $this->docPartId;
}
return strtolower($mediaPart);
}
/**
* Get element index.
*
* @return int
*/
public function getElementIndex()
{
return $this->elementIndex;
}
/**
* Set element index.
*
* @param int $value
*/
public function setElementIndex($value): void
{
$this->elementIndex = $value;
}
/**
* Get element unique ID.
*
* @return string
*/
public function getElementId()
{
return $this->elementId;
}
/**
* Set element unique ID from 6 first digit of md5.
*/
public function setElementId(): void
{
$this->elementId = substr(md5((string) mt_rand()), 0, 6);
}
/**
* Get relation Id.
*
* @return int
*/
public function getRelationId()
{
return $this->relationId;
}
/**
* Set relation Id.
*
* @param int $value
*/
public function setRelationId($value): void
{
$this->relationId = $value;
}
/**
* Get nested level.
*
* @return int
*/
public function getNestedLevel()
{
return $this->nestedLevel;
}
/**
* Get comments start.
*/
public function getCommentsRangeStart(): ?Comments
{
return $this->commentsRangeStart;
}
/**
* Get comment start.
*/
public function getCommentRangeStart(): ?Comment
{
if ($this->commentsRangeStart != null) {
return $this->commentsRangeStart->getItem($this->commentsRangeStart->countItems());
}
return null;
}
/**
* Set comment start.
*/
public function setCommentRangeStart(Comment $value): void
{
if ($this instanceof Comment) {
throw new InvalidArgumentException('Cannot set a Comment on a Comment');
}
if ($this->commentsRangeStart == null) {
$this->commentsRangeStart = new Comments();
}
// Set ID early to avoid duplicates.
if ($value->getElementId() == null) {
$value->setElementId();
}
foreach ($this->commentsRangeStart->getItems() as $comment) {
if ($value->getElementId() == $comment->getElementId()) {
return;
}
}
$idxItem = $this->commentsRangeStart->addItem($value);
$this->commentsRangeStart->getItem($idxItem)->setStartElement($this);
}
/**
* Get comments end.
*/
public function getCommentsRangeEnd(): ?Comments
{
return $this->commentsRangeEnd;
}
/**
* Get comment end.
*/
public function getCommentRangeEnd(): ?Comment
{
if ($this->commentsRangeEnd != null) {
return $this->commentsRangeEnd->getItem($this->commentsRangeEnd->countItems());
}
return null;
}
/**
* Set comment end.
*/
public function setCommentRangeEnd(Comment $value): void
{
if ($this instanceof Comment) {
throw new InvalidArgumentException('Cannot set a Comment on a Comment');
}
if ($this->commentsRangeEnd == null) {
$this->commentsRangeEnd = new Comments();
}
// Set ID early to avoid duplicates.
if ($value->getElementId() == null) {
$value->setElementId();
}
foreach ($this->commentsRangeEnd->getItems() as $comment) {
if ($value->getElementId() == $comment->getElementId()) {
return;
}
}
$idxItem = $this->commentsRangeEnd->addItem($value);
$this->commentsRangeEnd->getItem($idxItem)->setEndElement($this);
}
/**
* Get parent element.
*
* @return null|AbstractElement
*/
public function getParent()
{
return $this->parent;
}
/**
* Set parent container.
*
* Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell)
*/
public function setParentContainer(self $container): void
{
$this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1);
$this->parent = $container;
// Set nested level
$this->nestedLevel = $container->getNestedLevel();
if ($this->parentContainer == 'Cell') {
++$this->nestedLevel;
}
// Set phpword
$this->setPhpWord($container->getPhpWord());
// Set doc part
if (!$this instanceof Footnote) {
$this->setDocPart($container->getDocPart(), $container->getDocPartId());
}
$this->setMediaRelation();
$this->setCollectionRelation();
}
/**
* Set relation Id for media elements (link, image, object; legacy of OOXML).
*
* - Image element needs to be passed to Media object
* - Icon needs to be set for Object element
*/
private function setMediaRelation(): void
{
if (!$this instanceof Link && !$this instanceof Image && !$this instanceof OLEObject) {
return;
}
$elementName = substr(static::class, strrpos(static::class, '\\') + 1);
if ($elementName == 'OLEObject') {
$elementName = 'Object';
}
$mediaPart = $this->getMediaPart();
$source = $this->getSource();
$image = null;
if ($this instanceof Image) {
$image = $this;
}
$rId = Media::addElement($mediaPart, strtolower($elementName), $source, $image);
$this->setRelationId($rId);
if ($this instanceof OLEObject) {
$icon = $this->getIcon();
$rId = Media::addElement($mediaPart, 'image', $icon, new Image($icon));
$this->setImageRelationId($rId);
}
}
/**
* Set relation Id for elements that will be registered in the Collection subnamespaces.
*/
private function setCollectionRelation(): void
{
if ($this->collectionRelation === true && $this->phpWord instanceof PhpWord) {
$elementName = substr(static::class, strrpos(static::class, '\\') + 1);
$addMethod = "add{$elementName}";
$rId = $this->phpWord->$addMethod($this);
$this->setRelationId($rId);
}
}
/**
* Check if element is located in Section doc part (as opposed to Header/Footer).
*
* @return bool
*/
public function isInSection()
{
return $this->docPart == 'Section';
}
/**
* Set new style value.
*
* @param mixed $styleObject Style object
* @param null|array|string|Style $styleValue Style value
* @param bool $returnObject Always return object
*
* @return mixed
*/
protected function setNewStyle($styleObject, $styleValue = null, $returnObject = false)
{
if (null !== $styleValue && is_array($styleValue)) {
$styleObject->setStyleByArray($styleValue);
$style = $styleObject;
} else {
$style = $returnObject ? $styleObject : $styleValue;
}
return $style;
}
/**
* Sets the trackChange information.
*/
public function setTrackChange(TrackChange $trackChange): void
{
$this->trackChange = $trackChange;
}
/**
* Gets the trackChange information.
*
* @return TrackChange
*/
public function getTrackChange()
{
return $this->trackChange;
}
/**
* Set changed.
*
* @param string $type INSERTED|DELETED
* @param string $author
* @param null|DateTime|int $date allways in UTC
*/
public function setChangeInfo($type, $author, $date = null): void
{
$this->trackChange = new TrackChange($type, $author, $date);
}
/**
* Set enum value.
*
* @param null|string $value
* @param string[] $enum
* @param null|string $default
*
* @return null|string
*
* @todo Merge with the same method in AbstractStyle
*/
protected function setEnumVal($value = null, $enum = [], $default = null)
{
if ($value !== null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {
throw new InvalidArgumentException("Invalid style value: {$value}");
} elseif ($value === null || trim($value) == '') {
$value = $default;
}
return $value;
}
}
@@ -0,0 +1,61 @@
<?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\Element;
use PhpOffice\PhpWord\Shared\Text as SharedText;
/**
* Bookmark element.
*/
class Bookmark extends AbstractElement
{
/**
* Bookmark Name.
*
* @var string
*/
private $name;
/**
* Is part of collection.
*
* @var bool
*/
protected $collectionRelation = true;
/**
* Create a new Bookmark Element.
*
* @param string $name
*/
public function __construct($name = '')
{
$this->name = SharedText::toUTF8($name);
}
/**
* Get Bookmark name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
}
+78
View File
@@ -0,0 +1,78 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Cell as CellStyle;
/**
* Table cell element.
*/
class Cell extends AbstractContainer
{
/**
* @var string Container type
*/
protected $container = 'Cell';
/**
* Cell width.
*
* @var ?int
*/
private $width;
/**
* Cell style.
*
* @var ?CellStyle
*/
private $style;
/**
* Create new instance.
*
* @param null|int $width
* @param array|CellStyle $style
*/
public function __construct($width = null, $style = null)
{
$this->width = $width;
$this->style = $this->setNewStyle(new CellStyle(), $style, true);
}
/**
* Get cell style.
*
* @return ?CellStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get cell width.
*
* @return ?int
*/
public function getWidth()
{
return $this->width;
}
}
+130
View File
@@ -0,0 +1,130 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Chart as ChartStyle;
/**
* Chart element.
*
* @since 0.12.0
*/
class Chart extends AbstractElement
{
/**
* Is part of collection.
*
* @var bool
*/
protected $collectionRelation = true;
/**
* Type.
*
* @var string
*/
private $type = 'pie';
/**
* Series.
*
* @var array
*/
private $series = [];
/**
* Chart style.
*
* @var ?ChartStyle
*/
private $style;
/**
* Create new instance.
*
* @param string $type
* @param array $categories
* @param array $values
* @param array $style
* @param null|mixed $seriesName
*/
public function __construct($type, $categories, $values, $style = null, $seriesName = null)
{
$this->setType($type);
$this->addSeries($categories, $values, $seriesName);
$this->style = $this->setNewStyle(new ChartStyle(), $style, true);
}
/**
* Get type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set type.
*
* @param string $value
*/
public function setType($value): void
{
$enum = ['pie', 'doughnut', 'line', 'bar', 'stacked_bar', 'percent_stacked_bar', 'column', 'stacked_column', 'percent_stacked_column', 'area', 'radar', 'scatter'];
$this->type = $this->setEnumVal($value, $enum, 'pie');
}
/**
* Add series.
*
* @param array $categories
* @param array $values
* @param null|mixed $name
*/
public function addSeries($categories, $values, $name = null): void
{
$this->series[] = [
'categories' => $categories,
'values' => $values,
'name' => $name,
];
}
/**
* Get series.
*
* @return array
*/
public function getSeries()
{
return $this->series;
}
/**
* Get chart style.
*
* @return ?ChartStyle
*/
public function getStyle()
{
return $this->style;
}
}
@@ -0,0 +1,74 @@
<?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\Element;
use PhpOffice\PhpWord\Shared\Text as SharedText;
/**
* Check box element.
*
* @since 0.10.0
*/
class CheckBox extends Text
{
/**
* Name content.
*
* @var string
*/
private $name;
/**
* Create new instance.
*
* @param string $name
* @param string $text
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function __construct($name = null, $text = null, $fontStyle = null, $paragraphStyle = null)
{
$this->setName($name);
parent::__construct($text, $fontStyle, $paragraphStyle);
}
/**
* Set name content.
*
* @param string $name
*
* @return self
*/
public function setName($name)
{
$this->name = SharedText::toUTF8($name);
return $this;
}
/**
* Get name content.
*
* @return string
*/
public function getName()
{
return $this->name;
}
}
+118
View File
@@ -0,0 +1,118 @@
<?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\Element;
use DateTime;
/**
* Comment element.
*
* @see http://datypic.com/sc/ooxml/t-w_CT_Comment.html
*/
class Comment extends TrackChange
{
/**
* Initials.
*
* @var string
*/
private $initials;
/**
* The Element where this comment starts.
*
* @var AbstractElement
*/
private $startElement;
/**
* The Element where this comment ends.
*
* @var AbstractElement
*/
private $endElement;
/**
* Is part of collection.
*
* @var bool
*/
protected $collectionRelation = true;
/**
* Create a new Comment Element.
*
* @param string $author
* @param null|DateTime $date
* @param string $initials
*/
public function __construct($author, $date = null, $initials = null)
{
parent::__construct(null, $author, $date);
$this->initials = $initials;
}
/**
* Get Initials.
*
* @return string
*/
public function getInitials()
{
return $this->initials;
}
/**
* Sets the element where this comment starts.
*/
public function setStartElement(AbstractElement $value): void
{
$this->startElement = $value;
$value->setCommentRangeStart($this);
}
/**
* Get the element where this comment starts.
*
* @return AbstractElement
*/
public function getStartElement()
{
return $this->startElement;
}
/**
* Sets the element where this comment ends.
*/
public function setEndElement(AbstractElement $value): void
{
$this->endElement = $value;
$value->setCommentRangeEnd($this);
}
/**
* Get the element where this comment ends.
*
* @return AbstractElement
*/
public function getEndElement()
{
return $this->endElement;
}
}
@@ -0,0 +1,42 @@
<?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\Element;
/**
* Endnote element.
*
* @since 0.10.0
*/
class Endnote extends Footnote
{
/**
* @var string Container type
*/
protected $container = 'Endnote';
/**
* Create new instance.
*
* @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle
*/
public function __construct($paragraphStyle = null)
{
parent::__construct($paragraphStyle);
}
}
+308
View File
@@ -0,0 +1,308 @@
<?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\Element;
use InvalidArgumentException;
use PhpOffice\PhpWord\Style\Font;
/**
* Field element.
*
* @since 0.11.0
* @see http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html
*/
class Field extends AbstractElement
{
/**
* Field properties and options. Depending on type, a field can have different properties
* and options.
*
* @var array
*/
protected $fieldsArray = [
'PAGE' => [
'properties' => [
'format' => ['Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'],
],
'options' => ['PreserveFormat'],
],
'NUMPAGES' => [
'properties' => [
'format' => ['Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText',
'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper', ],
'numformat' => ['0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%'],
],
'options' => ['PreserveFormat'],
],
'DATE' => [
'properties' => [
'dateformat' => [
// Generic formats
'yyyy-MM-dd', 'yyyy-MM', 'MMM-yy', 'MMM-yyyy', 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss',
// Day-Month-Year formats
'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-MMM-yy', 'd MMM. yy',
'd-M-yy', 'd-M-yy h:mm', 'd-M-yy h:mm:ss', 'd-M-yy h:mm am/pm', 'd-M-yy h:mm:ss am/pm', 'd-M-yy HH:mm', 'd-M-yy HH:mm:ss',
'd/M/yy', 'd/M/yy h:mm', 'd/M/yy h:mm:ss', 'd/M/yy h:mm am/pm', 'd/M/yy h:mm:ss am/pm', 'd/M/yy HH:mm', 'd/M/yy HH:mm:ss',
'd-M-yyyy', 'd-M-yyyy h:mm', 'd-M-yyyy h:mm:ss', 'd-M-yyyy h:mm am/pm', 'd-M-yyyy h:mm:ss am/pm', 'd-M-yyyy HH:mm', 'd-M-yyyy HH:mm:ss',
'd/M/yyyy', 'd/M/yyyy h:mm', 'd/M/yyyy h:mm:ss', 'd/M/yyyy h:mm am/pm', 'd/M/yyyy h:mm:ss am/pm', 'd/M/yyyy HH:mm', 'd/M/yyyy HH:mm:ss',
// Month-Day-Year formats
'dddd, MMMM d yyyy', 'MMMM d yyyy', 'MMM-d-yy', 'MMM. d yy',
'M-d-yy', 'M-d-yy h:mm', 'M-d-yy h:mm:ss', 'M-d-yy h:mm am/pm', 'M-d-yy h:mm:ss am/pm', 'M-d-yy HH:mm', 'M-d-yy HH:mm:ss',
'M/d/yy', 'M/d/yy h:mm', 'M/d/yy h:mm:ss', 'M/d/yy h:mm am/pm', 'M/d/yy h:mm:ss am/pm', 'M/d/yy HH:mm', 'M/d/yy HH:mm:ss',
'M-d-yyyy', 'M-d-yyyy h:mm', 'M-d-yyyy h:mm:ss', 'M-d-yyyy h:mm am/pm', 'M-d-yyyy h:mm:ss am/pm', 'M-d-yyyy HH:mm', 'M-d-yyyy HH:mm:ss',
'M/d/yyyy', 'M/d/yyyy h:mm', 'M/d/yyyy h:mm:ss', 'M/d/yyyy h:mm am/pm', 'M/d/yyyy h:mm:ss am/pm', 'M/d/yyyy HH:mm', 'M/d/yyyy HH:mm:ss',
],
],
'options' => ['PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat'],
],
'MACROBUTTON' => [
'properties' => ['macroname' => ''],
],
'XE' => [
'properties' => [],
'options' => ['Bold', 'Italic'],
],
'INDEX' => [
'properties' => [],
'options' => ['PreserveFormat'],
],
'STYLEREF' => [
'properties' => ['StyleIdentifier' => ''],
'options' => ['PreserveFormat'],
],
'FILENAME' => [
'properties' => [
'format' => ['Upper', 'Lower', 'FirstCap', 'Caps'],
],
'options' => ['Path', 'PreserveFormat'],
],
'REF' => [
'properties' => ['name' => ''],
'options' => ['f', 'h', 'n', 'p', 'r', 't', 'w'],
],
];
/**
* Field type.
*
* @var string
*/
protected $type;
/**
* Field text.
*
* @var string|TextRun
*/
protected $text;
/**
* Field properties.
*
* @var array
*/
protected $properties = [];
/**
* Field options.
*
* @var array
*/
protected $options = [];
/**
* Font style.
*
* @var Font|string
*/
protected $fontStyle;
/**
* Set Font style.
*
* @param array|Font|string $style
*
* @return Font|string
*/
public function setFontStyle($style = null)
{
if ($style instanceof Font) {
$this->fontStyle = $style;
} elseif (is_array($style)) {
$this->fontStyle = new Font('text');
$this->fontStyle->setStyleByArray($style);
} elseif (null === $style) {
$this->fontStyle = null;
} else {
$this->fontStyle = $style;
}
return $this->fontStyle;
}
/**
* Get Font style.
*
* @return Font|string
*/
public function getFontStyle()
{
return $this->fontStyle;
}
/**
* Create a new Field Element.
*
* @param string $type
* @param array $properties
* @param array $options
* @param null|string|TextRun $text
* @param array|Font|string $fontStyle
*/
public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null)
{
$this->setType($type);
$this->setProperties($properties);
$this->setOptions($options);
$this->setText($text);
$this->setFontStyle($fontStyle);
}
/**
* Set Field type.
*
* @param string $type
*
* @return string
*/
public function setType($type = null)
{
if (isset($type)) {
if (isset($this->fieldsArray[$type])) {
$this->type = $type;
} else {
throw new InvalidArgumentException("Invalid type '$type'");
}
}
return $this->type;
}
/**
* Get Field type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set Field properties.
*
* @param array $properties
*
* @return self
*/
public function setProperties($properties = [])
{
if (is_array($properties)) {
foreach (array_keys($properties) as $propkey) {
if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) {
throw new InvalidArgumentException("Invalid property '$propkey'");
}
}
$this->properties = array_merge($this->properties, $properties);
}
return $this->properties;
}
/**
* Get Field properties.
*
* @return array
*/
public function getProperties()
{
return $this->properties;
}
/**
* Set Field options.
*
* @param array $options
*
* @return self
*/
public function setOptions($options = [])
{
if (is_array($options)) {
foreach (array_keys($options) as $optionkey) {
if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\') {
throw new InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options']));
}
}
$this->options = array_merge($this->options, $options);
}
return $this->options;
}
/**
* Get Field properties.
*
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* Set Field text.
*
* @param null|string|TextRun $text
*
* @return null|string|TextRun
*/
public function setText($text = null)
{
if (isset($text)) {
if (is_string($text) || $text instanceof TextRun) {
$this->text = $text;
} else {
throw new InvalidArgumentException('Invalid text');
}
}
return $this->text;
}
/**
* Get Field text.
*
* @return string|TextRun
*/
public function getText()
{
return $this->text;
}
}
+119
View File
@@ -0,0 +1,119 @@
<?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\Element;
/**
* Footer element.
*/
class Footer extends AbstractContainer
{
/**
* Header/footer types constants.
*
* @var string
*
* @see http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type
*/
const AUTO = 'default'; // default and odd pages
const FIRST = 'first';
const EVEN = 'even';
/**
* @var string Container type
*/
protected $container = 'Footer';
/**
* Header type.
*
* @var string
*/
protected $type = self::AUTO;
/**
* Create new instance.
*
* @param int $sectionId
* @param int $containerId
* @param string $type
*/
public function __construct($sectionId, $containerId = 1, $type = self::AUTO)
{
$this->sectionId = $sectionId;
$this->setType($type);
$this->setDocPart($this->container, ($sectionId - 1) * 3 + $containerId);
}
/**
* Set type.
*
* @since 0.10.0
*
* @param string $value
*/
public function setType($value = self::AUTO): void
{
if (!in_array($value, [self::AUTO, self::FIRST, self::EVEN])) {
$value = self::AUTO;
}
$this->type = $value;
}
/**
* Get type.
*
* @return string
*
* @since 0.10.0
*/
public function getType()
{
return $this->type;
}
/**
* Reset type to default.
*
* @return string
*/
public function resetType()
{
return $this->type = self::AUTO;
}
/**
* First page only header.
*
* @return string
*/
public function firstPage()
{
return $this->type = self::FIRST;
}
/**
* Even numbered pages only.
*
* @return string
*/
public function evenPage()
{
return $this->type = self::EVEN;
}
}
@@ -0,0 +1,64 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Paragraph;
class Footnote extends AbstractContainer
{
/**
* @var string Container type
*/
protected $container = 'Footnote';
/**
* Paragraph style.
*
* @var null|Paragraph|string
*/
protected $paragraphStyle;
/**
* Is part of collection.
*
* @var bool
*/
protected $collectionRelation = true;
/**
* Create new instance.
*
* @param array|Paragraph|string $paragraphStyle
*/
public function __construct($paragraphStyle = null)
{
$this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
$this->setDocPart($this->container);
}
/**
* Get paragraph style.
*
* @return null|Paragraph|string
*/
public function getParagraphStyle()
{
return $this->paragraphStyle;
}
}
@@ -0,0 +1,201 @@
<?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\Element;
/**
* Form field element.
*
* @since 0.12.0
* @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html
*/
class FormField extends Text
{
/**
* Form field type: textinput|checkbox|dropdown.
*
* @var string
*/
private $type = 'textinput';
/**
* Form field name.
*
* @var ?string
*/
private $name;
/**
* Default value.
*
* - TextInput: string
* - CheckBox: bool
* - DropDown: int Index of entries (zero based)
*
* @var bool|int|string
*/
private $default;
/**
* Value.
*
* @var null|bool|int|string
*/
private $value;
/**
* Dropdown entries.
*
* @var array
*/
private $entries = [];
/**
* Create new instance.
*
* @param string $type
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function __construct($type, $fontStyle = null, $paragraphStyle = null)
{
parent::__construct(null, $fontStyle, $paragraphStyle);
$this->setType($type);
}
/**
* Get type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set type.
*
* @param string $value
*
* @return self
*/
public function setType($value)
{
$enum = ['textinput', 'checkbox', 'dropdown'];
$this->type = $this->setEnumVal($value, $enum, $this->type);
return $this;
}
/**
* Get name.
*
* @return ?string
*/
public function getName()
{
return $this->name;
}
/**
* Set name.
*
* @param ?string $value
*
* @return self
*/
public function setName($value)
{
$this->name = $value;
return $this;
}
/**
* Get default.
*
* @return bool|int|string
*/
public function getDefault()
{
return $this->default;
}
/**
* Set default.
*
* @param bool|int|string $value
*
* @return self
*/
public function setDefault($value)
{
$this->default = $value;
return $this;
}
/**
* Get value.
*
* @return null|bool|int|string
*/
public function getValue()
{
return $this->value;
}
/**
* Set value.
*
* @param null|bool|int|string $value
*
* @return self
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* Get entries.
*
* @return array
*/
public function getEntries()
{
return $this->entries;
}
/**
* Set entries.
*
* @param array $value
*
* @return self
*/
public function setEntries($value)
{
$this->entries = $value;
return $this;
}
}
@@ -0,0 +1,54 @@
<?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
*/
declare(strict_types=1);
namespace PhpOffice\PhpWord\Element;
use PhpOffice\Math\Math;
/**
* Formula element.
*/
class Formula extends AbstractElement
{
/**
* @var Math
*/
protected $math;
/**
* Create a new Formula Element.
*/
public function __construct(Math $math)
{
$this->setMath($math);
}
public function setMath(Math $math): self
{
$this->math = $math;
return $this;
}
public function getMath(): Math
{
return $this->math;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?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\Element;
/**
* Header element.
*/
class Header extends Footer
{
/**
* @var string Container type
*/
protected $container = 'Header';
/**
* Add a Watermark Element.
*
* @param string $src
* @param mixed $style
*
* @return Image
*/
public function addWatermark($src, $style = null)
{
return $this->addImage($src, $style, true);
}
}
+601
View File
@@ -0,0 +1,601 @@
<?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\Element;
use PhpOffice\PhpWord\Exception\CreateTemporaryFileException;
use PhpOffice\PhpWord\Exception\InvalidImageException;
use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\ZipArchive;
use PhpOffice\PhpWord\Style\Image as ImageStyle;
/**
* Image element.
*/
class Image extends AbstractElement
{
/**
* Image source type constants.
*/
const SOURCE_LOCAL = 'local'; // Local images
const SOURCE_GD = 'gd'; // Generated using GD
const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image
const SOURCE_STRING = 'string'; // Image from string
/**
* Image source.
*
* @var string
*/
private $source;
/**
* Source type: local|gd|archive.
*
* @var string
*/
private $sourceType;
/**
* Image style.
*
* @var ?ImageStyle
*/
private $style;
/**
* Is watermark.
*
* @var bool
*/
private $watermark;
/**
* Name of image.
*
* @var string
*/
private $name;
/**
* Image type.
*
* @var string
*/
private $imageType;
/**
* Image create function.
*
* @var string
*/
private $imageCreateFunc;
/**
* Image function.
*
* @var null|callable(resource): void
*/
private $imageFunc;
/**
* Image extension.
*
* @var string
*/
private $imageExtension;
/**
* Image quality.
*
* Functions imagepng() and imagejpeg() have an optional parameter for
* quality.
*
* @var null|int
*/
private $imageQuality;
/**
* Is memory image.
*
* @var bool
*/
private $memoryImage;
/**
* Image target file name.
*
* @var string
*/
private $target;
/**
* Image media index.
*
* @var int
*/
private $mediaIndex;
/**
* Has media relation flag; true for Link, Image, and Object.
*
* @var bool
*/
protected $mediaRelation = true;
/**
* Create new image element.
*
* @param string $source
* @param mixed $style
* @param bool $watermark
* @param string $name
*/
public function __construct($source, $style = null, $watermark = false, $name = null)
{
$this->source = $source;
$this->style = $this->setNewStyle(new ImageStyle(), $style, true);
$this->setIsWatermark($watermark);
$this->setName($name);
$this->checkImage();
}
/**
* Get Image style.
*
* @return ?ImageStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get image source.
*
* @return string
*/
public function getSource()
{
return $this->source;
}
/**
* Get image source type.
*
* @return string
*/
public function getSourceType()
{
return $this->sourceType;
}
/**
* Sets the image name.
*
* @param string $value
*/
public function setName($value): void
{
$this->name = $value;
}
/**
* Get image name.
*
* @return null|string
*/
public function getName()
{
return $this->name;
}
/**
* Get image media ID.
*
* @return string
*/
public function getMediaId()
{
return md5($this->source);
}
/**
* Get is watermark.
*
* @return bool
*/
public function isWatermark()
{
return $this->watermark;
}
/**
* Set is watermark.
*
* @param bool $value
*/
public function setIsWatermark($value): void
{
$this->watermark = $value;
}
/**
* Get image type.
*
* @return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Get image create function.
*
* @return string
*/
public function getImageCreateFunction()
{
return $this->imageCreateFunc;
}
/**
* Get image function.
*
* @return null|callable(resource): void
*/
public function getImageFunction(): ?callable
{
return $this->imageFunc;
}
/**
* Get image quality.
*/
public function getImageQuality(): ?int
{
return $this->imageQuality;
}
/**
* Get image extension.
*
* @return string
*/
public function getImageExtension()
{
return $this->imageExtension;
}
/**
* Get is memory image.
*
* @return bool
*/
public function isMemImage()
{
return $this->memoryImage;
}
/**
* Get target file name.
*
* @return string
*/
public function getTarget()
{
return $this->target;
}
/**
* Set target file name.
*
* @param string $value
*/
public function setTarget($value): void
{
$this->target = $value;
}
/**
* Get media index.
*
* @return int
*/
public function getMediaIndex()
{
return $this->mediaIndex;
}
/**
* Set media index.
*
* @param int $value
*/
public function setMediaIndex($value): void
{
$this->mediaIndex = $value;
}
/**
* Get image string.
*/
public function getImageString(): ?string
{
$source = $this->source;
$actualSource = null;
$imageBinary = null;
$isTemp = false;
// Get actual source from archive image or other source
// Return null if not found
if ($this->sourceType == self::SOURCE_ARCHIVE) {
$source = substr($source, 6);
[$zipFilename, $imageFilename] = explode('#', $source);
$zip = new ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename) !== false) {
$isTemp = true;
$zip->extractTo(Settings::getTempDir(), $imageFilename);
$actualSource = Settings::getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
}
}
$zip->close();
} else {
$actualSource = $source;
}
// Can't find any case where $actualSource = null hasn't captured by
// preceding exceptions. Please uncomment when you find the case and
// put the case into Element\ImageTest.
// if ($actualSource === null) {
// return null;
// }
// Read image binary data and convert to hex/base64 string
if ($this->sourceType == self::SOURCE_GD) {
$imageResource = call_user_func($this->imageCreateFunc, $actualSource);
if ($this->imageType === 'image/png') {
// PNG images need to preserve alpha channel information
imagesavealpha($imageResource, true);
}
ob_start();
$callback = $this->imageFunc;
$callback($imageResource);
$imageBinary = ob_get_contents();
ob_end_clean();
} elseif ($this->sourceType == self::SOURCE_STRING) {
$imageBinary = $this->source;
} else {
$fileHandle = fopen($actualSource, 'rb', false);
$fileSize = filesize($actualSource);
if ($fileHandle !== false && $fileSize > 0) {
$imageBinary = fread($fileHandle, $fileSize);
fclose($fileHandle);
}
}
// Delete temporary file if necessary
if ($isTemp === true) {
@unlink($actualSource);
}
return $imageBinary;
}
/**
* Get image string data.
*
* @param bool $base64
*
* @return null|string
*
* @since 0.11.0
*/
public function getImageStringData($base64 = false)
{
$imageBinary = $this->getImageString();
if ($imageBinary === null) {
return null;
}
if ($base64) {
return base64_encode($imageBinary);
}
return bin2hex($imageBinary);
}
/**
* Check memory image, supported type, image functions, and proportional width/height.
*/
private function checkImage(): void
{
$this->setSourceType();
// Check image data
if ($this->sourceType == self::SOURCE_ARCHIVE) {
$imageData = $this->getArchiveImageSize($this->source);
} elseif ($this->sourceType == self::SOURCE_STRING) {
$imageData = @getimagesizefromstring($this->source);
} else {
$imageData = @getimagesize($this->source);
}
if (!is_array($imageData)) {
throw new InvalidImageException(sprintf('Invalid image: %s', $this->source));
}
[$actualWidth, $actualHeight, $imageType] = $imageData;
// Check image type support
$supportedTypes = [IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG];
if ($this->sourceType != self::SOURCE_GD && $this->sourceType != self::SOURCE_STRING) {
$supportedTypes = array_merge($supportedTypes, [IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM]);
}
if (!in_array($imageType, $supportedTypes)) {
throw new UnsupportedImageTypeException();
}
// Define image functions
$this->imageType = image_type_to_mime_type($imageType);
$this->setFunctions();
$this->setProportionalSize($actualWidth, $actualHeight);
}
/**
* Set source type.
*/
private function setSourceType(): void
{
if (stripos(strrev($this->source), strrev('.php')) === 0) {
$this->memoryImage = true;
$this->sourceType = self::SOURCE_GD;
} elseif (strpos($this->source, 'zip://') !== false) {
$this->memoryImage = false;
$this->sourceType = self::SOURCE_ARCHIVE;
} elseif (filter_var($this->source, FILTER_VALIDATE_URL) !== false) {
$this->memoryImage = true;
if (strpos($this->source, 'https') === 0) {
$fileContent = file_get_contents($this->source);
$this->source = $fileContent;
$this->sourceType = self::SOURCE_STRING;
} else {
$this->sourceType = self::SOURCE_GD;
}
} elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) {
$this->memoryImage = false;
$this->sourceType = self::SOURCE_LOCAL;
} else {
$this->memoryImage = true;
$this->sourceType = self::SOURCE_STRING;
}
}
/**
* Get image size from archive.
*
* @since 0.12.0 Throws CreateTemporaryFileException.
*
* @param string $source
*
* @return null|array
*/
private function getArchiveImageSize($source)
{
$imageData = null;
$source = substr($source, 6);
[$zipFilename, $imageFilename] = explode('#', $source);
$tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage');
if (false === $tempFilename) {
throw new CreateTemporaryFileException(); // @codeCoverageIgnore
}
$zip = new ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename) !== false) {
$imageContent = $zip->getFromName($imageFilename);
if ($imageContent !== false) {
file_put_contents($tempFilename, $imageContent);
$imageData = getimagesize($tempFilename);
unlink($tempFilename);
}
}
$zip->close();
}
return $imageData;
}
/**
* Set image functions and extensions.
*/
private function setFunctions(): void
{
switch ($this->imageType) {
case 'image/png':
$this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng';
$this->imageFunc = function ($resource): void {
imagepng($resource, null, $this->imageQuality);
};
$this->imageExtension = 'png';
$this->imageQuality = -1;
break;
case 'image/gif':
$this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif';
$this->imageFunc = function ($resource): void {
imagegif($resource);
};
$this->imageExtension = 'gif';
$this->imageQuality = null;
break;
case 'image/jpeg':
case 'image/jpg':
$this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg';
$this->imageFunc = function ($resource): void {
imagejpeg($resource, null, $this->imageQuality);
};
$this->imageExtension = 'jpg';
$this->imageQuality = 100;
break;
case 'image/bmp':
case 'image/x-ms-bmp':
$this->imageType = 'image/bmp';
$this->imageFunc = null;
$this->imageExtension = 'bmp';
$this->imageQuality = null;
break;
case 'image/tiff':
$this->imageType = 'image/tiff';
$this->imageFunc = null;
$this->imageExtension = 'tif';
$this->imageQuality = null;
break;
}
}
/**
* Set proportional width/height if one dimension not available.
*
* @param int $actualWidth
* @param int $actualHeight
*/
private function setProportionalSize($actualWidth, $actualHeight): void
{
$styleWidth = $this->style->getWidth();
$styleHeight = $this->style->getHeight();
if (!($styleWidth && $styleHeight)) {
if ($styleWidth == null && $styleHeight == null) {
$this->style->setWidth($actualWidth);
$this->style->setHeight($actualHeight);
} elseif ($styleWidth) {
$this->style->setHeight($actualHeight * ($styleWidth / $actualWidth));
} else {
$this->style->setWidth($actualWidth * ($styleHeight / $actualHeight));
}
}
}
}
+54
View File
@@ -0,0 +1,54 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Line as LineStyle;
/**
* Line element.
*/
class Line extends AbstractElement
{
/**
* Line style.
*
* @var ?LineStyle
*/
private $style;
/**
* Create new line element.
*
* @param mixed $style
*/
public function __construct($style = null)
{
$this->style = $this->setNewStyle(new LineStyle(), $style);
}
/**
* Get line style.
*
* @return ?LineStyle
*/
public function getStyle()
{
return $this->style;
}
}
+137
View File
@@ -0,0 +1,137 @@
<?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\Element;
use PhpOffice\PhpWord\Shared\Text as SharedText;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
/**
* Link element.
*/
class Link extends AbstractElement
{
/**
* Link source.
*
* @var string
*/
private $source;
/**
* Link text.
*
* @var string
*/
private $text;
/**
* Font style.
*
* @var null|Font|string
*/
private $fontStyle;
/**
* Paragraph style.
*
* @var null|Paragraph|string
*/
private $paragraphStyle;
/**
* Has media relation flag; true for Link, Image, and Object.
*
* @var bool
*/
protected $mediaRelation = true;
/**
* Has internal flag - anchor to internal bookmark.
*
* @var bool
*/
protected $internal = false;
/**
* Create a new Link Element.
*
* @param string $source
* @param string $text
* @param mixed $fontStyle
* @param mixed $paragraphStyle
* @param bool $internal
*/
public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false)
{
$this->source = SharedText::toUTF8($source);
$this->text = null === $text ? $this->source : SharedText::toUTF8($text);
$this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);
$this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
$this->internal = $internal;
}
/**
* Get link source.
*
* @return string
*/
public function getSource()
{
return $this->source;
}
/**
* Get link text.
*/
public function getText(): string
{
return $this->text;
}
/**
* Get Text style.
*
* @return null|Font|string
*/
public function getFontStyle()
{
return $this->fontStyle;
}
/**
* Get Paragraph style.
*
* @return null|Paragraph|string
*/
public function getParagraphStyle()
{
return $this->paragraphStyle;
}
/**
* is internal.
*
* @return bool
*/
public function isInternal()
{
return $this->internal;
}
}
@@ -0,0 +1,113 @@
<?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\Element;
use PhpOffice\PhpWord\Shared\Text as SharedText;
use PhpOffice\PhpWord\Style\ListItem as ListItemStyle;
/**
* List item element.
*/
class ListItem extends AbstractElement
{
/**
* Element style.
*
* @var ?ListItemStyle
*/
private $style;
/**
* Text object.
*
* @var Text
*/
private $textObject;
/**
* Depth.
*
* @var int
*/
private $depth;
/**
* Create a new ListItem.
*
* @param string $text
* @param int $depth
* @param mixed $fontStyle
* @param null|array|string $listStyle
* @param mixed $paragraphStyle
*/
public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null)
{
$this->textObject = new Text(SharedText::toUTF8($text), $fontStyle, $paragraphStyle);
$this->depth = $depth;
// Version >= 0.10.0 will pass numbering style name. Older version will use old method
if (null !== $listStyle && is_string($listStyle)) {
$this->style = new ListItemStyle($listStyle); // @codeCoverageIgnore
} else {
$this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true);
}
}
/**
* Get style.
*
* @return ?ListItemStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get Text object.
*
* @return Text
*/
public function getTextObject()
{
return $this->textObject;
}
/**
* Get depth.
*
* @return int
*/
public function getDepth()
{
return $this->depth;
}
/**
* Get text.
*
* @return string
*
* @since 0.11.0
*/
public function getText()
{
return $this->textObject->getText();
}
}
@@ -0,0 +1,86 @@
<?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\Element;
use PhpOffice\PhpWord\Style\ListItem as ListItemStyle;
/**
* List item element.
*/
class ListItemRun extends TextRun
{
/**
* @var string Container type
*/
protected $container = 'ListItemRun';
/**
* ListItem Style.
*
* @var ?ListItemStyle
*/
private $style;
/**
* ListItem Depth.
*
* @var int
*/
private $depth;
/**
* Create a new ListItem.
*
* @param int $depth
* @param null|array|string $listStyle
* @param mixed $paragraphStyle
*/
public function __construct($depth = 0, $listStyle = null, $paragraphStyle = null)
{
$this->depth = $depth;
// Version >= 0.10.0 will pass numbering style name. Older version will use old method
if (null !== $listStyle && is_string($listStyle)) {
$this->style = new ListItemStyle($listStyle);
} else {
$this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true);
}
parent::__construct($paragraphStyle);
}
/**
* Get ListItem style.
*
* @return ?ListItemStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get ListItem depth.
*
* @return int
*/
public function getDepth()
{
return $this->depth;
}
}
@@ -0,0 +1,140 @@
<?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\Element;
use PhpOffice\PhpWord\Exception\InvalidObjectException;
use PhpOffice\PhpWord\Style\Image as ImageStyle;
/**
* OLEObject element.
*/
class OLEObject extends AbstractElement
{
/**
* Ole-Object Src.
*
* @var string
*/
private $source;
/**
* Image Style.
*
* @var ?ImageStyle
*/
private $style;
/**
* Icon.
*
* @var string
*/
private $icon;
/**
* Image Relation ID.
*
* @var int
*/
private $imageRelationId;
/**
* Has media relation flag; true for Link, Image, and Object.
*
* @var bool
*/
protected $mediaRelation = true;
/**
* Create a new Ole-Object Element.
*
* @param string $source
* @param mixed $style
*/
public function __construct($source, $style = null)
{
$supportedTypes = ['xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'];
$pathInfo = pathinfo($source);
if (file_exists($source) && in_array($pathInfo['extension'], $supportedTypes)) {
$ext = $pathInfo['extension'];
if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') {
$ext = substr($ext, 0, -1);
}
$this->source = $source;
$this->style = $this->setNewStyle(new ImageStyle(), $style, true);
$this->icon = realpath(__DIR__ . "/../resources/{$ext}.png");
return;
}
throw new InvalidObjectException();
}
/**
* Get object source.
*
* @return string
*/
public function getSource()
{
return $this->source;
}
/**
* Get object style.
*
* @return ?ImageStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get object icon.
*
* @return string
*/
public function getIcon()
{
return $this->icon;
}
/**
* Get image relation ID.
*
* @return int
*/
public function getImageRelationId()
{
return $this->imageRelationId;
}
/**
* Set Image Relation ID.
*
* @param int $rId
*/
public function setImageRelationId($rId): void
{
$this->imageRelationId = $rId;
}
}
@@ -0,0 +1,32 @@
<?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\Element;
/**
* Page break element.
*/
class PageBreak extends AbstractElement
{
/**
* Create new page break.
*/
public function __construct()
{
}
}
@@ -0,0 +1,99 @@
<?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\Element;
use PhpOffice\PhpWord\Shared\Text as SharedText;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
/**
* Preserve text/field element.
*/
class PreserveText extends AbstractElement
{
/**
* Text content.
*
* @var null|array|string
*/
private $text;
/**
* Text style.
*
* @var null|Font|string
*/
private $fontStyle;
/**
* Paragraph style.
*
* @var null|Paragraph|string
*/
private $paragraphStyle;
/**
* Create a new Preserve Text Element.
*
* @param string $text
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function __construct($text = null, $fontStyle = null, $paragraphStyle = null)
{
$this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);
$this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
$this->text = SharedText::toUTF8($text);
$matches = preg_split('/({.*?})/', $this->text ?? '', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if (isset($matches[0])) {
$this->text = $matches;
}
}
/**
* Get Text style.
*
* @return null|Font|string
*/
public function getFontStyle()
{
return $this->fontStyle;
}
/**
* Get Paragraph style.
*
* @return null|Paragraph|string
*/
public function getParagraphStyle()
{
return $this->paragraphStyle;
}
/**
* Get Text content.
*
* @return null|array|string
*/
public function getText()
{
return $this->text;
}
}
+109
View File
@@ -0,0 +1,109 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Row as RowStyle;
/**
* Table row element.
*
* @since 0.8.0
*/
class Row extends AbstractElement
{
/**
* Row height.
*
* @var ?int
*/
private $height;
/**
* Row style.
*
* @var ?RowStyle
*/
private $style;
/**
* Row cells.
*
* @var Cell[]
*/
private $cells = [];
/**
* Create a new table row.
*
* @param int $height
* @param mixed $style
*/
public function __construct($height = null, $style = null)
{
$this->height = $height;
$this->style = $this->setNewStyle(new RowStyle(), $style, true);
}
/**
* Add a cell.
*
* @param int $width
* @param mixed $style
*
* @return Cell
*/
public function addCell($width = null, $style = null)
{
$cell = new Cell($width, $style);
$cell->setParentContainer($this);
$this->cells[] = $cell;
return $cell;
}
/**
* Get all cells.
*
* @return Cell[]
*/
public function getCells()
{
return $this->cells;
}
/**
* Get row style.
*
* @return ?RowStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get row height.
*
* @return ?int
*/
public function getHeight()
{
return $this->height;
}
}
+114
View File
@@ -0,0 +1,114 @@
<?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\Element;
use PhpOffice\PhpWord\ComplexType\RubyProperties;
/**
* Ruby element.
*
* @see https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.ruby?view=openxml-3.0.1
*/
class Ruby extends AbstractElement
{
/**
* Ruby properties.
*
* @var RubyProperties
*/
protected $properties;
/**
* Ruby text run.
*
* @var TextRun
*/
protected $rubyTextRun;
/**
* Ruby base text run.
*
* @var TextRun
*/
protected $baseTextRun;
/**
* Create a new Ruby Element.
*/
public function __construct(TextRun $baseTextRun, TextRun $rubyTextRun, RubyProperties $properties)
{
$this->baseTextRun = $baseTextRun;
$this->rubyTextRun = $rubyTextRun;
$this->properties = $properties;
}
/**
* Get base text run.
*/
public function getBaseTextRun(): TextRun
{
return $this->baseTextRun;
}
/**
* Set the base text run.
*/
public function setBaseTextRun(TextRun $textRun): self
{
$this->baseTextRun = $textRun;
return $this;
}
/**
* Get ruby text run.
*/
public function getRubyTextRun(): TextRun
{
return $this->rubyTextRun;
}
/**
* Set the ruby text run.
*/
public function setRubyTextRun(TextRun $textRun): self
{
$this->rubyTextRun = $textRun;
return $this;
}
/**
* Get ruby properties.
*/
public function getProperties(): RubyProperties
{
return $this->properties;
}
/**
* Set the ruby properties.
*/
public function setProperties(RubyProperties $properties): self
{
$this->properties = $properties;
return $this;
}
}
+196
View File
@@ -0,0 +1,196 @@
<?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\Element;
/**
* Structured document tag (SDT) element.
*
* @since 0.12.0
*/
class SDT extends Text
{
/**
* Form field type: comboBox|dropDownList|date.
*
* @var string
*/
private $type;
/**
* Value.
*
* @var null|bool|int|string
*/
private $value;
/**
* CheckBox/DropDown list entries.
*
* @var array
*/
private $listItems = [];
/**
* Alias.
*
* @var string
*/
private $alias;
/**
* Tag.
*
* @var string
*/
private $tag;
/**
* Create new instance.
*
* @param string $type
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function __construct($type, $fontStyle = null, $paragraphStyle = null)
{
parent::__construct(null, $fontStyle, $paragraphStyle);
$this->setType($type);
}
/**
* Get type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set type.
*
* @param string $value
*
* @return self
*/
public function setType($value)
{
$enum = ['plainText', 'comboBox', 'dropDownList', 'date'];
$this->type = $this->setEnumVal($value, $enum, 'comboBox');
return $this;
}
/**
* Get value.
*
* @return null|bool|int|string
*/
public function getValue()
{
return $this->value;
}
/**
* Set value.
*
* @param null|bool|int|string $value
*
* @return self
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* Get listItems.
*
* @return array
*/
public function getListItems()
{
return $this->listItems;
}
/**
* Set listItems.
*
* @param array $value
*
* @return self
*/
public function setListItems($value)
{
$this->listItems = $value;
return $this;
}
/**
* Get tag.
*
* @return string
*/
public function getTag()
{
return $this->tag;
}
/**
* Set tag.
*
* @param string $tag
*
* @return self
*/
public function setTag($tag)
{
$this->tag = $tag;
return $this;
}
/**
* Get alias.
*
* @return string
*/
public function getAlias()
{
return $this->alias;
}
/**
* Set alias.
*
* @param string $alias
*
* @return self
*/
public function setAlias($alias)
{
$this->alias = $alias;
return $this;
}
}
+218
View File
@@ -0,0 +1,218 @@
<?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\Element;
use Exception;
use PhpOffice\PhpWord\ComplexType\FootnoteProperties;
use PhpOffice\PhpWord\Style\Section as SectionStyle;
class Section extends AbstractContainer
{
/**
* @var string Container type
*/
protected $container = 'Section';
/**
* Section style.
*
* @var ?SectionStyle
*/
private $style;
/**
* Section headers, indexed from 1, not zero.
*
* @var Header[]
*/
private $headers = [];
/**
* Section footers, indexed from 1, not zero.
*
* @var Footer[]
*/
private $footers = [];
/**
* The properties for the footnote of this section.
*
* @var FootnoteProperties
*/
private $footnoteProperties;
/**
* Create new instance.
*
* @param int $sectionCount
* @param null|array|\PhpOffice\PhpWord\Style|string $style
*/
public function __construct($sectionCount, $style = null)
{
$this->sectionId = $sectionCount;
$this->setDocPart($this->container, $this->sectionId);
if (null === $style) {
$style = new SectionStyle();
}
$this->style = $this->setNewStyle(new SectionStyle(), $style);
}
/**
* Set section style.
*
* @param array $style
*/
public function setStyle($style = null): void
{
if (null !== $style && is_array($style)) {
$this->style->setStyleByArray($style);
}
}
/**
* Get section style.
*
* @return ?SectionStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Add header.
*
* @since 0.10.0
*
* @param string $type
*
* @return Header
*/
public function addHeader($type = Header::AUTO)
{
return $this->addHeaderFooter($type, true);
}
/**
* Add footer.
*
* @since 0.10.0
*
* @param string $type
*
* @return Footer
*/
public function addFooter($type = Header::AUTO)
{
return $this->addHeaderFooter($type, false);
}
/**
* Get header elements.
*
* @return Header[]
*/
public function getHeaders()
{
return $this->headers;
}
/**
* Get footer elements.
*
* @return Footer[]
*/
public function getFooters()
{
return $this->footers;
}
/**
* Get the footnote properties.
*
* @return FootnoteProperties
*/
public function getFootnoteProperties()
{
return $this->footnoteProperties;
}
/**
* Set the footnote properties.
*/
public function setFootnoteProperties(?FootnoteProperties $footnoteProperties = null): void
{
$this->footnoteProperties = $footnoteProperties;
}
/**
* Is there a header for this section that is for the first page only?
*
* If any of the Header instances have a type of Header::FIRST then this method returns true.
* False otherwise.
*
* @return bool
*/
public function hasDifferentFirstPage()
{
foreach ($this->headers as $header) {
if ($header->getType() == Header::FIRST) {
return true;
}
}
foreach ($this->footers as $footer) {
if ($footer->getType() == Header::FIRST) {
return true;
}
}
return false;
}
/**
* Add header/footer.
*
* @since 0.10.0
*
* @param string $type
* @param bool $header
*
* @return Footer|Header
*/
private function addHeaderFooter($type = Header::AUTO, $header = true)
{
$containerClass = substr(static::class, 0, strrpos(static::class, '\\') ?: 0) . '\\' .
($header ? 'Header' : 'Footer');
$collectionArray = $header ? 'headers' : 'footers';
$collection = &$this->$collectionArray;
if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) {
$index = count($collection);
/** @var AbstractContainer $container Type hint */
$container = new $containerClass($this->sectionId, ++$index, $type);
$container->setPhpWord($this->phpWord);
$collection[$index] = $container;
return $container;
}
throw new Exception('Invalid header/footer type.');
}
}
+90
View File
@@ -0,0 +1,90 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Shape as ShapeStyle;
/**
* Shape element.
*
* @since 0.12.0
*/
class Shape extends AbstractElement
{
/**
* Shape type arc|curve|line|polyline|rect|oval.
*
* @var string
*/
private $type;
/**
* Shape style.
*
* @var ?ShapeStyle
*/
private $style;
/**
* Create new instance.
*
* @param string $type
* @param mixed $style
*/
public function __construct($type, $style = null)
{
$this->setType($type);
$this->style = $this->setNewStyle(new ShapeStyle(), $style);
}
/**
* Get type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Set pattern.
*
* @param string $value
*
* @return self
*/
public function setType($value = null)
{
$enum = ['arc', 'curve', 'line', 'polyline', 'rect', 'oval'];
$this->type = $this->setEnumVal($value, $enum, null);
return $this;
}
/**
* Get shape style.
*
* @return ?ShapeStyle
*/
public function getStyle()
{
return $this->style;
}
}
+170
View File
@@ -0,0 +1,170 @@
<?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\Element;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\TOC as TOCStyle;
/**
* Table of contents.
*/
class TOC extends AbstractElement
{
/**
* TOC style.
*
* @var TOCStyle
*/
private $tocStyle;
/**
* Font style.
*
* @var Font|string
*/
private $fontStyle;
/**
* Min title depth to show.
*
* @var int
*/
private $minDepth = 1;
/**
* Max title depth to show.
*
* @var int
*/
private $maxDepth = 9;
/**
* Create a new Table-of-Contents Element.
*
* @param mixed $fontStyle
* @param array $tocStyle
* @param int $minDepth
* @param int $maxDepth
*/
public function __construct($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9)
{
$this->tocStyle = new TOCStyle();
if (null !== $tocStyle && is_array($tocStyle)) {
$this->tocStyle->setStyleByArray($tocStyle);
}
if (null !== $fontStyle && is_array($fontStyle)) {
$this->fontStyle = new Font();
$this->fontStyle->setStyleByArray($fontStyle);
} else {
$this->fontStyle = $fontStyle;
}
$this->minDepth = $minDepth;
$this->maxDepth = $maxDepth;
}
/**
* Get all titles.
*
* @return array
*/
public function getTitles()
{
if (!$this->phpWord instanceof PhpWord) {
return [];
}
$titles = $this->phpWord->getTitles()->getItems();
foreach ($titles as $i => $title) {
/** @var Title $title Type hint */
$depth = $title->getDepth();
if ($this->minDepth > $depth) {
unset($titles[$i]);
}
if (($this->maxDepth != 0) && ($this->maxDepth < $depth)) {
unset($titles[$i]);
}
}
return $titles;
}
/**
* Get TOC Style.
*
* @return TOCStyle
*/
public function getStyleTOC()
{
return $this->tocStyle;
}
/**
* Get Font Style.
*
* @return Font|string
*/
public function getStyleFont()
{
return $this->fontStyle;
}
/**
* Set max depth.
*
* @param int $value
*/
public function setMaxDepth($value): void
{
$this->maxDepth = $value;
}
/**
* Get Max Depth.
*
* @return int Max depth of titles
*/
public function getMaxDepth()
{
return $this->maxDepth;
}
/**
* Set min depth.
*
* @param int $value
*/
public function setMinDepth($value): void
{
$this->minDepth = $value;
}
/**
* Get Min Depth.
*
* @return int Min depth of titles
*/
public function getMinDepth()
{
return $this->minDepth;
}
}
+177
View File
@@ -0,0 +1,177 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Table as TableStyle;
/**
* Table element.
*/
class Table extends AbstractElement
{
/**
* Table style.
*
* @var ?TableStyle
*/
private $style;
/**
* Table rows.
*
* @var Row[]
*/
private $rows = [];
/**
* Table width.
*
* @var ?int
*/
private $width;
/**
* Create a new table.
*
* @param mixed $style
*/
public function __construct($style = null)
{
$this->style = $this->setNewStyle(new TableStyle(), $style);
}
/**
* Add a row.
*
* @param int $height
* @param mixed $style
*
* @return Row
*/
public function addRow($height = null, $style = null)
{
$row = new Row($height, $style);
$row->setParentContainer($this);
$this->rows[] = $row;
return $row;
}
/**
* Add a cell.
*
* @param int $width
* @param mixed $style
*
* @return Cell
*/
public function addCell($width = null, $style = null)
{
$index = count($this->rows) - 1;
$row = $this->rows[$index];
$cell = $row->addCell($width, $style);
return $cell;
}
/**
* Get all rows.
*
* @return Row[]
*/
public function getRows()
{
return $this->rows;
}
/**
* Get table style.
*
* @return null|string|TableStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get table width.
*
* @return ?int
*/
public function getWidth()
{
return $this->width;
}
/**
* Set table width.
*
* @param int $width
*/
public function setWidth($width): void
{
$this->width = $width;
}
/**
* Get column count.
*
* @return int
*/
public function countColumns()
{
$columnCount = 0;
$rowCount = count($this->rows);
for ($i = 0; $i < $rowCount; ++$i) {
/** @var Row $row Type hint */
$row = $this->rows[$i];
$cellCount = count($row->getCells());
if ($columnCount < $cellCount) {
$columnCount = $cellCount;
}
}
return $columnCount;
}
/**
* The first declared cell width for each column.
*
* @return int[]
*/
public function findFirstDefinedCellWidths()
{
$cellWidths = [];
foreach ($this->rows as $row) {
$cells = $row->getCells();
if (count($cells) <= count($cellWidths)) {
continue;
}
$cellWidths = [];
foreach ($cells as $cell) {
$cellWidths[] = $cell->getWidth();
}
}
return $cellWidths;
}
}
+155
View File
@@ -0,0 +1,155 @@
<?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\Element;
use PhpOffice\PhpWord\Shared\Text as SharedText;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
/**
* Text element.
*/
class Text extends AbstractElement
{
/**
* Text content.
*
* @var ?string
*/
protected $text;
/**
* Text style.
*
* @var Font|string
*/
protected $fontStyle;
/**
* Paragraph style.
*
* @var Paragraph|string
*/
protected $paragraphStyle;
/**
* Create a new Text Element.
*
* @param string $text
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function __construct($text = null, $fontStyle = null, $paragraphStyle = null)
{
$this->setText($text);
$paragraphStyle = $this->setParagraphStyle($paragraphStyle);
$this->setFontStyle($fontStyle, $paragraphStyle);
}
/**
* Set Text style.
*
* @param array|Font|string $style
* @param array|Paragraph|string $paragraphStyle
*
* @return Font|string
*/
public function setFontStyle($style = null, $paragraphStyle = null)
{
if ($style instanceof Font) {
$this->fontStyle = $style;
$this->setParagraphStyle($paragraphStyle);
} elseif (is_array($style)) {
$this->fontStyle = new Font('text', $paragraphStyle);
$this->fontStyle->setStyleByArray($style);
} elseif (null === $style) {
$this->fontStyle = new Font('text', $paragraphStyle);
} else {
$this->fontStyle = $style;
$this->setParagraphStyle($paragraphStyle);
}
return $this->fontStyle;
}
/**
* Get Text style.
*
* @return Font|string
*/
public function getFontStyle()
{
return $this->fontStyle;
}
/**
* Set Paragraph style.
*
* @param array|Paragraph|string $style
*
* @return Paragraph|string
*/
public function setParagraphStyle($style = null)
{
if (is_array($style)) {
$this->paragraphStyle = new Paragraph();
$this->paragraphStyle->setStyleByArray($style);
} elseif ($style instanceof Paragraph) {
$this->paragraphStyle = $style;
} elseif (null === $style) {
$this->paragraphStyle = new Paragraph();
} else {
$this->paragraphStyle = $style;
}
return $this->paragraphStyle;
}
/**
* Get Paragraph style.
*
* @return Paragraph|string
*/
public function getParagraphStyle()
{
return $this->paragraphStyle;
}
/**
* Set text content.
*
* @param string $text
*
* @return self
*/
public function setText($text)
{
$this->text = SharedText::toUTF8($text);
return $this;
}
/**
* Get Text content.
*/
public function getText(): ?string
{
return $this->text;
}
}
@@ -0,0 +1,61 @@
<?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\Element;
use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle;
/**
* TextBox element.
*
* @since 0.11.0
*/
class TextBox extends AbstractContainer
{
/**
* @var string Container type
*/
protected $container = 'TextBox';
/**
* TextBox style.
*
* @var ?TextBoxStyle
*/
private $style;
/**
* Create a new textbox.
*
* @param mixed $style
*/
public function __construct($style = null)
{
$this->style = $this->setNewStyle(new TextBoxStyle(), $style);
}
/**
* Get textbox style.
*
* @return ?TextBoxStyle
*/
public function getStyle()
{
return $this->style;
}
}
@@ -0,0 +1,133 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
/**
* Text break element.
*/
class TextBreak extends AbstractElement
{
/**
* Paragraph style.
*
* @var null|Paragraph|string
*/
private $paragraphStyle;
/**
* Text style.
*
* @var null|Font|string
*/
private $fontStyle;
/**
* Create a new TextBreak Element.
*
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function __construct($fontStyle = null, $paragraphStyle = null)
{
if (null !== $paragraphStyle) {
$paragraphStyle = $this->setParagraphStyle($paragraphStyle);
}
if (null !== $fontStyle) {
$this->setFontStyle($fontStyle, $paragraphStyle);
}
}
/**
* Set Text style.
*
* @param mixed $style
* @param mixed $paragraphStyle
*
* @return Font|string
*/
public function setFontStyle($style = null, $paragraphStyle = null)
{
if ($style instanceof Font) {
$this->fontStyle = $style;
$this->setParagraphStyle($paragraphStyle);
} elseif (is_array($style)) {
$this->fontStyle = new Font('text', $paragraphStyle);
$this->fontStyle->setStyleByArray($style);
} else {
$this->fontStyle = $style;
$this->setParagraphStyle($paragraphStyle);
}
return $this->fontStyle;
}
/**
* Get Text style.
*
* @return null|Font|string
*/
public function getFontStyle()
{
return $this->fontStyle;
}
/**
* Set Paragraph style.
*
* @param array|Paragraph|string $style
*
* @return Paragraph|string
*/
public function setParagraphStyle($style = null)
{
if (is_array($style)) {
$this->paragraphStyle = new Paragraph();
$this->paragraphStyle->setStyleByArray($style);
} elseif ($style instanceof Paragraph) {
$this->paragraphStyle = $style;
} else {
$this->paragraphStyle = $style;
}
return $this->paragraphStyle;
}
/**
* Get Paragraph style.
*
* @return null|Paragraph|string
*/
public function getParagraphStyle()
{
return $this->paragraphStyle;
}
/**
* Has font/paragraph style defined.
*
* @return bool
*/
public function hasStyle()
{
return null !== $this->fontStyle || null !== $this->paragraphStyle;
}
}
@@ -0,0 +1,97 @@
<?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\Element;
use PhpOffice\PhpWord\Style\Paragraph;
/**
* Textrun/paragraph element.
*/
class TextRun extends AbstractContainer
{
/**
* @var string Container type
*/
protected $container = 'TextRun';
/**
* Paragraph style.
*
* @var Paragraph|string
*/
protected $paragraphStyle;
/**
* Create new instance.
*
* @param array|Paragraph|string $paragraphStyle
*/
public function __construct($paragraphStyle = null)
{
$this->paragraphStyle = $this->setParagraphStyle($paragraphStyle);
}
/**
* Get Paragraph style.
*
* @return Paragraph|string
*/
public function getParagraphStyle()
{
return $this->paragraphStyle;
}
/**
* Set Paragraph style.
*
* @param array|Paragraph|string $style
*
* @return Paragraph|string
*/
public function setParagraphStyle($style = null)
{
if (is_array($style)) {
$this->paragraphStyle = new Paragraph();
$this->paragraphStyle->setStyleByArray($style);
} elseif ($style instanceof Paragraph) {
$this->paragraphStyle = $style;
} elseif (null === $style) {
$this->paragraphStyle = new Paragraph();
} else {
$this->paragraphStyle = $style;
}
return $this->paragraphStyle;
}
public function getText(): string
{
$outstr = '';
foreach ($this->getElements() as $element) {
if ($element instanceof Text) {
$outstr .= $element->getText();
} elseif ($element instanceof Ruby) {
$outstr .= $element->getBaseTextRun()->getText() .
' (' . $element->getRubyTextRun()->getText() . ')';
}
}
return $outstr;
}
}
+129
View File
@@ -0,0 +1,129 @@
<?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\Element;
use InvalidArgumentException;
use PhpOffice\PhpWord\Shared\Text as SharedText;
use PhpOffice\PhpWord\Style;
/**
* Title element.
*/
class Title extends AbstractElement
{
/**
* Title Text content.
*
* @var string|TextRun
*/
private $text;
/**
* Title depth.
*
* @var int
*/
private $depth = 1;
/**
* Name of the heading style, e.g. 'Heading1'.
*
* @var ?string
*/
private $style;
/**
* Is part of collection.
*
* @var bool
*/
protected $collectionRelation = true;
/**
* Page number.
*
* @var int
*/
private $pageNumber;
/**
* Create a new Title Element.
*
* @param string|TextRun $text
* @param int $depth
*/
public function __construct($text, $depth = 1, ?int $pageNumber = null)
{
if (is_string($text)) {
$this->text = SharedText::toUTF8($text);
} elseif ($text instanceof TextRun) {
$this->text = $text;
} else {
throw new InvalidArgumentException('Invalid text, should be a string or a TextRun');
}
$this->depth = $depth;
$styleName = $depth === 0 ? 'Title' : "Heading_{$this->depth}";
if (array_key_exists($styleName, Style::getStyles())) {
$this->style = str_replace('_', '', $styleName);
}
if ($pageNumber !== null) {
$this->pageNumber = $pageNumber;
}
}
/**
* Get Title Text content.
*
* @return string|TextRun
*/
public function getText()
{
return $this->text;
}
/**
* Get depth.
*
* @return int
*/
public function getDepth()
{
return $this->depth;
}
/**
* Get Title style.
*
* @return ?string
*/
public function getStyle()
{
return $this->style;
}
/**
* Get page number.
*/
public function getPageNumber(): ?int
{
return $this->pageNumber;
}
}
@@ -0,0 +1,105 @@
<?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\Element;
use DateTime;
/**
* TrackChange element.
*
* @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html
* @see http://datypic.com/sc/ooxml/t-w_CT_RunTrackChange.html
*/
class TrackChange extends AbstractContainer
{
const INSERTED = 'INSERTED';
const DELETED = 'DELETED';
/**
* @var string Container type
*/
protected $container = 'TrackChange';
/**
* The type of change, (insert or delete), not applicable for PhpOffice\PhpWord\Element\Comment.
*
* @var string
*/
private $changeType;
/**
* Author.
*
* @var string
*/
private $author;
/**
* Date.
*
* @var DateTime
*/
private $date;
/**
* Create a new TrackChange Element.
*
* @param string $changeType
* @param string $author
* @param null|bool|DateTime|int $date
*/
public function __construct($changeType = null, $author = null, $date = null)
{
$this->changeType = $changeType;
$this->author = $author;
if ($date !== null && $date !== false) {
$this->date = ($date instanceof DateTime) ? $date : new DateTime('@' . $date);
}
}
/**
* Get TrackChange Author.
*
* @return string
*/
public function getAuthor()
{
return $this->author;
}
/**
* Get TrackChange Date.
*
* @return DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Get the Change type.
*
* @return string
*/
public function getChangeType()
{
return $this->changeType;
}
}
@@ -0,0 +1,47 @@
<?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\Escaper;
/**
* @since 0.13.0
*
* @codeCoverageIgnore
*/
abstract class AbstractEscaper implements EscaperInterface
{
/**
* @param ?string $input
*
* @return string
*/
abstract protected function escapeSingleValue($input);
public function escape($input)
{
if (is_array($input)) {
foreach ($input as &$item) {
$item = $this->escapeSingleValue($item);
}
} else {
$input = $this->escapeSingleValue($input);
}
return $input;
}
}
@@ -0,0 +1,34 @@
<?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\Escaper;
/**
* @since 0.13.0
*
* @codeCoverageIgnore
*/
interface EscaperInterface
{
/**
* @param mixed $input
*
* @return mixed
*/
public function escape($input);
}
+34
View File
@@ -0,0 +1,34 @@
<?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\Escaper;
/**
* @since 0.13.0
*
* @codeCoverageIgnore
*/
class RegExp extends AbstractEscaper
{
const REG_EXP_DELIMITER = '/';
protected function escapeSingleValue($input)
{
return self::REG_EXP_DELIMITER . preg_quote($input, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u';
}
}
+99
View File
@@ -0,0 +1,99 @@
<?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\Escaper;
/**
* @since 0.13.0
*
* @codeCoverageIgnore
*/
class Rtf extends AbstractEscaper
{
protected function escapeAsciiCharacter($code)
{
if ($code == 9) {
return '{\\tab}';
}
if (0x20 > $code || $code >= 0x80) {
return '{\\u' . $code . '}';
}
if ($code == 123 || $code == 125 || $code == 92) { // open or close brace or backslash
return '\\' . chr($code);
}
return chr($code);
}
protected function escapeMultibyteCharacter($code)
{
return '\\uc0{\\u' . $code . '}';
}
/**
* @see http://www.randomchaos.com/documents/?source=php_and_unicode
*
* @param ?string $input
*/
protected function escapeSingleValue($input)
{
$escapedValue = '';
$numberOfBytes = 1;
$bytes = [];
for ($i = 0; $i < strlen($input); ++$i) {
$character = $input[$i];
$asciiCode = ord($character);
if ($asciiCode < 128) {
$escapedValue .= $this->escapeAsciiCharacter($asciiCode);
} else {
if (0 == count($bytes)) {
if ($asciiCode < 224) {
$numberOfBytes = 2;
} elseif ($asciiCode < 240) {
$numberOfBytes = 3;
} elseif ($asciiCode < 248) {
$numberOfBytes = 4;
}
}
$bytes[] = $asciiCode;
if ($numberOfBytes == count($bytes)) {
if (4 == $numberOfBytes) {
$multibyteCode = ($bytes[0] % 8) * 262144 + ($bytes[1] % 64) * 4096 + ($bytes[2] % 64) * 64 + ($bytes[3] % 64);
} elseif (3 == $numberOfBytes) {
$multibyteCode = ($bytes[0] % 16) * 4096 + ($bytes[1] % 64) * 64 + ($bytes[2] % 64);
} else {
$multibyteCode = ($bytes[0] % 32) * 64 + ($bytes[1] % 64);
}
if (65279 != $multibyteCode) {
$escapedValue .= $multibyteCode < 128 ? $this->escapeAsciiCharacter($multibyteCode) : $this->escapeMultibyteCharacter($multibyteCode);
}
$numberOfBytes = 1;
$bytes = [];
}
}
}
return $escapedValue;
}
}
+32
View File
@@ -0,0 +1,32 @@
<?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\Escaper;
/**
* @since 0.13.0
*
* @codeCoverageIgnore
*/
class Xml extends AbstractEscaper
{
protected function escapeSingleValue($input)
{
return (null !== $input) ? htmlspecialchars($input, ENT_QUOTES) : '';
}
}
@@ -0,0 +1,40 @@
<?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\Exception;
/**
* @since 0.12.0
*/
final class CopyFileException extends Exception
{
/**
* @param string $source The fully qualified source file name
* @param string $destination The fully qualified destination file name
* @param int $code The user defined exception code
* @param \Exception $previous The previous exception used for the exception chaining
*/
public function __construct($source, $destination, $code = 0, ?\Exception $previous = null)
{
parent::__construct(
sprintf('Could not copy \'%s\' file to \'%s\'.', $source, $destination),
$code,
$previous
);
}
}
@@ -0,0 +1,38 @@
<?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\Exception;
/**
* @since 0.12.0
*/
final class CreateTemporaryFileException extends Exception
{
/**
* @param int $code The user defined exception code
* @param \Exception $previous The previous exception used for the exception chaining
*/
public function __construct($code = 0, ?\Exception $previous = null)
{
parent::__construct(
'Could not create a temporary file with unique name in the specified directory.',
$code,
$previous
);
}
}
@@ -0,0 +1,26 @@
<?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\Exception;
/**
* General exception.
*/
class Exception extends \Exception
{
}
@@ -0,0 +1,26 @@
<?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\Exception;
/**
* Exception used for when an image is not found.
*/
class InvalidImageException extends Exception
{
}
@@ -0,0 +1,26 @@
<?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\Exception;
/**
* Exception used for when an image is not found.
*/
class InvalidObjectException extends Exception
{
}
@@ -0,0 +1,28 @@
<?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\Exception;
use InvalidArgumentException;
/**
* Exception used for when a style value is invalid.
*/
class InvalidStyleException extends InvalidArgumentException
{
}
@@ -0,0 +1,26 @@
<?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\Exception;
/**
* Exception used for when an image type is unsupported.
*/
class UnsupportedImageTypeException extends Exception
{
}
+145
View File
@@ -0,0 +1,145 @@
<?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;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\Reader\ReaderInterface;
use PhpOffice\PhpWord\Writer\WriterInterface;
use ReflectionClass;
abstract class IOFactory
{
/**
* Create new writer.
*
* @param string $name
*
* @return WriterInterface
*/
public static function createWriter(PhpWord $phpWord, $name = 'Word2007')
{
if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF', 'EPub3'], true)) {
throw new Exception("\"{$name}\" is not a valid writer.");
}
$fqName = "PhpOffice\\PhpWord\\Writer\\{$name}";
return new $fqName($phpWord);
}
/**
* Create new reader.
*
* @param string $name
*
* @return ReaderInterface
*/
public static function createReader($name = 'Word2007')
{
return self::createObject('Reader', $name);
}
/**
* Create new object.
*
* @param string $type
* @param string $name
* @param PhpWord $phpWord
*
* @return ReaderInterface|WriterInterface
*/
private static function createObject($type, $name, $phpWord = null)
{
$class = "PhpOffice\\PhpWord\\{$type}\\{$name}";
if (class_exists($class) && self::isConcreteClass($class)) {
return new $class($phpWord);
}
throw new Exception("\"{$name}\" is not a valid {$type}.");
}
/**
* Loads PhpWord from file.
*
* @param string $filename The name of the file
* @param string $readerName
*
* @return PhpWord $phpWord
*/
public static function load($filename, $readerName = 'Word2007')
{
/** @var ReaderInterface $reader */
$reader = self::createReader($readerName);
return $reader->load($filename);
}
/**
* Loads PhpWord ${variable} from file.
*
* @param string $filename The name of the file
*
* @return array The extracted variables
*/
public static function extractVariables(string $filename, string $readerName = 'Word2007'): array
{
/** @var ReaderInterface $reader */
$reader = self::createReader($readerName);
$document = $reader->load($filename);
$extractedVariables = [];
foreach ($document->getSections() as $section) {
$concatenatedText = '';
foreach ($section->getElements() as $element) {
if ($element instanceof TextRun) {
foreach ($element->getElements() as $textElement) {
if ($textElement instanceof Text) {
$text = $textElement->getText();
$concatenatedText .= $text;
}
}
}
}
preg_match_all('/\$\{([^}]+)\}/', $concatenatedText, $matches);
if (!empty($matches[1])) {
foreach ($matches[1] as $match) {
$trimmedMatch = trim($match);
$extractedVariables[] = $trimmedMatch;
}
}
}
return $extractedVariables;
}
/**
* Check if it's a concrete class (not abstract nor interface).
*
* @param string $class
*
* @return bool
*/
private static function isConcreteClass($class)
{
$reflection = new ReflectionClass($class);
return !$reflection->isAbstract() && !$reflection->isInterface();
}
}
+209
View File
@@ -0,0 +1,209 @@
<?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;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Exception\Exception;
/**
* Media collection.
*/
class Media
{
/**
* Media elements.
*
* @var array
*/
private static $elements = [];
/**
* Add new media element.
*
* @since 0.10.0
* @since 0.9.2
*
* @param string $container section|headerx|footerx|footnote|endnote
* @param string $mediaType image|object|link
* @param string $source
*
* @return int
*/
public static function addElement($container, $mediaType, $source, ?Image $image = null)
{
// Assign unique media Id and initiate media container if none exists
$mediaId = md5($container . $source);
if (!isset(self::$elements[$container])) {
self::$elements[$container] = [];
}
// Add media if not exists or point to existing media
if (!isset(self::$elements[$container][$mediaId])) {
$mediaCount = self::countElements($container);
$mediaTypeCount = self::countElements($container, $mediaType);
++$mediaTypeCount;
$rId = ++$mediaCount;
$target = null;
$mediaData = ['mediaIndex' => $mediaTypeCount];
switch ($mediaType) {
// Images
case 'image':
if (null === $image) {
throw new Exception('Image object not assigned.');
}
$isMemImage = $image->isMemImage();
$extension = $image->getImageExtension();
$mediaData['imageExtension'] = $extension;
$mediaData['imageType'] = $image->getImageType();
if ($isMemImage) {
$mediaData['isMemImage'] = true;
$mediaData['imageString'] = $image->getImageString();
}
$target = "{$container}_image{$mediaTypeCount}.{$extension}";
$image->setTarget($target);
$image->setMediaIndex($mediaTypeCount);
break;
// Objects
case 'object':
$target = "{$container}_oleObject{$mediaTypeCount}.bin";
break;
// Links
case 'link':
$target = $source;
break;
}
$mediaData['source'] = $source;
$mediaData['target'] = $target;
$mediaData['type'] = $mediaType;
$mediaData['rID'] = $rId;
self::$elements[$container][$mediaId] = $mediaData;
return $rId;
}
$mediaData = self::$elements[$container][$mediaId];
if (null !== $image) {
$image->setTarget($mediaData['target']);
$image->setMediaIndex($mediaData['mediaIndex']);
}
return $mediaData['rID'];
}
/**
* Get media elements count.
*
* @param string $container section|headerx|footerx|footnote|endnote
* @param string $mediaType image|object|link
*
* @return int
*
* @since 0.10.0
*/
public static function countElements($container, $mediaType = null)
{
$mediaCount = 0;
if (isset(self::$elements[$container])) {
foreach (self::$elements[$container] as $mediaData) {
if (null !== $mediaType) {
if ($mediaType == $mediaData['type']) {
++$mediaCount;
}
} else {
++$mediaCount;
}
}
}
return $mediaCount;
}
/**
* Get media elements.
*
* @param string $container section|headerx|footerx|footnote|endnote
* @param string $type image|object|link
*
* @return array
*
* @since 0.10.0
*/
public static function getElements($container, $type = null)
{
$elements = [];
// If header/footer, search for headerx and footerx where x is number
if ($container == 'header' || $container == 'footer') {
foreach (self::$elements as $key => $val) {
if (substr($key, 0, 6) == $container) {
$elements[$key] = $val;
}
}
return $elements;
}
if (!isset(self::$elements[$container])) {
return $elements;
}
return self::getElementsByType($container, $type);
}
/**
* Get elements by media type.
*
* @param string $container section|footnote|endnote
* @param string $type image|object|link
*
* @return array
*
* @since 0.11.0 Splitted from `getElements` to reduce complexity
*/
private static function getElementsByType($container, $type = null)
{
$elements = [];
foreach (self::$elements[$container] as $key => $data) {
if ($type !== null) {
if ($type == $data['type']) {
$elements[$key] = $data;
}
} else {
$elements[$key] = $data;
}
}
return $elements;
}
/**
* Reset media elements.
*/
public static function resetElements(): void
{
self::$elements = [];
}
}
@@ -0,0 +1,65 @@
<?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\Metadata;
/**
* Compatibility setting class.
*
* @since 0.12.0
* @see http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html
*/
class Compatibility
{
/**
* OOXML version.
*
* 12 = 2007
* 14 = 2010
* 15 = 2013
*
* @var int
*
* @see http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx
*/
private $ooxmlVersion = 12;
/**
* Get OOXML version.
*
* @return int
*/
public function getOoxmlVersion()
{
return $this->ooxmlVersion;
}
/**
* Set OOXML version.
*
* @param int $value
*
* @return self
*/
public function setOoxmlVersion($value)
{
$this->ooxmlVersion = $value;
return $this;
}
}
@@ -0,0 +1,603 @@
<?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\Metadata;
use DateTime;
/**
* Document information.
*/
class DocInfo
{
/** @const string Property type constants */
const PROPERTY_TYPE_BOOLEAN = 'b';
const PROPERTY_TYPE_INTEGER = 'i';
const PROPERTY_TYPE_FLOAT = 'f';
const PROPERTY_TYPE_DATE = 'd';
const PROPERTY_TYPE_STRING = 's';
const PROPERTY_TYPE_UNKNOWN = 'u';
/**
* Creator.
*
* @var string
*/
private $creator;
/**
* LastModifiedBy.
*
* @var string
*/
private $lastModifiedBy;
/**
* Created.
*
* @var int
*/
private $created;
/**
* Modified.
*
* @var int
*/
private $modified;
/**
* Title.
*
* @var string
*/
private $title;
/**
* Description.
*
* @var string
*/
private $description;
/**
* Subject.
*
* @var string
*/
private $subject;
/**
* Keywords.
*
* @var string
*/
private $keywords;
/**
* Category.
*
* @var string
*/
private $category;
/**
* Company.
*
* @var string
*/
private $company;
/**
* Manager.
*
* @var string
*/
private $manager;
/**
* Custom Properties.
*
* @var array
*/
private $customProperties = [];
/**
* Create new instance.
*/
public function __construct()
{
$this->creator = '';
$this->lastModifiedBy = $this->creator;
$this->created = time();
$this->modified = time();
$this->title = '';
$this->subject = '';
$this->description = '';
$this->keywords = '';
$this->category = '';
$this->company = '';
$this->manager = '';
}
/**
* Get Creator.
*
* @return string
*/
public function getCreator()
{
return $this->creator;
}
/**
* Set Creator.
*
* @param string $value
*
* @return self
*/
public function setCreator($value = '')
{
$this->creator = $this->setValue($value, '');
return $this;
}
/**
* Get Last Modified By.
*
* @return string
*/
public function getLastModifiedBy()
{
return $this->lastModifiedBy;
}
/**
* Set Last Modified By.
*
* @param string $value
*
* @return self
*/
public function setLastModifiedBy($value = '')
{
$this->lastModifiedBy = $this->setValue($value, $this->creator);
return $this;
}
/**
* Get Created.
*
* @return int
*/
public function getCreated()
{
return $this->created;
}
/**
* Set Created.
*
* @param int $value
*
* @return self
*/
public function setCreated($value = null)
{
$this->created = $this->setValue($value, time());
return $this;
}
/**
* Get Modified.
*
* @return int
*/
public function getModified()
{
return $this->modified;
}
/**
* Set Modified.
*
* @param int $value
*
* @return self
*/
public function setModified($value = null)
{
$this->modified = $this->setValue($value, time());
return $this;
}
/**
* Get Title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set Title.
*
* @param string $value
*
* @return self
*/
public function setTitle($value = '')
{
$this->title = $this->setValue($value, '');
return $this;
}
/**
* Get Description.
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set Description.
*
* @param string $value
*
* @return self
*/
public function setDescription($value = '')
{
$this->description = $this->setValue($value, '');
return $this;
}
/**
* Get Subject.
*
* @return string
*/
public function getSubject()
{
return $this->subject;
}
/**
* Set Subject.
*
* @param string $value
*
* @return self
*/
public function setSubject($value = '')
{
$this->subject = $this->setValue($value, '');
return $this;
}
/**
* Get Keywords.
*
* @return string
*/
public function getKeywords()
{
return $this->keywords;
}
/**
* Set Keywords.
*
* @param string $value
*
* @return self
*/
public function setKeywords($value = '')
{
$this->keywords = $this->setValue($value, '');
return $this;
}
/**
* Get Category.
*
* @return string
*/
public function getCategory()
{
return $this->category;
}
/**
* Set Category.
*
* @param string $value
*
* @return self
*/
public function setCategory($value = '')
{
$this->category = $this->setValue($value, '');
return $this;
}
/**
* Get Company.
*
* @return string
*/
public function getCompany()
{
return $this->company;
}
/**
* Set Company.
*
* @param string $value
*
* @return self
*/
public function setCompany($value = '')
{
$this->company = $this->setValue($value, '');
return $this;
}
/**
* Get Manager.
*
* @return string
*/
public function getManager()
{
return $this->manager;
}
/**
* Set Manager.
*
* @param string $value
*
* @return self
*/
public function setManager($value = '')
{
$this->manager = $this->setValue($value, '');
return $this;
}
/**
* Get a List of Custom Property Names.
*
* @return array of string
*/
public function getCustomProperties()
{
return array_keys($this->customProperties);
}
/**
* Check if a Custom Property is defined.
*
* @param string $propertyName
*
* @return bool
*/
public function isCustomPropertySet($propertyName)
{
return isset($this->customProperties[$propertyName]);
}
/**
* Get a Custom Property Value.
*
* @param string $propertyName
*
* @return mixed
*/
public function getCustomPropertyValue($propertyName)
{
if ($this->isCustomPropertySet($propertyName)) {
return $this->customProperties[$propertyName]['value'];
}
return null;
}
/**
* Get a Custom Property Type.
*
* @param string $propertyName
*
* @return ?string
*/
public function getCustomPropertyType($propertyName)
{
if ($this->isCustomPropertySet($propertyName)) {
return $this->customProperties[$propertyName]['type'];
}
return null;
}
/**
* Set a Custom Property.
*
* @param string $propertyName
* @param mixed $propertyValue
* @param string $propertyType
* 'i': Integer
* 'f': Floating Point
* 's': String
* 'd': Date/Time
* 'b': Boolean
*
* @return self
*/
public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
{
$propertyTypes = [
self::PROPERTY_TYPE_INTEGER,
self::PROPERTY_TYPE_FLOAT,
self::PROPERTY_TYPE_STRING,
self::PROPERTY_TYPE_DATE,
self::PROPERTY_TYPE_BOOLEAN,
];
if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) {
if ($propertyValue === null) {
$propertyType = self::PROPERTY_TYPE_STRING;
} elseif (is_float($propertyValue)) {
$propertyType = self::PROPERTY_TYPE_FLOAT;
} elseif (is_int($propertyValue)) {
$propertyType = self::PROPERTY_TYPE_INTEGER;
} elseif (is_bool($propertyValue)) {
$propertyType = self::PROPERTY_TYPE_BOOLEAN;
} elseif ($propertyValue instanceof DateTime) {
$propertyType = self::PROPERTY_TYPE_DATE;
} else {
$propertyType = self::PROPERTY_TYPE_STRING;
}
}
$this->customProperties[$propertyName] = [
'value' => $propertyValue,
'type' => $propertyType,
];
return $this;
}
/**
* Convert document property based on type.
*
* @param string $propertyValue
* @param string $propertyType
*
* @return mixed
*/
public static function convertProperty($propertyValue, $propertyType)
{
$conversion = self::getConversion($propertyType);
switch ($conversion) {
case 'empty': // Empty
return '';
case 'null': // Null
return null;
case 'int': // Signed integer
return (int) $propertyValue;
case 'uint': // Unsigned integer
return abs((int) $propertyValue);
case 'float': // Float
return (float) $propertyValue;
case 'date': // Date
return strtotime($propertyValue);
case 'bool': // Boolean
return $propertyValue == 'true';
}
return $propertyValue;
}
/**
* Convert document property type.
*
* @param string $propertyType
*
* @return string
*/
public static function convertPropertyType($propertyType)
{
$typeGroups = [
self::PROPERTY_TYPE_INTEGER => ['i1', 'i2', 'i4', 'i8', 'int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint'],
self::PROPERTY_TYPE_FLOAT => ['r4', 'r8', 'decimal'],
self::PROPERTY_TYPE_STRING => ['empty', 'null', 'lpstr', 'lpwstr', 'bstr'],
self::PROPERTY_TYPE_DATE => ['date', 'filetime'],
self::PROPERTY_TYPE_BOOLEAN => ['bool'],
];
foreach ($typeGroups as $groupId => $groupMembers) {
if (in_array($propertyType, $groupMembers)) {
return $groupId;
}
}
return self::PROPERTY_TYPE_UNKNOWN;
}
/**
* Set default for null and empty value.
*
* @param mixed $value
* @param mixed $default
*
* @return mixed
*/
private function setValue($value, $default)
{
if ($value === null || $value == '') {
$value = $default;
}
return $value;
}
/**
* Get conversion model depending on property type.
*
* @param string $propertyType
*
* @return string
*/
private static function getConversion($propertyType)
{
$conversions = [
'empty' => ['empty'],
'null' => ['null'],
'int' => ['i1', 'i2', 'i4', 'i8', 'int'],
'uint' => ['ui1', 'ui2', 'ui4', 'ui8', 'uint'],
'float' => ['r4', 'r8', 'decimal'],
'bool' => ['bool'],
'date' => ['date', 'filetime'],
];
foreach ($conversions as $conversion => $types) {
if (in_array($propertyType, $types)) {
return $conversion;
}
}
return 'string';
}
}
@@ -0,0 +1,206 @@
<?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\Metadata;
use InvalidArgumentException;
use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder;
use PhpOffice\PhpWord\SimpleType\DocProtect;
/**
* Document protection class.
*
* @since 0.12.0
* @see http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html
*/
class Protection
{
/**
* Editing restriction none|readOnly|comments|trackedChanges|forms.
*
* @var string
*
* @see http://www.datypic.com/sc/ooxml/a-w_edit-1.html
*/
private $editing;
/**
* password.
*
* @var string
*/
private $password;
/**
* Iterations to Run Hashing Algorithm.
*
* @var int
*/
private $spinCount = 100000;
/**
* Cryptographic Hashing Algorithm (see constants defined in \PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder).
*
* @var string
*/
private $algorithm = PasswordEncoder::ALGORITHM_SHA_1;
/**
* Salt for Password Verifier.
*
* @var string
*/
private $salt;
/**
* Create a new instance.
*
* @param string $editing
*/
public function __construct($editing = null)
{
if ($editing != null) {
$this->setEditing($editing);
}
}
/**
* Get editing protection.
*
* @return string
*/
public function getEditing()
{
return $this->editing;
}
/**
* Set editing protection.
*
* @param string $editing Any value of \PhpOffice\PhpWord\SimpleType\DocProtect
*
* @return self
*/
public function setEditing($editing = null)
{
DocProtect::validate($editing);
$this->editing = $editing;
return $this;
}
/**
* Get password.
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set password.
*
* @param string $password
*
* @return self
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get count for hash iterations.
*
* @return int
*/
public function getSpinCount()
{
return $this->spinCount;
}
/**
* Set count for hash iterations.
*
* @param int $spinCount
*
* @return self
*/
public function setSpinCount($spinCount)
{
$this->spinCount = $spinCount;
return $this;
}
/**
* Get algorithm.
*
* @return string
*/
public function getAlgorithm()
{
return $this->algorithm;
}
/**
* Set algorithm.
*
* @param string $algorithm
*
* @return self
*/
public function setAlgorithm($algorithm)
{
$this->algorithm = $algorithm;
return $this;
}
/**
* Get salt.
*
* @return string
*/
public function getSalt()
{
return $this->salt;
}
/**
* Set salt. Salt HAS to be 16 characters, or an exception will be thrown.
*
* @param string $salt
*
* @return self
*/
public function setSalt($salt)
{
if ($salt !== null && strlen($salt) !== 16) {
throw new InvalidArgumentException('salt has to be of exactly 16 bytes length');
}
$this->salt = $salt;
return $this;
}
}
@@ -0,0 +1,500 @@
<?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\Metadata;
use PhpOffice\PhpWord\ComplexType\ProofState;
use PhpOffice\PhpWord\ComplexType\TrackChangesView;
use PhpOffice\PhpWord\SimpleType\Zoom;
use PhpOffice\PhpWord\Style\Language;
/**
* Setting class.
*
* @since 0.14.0
* @see http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html
*/
class Settings
{
/**
* Magnification Setting.
*
* @see http://www.datypic.com/sc/ooxml/e-w_zoom-1.html
*
* @var mixed either integer, in which case it treated as a percent, or one of PhpOffice\PhpWord\SimpleType\Zoom
*/
private $zoom = 100;
/**
* Mirror Page Margins.
*
* @see http://www.datypic.com/sc/ooxml/e-w_mirrorMargins-1.html
*
* @var bool
*/
private $mirrorMargins;
/**
* Hide spelling errors.
*
* @var bool
*/
private $hideSpellingErrors = false;
/**
* Hide grammatical errors.
*
* @var bool
*/
private $hideGrammaticalErrors = false;
/**
* Visibility of Annotation Types.
*
* @var TrackChangesView
*/
private $revisionView;
/**
* Track Revisions to Document.
*
* @var bool
*/
private $trackRevisions = false;
/**
* Do Not Use Move Syntax When Tracking Revisions.
*
* @var bool
*/
private $doNotTrackMoves = false;
/**
* Do Not Track Formatting Revisions When Tracking Revisions.
*
* @var bool
*/
private $doNotTrackFormatting = false;
/**
* Spelling and Grammatical Checking State.
*
* @var ProofState
*/
private $proofState;
/**
* Document Editing Restrictions.
*
* @var Protection
*/
private $documentProtection;
/**
* Enables different header for odd and even pages.
*
* @var bool
*/
private $evenAndOddHeaders = false;
/**
* Theme Font Languages.
*
* @var ?Language
*/
private $themeFontLang;
/**
* Automatically Recalculate Fields on Open.
*
* @var bool
*/
private $updateFields = false;
/**
* Radix Point for Field Code Evaluation.
*
* @var string
*/
private $decimalSymbol = '.';
/**
* Automatically hyphenate document contents when displayed.
*
* @var null|bool
*/
private $autoHyphenation;
/**
* Maximum number of consecutively hyphenated lines.
*
* @var null|int
*/
private $consecutiveHyphenLimit;
/**
* The allowed amount of whitespace before hyphenation is applied.
*
* @var null|float|int
*/
private $hyphenationZone;
/**
* Do not hyphenate words in all capital letters.
*
* @var null|bool
*/
private $doNotHyphenateCaps;
/**
* Enable or disable book-folded printing.
*
* @var bool
*/
private $bookFoldPrinting = false;
/**
* @return Protection
*/
public function getDocumentProtection()
{
if ($this->documentProtection == null) {
$this->documentProtection = new Protection();
}
return $this->documentProtection;
}
/**
* @param Protection $documentProtection
*/
public function setDocumentProtection($documentProtection): void
{
$this->documentProtection = $documentProtection;
}
/**
* @return ProofState
*/
public function getProofState()
{
if ($this->proofState == null) {
$this->proofState = new ProofState();
}
return $this->proofState;
}
/**
* @param ProofState $proofState
*/
public function setProofState($proofState): void
{
$this->proofState = $proofState;
}
/**
* Are spelling errors hidden.
*
* @return bool
*/
public function hasHideSpellingErrors()
{
return $this->hideSpellingErrors;
}
/**
* Hide spelling errors.
*
* @param ?bool $hideSpellingErrors
*/
public function setHideSpellingErrors($hideSpellingErrors): void
{
$this->hideSpellingErrors = $hideSpellingErrors === null ? true : $hideSpellingErrors;
}
/**
* Are grammatical errors hidden.
*
* @return bool
*/
public function hasHideGrammaticalErrors()
{
return $this->hideGrammaticalErrors;
}
/**
* Hide grammatical errors.
*
* @param ?bool $hideGrammaticalErrors
*/
public function setHideGrammaticalErrors($hideGrammaticalErrors): void
{
$this->hideGrammaticalErrors = $hideGrammaticalErrors === null ? true : $hideGrammaticalErrors;
}
/**
* @return bool
*/
public function hasEvenAndOddHeaders()
{
return $this->evenAndOddHeaders;
}
/**
* @param ?bool $evenAndOddHeaders
*/
public function setEvenAndOddHeaders($evenAndOddHeaders): void
{
$this->evenAndOddHeaders = $evenAndOddHeaders === null ? true : $evenAndOddHeaders;
}
/**
* Get the Visibility of Annotation Types.
*
* @return TrackChangesView
*/
public function getRevisionView()
{
return $this->revisionView;
}
/**
* Set the Visibility of Annotation Types.
*/
public function setRevisionView(?TrackChangesView $trackChangesView = null): void
{
$this->revisionView = $trackChangesView;
}
/**
* @return bool
*/
public function hasTrackRevisions()
{
return $this->trackRevisions;
}
/**
* @param ?bool $trackRevisions
*/
public function setTrackRevisions($trackRevisions): void
{
$this->trackRevisions = $trackRevisions === null ? true : $trackRevisions;
}
/**
* @return bool
*/
public function hasDoNotTrackMoves()
{
return $this->doNotTrackMoves;
}
/**
* @param ?bool $doNotTrackMoves
*/
public function setDoNotTrackMoves($doNotTrackMoves): void
{
$this->doNotTrackMoves = $doNotTrackMoves === null ? true : $doNotTrackMoves;
}
/**
* @return bool
*/
public function hasDoNotTrackFormatting()
{
return $this->doNotTrackFormatting;
}
/**
* @param ?bool $doNotTrackFormatting
*/
public function setDoNotTrackFormatting($doNotTrackFormatting): void
{
$this->doNotTrackFormatting = $doNotTrackFormatting === null ? true : $doNotTrackFormatting;
}
/**
* @return mixed
*/
public function getZoom()
{
return $this->zoom;
}
/**
* @param mixed $zoom
*/
public function setZoom($zoom): void
{
if (is_numeric($zoom)) {
// zoom is a percentage
$this->zoom = $zoom;
} else {
Zoom::validate($zoom);
$this->zoom = $zoom;
}
}
/**
* @return bool
*/
public function hasMirrorMargins()
{
return $this->mirrorMargins;
}
/**
* @param bool $mirrorMargins
*/
public function setMirrorMargins($mirrorMargins): void
{
$this->mirrorMargins = $mirrorMargins;
}
/**
* Returns the Language.
*/
public function getThemeFontLang(): ?Language
{
return $this->themeFontLang;
}
/**
* Sets the Language for this document.
*/
public function setThemeFontLang(Language $themeFontLang): self
{
$this->themeFontLang = $themeFontLang;
return $this;
}
/**
* @return bool
*/
public function hasUpdateFields()
{
return $this->updateFields;
}
/**
* @param ?bool $updateFields
*/
public function setUpdateFields($updateFields): void
{
$this->updateFields = $updateFields === null ? false : $updateFields;
}
/**
* Returns the Radix Point for Field Code Evaluation.
*
* @return string
*/
public function getDecimalSymbol()
{
return $this->decimalSymbol;
}
/**
* sets the Radix Point for Field Code Evaluation.
*
* @param string $decimalSymbol
*/
public function setDecimalSymbol($decimalSymbol): void
{
$this->decimalSymbol = $decimalSymbol;
}
/**
* @return null|bool
*/
public function hasAutoHyphenation()
{
return $this->autoHyphenation;
}
/**
* @param bool $autoHyphenation
*/
public function setAutoHyphenation($autoHyphenation): void
{
$this->autoHyphenation = (bool) $autoHyphenation;
}
/**
* @return null|int
*/
public function getConsecutiveHyphenLimit()
{
return $this->consecutiveHyphenLimit;
}
/**
* @param int $consecutiveHyphenLimit
*/
public function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void
{
$this->consecutiveHyphenLimit = (int) $consecutiveHyphenLimit;
}
/**
* @return null|float|int
*/
public function getHyphenationZone()
{
return $this->hyphenationZone;
}
/**
* @param null|float|int $hyphenationZone Measurement unit is twip
*/
public function setHyphenationZone($hyphenationZone): void
{
$this->hyphenationZone = $hyphenationZone;
}
/**
* @return null|bool
*/
public function hasDoNotHyphenateCaps()
{
return $this->doNotHyphenateCaps;
}
/**
* @param bool $doNotHyphenateCaps
*/
public function setDoNotHyphenateCaps($doNotHyphenateCaps): void
{
$this->doNotHyphenateCaps = (bool) $doNotHyphenateCaps;
}
public function hasBookFoldPrinting(): bool
{
return $this->bookFoldPrinting;
}
public function setBookFoldPrinting(bool $bookFoldPrinting): self
{
$this->bookFoldPrinting = $bookFoldPrinting;
return $this;
}
}
+411
View File
@@ -0,0 +1,411 @@
<?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;
use BadMethodCallException;
use PhpOffice\PhpWord\Element\Section;
use PhpOffice\PhpWord\Exception\Exception;
/**
* PHPWord main class.
*
* @method Collection\Titles getTitles()
* @method Collection\Footnotes getFootnotes()
* @method Collection\Endnotes getEndnotes()
* @method Collection\Charts getCharts()
* @method Collection\Comments getComments()
* @method int addBookmark(Element\Bookmark $bookmark)
* @method int addTitle(Element\Title $title)
* @method int addFootnote(Element\Footnote $footnote)
* @method int addEndnote(Element\Endnote $endnote)
* @method int addChart(Element\Chart $chart)
* @method int addComment(Element\Comment $comment)
* @method Style\Paragraph addParagraphStyle(string $styleName, mixed $styles)
* @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null)
* @method Style\Font addLinkStyle(string $styleName, mixed $styles)
* @method Style\Font addTitleStyle(mixed $depth, mixed $fontStyle, mixed $paragraphStyle = null)
* @method Style\Table addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null)
* @method Style\Numbering addNumberingStyle(string $styleName, mixed $styles)
*/
class PhpWord
{
/**
* Collection of sections.
*
* @var Section[]
*/
private $sections = [];
/**
* Collections.
*
* @var array
*/
private $collections = [];
/**
* Metadata.
*
* @var array
*
* @since 0.12.0
*/
private $metadata = [];
/**
* Create new instance.
*
* Collections are created dynamically
*/
public function __construct()
{
// Reset Media and styles
Media::resetElements();
Style::resetStyles();
Settings::setDefaultRtl(null);
// Collection
$collections = ['Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments'];
foreach ($collections as $collection) {
$class = 'PhpOffice\\PhpWord\\Collection\\' . $collection;
$this->collections[$collection] = new $class();
}
// Metadata
$metadata = ['DocInfo', 'Settings', 'Compatibility'];
foreach ($metadata as $meta) {
$class = 'PhpOffice\\PhpWord\\Metadata\\' . $meta;
$this->metadata[$meta] = new $class();
}
}
/**
* Dynamic function call to reduce static dependency.
*
* @since 0.12.0
*
* @param mixed $function
* @param mixed $args
*
* @return mixed
*/
public function __call($function, $args)
{
$function = strtolower($function);
$getCollection = [];
$addCollection = [];
$addStyle = [];
$collections = ['Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart', 'Comment'];
foreach ($collections as $collection) {
$getCollection[] = strtolower("get{$collection}s");
$addCollection[] = strtolower("add{$collection}");
}
$styles = ['Paragraph', 'Font', 'Table', 'Numbering', 'Link', 'Title'];
foreach ($styles as $style) {
$addStyle[] = strtolower("add{$style}Style");
}
// Run get collection method
if (in_array($function, $getCollection)) {
$key = ucfirst(str_replace('get', '', $function));
return $this->collections[$key];
}
// Run add collection item method
if (in_array($function, $addCollection)) {
$key = ucfirst(str_replace('add', '', $function) . 's');
$collectionObject = $this->collections[$key];
return $collectionObject->addItem($args[0] ?? null);
}
// Run add style method
if (in_array($function, $addStyle)) {
return forward_static_call_array(['PhpOffice\\PhpWord\\Style', $function], $args);
}
// Exception
throw new BadMethodCallException("Method $function is not defined.");
}
/**
* Get document properties object.
*
* @return Metadata\DocInfo
*/
public function getDocInfo()
{
return $this->metadata['DocInfo'];
}
/**
* Get compatibility.
*
* @return Metadata\Compatibility
*
* @since 0.12.0
*/
public function getCompatibility()
{
return $this->metadata['Compatibility'];
}
/**
* Get compatibility.
*
* @return Metadata\Settings
*
* @since 0.14.0
*/
public function getSettings()
{
return $this->metadata['Settings'];
}
/**
* Get all sections.
*
* @return Section[]
*/
public function getSections()
{
return $this->sections;
}
/**
* Returns the section at the requested position.
*
* @param int $index
*
* @return null|Section
*/
public function getSection($index)
{
if (array_key_exists($index, $this->sections)) {
return $this->sections[$index];
}
return null;
}
/**
* Create new section.
*
* @param null|array|string $style
*
* @return Section
*/
public function addSection($style = null)
{
$section = new Section(count($this->sections) + 1, $style);
$section->setPhpWord($this);
$this->sections[] = $section;
return $section;
}
/**
* Sorts the sections using the callable passed.
*
* @see http://php.net/manual/en/function.usort.php for usage
*
* @param callable $sorter
*/
public function sortSections($sorter): void
{
usort($this->sections, $sorter);
}
/**
* Get default font name.
*
* @return string
*/
public function getDefaultFontName()
{
return Settings::getDefaultFontName();
}
/**
* Set default font name.
*
* @param string $fontName
*/
public function setDefaultFontName($fontName): void
{
Settings::setDefaultFontName($fontName);
}
/**
* Get default asian font name.
*/
public function getDefaultAsianFontName(): string
{
return Settings::getDefaultAsianFontName();
}
/**
* Set default asian font name.
*
* @param string $fontName
*/
public function setDefaultAsianFontName($fontName): void
{
Settings::setDefaultAsianFontName($fontName);
}
/**
* Set default font color.
*/
public function setDefaultFontColor(string $fontColor): void
{
Settings::setDefaultFontColor($fontColor);
}
/**
* Get default font color.
*/
public function getDefaultFontColor(): string
{
return Settings::getDefaultFontColor();
}
/**
* Get default font size.
*
* @return int
*/
public function getDefaultFontSize()
{
return Settings::getDefaultFontSize();
}
/**
* Set default font size.
*
* @param int $fontSize
*/
public function setDefaultFontSize($fontSize): void
{
Settings::setDefaultFontSize($fontSize);
}
/**
* Set default paragraph style definition to styles.xml.
*
* @param array $styles Paragraph style definition
*
* @return Style\Paragraph
*/
public function setDefaultParagraphStyle($styles)
{
return Style::setDefaultParagraphStyle($styles);
}
/**
* Save to file or download.
*
* All exceptions should already been handled by the writers
*
* @param string $filename
* @param string $format
* @param bool $download
*
* @return bool
*/
public function save($filename, $format = 'Word2007', $download = false)
{
$mime = [
'Word2007' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'ODText' => 'application/vnd.oasis.opendocument.text',
'RTF' => 'application/rtf',
'HTML' => 'text/html',
'PDF' => 'application/pdf',
];
$writer = IOFactory::createWriter($this, $format);
if ($download === true) {
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Type: ' . $mime[$format]);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
$filename = 'php://output'; // Change filename to force download
}
$writer->save($filename);
return true;
}
/**
* Create new section.
*
* @deprecated 0.10.0
*
* @param array $settings
*
* @return Section
*
* @codeCoverageIgnore
*/
public function createSection($settings = null)
{
return $this->addSection($settings);
}
/**
* Get document properties object.
*
* @deprecated 0.12.0
*
* @return Metadata\DocInfo
*
* @codeCoverageIgnore
*/
public function getDocumentProperties()
{
return $this->getDocInfo();
}
/**
* Set document properties object.
*
* @deprecated 0.12.0
*
* @param Metadata\DocInfo $documentProperties
*
* @return self
*
* @codeCoverageIgnore
*/
public function setDocumentProperties($documentProperties)
{
$this->metadata['Document'] = $documentProperties;
return $this;
}
}
@@ -0,0 +1,132 @@
<?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\Reader;
use PhpOffice\PhpWord\Exception\Exception;
/**
* Reader abstract class.
*
* @since 0.8.0
*
* @codeCoverageIgnore Abstract class
*/
abstract class AbstractReader implements ReaderInterface
{
/**
* Read data only?
*
* @var bool
*/
protected $readDataOnly = true;
/**
* File pointer.
*
* @var bool|resource
*/
protected $fileHandle;
/**
* Load images.
*
* @var bool
*/
protected $imageLoading = true;
/**
* Read data only?
*
* @return bool
*/
public function isReadDataOnly()
{
// return $this->readDataOnly;
return true;
}
/**
* Set read data only.
*
* @param bool $value
*
* @return self
*/
public function setReadDataOnly($value = true)
{
$this->readDataOnly = $value;
return $this;
}
public function hasImageLoading(): bool
{
return $this->imageLoading;
}
public function setImageLoading(bool $value): self
{
$this->imageLoading = $value;
return $this;
}
/**
* Open file for reading.
*
* @param string $filename
*
* @return resource
*/
protected function openFile($filename)
{
// Check if file exists
if (!file_exists($filename) || !is_readable($filename)) {
throw new Exception("Could not open $filename for reading! File does not exist.");
}
// Open file
$this->fileHandle = fopen($filename, 'rb');
if ($this->fileHandle === false) {
throw new Exception("Could not open file $filename for reading.");
}
}
/**
* Can the current ReaderInterface read the file?
*
* @param string $filename
*
* @return bool
*/
public function canRead($filename)
{
// Check if file exists
try {
$this->openFile($filename);
} catch (Exception $e) {
return false;
}
if (is_resource($this->fileHandle)) {
fclose($this->fileHandle);
}
return true;
}
}
+52
View File
@@ -0,0 +1,52 @@
<?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\Reader;
use Exception;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\Html as HTMLParser;
/**
* HTML Reader class.
*
* @since 0.11.0
*/
class HTML extends AbstractReader implements ReaderInterface
{
/**
* Loads PhpWord from file.
*
* @param string $docFile
*
* @return PhpWord
*/
public function load($docFile)
{
$phpWord = new PhpWord();
if ($this->canRead($docFile)) {
$section = $phpWord->addSection();
HTMLParser::addHtml($section, file_get_contents($docFile), true);
} else {
throw new Exception("Cannot read {$docFile}.");
}
return $phpWord;
}
}
File diff suppressed because it is too large Load Diff
+87
View File
@@ -0,0 +1,87 @@
<?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\Reader;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Reader for ODText.
*
* @since 0.10.0
*/
class ODText extends AbstractReader implements ReaderInterface
{
/**
* Loads PhpWord from file.
*
* @param string $docFile
*
* @return PhpWord
*/
public function load($docFile)
{
$phpWord = new PhpWord();
$relationships = $this->readRelationships($docFile);
$readerParts = [
'content.xml' => 'Content',
'meta.xml' => 'Meta',
];
foreach ($readerParts as $xmlFile => $partName) {
$this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile);
}
return $phpWord;
}
/**
* Read document part.
*/
private function readPart(PhpWord $phpWord, array $relationships, string $partName, string $docFile, string $xmlFile): void
{
$partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}";
if (class_exists($partClass)) {
/** @var ODText\AbstractPart $part Type hint */
$part = new $partClass($docFile, $xmlFile);
$part->setRels($relationships);
$part->read($phpWord);
}
}
/**
* Read all relationship files.
*/
private function readRelationships(string $docFile): array
{
$rels = [];
$xmlFile = 'META-INF/manifest.xml';
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($docFile, $xmlFile);
$nodes = $xmlReader->getElements('manifest:file-entry');
foreach ($nodes as $node) {
$type = $xmlReader->getAttribute('manifest:media-type', $node);
$target = $xmlReader->getAttribute('manifest:full-path', $node);
$rels[] = ['type' => $type, 'target' => $target];
}
return $rels;
}
}
@@ -0,0 +1,32 @@
<?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\Reader\ODText;
use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart;
/**
* Abstract part reader.
*
* @since 0.10.0
*
* @codeCoverageIgnore
*/
abstract class AbstractPart extends Word2007AbstractPart
{
}
@@ -0,0 +1,207 @@
<?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\Reader\ODText;
use DateTime;
use DOMElement;
use DOMNodeList;
use PhpOffice\Math\Reader\MathML;
use PhpOffice\PhpWord\Element\Section;
use PhpOffice\PhpWord\Element\TrackChange;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Content reader.
*
* @since 0.10.0
*/
class Content extends AbstractPart
{
/** @var ?Section */
private $section;
/**
* Read content.xml.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$trackedChanges = [];
$nodes = $xmlReader->getElements('office:body/office:text/*');
$this->section = null;
$this->processNodes($nodes, $xmlReader, $phpWord);
$this->section = null;
}
/** @param DOMNodeList<DOMElement> $nodes */
public function processNodes(DOMNodeList $nodes, XMLReader $xmlReader, PhpWord $phpWord): void
{
if ($nodes->length > 0) {
foreach ($nodes as $node) {
// $styleName = $xmlReader->getAttribute('text:style-name', $node);
switch ($node->nodeName) {
case 'text:h': // Heading
$depth = $xmlReader->getAttribute('text:outline-level', $node);
$this->getSection($phpWord)->addTitle($node->nodeValue, $depth);
break;
case 'text:p': // Paragraph
$styleName = $xmlReader->getAttribute('text:style-name', $node);
if (substr($styleName, 0, 2) === 'SB') {
break;
}
$element = $xmlReader->getElement('draw:frame/draw:object', $node);
if ($element) {
$mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml';
$xmlReaderObject = new XMLReader();
$mathElement = $xmlReaderObject->getDomFromZip($this->docFile, $mathFile);
if ($mathElement) {
$mathXML = $mathElement->saveXML($mathElement);
if (is_string($mathXML)) {
$reader = new MathML();
$math = $reader->read($mathXML);
$this->getSection($phpWord)->addFormula($math);
}
}
} else {
$children = $node->childNodes;
$spans = false;
/** @var DOMElement $child */
foreach ($children as $child) {
switch ($child->nodeName) {
case 'text:change-start':
$changeId = $child->getAttribute('text:change-id');
if (isset($trackedChanges[$changeId])) {
$changed = $trackedChanges[$changeId];
}
break;
case 'text:change-end':
unset($changed);
break;
case 'text:change':
$changeId = $child->getAttribute('text:change-id');
if (isset($trackedChanges[$changeId])) {
$changed = $trackedChanges[$changeId];
}
break;
case 'text:span':
$spans = true;
break;
}
}
if ($spans) {
$element = $this->getSection($phpWord)->addTextRun();
foreach ($children as $child) {
switch ($child->nodeName) {
case 'text:span':
/** @var DOMElement $child2 */
foreach ($child->childNodes as $child2) {
switch ($child2->nodeName) {
case '#text':
$element->addText($child2->nodeValue);
break;
case 'text:tab':
$element->addText("\t");
break;
case 'text:s':
$spaces = (int) $child2->getAttribute('text:c') ?: 1;
$element->addText(str_repeat(' ', $spaces));
break;
}
}
break;
}
}
} else {
$element = $this->getSection($phpWord)->addText($node->nodeValue);
}
if (isset($changed) && is_array($changed)) {
$element->setTrackChange($changed['changed']);
if (isset($changed['textNodes'])) {
foreach ($changed['textNodes'] as $changedNode) {
$element = $this->getSection($phpWord)->addText($changedNode->nodeValue);
$element->setTrackChange($changed['changed']);
}
}
}
}
break;
case 'text:list': // List
$listItems = $xmlReader->getElements('text:list-item/text:p', $node);
foreach ($listItems as $listItem) {
// $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem);
$this->getSection($phpWord)->addListItem($listItem->nodeValue, 0);
}
break;
case 'text:tracked-changes':
$changedRegions = $xmlReader->getElements('text:changed-region', $node);
foreach ($changedRegions as $changedRegion) {
$type = ($changedRegion->firstChild->nodeName == 'text:insertion') ? TrackChange::INSERTED : TrackChange::DELETED;
$creatorNode = $xmlReader->getElements('office:change-info/dc:creator', $changedRegion->firstChild);
$author = $creatorNode[0]->nodeValue;
$dateNode = $xmlReader->getElements('office:change-info/dc:date', $changedRegion->firstChild);
$date = $dateNode[0]->nodeValue;
$date = preg_replace('/\.\d+$/', '', $date);
$date = DateTime::createFromFormat('Y-m-d\TH:i:s', $date);
$changed = new TrackChange($type, $author, $date);
$textNodes = $xmlReader->getElements('text:deletion/text:p', $changedRegion);
$trackedChanges[$changedRegion->getAttribute('text:id')] = ['changed' => $changed, 'textNodes' => $textNodes];
}
break;
case 'text:section': // Section
// $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem);
$this->section = $phpWord->addSection();
$children = $node->childNodes;
$this->processNodes($children, $xmlReader, $phpWord);
break;
}
}
}
}
private function getSection(PhpWord $phpWord): Section
{
$section = $this->section;
if ($section === null) {
$section = $this->section = $phpWord->addSection();
}
return $section;
}
}
@@ -0,0 +1,78 @@
<?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\Reader\ODText;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Meta reader.
*
* @since 0.11.0
*/
class Meta extends AbstractPart
{
/**
* Read meta.xml.
*
* @todo Process property type
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$docProps = $phpWord->getDocInfo();
$metaNode = $xmlReader->getElement('office:meta');
// Standard properties
$properties = [
'title' => 'dc:title',
'subject' => 'dc:subject',
'description' => 'dc:description',
'keywords' => 'meta:keyword',
'creator' => 'meta:initial-creator',
'lastModifiedBy' => 'dc:creator',
// 'created' => 'meta:creation-date',
// 'modified' => 'dc:date',
];
foreach ($properties as $property => $path) {
$method = "set{$property}";
$propertyNode = $xmlReader->getElement($path, $metaNode);
if ($propertyNode !== null && method_exists($docProps, $method)) {
$docProps->$method($propertyNode->nodeValue);
}
}
// Custom properties
$propertyNodes = $xmlReader->getElements('meta:user-defined', $metaNode);
foreach ($propertyNodes as $propertyNode) {
$property = $xmlReader->getAttribute('meta:name', $propertyNode);
// Set category, company, and manager property
if (in_array($property, ['Category', 'Company', 'Manager'])) {
$method = "set{$property}";
$docProps->$method($propertyNode->nodeValue);
} else {
// Set other custom properties
$docProps->setCustomProperty($property, $propertyNode->nodeValue);
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
<?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\Reader;
use Exception;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Reader\RTF\Document;
/**
* RTF Reader class.
*
* @since 0.11.0
*/
class RTF extends AbstractReader implements ReaderInterface
{
/**
* Loads PhpWord from file.
*
* @param string $docFile
*
* @return PhpWord
*/
public function load($docFile)
{
$phpWord = new PhpWord();
if ($this->canRead($docFile)) {
$doc = new Document();
$doc->rtf = file_get_contents($docFile);
$doc->read($phpWord);
} else {
throw new Exception("Cannot read {$docFile}.");
}
return $phpWord;
}
}
@@ -0,0 +1,395 @@
<?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\Reader\RTF;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\SimpleType\Jc;
/**
* RTF document reader.
*
* References:
* - How to Write an RTF Reader http://latex2rtf.sourceforge.net/rtfspec_45.html
* - PHP rtfclass by Markus Fischer https://github.com/mfn/rtfclass
* - JavaScript RTF-parser by LazyGyu https://github.com/lazygyu/RTF-parser
*
* @since 0.11.0
*
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
*/
class Document
{
/** @const int */
const PARA = 'readParagraph';
const STYL = 'readStyle';
const SKIP = 'readSkip';
/**
* PhpWord object.
*
* @var PhpWord
*/
private $phpWord;
/**
* Section object.
*
* @var \PhpOffice\PhpWord\Element\Section
*/
private $section;
/**
* Textrun object.
*
* @var \PhpOffice\PhpWord\Element\TextRun
*/
private $textrun;
/**
* RTF content.
*
* @var string
*/
public $rtf;
/**
* Content length.
*
* @var int
*/
private $length = 0;
/**
* Character index.
*
* @var int
*/
private $offset = 0;
/**
* Current control word.
*
* @var string
*/
private $control = '';
/**
* Text content.
*
* @var string
*/
private $text = '';
/**
* Parsing a control word flag.
*
* @var bool
*/
private $isControl = false;
/**
* First character flag: watch out for control symbols.
*
* @var bool
*/
private $isFirst = false;
/**
* Group groups.
*
* @var array
*/
private $groups = [];
/**
* Parser flags; not used.
*
* @var array
*/
private $flags = [];
/**
* Parse RTF content.
*
* - Marks controlling characters `{`, `}`, and `\`
* - Removes line endings
* - Builds control words and control symbols
* - Pushes every other character into the text queue
*
* @todo Use `fread` stream for scalability
*/
public function read(PhpWord $phpWord): void
{
$markers = [
123 => 'markOpening', // {
125 => 'markClosing', // }
92 => 'markBackslash', // \
10 => 'markNewline', // LF
13 => 'markNewline', // CR
];
$this->phpWord = $phpWord;
$this->section = $phpWord->addSection();
$this->textrun = $this->section->addTextRun();
$this->length = strlen($this->rtf);
$this->flags['paragraph'] = true; // Set paragraph flag from the beginning
// Walk each characters
while ($this->offset < $this->length) {
$char = $this->rtf[$this->offset];
$ascii = ord($char);
if (isset($markers[$ascii])) { // Marker found: {, }, \, LF, or CR
$markerFunction = $markers[$ascii];
$this->$markerFunction();
} else {
if (false === $this->isControl) { // Non control word: Push character
$this->pushText($char);
} else {
if (preg_match('/^[a-zA-Z0-9-]?$/', $char)) { // No delimiter: Buffer control
$this->control .= $char;
$this->isFirst = false;
} else { // Delimiter found: Parse buffered control
if ($this->isFirst) {
$this->isFirst = false;
} else {
if (' ' == $char) { // Discard space as a control word delimiter
$this->flushControl(true);
}
}
}
}
}
++$this->offset;
}
$this->flushText();
}
/**
* Mark opening braket `{` character.
*/
private function markOpening(): void
{
$this->flush(true);
array_push($this->groups, $this->flags);
}
/**
* Mark closing braket `}` character.
*/
private function markClosing(): void
{
$this->flush(true);
$this->flags = array_pop($this->groups);
}
/**
* Mark backslash `\` character.
*/
private function markBackslash(): void
{
if ($this->isFirst) {
$this->setControl(false);
$this->text .= '\\';
} else {
$this->flush();
$this->setControl(true);
$this->control = '';
}
}
/**
* Mark newline character: Flush control word because it's not possible to span multiline.
*/
private function markNewline(): void
{
if ($this->isControl) {
$this->flushControl(true);
}
}
/**
* Flush control word or text.
*
* @param bool $isControl
*/
private function flush($isControl = false): void
{
if ($this->isControl) {
$this->flushControl($isControl);
} else {
$this->flushText();
}
}
/**
* Flush control word.
*
* @param bool $isControl
*/
private function flushControl($isControl = false): void
{
if (1 === preg_match('/^([A-Za-z]+)(-?[0-9]*) ?$/', $this->control, $match)) {
[, $control, $parameter] = $match;
$this->parseControl($control, $parameter);
}
if (true === $isControl) {
$this->setControl(false);
}
}
/**
* Flush text in queue.
*/
private function flushText(): void
{
if ($this->text != '') {
if (isset($this->flags['property'])) { // Set property
$this->flags['value'] = $this->text;
} else { // Set text
if (true === $this->flags['paragraph']) {
$this->flags['paragraph'] = false;
$this->flags['text'] = $this->text;
}
}
// Add text if it's not flagged as skipped
if (!isset($this->flags['skipped'])) {
$this->readText();
}
$this->text = '';
}
}
/**
* Reset control word and first char state.
*
* @param bool $value
*/
private function setControl($value): void
{
$this->isControl = $value;
$this->isFirst = $value;
}
/**
* Push text into queue.
*
* @param string $char
*/
private function pushText($char): void
{
if ('<' == $char) {
$this->text .= '&lt;';
} elseif ('>' == $char) {
$this->text .= '&gt;';
} else {
$this->text .= $char;
}
}
/**
* Parse control.
*
* @param string $control
* @param string $parameter
*/
private function parseControl($control, $parameter): void
{
$controls = [
'par' => [self::PARA, 'paragraph', true],
'b' => [self::STYL, 'font', 'bold', true],
'i' => [self::STYL, 'font', 'italic', true],
'u' => [self::STYL, 'font', 'underline', true],
'strike' => [self::STYL, 'font', 'strikethrough', true],
'fs' => [self::STYL, 'font', 'size', $parameter],
'qc' => [self::STYL, 'paragraph', 'alignment', Jc::CENTER],
'sa' => [self::STYL, 'paragraph', 'spaceAfter', $parameter],
'fonttbl' => [self::SKIP, 'fonttbl', null],
'colortbl' => [self::SKIP, 'colortbl', null],
'info' => [self::SKIP, 'info', null],
'generator' => [self::SKIP, 'generator', null],
'title' => [self::SKIP, 'title', null],
'subject' => [self::SKIP, 'subject', null],
'category' => [self::SKIP, 'category', null],
'keywords' => [self::SKIP, 'keywords', null],
'comment' => [self::SKIP, 'comment', null],
'shppict' => [self::SKIP, 'pic', null],
'fldinst' => [self::SKIP, 'link', null],
];
if (isset($controls[$control])) {
[$function] = $controls[$control];
if (method_exists($this, $function)) {
$directives = $controls[$control];
array_shift($directives); // remove the function variable; we won't need it
$this->$function($directives);
}
}
}
/**
* Read paragraph.
*
* @param array $directives
*/
private function readParagraph($directives): void
{
[$property, $value] = $directives;
$this->textrun = $this->section->addTextRun();
$this->flags[$property] = $value;
}
/**
* Read style.
*
* @param array $directives
*/
private function readStyle($directives): void
{
[$style, $property, $value] = $directives;
$this->flags['styles'][$style][$property] = $value;
}
/**
* Read skip.
*
* @param array $directives
*/
private function readSkip($directives): void
{
[$property] = $directives;
$this->flags['property'] = $property;
$this->flags['skipped'] = true;
}
/**
* Read text.
*/
private function readText(): void
{
$text = $this->textrun->addText($this->text);
if (isset($this->flags['styles']['font'])) {
$text->getFontStyle()->setStyleByArray($this->flags['styles']['font']);
}
}
}
@@ -0,0 +1,43 @@
<?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\Reader;
/**
* Reader interface.
*
* @since 0.8.0
*/
interface ReaderInterface
{
/**
* Can the current ReaderInterface read the file?
*
* @param string $filename
*
* @return bool
*/
public function canRead($filename);
/**
* Loads PhpWord from file.
*
* @param string $filename
*/
public function load($filename);
}
+194
View File
@@ -0,0 +1,194 @@
<?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\Reader;
use Exception;
use PhpOffice\PhpWord\Element\AbstractElement;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Reader\Word2007\AbstractPart;
use PhpOffice\PhpWord\Shared\XMLReader;
use PhpOffice\PhpWord\Shared\ZipArchive;
/**
* Reader for Word2007.
*
* @since 0.8.0
*
* @todo watermark, checkbox, toc
* @todo Partly done: image, object
*/
class Word2007 extends AbstractReader implements ReaderInterface
{
/**
* Loads PhpWord from file.
*
* @param string $docFile
*
* @return PhpWord
*/
public function load($docFile)
{
$phpWord = new PhpWord();
$relationships = $this->readRelationships($docFile);
$commentRefs = [];
$steps = [
[
'stepPart' => 'document',
'stepItems' => [
'styles' => 'Styles',
'numbering' => 'Numbering',
],
],
[
'stepPart' => 'main',
'stepItems' => [
'officeDocument' => 'Document',
'core-properties' => 'DocPropsCore',
'extended-properties' => 'DocPropsApp',
'custom-properties' => 'DocPropsCustom',
],
],
[
'stepPart' => 'document',
'stepItems' => [
'endnotes' => 'Endnotes',
'footnotes' => 'Footnotes',
'settings' => 'Settings',
'comments' => 'Comments',
],
],
];
foreach ($steps as $step) {
$stepPart = $step['stepPart'];
$stepItems = $step['stepItems'];
if (!isset($relationships[$stepPart])) {
continue;
}
foreach ($relationships[$stepPart] as $relItem) {
$relType = $relItem['type'];
if (isset($stepItems[$relType])) {
$partName = $stepItems[$relType];
$xmlFile = $relItem['target'];
$part = $this->readPart($phpWord, $relationships, $commentRefs, $partName, $docFile, $xmlFile);
$commentRefs = $part->getCommentReferences();
}
}
}
return $phpWord;
}
/**
* Read document part.
*
* @param array<string, array<string, null|AbstractElement>> $commentRefs
*/
private function readPart(PhpWord $phpWord, array $relationships, array $commentRefs, string $partName, string $docFile, string $xmlFile): AbstractPart
{
$partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}";
if (!class_exists($partClass)) {
throw new Exception(sprintf('The part "%s" doesn\'t exist', $partClass));
}
/** @var AbstractPart $part Type hint */
$part = new $partClass($docFile, $xmlFile);
$part->setImageLoading($this->hasImageLoading());
$part->setRels($relationships);
$part->setCommentReferences($commentRefs);
$part->read($phpWord);
return $part;
}
/**
* Read all relationship files.
*
* @param string $docFile
*
* @return array
*/
private function readRelationships($docFile)
{
$relationships = [];
// _rels/.rels
$relationships['main'] = $this->getRels($docFile, '_rels/.rels');
// word/_rels/*.xml.rels
$wordRelsPath = 'word/_rels/';
$zip = new ZipArchive();
if ($zip->open($docFile) === true) {
for ($i = 0; $i < $zip->numFiles; ++$i) {
$xmlFile = $zip->getNameIndex($i);
if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') {
$docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile));
$relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/');
}
}
$zip->close();
}
return $relationships;
}
/**
* Get relationship array.
*
* @param string $docFile
* @param string $xmlFile
* @param string $targetPrefix
*
* @return array
*/
private function getRels($docFile, $xmlFile, $targetPrefix = '')
{
$metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/';
$officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
$rels = [];
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($docFile, $xmlFile);
$nodes = $xmlReader->getElements('*');
foreach ($nodes as $node) {
$rId = $xmlReader->getAttribute('Id', $node);
$type = $xmlReader->getAttribute('Type', $node);
$target = $xmlReader->getAttribute('Target', $node);
$mode = $xmlReader->getAttribute('TargetMode', $node);
// Remove URL prefixes from $type to make it easier to read
$type = str_replace($metaPrefix, '', $type);
$type = str_replace($officePrefix, '', $type);
$docPart = str_replace('.xml', '', $target);
// Do not add prefix to link source
if ($type != 'hyperlink' && $mode != 'External') {
$target = $targetPrefix . $target;
}
// Push to return array
$rels[$rId] = ['type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode];
}
ksort($rels);
return $rels;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,56 @@
<?php
namespace PhpOffice\PhpWord\Reader\Word2007;
use DateTime;
use PhpOffice\PhpWord\Element\Comment;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
class Comments extends AbstractPart
{
/**
* Collection name comments.
*
* @var string
*/
protected $collection = 'comments';
/**
* Read settings.xml.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$comments = $phpWord->getComments();
$nodes = $xmlReader->getElements('*');
foreach ($nodes as $node) {
$name = str_replace('w:', '', $node->nodeName);
$author = $xmlReader->getAttribute('w:author', $node);
$date = $xmlReader->getAttribute('w:date', $node);
$initials = $xmlReader->getAttribute('w:initials', $node);
$element = new Comment($author, new DateTime($date), $initials);
$range = $this->getCommentReference($xmlReader->getAttribute('w:id', $node));
if ($range['start']) {
$range['start']->setCommentRangeStart($element);
}
if ($range['end']) {
$range['end']->setCommentRangeEnd($element);
}
$pNodes = $xmlReader->getElements('w:p/w:r', $node);
foreach ($pNodes as $pNode) {
$this->readRun($xmlReader, $pNode, $element, $this->collection);
}
$phpWord->getComments()->addItem($element);
}
}
}
@@ -0,0 +1,41 @@
<?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\Reader\Word2007;
/**
* Extended properties reader.
*
* @since 0.10.0
*/
class DocPropsApp extends DocPropsCore
{
/**
* Property mapping.
*
* @var array
*/
protected $mapping = ['Company' => 'setCompany', 'Manager' => 'setManager'];
/**
* Callback functions.
*
* @var array
*/
protected $callbacks = [];
}
@@ -0,0 +1,82 @@
<?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\Reader\Word2007;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Core properties reader.
*
* @since 0.10.0
*/
class DocPropsCore extends AbstractPart
{
/**
* Property mapping.
*
* @var array
*/
protected $mapping = [
'dc:creator' => 'setCreator',
'dc:title' => 'setTitle',
'dc:description' => 'setDescription',
'dc:subject' => 'setSubject',
'cp:keywords' => 'setKeywords',
'cp:category' => 'setCategory',
'cp:lastModifiedBy' => 'setLastModifiedBy',
'dcterms:created' => 'setCreated',
'dcterms:modified' => 'setModified',
];
/**
* Callback functions.
*
* @var array
*/
protected $callbacks = ['dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'];
/**
* Read core/extended document properties.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$docProps = $phpWord->getDocInfo();
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
if (!isset($this->mapping[$node->nodeName])) {
continue;
}
$method = $this->mapping[$node->nodeName];
$value = $node->nodeValue == '' ? null : $node->nodeValue;
if (isset($this->callbacks[$node->nodeName])) {
$value = $this->callbacks[$node->nodeName]($value);
}
if (method_exists($docProps, $method)) {
$docProps->$method($value);
}
}
}
}
}
@@ -0,0 +1,54 @@
<?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\Reader\Word2007;
use PhpOffice\PhpWord\Metadata\DocInfo;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Custom properties reader.
*
* @since 0.11.0
*/
class DocPropsCustom extends AbstractPart
{
/**
* Read custom document properties.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$docProps = $phpWord->getDocInfo();
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$propertyName = $xmlReader->getAttribute('name', $node);
$attributeNode = $xmlReader->getElement('*', $node);
$attributeType = $attributeNode->nodeName;
$attributeValue = $attributeNode->nodeValue;
$attributeValue = DocInfo::convertProperty($attributeValue, $attributeType);
$attributeType = DocInfo::convertPropertyType($attributeType);
$docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
}
}
}
}
@@ -0,0 +1,172 @@
<?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\Reader\Word2007;
use DOMElement;
use PhpOffice\PhpWord\Element\Section;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Document reader.
*
* @since 0.10.0
*
* @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
*/
class Document extends AbstractPart
{
/**
* PhpWord object.
*
* @var PhpWord
*/
private $phpWord;
/**
* Read document.xml.
*/
public function read(PhpWord $phpWord): void
{
$this->phpWord = $phpWord;
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$readMethods = ['w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode'];
$nodes = $xmlReader->getElements('w:body/*');
if ($nodes->length > 0) {
$section = $this->phpWord->addSection();
foreach ($nodes as $node) {
if (isset($readMethods[$node->nodeName])) {
$readMethod = $readMethods[$node->nodeName];
$this->$readMethod($xmlReader, $node, $section);
}
}
}
}
/**
* Read header footer.
*
* @param array $settings
*/
private function readHeaderFooter($settings, Section &$section): void
{
$readMethods = ['w:p' => 'readParagraph', 'w:tbl' => 'readTable'];
if (is_array($settings) && isset($settings['hf'])) {
foreach ($settings['hf'] as $rId => $hfSetting) {
if (isset($this->rels['document'][$rId])) {
[$hfType, $xmlFile, $docPart] = array_values($this->rels['document'][$rId]);
$addMethod = "add{$hfType}";
$hfObject = $section->$addMethod($hfSetting['type']);
// Read header/footer content
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $xmlFile);
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
if (isset($readMethods[$node->nodeName])) {
$readMethod = $readMethods[$node->nodeName];
$this->$readMethod($xmlReader, $node, $hfObject, $docPart);
}
}
}
}
}
}
}
/**
* Read w:sectPr.
*
* @ignoreScrutinizerPatch
*
* @return array
*/
private function readSectionStyle(XMLReader $xmlReader, DOMElement $domNode)
{
$styleDefs = [
'breakType' => [self::READ_VALUE, 'w:type'],
'vAlign' => [self::READ_VALUE, 'w:vAlign'],
'pageSizeW' => [self::READ_VALUE, 'w:pgSz', 'w:w'],
'pageSizeH' => [self::READ_VALUE, 'w:pgSz', 'w:h'],
'orientation' => [self::READ_VALUE, 'w:pgSz', 'w:orient'],
'colsNum' => [self::READ_VALUE, 'w:cols', 'w:num'],
'colsSpace' => [self::READ_VALUE, 'w:cols', 'w:space'],
'marginTop' => [self::READ_VALUE, 'w:pgMar', 'w:top'],
'marginLeft' => [self::READ_VALUE, 'w:pgMar', 'w:left'],
'marginBottom' => [self::READ_VALUE, 'w:pgMar', 'w:bottom'],
'marginRight' => [self::READ_VALUE, 'w:pgMar', 'w:right'],
'headerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:header'],
'footerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:footer'],
'gutter' => [self::READ_VALUE, 'w:pgMar', 'w:gutter'],
];
$styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
// Header and footer
// @todo Cleanup this part
$nodes = $xmlReader->getElements('*', $domNode);
foreach ($nodes as $node) {
if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') {
$id = $xmlReader->getAttribute('r:id', $node);
$styles['hf'][$id] = [
'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)),
'type' => $xmlReader->getAttribute('w:type', $node),
];
}
}
return $styles;
}
/**
* Read w:p node.
*/
private function readWPNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void
{
// Page break
if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') {
$section->addPageBreak(); // PageBreak
}
// Paragraph
$this->readParagraph($xmlReader, $node, $section);
// Section properties
if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) {
$sectPrNode = $xmlReader->getElement('w:pPr/w:sectPr', $node);
if ($sectPrNode !== null) {
$this->readWSectPrNode($xmlReader, $sectPrNode, $section);
}
$section = $this->phpWord->addSection();
}
}
/**
* Read w:sectPr node.
*/
private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void
{
$style = $this->readSectionStyle($xmlReader, $node);
$section->setStyle($style);
$this->readHeaderFooter($style, $section);
}
}
@@ -0,0 +1,41 @@
<?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\Reader\Word2007;
/**
* Endnotes reader.
*
* @since 0.10.0
*/
class Endnotes extends Footnotes
{
/**
* Collection name.
*
* @var string
*/
protected $collection = 'endnotes';
/**
* Element name.
*
* @var string
*/
protected $element = 'endnote';
}
@@ -0,0 +1,96 @@
<?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\Reader\Word2007;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Footnotes reader.
*
* @since 0.10.0
*/
class Footnotes extends AbstractPart
{
/**
* Collection name footnotes|endnotes.
*
* @var string
*/
protected $collection = 'footnotes';
/**
* Element name footnote|endnote.
*
* @var string
*/
protected $element = 'footnote';
/**
* Read (footnotes|endnotes).xml.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$id = $xmlReader->getAttribute('w:id', $node);
$type = $xmlReader->getAttribute('w:type', $node);
// Avoid w:type "separator" and "continuationSeparator"
// Only look for <footnote> or <endnote> without w:type attribute, or with w:type = normal
if ((null === $type || $type === 'normal')) {
$element = $this->getElement($phpWord, $id);
if ($element !== null) {
$pNodes = $xmlReader->getElements('w:p/*', $node);
foreach ($pNodes as $pNode) {
$this->readRun($xmlReader, $pNode, $element, $this->collection);
}
$addMethod = "add{$this->element}";
$phpWord->$addMethod($element);
}
}
}
}
}
/**
* Searches for the element with the given relationId.
*
* @param int $relationId
*
* @return null|\PhpOffice\PhpWord\Element\AbstractContainer
*/
private function getElement(PhpWord $phpWord, $relationId)
{
$getMethod = "get{$this->collection}";
$collection = $phpWord->$getMethod()->getItems();
//not found by key, looping to search by relationId
foreach ($collection as $collectionElement) {
if ($collectionElement->getRelationId() == $relationId) {
return $collectionElement;
}
}
return null;
}
}
@@ -0,0 +1,123 @@
<?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\Reader\Word2007;
use DOMElement;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Numbering reader.
*
* @since 0.10.0
*/
class Numbering extends AbstractPart
{
/**
* Read numbering.xml.
*/
public function read(PhpWord $phpWord): void
{
$abstracts = [];
$numberings = [];
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
// Abstract numbering definition
$nodes = $xmlReader->getElements('w:abstractNum');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$abstractId = $xmlReader->getAttribute('w:abstractNumId', $node);
$abstracts[$abstractId] = ['levels' => []];
$abstract = &$abstracts[$abstractId];
$subnodes = $xmlReader->getElements('*', $node);
foreach ($subnodes as $subnode) {
switch ($subnode->nodeName) {
case 'w:multiLevelType':
$abstract['type'] = $xmlReader->getAttribute('w:val', $subnode);
break;
case 'w:lvl':
$levelId = $xmlReader->getAttribute('w:ilvl', $subnode);
$abstract['levels'][$levelId] = $this->readLevel($xmlReader, $subnode, $levelId);
break;
}
}
}
}
// Numbering instance definition
$nodes = $xmlReader->getElements('w:num');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$numId = $xmlReader->getAttribute('w:numId', $node);
$abstractId = $xmlReader->getAttribute('w:val', $node, 'w:abstractNumId');
$numberings[$numId] = $abstracts[$abstractId];
$numberings[$numId]['numId'] = $numId;
$subnodes = $xmlReader->getElements('w:lvlOverride/w:lvl', $node);
foreach ($subnodes as $subnode) {
$levelId = $xmlReader->getAttribute('w:ilvl', $subnode);
$overrides = $this->readLevel($xmlReader, $subnode, $levelId);
foreach ($overrides as $key => $value) {
$numberings[$numId]['levels'][$levelId][$key] = $value;
}
}
}
}
// Push to Style collection
foreach ($numberings as $numId => $numbering) {
$phpWord->addNumberingStyle("PHPWordList{$numId}", $numbering);
}
}
/**
* Read numbering level definition from w:abstractNum and w:num.
*
* @param int $levelId
*
* @return array
*/
private function readLevel(XMLReader $xmlReader, DOMElement $subnode, $levelId)
{
$level = [];
$level['level'] = $levelId;
$level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start');
$level['format'] = $xmlReader->getAttribute('w:val', $subnode, 'w:numFmt');
$level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart');
$level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff');
$level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText');
$level['alignment'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc');
$level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab');
$level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind');
$level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind');
$level['font'] = $xmlReader->getAttribute('w:ascii', $subnode, 'w:rPr/w:rFonts');
$level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts');
foreach ($level as $key => $value) {
if (null === $value) {
unset($level[$key]);
}
}
return $level;
}
}
@@ -0,0 +1,171 @@
<?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\Reader\Word2007;
use DOMElement;
use PhpOffice\PhpWord\ComplexType\TrackChangesView;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
use PhpOffice\PhpWord\Style\Language;
/**
* Settings reader.
*
* @since 0.14.0
*/
class Settings extends AbstractPart
{
/**
* @var array<string>
*/
private $booleanProperties = [
'mirrorMargins',
'hideSpellingErrors',
'hideGrammaticalErrors',
'trackRevisions',
'doNotTrackMoves',
'doNotTrackFormatting',
'evenAndOddHeaders',
'updateFields',
'autoHyphenation',
'doNotHyphenateCaps',
'bookFoldPrinting',
];
/**
* Read settings.xml.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$docSettings = $phpWord->getSettings();
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$name = str_replace('w:', '', $node->nodeName);
$value = $xmlReader->getAttribute('w:val', $node);
$method = 'set' . $name;
if (in_array($name, $this->booleanProperties)) {
$docSettings->$method($value !== 'false');
} elseif (method_exists($this, $method)) {
$this->$method($xmlReader, $phpWord, $node);
} elseif (method_exists($docSettings, $method)) {
$docSettings->$method($value);
}
}
}
}
/**
* Sets the document Language.
*/
protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$val = $xmlReader->getAttribute('w:val', $node);
$eastAsia = $xmlReader->getAttribute('w:eastAsia', $node);
$bidi = $xmlReader->getAttribute('w:bidi', $node);
$themeFontLang = new Language();
$themeFontLang->setLatin($val);
$themeFontLang->setEastAsia($eastAsia);
$themeFontLang->setBidirectional($bidi);
$phpWord->getSettings()->setThemeFontLang($themeFontLang);
}
/**
* Sets the document protection.
*/
protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$documentProtection = $phpWord->getSettings()->getDocumentProtection();
$edit = $xmlReader->getAttribute('w:edit', $node);
if ($edit !== null) {
$documentProtection->setEditing($edit);
}
}
/**
* Sets the proof state.
*/
protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$proofState = $phpWord->getSettings()->getProofState();
$spelling = $xmlReader->getAttribute('w:spelling', $node);
$grammar = $xmlReader->getAttribute('w:grammar', $node);
if ($spelling !== null) {
$proofState->setSpelling($spelling);
}
if ($grammar !== null) {
$proofState->setGrammar($grammar);
}
}
/**
* Sets the proof state.
*/
protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$percent = $xmlReader->getAttribute('w:percent', $node);
$val = $xmlReader->getAttribute('w:val', $node);
if ($percent !== null || $val !== null) {
$phpWord->getSettings()->setZoom($percent === null ? $val : $percent);
}
}
/**
* Set the Revision view.
*/
protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$revisionView = new TrackChangesView();
$revisionView->setMarkup(filter_var($xmlReader->getAttribute('w:markup', $node), FILTER_VALIDATE_BOOLEAN));
$revisionView->setComments($xmlReader->getAttribute('w:comments', $node));
$revisionView->setInsDel(filter_var($xmlReader->getAttribute('w:insDel', $node), FILTER_VALIDATE_BOOLEAN));
$revisionView->setFormatting(filter_var($xmlReader->getAttribute('w:formatting', $node), FILTER_VALIDATE_BOOLEAN));
$revisionView->setInkAnnotations(filter_var($xmlReader->getAttribute('w:inkAnnotations', $node), FILTER_VALIDATE_BOOLEAN));
$phpWord->getSettings()->setRevisionView($revisionView);
}
protected function setConsecutiveHyphenLimit(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$value = $xmlReader->getAttribute('w:val', $node);
if ($value !== null) {
$phpWord->getSettings()->setConsecutiveHyphenLimit($value);
}
}
protected function setHyphenationZone(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void
{
$value = $xmlReader->getAttribute('w:val', $node);
if ($value !== null) {
$phpWord->getSettings()->setHyphenationZone($value);
}
}
}
@@ -0,0 +1,113 @@
<?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\Reader\Word2007;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
use PhpOffice\PhpWord\Style\Language;
/**
* Styles reader.
*
* @since 0.10.0
*/
class Styles extends AbstractPart
{
/**
* Read styles.xml.
*/
public function read(PhpWord $phpWord): void
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault');
if ($fontDefaults !== null) {
$fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults);
if ($fontDefaultStyle) {
if (array_key_exists('name', $fontDefaultStyle)) {
$phpWord->setDefaultFontName($fontDefaultStyle['name']);
}
if (array_key_exists('size', $fontDefaultStyle)) {
$phpWord->setDefaultFontSize($fontDefaultStyle['size']);
}
if (array_key_exists('color', $fontDefaultStyle)) {
$phpWord->setDefaultFontColor($fontDefaultStyle['color']);
}
if (array_key_exists('lang', $fontDefaultStyle)) {
$phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang']));
}
}
}
$paragraphDefaults = $xmlReader->getElement('w:docDefaults/w:pPrDefault');
if ($paragraphDefaults !== null) {
$paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults);
if ($paragraphDefaultStyle != null) {
$phpWord->setDefaultParagraphStyle($paragraphDefaultStyle);
}
}
$nodes = $xmlReader->getElements('w:style');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$type = $xmlReader->getAttribute('w:type', $node);
$name = $xmlReader->getAttribute('w:val', $node, 'w:name');
if (null === $name) {
$name = $xmlReader->getAttribute('w:styleId', $node);
}
$headingMatches = [];
preg_match('/Heading\s*(\d)/i', $name, $headingMatches);
// $default = ($xmlReader->getAttribute('w:default', $node) == 1);
switch ($type) {
case 'paragraph':
$paragraphStyle = $this->readParagraphStyle($xmlReader, $node);
$fontStyle = $this->readFontStyle($xmlReader, $node);
if (!empty($headingMatches)) {
$phpWord->addTitleStyle($headingMatches[1], $fontStyle, $paragraphStyle);
} else {
if (empty($fontStyle)) {
if (is_array($paragraphStyle)) {
$phpWord->addParagraphStyle($name, $paragraphStyle);
}
} else {
$phpWord->addFontStyle($name, $fontStyle, $paragraphStyle);
}
}
break;
case 'character':
$fontStyle = $this->readFontStyle($xmlReader, $node);
if (!empty($fontStyle)) {
$phpWord->addFontStyle($name, $fontStyle);
}
break;
case 'table':
$tStyle = $this->readTableStyle($xmlReader, $node);
if (!empty($tStyle)) {
$phpWord->addTableStyle($name, $tStyle);
}
break;
}
}
}
}
}
+527
View File
@@ -0,0 +1,527 @@
<?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;
/**
* PHPWord settings class.
*
* @since 0.8.0
*/
class Settings
{
/**
* Zip libraries.
*
* @const string
*/
public const ZIPARCHIVE = 'ZipArchive';
public const PCLZIP = 'PclZip';
public const OLD_LIB = Shared\ZipArchive::class; // @deprecated 0.11
/**
* PDF rendering libraries.
*
* @const string
*/
public const PDF_RENDERER_DOMPDF = 'DomPDF';
public const PDF_RENDERER_TCPDF = 'TCPDF';
public const PDF_RENDERER_MPDF = 'MPDF';
/**
* Measurement units multiplication factor.
* Applied to:
* - Section: margins, header/footer height, gutter, column spacing
* - Tab: position
* - Indentation: left, right, firstLine, hanging
* - Spacing: before, after.
*
* @const string
*/
public const UNIT_TWIP = 'twip'; // = 1/20 point
public const UNIT_CM = 'cm';
public const UNIT_MM = 'mm';
public const UNIT_INCH = 'inch';
public const UNIT_POINT = 'point'; // = 1/72 inch
public const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points
/**
* Default font settings.
* OOXML defined font size values in halfpoints, i.e. twice of what PhpWord
* use, and the conversion will be conducted during XML writing.
*/
public const DEFAULT_FONT_NAME = 'Arial';
public const DEFAULT_FONT_SIZE = 10;
public const DEFAULT_FONT_COLOR = '000000';
public const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs
public const DEFAULT_PAPER = 'A4';
/**
* Compatibility option for XMLWriter.
*
* @var bool
*/
private static $xmlWriterCompatibility = true;
/**
* Name of the class used for Zip file management.
*
* @var string
*/
private static $zipClass = self::ZIPARCHIVE;
/**
* Name of the external Library used for rendering PDF files.
*
* @var null|string
*/
private static $pdfRendererName;
/**
* Options used for rendering PDF files.
*
* @var array
*/
private static $pdfRendererOptions = [];
/**
* Directory Path to the external Library used for rendering PDF files.
*
* @var null|string
*/
private static $pdfRendererPath;
/**
* Measurement unit.
*
* @var string
*/
private static $measurementUnit = self::UNIT_TWIP;
/**
* Default font name.
*
* @var string
*/
private static $defaultFontName = self::DEFAULT_FONT_NAME;
/**
* Default asian font name.
*
* @var string
*/
private static $defaultAsianFontName = self::DEFAULT_FONT_NAME;
/**
* Default font color.
*
* @var string
*/
private static $defaultFontColor = self::DEFAULT_FONT_COLOR;
/**
* Default font size.
*
* @var float|int
*/
private static $defaultFontSize = self::DEFAULT_FONT_SIZE;
/**
* Default paper.
*
* @var string
*/
private static $defaultPaper = self::DEFAULT_PAPER;
/**
* Is RTL by default ?
*
* @var ?bool
*/
private static $defaultRtl;
/**
* The user defined temporary directory.
*
* @var string
*/
private static $tempDir = '';
/**
* Enables built-in output escaping mechanism.
* Default value is `false` for backward compatibility with versions below 0.13.0.
*
* @var bool
*/
private static $outputEscapingEnabled = false;
/**
* Return the compatibility option used by the XMLWriter.
*
* @return bool Compatibility
*/
public static function hasCompatibility(): bool
{
return self::$xmlWriterCompatibility;
}
/**
* Set the compatibility option used by the XMLWriter.
* This sets the setIndent and setIndentString for better compatibility.
*/
public static function setCompatibility(bool $compatibility): bool
{
self::$xmlWriterCompatibility = $compatibility;
return true;
}
/**
* Get zip handler class.
*/
public static function getZipClass(): string
{
return self::$zipClass;
}
/**
* Set zip handler class.
*/
public static function setZipClass(string $zipClass): bool
{
if (in_array($zipClass, [self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB])) {
self::$zipClass = $zipClass;
return true;
}
return false;
}
/**
* Set details of the external library for rendering PDF files.
*
* @return bool Success or failure
*/
public static function setPdfRenderer(string $libraryName, string $libraryBaseDir): bool
{
if (!self::setPdfRendererName($libraryName)) {
return false;
}
return self::setPdfRendererPath($libraryBaseDir);
}
/**
* Return the PDF Rendering Library.
*/
public static function getPdfRendererName(): ?string
{
return self::$pdfRendererName;
}
/**
* Identify the external library to use for rendering PDF files.
*/
public static function setPdfRendererName(?string $libraryName): bool
{
$pdfRenderers = [self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF];
if (!in_array($libraryName, $pdfRenderers)) {
return false;
}
self::$pdfRendererName = $libraryName;
return true;
}
/**
* Return the directory path to the PDF Rendering Library.
*/
public static function getPdfRendererPath(): ?string
{
return self::$pdfRendererPath;
}
/**
* Set options of the external library for rendering PDF files.
*/
public static function setPdfRendererOptions(array $options): void
{
self::$pdfRendererOptions = $options;
}
/**
* Return the PDF Rendering Options.
*/
public static function getPdfRendererOptions(): array
{
return self::$pdfRendererOptions;
}
/**
* Location of external library to use for rendering PDF files.
*
* @param null|string $libraryBaseDir Directory path to the library's base folder
*
* @return bool Success or failure
*/
public static function setPdfRendererPath(?string $libraryBaseDir): bool
{
if (!$libraryBaseDir || false === file_exists($libraryBaseDir) || false === is_readable($libraryBaseDir)) {
return false;
}
self::$pdfRendererPath = $libraryBaseDir;
return true;
}
/**
* Get measurement unit.
*/
public static function getMeasurementUnit(): string
{
return self::$measurementUnit;
}
/**
* Set measurement unit.
*/
public static function setMeasurementUnit(string $value): bool
{
$units = [
self::UNIT_TWIP,
self::UNIT_CM,
self::UNIT_MM,
self::UNIT_INCH,
self::UNIT_POINT,
self::UNIT_PICA,
];
if (!in_array($value, $units)) {
return false;
}
self::$measurementUnit = $value;
return true;
}
/**
* Sets the user defined path to temporary directory.
*
* @param string $tempDir The user defined path to temporary directory
*
* @since 0.12.0
*/
public static function setTempDir(string $tempDir): void
{
self::$tempDir = $tempDir;
}
/**
* Returns path to temporary directory.
*
* @since 0.12.0
*/
public static function getTempDir(): string
{
if (!empty(self::$tempDir)) {
$tempDir = self::$tempDir;
} else {
$tempDir = sys_get_temp_dir();
}
return $tempDir;
}
/**
* @since 0.13.0
*/
public static function isOutputEscapingEnabled(): bool
{
return self::$outputEscapingEnabled;
}
/**
* @since 0.13.0
*/
public static function setOutputEscapingEnabled(bool $outputEscapingEnabled): void
{
self::$outputEscapingEnabled = $outputEscapingEnabled;
}
/**
* Get default font name.
*/
public static function getDefaultFontName(): string
{
return self::$defaultFontName;
}
/**
* Get default font name.
*/
public static function getDefaultAsianFontName(): string
{
return self::$defaultAsianFontName;
}
/**
* Set default font name.
*/
public static function setDefaultFontName(string $value): bool
{
if (trim($value) !== '') {
self::$defaultFontName = $value;
return true;
}
return false;
}
public static function setDefaultAsianFontName(string $value): bool
{
if (trim($value) !== '') {
self::$defaultAsianFontName = $value;
return true;
}
return false;
}
/**
* Get default font color.
*/
public static function getDefaultFontColor(): string
{
return self::$defaultFontColor;
}
/**
* Set default font color.
*/
public static function setDefaultFontColor(string $value): bool
{
if (trim($value) !== '') {
self::$defaultFontColor = $value;
return true;
}
return false;
}
/**
* Get default font size.
*
* @return float|int
*/
public static function getDefaultFontSize()
{
return self::$defaultFontSize;
}
/**
* Set default font size.
*
* @param null|float|int $value
*/
public static function setDefaultFontSize($value): bool
{
if ((is_int($value) || is_float($value)) && (int) $value > 0) {
self::$defaultFontSize = $value;
return true;
}
return false;
}
public static function setDefaultRtl(?bool $defaultRtl): void
{
self::$defaultRtl = $defaultRtl;
}
public static function isDefaultRtl(): ?bool
{
return self::$defaultRtl;
}
/**
* Load setting from phpword.yml or phpword.yml.dist.
*/
public static function loadConfig(?string $filename = null): array
{
// Get config file
$configFile = null;
$configPath = __DIR__ . '/../../';
if ($filename !== null) {
$files = [$filename];
} else {
$files = ["{$configPath}phpword.ini", "{$configPath}phpword.ini.dist"];
}
foreach ($files as $file) {
if (file_exists($file)) {
$configFile = realpath($file);
break;
}
}
// Parse config file
$config = [];
if ($configFile !== null) {
$config = @parse_ini_file($configFile);
if ($config === false) {
return [];
}
}
// Set config value
$appliedConfig = [];
foreach ($config as $key => $value) {
$method = "set{$key}";
if (method_exists(__CLASS__, $method)) {
self::$method($value);
$appliedConfig[$key] = $value;
}
}
return $appliedConfig;
}
/**
* Get default paper.
*/
public static function getDefaultPaper(): string
{
return self::$defaultPaper;
}
/**
* Set default paper.
*/
public static function setDefaultPaper(string $value): bool
{
if (trim($value) !== '') {
self::$defaultPaper = $value;
return true;
}
return false;
}
}
@@ -0,0 +1,80 @@
<?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));
}
}
}
@@ -0,0 +1,456 @@
<?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));
}
}
+77
View File
@@ -0,0 +1,77 @@
<?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
*/
declare(strict_types=1);
namespace PhpOffice\PhpWord\Shared;
class Css
{
/**
* @var string
*/
private $cssContent;
/**
* @var array<string, array<string, string>>
*/
private $styles = [];
public function __construct(string $cssContent)
{
$this->cssContent = $cssContent;
}
public function process(): void
{
$cssContent = str_replace(["\r", "\n"], '', $this->cssContent);
preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $cssContent, $cssExtracted);
// Check if there are x selectors and x rules
if (count($cssExtracted[1]) != count($cssExtracted[2])) {
return;
}
foreach ($cssExtracted[1] as $key => $selector) {
$rules = trim($cssExtracted[2][$key]);
$rules = explode(';', $rules);
foreach ($rules as $rule) {
if (empty($rule)) {
continue;
}
[$key, $value] = explode(':', trim($rule));
$this->styles[$this->sanitize($selector)][$this->sanitize($key)] = $this->sanitize($value);
}
}
}
public function getStyles(): array
{
return $this->styles;
}
public function getStyle(string $selector): array
{
$selector = $this->sanitize($selector);
return $this->styles[$selector] ?? [];
}
private function sanitize(string $value): string
{
return addslashes(trim($value));
}
}
+264
View File
@@ -0,0 +1,264 @@
<?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];
}
}
File diff suppressed because it is too large Load Diff
@@ -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\Microsoft;
use PhpOffice\PhpWord\Exception\Exception;
/**
* 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';
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.
*
* @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');
if (!is_string($passUtf8)) {
throw new Exception('Failed to convert password to UCS-2LE');
}
$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 & 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');
// 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 keys 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 & self::ALL_ONE_BITS;
if ($value & self::HIGH_ORDER_BIT) {
$value = -((~$value & self::ALL_ONE_BITS) + 1);
}
return $value;
}
}
+334
View File
@@ -0,0 +1,334 @@
<?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;
public $numBigBlockDepotBlocks = null;
public $rootStartBlock = null;
public $sbdStartBlock = null;
public $extensionBlock = null;
public $numExtensionBlocks = null;
public $bigBlockChain = null;
public $smallBlockChain = null;
public $entry = null;
public $rootentry = null;
public $wrkObjectPoolelseif = null;
public $props = array();
/**
* 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;
}
}
File diff suppressed because it is too large Load Diff
+259
View File
@@ -0,0 +1,259 @@
<?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 PhpOffice\PhpWord\Exception\Exception;
/**
* 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 null|string $value
*
* @return ?string
*/
public static function toUTF8($value = '')
{
if (null !== $value && !self::isUTF8($value)) {
// PHP8.2 : utf8_encode is deprecated, but mb_convert_encoding always usable
$value = (function_exists('mb_convert_encoding')) ? mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1') : utf8_encode($value);
if ($value === false) {
throw new Exception('Unable to convert text to UTF-8');
}
}
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;
}
}
@@ -0,0 +1,77 @@
<?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
*/
declare(strict_types=1);
namespace PhpOffice\PhpWord\Shared;
class Validate
{
public const CSS_WHITESPACE = [
'pre-wrap',
'normal',
'nowrap',
'pre',
'pre-line',
'initial',
'inherit',
];
public const CSS_GENERICFONT = [
'serif',
'sans-serif',
'monospace',
'cursive',
'fantasy',
'system-ui',
'math',
'emoji',
'fangsong',
];
/**
* Validate html css white-space value. It is expected that only pre-wrap and normal (default) are useful.
*
* @param string $value CSS White space
*
* @return string value if valid, empty string if not
*/
public static function validateCSSWhiteSpace(?string $value): string
{
if (in_array($value, self::CSS_WHITESPACE)) {
return $value;
}
return '';
}
/**
* Validate generic font for fallback for html.
*
* @param string $value Generic font name
*
* @return string Value if legitimate, empty string if not
*/
public static function validateCSSGenericFont(?string $value): string
{
if (in_array($value, self::CSS_GENERICFONT)) {
return $value;
}
return '';
}
}

Some files were not shown because too many files have changed in this diff Show More