Completed
Pull Request — authpdo (#1572)
by
unknown
04:27
created

JpegMeta::getDates()   F

Complexity

Conditions 28
Paths 3127

Size

Total Lines 130
Code Lines 88

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 130
rs 2
cc 28
eloc 88
nc 3127
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * JPEG metadata reader/writer
4
 *
5
 * @license    BSD <http://www.opensource.org/licenses/bsd-license.php>
6
 * @link       http://github.com/sd/jpeg-php
7
 * @author     Sebastian Delmont <[email protected]>
8
 * @author     Andreas Gohr <[email protected]>
9
 * @author     Hakan Sandell <[email protected]>
10
 * @todo       Add support for Maker Notes, Extend for GIF and PNG metadata
11
 */
12
13
// Original copyright notice:
14
//
15
// Copyright (c) 2003 Sebastian Delmont <[email protected]>
16
// All rights reserved.
17
//
18
// Redistribution and use in source and binary forms, with or without
19
// modification, are permitted provided that the following conditions
20
// are met:
21
// 1. Redistributions of source code must retain the above copyright
22
//    notice, this list of conditions and the following disclaimer.
23
// 2. Redistributions in binary form must reproduce the above copyright
24
//    notice, this list of conditions and the following disclaimer in the
25
//    documentation and/or other materials provided with the distribution.
26
// 3. Neither the name of the author nor the names of its contributors
27
//    may be used to endorse or promote products derived from this software
28
//    without specific prior written permission.
29
//
30
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
31
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
33
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
36
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
37
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
38
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
39
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
41
42
class JpegMeta {
43
    var $_fileName;
44
    var $_fp = null;
45
    var $_fpout = null;
46
    var $_type = 'unknown';
47
48
    var $_markers;
49
    var $_info;
50
51
52
    /**
53
     * Constructor
54
     *
55
     * @author Sebastian Delmont <[email protected]>
56
     */
57
    function __construct($fileName) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
58
59
        $this->_fileName = $fileName;
60
61
        $this->_fp = null;
62
        $this->_type = 'unknown';
63
64
        unset($this->_info);
65
        unset($this->_markers);
66
    }
67
68
    /**
69
     * Returns all gathered info as multidim array
70
     *
71
     * @author Sebastian Delmont <[email protected]>
72
     */
73
    function & getRawInfo() {
74
        $this->_parseAll();
75
76
        if ($this->_markers == null) {
77
            return false;
78
        }
79
80
        return $this->_info;
81
    }
82
83
    /**
84
     * Returns basic image info
85
     *
86
     * @author Sebastian Delmont <[email protected]>
87
     */
88
    function & getBasicInfo() {
89
        $this->_parseAll();
90
91
        $info = array();
92
93
        if ($this->_markers == null) {
94
            return false;
95
        }
96
97
        $info['Name'] = $this->_info['file']['Name'];
98
        if (isset($this->_info['file']['Url'])) {
99
            $info['Url'] = $this->_info['file']['Url'];
100
            $info['NiceSize'] = "???KB";
101
        } else {
102
            $info['Size'] = $this->_info['file']['Size'];
103
            $info['NiceSize'] = $this->_info['file']['NiceSize'];
104
        }
105
106
        if (@isset($this->_info['sof']['Format'])) {
107
            $info['Format'] = $this->_info['sof']['Format'] . " JPEG";
108
        } else {
109
            $info['Format'] = $this->_info['sof']['Format'] . " JPEG";
110
        }
111
112
        if (@isset($this->_info['sof']['ColorChannels'])) {
113
            $info['ColorMode'] = ($this->_info['sof']['ColorChannels'] > 1) ? "Color" : "B&W";
114
        }
115
116
        $info['Width'] = $this->getWidth();
117
        $info['Height'] = $this->getHeight();
118
        $info['DimStr'] = $this->getDimStr();
119
120
        $dates = $this->getDates();
121
122
        $info['DateTime'] = $dates['EarliestTime'];
123
        $info['DateTimeStr'] = $dates['EarliestTimeStr'];
124
125
        $info['HasThumbnail'] = $this->hasThumbnail();
126
127
        return $info;
128
    }
129
130
131
    /**
132
     * Convinience function to access nearly all available Data
133
     * through one function
134
     *
135
     * @author Andreas Gohr <[email protected]>
136
     *
137
     * @param array|string $fields field name or array with field names
138
     * @return bool|string
139
     */
140
    function getField($fields) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
141
        if(!is_array($fields)) $fields = array($fields);
142
        $info = false;
143
        foreach($fields as $field){
144
            if(strtolower(substr($field,0,5)) == 'iptc.'){
145
                $info = $this->getIPTCField(substr($field,5));
146
            }elseif(strtolower(substr($field,0,5)) == 'exif.'){
147
                $info = $this->getExifField(substr($field,5));
148
            }elseif(strtolower(substr($field,0,4)) == 'xmp.'){
149
                $info = $this->getXmpField(substr($field,4));
150
            }elseif(strtolower(substr($field,0,5)) == 'file.'){
151
                $info = $this->getFileField(substr($field,5));
152
            }elseif(strtolower(substr($field,0,5)) == 'date.'){
153
                $info = $this->getDateField(substr($field,5));
154
            }elseif(strtolower($field) == 'simple.camera'){
155
                $info = $this->getCamera();
156
            }elseif(strtolower($field) == 'simple.raw'){
157
                return $this->getRawInfo();
158
            }elseif(strtolower($field) == 'simple.title'){
159
                $info = $this->getTitle();
160
            }elseif(strtolower($field) == 'simple.shutterspeed'){
161
                $info = $this->getShutterSpeed();
162
            }else{
163
                $info = $this->getExifField($field);
164
            }
165
            if($info != false) break;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $info of type false|string|array against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
166
        }
167
168
        if($info === false)  $info = '';
169
        if(is_array($info)){
170
            if(isset($info['val'])){
171
                $info = $info['val'];
172
            }else{
173
                $info = join(', ',$info);
174
            }
175
        }
176
        return trim($info);
177
    }
178
179
    /**
180
     * Convinience function to set nearly all available Data
181
     * through one function
182
     *
183
     * @author Andreas Gohr <[email protected]>
184
     *
185
     * @param string $field field name
186
     * @param string $value
187
     * @return bool success or fail
188
     */
189
    function setField($field, $value) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
190
        if(strtolower(substr($field,0,5)) == 'iptc.'){
191
            return $this->setIPTCField(substr($field,5),$value);
192
        }elseif(strtolower(substr($field,0,5)) == 'exif.'){
193
            return $this->setExifField(substr($field,5),$value);
194
        }else{
195
            return $this->setExifField($field,$value);
196
        }
197
    }
198
199
    /**
200
     * Convinience function to delete nearly all available Data
201
     * through one function
202
     *
203
     * @author Andreas Gohr <[email protected]>
204
     *
205
     * @param string $field field name
206
     * @return bool
207
     */
208
    function deleteField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
209
        if(strtolower(substr($field,0,5)) == 'iptc.'){
210
            return $this->deleteIPTCField(substr($field,5));
211
        }elseif(strtolower(substr($field,0,5)) == 'exif.'){
212
            return $this->deleteExifField(substr($field,5));
213
        }else{
214
            return $this->deleteExifField($field);
215
        }
216
    }
217
218
    /**
219
     * Return a date field
220
     *
221
     * @author Andreas Gohr <[email protected]>
222
     *
223
     * @param string $field
224
     * @return false|string
225
     */
226
    function getDateField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
227
        if (!isset($this->_info['dates'])) {
228
            $this->_info['dates'] = $this->getDates();
229
        }
230
231
        if (isset($this->_info['dates'][$field])) {
232
            return $this->_info['dates'][$field];
233
        }
234
235
        return false;
236
    }
237
238
    /**
239
     * Return a file info field
240
     *
241
     * @author Andreas Gohr <[email protected]>
242
     *
243
     * @param string $field field name
244
     * @return false|string
245
     */
246
    function getFileField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
247
        if (!isset($this->_info['file'])) {
248
            $this->_parseFileInfo();
249
        }
250
251
        if (isset($this->_info['file'][$field])) {
252
            return $this->_info['file'][$field];
253
        }
254
255
        return false;
256
    }
257
258
    /**
259
     * Return the camera info (Maker and Model)
260
     *
261
     * @author Andreas Gohr <[email protected]>
262
     * @todo   handle makernotes
263
     *
264
     * @return false|string
265
     */
266
    function getCamera(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
267
        $make  = $this->getField(array('Exif.Make','Exif.TIFFMake'));
268
        $model = $this->getField(array('Exif.Model','Exif.TIFFModel'));
269
        $cam = trim("$make $model");
270
        if(empty($cam)) return false;
271
        return $cam;
272
    }
273
274
    /**
275
     * Return shutter speed as a ratio
276
     *
277
     * @author Joe Lapp <[email protected]>
278
     *
279
     * @return string
280
     */
281
    function getShutterSpeed() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
282
        if (!isset($this->_info['exif'])) {
283
            $this->_parseMarkerExif();
284
        }
285
        if(!isset($this->_info['exif']['ExposureTime'])){
286
            return '';
287
        }
288
289
        $field = $this->_info['exif']['ExposureTime'];
290
        if($field['den'] == 1) return $field['num'];
291
        return $field['num'].'/'.$field['den'];
292
    }
293
294
    /**
295
     * Return an EXIF field
296
     *
297
     * @author Sebastian Delmont <[email protected]>
298
     *
299
     * @param string $field field name
300
     * @return false|string
301
     */
302
    function getExifField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
303
        if (!isset($this->_info['exif'])) {
304
            $this->_parseMarkerExif();
305
        }
306
307
        if ($this->_markers == null) {
308
            return false;
309
        }
310
311
        if (isset($this->_info['exif'][$field])) {
312
            return $this->_info['exif'][$field];
313
        }
314
315
        return false;
316
    }
317
318
    /**
319
     * Return an XMP field
320
     *
321
     * @author Hakan Sandell <[email protected]>
322
     *
323
     * @param string $field field name
324
     * @return false|string
325
     */
326
    function getXmpField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
327
        if (!isset($this->_info['xmp'])) {
328
            $this->_parseMarkerXmp();
329
        }
330
331
        if ($this->_markers == null) {
332
            return false;
333
        }
334
335
        if (isset($this->_info['xmp'][$field])) {
336
            return $this->_info['xmp'][$field];
337
        }
338
339
        return false;
340
    }
341
342
    /**
343
     * Return an Adobe Field
344
     *
345
     * @author Sebastian Delmont <[email protected]>
346
     *
347
     * @param string $field field name
348
     * @return false|string
349
     */
350
    function getAdobeField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
351
        if (!isset($this->_info['adobe'])) {
352
            $this->_parseMarkerAdobe();
353
        }
354
355
        if ($this->_markers == null) {
356
            return false;
357
        }
358
359
        if (isset($this->_info['adobe'][$field])) {
360
            return $this->_info['adobe'][$field];
361
        }
362
363
        return false;
364
    }
365
366
    /**
367
     * Return an IPTC field
368
     *
369
     * @author Sebastian Delmont <[email protected]>
370
     *
371
     * @param string $field field name
372
     * @return false|string
373
     */
374
    function getIPTCField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
375
        if (!isset($this->_info['iptc'])) {
376
            $this->_parseMarkerAdobe();
377
        }
378
379
        if ($this->_markers == null) {
380
            return false;
381
        }
382
383
        if (isset($this->_info['iptc'][$field])) {
384
            return $this->_info['iptc'][$field];
385
        }
386
387
        return false;
388
    }
389
390
    /**
391
     * Set an EXIF field
392
     *
393
     * @author Sebastian Delmont <[email protected]>
394
     * @author Joe Lapp <[email protected]>
395
     *
396
     * @param string $field field name
397
     * @param string $value
398
     * @return bool
399
     */
400
    function setExifField($field, $value) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
401
        if (!isset($this->_info['exif'])) {
402
            $this->_parseMarkerExif();
403
        }
404
405
        if ($this->_markers == null) {
406
            return false;
407
        }
408
409
        if ($this->_info['exif'] == false) {
410
            $this->_info['exif'] = array();
411
        }
412
413
        // make sure datetimes are in correct format
414
        if(strlen($field) >= 8 && strtolower(substr($field, 0, 8)) == 'datetime') {
415
            if(strlen($value) < 8 || $value{4} != ':' || $value{7} != ':') {
416
                $value = date('Y:m:d H:i:s', strtotime($value));
417
            }
418
        }
419
420
        $this->_info['exif'][$field] = $value;
421
422
        return true;
423
    }
424
425
    /**
426
     * Set an Adobe Field
427
     *
428
     * @author Sebastian Delmont <[email protected]>
429
     *
430
     * @param string $field field name
431
     * @param string $value
432
     * @return bool
433
     */
434
    function setAdobeField($field, $value) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
435
        if (!isset($this->_info['adobe'])) {
436
            $this->_parseMarkerAdobe();
437
        }
438
439
        if ($this->_markers == null) {
440
            return false;
441
        }
442
443
        if ($this->_info['adobe'] == false) {
444
            $this->_info['adobe'] = array();
445
        }
446
447
        $this->_info['adobe'][$field] = $value;
448
449
        return true;
450
    }
451
452
    /**
453
     * Calculates the multiplier needed to resize the image to the given
454
     * dimensions
455
     *
456
     * @author Andreas Gohr <[email protected]>
457
     *
458
     * @param int $maxwidth
459
     * @param int $maxheight
460
     * @return float|int
461
     */
462
    function getResizeRatio($maxwidth,$maxheight=0){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
463
        if(!$maxheight) $maxheight = $maxwidth;
464
465
        $w = $this->getField('File.Width');
466
        $h = $this->getField('File.Height');
467
468
        $ratio = 1;
469
        if($w >= $h){
470
            if($w >= $maxwidth){
471
                $ratio = $maxwidth/$w;
472
            }elseif($h > $maxheight){
473
                $ratio = $maxheight/$h;
474
            }
475
        }else{
476
            if($h >= $maxheight){
477
                $ratio = $maxheight/$h;
478
            }elseif($w > $maxwidth){
479
                $ratio = $maxwidth/$w;
480
            }
481
        }
482
        return $ratio;
483
    }
484
485
486
    /**
487
     * Set an IPTC field
488
     *
489
     * @author Sebastian Delmont <[email protected]>
490
     *
491
     * @param string $field field name
492
     * @param string $value
493
     * @return bool
494
     */
495
    function setIPTCField($field, $value) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
496
        if (!isset($this->_info['iptc'])) {
497
            $this->_parseMarkerAdobe();
498
        }
499
500
        if ($this->_markers == null) {
501
            return false;
502
        }
503
504
        if ($this->_info['iptc'] == false) {
505
            $this->_info['iptc'] = array();
506
        }
507
508
        $this->_info['iptc'][$field] = $value;
509
510
        return true;
511
    }
512
513
    /**
514
     * Delete an EXIF field
515
     *
516
     * @author Sebastian Delmont <[email protected]>
517
     *
518
     * @param string $field field name
519
     * @return bool
520
     */
521
    function deleteExifField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
522
        if (!isset($this->_info['exif'])) {
523
            $this->_parseMarkerAdobe();
524
        }
525
526
        if ($this->_markers == null) {
527
            return false;
528
        }
529
530
        if ($this->_info['exif'] != false) {
531
            unset($this->_info['exif'][$field]);
532
        }
533
534
        return true;
535
    }
536
537
    /**
538
     * Delete an Adobe field
539
     *
540
     * @author Sebastian Delmont <[email protected]>
541
     *
542
     * @param string $field field name
543
     * @return bool
544
     */
545
    function deleteAdobeField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
546
        if (!isset($this->_info['adobe'])) {
547
            $this->_parseMarkerAdobe();
548
        }
549
550
        if ($this->_markers == null) {
551
            return false;
552
        }
553
554
        if ($this->_info['adobe'] != false) {
555
            unset($this->_info['adobe'][$field]);
556
        }
557
558
        return true;
559
    }
560
561
    /**
562
     * Delete an IPTC field
563
     *
564
     * @author Sebastian Delmont <[email protected]>
565
     *
566
     * @param string $field field name
567
     * @return bool
568
     */
569
    function deleteIPTCField($field) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
570
        if (!isset($this->_info['iptc'])) {
571
            $this->_parseMarkerAdobe();
572
        }
573
574
        if ($this->_markers == null) {
575
            return false;
576
        }
577
578
        if ($this->_info['iptc'] != false) {
579
            unset($this->_info['iptc'][$field]);
580
        }
581
582
        return true;
583
    }
584
585
    /**
586
     * Get the image's title, tries various fields
587
     *
588
     * @param int $max maximum number chars (keeps words)
589
     * @return false|string
590
     *
591
     * @author Andreas Gohr <[email protected]>
592
     */
593
    function getTitle($max=80){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
594
        // try various fields
595
        $cap = $this->getField(array('Iptc.Headline',
596
                    'Iptc.Caption',
597
                    'Xmp.dc:title',
598
                    'Exif.UserComment',
599
                    'Exif.TIFFUserComment',
600
                    'Exif.TIFFImageDescription',
601
                    'File.Name'));
602
        if (empty($cap)) return false;
603
604
        if(!$max) return $cap;
605
        // Shorten to 80 chars (keeping words)
606
        $new = preg_replace('/\n.+$/','',wordwrap($cap, $max));
607
        if($new != $cap) $new .= '...';
608
609
        return $new;
610
    }
611
612
    /**
613
     * Gather various date fields
614
     *
615
     * @author Sebastian Delmont <[email protected]>
616
     *
617
     * @return array|bool
618
     */
619
    function getDates() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
620
        $this->_parseAll();
621
        if ($this->_markers == null) {
622
            if (@isset($this->_info['file']['UnixTime'])) {
623
                $dates = array();
624
                $dates['FileModified'] = $this->_info['file']['UnixTime'];
625
                $dates['Time'] = $this->_info['file']['UnixTime'];
626
                $dates['TimeSource'] = 'FileModified';
627
                $dates['TimeStr'] = date("Y-m-d H:i:s", $this->_info['file']['UnixTime']);
628
                $dates['EarliestTime'] = $this->_info['file']['UnixTime'];
629
                $dates['EarliestTimeSource'] = 'FileModified';
630
                $dates['EarliestTimeStr'] = date("Y-m-d H:i:s", $this->_info['file']['UnixTime']);
631
                $dates['LatestTime'] = $this->_info['file']['UnixTime'];
632
                $dates['LatestTimeSource'] = 'FileModified';
633
                $dates['LatestTimeStr'] = date("Y-m-d H:i:s", $this->_info['file']['UnixTime']);
634
                return $dates;
635
            }
636
            return false;
637
        }
638
639
        $dates = array();
640
641
        $latestTime = 0;
642
        $latestTimeSource = "";
643
        $earliestTime = time();
644
        $earliestTimeSource = "";
645
646
        if (@isset($this->_info['exif']['DateTime'])) {
647
            $dates['ExifDateTime'] = $this->_info['exif']['DateTime'];
648
649
            $aux = $this->_info['exif']['DateTime'];
650
            $aux{4} = "-";
651
            $aux{7} = "-";
652
            $t = strtotime($aux);
653
654
            if ($t && $t > $latestTime) {
655
                $latestTime = $t;
656
                $latestTimeSource = "ExifDateTime";
657
            }
658
659
            if ($t && $t < $earliestTime) {
660
                $earliestTime = $t;
661
                $earliestTimeSource = "ExifDateTime";
662
            }
663
        }
664
665
        if (@isset($this->_info['exif']['DateTimeOriginal'])) {
666
            $dates['ExifDateTimeOriginal'] = $this->_info['exif']['DateTime'];
667
668
            $aux = $this->_info['exif']['DateTimeOriginal'];
669
            $aux{4} = "-";
670
            $aux{7} = "-";
671
            $t = strtotime($aux);
672
673
            if ($t && $t > $latestTime) {
674
                $latestTime = $t;
675
                $latestTimeSource = "ExifDateTimeOriginal";
676
            }
677
678
            if ($t && $t < $earliestTime) {
679
                $earliestTime = $t;
680
                $earliestTimeSource = "ExifDateTimeOriginal";
681
            }
682
        }
683
684
        if (@isset($this->_info['exif']['DateTimeDigitized'])) {
685
            $dates['ExifDateTimeDigitized'] = $this->_info['exif']['DateTime'];
686
687
            $aux = $this->_info['exif']['DateTimeDigitized'];
688
            $aux{4} = "-";
689
            $aux{7} = "-";
690
            $t = strtotime($aux);
691
692
            if ($t && $t > $latestTime) {
693
                $latestTime = $t;
694
                $latestTimeSource = "ExifDateTimeDigitized";
695
            }
696
697
            if ($t && $t < $earliestTime) {
698
                $earliestTime = $t;
699
                $earliestTimeSource = "ExifDateTimeDigitized";
700
            }
701
        }
702
703
        if (@isset($this->_info['iptc']['DateCreated'])) {
704
            $dates['IPTCDateCreated'] = $this->_info['iptc']['DateCreated'];
705
706
            $aux = $this->_info['iptc']['DateCreated'];
707
            $aux = substr($aux, 0, 4) . "-" . substr($aux, 4, 2) . "-" . substr($aux, 6, 2);
708
            $t = strtotime($aux);
709
710
            if ($t && $t > $latestTime) {
711
                $latestTime = $t;
712
                $latestTimeSource = "IPTCDateCreated";
713
            }
714
715
            if ($t && $t < $earliestTime) {
716
                $earliestTime = $t;
717
                $earliestTimeSource = "IPTCDateCreated";
718
            }
719
        }
720
721
        if (@isset($this->_info['file']['UnixTime'])) {
722
            $dates['FileModified'] = $this->_info['file']['UnixTime'];
723
724
            $t = $this->_info['file']['UnixTime'];
725
726
            if ($t && $t > $latestTime) {
727
                $latestTime = $t;
728
                $latestTimeSource = "FileModified";
729
            }
730
731
            if ($t && $t < $earliestTime) {
732
                $earliestTime = $t;
733
                $earliestTimeSource = "FileModified";
734
            }
735
        }
736
737
        $dates['Time'] = $earliestTime;
738
        $dates['TimeSource'] = $earliestTimeSource;
739
        $dates['TimeStr'] = date("Y-m-d H:i:s", $earliestTime);
740
        $dates['EarliestTime'] = $earliestTime;
741
        $dates['EarliestTimeSource'] = $earliestTimeSource;
742
        $dates['EarliestTimeStr'] = date("Y-m-d H:i:s", $earliestTime);
743
        $dates['LatestTime'] = $latestTime;
744
        $dates['LatestTimeSource'] = $latestTimeSource;
745
        $dates['LatestTimeStr'] = date("Y-m-d H:i:s", $latestTime);
746
747
        return $dates;
748
    }
749
750
    /**
751
     * Get the image width, tries various fields
752
     *
753
     * @author Sebastian Delmont <[email protected]>
754
     *
755
     * @return false|string
756
     */
757
    function getWidth() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
758
        if (!isset($this->_info['sof'])) {
759
            $this->_parseMarkerSOF();
760
        }
761
762
        if ($this->_markers == null) {
763
            return false;
764
        }
765
766
        if (isset($this->_info['sof']['ImageWidth'])) {
767
            return $this->_info['sof']['ImageWidth'];
768
        }
769
770
        if (!isset($this->_info['exif'])) {
771
            $this->_parseMarkerExif();
772
        }
773
774
        if (isset($this->_info['exif']['PixelXDimension'])) {
775
            return $this->_info['exif']['PixelXDimension'];
776
        }
777
778
        return false;
779
    }
780
781
    /**
782
     * Get the image height, tries various fields
783
     *
784
     * @author Sebastian Delmont <[email protected]>
785
     *
786
     * @return false|string
787
     */
788
    function getHeight() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
789
        if (!isset($this->_info['sof'])) {
790
            $this->_parseMarkerSOF();
791
        }
792
793
        if ($this->_markers == null) {
794
            return false;
795
        }
796
797
        if (isset($this->_info['sof']['ImageHeight'])) {
798
            return $this->_info['sof']['ImageHeight'];
799
        }
800
801
        if (!isset($this->_info['exif'])) {
802
            $this->_parseMarkerExif();
803
        }
804
805
        if (isset($this->_info['exif']['PixelYDimension'])) {
806
            return $this->_info['exif']['PixelYDimension'];
807
        }
808
809
        return false;
810
    }
811
812
    /**
813
     * Get an dimension string for use in img tag
814
     *
815
     * @author Sebastian Delmont <[email protected]>
816
     *
817
     * @return false|string
818
     */
819
    function getDimStr() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
820
        if ($this->_markers == null) {
821
            return false;
822
        }
823
824
        $w = $this->getWidth();
825
        $h = $this->getHeight();
826
827
        return "width='" . $w . "' height='" . $h . "'";
828
    }
829
830
    /**
831
     * Checks for an embedded thumbnail
832
     *
833
     * @author Sebastian Delmont <[email protected]>
834
     *
835
     * @param string $which possible values: 'any', 'exif' or 'adobe'
836
     * @return false|string
837
     */
838
    function hasThumbnail($which = 'any') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
839
        if (($which == 'any') || ($which == 'exif')) {
840
            if (!isset($this->_info['exif'])) {
841
                $this->_parseMarkerExif();
842
            }
843
844
            if ($this->_markers == null) {
845
                return false;
846
            }
847
848
            if (isset($this->_info['exif']) && is_array($this->_info['exif'])) {
849
                if (isset($this->_info['exif']['JFIFThumbnail'])) {
850
                    return 'exif';
851
                }
852
            }
853
        }
854
855
        if ($which == 'adobe') {
856
            if (!isset($this->_info['adobe'])) {
857
                $this->_parseMarkerAdobe();
858
            }
859
860
            if ($this->_markers == null) {
861
                return false;
862
            }
863
864
            if (isset($this->_info['adobe']) && is_array($this->_info['adobe'])) {
865
                if (isset($this->_info['adobe']['ThumbnailData'])) {
866
                    return 'exif';
867
                }
868
            }
869
        }
870
871
        return false;
872
    }
873
874
    /**
875
     * Send embedded thumbnail to browser
876
     *
877
     * @author Sebastian Delmont <[email protected]>
878
     *
879
     * @param string $which possible values: 'any', 'exif' or 'adobe'
880
     * @return bool
881
     */
882
    function sendThumbnail($which = 'any') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
883
        $data = null;
884
885
        if (($which == 'any') || ($which == 'exif')) {
886
            if (!isset($this->_info['exif'])) {
887
                $this->_parseMarkerExif();
888
            }
889
890
            if ($this->_markers == null) {
891
                return false;
892
            }
893
894
            if (isset($this->_info['exif']) && is_array($this->_info['exif'])) {
895
                if (isset($this->_info['exif']['JFIFThumbnail'])) {
896
                    $data =& $this->_info['exif']['JFIFThumbnail'];
897
                }
898
            }
899
        }
900
901
        if (($which == 'adobe') || ($data == null)){
902
            if (!isset($this->_info['adobe'])) {
903
                $this->_parseMarkerAdobe();
904
            }
905
906
            if ($this->_markers == null) {
907
                return false;
908
            }
909
910
            if (isset($this->_info['adobe']) && is_array($this->_info['adobe'])) {
911
                if (isset($this->_info['adobe']['ThumbnailData'])) {
912
                    $data =& $this->_info['adobe']['ThumbnailData'];
913
                }
914
            }
915
        }
916
917
        if ($data != null) {
918
            header("Content-type: image/jpeg");
919
            echo $data;
920
            return true;
921
        }
922
923
        return false;
924
    }
925
926
    /**
927
     * Save changed Metadata
928
     *
929
     * @author Sebastian Delmont <[email protected]>
930
     * @author Andreas Gohr <[email protected]>
931
     *
932
     * @param string $fileName file name or empty string for a random name
933
     * @return bool
934
     */
935
    function save($fileName = "") {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
936
        if ($fileName == "") {
937
            $tmpName = tempnam(dirname($this->_fileName),'_metatemp_');
938
            $this->_writeJPEG($tmpName);
939
            if (file_exists($tmpName)) {
940
                return io_rename($tmpName, $this->_fileName);
941
            }
942
        } else {
943
            return $this->_writeJPEG($fileName);
944
        }
945
        return false;
946
    }
947
948
    /*************************************************************/
949
    /* PRIVATE FUNCTIONS (Internal Use Only!)                    */
950
    /*************************************************************/
951
952
    /*************************************************************/
953
    function _dispose($fileName = "") {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
954
        $this->_fileName = $fileName;
955
956
        $this->_fp = null;
957
        $this->_type = 'unknown';
958
959
        unset($this->_markers);
960
        unset($this->_info);
961
    }
962
963
    /*************************************************************/
964
    function _readJPEG() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
965
        unset($this->_markers);
966
        //unset($this->_info);
967
        $this->_markers = array();
968
        //$this->_info = array();
969
970
        $this->_fp = @fopen($this->_fileName, 'rb');
971
        if ($this->_fp) {
972
            if (file_exists($this->_fileName)) {
973
                $this->_type = 'file';
974
            }
975
            else {
976
                $this->_type = 'url';
977
            }
978
        } else {
979
            $this->_fp = null;
980
            return false;  // ERROR: Can't open file
981
        }
982
983
        // Check for the JPEG signature
984
        $c1 = ord(fgetc($this->_fp));
985
        $c2 = ord(fgetc($this->_fp));
986
987
        if ($c1 != 0xFF || $c2 != 0xD8) {   // (0xFF + SOI)
988
            $this->_markers = null;
989
            return false;  // ERROR: File is not a JPEG
990
        }
991
992
        $count = 0;
993
994
        $done = false;
995
        $ok = true;
996
997
        while (!$done) {
998
            $capture = false;
0 ignored issues
show
Unused Code introduced by
$capture is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
999
1000
            // First, skip any non 0xFF bytes
1001
            $discarded = 0;
1002
            $c = ord(fgetc($this->_fp));
1003
            while (!feof($this->_fp) && ($c != 0xFF)) {
1004
                $discarded++;
1005
                $c = ord(fgetc($this->_fp));
1006
            }
1007
            // Then skip all 0xFF until the marker byte
1008
            do {
1009
                $marker = ord(fgetc($this->_fp));
1010
            } while (!feof($this->_fp) && ($marker == 0xFF));
1011
1012
            if (feof($this->_fp)) {
1013
                return false; // ERROR: Unexpected EOF
1014
            }
1015
            if ($discarded != 0) {
1016
                return false; // ERROR: Extraneous data
1017
            }
1018
1019
            $length = ord(fgetc($this->_fp)) * 256 + ord(fgetc($this->_fp));
1020
            if (feof($this->_fp)) {
1021
                return false; // ERROR: Unexpected EOF
1022
            }
1023
            if ($length < 2) {
1024
                return false; // ERROR: Extraneous data
1025
            }
1026
            $length = $length - 2; // The length we got counts itself
1027
1028
            switch ($marker) {
1029
                case 0xC0:    // SOF0
1030
                case 0xC1:    // SOF1
1031
                case 0xC2:    // SOF2
1032
                case 0xC9:    // SOF9
1033
                case 0xE0:    // APP0: JFIF data
1034
                case 0xE1:    // APP1: EXIF or XMP data
1035
                case 0xED:    // APP13: IPTC / Photoshop data
1036
                    $capture = true;
1037
                    break;
1038
                case 0xDA:    // SOS: Start of scan... the image itself and the last block on the file
1039
                    $capture = false;
1040
                    $length = -1;  // This field has no length... it includes all data until EOF
1041
                    $done = true;
1042
                    break;
1043
                default:
1044
                    $capture = true;//false;
1045
                    break;
1046
            }
1047
1048
            $this->_markers[$count] = array();
1049
            $this->_markers[$count]['marker'] = $marker;
1050
            $this->_markers[$count]['length'] = $length;
1051
1052
            if ($capture) {
1053
                if ($length)
1054
                    $this->_markers[$count]['data'] = fread($this->_fp, $length);
1055
                else
1056
                    $this->_markers[$count]['data'] = "";
1057
            }
1058
            elseif (!$done) {
1059
                $result = @fseek($this->_fp, $length, SEEK_CUR);
1060
                // fseek doesn't seem to like HTTP 'files', but fgetc has no problem
1061
                if (!($result === 0)) {
1062
                    for ($i = 0; $i < $length; $i++) {
1063
                        fgetc($this->_fp);
1064
                    }
1065
                }
1066
            }
1067
            $count++;
1068
        }
1069
1070
        if ($this->_fp) {
1071
            fclose($this->_fp);
1072
            $this->_fp = null;
1073
        }
1074
1075
        return $ok;
1076
    }
1077
1078
    /*************************************************************/
1079
    function _parseAll() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1080
        if (!isset($this->_info['file'])) {
1081
            $this->_parseFileInfo();
1082
        }
1083
        if (!isset($this->_markers)) {
1084
            $this->_readJPEG();
1085
        }
1086
1087
        if ($this->_markers == null) {
1088
            return false;
1089
        }
1090
1091
        if (!isset($this->_info['jfif'])) {
1092
            $this->_parseMarkerJFIF();
1093
        }
1094
        if (!isset($this->_info['jpeg'])) {
1095
            $this->_parseMarkerSOF();
1096
        }
1097
        if (!isset($this->_info['exif'])) {
1098
            $this->_parseMarkerExif();
1099
        }
1100
        if (!isset($this->_info['xmp'])) {
1101
            $this->_parseMarkerXmp();
1102
        }
1103
        if (!isset($this->_info['adobe'])) {
1104
            $this->_parseMarkerAdobe();
1105
        }
1106
    }
1107
1108
    /*************************************************************/
1109
1110
    /**
1111
     * @param string $outputName
1112
     */
1113
    function _writeJPEG($outputName) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1114
        $this->_parseAll();
1115
1116
        $wroteEXIF = false;
1117
        $wroteAdobe = false;
1118
1119
        $this->_fp = @fopen($this->_fileName, 'r');
1120
        if ($this->_fp) {
1121
            if (file_exists($this->_fileName)) {
1122
                $this->_type = 'file';
1123
            }
1124
            else {
1125
                $this->_type = 'url';
1126
            }
1127
        } else {
1128
            $this->_fp = null;
1129
            return false;  // ERROR: Can't open file
1130
        }
1131
1132
        $this->_fpout = fopen($outputName, 'wb');
1133
        if (!$this->_fpout) {
1134
            $this->_fpout = null;
1135
            fclose($this->_fp);
1136
            $this->_fp = null;
1137
            return false;  // ERROR: Can't open output file
1138
        }
1139
1140
        // Check for the JPEG signature
1141
        $c1 = ord(fgetc($this->_fp));
1142
        $c2 = ord(fgetc($this->_fp));
1143
1144
        if ($c1 != 0xFF || $c2 != 0xD8) {   // (0xFF + SOI)
1145
            return false;  // ERROR: File is not a JPEG
1146
        }
1147
1148
        fputs($this->_fpout, chr(0xFF), 1);
1149
        fputs($this->_fpout, chr(0xD8), 1); // (0xFF + SOI)
1150
1151
        $count = 0;
0 ignored issues
show
Unused Code introduced by
$count is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1152
1153
        $done = false;
1154
        $ok = true;
1155
1156
        while (!$done) {
1157
            // First, skip any non 0xFF bytes
1158
            $discarded = 0;
1159
            $c = ord(fgetc($this->_fp));
1160
            while (!feof($this->_fp) && ($c != 0xFF)) {
1161
                $discarded++;
1162
                $c = ord(fgetc($this->_fp));
1163
            }
1164
            // Then skip all 0xFF until the marker byte
1165
            do {
1166
                $marker = ord(fgetc($this->_fp));
1167
            } while (!feof($this->_fp) && ($marker == 0xFF));
1168
1169
            if (feof($this->_fp)) {
1170
                $ok = false;
1171
                break; // ERROR: Unexpected EOF
1172
            }
1173
            if ($discarded != 0) {
1174
                $ok = false;
1175
                break; // ERROR: Extraneous data
1176
            }
1177
1178
            $length = ord(fgetc($this->_fp)) * 256 + ord(fgetc($this->_fp));
1179
            if (feof($this->_fp)) {
1180
                $ok = false;
1181
                break; // ERROR: Unexpected EOF
1182
            }
1183
            if ($length < 2) {
1184
                $ok = false;
1185
                break; // ERROR: Extraneous data
1186
            }
1187
            $length = $length - 2; // The length we got counts itself
1188
1189
            unset($data);
1190
            if ($marker == 0xE1) { // APP1: EXIF data
1191
                $data =& $this->_createMarkerEXIF();
1192
                $wroteEXIF = true;
1193
            }
1194
            elseif ($marker == 0xED) { // APP13: IPTC / Photoshop data
1195
                $data =& $this->_createMarkerAdobe();
1196
                $wroteAdobe = true;
1197
            }
1198
            elseif ($marker == 0xDA) { // SOS: Start of scan... the image itself and the last block on the file
1199
                $done = true;
1200
            }
1201
1202
            if (!$wroteEXIF && (($marker < 0xE0) || ($marker > 0xEF))) {
1203
                if (isset($this->_info['exif']) && is_array($this->_info['exif'])) {
1204
                    $exif =& $this->_createMarkerEXIF();
1205
                    $this->_writeJPEGMarker(0xE1, strlen($exif), $exif, 0);
1206
                    unset($exif);
1207
                }
1208
                $wroteEXIF = true;
1209
            }
1210
1211
            if (!$wroteAdobe && (($marker < 0xE0) || ($marker > 0xEF))) {
1212
                if ((isset($this->_info['adobe']) && is_array($this->_info['adobe']))
1213
                        || (isset($this->_info['iptc']) && is_array($this->_info['iptc']))) {
1214
                    $adobe =& $this->_createMarkerAdobe();
1215
                    $this->_writeJPEGMarker(0xED, strlen($adobe), $adobe, 0);
1216
                    unset($adobe);
1217
                }
1218
                $wroteAdobe = true;
1219
            }
1220
1221
            $origLength = $length;
1222
            if (isset($data)) {
1223
                $length = strlen($data);
1224
            }
1225
1226
            if ($marker != -1) {
1227
                $this->_writeJPEGMarker($marker, $length, $data, $origLength);
1228
            }
1229
        }
1230
1231
        if ($this->_fp) {
1232
            fclose($this->_fp);
1233
            $this->_fp = null;
1234
        }
1235
1236
        if ($this->_fpout) {
1237
            fclose($this->_fpout);
1238
            $this->_fpout = null;
1239
        }
1240
1241
        return $ok;
1242
    }
1243
1244
    /*************************************************************/
1245
1246
    /**
1247
     * @param integer $marker
1248
     * @param integer $length
1249
     * @param integer $origLength
1250
     */
1251
    function _writeJPEGMarker($marker, $length, &$data, $origLength) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1252
        if ($length <= 0) {
1253
            return false;
1254
        }
1255
1256
        fputs($this->_fpout, chr(0xFF), 1);
1257
        fputs($this->_fpout, chr($marker), 1);
1258
        fputs($this->_fpout, chr((($length + 2) & 0x0000FF00) >> 8), 1);
1259
        fputs($this->_fpout, chr((($length + 2) & 0x000000FF) >> 0), 1);
1260
1261
        if (isset($data)) {
1262
            // Copy the generated data
1263
            fputs($this->_fpout, $data, $length);
1264
1265
            if ($origLength > 0) {   // Skip the original data
1266
                $result = @fseek($this->_fp, $origLength, SEEK_CUR);
1267
                // fseek doesn't seem to like HTTP 'files', but fgetc has no problem
1268
                if ($result != 0) {
1269
                    for ($i = 0; $i < $origLength; $i++) {
1270
                        fgetc($this->_fp);
1271
                    }
1272
                }
1273
            }
1274
        } else {
1275
            if ($marker == 0xDA) {  // Copy until EOF
1276
                while (!feof($this->_fp)) {
1277
                    $data = fread($this->_fp, 1024 * 16);
1278
                    fputs($this->_fpout, $data, strlen($data));
1279
                }
1280
            } else { // Copy only $length bytes
1281
                $data = @fread($this->_fp, $length);
1282
                fputs($this->_fpout, $data, $length);
1283
            }
1284
        }
1285
1286
        return true;
1287
    }
1288
1289
    /**
1290
     * Gets basic info from the file - should work with non-JPEGs
1291
     *
1292
     * @author  Sebastian Delmont <[email protected]>
1293
     * @author  Andreas Gohr <[email protected]>
1294
     */
1295
    function _parseFileInfo() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1296
        if (file_exists($this->_fileName) && is_file($this->_fileName)) {
1297
            $this->_info['file'] = array();
1298
            $this->_info['file']['Name'] = utf8_decodeFN(utf8_basename($this->_fileName));
1299
            $this->_info['file']['Path'] = fullpath($this->_fileName);
1300
            $this->_info['file']['Size'] = filesize($this->_fileName);
1301
            if ($this->_info['file']['Size'] < 1024) {
1302
                $this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B';
1303
            } elseif ($this->_info['file']['Size'] < (1024 * 1024)) {
1304
                $this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'KB';
1305
            } elseif ($this->_info['file']['Size'] < (1024 * 1024 * 1024)) {
1306
                $this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / (1024*1024)) . 'MB';
1307
            } else {
1308
                $this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B';
1309
            }
1310
            $this->_info['file']['UnixTime'] = filemtime($this->_fileName);
1311
1312
            // get image size directly from file
1313
            $size = getimagesize($this->_fileName);
1314
            $this->_info['file']['Width']  = $size[0];
1315
            $this->_info['file']['Height'] = $size[1];
1316
            // set mime types and formats
1317
            // http://www.php.net/manual/en/function.getimagesize.php
1318
            // http://www.php.net/manual/en/function.image-type-to-mime-type.php
1319
            switch ($size[2]){
1320
                case 1:
1321
                    $this->_info['file']['Mime']   = 'image/gif';
1322
                    $this->_info['file']['Format'] = 'GIF';
1323
                    break;
1324
                case 2:
1325
                    $this->_info['file']['Mime']   = 'image/jpeg';
1326
                    $this->_info['file']['Format'] = 'JPEG';
1327
                    break;
1328
                case 3:
1329
                    $this->_info['file']['Mime']   = 'image/png';
1330
                    $this->_info['file']['Format'] = 'PNG';
1331
                    break;
1332
                case 4:
1333
                    $this->_info['file']['Mime']   = 'application/x-shockwave-flash';
1334
                    $this->_info['file']['Format'] = 'SWF';
1335
                    break;
1336
                case 5:
1337
                    $this->_info['file']['Mime']   = 'image/psd';
1338
                    $this->_info['file']['Format'] = 'PSD';
1339
                    break;
1340
                case 6:
1341
                    $this->_info['file']['Mime']   = 'image/bmp';
1342
                    $this->_info['file']['Format'] = 'BMP';
1343
                    break;
1344
                case 7:
1345
                    $this->_info['file']['Mime']   = 'image/tiff';
1346
                    $this->_info['file']['Format'] = 'TIFF (Intel)';
1347
                    break;
1348
                case 8:
1349
                    $this->_info['file']['Mime']   = 'image/tiff';
1350
                    $this->_info['file']['Format'] = 'TIFF (Motorola)';
1351
                    break;
1352
                case 9:
1353
                    $this->_info['file']['Mime']   = 'application/octet-stream';
1354
                    $this->_info['file']['Format'] = 'JPC';
1355
                    break;
1356
                case 10:
1357
                    $this->_info['file']['Mime']   = 'image/jp2';
1358
                    $this->_info['file']['Format'] = 'JP2';
1359
                    break;
1360
                case 11:
1361
                    $this->_info['file']['Mime']   = 'application/octet-stream';
1362
                    $this->_info['file']['Format'] = 'JPX';
1363
                    break;
1364
                case 12:
1365
                    $this->_info['file']['Mime']   = 'application/octet-stream';
1366
                    $this->_info['file']['Format'] = 'JB2';
1367
                    break;
1368
                case 13:
1369
                    $this->_info['file']['Mime']   = 'application/x-shockwave-flash';
1370
                    $this->_info['file']['Format'] = 'SWC';
1371
                    break;
1372
                case 14:
1373
                    $this->_info['file']['Mime']   = 'image/iff';
1374
                    $this->_info['file']['Format'] = 'IFF';
1375
                    break;
1376
                case 15:
1377
                    $this->_info['file']['Mime']   = 'image/vnd.wap.wbmp';
1378
                    $this->_info['file']['Format'] = 'WBMP';
1379
                    break;
1380
                case 16:
1381
                    $this->_info['file']['Mime']   = 'image/xbm';
1382
                    $this->_info['file']['Format'] = 'XBM';
1383
                    break;
1384
                default:
1385
                    $this->_info['file']['Mime']   = 'image/unknown';
1386
            }
1387
        } else {
1388
            $this->_info['file'] = array();
1389
            $this->_info['file']['Name'] = utf8_basename($this->_fileName);
1390
            $this->_info['file']['Url'] = $this->_fileName;
1391
        }
1392
1393
        return true;
1394
    }
1395
1396
    /*************************************************************/
1397
    function _parseMarkerJFIF() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1398
        if (!isset($this->_markers)) {
1399
            $this->_readJPEG();
1400
        }
1401
1402
        if ($this->_markers == null) {
1403
            return false;
1404
        }
1405
1406
        $data = null;
1407
        $count = count($this->_markers);
1408
        for ($i = 0; $i < $count; $i++) {
1409
            if ($this->_markers[$i]['marker'] == 0xE0) {
1410
                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 4);
1411
                if ($signature == 'JFIF') {
1412
                    $data =& $this->_markers[$i]['data'];
1413
                    break;
1414
                }
1415
            }
1416
        }
1417
1418
        if ($data == null) {
1419
            $this->_info['jfif'] = false;
1420
            return false;
1421
        }
1422
1423
        $this->_info['jfif'] = array();
1424
1425
        $vmaj = $this->_getByte($data, 5);
1426
        $vmin = $this->_getByte($data, 6);
1427
1428
        $this->_info['jfif']['Version'] = sprintf('%d.%02d', $vmaj, $vmin);
1429
1430
        $units = $this->_getByte($data, 7);
1431
        switch ($units) {
1432
            case 0:
1433
                $this->_info['jfif']['Units'] = 'pixels';
1434
                break;
1435
            case 1:
1436
                $this->_info['jfif']['Units'] = 'dpi';
1437
                break;
1438
            case 2:
1439
                $this->_info['jfif']['Units'] = 'dpcm';
1440
                break;
1441
            default:
1442
                $this->_info['jfif']['Units'] = 'unknown';
1443
                break;
1444
        }
1445
1446
        $xdens = $this->_getShort($data, 8);
1447
        $ydens = $this->_getShort($data, 10);
1448
1449
        $this->_info['jfif']['XDensity'] = $xdens;
1450
        $this->_info['jfif']['YDensity'] = $ydens;
1451
1452
        $thumbx = $this->_getByte($data, 12);
1453
        $thumby = $this->_getByte($data, 13);
1454
1455
        $this->_info['jfif']['ThumbnailWidth'] = $thumbx;
1456
        $this->_info['jfif']['ThumbnailHeight'] = $thumby;
1457
1458
        return true;
1459
    }
1460
1461
    /*************************************************************/
1462
    function _parseMarkerSOF() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1463
        if (!isset($this->_markers)) {
1464
            $this->_readJPEG();
1465
        }
1466
1467
        if ($this->_markers == null) {
1468
            return false;
1469
        }
1470
1471
        $data = null;
1472
        $count = count($this->_markers);
1473
        for ($i = 0; $i < $count; $i++) {
1474
            switch ($this->_markers[$i]['marker']) {
1475
                case 0xC0: // SOF0
1476
                case 0xC1: // SOF1
1477
                case 0xC2: // SOF2
1478
                case 0xC9: // SOF9
1479
                    $data =& $this->_markers[$i]['data'];
1480
                    $marker = $this->_markers[$i]['marker'];
1481
                    break;
1482
            }
1483
        }
1484
1485
        if ($data == null) {
1486
            $this->_info['sof'] = false;
1487
            return false;
1488
        }
1489
1490
        $pos = 0;
1491
        $this->_info['sof'] = array();
1492
1493
        switch ($marker) {
0 ignored issues
show
Bug introduced by
The variable $marker does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1494
            case 0xC0: // SOF0
1495
                $format = 'Baseline';
1496
                break;
1497
            case 0xC1: // SOF1
1498
                $format = 'Progessive';
1499
                break;
1500
            case 0xC2: // SOF2
1501
                $format = 'Non-baseline';
1502
                break;
1503
            case 0xC9: // SOF9
1504
                $format = 'Arithmetic';
1505
                break;
1506
            default:
1507
                return false;
1508
        }
1509
1510
        $this->_info['sof']['Format']          = $format;
1511
        $this->_info['sof']['SamplePrecision'] = $this->_getByte($data, $pos + 0);
1512
        $this->_info['sof']['ImageHeight']     = $this->_getShort($data, $pos + 1);
1513
        $this->_info['sof']['ImageWidth']      = $this->_getShort($data, $pos + 3);
1514
        $this->_info['sof']['ColorChannels']   = $this->_getByte($data, $pos + 5);
1515
1516
        return true;
1517
    }
1518
1519
    /**
1520
     * Parses the XMP data
1521
     *
1522
     * @author  Hakan Sandell <[email protected]>
1523
     */
1524
    function _parseMarkerXmp() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1525
        if (!isset($this->_markers)) {
1526
            $this->_readJPEG();
1527
        }
1528
1529
        if ($this->_markers == null) {
1530
            return false;
1531
        }
1532
1533
        $data = null;
1534
        $count = count($this->_markers);
1535
        for ($i = 0; $i < $count; $i++) {
1536
            if ($this->_markers[$i]['marker'] == 0xE1) {
1537
                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 29);
1538
                if ($signature == "http://ns.adobe.com/xap/1.0/\0") {
1539
                    $data = substr($this->_markers[$i]['data'], 29);
1540
                    break;
1541
                }
1542
            }
1543
        }
1544
1545
        if ($data == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $data of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1546
            $this->_info['xmp'] = false;
1547
            return false;
1548
        }
1549
1550
        $parser = xml_parser_create();
1551
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1552
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
1553
        $result = xml_parse_into_struct($parser, $data, $values, $tags);
1554
        xml_parser_free($parser);
1555
1556
        if ($result == 0) {
1557
            $this->_info['xmp'] = false;
1558
            return false;
1559
        }
1560
1561
        $this->_info['xmp'] = array();
1562
        $count = count($values);
1563
        for ($i = 0; $i < $count; $i++) {
1564
            if ($values[$i]['tag'] == 'rdf:Description' && $values[$i]['type'] == 'open') {
1565
1566
                while ((++$i < $count) && ($values[$i]['tag'] != 'rdf:Description')) {
1567
                    $this->_parseXmpNode($values, $i, $this->_info['xmp'][$values[$i]['tag']], $count);
1568
                }
1569
            }
1570
        }
1571
        return true;
1572
    }
1573
1574
    /**
1575
     * Parses XMP nodes by recursion
1576
     *
1577
     * @author  Hakan Sandell <[email protected]>
1578
     * @param integer $count
1579
     */
1580
    function _parseXmpNode($values, &$i, &$meta, $count) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1581
        if ($values[$i]['type'] == 'close') return;
1582
1583
        if ($values[$i]['type'] == 'complete') {
1584
            // Simple Type property
1585
            $meta = $values[$i]['value'];
1586
            return;
1587
        }
1588
1589
        $i++;
1590
        if ($i >= $count) return;
1591
1592
        if ($values[$i]['tag'] == 'rdf:Bag' || $values[$i]['tag'] == 'rdf:Seq') {
1593
            // Array property
1594
            $meta = array();
1595
            while ($values[++$i]['tag'] == 'rdf:li') {
1596
                $this->_parseXmpNode($values, $i, $meta[], $count);
1597
            }
1598
            $i++; // skip closing Bag/Seq tag
1599
1600
        } elseif ($values[$i]['tag'] == 'rdf:Alt') {
1601
            // Language Alternative property, only the first (default) value is used
1602
            if ($values[$i]['type'] == 'open') {
1603
                $i++;
1604
                $this->_parseXmpNode($values, $i, $meta, $count);
1605
                while ((++$i < $count) && ($values[$i]['tag'] != 'rdf:Alt'));
1606
                $i++; // skip closing Alt tag
1607
            }
1608
1609
        } else {
1610
            // Structure property
1611
            $meta = array();
1612
            $startTag = $values[$i-1]['tag'];
1613
            do {
1614
                $this->_parseXmpNode($values, $i, $meta[$values[$i]['tag']], $count);
1615
            } while ((++$i < $count) && ($values[$i]['tag'] != $startTag));
1616
        }
1617
    }
1618
1619
    /*************************************************************/
1620
    function _parseMarkerExif() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1621
        if (!isset($this->_markers)) {
1622
            $this->_readJPEG();
1623
        }
1624
1625
        if ($this->_markers == null) {
1626
            return false;
1627
        }
1628
1629
        $data = null;
1630
        $count = count($this->_markers);
1631
        for ($i = 0; $i < $count; $i++) {
1632
            if ($this->_markers[$i]['marker'] == 0xE1) {
1633
                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 6);
1634
                if ($signature == "Exif\0\0") {
1635
                    $data =& $this->_markers[$i]['data'];
1636
                    break;
1637
                }
1638
            }
1639
        }
1640
1641
        if ($data == null) {
1642
            $this->_info['exif'] = false;
1643
            return false;
1644
        }
1645
        $pos = 6;
1646
        $this->_info['exif'] = array();
1647
1648
        // We don't increment $pos after this because Exif uses offsets relative to this point
1649
1650
        $byteAlign = $this->_getShort($data, $pos + 0);
1651
1652
        if ($byteAlign == 0x4949) { // "II"
1653
            $isBigEndian = false;
1654
        } elseif ($byteAlign == 0x4D4D) { // "MM"
1655
            $isBigEndian = true;
1656
        } else {
1657
            return false; // Unexpected data
1658
        }
1659
1660
        $alignCheck = $this->_getShort($data, $pos + 2, $isBigEndian);
1661
        if ($alignCheck != 0x002A) // That's the expected value
1662
            return false; // Unexpected data
1663
1664
        if ($isBigEndian) {
1665
            $this->_info['exif']['ByteAlign'] = "Big Endian";
1666
        } else {
1667
            $this->_info['exif']['ByteAlign'] = "Little Endian";
1668
        }
1669
1670
        $offsetIFD0 = $this->_getLong($data, $pos + 4, $isBigEndian);
1671
        if ($offsetIFD0 < 8)
1672
            return false; // Unexpected data
1673
1674
        $offsetIFD1 = $this->_readIFD($data, $pos, $offsetIFD0, $isBigEndian, 'ifd0');
1675
        if ($offsetIFD1 != 0)
1676
            $this->_readIFD($data, $pos, $offsetIFD1, $isBigEndian, 'ifd1');
1677
1678
        return true;
1679
    }
1680
1681
    /*************************************************************/
1682
1683
    /**
1684
     * @param integer $base
1685
     * @param boolean $isBigEndian
1686
     * @param string $mode
1687
     */
1688
    function _readIFD($data, $base, $offset, $isBigEndian, $mode) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1689
        $EXIFTags = $this->_exifTagNames($mode);
1690
1691
        $numEntries = $this->_getShort($data, $base + $offset, $isBigEndian);
1692
        $offset += 2;
1693
1694
        $exifTIFFOffset = 0;
1695
        $exifTIFFLength = 0;
1696
        $exifThumbnailOffset = 0;
1697
        $exifThumbnailLength = 0;
1698
1699
        for ($i = 0; $i < $numEntries; $i++) {
1700
            $tag = $this->_getShort($data, $base + $offset, $isBigEndian);
1701
            $offset += 2;
1702
            $type = $this->_getShort($data, $base + $offset, $isBigEndian);
1703
            $offset += 2;
1704
            $count = $this->_getLong($data, $base + $offset, $isBigEndian);
1705
            $offset += 4;
1706
1707
            if (($type < 1) || ($type > 12))
1708
                return false; // Unexpected Type
1709
1710
            $typeLengths = array( -1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 );
1711
1712
            $dataLength = $typeLengths[$type] * $count;
1713
            if ($dataLength > 4) {
1714
                $dataOffset = $this->_getLong($data, $base + $offset, $isBigEndian);
1715
                $rawValue = $this->_getFixedString($data, $base + $dataOffset, $dataLength);
1716
            } else {
1717
                $rawValue = $this->_getFixedString($data, $base + $offset, $dataLength);
1718
            }
1719
            $offset += 4;
1720
1721
            switch ($type) {
1722
                case 1:    // UBYTE
1723
                    if ($count == 1) {
1724
                        $value = $this->_getByte($rawValue, 0);
1725
                    } else {
1726
                        $value = array();
1727
                        for ($j = 0; $j < $count; $j++)
1728
                            $value[$j] = $this->_getByte($rawValue, $j);
1729
                    }
1730
                    break;
1731
                case 2:    // ASCII
1732
                    $value = $rawValue;
1733
                    break;
1734
                case 3:    // USHORT
1735
                    if ($count == 1) {
1736
                        $value = $this->_getShort($rawValue, 0, $isBigEndian);
1737
                    } else {
1738
                        $value = array();
1739
                        for ($j = 0; $j < $count; $j++)
1740
                            $value[$j] = $this->_getShort($rawValue, $j * 2, $isBigEndian);
1741
                    }
1742
                    break;
1743
                case 4:    // ULONG
1744
                    if ($count == 1) {
1745
                        $value = $this->_getLong($rawValue, 0, $isBigEndian);
1746
                    } else {
1747
                        $value = array();
1748
                        for ($j = 0; $j < $count; $j++)
1749
                            $value[$j] = $this->_getLong($rawValue, $j * 4, $isBigEndian);
1750
                    }
1751
                    break;
1752
                case 5:    // URATIONAL
1753
                    if ($count == 1) {
1754
                        $a = $this->_getLong($rawValue, 0, $isBigEndian);
1755
                        $b = $this->_getLong($rawValue, 4, $isBigEndian);
1756
                        $value = array();
1757
                        $value['val'] = 0;
1758
                        $value['num'] = $a;
1759
                        $value['den'] = $b;
1760
                        if (($a != 0) && ($b != 0)) {
1761
                            $value['val'] = $a / $b;
1762
                        }
1763
                    } else {
1764
                        $value = array();
1765
                        for ($j = 0; $j < $count; $j++) {
1766
                            $a = $this->_getLong($rawValue, $j * 8, $isBigEndian);
1767
                            $b = $this->_getLong($rawValue, ($j * 8) + 4, $isBigEndian);
1768
                            $value = array();
1769
                            $value[$j]['val'] = 0;
1770
                            $value[$j]['num'] = $a;
1771
                            $value[$j]['den'] = $b;
1772
                            if (($a != 0) && ($b != 0))
1773
                                $value[$j]['val'] = $a / $b;
1774
                        }
1775
                    }
1776
                    break;
1777
                case 6:    // SBYTE
1778
                    if ($count == 1) {
1779
                        $value = $this->_getByte($rawValue, 0);
1780
                    } else {
1781
                        $value = array();
1782
                        for ($j = 0; $j < $count; $j++)
1783
                            $value[$j] = $this->_getByte($rawValue, $j);
1784
                    }
1785
                    break;
1786
                case 7:    // UNDEFINED
1787
                    $value = $rawValue;
1788
                    break;
1789
                case 8:    // SSHORT
1790
                    if ($count == 1) {
1791
                        $value = $this->_getShort($rawValue, 0, $isBigEndian);
1792
                    } else {
1793
                        $value = array();
1794
                        for ($j = 0; $j < $count; $j++)
1795
                            $value[$j] = $this->_getShort($rawValue, $j * 2, $isBigEndian);
1796
                    }
1797
                    break;
1798
                case 9:    // SLONG
1799
                    if ($count == 1) {
1800
                        $value = $this->_getLong($rawValue, 0, $isBigEndian);
1801
                    } else {
1802
                        $value = array();
1803
                        for ($j = 0; $j < $count; $j++)
1804
                            $value[$j] = $this->_getLong($rawValue, $j * 4, $isBigEndian);
1805
                    }
1806
                    break;
1807
                case 10:   // SRATIONAL
1808
                    if ($count == 1) {
1809
                        $a = $this->_getLong($rawValue, 0, $isBigEndian);
1810
                        $b = $this->_getLong($rawValue, 4, $isBigEndian);
1811
                        $value = array();
1812
                        $value['val'] = 0;
1813
                        $value['num'] = $a;
1814
                        $value['den'] = $b;
1815
                        if (($a != 0) && ($b != 0))
1816
                            $value['val'] = $a / $b;
1817
                    } else {
1818
                        $value = array();
1819
                        for ($j = 0; $j < $count; $j++) {
1820
                            $a = $this->_getLong($rawValue, $j * 8, $isBigEndian);
1821
                            $b = $this->_getLong($rawValue, ($j * 8) + 4, $isBigEndian);
1822
                            $value = array();
1823
                            $value[$j]['val'] = 0;
1824
                            $value[$j]['num'] = $a;
1825
                            $value[$j]['den'] = $b;
1826
                            if (($a != 0) && ($b != 0))
1827
                                $value[$j]['val'] = $a / $b;
1828
                        }
1829
                    }
1830
                    break;
1831
                case 11:   // FLOAT
1832
                    $value = $rawValue;
1833
                    break;
1834
1835
                case 12:   // DFLOAT
1836
                    $value = $rawValue;
1837
                    break;
1838
                default:
1839
                    return false; // Unexpected Type
1840
            }
1841
1842
            $tagName = '';
0 ignored issues
show
Unused Code introduced by
$tagName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1843
            if (($mode == 'ifd0') && ($tag == 0x8769)) {  // ExifIFDOffset
1844
                $this->_readIFD($data, $base, $value, $isBigEndian, 'exif');
1845
            } elseif (($mode == 'ifd0') && ($tag == 0x8825)) {  // GPSIFDOffset
1846
                $this->_readIFD($data, $base, $value, $isBigEndian, 'gps');
1847
            } elseif (($mode == 'ifd1') && ($tag == 0x0111)) {  // TIFFStripOffsets
1848
                $exifTIFFOffset = $value;
1849
            } elseif (($mode == 'ifd1') && ($tag == 0x0117)) {  // TIFFStripByteCounts
1850
                $exifTIFFLength = $value;
1851
            } elseif (($mode == 'ifd1') && ($tag == 0x0201)) {  // TIFFJFIFOffset
1852
                $exifThumbnailOffset = $value;
1853
            } elseif (($mode == 'ifd1') && ($tag == 0x0202)) {  // TIFFJFIFLength
1854
                $exifThumbnailLength = $value;
1855
            } elseif (($mode == 'exif') && ($tag == 0xA005)) {  // InteropIFDOffset
1856
                $this->_readIFD($data, $base, $value, $isBigEndian, 'interop');
1857
            }
1858
            // elseif (($mode == 'exif') && ($tag == 0x927C)) {  // MakerNote
1859
            // }
1860
            else {
1861
                if (isset($EXIFTags[$tag])) {
1862
                    $tagName = $EXIFTags[$tag];
1863
                    if (isset($this->_info['exif'][$tagName])) {
1864
                        if (!is_array($this->_info['exif'][$tagName])) {
1865
                            $aux = array();
1866
                            $aux[0] = $this->_info['exif'][$tagName];
1867
                            $this->_info['exif'][$tagName] = $aux;
1868
                        }
1869
1870
                        $this->_info['exif'][$tagName][count($this->_info['exif'][$tagName])] = $value;
1871
                    } else {
1872
                        $this->_info['exif'][$tagName] = $value;
1873
                    }
1874
                }
1875
                /*
1876
                 else {
1877
                    echo sprintf("<h1>Unknown tag %02x (t: %d l: %d) %s in %s</h1>", $tag, $type, $count, $mode, $this->_fileName);
1878
                    // Unknown Tags will be ignored!!!
1879
                    // That's because the tag might be a pointer (like the Exif tag)
1880
                    // and saving it without saving the data it points to might
1881
                    // create an invalid file.
1882
                }
1883
                */
1884
            }
1885
        }
1886
1887
        if (($exifThumbnailOffset > 0) && ($exifThumbnailLength > 0)) {
1888
            $this->_info['exif']['JFIFThumbnail'] = $this->_getFixedString($data, $base + $exifThumbnailOffset, $exifThumbnailLength);
1889
        }
1890
1891
        if (($exifTIFFOffset > 0) && ($exifTIFFLength > 0)) {
1892
            $this->_info['exif']['TIFFStrips'] = $this->_getFixedString($data, $base + $exifTIFFOffset, $exifTIFFLength);
1893
        }
1894
1895
        $nextOffset = $this->_getLong($data, $base + $offset, $isBigEndian);
1896
        return $nextOffset;
1897
    }
1898
1899
    /*************************************************************/
1900
    function & _createMarkerExif() {
1901
        $data = null;
1902
        $count = count($this->_markers);
1903
        for ($i = 0; $i < $count; $i++) {
1904
            if ($this->_markers[$i]['marker'] == 0xE1) {
1905
                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 6);
1906
                if ($signature == "Exif\0\0") {
1907
                    $data =& $this->_markers[$i]['data'];
1908
                    break;
1909
                }
1910
            }
1911
        }
1912
1913
        if (!isset($this->_info['exif'])) {
1914
            return false;
1915
        }
1916
1917
        $data = "Exif\0\0";
1918
        $pos = 6;
1919
        $offsetBase = 6;
1920
1921
        if (isset($this->_info['exif']['ByteAlign']) && ($this->_info['exif']['ByteAlign'] == "Big Endian")) {
1922
            $isBigEndian = true;
1923
            $aux = "MM";
1924
            $pos = $this->_putString($data, $pos, $aux);
1925
        } else {
1926
            $isBigEndian = false;
1927
            $aux = "II";
1928
            $pos = $this->_putString($data, $pos, $aux);
1929
        }
1930
        $pos = $this->_putShort($data, $pos, 0x002A, $isBigEndian);
1931
        $pos = $this->_putLong($data, $pos, 0x00000008, $isBigEndian); // IFD0 Offset is always 8
1932
1933
        $ifd0 =& $this->_getIFDEntries($isBigEndian, 'ifd0');
1934
        $ifd1 =& $this->_getIFDEntries($isBigEndian, 'ifd1');
1935
1936
        $pos = $this->_writeIFD($data, $pos, $offsetBase, $ifd0, $isBigEndian, true);
1937
        $pos = $this->_writeIFD($data, $pos, $offsetBase, $ifd1, $isBigEndian, false);
0 ignored issues
show
Unused Code introduced by
$pos is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1938
1939
        return $data;
1940
    }
1941
1942
    /*************************************************************/
1943
1944
    /**
1945
     * @param integer $offsetBase
1946
     * @param boolean $isBigEndian
1947
     * @param boolean $hasNext
1948
     */
1949
    function _writeIFD(&$data, $pos, $offsetBase, &$entries, $isBigEndian, $hasNext) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1950
        $tiffData = null;
1951
        $tiffDataOffsetPos = -1;
1952
1953
        $entryCount = count($entries);
1954
1955
        $dataPos = $pos + 2 + ($entryCount * 12) + 4;
1956
        $pos = $this->_putShort($data, $pos, $entryCount, $isBigEndian);
1957
1958
        for ($i = 0; $i < $entryCount; $i++) {
1959
            $tag = $entries[$i]['tag'];
1960
            $type = $entries[$i]['type'];
1961
1962
            if ($type == -99) { // SubIFD
1963
                $pos = $this->_putShort($data, $pos, $tag, $isBigEndian);
1964
                $pos = $this->_putShort($data, $pos, 0x04, $isBigEndian); // LONG
1965
                $pos = $this->_putLong($data, $pos, 0x01, $isBigEndian); // Count = 1
1966
                $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian);
1967
1968
                $dataPos = $this->_writeIFD($data, $dataPos, $offsetBase, $entries[$i]['value'], $isBigEndian, false);
1969
            } elseif ($type == -98) { // TIFF Data
1970
                $pos = $this->_putShort($data, $pos, $tag, $isBigEndian);
1971
                $pos = $this->_putShort($data, $pos, 0x04, $isBigEndian); // LONG
1972
                $pos = $this->_putLong($data, $pos, 0x01, $isBigEndian); // Count = 1
1973
                $tiffDataOffsetPos = $pos;
1974
                $pos = $this->_putLong($data, $pos, 0x00, $isBigEndian); // For Now
1975
                $tiffData =& $entries[$i]['value'] ;
1976
            } else { // Regular Entry
1977
                $pos = $this->_putShort($data, $pos, $tag, $isBigEndian);
1978
                $pos = $this->_putShort($data, $pos, $type, $isBigEndian);
1979
                $pos = $this->_putLong($data, $pos, $entries[$i]['count'], $isBigEndian);
1980
                if (strlen($entries[$i]['value']) > 4) {
1981
                    $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian);
1982
                    $dataPos = $this->_putString($data, $dataPos, $entries[$i]['value']);
1983
                } else {
1984
                    $val = str_pad($entries[$i]['value'], 4, "\0");
1985
                    $pos = $this->_putString($data, $pos, $val);
1986
                }
1987
            }
1988
        }
1989
1990
        if ($tiffData != null) {
1991
            $this->_putLong($data, $tiffDataOffsetPos, $dataPos - $offsetBase, $isBigEndian);
1992
            $dataPos = $this->_putString($data, $dataPos, $tiffData);
1993
        }
1994
1995
        if ($hasNext) {
1996
            $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian);
0 ignored issues
show
Unused Code introduced by
$pos is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1997
        } else {
1998
            $pos = $this->_putLong($data, $pos, 0, $isBigEndian);
0 ignored issues
show
Unused Code introduced by
$pos is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1999
        }
2000
2001
        return $dataPos;
2002
    }
2003
2004
    /*************************************************************/
2005
2006
    /**
2007
     * @param boolean $isBigEndian
2008
     * @param string $mode
2009
     */
2010
    function & _getIFDEntries($isBigEndian, $mode) {
2011
        $EXIFNames = $this->_exifTagNames($mode);
2012
        $EXIFTags = $this->_exifNameTags($mode);
0 ignored issues
show
Unused Code introduced by
$EXIFTags is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2013
        $EXIFTypeInfo = $this->_exifTagTypes($mode);
2014
2015
        $ifdEntries = array();
2016
        $entryCount = 0;
2017
2018
        reset($EXIFNames);
2019
        while (list($tag, $name) = each($EXIFNames)) {
2020
            $type = $EXIFTypeInfo[$tag][0];
2021
            $count = $EXIFTypeInfo[$tag][1];
2022
            $value = null;
2023
2024
            if (($mode == 'ifd0') && ($tag == 0x8769)) {  // ExifIFDOffset
2025
                if (isset($this->_info['exif']['EXIFVersion'])) {
2026
                    $value =& $this->_getIFDEntries($isBigEndian, "exif");
2027
                    $type = -99;
2028
                }
2029
                else {
2030
                    $value = null;
2031
                }
2032
            } elseif (($mode == 'ifd0') && ($tag == 0x8825)) {  // GPSIFDOffset
2033
                if (isset($this->_info['exif']['GPSVersionID'])) {
2034
                    $value =& $this->_getIFDEntries($isBigEndian, "gps");
2035
                    $type = -99;
2036
                } else {
2037
                    $value = null;
2038
                }
2039
            } elseif (($mode == 'ifd1') && ($tag == 0x0111)) {  // TIFFStripOffsets
2040
                if (isset($this->_info['exif']['TIFFStrips'])) {
2041
                    $value =& $this->_info['exif']['TIFFStrips'];
2042
                    $type = -98;
2043
                } else {
2044
                    $value = null;
2045
                }
2046
            } elseif (($mode == 'ifd1') && ($tag == 0x0117)) {  // TIFFStripByteCounts
2047
                if (isset($this->_info['exif']['TIFFStrips'])) {
2048
                    $value = strlen($this->_info['exif']['TIFFStrips']);
2049
                } else {
2050
                    $value = null;
2051
                }
2052
            } elseif (($mode == 'ifd1') && ($tag == 0x0201)) {  // TIFFJFIFOffset
2053
                if (isset($this->_info['exif']['JFIFThumbnail'])) {
2054
                    $value =& $this->_info['exif']['JFIFThumbnail'];
2055
                    $type = -98;
2056
                } else {
2057
                    $value = null;
2058
                }
2059
            } elseif (($mode == 'ifd1') && ($tag == 0x0202)) {  // TIFFJFIFLength
2060
                if (isset($this->_info['exif']['JFIFThumbnail'])) {
2061
                    $value = strlen($this->_info['exif']['JFIFThumbnail']);
2062
                } else {
2063
                    $value = null;
2064
                }
2065
            } elseif (($mode == 'exif') && ($tag == 0xA005)) {  // InteropIFDOffset
2066
                if (isset($this->_info['exif']['InteroperabilityIndex'])) {
2067
                    $value =& $this->_getIFDEntries($isBigEndian, "interop");
2068
                    $type = -99;
2069
                } else {
2070
                    $value = null;
2071
                }
2072
            } elseif (isset($this->_info['exif'][$name])) {
2073
                $origValue =& $this->_info['exif'][$name];
2074
2075
                // This makes it easier to process variable size elements
2076
                if (!is_array($origValue) || isset($origValue['val'])) {
2077
                    unset($origValue); // Break the reference
2078
                    $origValue = array($this->_info['exif'][$name]);
2079
                }
2080
                $origCount = count($origValue);
2081
2082
                if ($origCount == 0 ) {
2083
                    $type = -1;  // To ignore this field
2084
                }
2085
2086
                $value = " ";
2087
2088
                switch ($type) {
2089
                    case 1:    // UBYTE
2090
                        if ($count == 0) {
2091
                            $count = $origCount;
2092
                        }
2093
2094
                        $j = 0;
2095
                        while (($j < $count) && ($j < $origCount)) {
2096
2097
                            $this->_putByte($value, $j, $origValue[$j]);
2098
                            $j++;
2099
                        }
2100
2101
                        while ($j < $count) {
2102
                            $this->_putByte($value, $j, 0);
2103
                            $j++;
2104
                        }
2105
                        break;
2106
                    case 2:    // ASCII
2107
                        $v = strval($origValue[0]);
2108
                        if (($count != 0) && (strlen($v) > $count)) {
2109
                            $v = substr($v, 0, $count);
2110
                        }
2111
                        elseif (($count > 0) && (strlen($v) < $count)) {
2112
                            $v = str_pad($v, $count, "\0");
2113
                        }
2114
2115
                        $count = strlen($v);
2116
2117
                        $this->_putString($value, 0, $v);
2118
                        break;
2119
                    case 3:    // USHORT
2120
                        if ($count == 0) {
2121
                            $count = $origCount;
2122
                        }
2123
2124
                        $j = 0;
2125
                        while (($j < $count) && ($j < $origCount)) {
2126
                            $this->_putShort($value, $j * 2, $origValue[$j], $isBigEndian);
2127
                            $j++;
2128
                        }
2129
2130
                        while ($j < $count) {
2131
                            $this->_putShort($value, $j * 2, 0, $isBigEndian);
2132
                            $j++;
2133
                        }
2134
                        break;
2135
                    case 4:    // ULONG
2136
                        if ($count == 0) {
2137
                            $count = $origCount;
2138
                        }
2139
2140
                        $j = 0;
2141
                        while (($j < $count) && ($j < $origCount)) {
2142
                            $this->_putLong($value, $j * 4, $origValue[$j], $isBigEndian);
2143
                            $j++;
2144
                        }
2145
2146
                        while ($j < $count) {
2147
                            $this->_putLong($value, $j * 4, 0, $isBigEndian);
2148
                            $j++;
2149
                        }
2150
                        break;
2151
                    case 5:    // URATIONAL
2152
                        if ($count == 0) {
2153
                            $count = $origCount;
2154
                        }
2155
2156
                        $j = 0;
2157
                        while (($j < $count) && ($j < $origCount)) {
2158
                            $v = $origValue[$j];
2159
                            if (is_array($v)) {
2160
                                $a = $v['num'];
2161
                                $b = $v['den'];
2162
                            }
2163
                            else {
2164
                                $a = 0;
2165
                                $b = 0;
2166
                                // TODO: Allow other types and convert them
2167
                            }
2168
                            $this->_putLong($value, $j * 8, $a, $isBigEndian);
2169
                            $this->_putLong($value, ($j * 8) + 4, $b, $isBigEndian);
2170
                            $j++;
2171
                        }
2172
2173
                        while ($j < $count) {
2174
                            $this->_putLong($value, $j * 8, 0, $isBigEndian);
2175
                            $this->_putLong($value, ($j * 8) + 4, 0, $isBigEndian);
2176
                            $j++;
2177
                        }
2178
                        break;
2179
                    case 6:    // SBYTE
2180
                        if ($count == 0) {
2181
                            $count = $origCount;
2182
                        }
2183
2184
                        $j = 0;
2185
                        while (($j < $count) && ($j < $origCount)) {
2186
                            $this->_putByte($value, $j, $origValue[$j]);
2187
                            $j++;
2188
                        }
2189
2190
                        while ($j < $count) {
2191
                            $this->_putByte($value, $j, 0);
2192
                            $j++;
2193
                        }
2194
                        break;
2195
                    case 7:    // UNDEFINED
2196
                        $v = strval($origValue[0]);
2197
                        if (($count != 0) && (strlen($v) > $count)) {
2198
                            $v = substr($v, 0, $count);
2199
                        }
2200
                        elseif (($count > 0) && (strlen($v) < $count)) {
2201
                            $v = str_pad($v, $count, "\0");
2202
                        }
2203
2204
                        $count = strlen($v);
2205
2206
                        $this->_putString($value, 0, $v);
2207
                        break;
2208
                    case 8:    // SSHORT
2209
                        if ($count == 0) {
2210
                            $count = $origCount;
2211
                        }
2212
2213
                        $j = 0;
2214
                        while (($j < $count) && ($j < $origCount)) {
2215
                            $this->_putShort($value, $j * 2, $origValue[$j], $isBigEndian);
2216
                            $j++;
2217
                        }
2218
2219
                        while ($j < $count) {
2220
                            $this->_putShort($value, $j * 2, 0, $isBigEndian);
2221
                            $j++;
2222
                        }
2223
                        break;
2224
                    case 9:    // SLONG
2225
                        if ($count == 0) {
2226
                            $count = $origCount;
2227
                        }
2228
2229
                        $j = 0;
2230
                        while (($j < $count) && ($j < $origCount)) {
2231
                            $this->_putLong($value, $j * 4, $origValue[$j], $isBigEndian);
2232
                            $j++;
2233
                        }
2234
2235
                        while ($j < $count) {
2236
                            $this->_putLong($value, $j * 4, 0, $isBigEndian);
2237
                            $j++;
2238
                        }
2239
                        break;
2240
                    case 10:   // SRATIONAL
2241
                        if ($count == 0) {
2242
                            $count = $origCount;
2243
                        }
2244
2245
                        $j = 0;
2246
                        while (($j < $count) && ($j < $origCount)) {
2247
                            $v = $origValue[$j];
2248
                            if (is_array($v)) {
2249
                                $a = $v['num'];
2250
                                $b = $v['den'];
2251
                            }
2252
                            else {
2253
                                $a = 0;
2254
                                $b = 0;
2255
                                // TODO: Allow other types and convert them
2256
                            }
2257
2258
                            $this->_putLong($value, $j * 8, $a, $isBigEndian);
2259
                            $this->_putLong($value, ($j * 8) + 4, $b, $isBigEndian);
2260
                            $j++;
2261
                        }
2262
2263
                        while ($j < $count) {
2264
                            $this->_putLong($value, $j * 8, 0, $isBigEndian);
2265
                            $this->_putLong($value, ($j * 8) + 4, 0, $isBigEndian);
2266
                            $j++;
2267
                        }
2268
                        break;
2269
                    case 11:   // FLOAT
2270
                        if ($count == 0) {
2271
                            $count = $origCount;
2272
                        }
2273
2274
                        $j = 0;
2275
                        while (($j < $count) && ($j < $origCount)) {
2276
                            $v = strval($origValue[$j]);
2277
                            if (strlen($v) > 4) {
2278
                                $v = substr($v, 0, 4);
2279
                            }
2280
                            elseif (strlen($v) < 4) {
2281
                                $v = str_pad($v, 4, "\0");
2282
                            }
2283
                            $this->_putString($value, $j * 4, $v);
2284
                            $j++;
2285
                        }
2286
2287
                        while ($j < $count) {
2288
                            $v = "\0\0\0\0";
2289
                            $this->_putString($value, $j * 4, $v);
2290
                            $j++;
2291
                        }
2292
                        break;
2293
                    case 12:   // DFLOAT
2294
                        if ($count == 0) {
2295
                            $count = $origCount;
2296
                        }
2297
2298
                        $j = 0;
2299
                        while (($j < $count) && ($j < $origCount)) {
2300
                            $v = strval($origValue[$j]);
2301
                            if (strlen($v) > 8) {
2302
                                $v = substr($v, 0, 8);
2303
                            }
2304
                            elseif (strlen($v) < 8) {
2305
                                $v = str_pad($v, 8, "\0");
2306
                            }
2307
                            $this->_putString($value, $j * 8, $v);
2308
                            $j++;
2309
                        }
2310
2311
                        while ($j < $count) {
2312
                            $v = "\0\0\0\0\0\0\0\0";
2313
                            $this->_putString($value, $j * 8, $v);
2314
                            $j++;
2315
                        }
2316
                        break;
2317
                    default:
2318
                        $value = null;
2319
                        break;
2320
                }
2321
            }
2322
2323
            if ($value != null) {
2324
                $ifdEntries[$entryCount] = array();
2325
                $ifdEntries[$entryCount]['tag'] = $tag;
2326
                $ifdEntries[$entryCount]['type'] = $type;
2327
                $ifdEntries[$entryCount]['count'] = $count;
2328
                $ifdEntries[$entryCount]['value'] = $value;
2329
2330
                $entryCount++;
2331
            }
2332
        }
2333
2334
        return $ifdEntries;
2335
    }
2336
2337
    /*************************************************************/
2338
    function _parseMarkerAdobe() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2339
        if (!isset($this->_markers)) {
2340
            $this->_readJPEG();
2341
        }
2342
2343
        if ($this->_markers == null) {
2344
            return false;
2345
        }
2346
2347
        $data = null;
2348
        $count = count($this->_markers);
2349
        for ($i = 0; $i < $count; $i++) {
2350
            if ($this->_markers[$i]['marker'] == 0xED) {
2351
                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 14);
2352
                if ($signature == "Photoshop 3.0\0") {
2353
                    $data =& $this->_markers[$i]['data'];
2354
                    break;
2355
                }
2356
            }
2357
        }
2358
2359
        if ($data == null) {
2360
            $this->_info['adobe'] = false;
2361
            $this->_info['iptc'] = false;
2362
            return false;
2363
        }
2364
        $pos = 14;
2365
        $this->_info['adobe'] = array();
2366
        $this->_info['adobe']['raw'] = array();
2367
        $this->_info['iptc'] = array();
2368
2369
        $datasize = strlen($data);
2370
2371
        while ($pos < $datasize) {
2372
            $signature = $this->_getFixedString($data, $pos, 4);
2373
            if ($signature != '8BIM')
2374
                return false;
2375
            $pos += 4;
2376
2377
            $type = $this->_getShort($data, $pos);
2378
            $pos += 2;
2379
2380
            $strlen = $this->_getByte($data, $pos);
2381
            $pos += 1;
2382
            $header = '';
2383
            for ($i = 0; $i < $strlen; $i++) {
2384
                $header .= $data{$pos + $i};
2385
            }
2386
            $pos += $strlen + 1 - ($strlen % 2);  // The string is padded to even length, counting the length byte itself
2387
2388
            $length = $this->_getLong($data, $pos);
2389
            $pos += 4;
2390
2391
            $basePos = $pos;
2392
2393
            switch ($type) {
2394
                case 0x0404: // Caption (IPTC Data)
2395
                    $pos = $this->_readIPTC($data, $pos);
2396
                    if ($pos == false)
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $pos of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
2397
                        return false;
2398
                    break;
2399
                case 0x040A: // CopyrightFlag
2400
                    $this->_info['adobe']['CopyrightFlag'] = $this->_getByte($data, $pos);
2401
                    $pos += $length;
2402
                    break;
2403
                case 0x040B: // ImageURL
2404
                    $this->_info['adobe']['ImageURL'] = $this->_getFixedString($data, $pos, $length);
2405
                    $pos += $length;
2406
                    break;
2407
                case 0x040C: // Thumbnail
2408
                    $aux = $this->_getLong($data, $pos);
2409
                    $pos += 4;
2410
                    if ($aux == 1) {
2411
                        $this->_info['adobe']['ThumbnailWidth'] = $this->_getLong($data, $pos);
2412
                        $pos += 4;
2413
                        $this->_info['adobe']['ThumbnailHeight'] = $this->_getLong($data, $pos);
2414
                        $pos += 4;
2415
2416
                        $pos += 16; // Skip some data
2417
2418
                        $this->_info['adobe']['ThumbnailData'] = $this->_getFixedString($data, $pos, $length - 28);
2419
                        $pos += $length - 28;
2420
                    }
2421
                    break;
2422
                default:
2423
                    break;
2424
            }
2425
2426
            // We save all blocks, even those we recognized
2427
            $label = sprintf('8BIM_0x%04x', $type);
2428
            $this->_info['adobe']['raw'][$label] = array();
2429
            $this->_info['adobe']['raw'][$label]['type'] = $type;
2430
            $this->_info['adobe']['raw'][$label]['header'] = $header;
2431
            $this->_info['adobe']['raw'][$label]['data'] =& $this->_getFixedString($data, $basePos, $length);
2432
2433
            $pos = $basePos + $length + ($length % 2); // Even padding
2434
        }
2435
2436
    }
2437
2438
    /*************************************************************/
2439
    function _readIPTC(&$data, $pos = 0) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2440
        $totalLength = strlen($data);
2441
2442
        $IPTCTags = $this->_iptcTagNames();
2443
2444
        while ($pos < ($totalLength - 5)) {
2445
            $signature = $this->_getShort($data, $pos);
2446
            if ($signature != 0x1C02)
2447
                return $pos;
2448
            $pos += 2;
2449
2450
            $type = $this->_getByte($data, $pos);
2451
            $pos += 1;
2452
            $length = $this->_getShort($data, $pos);
2453
            $pos += 2;
2454
2455
            $basePos = $pos;
2456
            $label = '';
0 ignored issues
show
Unused Code introduced by
$label is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2457
2458
            if (isset($IPTCTags[$type])) {
2459
                $label = $IPTCTags[$type];
2460
            } else {
2461
                $label = sprintf('IPTC_0x%02x', $type);
2462
            }
2463
2464
            if ($label != '') {
2465
                if (isset($this->_info['iptc'][$label])) {
2466
                    if (!is_array($this->_info['iptc'][$label])) {
2467
                        $aux = array();
2468
                        $aux[0] = $this->_info['iptc'][$label];
2469
                        $this->_info['iptc'][$label] = $aux;
2470
                    }
2471
                    $this->_info['iptc'][$label][ count($this->_info['iptc'][$label]) ] = $this->_getFixedString($data, $pos, $length);
2472
                } else {
2473
                    $this->_info['iptc'][$label] = $this->_getFixedString($data, $pos, $length);
2474
                }
2475
            }
2476
2477
            $pos = $basePos + $length; // No padding
2478
        }
2479
        return $pos;
2480
    }
2481
2482
    /*************************************************************/
2483
    function & _createMarkerAdobe() {
2484
        if (isset($this->_info['iptc'])) {
2485
            if (!isset($this->_info['adobe'])) {
2486
                $this->_info['adobe'] = array();
2487
            }
2488
            if (!isset($this->_info['adobe']['raw'])) {
2489
                $this->_info['adobe']['raw'] = array();
2490
            }
2491
            if (!isset($this->_info['adobe']['raw']['8BIM_0x0404'])) {
2492
                $this->_info['adobe']['raw']['8BIM_0x0404'] = array();
2493
            }
2494
            $this->_info['adobe']['raw']['8BIM_0x0404']['type'] = 0x0404;
2495
            $this->_info['adobe']['raw']['8BIM_0x0404']['header'] = "Caption";
2496
            $this->_info['adobe']['raw']['8BIM_0x0404']['data'] =& $this->_writeIPTC();
2497
        }
2498
2499
        if (isset($this->_info['adobe']['raw']) && (count($this->_info['adobe']['raw']) > 0)) {
2500
            $data = "Photoshop 3.0\0";
2501
            $pos = 14;
2502
2503
            reset($this->_info['adobe']['raw']);
2504
            while (list($key) = each($this->_info['adobe']['raw'])) {
2505
                $pos = $this->_write8BIM(
2506
                        $data,
2507
                        $pos,
2508
                        $this->_info['adobe']['raw'][$key]['type'],
2509
                        $this->_info['adobe']['raw'][$key]['header'],
2510
                        $this->_info['adobe']['raw'][$key]['data'] );
2511
            }
2512
        }
2513
2514
        return $data;
0 ignored issues
show
Bug introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2515
    }
2516
2517
    /*************************************************************/
2518
2519
    /**
2520
     * @param integer $pos
2521
     */
2522
    function _write8BIM(&$data, $pos, $type, $header, &$value) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2523
        $signature = "8BIM";
2524
2525
        $pos = $this->_putString($data, $pos, $signature);
2526
        $pos = $this->_putShort($data, $pos, $type);
2527
2528
        $len = strlen($header);
2529
2530
        $pos = $this->_putByte($data, $pos, $len);
2531
        $pos = $this->_putString($data, $pos, $header);
2532
        if (($len % 2) == 0) {  // Even padding, including the length byte
2533
            $pos = $this->_putByte($data, $pos, 0);
2534
        }
2535
2536
        $len = strlen($value);
2537
        $pos = $this->_putLong($data, $pos, $len);
2538
        $pos = $this->_putString($data, $pos, $value);
2539
        if (($len % 2) != 0) {  // Even padding
2540
            $pos = $this->_putByte($data, $pos, 0);
2541
        }
2542
        return $pos;
2543
    }
2544
2545
    /*************************************************************/
2546
    function & _writeIPTC() {
2547
        $data = " ";
2548
        $pos = 0;
2549
2550
        $IPTCNames =& $this->_iptcNameTags();
2551
2552
        reset($this->_info['iptc']);
2553
2554
        while (list($label) = each($this->_info['iptc'])) {
2555
            $value =& $this->_info['iptc'][$label];
2556
            $type = -1;
2557
2558
            if (isset($IPTCNames[$label])) {
2559
                $type = $IPTCNames[$label];
2560
            }
2561
            elseif (substr($label, 0, 7) == "IPTC_0x") {
2562
                $type = hexdec(substr($label, 7, 2));
2563
            }
2564
2565
            if ($type != -1) {
2566
                if (is_array($value)) {
2567
                    $vcnt = count($value);
2568
                    for ($i = 0; $i < $vcnt; $i++) {
2569
                        $pos = $this->_writeIPTCEntry($data, $pos, $type, $value[$i]);
2570
                    }
2571
                }
2572
                else {
2573
                    $pos = $this->_writeIPTCEntry($data, $pos, $type, $value);
2574
                }
2575
            }
2576
        }
2577
2578
        return $data;
2579
    }
2580
2581
    /*************************************************************/
2582
2583
    /**
2584
     * @param integer $pos
2585
     */
2586
    function _writeIPTCEntry(&$data, $pos, $type, &$value) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2587
        $pos = $this->_putShort($data, $pos, 0x1C02);
2588
        $pos = $this->_putByte($data, $pos, $type);
2589
        $pos = $this->_putShort($data, $pos, strlen($value));
2590
        $pos = $this->_putString($data, $pos, $value);
2591
2592
        return $pos;
2593
    }
2594
2595
    /*************************************************************/
2596
    function _exifTagNames($mode) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2597
        $tags = array();
2598
2599
        if ($mode == 'ifd0') {
2600
            $tags[0x010E] = 'ImageDescription';
2601
            $tags[0x010F] = 'Make';
2602
            $tags[0x0110] = 'Model';
2603
            $tags[0x0112] = 'Orientation';
2604
            $tags[0x011A] = 'XResolution';
2605
            $tags[0x011B] = 'YResolution';
2606
            $tags[0x0128] = 'ResolutionUnit';
2607
            $tags[0x0131] = 'Software';
2608
            $tags[0x0132] = 'DateTime';
2609
            $tags[0x013B] = 'Artist';
2610
            $tags[0x013E] = 'WhitePoint';
2611
            $tags[0x013F] = 'PrimaryChromaticities';
2612
            $tags[0x0211] = 'YCbCrCoefficients';
2613
            $tags[0x0212] = 'YCbCrSubSampling';
2614
            $tags[0x0213] = 'YCbCrPositioning';
2615
            $tags[0x0214] = 'ReferenceBlackWhite';
2616
            $tags[0x8298] = 'Copyright';
2617
            $tags[0x8769] = 'ExifIFDOffset';
2618
            $tags[0x8825] = 'GPSIFDOffset';
2619
        }
2620
        if ($mode == 'ifd1') {
2621
            $tags[0x00FE] = 'TIFFNewSubfileType';
2622
            $tags[0x00FF] = 'TIFFSubfileType';
2623
            $tags[0x0100] = 'TIFFImageWidth';
2624
            $tags[0x0101] = 'TIFFImageHeight';
2625
            $tags[0x0102] = 'TIFFBitsPerSample';
2626
            $tags[0x0103] = 'TIFFCompression';
2627
            $tags[0x0106] = 'TIFFPhotometricInterpretation';
2628
            $tags[0x0107] = 'TIFFThreshholding';
2629
            $tags[0x0108] = 'TIFFCellWidth';
2630
            $tags[0x0109] = 'TIFFCellLength';
2631
            $tags[0x010A] = 'TIFFFillOrder';
2632
            $tags[0x010E] = 'TIFFImageDescription';
2633
            $tags[0x010F] = 'TIFFMake';
2634
            $tags[0x0110] = 'TIFFModel';
2635
            $tags[0x0111] = 'TIFFStripOffsets';
2636
            $tags[0x0112] = 'TIFFOrientation';
2637
            $tags[0x0115] = 'TIFFSamplesPerPixel';
2638
            $tags[0x0116] = 'TIFFRowsPerStrip';
2639
            $tags[0x0117] = 'TIFFStripByteCounts';
2640
            $tags[0x0118] = 'TIFFMinSampleValue';
2641
            $tags[0x0119] = 'TIFFMaxSampleValue';
2642
            $tags[0x011A] = 'TIFFXResolution';
2643
            $tags[0x011B] = 'TIFFYResolution';
2644
            $tags[0x011C] = 'TIFFPlanarConfiguration';
2645
            $tags[0x0122] = 'TIFFGrayResponseUnit';
2646
            $tags[0x0123] = 'TIFFGrayResponseCurve';
2647
            $tags[0x0128] = 'TIFFResolutionUnit';
2648
            $tags[0x0131] = 'TIFFSoftware';
2649
            $tags[0x0132] = 'TIFFDateTime';
2650
            $tags[0x013B] = 'TIFFArtist';
2651
            $tags[0x013C] = 'TIFFHostComputer';
2652
            $tags[0x0140] = 'TIFFColorMap';
2653
            $tags[0x0152] = 'TIFFExtraSamples';
2654
            $tags[0x0201] = 'TIFFJFIFOffset';
2655
            $tags[0x0202] = 'TIFFJFIFLength';
2656
            $tags[0x0211] = 'TIFFYCbCrCoefficients';
2657
            $tags[0x0212] = 'TIFFYCbCrSubSampling';
2658
            $tags[0x0213] = 'TIFFYCbCrPositioning';
2659
            $tags[0x0214] = 'TIFFReferenceBlackWhite';
2660
            $tags[0x8298] = 'TIFFCopyright';
2661
            $tags[0x9286] = 'TIFFUserComment';
2662
        } elseif ($mode == 'exif') {
2663
            $tags[0x829A] = 'ExposureTime';
2664
            $tags[0x829D] = 'FNumber';
2665
            $tags[0x8822] = 'ExposureProgram';
2666
            $tags[0x8824] = 'SpectralSensitivity';
2667
            $tags[0x8827] = 'ISOSpeedRatings';
2668
            $tags[0x8828] = 'OECF';
2669
            $tags[0x9000] = 'EXIFVersion';
2670
            $tags[0x9003] = 'DatetimeOriginal';
2671
            $tags[0x9004] = 'DatetimeDigitized';
2672
            $tags[0x9101] = 'ComponentsConfiguration';
2673
            $tags[0x9102] = 'CompressedBitsPerPixel';
2674
            $tags[0x9201] = 'ShutterSpeedValue';
2675
            $tags[0x9202] = 'ApertureValue';
2676
            $tags[0x9203] = 'BrightnessValue';
2677
            $tags[0x9204] = 'ExposureBiasValue';
2678
            $tags[0x9205] = 'MaxApertureValue';
2679
            $tags[0x9206] = 'SubjectDistance';
2680
            $tags[0x9207] = 'MeteringMode';
2681
            $tags[0x9208] = 'LightSource';
2682
            $tags[0x9209] = 'Flash';
2683
            $tags[0x920A] = 'FocalLength';
2684
            $tags[0x927C] = 'MakerNote';
2685
            $tags[0x9286] = 'UserComment';
2686
            $tags[0x9290] = 'SubSecTime';
2687
            $tags[0x9291] = 'SubSecTimeOriginal';
2688
            $tags[0x9292] = 'SubSecTimeDigitized';
2689
            $tags[0xA000] = 'FlashPixVersion';
2690
            $tags[0xA001] = 'ColorSpace';
2691
            $tags[0xA002] = 'PixelXDimension';
2692
            $tags[0xA003] = 'PixelYDimension';
2693
            $tags[0xA004] = 'RelatedSoundFile';
2694
            $tags[0xA005] = 'InteropIFDOffset';
2695
            $tags[0xA20B] = 'FlashEnergy';
2696
            $tags[0xA20C] = 'SpatialFrequencyResponse';
2697
            $tags[0xA20E] = 'FocalPlaneXResolution';
2698
            $tags[0xA20F] = 'FocalPlaneYResolution';
2699
            $tags[0xA210] = 'FocalPlaneResolutionUnit';
2700
            $tags[0xA214] = 'SubjectLocation';
2701
            $tags[0xA215] = 'ExposureIndex';
2702
            $tags[0xA217] = 'SensingMethod';
2703
            $tags[0xA300] = 'FileSource';
2704
            $tags[0xA301] = 'SceneType';
2705
            $tags[0xA302] = 'CFAPattern';
2706
        } elseif ($mode == 'interop') {
2707
            $tags[0x0001] = 'InteroperabilityIndex';
2708
            $tags[0x0002] = 'InteroperabilityVersion';
2709
            $tags[0x1000] = 'RelatedImageFileFormat';
2710
            $tags[0x1001] = 'RelatedImageWidth';
2711
            $tags[0x1002] = 'RelatedImageLength';
2712
        } elseif ($mode == 'gps') {
2713
            $tags[0x0000] = 'GPSVersionID';
2714
            $tags[0x0001] = 'GPSLatitudeRef';
2715
            $tags[0x0002] = 'GPSLatitude';
2716
            $tags[0x0003] = 'GPSLongitudeRef';
2717
            $tags[0x0004] = 'GPSLongitude';
2718
            $tags[0x0005] = 'GPSAltitudeRef';
2719
            $tags[0x0006] = 'GPSAltitude';
2720
            $tags[0x0007] = 'GPSTimeStamp';
2721
            $tags[0x0008] = 'GPSSatellites';
2722
            $tags[0x0009] = 'GPSStatus';
2723
            $tags[0x000A] = 'GPSMeasureMode';
2724
            $tags[0x000B] = 'GPSDOP';
2725
            $tags[0x000C] = 'GPSSpeedRef';
2726
            $tags[0x000D] = 'GPSSpeed';
2727
            $tags[0x000E] = 'GPSTrackRef';
2728
            $tags[0x000F] = 'GPSTrack';
2729
            $tags[0x0010] = 'GPSImgDirectionRef';
2730
            $tags[0x0011] = 'GPSImgDirection';
2731
            $tags[0x0012] = 'GPSMapDatum';
2732
            $tags[0x0013] = 'GPSDestLatitudeRef';
2733
            $tags[0x0014] = 'GPSDestLatitude';
2734
            $tags[0x0015] = 'GPSDestLongitudeRef';
2735
            $tags[0x0016] = 'GPSDestLongitude';
2736
            $tags[0x0017] = 'GPSDestBearingRef';
2737
            $tags[0x0018] = 'GPSDestBearing';
2738
            $tags[0x0019] = 'GPSDestDistanceRef';
2739
            $tags[0x001A] = 'GPSDestDistance';
2740
        }
2741
2742
        return $tags;
2743
    }
2744
2745
    /*************************************************************/
2746
    function _exifTagTypes($mode) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2747
        $tags = array();
2748
2749
        if ($mode == 'ifd0') {
2750
            $tags[0x010E] = array(2, 0); // ImageDescription -> ASCII, Any
2751
            $tags[0x010F] = array(2, 0); // Make -> ASCII, Any
2752
            $tags[0x0110] = array(2, 0); // Model -> ASCII, Any
2753
            $tags[0x0112] = array(3, 1); // Orientation -> SHORT, 1
2754
            $tags[0x011A] = array(5, 1); // XResolution -> RATIONAL, 1
2755
            $tags[0x011B] = array(5, 1); // YResolution -> RATIONAL, 1
2756
            $tags[0x0128] = array(3, 1); // ResolutionUnit -> SHORT
2757
            $tags[0x0131] = array(2, 0); // Software -> ASCII, Any
2758
            $tags[0x0132] = array(2, 20); // DateTime -> ASCII, 20
2759
            $tags[0x013B] = array(2, 0); // Artist -> ASCII, Any
2760
            $tags[0x013E] = array(5, 2); // WhitePoint -> RATIONAL, 2
2761
            $tags[0x013F] = array(5, 6); // PrimaryChromaticities -> RATIONAL, 6
2762
            $tags[0x0211] = array(5, 3); // YCbCrCoefficients -> RATIONAL, 3
2763
            $tags[0x0212] = array(3, 2); // YCbCrSubSampling -> SHORT, 2
2764
            $tags[0x0213] = array(3, 1); // YCbCrPositioning -> SHORT, 1
2765
            $tags[0x0214] = array(5, 6); // ReferenceBlackWhite -> RATIONAL, 6
2766
            $tags[0x8298] = array(2, 0); // Copyright -> ASCII, Any
2767
            $tags[0x8769] = array(4, 1); // ExifIFDOffset -> LONG, 1
2768
            $tags[0x8825] = array(4, 1); // GPSIFDOffset -> LONG, 1
2769
        }
2770
        if ($mode == 'ifd1') {
2771
            $tags[0x00FE] = array(4, 1); // TIFFNewSubfileType -> LONG, 1
2772
            $tags[0x00FF] = array(3, 1); // TIFFSubfileType -> SHORT, 1
2773
            $tags[0x0100] = array(4, 1); // TIFFImageWidth -> LONG (or SHORT), 1
2774
            $tags[0x0101] = array(4, 1); // TIFFImageHeight -> LONG (or SHORT), 1
2775
            $tags[0x0102] = array(3, 3); // TIFFBitsPerSample -> SHORT, 3
2776
            $tags[0x0103] = array(3, 1); // TIFFCompression -> SHORT, 1
2777
            $tags[0x0106] = array(3, 1); // TIFFPhotometricInterpretation -> SHORT, 1
2778
            $tags[0x0107] = array(3, 1); // TIFFThreshholding -> SHORT, 1
2779
            $tags[0x0108] = array(3, 1); // TIFFCellWidth -> SHORT, 1
2780
            $tags[0x0109] = array(3, 1); // TIFFCellLength -> SHORT, 1
2781
            $tags[0x010A] = array(3, 1); // TIFFFillOrder -> SHORT, 1
2782
            $tags[0x010E] = array(2, 0); // TIFFImageDescription -> ASCII, Any
2783
            $tags[0x010F] = array(2, 0); // TIFFMake -> ASCII, Any
2784
            $tags[0x0110] = array(2, 0); // TIFFModel -> ASCII, Any
2785
            $tags[0x0111] = array(4, 0); // TIFFStripOffsets -> LONG (or SHORT), Any (one per strip)
2786
            $tags[0x0112] = array(3, 1); // TIFFOrientation -> SHORT, 1
2787
            $tags[0x0115] = array(3, 1); // TIFFSamplesPerPixel -> SHORT, 1
2788
            $tags[0x0116] = array(4, 1); // TIFFRowsPerStrip -> LONG (or SHORT), 1
2789
            $tags[0x0117] = array(4, 0); // TIFFStripByteCounts -> LONG (or SHORT), Any (one per strip)
2790
            $tags[0x0118] = array(3, 0); // TIFFMinSampleValue -> SHORT, Any (SamplesPerPixel)
2791
            $tags[0x0119] = array(3, 0); // TIFFMaxSampleValue -> SHORT, Any (SamplesPerPixel)
2792
            $tags[0x011A] = array(5, 1); // TIFFXResolution -> RATIONAL, 1
2793
            $tags[0x011B] = array(5, 1); // TIFFYResolution -> RATIONAL, 1
2794
            $tags[0x011C] = array(3, 1); // TIFFPlanarConfiguration -> SHORT, 1
2795
            $tags[0x0122] = array(3, 1); // TIFFGrayResponseUnit -> SHORT, 1
2796
            $tags[0x0123] = array(3, 0); // TIFFGrayResponseCurve -> SHORT, Any (2^BitsPerSample)
2797
            $tags[0x0128] = array(3, 1); // TIFFResolutionUnit -> SHORT, 1
2798
            $tags[0x0131] = array(2, 0); // TIFFSoftware -> ASCII, Any
2799
            $tags[0x0132] = array(2, 20); // TIFFDateTime -> ASCII, 20
2800
            $tags[0x013B] = array(2, 0); // TIFFArtist -> ASCII, Any
2801
            $tags[0x013C] = array(2, 0); // TIFFHostComputer -> ASCII, Any
2802
            $tags[0x0140] = array(3, 0); // TIFFColorMap -> SHORT, Any (3 * 2^BitsPerSample)
2803
            $tags[0x0152] = array(3, 0); // TIFFExtraSamples -> SHORT, Any (SamplesPerPixel - 3)
2804
            $tags[0x0201] = array(4, 1); // TIFFJFIFOffset -> LONG, 1
2805
            $tags[0x0202] = array(4, 1); // TIFFJFIFLength -> LONG, 1
2806
            $tags[0x0211] = array(5, 3); // TIFFYCbCrCoefficients -> RATIONAL, 3
2807
            $tags[0x0212] = array(3, 2); // TIFFYCbCrSubSampling -> SHORT, 2
2808
            $tags[0x0213] = array(3, 1); // TIFFYCbCrPositioning -> SHORT, 1
2809
            $tags[0x0214] = array(5, 6); // TIFFReferenceBlackWhite -> RATIONAL, 6
2810
            $tags[0x8298] = array(2, 0); // TIFFCopyright -> ASCII, Any
2811
            $tags[0x9286] = array(2, 0); // TIFFUserComment -> ASCII, Any
2812
        } elseif ($mode == 'exif') {
2813
            $tags[0x829A] = array(5, 1); // ExposureTime -> RATIONAL, 1
2814
            $tags[0x829D] = array(5, 1); // FNumber -> RATIONAL, 1
2815
            $tags[0x8822] = array(3, 1); // ExposureProgram -> SHORT, 1
2816
            $tags[0x8824] = array(2, 0); // SpectralSensitivity -> ASCII, Any
2817
            $tags[0x8827] = array(3, 0); // ISOSpeedRatings -> SHORT, Any
2818
            $tags[0x8828] = array(7, 0); // OECF -> UNDEFINED, Any
2819
            $tags[0x9000] = array(7, 4); // EXIFVersion -> UNDEFINED, 4
2820
            $tags[0x9003] = array(2, 20); // DatetimeOriginal -> ASCII, 20
2821
            $tags[0x9004] = array(2, 20); // DatetimeDigitized -> ASCII, 20
2822
            $tags[0x9101] = array(7, 4); // ComponentsConfiguration -> UNDEFINED, 4
2823
            $tags[0x9102] = array(5, 1); // CompressedBitsPerPixel -> RATIONAL, 1
2824
            $tags[0x9201] = array(10, 1); // ShutterSpeedValue -> SRATIONAL, 1
2825
            $tags[0x9202] = array(5, 1); // ApertureValue -> RATIONAL, 1
2826
            $tags[0x9203] = array(10, 1); // BrightnessValue -> SRATIONAL, 1
2827
            $tags[0x9204] = array(10, 1); // ExposureBiasValue -> SRATIONAL, 1
2828
            $tags[0x9205] = array(5, 1); // MaxApertureValue -> RATIONAL, 1
2829
            $tags[0x9206] = array(5, 1); // SubjectDistance -> RATIONAL, 1
2830
            $tags[0x9207] = array(3, 1); // MeteringMode -> SHORT, 1
2831
            $tags[0x9208] = array(3, 1); // LightSource -> SHORT, 1
2832
            $tags[0x9209] = array(3, 1); // Flash -> SHORT, 1
2833
            $tags[0x920A] = array(5, 1); // FocalLength -> RATIONAL, 1
2834
            $tags[0x927C] = array(7, 0); // MakerNote -> UNDEFINED, Any
2835
            $tags[0x9286] = array(7, 0); // UserComment -> UNDEFINED, Any
2836
            $tags[0x9290] = array(2, 0); // SubSecTime -> ASCII, Any
2837
            $tags[0x9291] = array(2, 0); // SubSecTimeOriginal -> ASCII, Any
2838
            $tags[0x9292] = array(2, 0); // SubSecTimeDigitized -> ASCII, Any
2839
            $tags[0xA000] = array(7, 4); // FlashPixVersion -> UNDEFINED, 4
2840
            $tags[0xA001] = array(3, 1); // ColorSpace -> SHORT, 1
2841
            $tags[0xA002] = array(4, 1); // PixelXDimension -> LONG (or SHORT), 1
2842
            $tags[0xA003] = array(4, 1); // PixelYDimension -> LONG (or SHORT), 1
2843
            $tags[0xA004] = array(2, 13); // RelatedSoundFile -> ASCII, 13
2844
            $tags[0xA005] = array(4, 1); // InteropIFDOffset -> LONG, 1
2845
            $tags[0xA20B] = array(5, 1); // FlashEnergy -> RATIONAL, 1
2846
            $tags[0xA20C] = array(7, 0); // SpatialFrequencyResponse -> UNDEFINED, Any
2847
            $tags[0xA20E] = array(5, 1); // FocalPlaneXResolution -> RATIONAL, 1
2848
            $tags[0xA20F] = array(5, 1); // FocalPlaneYResolution -> RATIONAL, 1
2849
            $tags[0xA210] = array(3, 1); // FocalPlaneResolutionUnit -> SHORT, 1
2850
            $tags[0xA214] = array(3, 2); // SubjectLocation -> SHORT, 2
2851
            $tags[0xA215] = array(5, 1); // ExposureIndex -> RATIONAL, 1
2852
            $tags[0xA217] = array(3, 1); // SensingMethod -> SHORT, 1
2853
            $tags[0xA300] = array(7, 1); // FileSource -> UNDEFINED, 1
2854
            $tags[0xA301] = array(7, 1); // SceneType -> UNDEFINED, 1
2855
            $tags[0xA302] = array(7, 0); // CFAPattern -> UNDEFINED, Any
2856
        } elseif ($mode == 'interop') {
2857
            $tags[0x0001] = array(2, 0); // InteroperabilityIndex -> ASCII, Any
2858
            $tags[0x0002] = array(7, 4); // InteroperabilityVersion -> UNKNOWN, 4
2859
            $tags[0x1000] = array(2, 0); // RelatedImageFileFormat -> ASCII, Any
2860
            $tags[0x1001] = array(4, 1); // RelatedImageWidth -> LONG (or SHORT), 1
2861
            $tags[0x1002] = array(4, 1); // RelatedImageLength -> LONG (or SHORT), 1
2862
        } elseif ($mode == 'gps') {
2863
            $tags[0x0000] = array(1, 4); // GPSVersionID -> BYTE, 4
2864
            $tags[0x0001] = array(2, 2); // GPSLatitudeRef -> ASCII, 2
2865
            $tags[0x0002] = array(5, 3); // GPSLatitude -> RATIONAL, 3
2866
            $tags[0x0003] = array(2, 2); // GPSLongitudeRef -> ASCII, 2
2867
            $tags[0x0004] = array(5, 3); // GPSLongitude -> RATIONAL, 3
2868
            $tags[0x0005] = array(2, 2); // GPSAltitudeRef -> ASCII, 2
2869
            $tags[0x0006] = array(5, 1); // GPSAltitude -> RATIONAL, 1
2870
            $tags[0x0007] = array(5, 3); // GPSTimeStamp -> RATIONAL, 3
2871
            $tags[0x0008] = array(2, 0); // GPSSatellites -> ASCII, Any
2872
            $tags[0x0009] = array(2, 2); // GPSStatus -> ASCII, 2
2873
            $tags[0x000A] = array(2, 2); // GPSMeasureMode -> ASCII, 2
2874
            $tags[0x000B] = array(5, 1); // GPSDOP -> RATIONAL, 1
2875
            $tags[0x000C] = array(2, 2); // GPSSpeedRef -> ASCII, 2
2876
            $tags[0x000D] = array(5, 1); // GPSSpeed -> RATIONAL, 1
2877
            $tags[0x000E] = array(2, 2); // GPSTrackRef -> ASCII, 2
2878
            $tags[0x000F] = array(5, 1); // GPSTrack -> RATIONAL, 1
2879
            $tags[0x0010] = array(2, 2); // GPSImgDirectionRef -> ASCII, 2
2880
            $tags[0x0011] = array(5, 1); // GPSImgDirection -> RATIONAL, 1
2881
            $tags[0x0012] = array(2, 0); // GPSMapDatum -> ASCII, Any
2882
            $tags[0x0013] = array(2, 2); // GPSDestLatitudeRef -> ASCII, 2
2883
            $tags[0x0014] = array(5, 3); // GPSDestLatitude -> RATIONAL, 3
2884
            $tags[0x0015] = array(2, 2); // GPSDestLongitudeRef -> ASCII, 2
2885
            $tags[0x0016] = array(5, 3); // GPSDestLongitude -> RATIONAL, 3
2886
            $tags[0x0017] = array(2, 2); // GPSDestBearingRef -> ASCII, 2
2887
            $tags[0x0018] = array(5, 1); // GPSDestBearing -> RATIONAL, 1
2888
            $tags[0x0019] = array(2, 2); // GPSDestDistanceRef -> ASCII, 2
2889
            $tags[0x001A] = array(5, 1); // GPSDestDistance -> RATIONAL, 1
2890
        }
2891
2892
        return $tags;
2893
    }
2894
2895
    /*************************************************************/
2896
    function _exifNameTags($mode) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2897
        $tags = $this->_exifTagNames($mode);
2898
        return $this->_names2Tags($tags);
2899
    }
2900
2901
    /*************************************************************/
2902
    function _iptcTagNames() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2903
        $tags = array();
2904
        $tags[0x14] = 'SuplementalCategories';
2905
        $tags[0x19] = 'Keywords';
2906
        $tags[0x78] = 'Caption';
2907
        $tags[0x7A] = 'CaptionWriter';
2908
        $tags[0x69] = 'Headline';
2909
        $tags[0x28] = 'SpecialInstructions';
2910
        $tags[0x0F] = 'Category';
2911
        $tags[0x50] = 'Byline';
2912
        $tags[0x55] = 'BylineTitle';
2913
        $tags[0x6E] = 'Credit';
2914
        $tags[0x73] = 'Source';
2915
        $tags[0x74] = 'CopyrightNotice';
2916
        $tags[0x05] = 'ObjectName';
2917
        $tags[0x5A] = 'City';
2918
        $tags[0x5C] = 'Sublocation';
2919
        $tags[0x5F] = 'ProvinceState';
2920
        $tags[0x65] = 'CountryName';
2921
        $tags[0x67] = 'OriginalTransmissionReference';
2922
        $tags[0x37] = 'DateCreated';
2923
        $tags[0x0A] = 'CopyrightFlag';
2924
2925
        return $tags;
2926
    }
2927
2928
    /*************************************************************/
2929
    function & _iptcNameTags() {
2930
        $tags = $this->_iptcTagNames();
2931
        return $this->_names2Tags($tags);
2932
    }
2933
2934
    /*************************************************************/
2935
    function _names2Tags($tags2Names) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2936
        $names2Tags = array();
2937
        reset($tags2Names);
2938
        while (list($tag, $name) = each($tags2Names)) {
2939
            $names2Tags[$name] = $tag;
2940
        }
2941
2942
        return $names2Tags;
2943
    }
2944
2945
    /*************************************************************/
2946
2947
    /**
2948
     * @param integer $pos
2949
     */
2950
    function _getByte(&$data, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2951
        return ord($data{$pos});
2952
    }
2953
2954
    /*************************************************************/
2955
2956
    /**
2957
     * @param integer $pos
2958
     */
2959
    function _putByte(&$data, $pos, $val) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2960
        $val = intval($val);
2961
2962
        $data{$pos} = chr($val);
2963
2964
        return $pos + 1;
2965
    }
2966
2967
    /*************************************************************/
2968
    function _getShort(&$data, $pos, $bigEndian = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2969
        if ($bigEndian) {
2970
            return (ord($data{$pos}) << 8)
2971
                + ord($data{$pos + 1});
2972
        } else {
2973
            return ord($data{$pos})
2974
                + (ord($data{$pos + 1}) << 8);
2975
        }
2976
    }
2977
2978
    /*************************************************************/
2979
    function _putShort(&$data, $pos = 0, $val = 0, $bigEndian = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2980
        $val = intval($val);
2981
2982
        if ($bigEndian) {
2983
            $data{$pos + 0} = chr(($val & 0x0000FF00) >> 8);
2984
            $data{$pos + 1} = chr(($val & 0x000000FF) >> 0);
2985
        } else {
2986
            $data{$pos + 0} = chr(($val & 0x00FF) >> 0);
2987
            $data{$pos + 1} = chr(($val & 0xFF00) >> 8);
2988
        }
2989
2990
        return $pos + 2;
2991
    }
2992
2993
    /*************************************************************/
2994
2995
    /**
2996
     * @param integer $pos
2997
     */
2998
    function _getLong(&$data, $pos, $bigEndian = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2999
        if ($bigEndian) {
3000
            return (ord($data{$pos}) << 24)
3001
                + (ord($data{$pos + 1}) << 16)
3002
                + (ord($data{$pos + 2}) << 8)
3003
                + ord($data{$pos + 3});
3004
        } else {
3005
            return ord($data{$pos})
3006
                + (ord($data{$pos + 1}) << 8)
3007
                + (ord($data{$pos + 2}) << 16)
3008
                + (ord($data{$pos + 3}) << 24);
3009
        }
3010
    }
3011
3012
    /*************************************************************/
3013
3014
    /**
3015
     * @param integer $pos
3016
     */
3017
    function _putLong(&$data, $pos, $val, $bigEndian = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3018
        $val = intval($val);
3019
3020
        if ($bigEndian) {
3021
            $data{$pos + 0} = chr(($val & 0xFF000000) >> 24);
3022
            $data{$pos + 1} = chr(($val & 0x00FF0000) >> 16);
3023
            $data{$pos + 2} = chr(($val & 0x0000FF00) >> 8);
3024
            $data{$pos + 3} = chr(($val & 0x000000FF) >> 0);
3025
        } else {
3026
            $data{$pos + 0} = chr(($val & 0x000000FF) >> 0);
3027
            $data{$pos + 1} = chr(($val & 0x0000FF00) >> 8);
3028
            $data{$pos + 2} = chr(($val & 0x00FF0000) >> 16);
3029
            $data{$pos + 3} = chr(($val & 0xFF000000) >> 24);
3030
        }
3031
3032
        return $pos + 4;
3033
    }
3034
3035
    /*************************************************************/
3036
    function & _getNullString(&$data, $pos) {
3037
        $str = '';
3038
        $max = strlen($data);
3039
3040
        while ($pos < $max) {
3041
            if (ord($data{$pos}) == 0) {
3042
                return $str;
3043
            } else {
3044
                $str .= $data{$pos};
3045
            }
3046
            $pos++;
3047
        }
3048
3049
        return $str;
3050
    }
3051
3052
    /*************************************************************/
3053
    function & _getFixedString(&$data, $pos, $length = -1) {
3054
        if ($length == -1) {
3055
            $length = strlen($data) - $pos;
3056
        }
3057
3058
        $rv = substr($data, $pos, $length);
3059
        return $rv;
3060
    }
3061
3062
    /*************************************************************/
3063
    function _putString(&$data, $pos, &$str) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3064
        $len = strlen($str);
3065
        for ($i = 0; $i < $len; $i++) {
3066
            $data{$pos + $i} = $str{$i};
3067
        }
3068
3069
        return $pos + $len;
3070
    }
3071
3072
    /*************************************************************/
3073
    function _hexDump(&$data, $start = 0, $length = -1) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3074
        if (($length == -1) || (($length + $start) > strlen($data))) {
3075
            $end = strlen($data);
3076
        } else {
3077
            $end = $start + $length;
3078
        }
3079
3080
        $ascii = '';
3081
        $count = 0;
3082
3083
        echo "<tt>\n";
3084
3085
        while ($start < $end) {
3086
            if (($count % 16) == 0) {
3087
                echo sprintf('%04d', $count) . ': ';
3088
            }
3089
3090
            $c = ord($data{$start});
3091
            $count++;
3092
            $start++;
3093
3094
            $aux = dechex($c);
3095
            if (strlen($aux) == 1)
3096
                echo '0';
3097
            echo $aux . ' ';
3098
3099
            if ($c == 60)
3100
                $ascii .= '&lt;';
3101
            elseif ($c == 62)
3102
                $ascii .= '&gt;';
3103
            elseif ($c == 32)
3104
                $ascii .= '&#160;';
3105
            elseif ($c > 32)
3106
                $ascii .= chr($c);
3107
            else
3108
                $ascii .= '.';
3109
3110
            if (($count % 4) == 0) {
3111
                echo ' - ';
3112
            }
3113
3114
            if (($count % 16) == 0) {
3115
                echo ': ' . $ascii . "<br>\n";
3116
                $ascii = '';
3117
            }
3118
        }
3119
3120
        if ($ascii != '') {
3121
            while (($count % 16) != 0) {
3122
                echo '-- ';
3123
                $count++;
3124
                if (($count % 4) == 0) {
3125
                    echo ' - ';
3126
                }
3127
            }
3128
            echo ': ' . $ascii . "<br>\n";
3129
        }
3130
3131
        echo "</tt>\n";
3132
    }
3133
3134
    /*****************************************************************/
3135
}
3136
3137
/* vim: set expandtab tabstop=4 shiftwidth=4: */
3138