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

NewUnixExtraField::getGid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace PhpZip\Model\Extra\Fields;
4
5
use PhpZip\Exception\ZipException;
6
use PhpZip\Model\Extra\ZipExtraField;
7
use PhpZip\Model\ZipEntry;
8
9
/**
10
 * Info-ZIP New Unix Extra Field:
11
 * ====================================.
12
 *
13
 * Currently stores Unix UIDs/GIDs up to 32 bits.
14
 * (Last Revision 20080509)
15
 *
16
 * Value         Size        Description
17
 * -----         ----        -----------
18
 * (UnixN) 0x7875        Short       tag for this extra block type ("ux")
19
 * TSize         Short       total data size for this block
20
 * Version       1 byte      version of this extra field, currently 1
21
 * UIDSize       1 byte      Size of UID field
22
 * UID           Variable    UID for this entry
23
 * GIDSize       1 byte      Size of GID field
24
 * GID           Variable    GID for this entry
25
 *
26
 * Currently Version is set to the number 1.  If there is a need
27
 * to change this field, the version will be incremented.  Changes
28
 * may not be backward compatible so this extra field should not be
29
 * used if the version is not recognized.
30
 *
31
 * UIDSize is the size of the UID field in bytes.  This size should
32
 * match the size of the UID field on the target OS.
33
 *
34
 * UID is the UID for this entry in standard little endian format.
35
 *
36
 * GIDSize is the size of the GID field in bytes.  This size should
37
 * match the size of the GID field on the target OS.
38
 *
39
 * GID is the GID for this entry in standard little endian format.
40
 *
41
 * If both the old 16-bit Unix extra field (tag 0x7855, Info-ZIP Unix)
42
 * and this extra field are present, the values in this extra field
43
 * supercede the values in that extra field.
44
 */
45
class NewUnixExtraField implements ZipExtraField
46
{
47
    /** @var int header id */
48
    const HEADER_ID = 0x7875;
49
50
    /** ID of the first non-root user created on a unix system. */
51
    const USER_GID_PID = 1000;
52
53
    /** @var int version of this extra field, currently 1 */
54
    private $version = 1;
55
56
    /** @var int User id */
57
    private $uid;
58
59
    /** @var int Group id */
60
    private $gid;
61
62
    /**
63
     * NewUnixExtraField constructor.
64
     *
65
     * @param int $version
66
     * @param int $uid
67
     * @param int $gid
68
     */
69 10
    public function __construct($version = 1, $uid = self::USER_GID_PID, $gid = self::USER_GID_PID)
70
    {
71 10
        $this->version = (int) $version;
72 10
        $this->uid = (int) $uid;
73 10
        $this->gid = (int) $gid;
74 10
    }
75
76
    /**
77
     * Returns the Header ID (type) of this Extra Field.
78
     * The Header ID is an unsigned short integer (two bytes)
79
     * which must be constant during the life cycle of this object.
80
     *
81
     * @return int
82
     */
83 9
    public function getHeaderId()
84
    {
85 9
        return self::HEADER_ID;
86
    }
87
88
    /**
89
     * Populate data from this array as if it was in local file data.
90
     *
91
     * @param string        $buffer the buffer to read data from
92
     * @param ZipEntry|null $entry
93
     *
94
     * @throws ZipException
95
     *
96
     * @return NewUnixExtraField
97
     */
98 7
    public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
99
    {
100 7
        $length = \strlen($buffer);
101
102 7
        if ($length < 3) {
103
            throw new ZipException(sprintf('X7875_NewUnix length is too short, only %s bytes', $length));
104
        }
105 7
        $offset = 0;
106 7
        $data = unpack('Cversion/CuidSize', $buffer);
107 7
        $offset += 2;
108 7
        $uidSize = $data['uidSize'];
109 7
        $gid = self::readSizeIntegerLE(substr($buffer, $offset, $uidSize), $uidSize);
110 7
        $offset += $uidSize;
111 7
        $gidSize = unpack('C', $buffer[$offset])[1];
112 7
        $offset++;
113 7
        $uid = self::readSizeIntegerLE(substr($buffer, $offset, $gidSize), $gidSize);
114
115 7
        return new self($data['version'], $gid, $uid);
116
    }
117
118
    /**
119
     * Populate data from this array as if it was in central directory data.
120
     *
121
     * @param string        $buffer the buffer to read data from
122
     * @param ZipEntry|null $entry
123
     *
124
     * @throws ZipException
125
     *
126
     * @return NewUnixExtraField
127
     */
128 7
    public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
129
    {
130 7
        return self::unpackLocalFileData($buffer, $entry);
131
    }
132
133
    /**
134
     * The actual data to put into local file data - without Header-ID
135
     * or length specifier.
136
     *
137
     * @return string the data
138
     */
139 7
    public function packLocalFileData()
140
    {
141 7
        return pack(
142 7
            'CCVCV',
143 7
            $this->version,
144 7
            4, // UIDSize
145 7
            $this->uid,
146 7
            4, // GIDSize
147 7
            $this->gid
148
        );
149
    }
150
151
    /**
152
     * The actual data to put into central directory - without Header-ID or
153
     * length specifier.
154
     *
155
     * @return string the data
156
     */
157 7
    public function packCentralDirData()
158
    {
159 7
        return $this->packLocalFileData();
160
    }
161
162
    /**
163
     * @param string $data
164
     * @param int    $size
165
     *
166
     * @throws ZipException
167
     *
168
     * @return int
169
     */
170 7
    private static function readSizeIntegerLE($data, $size)
171
    {
172
        $format = [
173 7
            1 => 'C', // unsigned byte
174
            2 => 'v', // unsigned short LE
175
            4 => 'V', // unsigned int LE
176
        ];
177
178 7
        if (!isset($format[$size])) {
179
            throw new ZipException(sprintf('Invalid size bytes: %d', $size));
180
        }
181
182 7
        return unpack($format[$size], $data)[1];
183
    }
184
185
    /**
186
     * @return int
187
     */
188 6
    public function getUid()
189
    {
190 6
        return $this->uid;
191
    }
192
193
    /**
194
     * @param int $uid
195
     */
196 1
    public function setUid($uid)
197
    {
198 1
        $this->uid = $uid & 0xffffffff;
199 1
    }
200
201
    /**
202
     * @return int
203
     */
204 6
    public function getGid()
205
    {
206 6
        return $this->gid;
207
    }
208
209
    /**
210
     * @param int $gid
211
     */
212 1
    public function setGid($gid)
213
    {
214 1
        $this->gid = $gid & 0xffffffff;
215 1
    }
216
217
    /**
218
     * @return int
219
     */
220 6
    public function getVersion()
221
    {
222 6
        return $this->version;
223
    }
224
225
    /**
226
     * @return string
227
     */
228
    public function __toString()
229
    {
230
        return sprintf(
231
            '0x%04x NewUnix: UID=%d GID=%d',
232
            self::HEADER_ID,
233
            $this->uid,
234
            $this->gid
235
        );
236
    }
237
}
238