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.
Test Setup Failed
Pull Request — master (#31)
by Oliver
01:47
created

PharInvocationResolver   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 82
dl 0
loc 211
rs 9.84
c 0
b 0
f 0
wmc 32

8 Methods

Rating   Name   Duplication   Size   Complexity  
C resolveBaseName() 0 43 12
A findByAlias() 0 11 2
A resolvePossibleAlias() 0 4 2
A resolve() 0 22 6
A retrieveInvocation() 0 14 3
A addBaseName() 0 6 2
A findInBaseNames() 0 18 4
A findByBaseName() 0 7 1
1
<?php
2
declare(strict_types=1);
3
namespace TYPO3\PharStreamWrapper\Resolver;
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
use TYPO3\PharStreamWrapper\Helper;
16
use TYPO3\PharStreamWrapper\Manager;
17
use TYPO3\PharStreamWrapper\Phar\Reader;
18
use TYPO3\PharStreamWrapper\Resolvable;
19
20
class PharInvocationResolver implements Resolvable
21
{
22
    const RESOLVE_REALPATH = 1;
23
    const RESOLVE_ALIAS = 2;
24
    const ASSERT_INTERNAL_INVOCATION = 32;
25
26
    /**
27
     * @var string[]
28
     */
29
    private $invocationFunctionNames = [
30
        'include',
31
        'include_once',
32
        'require',
33
        'require_once'
34
    ];
35
36
    /**
37
     * Contains resolved base names in order to reduce file IO.
38
     *
39
     * @var string[]
40
     */
41
    private $baseNames = [];
42
43
    /**
44
     * Resolves PharInvocation value object (baseName and optional alias).
45
     *
46
     * Phar aliases are intended to be used only inside Phar archives, however
47
     * PharStreamWrapper needs this information exposed outside of Phar as well
48
     * It is possible that same alias is used for different $baseName values.
49
     * That's why PharInvocationCollection behaves like a stack when resolving
50
     * base-name for a given alias. On the other hand it is not possible that
51
     * one $baseName is referring to multiple aliases.
52
     * @see https://secure.php.net/manual/en/phar.setalias.php
53
     * @see https://secure.php.net/manual/en/phar.mapphar.php
54
     *
55
     * @param string $path
56
     * @param int|null $flags
57
     * @return null|PharInvocation
58
     */
59
    public function resolve(string $path, int $flags = null)
60
    {
61
        $hasPharPrefix = Helper::hasPharPrefix($path);
62
        $flags = $flags ?? static::RESOLVE_REALPATH | static::RESOLVE_ALIAS | static::ASSERT_INTERNAL_INVOCATION;
63
64
        if ($hasPharPrefix && $flags & static::RESOLVE_ALIAS) {
65
            $invocation = $this->findByAlias($path);
66
            if ($invocation !== null) {
67
                return $invocation;
68
            }
69
        }
70
71
        $baseName = $this->resolveBaseName($path, $flags);
72
        if ($baseName === null) {
73
            return null;
74
        }
75
76
        if ($flags & static::RESOLVE_REALPATH) {
77
            $baseName = $this->baseNames[$baseName];
78
        }
79
80
        return $this->retrieveInvocation($baseName, $flags);
81
    }
82
83
    /**
84
     * Retrieves PharInvocation, either existing in collection or created on demand
85
     * with resolving a potential alias name used in the according Phar archive.
86
     *
87
     * @param string $baseName
88
     * @param int $flags
89
     * @return PharInvocation
90
     */
91
    private function retrieveInvocation(string $baseName, int $flags): PharInvocation
92
    {
93
        $invocation = $this->findByBaseName($baseName);
94
        if ($invocation !== null) {
95
            return $invocation;
96
        }
97
98
        if ($flags & static::RESOLVE_ALIAS) {
99
            $alias = (new Reader($baseName))->resolveContainer()->getAlias();
100
        } else {
101
            $alias = '';
102
        }
103
104
        return new PharInvocation($baseName, $alias);
105
    }
106
107
    /**
108
     * @param string $path
109
     * @param int $flags
110
     * @return null|string
111
     */
112
    private function resolveBaseName(string $path, int $flags)
113
    {
114
        $baseName = $this->findInBaseNames($path);
115
        if ($baseName !== null) {
116
            return $baseName;
117
        }
118
119
        $baseName = Helper::determineBaseFile($path);
120
        if ($baseName !== null) {
121
            $this->addBaseName($baseName);
122
            return $baseName;
123
        }
124
125
        $possibleAlias = $this->resolvePossibleAlias($path);
126
        if (!($flags & static::RESOLVE_ALIAS) || $possibleAlias === null) {
127
            return null;
128
        }
129
130
        $trace = debug_backtrace();
131
        foreach ($trace as $item) {
132
            if (!isset($item['function']) || !isset($item['args'][0])
133
                || !in_array($item['function'], $this->invocationFunctionNames, true)) {
134
                continue;
135
            }
136
            $currentPath = $item['args'][0];
137
            if (Helper::hasPharPrefix($currentPath)) {
138
                continue;
139
            }
140
            $currentBaseName = Helper::determineBaseFile($currentPath);
141
            if ($currentBaseName === null) {
142
                continue;
143
            }
144
            // ensure the possible alias name (how we have been called initially) matches
145
            // the resolved alias name that was retrieved by the current possible base name
146
            $currentAlias = (new Reader($currentBaseName))->resolveContainer()->getAlias();
147
            if ($currentAlias !== $possibleAlias) {
148
                continue;
149
            }
150
            $this->addBaseName($currentBaseName);
151
            return $currentBaseName;
152
        }
153
154
        return null;
155
    }
156
157
    /**
158
     * @param string $path
159
     * @return null|string
160
     */
161
    private function resolvePossibleAlias(string $path)
162
    {
163
        $normalizedPath = Helper::normalizePath($path);
164
        return strstr($normalizedPath, '/', true) ?: null;
165
    }
166
167
    /**
168
     * @param string $baseName
169
     * @return null|PharInvocation
170
     */
171
    private function findByBaseName(string $baseName)
172
    {
173
        return Manager::instance()->getCollection()->findByCallback(
174
            function (PharInvocation $candidate) use ($baseName) {
175
                return $candidate->getBaseName() === $baseName;
176
            },
177
            true
178
        );
179
    }
180
181
    /**
182
     * @param string $path
183
     * @return null|string
184
     */
185
    private function findInBaseNames(string $path)
186
    {
187
        // return directly if the resolved base name was submitted
188
        if (in_array($path, $this->baseNames, true)) {
189
            return $path;
190
        }
191
192
        $parts = explode('/', Helper::normalizePath($path));
193
194
        while (count($parts)) {
195
            $currentPath = implode('/', $parts);
196
            if (isset($this->baseNames[$currentPath])) {
197
                return $currentPath;
198
            }
199
            array_pop($parts);
200
        }
201
202
        return null;
203
    }
204
205
    /**
206
     * @param string $baseName
207
     */
208
    private function addBaseName(string $baseName)
209
    {
210
        if (isset($this->baseNames[$baseName])) {
211
            return;
212
        }
213
        $this->baseNames[$baseName] = realpath($baseName);
214
    }
215
216
    /**
217
     * @param string $path
218
     * @return null|PharInvocation
219
     */
220
    private function findByAlias(string $path)
221
    {
222
        $possibleAlias = $this->resolvePossibleAlias($path);
223
        if ($possibleAlias === null) {
224
            return null;
225
        }
226
        return Manager::instance()->getCollection()->findByCallback(
227
            function (PharInvocation $candidate) use ($possibleAlias) {
228
                return $candidate->getAlias() === $possibleAlias;
229
            },
230
            true
231
        );
232
    }
233
}
234