• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Moln / php-mysql-replication / 4424054906

pending completion
4424054906

Pull #11

github

GitHub
Merge 39f41dd0c into 52f8f33ab
Pull Request #11: Improve MySQLReplication BinaryDataReader

2 of 2 new or added lines in 1 file covered. (100.0%)

1253 of 1551 relevant lines covered (80.79%)

26.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.06
/src/MySQLReplication/BinaryDataReader/BinaryDataReader.php
1
<?php
2
declare(strict_types=1);
3

4
namespace MySQLReplication\BinaryDataReader;
5

6
class BinaryDataReader
7
{
8
    public const NULL_COLUMN = 251;
9
    public const UNSIGNED_CHAR_COLUMN = 251;
10
    public const UNSIGNED_SHORT_COLUMN = 252;
11
    public const UNSIGNED_INT24_COLUMN = 253;
12
    public const UNSIGNED_INT64_COLUMN = 254;
13
    public const UNSIGNED_CHAR_LENGTH = 1;
14
    public const UNSIGNED_SHORT_LENGTH = 2;
15
    public const UNSIGNED_INT24_LENGTH = 3;
16
    public const UNSIGNED_INT32_LENGTH = 4;
17
    public const UNSIGNED_FLOAT_LENGTH = 4;
18
    public const UNSIGNED_DOUBLE_LENGTH = 8;
19
    public const UNSIGNED_INT40_LENGTH = 5;
20
    public const UNSIGNED_INT48_LENGTH = 6;
21
    public const UNSIGNED_INT56_LENGTH = 7;
22
    public const UNSIGNED_INT64_LENGTH = 8;
23

24
    private $data;
25

26
    /**
27
     * @var int
28
     */
29
    private $readBytes = 0;
30

31
    public function __construct(string $data)
32
    {
33
        $this->data = $data;
92✔
34
    }
35

36
    public static function pack64bit(int $value): string
37
    {
38
        return pack(
3✔
39
            'C8',
3✔
40
            ($value >> 0) & 0xFF,
3✔
41
            ($value >> 8) & 0xFF,
3✔
42
            ($value >> 16) & 0xFF,
3✔
43
            ($value >> 24) & 0xFF,
3✔
44
            ($value >> 32) & 0xFF,
3✔
45
            ($value >> 40) & 0xFF,
3✔
46
            ($value >> 48) & 0xFF,
3✔
47
            ($value >> 56) & 0xFF
3✔
48
        );
3✔
49
    }
50

51
    public function advance(int $length): void
52
    {
53
        $this->read($length);
64✔
54
    }
55

56
    public function readInt16(): int
57
    {
58
        return unpack('s', $this->read(self::UNSIGNED_SHORT_LENGTH))[1];
6✔
59
    }
60

61
    public function read(int $length): string
62
    {
63
        $return = substr($this->data, 0, $length);
89✔
64
        $this->readBytes += $length;
89✔
65
        $this->data = substr($this->data, $length);
89✔
66

67
        return $return;
89✔
68
    }
69

70
    public function unread(string $data): void
71
    {
72
        $this->readBytes -= strlen($data);
11✔
73
        $this->data = $data . $this->data;
11✔
74
    }
75

76
    /**
77
     * @throws BinaryDataReaderException
78
     */
79
    public function readCodedBinary(): ?int
80
    {
81
        $c = ord($this->read(self::UNSIGNED_CHAR_LENGTH));
60✔
82
        if ($c === self::NULL_COLUMN) {
60✔
83
            return null;
1✔
84
        }
85
        if ($c < self::UNSIGNED_CHAR_COLUMN) {
60✔
86
            return $c;
59✔
87
        }
88
        if ($c === self::UNSIGNED_SHORT_COLUMN) {
2✔
89
            return $this->readUInt16();
1✔
90
        }
91
        if ($c === self::UNSIGNED_INT24_COLUMN) {
2✔
92
            return $this->readUInt24();
1✔
93
        }
94

95
        throw new BinaryDataReaderException('Column num ' . $c . ' not handled');
1✔
96
    }
97

98
    public function readUInt16(): int
99
    {
100
        return unpack('v', $this->read(self::UNSIGNED_SHORT_LENGTH))[1];
64✔
101
    }
102

103
    public function readUInt24(): int
104
    {
105
        $data = unpack('C3', $this->read(self::UNSIGNED_INT24_LENGTH));
8✔
106

107
        return $data[1] + ($data[2] << 8) + ($data[3] << 16);
8✔
108
    }
109

110
    public function readUInt64(): string
111
    {
112
        return $this->unpackUInt64($this->read(self::UNSIGNED_INT64_LENGTH));
10✔
113
    }
114

115
    public function unpackUInt64(string $binary): string
116
    {
117
        $data = unpack('V*', $binary);
61✔
118

119
        return bcadd((string)$data[1], bcmul((string)$data[2], bcpow('2', '32')));
61✔
120
    }
121

122
    public function readInt24(): int
123
    {
124
        $data = unpack('C3', $this->read(self::UNSIGNED_INT24_LENGTH));
2✔
125

126
        $res = $data[1] | ($data[2] << 8) | ($data[3] << 16);
2✔
127
        if ($res >= 0x800000) {
2✔
128
            $res -= 0x1000000;
2✔
129
        }
130

131
        return $res;
2✔
132
    }
133

134
    public function readInt64(): string
135
    {
136
        $data = unpack('V*', $this->read(self::UNSIGNED_INT64_LENGTH));
4✔
137

138
        return bcadd((string)$data[1], (string)($data[2] << 32));
4✔
139
    }
140

141
    /**
142
     * @throws BinaryDataReaderException
143
     */
144
    public function readLengthString(int $size): string
145
    {
146
        return $this->read($this->readUIntBySize($size));
18✔
147
    }
148

149
    /**
150
     * @throws BinaryDataReaderException
151
     */
152
    public function readUIntBySize(int $size): int
153
    {
154
        if ($size === self::UNSIGNED_CHAR_LENGTH) {
28✔
155
            return $this->readUInt8();
12✔
156
        }
157
        if ($size === self::UNSIGNED_SHORT_LENGTH) {
16✔
158
            return $this->readUInt16();
7✔
159
        }
160
        if ($size === self::UNSIGNED_INT24_LENGTH) {
13✔
161
            return $this->readUInt24();
2✔
162
        }
163
        if ($size === self::UNSIGNED_INT32_LENGTH) {
11✔
164
            return $this->readUInt32();
7✔
165
        }
166
        if ($size === self::UNSIGNED_INT40_LENGTH) {
4✔
167
            return $this->readUInt40();
1✔
168
        }
169
        if ($size === self::UNSIGNED_INT48_LENGTH) {
3✔
170
            return $this->readUInt48();
1✔
171
        }
172
        if ($size === self::UNSIGNED_INT56_LENGTH) {
2✔
173
            return $this->readUInt56();
1✔
174
        }
175
        if ($size === self::UNSIGNED_INT64_LENGTH) {
1✔
176
            return intval($this->readUInt64());
×
177
        }
178

179
        throw new BinaryDataReaderException('$size ' . $size . ' not handled');
1✔
180
    }
181

182
    public function readUInt8(): int
183
    {
184
        return unpack('C', $this->read(self::UNSIGNED_CHAR_LENGTH))[1];
64✔
185
    }
186

187
    public function readUInt32(): int
188
    {
189
        return unpack('I', $this->read(self::UNSIGNED_INT32_LENGTH))[1];
63✔
190
    }
191

192
    public function readUInt40(): int
193
    {
194
        $data1 = unpack('C', $this->read(self::UNSIGNED_CHAR_LENGTH))[1];
1✔
195
        $data2 = unpack('I', $this->read(self::UNSIGNED_INT32_LENGTH))[1];
1✔
196

197
        return $data1 + ($data2 << 8);
1✔
198
    }
199

200
    public function readUInt48(): int
201
    {
202
        $data = unpack('v3', $this->read(self::UNSIGNED_INT48_LENGTH));
1✔
203

204
        return $data[1] + ($data[2] << 16) + ($data[3] << 32);
1✔
205
    }
206

207
    public function readUInt56(): int
208
    {
209
        $data1 = unpack('C', $this->read(self::UNSIGNED_CHAR_LENGTH))[1];
1✔
210
        $data2 = unpack('S', $this->read(self::UNSIGNED_SHORT_LENGTH))[1];
1✔
211
        $data3 = unpack('I', $this->read(self::UNSIGNED_INT32_LENGTH))[1];
1✔
212

213
        return $data1 + ($data2 << 8) + ($data3 << 24);
1✔
214
    }
215

216
    /**
217
     * @throws BinaryDataReaderException
218
     */
219
    public function readIntBeBySize(int $size): int
220
    {
221
        if ($size === self::UNSIGNED_CHAR_LENGTH) {
21✔
222
            return $this->readInt8();
7✔
223
        }
224
        if ($size === self::UNSIGNED_SHORT_LENGTH) {
16✔
225
            return $this->readInt16Be();
3✔
226
        }
227
        if ($size === self::UNSIGNED_INT24_LENGTH) {
15✔
228
            return $this->readInt24Be();
7✔
229
        }
230
        if ($size === self::UNSIGNED_INT32_LENGTH) {
8✔
231
            return $this->readInt32Be();
2✔
232
        }
233
        if ($size === self::UNSIGNED_INT40_LENGTH) {
6✔
234
            return $this->readInt40Be();
5✔
235
        }
236

237
        throw new BinaryDataReaderException('$size ' . $size . ' not handled');
1✔
238
    }
239

240
    public function readInt8(): int
241
    {
242
        $re = unpack('c', $this->read(self::UNSIGNED_CHAR_LENGTH))[1];
11✔
243
        return $re >= 0x80 ? $re - 0x100 : $re;
11✔
244
    }
245

246
    public function readInt16Be(): int
247
    {
248
        $re = unpack('n', $this->read(self::UNSIGNED_SHORT_LENGTH))[1];
3✔
249
        return $re >= 0x8000 ? $re - 0x10000 : $re;
3✔
250
    }
251

252
    public function readInt24Be(): int
253
    {
254
        $data = unpack('C3', $this->read(self::UNSIGNED_INT24_LENGTH));
9✔
255
        $re = ($data[1] << 16) | ($data[2] << 8) | $data[3];
9✔
256
        return $re >= 0x800000 ? $re - 0x1000000 : $re;
9✔
257
    }
258

259
    public function readInt32Be(): int
260
    {
261
        $re = unpack('N', $this->read(self::UNSIGNED_INT32_LENGTH))[1];
12✔
262
        return $re >= 0x80000000 ? $re - 0x100000000 : $re;
12✔
263
    }
264

265
    public function readInt40Be(): int
266
    {
267
        $data1 = unpack('N', $this->read(self::UNSIGNED_INT32_LENGTH))[1];
5✔
268
        $data2 = unpack('C', $this->read(self::UNSIGNED_CHAR_LENGTH))[1];
5✔
269

270
        return $data2 + ($data1 << 8);
5✔
271
    }
272

273
    public function readInt32(): int
274
    {
275
        return unpack('i', $this->read(self::UNSIGNED_INT32_LENGTH))[1];
63✔
276
    }
277

278
    public function readFloat(): float
279
    {
280
        return unpack('f', $this->read(self::UNSIGNED_FLOAT_LENGTH))[1];
2✔
281
    }
282

283
    public function readDouble(): float
284
    {
285
        return unpack('d', $this->read(self::UNSIGNED_DOUBLE_LENGTH))[1];
3✔
286
    }
287

288
    public function readTableId(): string
289
    {
290
        return $this->unpackUInt64($this->read(self::UNSIGNED_INT48_LENGTH) . chr(0) . chr(0));
59✔
291
    }
292

293
    public function isComplete(int $size): bool
294
    {
295
        return ! ($this->readBytes - 20 < $size);
57✔
296
    }
297

298
    public function getBinaryDataLength(): int
299
    {
300
        return strlen($this->data);
5✔
301
    }
302

303
    public function getData(): string
304
    {
305
        return $this->data;
1✔
306
    }
307

308
    public function getBinarySlice(int $binary, int $start, int $size, int $binaryLength): int
309
    {
310
        $binary >>= $binaryLength - ($start + $size);
6✔
311
        $mask = ((1 << $size) - 1);
6✔
312

313
        return $binary & $mask;
6✔
314
    }
315

316
    public function getReadBytes(): int
317
    {
318
        return $this->readBytes;
5✔
319
    }
320
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc