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 ( dbc6f7...fff6f5 )
by Oliver
03:52
created

PharInvocationResolver::findByAlias()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 2
nop 1
dl 0
loc 11
rs 10
c 0
b 0
f 0
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
        // add unconfirmed(!) new invocation to collection
104
        $invocation = new PharInvocation($baseName, $alias);
105
        Manager::instance()->getCollection()->collect($invocation);
106
        return $invocation;
107
    }
108
109
    /**
110
     * @param string $path
111
     * @param int $flags
112
     * @return null|string
113
     */
114
    private function resolveBaseName(string $path, int $flags)
115
    {
116
        $baseName = $this->findInBaseNames($path);
117
        if ($baseName !== null) {
118
            return $baseName;
119
        }
120
121
        $baseName = Helper::determineBaseFile($path);
122
        if ($baseName !== null) {
123
            $this->addBaseName($baseName);
124
            return $baseName;
125
        }
126
127
        $possibleAlias = $this->resolvePossibleAlias($path);
128
        if (!($flags & static::RESOLVE_ALIAS) || $possibleAlias === null) {
129
            return null;
130
        }
131
132
        $trace = debug_backtrace();
133
        foreach ($trace as $item) {
134
            if (!isset($item['function']) || !isset($item['args'][0])
135
                || !in_array($item['function'], $this->invocationFunctionNames, true)) {
136
                continue;
137
            }
138
            $currentPath = $item['args'][0];
139
            if (Helper::hasPharPrefix($currentPath)) {
140
                continue;
141
            }
142
            $currentBaseName = Helper::determineBaseFile($currentPath);
143
            if ($currentBaseName === null) {
144
                continue;
145
            }
146
            // ensure the possible alias name (how we have been called initially) matches
147
            // the resolved alias name that was retrieved by the current possible base name
148
            $currentAlias = (new Reader($currentBaseName))->resolveContainer()->getAlias();
149
            if ($currentAlias !== $possibleAlias) {
150
                continue;
151
            }
152
            $this->addBaseName($currentBaseName);
153
            return $currentBaseName;
154
        }
155
156
        return null;
157
    }
158
159
    /**
160
     * @param string $path
161
     * @return null|string
162
     */
163
    private function resolvePossibleAlias(string $path)
164
    {
165
        $normalizedPath = Helper::normalizePath($path);
166
        return strstr($normalizedPath, '/', true) ?: null;
167
    }
168
169
    /**
170
     * @param string $baseName
171
     * @return null|PharInvocation
172
     */
173
    private function findByBaseName(string $baseName)
174
    {
175
        return Manager::instance()->getCollection()->findByCallback(
176
            function (PharInvocation $candidate) use ($baseName) {
177
                return $candidate->getBaseName() === $baseName;
178
            },
179
            true
180
        );
181
    }
182
183
    /**
184
     * @param string $path
185
     * @return null|string
186
     */
187
    private function findInBaseNames(string $path)
188
    {
189
        // return directly if the resolved base name was submitted
190
        if (in_array($path, $this->baseNames, true)) {
191
            return $path;
192
        }
193
194
        $parts = explode('/', Helper::normalizePath($path));
195
196
        while (count($parts)) {
197
            $currentPath = implode('/', $parts);
198
            if (isset($this->baseNames[$currentPath])) {
199
                return $currentPath;
200
            }
201
            array_pop($parts);
202
        }
203
204
        return null;
205
    }
206
207
    /**
208
     * @param string $baseName
209
     */
210
    private function addBaseName(string $baseName)
211
    {
212
        if (isset($this->baseNames[$baseName])) {
213
            return;
214
        }
215
        $this->baseNames[$baseName] = realpath($baseName);
216
    }
217
218
    /**
219
     * Finds confirmed(!) invocations by alias.
220
     *
221
     * @param string $path
222
     * @return null|PharInvocation
223
     * @see \TYPO3\PharStreamWrapper\PharStreamWrapper::collectInvocation()
224
     */
225
    private function findByAlias(string $path)
226
    {
227
        $possibleAlias = $this->resolvePossibleAlias($path);
228
        if ($possibleAlias === null) {
229
            return null;
230
        }
231
        return Manager::instance()->getCollection()->findByCallback(
232
            function (PharInvocation $candidate) use ($possibleAlias) {
233
                return $candidate->isConfirmed() && $candidate->getAlias() === $possibleAlias;
234
            },
235
            true
236
        );
237
    }
238
}
239