Skip to content

Commit d37cbe0

Browse files
Applied changes from v4.0.0 for version supporting php<7.4
1 parent 350a15c commit d37cbe0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+511
-504
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
},
4444
"suggest": {
4545
"laudis/neo4j-php-client": "Neo4j-PHP-Client is the most advanced PHP Client for Neo4j",
46-
"ext-sockets": "Needed when using the Bolt\\connection\\Socket",
46+
"ext-sockets": "Needed when using Socket connection class",
4747
"ext-openssl": "Needed when using StreamSocket connection class with SSL"
4848
},
4949
"scripts": {

src/PackStream/v1/Packer.php

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Generator;
88
use Bolt\structures\{
99
IStructure,
10-
Relationship,
1110
Date,
1211
Time,
1312
LocalTime,
@@ -16,7 +15,8 @@
1615
LocalDateTime,
1716
Duration,
1817
Point2D,
19-
Point3D
18+
Point3D,
19+
Bytes
2020
};
2121

2222
/**
@@ -39,7 +39,6 @@ class Packer implements IPacker
3939
private $littleEndian;
4040

4141
private $structuresLt = [
42-
Relationship::class => [0x52, 'id' => 'packInteger', 'startNodeId' => 'packInteger', 'endNodeId' => 'packInteger', 'type' => 'packString', 'properties' => 'packMap'],
4342
Date::class => [0x44, 'days' => 'packInteger'],
4443
Time::class => [0x54, 'nanoseconds' => 'packInteger', 'tz_offset_seconds' => 'packInteger'],
4544
LocalTime::class => [0x74, 'nanoseconds' => 'packInteger'],
@@ -122,6 +121,8 @@ private function p($param): string
122121
case 'object':
123122
if ($param instanceof IStructure) {
124123
return $this->packStructure($param);
124+
} elseif ($param instanceof Bytes) {
125+
return $this->packByteArray($param);
125126
} else {
126127
return $this->packMap((array)$param);
127128
}
@@ -159,7 +160,8 @@ private function packString(string $str): string
159160
*/
160161
private function packFloat(float $value): string
161162
{
162-
return chr(0xC1) . strrev(pack('d', $value));
163+
$packed = pack('d', $value);
164+
return chr(0xC1) . ($this->littleEndian ? strrev($packed) : $packed);
163165
}
164166

165167
/**
@@ -169,15 +171,10 @@ private function packFloat(float $value): string
169171
*/
170172
private function packInteger(int $value): string
171173
{
172-
if ($value >= 0 && $value <= 127) { //+TINY_INT
173-
$packed = pack('C', 0b00000000 | $value);
174-
return $this->littleEndian ? strrev($packed) : $packed;
175-
} elseif ($value >= -16 && $value < 0) { //-TINY_INT
176-
$packed = pack('c', 0b11110000 | $value);
177-
return $this->littleEndian ? strrev($packed) : $packed;
174+
if ($value >= -16 && $value <= 127) { //TINY_INT
175+
return pack('c', $value);
178176
} elseif ($value >= -128 && $value <= -17) { //INT_8
179-
$packed = pack('c', $value);
180-
return chr(0xC8) . ($this->littleEndian ? strrev($packed) : $packed);
177+
return chr(0xC8) . pack('c', $value);
181178
} elseif (($value >= 128 && $value <= 32767) || ($value >= -32768 && $value <= -129)) { //INT_16
182179
$packed = pack('s', $value);
183180
return chr(0xC9) . ($this->littleEndian ? strrev($packed) : $packed);
@@ -272,4 +269,23 @@ private function packStructure(IStructure $structure): string
272269
return $output;
273270
}
274271

272+
/**
273+
* @param Bytes $bytes
274+
* @return string
275+
* @throws PackException
276+
*/
277+
private function packByteArray(Bytes $bytes): string
278+
{
279+
$size = count($bytes);
280+
if ($size < self::MEDIUM) {
281+
return chr(0xCC) . pack('C', $size) . $bytes;
282+
} elseif ($size < self::LARGE) {
283+
return chr(0xCD) . pack('n', $size) . $bytes;
284+
} elseif ($size <= 2147483647) {
285+
return chr(0xCE) . pack('N', $size) . $bytes;
286+
} else {
287+
throw new PackException('ByteArray too big');
288+
}
289+
}
290+
275291
}

src/PackStream/v1/Unpacker.php

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
LocalDateTime,
1717
Duration,
1818
Point2D,
19-
Point3D
19+
Point3D,
20+
Bytes
2021
};
2122
use Bolt\PackStream\IUnpacker;
2223
use Bolt\error\UnpackException;
@@ -145,6 +146,10 @@ private function u()
145146
if ($output !== null) {
146147
return $output;
147148
}
149+
$output = $this->unpackByteArray($marker);
150+
if ($output !== null) {
151+
return $output;
152+
}
148153

149154
return null;
150155
}
@@ -201,7 +206,7 @@ private function unpackSpecificStructure(string $class, string ...$methods): ISt
201206

202207
/**
203208
* @param int $marker
204-
* @return array
209+
* @return array|null
205210
* @throws UnpackException
206211
*/
207212
private function unpackMap(int $marker): ?array
@@ -227,7 +232,7 @@ private function unpackMap(int $marker): ?array
227232

228233
/**
229234
* @param int $marker
230-
* @return string
235+
* @return string|null
231236
*/
232237
private function unpackString(int $marker): ?string
233238
{
@@ -248,14 +253,12 @@ private function unpackString(int $marker): ?string
248253

249254
/**
250255
* @param int $marker
251-
* @return int
256+
* @return int|null
252257
*/
253258
private function unpackInteger(int $marker): ?int
254259
{
255-
if ($marker >> 7 == 0b0) { //+TINY_INT
256-
return $marker;
257-
} elseif ($marker >> 4 == 0b1111) { //-TINY_INT
258-
return (int)unpack('c', strrev(chr($marker)))[1];
260+
if ($marker >> 4 >= 0xF || $marker >> 4 <= 0x7) { //TINY_INT
261+
return (int)unpack('c', chr($marker))[1];
259262
} elseif ($marker == 0xC8) { //INT_8
260263
return (int)unpack('c', $this->next(1))[1];
261264
} elseif ($marker == 0xC9) { //INT_16
@@ -266,28 +269,29 @@ private function unpackInteger(int $marker): ?int
266269
return (int)unpack('l', $this->littleEndian ? strrev($value) : $value)[1];
267270
} elseif ($marker == 0xCB) { //INT_64
268271
$value = $this->next(8);
269-
return (int)unpack("q", $this->littleEndian ? strrev($value) : $value)[1];
272+
return (int)unpack('q', $this->littleEndian ? strrev($value) : $value)[1];
270273
} else {
271274
return null;
272275
}
273276
}
274277

275278
/**
276279
* @param int $marker
277-
* @return float
280+
* @return float|null
278281
*/
279282
private function unpackFloat(int $marker): ?float
280283
{
281284
if ($marker == 0xC1) {
282-
return (float)unpack('d', strrev($this->next(8)))[1];
285+
$value = $this->next(8);
286+
return (float)unpack('d', $this->littleEndian ? strrev($value) : $value)[1];
283287
} else {
284288
return null;
285289
}
286290
}
287291

288292
/**
289293
* @param int $marker
290-
* @return array
294+
* @return array|null
291295
* @throws UnpackException
292296
*/
293297
private function unpackList(int $marker): ?array
@@ -312,4 +316,23 @@ private function unpackList(int $marker): ?array
312316
return $output;
313317
}
314318

319+
/**
320+
* @param int $marker
321+
* @return Bytes|null
322+
*/
323+
private function unpackByteArray(int $marker): ?Bytes
324+
{
325+
if ($marker == 0xCC) {
326+
$size = (int)unpack('C', $this->next(1))[1];
327+
} elseif ($marker == 0xCD) {
328+
$size = (int)unpack('n', $this->next(2))[1];
329+
} elseif ($marker == 0xCE) {
330+
$size = (int)unpack('N', $this->next(4))[1];
331+
} else {
332+
return null;
333+
}
334+
335+
return new Bytes(str_split($this->next($size)));
336+
}
337+
315338
}

src/connection/AConnection.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,14 @@ abstract class AConnection implements IConnection
2323
protected $port;
2424

2525
/**
26-
* @var int
26+
* @var float
2727
*/
2828
protected $timeout;
2929

3030
/**
31-
* AConnection constructor.
32-
* @param string $ip
33-
* @param int $port
34-
* @param int|float $timeout
31+
* @inheritDoc
3532
*/
36-
public function __construct(string $ip = '127.0.0.1', int $port = 7687, $timeout = 15)
33+
public function __construct(string $ip = '127.0.0.1', int $port = 7687, float $timeout = 15)
3734
{
3835
$this->ip = $ip;
3936
$this->port = $port;
@@ -43,18 +40,17 @@ public function __construct(string $ip = '127.0.0.1', int $port = 7687, $timeout
4340
/**
4441
* Print buffer as HEX
4542
* @param string $str
46-
* @param bool $write
43+
* @param string $prefix
4744
*/
48-
protected function printHex(string $str, bool $write = true)
45+
protected function printHex(string $str, string $prefix = 'C: ')
4946
{
5047
$str = implode(unpack('H*', $str));
51-
echo '<pre>';
52-
echo $write ? '> ' : '< ';
48+
echo '<pre>' . $prefix;
5349
foreach (str_split($str, 8) as $chunk) {
5450
echo implode(' ', str_split($chunk, 2));
5551
echo ' ';
5652
}
57-
echo '</pre>';
53+
echo '</pre>' . PHP_EOL;
5854
}
5955

6056
public function getIp(): string
@@ -72,7 +68,7 @@ public function getTimeout(): float
7268
return $this->timeout;
7369
}
7470

75-
public function setTimeout(float $timeout): void
71+
public function setTimeout(float $timeout)
7672
{
7773
$this->timeout = $timeout;
7874
}

src/connection/IConnection.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ interface IConnection
1414
/**
1515
* @param string $ip
1616
* @param int $port
17-
* @param int|float $timeout
17+
* @param float $timeout
1818
*/
19-
public function __construct(string $ip = '127.0.0.1', int $port = 7687, $timeout = 15);
19+
public function __construct(string $ip = '127.0.0.1', int $port = 7687, float $timeout = 15);
2020

2121
public function connect(): bool;
2222

@@ -32,5 +32,5 @@ public function getPort(): int;
3232

3333
public function getTimeout(): float;
3434

35-
public function setTimeout(float $timeout): void;
35+
public function setTimeout(float $timeout);
3636
}

src/connection/Socket.php

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,12 @@
1515
*/
1616
class Socket extends AConnection
1717
{
18-
1918
/**
2019
* @var resource|object|bool
2120
*/
2221
private $socket = false;
2322

2423
private const POSSIBLE_TIMEOUTS_CODES = [11, 10060];
25-
/** @var float|null */
26-
private $timetAtTimeoutConfiguration;
2724

2825
/**
2926
* Create socket connection
@@ -69,18 +66,14 @@ public function write(string $buffer)
6966
throw new ConnectException('Not initialized socket');
7067
}
7168

72-
$size = mb_strlen($buffer, '8bit');
73-
$sent = 0;
74-
7569
if (Bolt::$debug)
7670
$this->printHex($buffer);
7771

72+
$size = mb_strlen($buffer, '8bit');
7873
while (0 < $size) {
7974
$sent = @socket_write($this->socket, $buffer, $size);
80-
if ($sent === false) {
75+
if ($sent === false)
8176
$this->throwConnectException();
82-
}
83-
8477
$buffer = mb_strcut($buffer, $sent, null, '8bit');
8578
$size -= $sent;
8679
}
@@ -94,22 +87,19 @@ public function write(string $buffer)
9487
*/
9588
public function read(int $length = 2048): string
9689
{
97-
$output = '';
98-
99-
if ($this->socket === false) {
90+
if ($this->socket === false)
10091
throw new ConnectException('Not initialized socket');
101-
}
10292

93+
$output = '';
10394
do {
10495
$readed = @socket_read($this->socket, $length - mb_strlen($output, '8bit'), PHP_BINARY_READ);
105-
if ($readed === false) {
96+
if ($readed === false)
10697
$this->throwConnectException();
107-
}
10898
$output .= $readed;
10999
} while (mb_strlen($output, '8bit') < $length);
110100

111101
if (Bolt::$debug)
112-
$this->printHex($output, false);
102+
$this->printHex($output, 'S: ');
113103

114104
return $output;
115105
}
@@ -125,20 +115,21 @@ public function disconnect()
125115
}
126116
}
127117

128-
public function setTimeout(float $timeout): void
118+
public function setTimeout(float $timeout)
129119
{
130120
parent::setTimeout($timeout);
131121
$this->configureTimeout();
132122
}
133123

134-
private function configureTimeout(): void
124+
private function configureTimeout()
135125
{
126+
if ($this->socket === false)
127+
return;
136128
$timeoutSeconds = floor($this->timeout);
137129
$microSeconds = floor(($this->timeout - $timeoutSeconds) * 1000000);
138130
$timeoutOption = ['sec' => $timeoutSeconds, 'usec' => $microSeconds];
139131
socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, $timeoutOption);
140132
socket_set_option($this->socket, SOL_SOCKET, SO_SNDTIMEO, $timeoutOption);
141-
$this->timetAtTimeoutConfiguration = microtime(true);
142133
}
143134

144135
/**
@@ -149,11 +140,8 @@ private function throwConnectException(): void
149140
{
150141
$code = socket_last_error($this->socket);
151142
if (in_array($code, self::POSSIBLE_TIMEOUTS_CODES)) {
152-
$timediff = microtime(true) - $this->timetAtTimeoutConfiguration;
153-
if ($timediff >= $this->timeout) {
154-
throw ConnectionTimeoutException::createFromTimeout($this->timeout);
155-
}
156-
} else if ($code !== 0) {
143+
throw new ConnectionTimeoutException('Connection timeout reached after ' . $this->timeout . ' seconds.');
144+
} elseif ($code !== 0) {
157145
throw new ConnectException(socket_strerror($code), $code);
158146
}
159147
}

0 commit comments

Comments
 (0)