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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 Properties
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 string
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 Properties
457     */
458    public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
459    {
460        if (($propertyType === null) || (!in_array($propertyType, [self::PROPERTY_TYPE_INTEGER,
461                                                                        self::PROPERTY_TYPE_FLOAT,
462                                                                        self::PROPERTY_TYPE_STRING,
463                                                                        self::PROPERTY_TYPE_DATE,
464                                                                        self::PROPERTY_TYPE_BOOLEAN, ]))) {
465            if ($propertyValue === null) {
466                $propertyType = self::PROPERTY_TYPE_STRING;
467            } elseif (is_float($propertyValue)) {
468                $propertyType = self::PROPERTY_TYPE_FLOAT;
469            } elseif (is_int($propertyValue)) {
470                $propertyType = self::PROPERTY_TYPE_INTEGER;
471            } elseif (is_bool($propertyValue)) {
472                $propertyType = self::PROPERTY_TYPE_BOOLEAN;
473            } else {
474                $propertyType = self::PROPERTY_TYPE_STRING;
475            }
476        }
477
478        $this->customProperties[$propertyName] = [
479            'value' => $propertyValue,
480            'type' => $propertyType,
481        ];
482
483        return $this;
484    }
485
486    /**
487     * Implement PHP __clone to create a deep clone, not just a shallow copy.
488     */
489    public function __clone()
490    {
491        $vars = get_object_vars($this);
492        foreach ($vars as $key => $value) {
493            if (is_object($value)) {
494                $this->$key = clone $value;
495            } else {
496                $this->$key = $value;
497            }
498        }
499    }
500
501    public static function convertProperty($propertyValue, $propertyType)
502    {
503        switch ($propertyType) {
504            case 'empty':     //    Empty
505                return '';
506
507                break;
508            case 'null':      //    Null
509                return null;
510
511                break;
512            case 'i1':        //    1-Byte Signed Integer
513            case 'i2':        //    2-Byte Signed Integer
514            case 'i4':        //    4-Byte Signed Integer
515            case 'i8':        //    8-Byte Signed Integer
516            case 'int':       //    Integer
517                return (int) $propertyValue;
518
519                break;
520            case 'ui1':       //    1-Byte Unsigned Integer
521            case 'ui2':       //    2-Byte Unsigned Integer
522            case 'ui4':       //    4-Byte Unsigned Integer
523            case 'ui8':       //    8-Byte Unsigned Integer
524            case 'uint':      //    Unsigned Integer
525                return abs((int) $propertyValue);
526
527                break;
528            case 'r4':        //    4-Byte Real Number
529            case 'r8':        //    8-Byte Real Number
530            case 'decimal':   //    Decimal
531                return (float) $propertyValue;
532
533                break;
534            case 'lpstr':     //    LPSTR
535            case 'lpwstr':    //    LPWSTR
536            case 'bstr':      //    Basic String
537                return $propertyValue;
538
539                break;
540            case 'date':      //    Date and Time
541            case 'filetime':  //    File Time
542                return strtotime($propertyValue);
543
544                break;
545            case 'bool':     //    Boolean
546                return $propertyValue == 'true';
547
548                break;
549            case 'cy':       //    Currency
550            case 'error':    //    Error Status Code
551            case 'vector':   //    Vector
552            case 'array':    //    Array
553            case 'blob':     //    Binary Blob
554            case 'oblob':    //    Binary Blob Object
555            case 'stream':   //    Binary Stream
556            case 'ostream':  //    Binary Stream Object
557            case 'storage':  //    Binary Storage
558            case 'ostorage': //    Binary Storage Object
559            case 'vstream':  //    Binary Versioned Stream
560            case 'clsid':    //    Class ID
561            case 'cf':       //    Clipboard Data
562                return $propertyValue;
563
564                break;
565        }
566
567        return $propertyValue;
568    }
569
570    public static function convertPropertyType($propertyType)
571    {
572        switch ($propertyType) {
573            case 'i1':       //    1-Byte Signed Integer
574            case 'i2':       //    2-Byte Signed Integer
575            case 'i4':       //    4-Byte Signed Integer
576            case 'i8':       //    8-Byte Signed Integer
577            case 'int':      //    Integer
578            case 'ui1':      //    1-Byte Unsigned Integer
579            case 'ui2':      //    2-Byte Unsigned Integer
580            case 'ui4':      //    4-Byte Unsigned Integer
581            case 'ui8':      //    8-Byte Unsigned Integer
582            case 'uint':     //    Unsigned Integer
583                return self::PROPERTY_TYPE_INTEGER;
584
585                break;
586            case 'r4':       //    4-Byte Real Number
587            case 'r8':       //    8-Byte Real Number
588            case 'decimal':  //    Decimal
589                return self::PROPERTY_TYPE_FLOAT;
590
591                break;
592            case 'empty':    //    Empty
593            case 'null':     //    Null
594            case 'lpstr':    //    LPSTR
595            case 'lpwstr':   //    LPWSTR
596            case 'bstr':     //    Basic String
597                return self::PROPERTY_TYPE_STRING;
598
599                break;
600            case 'date':     //    Date and Time
601            case 'filetime': //    File Time
602                return self::PROPERTY_TYPE_DATE;
603
604                break;
605            case 'bool':     //    Boolean
606                return self::PROPERTY_TYPE_BOOLEAN;
607
608                break;
609            case 'cy':       //    Currency
610            case 'error':    //    Error Status Code
611            case 'vector':   //    Vector
612            case 'array':    //    Array
613            case 'blob':     //    Binary Blob
614            case 'oblob':    //    Binary Blob Object
615            case 'stream':   //    Binary Stream
616            case 'ostream':  //    Binary Stream Object
617            case 'storage':  //    Binary Storage
618            case 'ostorage': //    Binary Storage Object
619            case 'vstream':  //    Binary Versioned Stream
620            case 'clsid':    //    Class ID
621            case 'cf':       //    Clipboard Data
622                return self::PROPERTY_TYPE_UNKNOWN;
623
624                break;
625        }
626
627        return self::PROPERTY_TYPE_UNKNOWN;
628    }
629}
630