See Release Notes
Long Term Support Release
<?php namespace PhpOffice\PhpSpreadsheet\Document;> use DateTime; class Properties > use PhpOffice\PhpSpreadsheet\Shared\IntOrFloat; { >/** 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';> public const PROPERTY_TYPE_BOOLEAN = 'b'; > public const PROPERTY_TYPE_INTEGER = 'i'; > public const PROPERTY_TYPE_FLOAT = 'f'; > public const PROPERTY_TYPE_DATE = 'd'; > public const PROPERTY_TYPE_STRING = 's'; > public const PROPERTY_TYPE_UNKNOWN = 'u'; > > private const VALID_PROPERTY_TYPE_LIST = [ > self::PROPERTY_TYPE_BOOLEAN, > self::PROPERTY_TYPE_INTEGER, > self::PROPERTY_TYPE_FLOAT, > self::PROPERTY_TYPE_DATE, > self::PROPERTY_TYPE_STRING, > ];/** * Creator. * * @var string */ private $creator = 'Unknown Creator'; /** * LastModifiedBy. * * @var string */ private $lastModifiedBy; /** * Created. *< * @var int> * @var float|int*/ private $created; /** * Modified. *< * @var int> * @var float|int*/ private $modified; /** * Title. * * @var string */ private $title = 'Untitled Spreadsheet'; /** * Description. * * @var string */ private $description = ''; /** * Subject. * * @var string */ private $subject = ''; /** * Keywords. * * @var string */ private $keywords = ''; /** * Category. * * @var string */ private $category = ''; /** * Manager. * * @var string */ private $manager = ''; /** * Company. * * @var string */< private $company = 'Microsoft Corporation';> private $company = '';/** * Custom Properties. *< * @var string> * @var array{value: mixed, type: string}[]*/ private $customProperties = [];> private string $hyperlinkBase = ''; /** >* Create a new Document Properties instance. */ public function __construct() { // Initialise values $this->lastModifiedBy = $this->creator;< $this->created = time(); < $this->modified = time();> $this->created = self::intOrFloatTimestamp(null); > $this->modified = $this->created;} /** * Get Creator.< * < * @return string*/< public function getCreator()> public function getCreator(): string{ return $this->creator; } /** * Set Creator. *< * @param string $creator < * < * @return Properties> * @return $this*/< public function setCreator($creator)> public function setCreator(string $creator): self{ $this->creator = $creator; return $this; } /** * Get Last Modified By.< * < * @return string*/< public function getLastModifiedBy()> public function getLastModifiedBy(): string{ return $this->lastModifiedBy; } /** * Set Last Modified By. *< * @param string $pValue < * < * @return Properties> * @return $this*/< public function setLastModifiedBy($pValue)> public function setLastModifiedBy(string $modifiedBy): self{< $this->lastModifiedBy = $pValue;> $this->lastModifiedBy = $modifiedBy;return $this; } /**> * @param null|float|int|string $timestamp * Get Created. > * * > * @return float|int * @return int > */ */ > private static function intOrFloatTimestamp($timestamp) public function getCreated() > { { > if ($timestamp === null) { return $this->created; > $timestamp = (float) (new DateTime())->format('U'); } > } elseif (is_string($timestamp)) { > if (is_numeric($timestamp)) { /** > $timestamp = (float) $timestamp; * Set Created. > } else { * > $timestamp = (string) preg_replace('/[.][0-9]*$/', '', $timestamp); * @param int|string $time > $timestamp = (string) preg_replace('/^(\\d{4})- (\\d)/', '$1-0$2', $timestamp); * > $timestamp = (string) preg_replace('/^(\\d{4}-\\d{2})- (\\d)/', '$1-0$2', $timestamp); * @return Properties > $timestamp = (float) (new DateTime($timestamp))->format('U'); */ > } public function setCreated($time) > } { > if ($time === null) { > return IntOrFloat::evaluate($timestamp); $time = time(); > } } elseif (is_string($time)) { > if (is_numeric($time)) { > /**< * @return int> * @return float|int< * @param int|string $time> * @param null|float|int|string $timestamp< * @return Properties> * @return $this< public function setCreated($time)> public function setCreated($timestamp): self< if ($time === null) { < $time = time(); < } elseif (is_string($time)) { < if (is_numeric($time)) { < $time = (int) $time; < } else { < $time = strtotime($time); < } < } < < $this->created = $time;> $this->created = self::intOrFloatTimestamp($timestamp);< * @return int> * @return float|intpublic function getModified() { return $this->modified; } /** * Set Modified. *< * @param int|string $time> * @param null|float|int|string $timestamp*< * @return Properties> * @return $this*/< public function setModified($time)> public function setModified($timestamp): self{< if ($time === null) { < $time = time(); < } elseif (is_string($time)) { < if (is_numeric($time)) { < $time = (int) $time; < } else { < $time = strtotime($time); < } < } < < $this->modified = $time;> $this->modified = self::intOrFloatTimestamp($timestamp);return $this; } /** * Get Title.< * < * @return string*/< public function getTitle()> public function getTitle(): string{ return $this->title; } /** * Set Title. *< * @param string $title < * < * @return Properties> * @return $this*/< public function setTitle($title)> public function setTitle(string $title): self{ $this->title = $title; return $this; } /** * Get Description.< * < * @return string*/< public function getDescription()> public function getDescription(): string{ return $this->description; } /** * Set Description. *< * @param string $description < * < * @return Properties> * @return $this*/< public function setDescription($description)> public function setDescription(string $description): self{ $this->description = $description; return $this; } /** * Get Subject.< * < * @return string*/< public function getSubject()> public function getSubject(): string{ return $this->subject; } /** * Set Subject. *< * @param string $subject < * < * @return Properties> * @return $this*/< public function setSubject($subject)> public function setSubject(string $subject): self{ $this->subject = $subject; return $this; } /** * Get Keywords.< * < * @return string*/< public function getKeywords()> public function getKeywords(): string{ return $this->keywords; } /** * Set Keywords. *< * @param string $keywords < * < * @return Properties> * @return $this*/< public function setKeywords($keywords)> public function setKeywords(string $keywords): self{ $this->keywords = $keywords; return $this; } /** * Get Category.< * < * @return string*/< public function getCategory()> public function getCategory(): string{ return $this->category; } /** * Set Category. *< * @param string $category < * < * @return Properties> * @return $this*/< public function setCategory($category)> public function setCategory(string $category): self{ $this->category = $category; return $this; } /** * Get Company.< * < * @return string*/< public function getCompany()> public function getCompany(): string{ return $this->company; } /** * Set Company. *< * @param string $company < * < * @return Properties> * @return $this*/< public function setCompany($company)> public function setCompany(string $company): self{ $this->company = $company; return $this; } /** * Get Manager.< * < * @return string*/< public function getManager()> public function getManager(): string{ return $this->manager; } /** * Set Manager. *< * @param string $manager < * < * @return Properties> * @return $this*/< public function setManager($manager)> public function setManager(string $manager): self{ $this->manager = $manager; return $this; } /** * Get a List of Custom Property Names. *< * @return array of string> * @return string[]*/< public function getCustomProperties()> public function getCustomProperties(): array{ return array_keys($this->customProperties); } /** * Check if a Custom Property is defined.< * < * @param string $propertyName < * < * @return bool*/< public function isCustomPropertySet($propertyName)> public function isCustomPropertySet(string $propertyName): bool{< return isset($this->customProperties[$propertyName]);> return array_key_exists($propertyName, $this->customProperties);} /** * Get a Custom Property Value. *< * @param string $propertyName < ** @return mixed */< public function getCustomPropertyValue($propertyName)> public function getCustomPropertyValue(string $propertyName){ if (isset($this->customProperties[$propertyName])) { return $this->customProperties[$propertyName]['value']; }> } > return null;/** * Get a Custom Property Type. *< * @param string $propertyName < * < * @return string> * @return null|string*/< public function getCustomPropertyType($propertyName)> public function getCustomPropertyType(string $propertyName){< if (isset($this->customProperties[$propertyName])) { < return $this->customProperties[$propertyName]['type'];> return $this->customProperties[$propertyName]['type'] ?? null;}> } > /** > * @param mixed $propertyValue /** > */ * Set a Custom Property. > private function identifyPropertyType($propertyValue): string * > { * @param string $propertyName > if (is_float($propertyValue)) { * @param mixed $propertyValue > return self::PROPERTY_TYPE_FLOAT; * @param string $propertyType > } * 'i' : Integer > if (is_int($propertyValue)) { * 'f' : Floating Point > return self::PROPERTY_TYPE_INTEGER; * 's' : String > } * 'd' : Date/Time > if (is_bool($propertyValue)) { * 'b' : Boolean > return self::PROPERTY_TYPE_BOOLEAN; * > } * @return Properties > */ > return self::PROPERTY_TYPE_STRING;< * @param string $propertyName< * @return Properties> * @return $this< public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)> public function setCustomProperty(string $propertyName, $propertyValue = '', $propertyType = null): self< if (($propertyType === null) || (!in_array($propertyType, [self::PROPERTY_TYPE_INTEGER, < self::PROPERTY_TYPE_FLOAT, < self::PROPERTY_TYPE_STRING, < self::PROPERTY_TYPE_DATE, < self::PROPERTY_TYPE_BOOLEAN, ]))) { < 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; < } else { < $propertyType = self::PROPERTY_TYPE_STRING; < }> if (($propertyType === null) || (!in_array($propertyType, self::VALID_PROPERTY_TYPE_LIST))) { > $propertyType = $this->identifyPropertyType($propertyValue);> if (!is_object($propertyValue)) {$this->customProperties[$propertyName] = [< 'value' => $propertyValue,> 'value' => self::convertProperty($propertyValue, $propertyType),'type' => $propertyType, ];> }return $this; }> private const PROPERTY_TYPE_ARRAY = [ /** > 'i' => self::PROPERTY_TYPE_INTEGER, // Integer * Implement PHP __clone to create a deep clone, not just a shallow copy. > 'i1' => self::PROPERTY_TYPE_INTEGER, // 1-Byte Signed Integer */ > 'i2' => self::PROPERTY_TYPE_INTEGER, // 2-Byte Signed Integer public function __clone() > 'i4' => self::PROPERTY_TYPE_INTEGER, // 4-Byte Signed Integer { > 'i8' => self::PROPERTY_TYPE_INTEGER, // 8-Byte Signed Integer $vars = get_object_vars($this); > 'int' => self::PROPERTY_TYPE_INTEGER, // Integer foreach ($vars as $key => $value) { > 'ui1' => self::PROPERTY_TYPE_INTEGER, // 1-Byte Unsigned Integer if (is_object($value)) { > 'ui2' => self::PROPERTY_TYPE_INTEGER, // 2-Byte Unsigned Integer $this->$key = clone $value; > 'ui4' => self::PROPERTY_TYPE_INTEGER, // 4-Byte Unsigned Integer } else { > 'ui8' => self::PROPERTY_TYPE_INTEGER, // 8-Byte Unsigned Integer $this->$key = $value; > 'uint' => self::PROPERTY_TYPE_INTEGER, // Unsigned Integer } > 'f' => self::PROPERTY_TYPE_FLOAT, // Real Number } > 'r4' => self::PROPERTY_TYPE_FLOAT, // 4-Byte Real Number } > 'r8' => self::PROPERTY_TYPE_FLOAT, // 8-Byte Real Number > 'decimal' => self::PROPERTY_TYPE_FLOAT, // Decimal public static function convertProperty($propertyValue, $propertyType) > 's' => self::PROPERTY_TYPE_STRING, // String { > 'empty' => self::PROPERTY_TYPE_STRING, // Empty switch ($propertyType) { > 'null' => self::PROPERTY_TYPE_STRING, // Null case 'empty': // Empty > 'lpstr' => self::PROPERTY_TYPE_STRING, // LPSTR return ''; > 'lpwstr' => self::PROPERTY_TYPE_STRING, // LPWSTR > 'bstr' => self::PROPERTY_TYPE_STRING, // Basic String break; > 'd' => self::PROPERTY_TYPE_DATE, // Date and Time case 'null': // Null > 'date' => self::PROPERTY_TYPE_DATE, // Date and Time return null; > 'filetime' => self::PROPERTY_TYPE_DATE, // File Time > 'b' => self::PROPERTY_TYPE_BOOLEAN, // Boolean break; > 'bool' => self::PROPERTY_TYPE_BOOLEAN, // Boolean case 'i1': // 1-Byte Signed Integer > ]; case 'i2': // 2-Byte Signed Integer > case 'i4': // 4-Byte Signed Integer > private const SPECIAL_TYPES = [ case 'i8': // 8-Byte Signed Integer > 'empty' => '', case 'int': // Integer > 'null' => null, return (int) $propertyValue; > ]; >< * Implement PHP __clone to create a deep clone, not just a shallow copy.> * Convert property to form desired by Excel. > * > * @param mixed $propertyValue > * > * @return mixed< public function __clone()> public static function convertProperty($propertyValue, string $propertyType)< $vars = get_object_vars($this); < foreach ($vars as $key => $value) { < if (is_object($value)) { < $this->$key = clone $value; < } else { < $this->$key = $value; < } < }> return self::SPECIAL_TYPES[$propertyType] ?? self::convertProperty2($propertyValue, $propertyType);< public static function convertProperty($propertyValue, $propertyType)> /** > * Convert property to form desired by Excel. > * > * @param mixed $propertyValue > * > * @return mixed > */ > private static function convertProperty2($propertyValue, string $type)case 'decimal': // Decimal> $propertyType = self::convertPropertyType($type);< case 'empty': // Empty < return '';> case self::PROPERTY_TYPE_INTEGER: > $intValue = (int) $propertyValue;< break; < case 'null': // Null < return null; < < break; < case 'i1': // 1-Byte Signed Integer < case 'i2': // 2-Byte Signed Integer < case 'i4': // 4-Byte Signed Integer < case 'i8': // 8-Byte Signed Integer < case 'int': // Integer < return (int) $propertyValue; < < break; < case 'ui1': // 1-Byte Unsigned Integer < case 'ui2': // 2-Byte Unsigned Integer < case 'ui4': // 4-Byte Unsigned Integer < case 'ui8': // 8-Byte Unsigned Integer < case 'uint': // Unsigned Integer < return abs((int) $propertyValue); < < break; < case 'r4': // 4-Byte Real Number < case 'r8': // 8-Byte Real Number < case 'decimal': // Decimal> return ($type[0] === 'u') ? abs($intValue) : $intValue; > case self::PROPERTY_TYPE_FLOAT:< < break; < case 'lpstr': // LPSTR < case 'lpwstr': // LPWSTR < case 'bstr': // Basic String> case self::PROPERTY_TYPE_DATE: > return self::intOrFloatTimestamp($propertyValue); > case self::PROPERTY_TYPE_BOOLEAN: > return is_bool($propertyValue) ? $propertyValue : ($propertyValue === 'true'); > default: // includes string< < break; < case 'date': // Date and Time < case 'filetime': // File Time < return strtotime($propertyValue); < < break; < case 'bool': // Boolean < return $propertyValue == 'true'; < < break; < case 'cy': // Currency < case 'error': // Error Status Code < case 'vector': // Vector < case 'array': // Array < case 'blob': // Binary Blob < case 'oblob': // Binary Blob Object < case 'stream': // Binary Stream < case 'ostream': // Binary Stream Object < case 'storage': // Binary Storage < case 'ostorage': // Binary Storage Object < case 'vstream': // Binary Versioned Stream < case 'clsid': // Class ID < case 'cf': // Clipboard Data < return $propertyValue; < < break;< < return $propertyValue;< public static function convertPropertyType($propertyType)> public static function convertPropertyType(string $propertyType): string< switch ($propertyType) { < case 'i1': // 1-Byte Signed Integer < case 'i2': // 2-Byte Signed Integer < case 'i4': // 4-Byte Signed Integer < case 'i8': // 8-Byte Signed Integer < case 'int': // Integer < case 'ui1': // 1-Byte Unsigned Integer < case 'ui2': // 2-Byte Unsigned Integer < case 'ui4': // 4-Byte Unsigned Integer < case 'ui8': // 8-Byte Unsigned Integer < case 'uint': // Unsigned Integer < return self::PROPERTY_TYPE_INTEGER; < < break; < case 'r4': // 4-Byte Real Number < case 'r8': // 8-Byte Real Number < case 'decimal': // Decimal < return self::PROPERTY_TYPE_FLOAT; < < break; < case 'empty': // Empty < case 'null': // Null < case 'lpstr': // LPSTR < case 'lpwstr': // LPWSTR < case 'bstr': // Basic String < return self::PROPERTY_TYPE_STRING; < < break; < case 'date': // Date and Time < case 'filetime': // File Time < return self::PROPERTY_TYPE_DATE; < < break; < case 'bool': // Boolean < return self::PROPERTY_TYPE_BOOLEAN; < < break; < case 'cy': // Currency < case 'error': // Error Status Code < case 'vector': // Vector < case 'array': // Array < case 'blob': // Binary Blob < case 'oblob': // Binary Blob Object < case 'stream': // Binary Stream < case 'ostream': // Binary Stream Object < case 'storage': // Binary Storage < case 'ostorage': // Binary Storage Object < case 'vstream': // Binary Versioned Stream < case 'clsid': // Class ID < case 'cf': // Clipboard Data < return self::PROPERTY_TYPE_UNKNOWN;> return self::PROPERTY_TYPE_ARRAY[$propertyType] ?? self::PROPERTY_TYPE_UNKNOWN; > }< break;> public function getHyperlinkBase(): string > { > return $this->hyperlinkBase;< return self::PROPERTY_TYPE_UNKNOWN;> public function setHyperlinkBase(string $hyperlinkBase): self > { > $this->hyperlinkBase = $hyperlinkBase; > > return $this;