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