GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( b4f049...957735 )
by Oliver
01:06
created

Reader::determineFileTypeByHeader()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 0
dl 0
loc 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
namespace TYPO3\PharStreamWrapper\Phar;
4
5
/*
6
 * This file is part of the TYPO3 project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under the terms
9
 * of the MIT License (MIT). For the full copyright and license information,
10
 * please read the LICENSE file that was distributed with this source code.
11
 *
12
 * The TYPO3 project - inspiring people to share!
13
 */
14
15
class Reader
16
{
17
    /**
18
     * @var string
19
     */
20
    private $fileName;
21
22
    /**
23
     * Mime-type in order to use zlib, bzip2 or no compression.
24
     * In case ext-fileinfo is not present only the relevant types
25
     * 'application/x-gzip' and 'application/x-bzip2' are assigned
26
     * to this class property.
27
     *
28
     * @var string
29
     */
30
    private $fileType;
31
32
    /**
33
     * @param string $fileName
34
     */
35
    public function __construct(string $fileName)
36
    {
37
        if (strpos($fileName, '://') !== false) {
38
            throw new ReaderException(
39
                'File name must not contain stream prefix',
40
                1539623708
41
            );
42
        }
43
44
        $this->fileName = $fileName;
45
        $this->fileType = $this->determineFileType();
46
    }
47
48
    /**
49
     * @return Container
50
     */
51
    public function resolveContainer(): Container
52
    {
53
        $data = $this->extractData($this->resolveStream() . $this->fileName);
54
55
        if ($data['stubContent'] === null) {
56
            throw new ReaderException(
57
                'Cannot resolve stub',
58
                1547807881
59
            );
60
        }
61
        if ($data['manifestContent'] === null || $data['manifestLength'] === null) {
62
            throw new ReaderException(
63
                'Cannot resolve manifest',
64
                1547807882
65
            );
66
        }
67
        if (strlen($data['manifestContent']) < $data['manifestLength']) {
68
            throw new ReaderException(
69
                sprintf(
70
                    'Exected manifest length %d, got %d',
71
                    strlen($data['manifestContent']),
72
                    $data['manifestLength']
73
                ),
74
                1547807883
75
            );
76
        }
77
78
        return new Container(
79
            Stub::fromContent($data['stubContent']),
80
            Manifest::fromContent($data['manifestContent'])
81
        );
82
    }
83
84
    /**
85
     * @param string $fileName e.g. '/path/file.phar' or 'compress.zlib:///path/file.phar'
86
     * @return array
87
     */
88
    private function extractData(string $fileName): array
89
    {
90
        $stubContent = null;
91
        $manifestContent = null;
92
        $manifestLength = null;
93
94
        $resource = fopen($fileName, 'r');
95
        if (!is_resource($resource)) {
96
            throw new ReaderException(
97
                sprintf('Resource %s could not be opened', $fileName),
98
                1547902055
99
            );
100
        }
101
102
        while (!feof($resource)) {
103
            $line = fgets($resource);
104
            // stop reading file when manifest can be extracted
105
            if ($manifestLength !== null && $manifestContent !== null && strlen($manifestContent) >= $manifestLength) {
106
                break;
107
            }
108
109
            $manifestPosition = strpos($line, '__HALT_COMPILER();');
110
111
            // first line contains start of manifest
112
            if ($stubContent === null && $manifestContent === null && $manifestPosition !== false) {
113
                $stubContent = substr($line, 0, $manifestPosition - 1);
114
                $manifestContent = preg_replace('#^.*__HALT_COMPILER\(\);(?>[ \n]\?>(?>\r\n|\n)?)?#', '', $line);
115
                $manifestLength = $this->resolveManifestLength($manifestContent);
116
            // line contains start of stub
117
            } elseif ($stubContent === null) {
118
                $stubContent = $line;
119
            // line contains start of manifest
120
            } elseif ($manifestContent === null && $manifestPosition !== false) {
121
                $manifestContent = preg_replace('#^.*__HALT_COMPILER\(\);(?>[ \n]\?>(?>\r\n|\n)?)?#', '', $line);
122
                $manifestLength = $this->resolveManifestLength($manifestContent);
123
            // manifest has been started (thus is cannot be stub anymore), add content
124
            } elseif ($manifestContent !== null) {
125
                $manifestContent .= $line;
126
                $manifestLength = $this->resolveManifestLength($manifestContent);
127
            // stub has been started (thus cannot be manifest here, yet), add content
128
            } elseif ($stubContent !== null) {
129
                $stubContent .= $line;
130
            }
131
        }
132
        fclose($resource);
133
134
        return [
135
            'stubContent' => $stubContent,
136
            'manifestContent' => $manifestContent,
137
            'manifestLength' => $manifestLength,
138
        ];
139
    }
140
141
    /**
142
     * Resolves stream in order to handle compressed Phar archives.
143
     *
144
     * @return string
145
     */
146
    private function resolveStream(): string
147
    {
148
        if ($this->fileType === 'application/x-gzip') {
149
            return 'compress.zlib://';
150
        } elseif ($this->fileType === 'application/x-bzip2') {
151
            return 'compress.bzip2://';
152
        }
153
        return '';
154
    }
155
156
    /**
157
     * @return string
158
     */
159
    private function determineFileType()
160
    {
161
        if (class_exists('\\finfo')) {
162
            $fileInfo = new \finfo();
163
            return $fileInfo->file($this->fileName, FILEINFO_MIME_TYPE);
164
        }
165
        return $this->determineFileTypeByHeader();
166
    }
167
168
    /**
169
     * In case ext-fileinfo is not present only the relevant types
170
     * 'application/x-gzip' and 'application/x-bzip2' are resolved.
171
     *
172
     * @return string
173
     */
174
    private function determineFileTypeByHeader(): string
175
    {
176
        $resource = fopen($this->fileName, 'r');
177
        $header = fgets($resource, 4);
0 ignored issues
show
Bug introduced by
It seems like $resource can also be of type false; however, parameter $handle of fgets() does only seem to accept resource, 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

177
        $header = fgets(/** @scrutinizer ignore-type */ $resource, 4);
Loading history...
178
        fclose($resource);
0 ignored issues
show
Bug introduced by
It seems like $resource can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, 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

178
        fclose(/** @scrutinizer ignore-type */ $resource);
Loading history...
179
        $mimeType = '';
180
        if (strpos($header, "\x42\x5a\x68") === 0) {
181
            $mimeType = 'application/x-bzip2';
182
        } elseif (strpos($header, "\x1f\x8b") === 0) {
183
            $mimeType = 'application/x-gzip';
184
        }
185
        return $mimeType;
186
    }
187
188
    /**
189
     * @param string $content
190
     * @return int|null
191
     */
192
    private function resolveManifestLength(string $content)
193
    {
194
        if (strlen($content) < 4) {
195
            return null;
196
        }
197
        return static::resolveFourByteLittleEndian($content, 0);
198
    }
199
200
    /**
201
     * @param string $content
202
     * @param int $start
203
     * @return int
204
     */
205
    public static function resolveFourByteLittleEndian(string $content, int $start): int
206
    {
207
        $payload = substr($content, $start, 4);
208
        if (!is_string($payload)) {
0 ignored issues
show
introduced by
The condition is_string($payload) is always true.
Loading history...
209
            throw new ReaderException(
210
                sprintf('Cannot resolve value at offset %d', $start),
211
                1539614260
212
            );
213
        }
214
215
        $value = unpack('V', $payload);
216
        if (!isset($value[1])) {
217
            throw new ReaderException(
218
                sprintf('Cannot resolve value at offset %d', $start),
219
                1539614261
220
            );
221
        }
222
        return $value[1];
223
    }
224
225
    /**
226
     * @param string $content
227
     * @param int $start
228
     * @return int
229
     */
230
    public static function resolveTwoByteBigEndian(string $content, int $start): int
231
    {
232
        $payload = substr($content, $start, 2);
233
        if (!is_string($payload)) {
0 ignored issues
show
introduced by
The condition is_string($payload) is always true.
Loading history...
234
            throw new ReaderException(
235
                sprintf('Cannot resolve value at offset %d', $start),
236
                1539614263
237
            );
238
        }
239
240
        $value = unpack('n', $payload);
241
        if (!isset($value[1])) {
242
            throw new ReaderException(
243
                sprintf('Cannot resolve value at offset %d', $start),
244
                1539614264
245
            );
246
        }
247
        return $value[1];
248
    }
249
}
250