Passed
Push — master ( b4e552...a91d54 )
by y
03:05
created

WebSocketFrame::isPong()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 2
rs 10
1
<?php
2
3
namespace Helix\Socket;
4
5
/**
6
 * https://tools.ietf.org/html/rfc6455#section-5.2
7
 */
8
class WebSocketFrame {
9
10
    const OP_CONTINUE = 0x00;
11
    const OP_TEXT = 0x01;
12
    const OP_BINARY = 0x02;
13
    const OP_CLOSE = 0x08;
14
    const OP_PING = 0x09;
15
    const OP_PONG = 0x0a;
16
17
    /**
18
     * @var string
19
     */
20
    protected $data;
21
22
    /**
23
     * @param string $payload
24
     * @param int $opCode
25
     * @param bool $final
26
     * @return string
27
     */
28
    public static function pack (string $payload, int $opCode = self::OP_TEXT, bool $final = true): string {
0 ignored issues
show
Unused Code introduced by
The parameter $final is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

28
    public static function pack (string $payload, int $opCode = self::OP_TEXT, /** @scrutinizer ignore-unused */ bool $final = true): string {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
29
        $frame = chr(0x80 | $opCode);
30
        $len = strlen($payload);
31
        if ($len > 65535) {
32
            $frame .= chr(127);
33
            $frame .= pack('J', $len);
34
        }
35
        elseif ($len >= 126) {
36
            $frame .= chr(126);
37
            $frame .= pack('n', $len);
38
        }
39
        else {
40
            $frame .= chr($len);
41
        }
42
        return $frame . $payload;
43
    }
44
45
    public function __construct (string $data) {
46
        $this->data = $data;
47
    }
48
49
    final public function getLength () {
50
        switch ($char = ord($this->data[1]) & 0x7f) {
51
            case 127: // big-endian long-long
52
                return unpack('J', substr($this->data, 2, 8));
53
            case 126: // big-endian short
54
                return unpack('n', substr($this->data, 2, 2));
55
            default:
56
                return $char;
57
        }
58
    }
59
60
    /**
61
     * @return int[]
62
     */
63
    final public function getMask () {
64
        if ($this->isMasked()) {
65
            switch (ord($this->data[1]) & 0x7f) {
66
                case 127:
67
                    return array_values(unpack('C*', substr($this->data, 6, 4)));
0 ignored issues
show
Bug introduced by
It seems like unpack('C*', substr($this->data, 6, 4)) can also be of type false; however, parameter $input of array_values() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

67
                    return array_values(/** @scrutinizer ignore-type */ unpack('C*', substr($this->data, 6, 4)));
Loading history...
68
                case 126:
69
                    return array_values(unpack('C*', substr($this->data, 4, 4)));
70
                default:
71
                    return array_values(unpack('C*', substr($this->data, 2, 4)));
72
            }
73
        }
74
        return [0, 0, 0, 0];
75
    }
76
77
    final public function getOpCode (): int {
78
        return ord($this->data[0]) & 0x0f;
79
    }
80
81
    final public function getPayload (): string {
82
        $length = $this->getLength();
83
        if ($length === 0) {
84
            return '';
85
        }
86
        $offset = 2;
87
        if ($length >= 126) {
88
            $offset += 2;
89
            if ($length > 65535) {
90
                $offset += 6;
91
            }
92
        }
93
        if ($this->isMasked()) {
94
            $offset += 4;
95
        }
96
        $mask = $this->getMask();
97
        $payload = array_values(unpack('C*', substr($this->data, $offset)));
0 ignored issues
show
Bug introduced by
It seems like unpack('C*', substr($this->data, $offset)) can also be of type false; however, parameter $input of array_values() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

97
        $payload = array_values(/** @scrutinizer ignore-type */ unpack('C*', substr($this->data, $offset)));
Loading history...
98
        $decoded = '';
99
        for ($i = 0; $i < $length; $i++) {
100
            $decoded .= chr($payload[$i] ^ $mask[$i % 4]);
101
        }
102
        return $decoded;
103
    }
104
105
    final public function isBinary (): bool {
106
        return $this->getOpCode() === self::OP_BINARY;
107
    }
108
109
    final public function isClose (): bool {
110
        return $this->getOpCode() === self::OP_CLOSE;
111
    }
112
113
    final public function isFinal (): bool {
114
        return (bool)(ord($this->data[0]) & 0x80);
115
    }
116
117
    final public function isMasked (): bool {
118
        return (bool)(ord($this->data[1]) & 0x80);
119
    }
120
121
    final public function isPong (): bool {
122
        return $this->getOpCode() === self::OP_PONG;
123
    }
124
125
    final public function isText (): bool {
126
        return $this->getOpCode() === self::OP_TEXT;
127
    }
128
129
}