Record::unpackPayload()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 9.9666
cc 1
nc 1
nop 2
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Lisachenko\Protocol\FCGI;
4
5
use Lisachenko\Protocol\FCGI;
6
7
/**
8
 * FCGI record.
9
 *
10
 * @author Alexander.Lisachenko
11
 */
12
class Record
13
{
14
15
    /**
16
     * Identifies the FastCGI protocol version.
17
     *
18
     * @var int
19
     */
20
    protected $version = FCGI::VERSION_1;
21
22
    /**
23
     * Identifies the FastCGI record type, i.e. the general function that the record performs.
24
     *
25
     * @var int
26
     */
27
    protected $type = FCGI::UNKNOWN_TYPE;
28
29
    /**
30
     * Identifies the FastCGI request to which the record belongs.
31
     *
32
     * @var int
33
     */
34
    protected $requestId = FCGI::NULL_REQUEST_ID;
35
36
    /**
37
     * Reserved byte for future proposes
38
     *
39
     * @var int
40
     */
41
    protected $reserved = 0;
42
43
    /**
44
     * The number of bytes in the contentData component of the record.
45
     *
46
     * @var int
47
     */
48
    private $contentLength = 0;
49
50
    /**
51
     * The number of bytes in the paddingData component of the record.
52
     *
53
     * @var int
54
     */
55
    private $paddingLength = 0;
56
57
    /**
58
     * Binary data, between 0 and 65535 bytes of data, interpreted according to the record type.
59
     *
60
     * @var string
61
     */
62
    private $contentData = '';
63
64
    /**
65
     * Padding data, between 0 and 255 bytes of data, which are ignored.
66
     *
67
     * @var string
68
     */
69
    private $paddingData = '';
70
71
    /**
72
     * Unpacks the message from the binary data buffer
73
     *
74
     * @param string $data Binary buffer with raw data
75
     *
76
     * @return static
77
     */
78
    final public static function unpack(string $data): self
79 14
    {
80
        $self = new static();
81 14
        [
82
            $self->version,
83 14
            $self->type,
84 14
            $self->requestId,
85 14
            $self->contentLength,
86 14
            $self->paddingLength,
87 14
            $self->reserved
88 14
        ] = array_values(unpack(FCGI::HEADER_FORMAT, $data));
89 14
90
        $payload = substr($data, FCGI::HEADER_LEN);
91 14
        self::unpackPayload($self, $payload);
92 14
        if (get_called_class() !== __CLASS__ && $self->contentLength > 0) {
93 14
            static::unpackPayload($self, $payload);
94 11
        }
95 11
96
        return $self;
97 14
    }
98
99
    /**
100
     * Returns the binary message representation of record
101
     */
102
    final public function __toString(): string
103
    {
104
        $headerPacket = pack(
105 13
            "CCnnCC",
106
            $this->version,
107 13
            $this->type,
108 13
            $this->requestId,
109 13
            $this->contentLength,
110 13
            $this->paddingLength,
111 13
            $this->reserved
112 13
        );
113 13
114 13
        $payloadPacket = $this->packPayload();
115 13
        $paddingPacket = pack("a{$this->paddingLength}", $this->paddingData);
116
117 13
        return $headerPacket . $payloadPacket . $paddingPacket;
118 13
    }
119
120 13
    /**
121
     * Sets the content data and adjusts the length fields
122
     *
123
     * @param string $data
124
     *
125
     * @return static
126
     */
127
    public function setContentData(string $data): self
128 23
    {
129
        $this->contentData = $data;
130 23
        $this->contentLength = strlen($this->contentData);
131 23
        $extraLength = $this->contentLength % 8;
132 23
        $this->paddingLength = $extraLength ? (8 - $extraLength) : 0;
133 23
        return $this;
134 23
    }
135
136
    /**
137
     * Returns the context data from the record
138
     */
139
    public function getContentData(): string
140
    {
141 10
        return $this->contentData;
142
    }
143 10
144
    /**
145
     * Returns the version of record
146
     */
147
    public function getVersion(): int
148
    {
149
        return $this->version;
150
    }
151 1
152
    /**
153 1
     * Returns record type
154
     */
155
    public function getType(): int
156
    {
157
        return $this->type;
158
    }
159 24
160
    /**
161 24
     * Returns request ID
162
     */
163
    public function getRequestId(): int
164
    {
165
        return $this->requestId;
166
    }
167 4
168
    /**
169 4
     * Sets request ID
170
     *
171
     * There should be only one unique ID for all active requests,
172
     * use random number or preferably resetting auto-increment.
173
     *
174
     * @param int $requestId
175
     *
176
     * @return static
177 3
     */
178
    public function setRequestId(int $requestId): self
179 3
    {
180
        $this->requestId = $requestId;
181 3
        return $this;
182
    }
183
184
    /**
185
     * Returns the size of content length
186
     */
187
    final public function getContentLength(): int
188
    {
189 5
        return $this->contentLength;
190
    }
191 5
192
    /**
193
     * Returns the size of padding length
194
     */
195
    final public function getPaddingLength(): int
196
    {
197
        return $this->paddingLength;
198
    }
199 3
200
    /**
201 3
     * Method to unpack the payload for the record.
202
     *
203
     * NB: Default implementation will be always called
204
     *
205
     * @param static $self Instance of current frame
206
     * @param string $data Binary data
207
     */
208
    protected static function unpackPayload($self, string $data): void
209
    {
210
        [
211
            $self->contentData,
212 14
            $self->paddingData
213
        ] = array_values(
214
            unpack("a{$self->contentLength}contentData/a{$self->paddingLength}paddingData", $data)
215 14
        );
216 14
    }
217 14
218 14
    /**
219 14
     * Implementation of packing the payload
220 14
     */
221
    protected function packPayload(): string
222
    {
223
        return pack("a{$this->contentLength}", $this->contentData);
224
    }
225
226
}
227