See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Document; 4 5 use DateTime; 6 use PhpOffice\PhpSpreadsheet\Shared\IntOrFloat; 7 8 class Properties 9 { 10 /** constants */ 11 public const PROPERTY_TYPE_BOOLEAN = 'b'; 12 public const PROPERTY_TYPE_INTEGER = 'i'; 13 public const PROPERTY_TYPE_FLOAT = 'f'; 14 public const PROPERTY_TYPE_DATE = 'd'; 15 public const PROPERTY_TYPE_STRING = 's'; 16 public const PROPERTY_TYPE_UNKNOWN = 'u'; 17 18 private const VALID_PROPERTY_TYPE_LIST = [ 19 self::PROPERTY_TYPE_BOOLEAN, 20 self::PROPERTY_TYPE_INTEGER, 21 self::PROPERTY_TYPE_FLOAT, 22 self::PROPERTY_TYPE_DATE, 23 self::PROPERTY_TYPE_STRING, 24 ]; 25 26 /** 27 * Creator. 28 * 29 * @var string 30 */ 31 private $creator = 'Unknown Creator'; 32 33 /** 34 * LastModifiedBy. 35 * 36 * @var string 37 */ 38 private $lastModifiedBy; 39 40 /** 41 * Created. 42 * 43 * @var float|int 44 */ 45 private $created; 46 47 /** 48 * Modified. 49 * 50 * @var float|int 51 */ 52 private $modified; 53 54 /** 55 * Title. 56 * 57 * @var string 58 */ 59 private $title = 'Untitled Spreadsheet'; 60 61 /** 62 * Description. 63 * 64 * @var string 65 */ 66 private $description = ''; 67 68 /** 69 * Subject. 70 * 71 * @var string 72 */ 73 private $subject = ''; 74 75 /** 76 * Keywords. 77 * 78 * @var string 79 */ 80 private $keywords = ''; 81 82 /** 83 * Category. 84 * 85 * @var string 86 */ 87 private $category = ''; 88 89 /** 90 * Manager. 91 * 92 * @var string 93 */ 94 private $manager = ''; 95 96 /** 97 * Company. 98 * 99 * @var string 100 */ 101 private $company = ''; 102 103 /** 104 * Custom Properties. 105 * 106 * @var array{value: mixed, type: string}[] 107 */ 108 private $customProperties = []; 109 110 /** 111 * Create a new Document Properties instance. 112 */ 113 public function __construct() 114 { 115 // Initialise values 116 $this->lastModifiedBy = $this->creator; 117 $this->created = self::intOrFloatTimestamp(null); 118 $this->modified = $this->created; 119 } 120 121 /** 122 * Get Creator. 123 */ 124 public function getCreator(): string 125 { 126 return $this->creator; 127 } 128 129 /** 130 * Set Creator. 131 * 132 * @return $this 133 */ 134 public function setCreator(string $creator): self 135 { 136 $this->creator = $creator; 137 138 return $this; 139 } 140 141 /** 142 * Get Last Modified By. 143 */ 144 public function getLastModifiedBy(): string 145 { 146 return $this->lastModifiedBy; 147 } 148 149 /** 150 * Set Last Modified By. 151 * 152 * @return $this 153 */ 154 public function setLastModifiedBy(string $modifiedBy): self 155 { 156 $this->lastModifiedBy = $modifiedBy; 157 158 return $this; 159 } 160 161 /** 162 * @param null|float|int|string $timestamp 163 * 164 * @return float|int 165 */ 166 private static function intOrFloatTimestamp($timestamp) 167 { 168 if ($timestamp === null) { 169 $timestamp = (float) (new DateTime())->format('U'); 170 } elseif (is_string($timestamp)) { 171 if (is_numeric($timestamp)) { 172 $timestamp = (float) $timestamp; 173 } else { 174 $timestamp = (string) preg_replace('/[.][0-9]*$/', '', $timestamp); 175 $timestamp = (string) preg_replace('/^(\\d{4})- (\\d)/', '$1-0$2', $timestamp); 176 $timestamp = (string) preg_replace('/^(\\d{4}-\\d{2})- (\\d)/', '$1-0$2', $timestamp); 177 $timestamp = (float) (new DateTime($timestamp))->format('U'); 178 } 179 } 180 181 return IntOrFloat::evaluate($timestamp); 182 } 183 184 /** 185 * Get Created. 186 * 187 * @return float|int 188 */ 189 public function getCreated() 190 { 191 return $this->created; 192 } 193 194 /** 195 * Set Created. 196 * 197 * @param null|float|int|string $timestamp 198 * 199 * @return $this 200 */ 201 public function setCreated($timestamp): self 202 { 203 $this->created = self::intOrFloatTimestamp($timestamp); 204 205 return $this; 206 } 207 208 /** 209 * Get Modified. 210 * 211 * @return float|int 212 */ 213 public function getModified() 214 { 215 return $this->modified; 216 } 217 218 /** 219 * Set Modified. 220 * 221 * @param null|float|int|string $timestamp 222 * 223 * @return $this 224 */ 225 public function setModified($timestamp): self 226 { 227 $this->modified = self::intOrFloatTimestamp($timestamp); 228 229 return $this; 230 } 231 232 /** 233 * Get Title. 234 */ 235 public function getTitle(): string 236 { 237 return $this->title; 238 } 239 240 /** 241 * Set Title. 242 * 243 * @return $this 244 */ 245 public function setTitle(string $title): self 246 { 247 $this->title = $title; 248 249 return $this; 250 } 251 252 /** 253 * Get Description. 254 */ 255 public function getDescription(): string 256 { 257 return $this->description; 258 } 259 260 /** 261 * Set Description. 262 * 263 * @return $this 264 */ 265 public function setDescription(string $description): self 266 { 267 $this->description = $description; 268 269 return $this; 270 } 271 272 /** 273 * Get Subject. 274 */ 275 public function getSubject(): string 276 { 277 return $this->subject; 278 } 279 280 /** 281 * Set Subject. 282 * 283 * @return $this 284 */ 285 public function setSubject(string $subject): self 286 { 287 $this->subject = $subject; 288 289 return $this; 290 } 291 292 /** 293 * Get Keywords. 294 */ 295 public function getKeywords(): string 296 { 297 return $this->keywords; 298 } 299 300 /** 301 * Set Keywords. 302 * 303 * @return $this 304 */ 305 public function setKeywords(string $keywords): self 306 { 307 $this->keywords = $keywords; 308 309 return $this; 310 } 311 312 /** 313 * Get Category. 314 */ 315 public function getCategory(): string 316 { 317 return $this->category; 318 } 319 320 /** 321 * Set Category. 322 * 323 * @return $this 324 */ 325 public function setCategory(string $category): self 326 { 327 $this->category = $category; 328 329 return $this; 330 } 331 332 /** 333 * Get Company. 334 */ 335 public function getCompany(): string 336 { 337 return $this->company; 338 } 339 340 /** 341 * Set Company. 342 * 343 * @return $this 344 */ 345 public function setCompany(string $company): self 346 { 347 $this->company = $company; 348 349 return $this; 350 } 351 352 /** 353 * Get Manager. 354 */ 355 public function getManager(): string 356 { 357 return $this->manager; 358 } 359 360 /** 361 * Set Manager. 362 * 363 * @return $this 364 */ 365 public function setManager(string $manager): self 366 { 367 $this->manager = $manager; 368 369 return $this; 370 } 371 372 /** 373 * Get a List of Custom Property Names. 374 * 375 * @return string[] 376 */ 377 public function getCustomProperties(): array 378 { 379 return array_keys($this->customProperties); 380 } 381 382 /** 383 * Check if a Custom Property is defined. 384 */ 385 public function isCustomPropertySet(string $propertyName): bool 386 { 387 return array_key_exists($propertyName, $this->customProperties); 388 } 389 390 /** 391 * Get a Custom Property Value. 392 * 393 * @return mixed 394 */ 395 public function getCustomPropertyValue(string $propertyName) 396 { 397 if (isset($this->customProperties[$propertyName])) { 398 return $this->customProperties[$propertyName]['value']; 399 } 400 401 return null; 402 } 403 404 /** 405 * Get a Custom Property Type. 406 * 407 * @return null|string 408 */ 409 public function getCustomPropertyType(string $propertyName) 410 { 411 return $this->customProperties[$propertyName]['type'] ?? null; 412 } 413 414 /** 415 * @param mixed $propertyValue 416 */ 417 private function identifyPropertyType($propertyValue): string 418 { 419 if (is_float($propertyValue)) { 420 return self::PROPERTY_TYPE_FLOAT; 421 } 422 if (is_int($propertyValue)) { 423 return self::PROPERTY_TYPE_INTEGER; 424 } 425 if (is_bool($propertyValue)) { 426 return self::PROPERTY_TYPE_BOOLEAN; 427 } 428 429 return self::PROPERTY_TYPE_STRING; 430 } 431 432 /** 433 * Set a Custom Property. 434 * 435 * @param mixed $propertyValue 436 * @param string $propertyType 437 * 'i' : Integer 438 * 'f' : Floating Point 439 * 's' : String 440 * 'd' : Date/Time 441 * 'b' : Boolean 442 * 443 * @return $this 444 */ 445 public function setCustomProperty(string $propertyName, $propertyValue = '', $propertyType = null): self 446 { 447 if (($propertyType === null) || (!in_array($propertyType, self::VALID_PROPERTY_TYPE_LIST))) { 448 $propertyType = $this->identifyPropertyType($propertyValue); 449 } 450 451 if (!is_object($propertyValue)) { 452 $this->customProperties[$propertyName] = [ 453 'value' => self::convertProperty($propertyValue, $propertyType), 454 'type' => $propertyType, 455 ]; 456 } 457 458 return $this; 459 } 460 461 private const PROPERTY_TYPE_ARRAY = [ 462 'i' => self::PROPERTY_TYPE_INTEGER, // Integer 463 'i1' => self::PROPERTY_TYPE_INTEGER, // 1-Byte Signed Integer 464 'i2' => self::PROPERTY_TYPE_INTEGER, // 2-Byte Signed Integer 465 'i4' => self::PROPERTY_TYPE_INTEGER, // 4-Byte Signed Integer 466 'i8' => self::PROPERTY_TYPE_INTEGER, // 8-Byte Signed Integer 467 'int' => self::PROPERTY_TYPE_INTEGER, // Integer 468 'ui1' => self::PROPERTY_TYPE_INTEGER, // 1-Byte Unsigned Integer 469 'ui2' => self::PROPERTY_TYPE_INTEGER, // 2-Byte Unsigned Integer 470 'ui4' => self::PROPERTY_TYPE_INTEGER, // 4-Byte Unsigned Integer 471 'ui8' => self::PROPERTY_TYPE_INTEGER, // 8-Byte Unsigned Integer 472 'uint' => self::PROPERTY_TYPE_INTEGER, // Unsigned Integer 473 'f' => self::PROPERTY_TYPE_FLOAT, // Real Number 474 'r4' => self::PROPERTY_TYPE_FLOAT, // 4-Byte Real Number 475 'r8' => self::PROPERTY_TYPE_FLOAT, // 8-Byte Real Number 476 'decimal' => self::PROPERTY_TYPE_FLOAT, // Decimal 477 's' => self::PROPERTY_TYPE_STRING, // String 478 'empty' => self::PROPERTY_TYPE_STRING, // Empty 479 'null' => self::PROPERTY_TYPE_STRING, // Null 480 'lpstr' => self::PROPERTY_TYPE_STRING, // LPSTR 481 'lpwstr' => self::PROPERTY_TYPE_STRING, // LPWSTR 482 'bstr' => self::PROPERTY_TYPE_STRING, // Basic String 483 'd' => self::PROPERTY_TYPE_DATE, // Date and Time 484 'date' => self::PROPERTY_TYPE_DATE, // Date and Time 485 'filetime' => self::PROPERTY_TYPE_DATE, // File Time 486 'b' => self::PROPERTY_TYPE_BOOLEAN, // Boolean 487 'bool' => self::PROPERTY_TYPE_BOOLEAN, // Boolean 488 ]; 489 490 private const SPECIAL_TYPES = [ 491 'empty' => '', 492 'null' => null, 493 ]; 494 495 /** 496 * Convert property to form desired by Excel. 497 * 498 * @param mixed $propertyValue 499 * 500 * @return mixed 501 */ 502 public static function convertProperty($propertyValue, string $propertyType) 503 { 504 return self::SPECIAL_TYPES[$propertyType] ?? self::convertProperty2($propertyValue, $propertyType); 505 } 506 507 /** 508 * Convert property to form desired by Excel. 509 * 510 * @param mixed $propertyValue 511 * 512 * @return mixed 513 */ 514 private static function convertProperty2($propertyValue, string $type) 515 { 516 $propertyType = self::convertPropertyType($type); 517 switch ($propertyType) { 518 case self::PROPERTY_TYPE_INTEGER: 519 $intValue = (int) $propertyValue; 520 521 return ($type[0] === 'u') ? abs($intValue) : $intValue; 522 case self::PROPERTY_TYPE_FLOAT: 523 return (float) $propertyValue; 524 case self::PROPERTY_TYPE_DATE: 525 return self::intOrFloatTimestamp($propertyValue); 526 case self::PROPERTY_TYPE_BOOLEAN: 527 return is_bool($propertyValue) ? $propertyValue : ($propertyValue === 'true'); 528 default: // includes string 529 return $propertyValue; 530 } 531 } 532 533 public static function convertPropertyType(string $propertyType): string 534 { 535 return self::PROPERTY_TYPE_ARRAY[$propertyType] ?? self::PROPERTY_TYPE_UNKNOWN; 536 } 537 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body