Completed
Pull Request — master (#11)
by Alexander
02:53
created

FrameParser   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 85.71%

Importance

Changes 0
Metric Value
wmc 6
lcom 1
cbo 1
dl 0
loc 75
c 0
b 0
f 0
ccs 18
cts 21
cp 0.8571
rs 10
1
<?php
2
/*
3
 * Protocol FCGI library
4
 *
5
 * @copyright Copyright 2021. Lisachenko Alexander <[email protected]>
6
 * This source file is subject to the license that is bundled
7
 * with this source code in the file LICENSE.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Lisachenko\Protocol\FCGI;
13
14
use Lisachenko\Protocol\FCGI;
15
16
/**
17
 * Utility class to simplify parsing of FCGI protocol data.
18
 *
19
 * @author Alexander.Lisachenko
20
 */
21
class FrameParser
22
{
23
    /**
24
     * Mapping of constants to the classes
25
     * @phpstan-var array<int, class-string>
26
     */
27
    protected static array $classMapping = [
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_ARRAY, expecting T_FUNCTION or T_CONST
Loading history...
28
        FCGI::BEGIN_REQUEST     => FCGI\Record\BeginRequest::class,
29
        FCGI::ABORT_REQUEST     => FCGI\Record\AbortRequest::class,
30
        FCGI::END_REQUEST       => FCGI\Record\EndRequest::class,
31
        FCGI::PARAMS            => FCGI\Record\Params::class,
32
        FCGI::STDIN             => FCGI\Record\Stdin::class,
33
        FCGI::STDOUT            => FCGI\Record\Stdout::class,
34
        FCGI::STDERR            => FCGI\Record\Stderr::class,
35
        FCGI::DATA              => FCGI\Record\Data::class,
36
        FCGI::GET_VALUES        => FCGI\Record\GetValues::class,
37
        FCGI::GET_VALUES_RESULT => FCGI\Record\GetValuesResult::class,
38
        FCGI::UNKNOWN_TYPE      => FCGI\Record\UnknownType::class,
39
    ];
40
41
    /**
42 1
     * Checks if the buffer contains a valid frame to parse
43
     */
44 1
    public static function hasFrame(string $binaryBuffer): bool
45 1
    {
46
        $bufferLength = strlen($binaryBuffer);
47
        if ($bufferLength < FCGI::HEADER_LEN) {
48
            return false;
49 1
        }
50 1
51 1
        /** @phpstan-var false|array{version: int, type: int, requestId: int, contentLength: int, paddingLength: int} */
52
        $fastInfo = unpack(FCGI::HEADER_FORMAT, $binaryBuffer);
53
        if ($fastInfo === false) {
54 1
            throw new \RuntimeException('Can not unpack data from the binary buffer');
55
        }
56
        if ($bufferLength < FCGI::HEADER_LEN + $fastInfo['contentLength'] + $fastInfo['paddingLength']) {
57
            return false;
58
        }
59
60
        return true;
61
    }
62
63
    /**
64 1
     * Parses a frame from the binary buffer
65
     *
66 1
     * @return Record One of the corresponding FCGI record
67 1
     */
68
    public static function parseFrame(string &$binaryBuffer): Record
69
    {
70 1
        $bufferLength = strlen($binaryBuffer);
71 1
        if ($bufferLength < FCGI::HEADER_LEN) {
72 1
            throw new \RuntimeException("Not enough data in the buffer to parse");
73
        }
74
        /** @phpstan-var false|array{version: int, type: int, requestId: int, contentLength: int, paddingLength: int} */
75
        $recordHeader = unpack(FCGI::HEADER_FORMAT, $binaryBuffer);
76
        if ($recordHeader === false) {
77 1
            throw new \RuntimeException('Can not unpack data from the binary buffer');
78 1
        }
79
        $recordType = $recordHeader['type'];
80
        if (!isset(self::$classMapping[$recordType])) {
81 1
            throw new \DomainException("Invalid FCGI record type {$recordType} received");
82 1
        }
83
84 1
        /** @var Record $className */
85
        $className = self::$classMapping[$recordType];
86
        $record    = $className::unpack($binaryBuffer);
87
88
        $offset       = FCGI::HEADER_LEN + $record->getContentLength() + $record->getPaddingLength();
89
        $binaryBuffer = substr($binaryBuffer, $offset);
90
91
        return $record;
92
    }
93
94
}
95