Passed
Push — trunk ( aca09f...bd7f95 )
by Christian
14:04 queued 13s
created

PhpBinaryFinder::find()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 30
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 8
nop 0
dl 0
loc 30
rs 9.2222
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Shopware\WebInstaller\Services;
5
6
use Shopware\Core\Framework\Log\Package;
7
use Symfony\Component\Process\Exception\ProcessSignaledException;
8
use Symfony\Component\Process\ExecutableFinder;
9
use Symfony\Component\Process\Process;
10
11
/**
12
 * @internal
13
 *
14
 * @codeCoverageIgnore
15
 */
16
#[Package('core')]
17
class PhpBinaryFinder
18
{
19
    private const PHP_BINARY_NAMES = ['php8.2', 'php8.1', 'php'];
20
21
    private const PHP_KNOWN_LOCATIONS = [
22
        '/opt/plesk/php/{major}.{minor}/bin/php',
23
        '/bin/php{major}{minor}',
24
        '/opt/RZphp{major}{minor}/bin/php-cli',
25
        '/opt/alt/php{major}{minor}/usr/bin/php',
26
        '/opt/php-{major}.{minor}.{release}/bin/php',
27
        '/opt/php-{major}.{minor}/bin/php',
28
        '/opt/php{major}.{minor}/bin/php',
29
        '/opt/php{major}{minor}/bin/php',
30
        '/opt/php{major}/bin/php',
31
        '/usr/bin/php{major}.{minor}-cli',
32
        '/usr/bin/php{major}.{minor}',
33
        '/usr/bin/php{major}{minor}',
34
        '/usr/bin/php{major}{minor}/php{major}',
35
        '/usr/bin/php{major}',
36
        '/usr/iports/php{major}{minor}/bin/php',
37
        '/usr/lib/cgi-bin/php{major}.{minor}',
38
        '/usr/lib64/php{major}.{minor}/bin/php',
39
        '/usr/local/bin/edis-php-cli-{major}{minor}-stable-openssl',
40
        '/usr/local/bin/edis-php-cli-{major}{minor}',
41
        '/usr/local/bin/php{major}-{major}{minor}LATEST-CLI',
42
        '/usr/local/bin/php{major}.{minor}.{release}-cli',
43
        '/usr/local/php-{major}.{minor}/bin/php',
44
        '/usr/local/php{major}{minor}/bin/php',
45
        '/usr/local/php{major}.{minor}/bin/php',
46
        '/usr/local/phpfarm/inst/php-{major}.{minor}/bin/php',
47
        '/usr/local/php{major}{minor}/bin/php',
48
        '/opt/phpbrew/php/php-{major}.{minor}/bin/php',
49
        '/opt/phpfarm/inst/php-{major}.{minor}/bin/php-cgi',
50
        '/vrmd/webserver/php{major}{minor}/bin/php',
51
        '/package/host/localhost/php-{major}.{minor}/bin/php',
52
        '/Applications/MAMP/bin/php/php{major}.{minor}.{release}/bin/php',
53
        '/usr/local/bin/php_cli',
54
        '/usr/local/bin/php',
55
        '/usr/bin/php',
56
    ];
57
58
    public function find(): string
59
    {
60
        // Look for specific PHP binaries by hosters
61
        if ($hosterSpecificBinary = $this->findHostedSpecificBinary()) {
62
            return $hosterSpecificBinary;
63
        }
64
65
        // Look for PHP binaries in same place as our fpm/cgi binary
66
        if (\defined('PHP_BINARY')) {
67
            $phpPath = \dirname(\PHP_BINARY);
68
            $fileName = explode('-', basename(\PHP_BINARY), 2);
69
            $expectedPath = $phpPath . \DIRECTORY_SEPARATOR . $fileName[0];
70
71
            if ($this->isPHPRunning($expectedPath)) {
72
                return $expectedPath;
73
            }
74
        }
75
76
        // Look into PHP path
77
        $finder = new ExecutableFinder();
78
79
        foreach (self::PHP_BINARY_NAMES as $name) {
80
            $binary = $finder->find($name);
81
82
            if ($binary !== null) {
83
                return $binary;
84
            }
85
        }
86
87
        return '';
88
    }
89
90
    private function findHostedSpecificBinary(): ?string
91
    {
92
        foreach (self::PHP_KNOWN_LOCATIONS as $knownLocation) {
93
            $path = $this->getPhpVersionPath($knownLocation);
94
95
            if ($this->isPHPRunning($path)) {
96
                return $path;
97
            }
98
        }
99
100
        return null;
101
    }
102
103
    private function getPhpVersionPath(string $path): string
104
    {
105
        return str_replace(
106
            [
107
                '{major}',
108
                '{minor}',
109
                '{release}',
110
                '{extra}',
111
            ],
112
            [
113
                \PHP_MAJOR_VERSION,
114
                \PHP_MINOR_VERSION,
115
                \PHP_RELEASE_VERSION,
116
                \PHP_EXTRA_VERSION,
117
            ],
118
            $path
119
        );
120
    }
121
122
    private function isPHPRunning(string $path): bool
123
    {
124
        $process = new Process([$path, '-v']);
125
126
        try {
127
            $process->run();
128
        } catch (ProcessSignaledException) {
129
            return false;
130
        }
131
132
        return $process->isSuccessful();
133
    }
134
}
135