Completed
Push — master ( b3b676...8fdc21 )
by Alexey
06:06 queued 11s
created

OldUnixExtraField::getModifyDateTime()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3.576

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 5
nc 4
nop 0
dl 0
loc 7
ccs 3
cts 5
cp 0.6
crap 3.576
rs 10
c 1
b 0
f 1
1
<?php
2
3
namespace PhpZip\Model\Extra\Fields;
4
5
use PhpZip\Model\Extra\ZipExtraField;
6
use PhpZip\Model\ZipEntry;
7
8
/**
9
 * Info-ZIP Unix Extra Field (type 1):
10
 * ==================================.
11
 *
12
 * The following is the layout of the old Info-ZIP extra block for
13
 * Unix.  It has been replaced by the extended-timestamp extra block
14
 * (0x5455) and the Unix type 2 extra block (0x7855).
15
 * (Last Revision 19970118)
16
 *
17
 * Local-header version:
18
 *
19
 * Value         Size        Description
20
 * -----         ----        -----------
21
 * (Unix1) 0x5855        Short       tag for this extra block type ("UX")
22
 * TSize         Short       total data size for this block
23
 * AcTime        Long        time of last access (UTC/GMT)
24
 * ModTime       Long        time of last modification (UTC/GMT)
25
 * UID           Short       Unix user ID (optional)
26
 * GID           Short       Unix group ID (optional)
27
 *
28
 * Central-header version:
29
 *
30
 * Value         Size        Description
31
 * -----         ----        -----------
32
 * (Unix1) 0x5855        Short       tag for this extra block type ("UX")
33
 * TSize         Short       total data size for this block
34
 * AcTime        Long        time of last access (GMT/UTC)
35
 * ModTime       Long        time of last modification (GMT/UTC)
36
 *
37
 * The file access and modification times are in standard Unix signed-
38
 * long format, indicating the number of seconds since 1 January 1970
39
 * 00:00:00.  The times are relative to Coordinated Universal Time
40
 * (UTC), also sometimes referred to as Greenwich Mean Time (GMT).  To
41
 * convert to local time, the software must know the local timezone
42
 * offset from UTC/GMT.  The modification time may be used by non-Unix
43
 * systems to support inter-timezone freshening and updating of zip
44
 * archives.
45
 *
46
 * The local-header extra block may optionally contain UID and GID
47
 * info for the file.  The local-header TSize value is the only
48
 * indication of this.  Note that Unix UIDs and GIDs are usually
49
 * specific to a particular machine, and they generally require root
50
 * access to restore.
51
 *
52
 * This extra field type is obsolete, but it has been in use since
53
 * mid-1994. Therefore future archiving software should continue to
54
 * support it.
55
 */
56
class OldUnixExtraField implements ZipExtraField
57
{
58
    /** @var int Header id */
59
    const HEADER_ID = 0x5855;
60
61
    /** @var int|null Access timestamp */
62
    private $accessTime;
63
64
    /** @var int|null Modify timestamp */
65
    private $modifyTime;
66
67
    /** @var int|null User id */
68
    private $uid;
69
70
    /** @var int|null Group id */
71
    private $gid;
72
73
    /**
74
     * @param int|null $accessTime
75
     * @param int|null $modifyTime
76
     * @param int|null $uid
77
     * @param int|null $gid
78
     */
79 5
    public function __construct($accessTime, $modifyTime, $uid, $gid)
80
    {
81 5
        $this->accessTime = $accessTime;
82 5
        $this->modifyTime = $modifyTime;
83 5
        $this->uid = $uid;
84 5
        $this->gid = $gid;
85 5
    }
86
87
    /**
88
     * Returns the Header ID (type) of this Extra Field.
89
     * The Header ID is an unsigned short integer (two bytes)
90
     * which must be constant during the life cycle of this object.
91
     *
92
     * @return int
93
     */
94 7
    public function getHeaderId()
95
    {
96 7
        return self::HEADER_ID;
97
    }
98
99
    /**
100
     * Populate data from this array as if it was in local file data.
101
     *
102
     * @param string        $buffer the buffer to read data from
103
     * @param ZipEntry|null $entry
104
     *
105
     * @return OldUnixExtraField
106
     */
107 4
    public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
108
    {
109 4
        $length = \strlen($buffer);
110
111 4
        $accessTime = $modifyTime = $uid = $gid = null;
112
113 4
        if ($length >= 4) {
114 3
            $accessTime = unpack('V', $buffer)[1];
115
        }
116
117 4
        if ($length >= 8) {
118 3
            $modifyTime = unpack('V', substr($buffer, 4, 4))[1];
119
        }
120
121 4
        if ($length >= 10) {
122 3
            $uid = unpack('v', substr($buffer, 8, 2))[1];
123
        }
124
125 4
        if ($length >= 12) {
126 3
            $gid = unpack('v', substr($buffer, 10, 2))[1];
127
        }
128
129 4
        return new self($accessTime, $modifyTime, $uid, $gid);
130
    }
131
132
    /**
133
     * Populate data from this array as if it was in central directory data.
134
     *
135
     * @param string        $buffer the buffer to read data from
136
     * @param ZipEntry|null $entry
137
     *
138
     * @return OldUnixExtraField
139
     */
140 4
    public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
141
    {
142 4
        $length = \strlen($buffer);
143
144 4
        $accessTime = $modifyTime = null;
145
146 4
        if ($length >= 4) {
147 3
            $accessTime = unpack('V', $buffer)[1];
148
        }
149
150 4
        if ($length >= 8) {
151 3
            $modifyTime = unpack('V', substr($buffer, 4, 4))[1];
152
        }
153
154 4
        return new self($accessTime, $modifyTime, null, null);
155
    }
156
157
    /**
158
     * The actual data to put into local file data - without Header-ID
159
     * or length specifier.
160
     *
161
     * @return string the data
162
     */
163 4
    public function packLocalFileData()
164
    {
165 4
        $data = '';
166
167 4
        if ($this->accessTime !== null) {
168 3
            $data .= pack('V', $this->accessTime);
169
170 3
            if ($this->modifyTime !== null) {
171 3
                $data .= pack('V', $this->modifyTime);
172
173 3
                if ($this->uid !== null) {
174 3
                    $data .= pack('v', $this->uid);
175
176 3
                    if ($this->gid !== null) {
177 3
                        $data .= pack('v', $this->gid);
178
                    }
179
                }
180
            }
181
        }
182
183 4
        return $data;
184
    }
185
186
    /**
187
     * The actual data to put into central directory - without Header-ID or
188
     * length specifier.
189
     *
190
     * @return string the data
191
     */
192 4
    public function packCentralDirData()
193
    {
194 4
        $data = '';
195
196 4
        if ($this->accessTime !== null) {
197 3
            $data .= pack('V', $this->accessTime);
198
199 3
            if ($this->modifyTime !== null) {
200 3
                $data .= pack('V', $this->modifyTime);
201
            }
202
        }
203
204 4
        return $data;
205
    }
206
207
    /**
208
     * @return int|null
209
     */
210 5
    public function getAccessTime()
211
    {
212 5
        return $this->accessTime;
213
    }
214
215
    /**
216
     * @param int|null $accessTime
217
     */
218 1
    public function setAccessTime($accessTime)
219
    {
220 1
        $this->accessTime = $accessTime;
221 1
    }
222
223
    /**
224
     * @return \DateTimeInterface|null
225
     */
226 5
    public function getAccessDateTime()
227
    {
228
        try {
229 5
            return $this->accessTime === null ? null :
230 5
                new \DateTimeImmutable('@' . $this->accessTime);
231
        } catch (\Exception $e) {
232
            return null;
233
        }
234
    }
235
236
    /**
237
     * @return int|null
238
     */
239 5
    public function getModifyTime()
240
    {
241 5
        return $this->modifyTime;
242
    }
243
244
    /**
245
     * @param int|null $modifyTime
246
     */
247 1
    public function setModifyTime($modifyTime)
248
    {
249 1
        $this->modifyTime = $modifyTime;
250 1
    }
251
252
    /**
253
     * @return \DateTimeInterface|null
254
     */
255 5
    public function getModifyDateTime()
256
    {
257
        try {
258 5
            return $this->modifyTime === null ? null :
259 5
                new \DateTimeImmutable('@' . $this->modifyTime);
260
        } catch (\Exception $e) {
261
            return null;
262
        }
263
    }
264
265
    /**
266
     * @return int|null
267
     */
268 5
    public function getUid()
269
    {
270 5
        return $this->uid;
271
    }
272
273
    /**
274
     * @param int|null $uid
275
     */
276 1
    public function setUid($uid)
277
    {
278 1
        $this->uid = $uid;
279 1
    }
280
281
    /**
282
     * @return int|null
283
     */
284 5
    public function getGid()
285
    {
286 5
        return $this->gid;
287
    }
288
289
    /**
290
     * @param int|null $gid
291
     */
292 1
    public function setGid($gid)
293
    {
294 1
        $this->gid = $gid;
295 1
    }
296
297
    /**
298
     * @return string
299
     */
300
    public function __toString()
301
    {
302
        $args = [self::HEADER_ID];
303
        $format = '0x%04x OldUnix:';
304
305
        if (($modifyTime = $this->getModifyDateTime()) !== null) {
306
            $format .= ' Modify:[%s]';
307
            $args[] = $modifyTime->format(\DATE_ATOM);
308
        }
309
310
        if (($accessTime = $this->getAccessDateTime()) !== null) {
311
            $format .= ' Access:[%s]';
312
            $args[] = $accessTime->format(\DATE_ATOM);
313
        }
314
315
        if ($this->uid !== null) {
316
            $format .= ' UID=%d';
317
            $args[] = $this->uid;
318
        }
319
320
        if ($this->gid !== null) {
321
            $format .= ' GID=%d';
322
            $args[] = $this->gid;
323
        }
324
325
        return vsprintf($format, $args);
326
    }
327
}
328