PageRenderTime 46ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php

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