Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
72.34% |
34 / 47 |
|
20.00% |
1 / 5 |
CRAP | |
0.00% |
0 / 1 |
LocateBinaries | |
72.34% |
34 / 47 |
|
20.00% |
1 / 5 |
24.86 | |
0.00% |
0 / 1 |
locateInCommonSystemPaths | |
77.78% |
14 / 18 |
|
0.00% |
0 / 1 |
4.18 | |||
locateBinariesUsingWhereIs | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
5.03 | |||
locateBinariesUsingWhich | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
locateBinariesUsingWhere | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
locateInstalledBinaries | |
63.64% |
7 / 11 |
|
0.00% |
0 / 1 |
6.20 |
1 | <?php |
2 | |
3 | namespace LocateBinaries; |
4 | |
5 | use FileUtil\FileExists; |
6 | use ExecWithFallback\ExecWithFallback; |
7 | |
8 | /** |
9 | * Locate path (or multiple paths) of a binary |
10 | * |
11 | * @package LocateBinaries |
12 | * @author Bjørn Rosell <it@rosell.dk> |
13 | */ |
14 | class LocateBinaries |
15 | { |
16 | |
17 | /** |
18 | * Locate binaries by looking in common system paths. |
19 | * |
20 | * We try a small set of common system paths, such as "/usr/bin". |
21 | * On Windows, we only try C:\Windows\System32 |
22 | * Note that you do not have to add ".exe" file extension on Windows, it is taken care of |
23 | * |
24 | * @param string $binary the binary to look for (ie "cwebp") |
25 | * |
26 | * @return array binaries found in common system locations |
27 | */ |
28 | public static function locateInCommonSystemPaths($binary) |
29 | { |
30 | $binaries = []; |
31 | |
32 | $commonSystemPaths = []; |
33 | |
34 | // TODO: Maybe check $PATH instead of using hardcoded paths? |
35 | |
36 | if (stripos(PHP_OS, 'WIN') === 0) { |
37 | $commonSystemPaths = [ |
38 | 'C:\Windows\System32', |
39 | ]; |
40 | $binary .= '.exe'; |
41 | } else { |
42 | $commonSystemPaths = [ |
43 | '/usr/bin', |
44 | '/usr/local/bin', |
45 | '/usr/gnu/bin', |
46 | '/usr/syno/bin', |
47 | '/bin', |
48 | ]; |
49 | } |
50 | |
51 | foreach ($commonSystemPaths as $dir) { |
52 | // PS: FileExists might throw if exec() or similar is unavailable. We let it. |
53 | // - this class assumes exec is available |
54 | if (FileExists::fileExistsTryHarder($dir . DIRECTORY_SEPARATOR . $binary)) { |
55 | $binaries[] = $dir . DIRECTORY_SEPARATOR . $binary; |
56 | } |
57 | } |
58 | return $binaries; |
59 | } |
60 | |
61 | /** |
62 | * Locate installed binaries using ie "whereis -b cwebp" (for Linux, Mac, etc) |
63 | * |
64 | * @return array Array of paths locateed (possibly empty) |
65 | */ |
66 | private static function locateBinariesUsingWhereIs($binary) |
67 | { |
68 | $isMac = (PHP_OS == 'Darwin'); |
69 | $command = 'whereis ' . ($isMac ? '' : '-b ') . $binary . ' 2>&1'; |
70 | |
71 | ExecWithFallback::exec($command, $output, $returnCode); |
72 | //echo 'command:' . $command; |
73 | //echo 'output:' . print_r($output, true); |
74 | |
75 | if (($returnCode == 0) && (isset($output[0]))) { |
76 | // On linux, result looks like this: |
77 | // "cwebp: /usr/bin/cwebp /usr/local/bin/cwebp" |
78 | // or, for empty: "cwebp:" |
79 | |
80 | if ($output[0] == ($binary . ':')) { |
81 | return []; |
82 | } |
83 | |
84 | // On mac, it is not prepended with name of binary. |
85 | // I don't know if mac returns one result per line or is space seperated |
86 | // As I don't know if some systems might return several lines, |
87 | // I assume that some do and convert to space-separation: |
88 | $result = implode(' ', $output); |
89 | |
90 | // Next, lets remove the prepended binary (if exists) |
91 | $result = preg_replace('#\b' . $binary . ':\s?#', '', $result); |
92 | |
93 | // And back to array |
94 | return explode(' ', $result); |
95 | } |
96 | return []; |
97 | } |
98 | |
99 | /** |
100 | * locate installed binaries using "which -a cwebp" |
101 | * |
102 | * @param string $binary the binary to look for (ie "cwebp") |
103 | * |
104 | * @return array Array of paths locateed (possibly empty) |
105 | */ |
106 | private static function locateBinariesUsingWhich($binary) |
107 | { |
108 | // As suggested by @cantoute here: |
109 | // https://wordpress.org/support/topic/sh-1-usr-local-bin-cwebp-not-found/ |
110 | ExecWithFallback::exec('which -a ' . $binary . ' 2>&1', $output, $returnCode); |
111 | if ($returnCode == 0) { |
112 | return $output; |
113 | } |
114 | return []; |
115 | } |
116 | |
117 | /** |
118 | * Locate binaries using where.exe (for Windows) |
119 | * |
120 | * @param string $binary the binary to look for (ie "cwebp") |
121 | * |
122 | * @return array binaries found |
123 | */ |
124 | private static function locateBinariesUsingWhere($binary) |
125 | { |
126 | ExecWithFallback::exec('where.exe ' . $binary . ' 2>&1', $output, $returnCode); |
127 | if ($returnCode == 0) { |
128 | return $output; |
129 | } |
130 | return []; |
131 | } |
132 | |
133 | /** |
134 | * Locate installed binaries |
135 | * |
136 | * For linuk, we use "which -a" or, if that fails "whereis -b" |
137 | * For Windows, we use "where.exe" |
138 | * These commands only searces within $PATH. So it only finds installed binaries (which is good, |
139 | * as it would be unsafe to deal with binaries found scattered around) |
140 | * |
141 | * @param string $binary the binary to look for (ie "cwebp") |
142 | * |
143 | * @return array binaries found |
144 | */ |
145 | public static function locateInstalledBinaries($binary) |
146 | { |
147 | if (stripos(PHP_OS, 'WIN') === 0) { |
148 | $paths = self::locateBinariesUsingWhere($binary); |
149 | if (count($paths) > 0) { |
150 | return $paths; |
151 | } |
152 | } else { |
153 | $paths = self::locateBinariesUsingWhich($binary); |
154 | if (count($paths) > 0) { |
155 | return $paths; |
156 | } |
157 | |
158 | $paths = self::locateBinariesUsingWhereIs($binary); |
159 | if (count($paths) > 0) { |
160 | return $paths; |
161 | } |
162 | } |
163 | return []; |
164 | } |
165 | } |