This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Fructify\Reload\Protocol\WebSocket; |
||
3 | |||
4 | /** |
||
5 | * Description of Frame |
||
6 | * |
||
7 | * @author ricky |
||
8 | */ |
||
9 | class Frame |
||
10 | { |
||
11 | |||
12 | const DECODE_STATUS_MORE_DATA = 0; |
||
13 | const DECODE_STATUS_ERROR = -1; |
||
14 | const OP_CONTINUE = 0; |
||
15 | const OP_TEXT = 1; |
||
16 | const OP_BINARY = 2; |
||
17 | const OP_CLOSE = 8; |
||
18 | const OP_PING = 9; |
||
19 | const OP_PONG = 10; |
||
20 | const MASK_LENGTH = 4; |
||
21 | |||
22 | protected $data = ''; |
||
23 | protected $firstByte = null; |
||
24 | protected $secondByte = 0; |
||
25 | protected $isCoalesced = false; |
||
26 | protected $extendedPayload = ''; |
||
27 | |||
28 | protected $isClosed = false; |
||
29 | |||
30 | /** |
||
31 | * |
||
32 | * @return Frame |
||
33 | */ |
||
34 | public static function parse($data) |
||
35 | { |
||
36 | if (!($data instanceof MessageQueue)) { |
||
37 | $data = new MessageQueue($data); |
||
38 | } |
||
39 | $frame = new static(); |
||
40 | $frameSize = $frame->decode($data); |
||
41 | if (!$frame->isCoalesced()) { |
||
42 | return $frameSize; |
||
43 | } |
||
44 | $data->shift($frameSize); |
||
45 | |||
46 | return $frame; |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * |
||
51 | * @param string $data |
||
52 | * @return Frame |
||
53 | */ |
||
54 | public static function generate($data) |
||
55 | { |
||
56 | $frame = new static($data); |
||
57 | |||
58 | return $frame; |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * |
||
63 | * @param string $data |
||
64 | * @return Frame |
||
65 | */ |
||
66 | public static function close($data) |
||
67 | { |
||
68 | $frame = new static($data, true, static::OP_CLOSE); |
||
69 | $frame->setClosed(); |
||
70 | |||
71 | return $frame; |
||
72 | } |
||
73 | |||
74 | protected function __construct($data = null, $final = true, $opcode = self::OP_TEXT) |
||
75 | { |
||
76 | $this->firstByte = ($final ? 0x80 : 0) + $opcode; |
||
77 | $this->appendData($data); |
||
78 | } |
||
79 | |||
80 | public function setClosed($isClosed = true) |
||
81 | { |
||
82 | $this->isClosed = $isClosed; |
||
83 | } |
||
84 | |||
85 | public function isClosed() |
||
86 | { |
||
87 | return $this->isClosed; |
||
88 | } |
||
89 | |||
90 | public function getOpcode() |
||
91 | { |
||
92 | return $this->firstByte & 0x7f; |
||
93 | } |
||
94 | |||
95 | public function setFirstByte($byte) |
||
96 | { |
||
97 | $this->firstByte = $byte; |
||
98 | } |
||
99 | |||
100 | public function setSecondByte($byte) |
||
101 | { |
||
102 | $this->secondByte = $byte; |
||
103 | } |
||
104 | |||
105 | public function setData($data) |
||
106 | { |
||
107 | $this->data = ''; |
||
108 | $this->appendData($data); |
||
109 | } |
||
110 | |||
111 | public function appendData($data) |
||
112 | { |
||
113 | $this->data.=$data; |
||
114 | $this->updatePayloadLength($this->data, $this->secondByte, $this->extendedPayload); |
||
115 | } |
||
116 | |||
117 | public function setMask($mask) |
||
118 | { |
||
119 | $mask &= 1; |
||
120 | $this->secondByte |= ($mask << 7); |
||
121 | } |
||
122 | |||
123 | public function isMask() |
||
124 | { |
||
125 | return ($this->secondByte >> 7) == 1; |
||
126 | } |
||
127 | |||
128 | public function generateMaskingKey() |
||
129 | { |
||
130 | $maskingKey = ''; |
||
131 | for ($i = 0; $i < static::MASK_LENGTH; $i++) { |
||
132 | $maskingKey .= pack('C', rand(0, 255)); |
||
133 | } |
||
134 | |||
135 | return $maskingKey; |
||
136 | } |
||
137 | |||
138 | protected function applyMask($maskingKey, $payload = null) |
||
139 | { |
||
140 | $applied = ''; |
||
141 | for ($i = 0, $len = strlen($payload); $i < $len; $i++) { |
||
142 | $applied .= $payload[$i] ^ $maskingKey[$i % static::MASK_LENGTH]; |
||
143 | } |
||
144 | |||
145 | return $applied; |
||
146 | } |
||
147 | |||
148 | protected function maskPayload($payload) |
||
149 | { |
||
150 | if (!$this->isMask()) { |
||
151 | return $payload; |
||
152 | } |
||
153 | $maskingKey = $this->generateMaskingKey(); |
||
154 | |||
155 | return $maskingKey . $this->applyMask($maskingKey, $payload); |
||
156 | } |
||
157 | |||
158 | public function getPayloadLength($encodedData) |
||
159 | { |
||
160 | $length = $this->secondByte & 0x7f; |
||
161 | if ($length < 126) { |
||
162 | return [$length, 0]; |
||
163 | } |
||
164 | |||
165 | if ($length == 126) { // with 2 bytes extended payload length |
||
166 | View Code Duplication | if (($packedPayloadLength = substr($encodedData, 2, 2)) === false) { |
|
0 ignored issues
–
show
|
|||
167 | return [0, 0]; |
||
168 | } |
||
169 | |||
170 | return [unpack("n", $packedPayloadLength)[1] + 2, 2]; |
||
171 | } |
||
172 | |||
173 | if ($length == 127) { //with 8 bytes extended payload length |
||
174 | View Code Duplication | if (($packedPayloadLength = substr($encodedData, 2, 8)) === false) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
175 | return [0, 0]; |
||
176 | } |
||
177 | $payloadLength = unpack("N2", $packedPayloadLength); |
||
178 | |||
179 | return [($payloadLength[1] << 32) | $payloadLength[2] + 8, 8]; |
||
180 | } |
||
181 | } |
||
182 | |||
183 | public function decode($encodedData) |
||
184 | { |
||
185 | $this->isCoalesced = false; |
||
186 | if (strlen($encodedData) <= 2) { |
||
187 | return static::DECODE_STATUS_MORE_DATA; |
||
188 | } |
||
189 | $bytes = unpack("C2", $encodedData); |
||
190 | $this->setFirstByte($bytes[1]); |
||
191 | $this->setSecondByte($bytes[2]); |
||
192 | |||
193 | if (!$this->verifyPayload()) { |
||
194 | return static::DECODE_STATUS_ERROR; |
||
195 | } |
||
196 | list($payloadLength, $extendedPayloadBytes) = $this->getPayloadLength($encodedData); |
||
197 | $totalFramLength = 2 + $payloadLength; |
||
198 | if ($this->isMask()) { |
||
199 | $totalFramLength += static::MASK_LENGTH; |
||
200 | } |
||
201 | if ($payloadLength == 0 || strlen($encodedData) < $totalFramLength) { |
||
202 | return static::DECODE_STATUS_MORE_DATA; |
||
203 | } |
||
204 | $maskingKey = substr($encodedData, 2 + $extendedPayloadBytes, static::MASK_LENGTH); |
||
205 | $data = $this->applyMask($maskingKey, substr($encodedData, 2 + $extendedPayloadBytes + static::MASK_LENGTH)); |
||
206 | $this->setData($data); |
||
207 | if (strlen($encodedData) >= $totalFramLength) { |
||
208 | $this->isCoalesced = true; |
||
209 | } |
||
210 | |||
211 | return $totalFramLength; |
||
212 | } |
||
213 | |||
214 | public function isCoalesced() |
||
215 | { |
||
216 | return $this->isCoalesced; |
||
217 | } |
||
218 | |||
219 | public function getRSV1() |
||
220 | { |
||
221 | return ($this->firstByte & 4) > 0; |
||
222 | } |
||
223 | |||
224 | public function getRSV2() |
||
225 | { |
||
226 | return ($this->firstByte & 2) > 0; |
||
227 | } |
||
228 | |||
229 | public function getRSV3() |
||
230 | { |
||
231 | return ($this->firstByte & 1) > 0; |
||
232 | } |
||
233 | |||
234 | protected function verifyPayload() |
||
235 | { |
||
236 | if ($this->getRSV1() && $this->getRSV2() && $this->getRSV3()) { |
||
237 | return false; |
||
238 | } |
||
239 | |||
240 | return true; |
||
241 | } |
||
242 | |||
243 | public function getData() |
||
244 | { |
||
245 | return $this->data; |
||
246 | } |
||
247 | |||
248 | public function encode() |
||
249 | { |
||
250 | $this->isCoalesced = true; |
||
251 | |||
252 | return pack('CC', $this->firstByte, $this->secondByte) . $this->extendedPayload . $this->maskPayload($this->data); |
||
253 | } |
||
254 | |||
255 | protected function updatePayloadLength($data, &$secondByte, &$extendedPayload) |
||
256 | { |
||
257 | $secondByte &= 0x80; |
||
258 | $size = strlen($data); |
||
259 | if ($size < 126) { |
||
260 | $secondByte |= $size; |
||
261 | |||
262 | return; |
||
263 | } |
||
264 | |||
265 | if ($size <= 65535) { //use 2 bytes extended payload |
||
266 | $secondByte |= 126; |
||
267 | $extendedPayload = pack("n", $size); |
||
268 | |||
269 | return; |
||
270 | } |
||
271 | |||
272 | //use 4 bytes extended payload |
||
273 | $secondByte |= 127; |
||
274 | $extendedPayload = pack("NN", $size >> 32, $size & 0xffffffff); |
||
275 | } |
||
276 | |||
277 | } |
||
278 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.