Passed
Push — release-11.0.x ( 910681...ed160c )
by Rafael
11:00
created

Process   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Test Coverage

Coverage 86.36%

Importance

Changes 10
Bugs 0 Features 0
Metric Value
eloc 55
c 10
b 0
f 0
dl 0
loc 207
ccs 57
cts 66
cp 0.8636
rs 10
wmc 22

12 Methods

Rating   Name   Duplication   Size   Complexity  
A setArguments() 0 3 1
A isRunning() 0 17 3
A getExecutable() 0 3 1
A getPid() 0 3 1
A __construct() 0 4 1
A stop() 0 12 2
A escapePsOutputCommand() 0 16 4
A start() 0 4 1
A setPid() 0 3 1
A runCommand() 0 12 2
A findPid() 0 20 4
A getArguments() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApacheSolrForTypo3\Tika;
6
7
/*
8
 * This file is part of the TYPO3 CMS project.
9
 *
10
 * It is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU General Public License, either version 2
12
 * of the License, or any later version.
13
 *
14
 * For the full copyright and license information, please read the
15
 * LICENSE.txt file that was distributed with this source code.
16
 *
17
 * The TYPO3 project - inspiring people to share!
18
 */
19
20
/**
21
 * Run, check, and stop external processes. Linux only.
22
 * @author Ingo Renner <[email protected]>
23
 */
24
class Process
25
{
26
27
    /**
28
     * Process ID
29
     *
30
     * @var int|null
31
     */
32
    protected ?int $pid = null;
33
34
    /**
35
     * Executable running the command
36
     *
37
     * @var string
38
     */
39
    protected string $executable;
40
41
    /**
42
     * Executable arguments
43
     *
44
     * @var string
45
     */
46
    protected string $arguments;
47
48
    /**
49
     * Constructor
50
     *
51
     * @param string $executable
52
     * @param string $arguments
53
     */
54 7
    public function __construct(string $executable, string $arguments = '')
55
    {
56 7
        $this->executable = $executable;
57 7
        $this->arguments = $arguments;
58 7
    }
59
60
    /**
61
     * Arguments getter
62
     *
63
     * @return string
64
     */
65 1
    public function getArguments(): string
66
    {
67 1
        return $this->arguments;
68
    }
69
70
    /**
71
     * Arguments setter
72
     *
73
     * @param string $arguments
74
     */
75
    public function setArguments(string $arguments): void
76
    {
77
        $this->arguments = $arguments;
78
    }
79
80
    /**
81
     * Gets the process executable
82
     *
83
     * @return string
84
     */
85 1
    public function getExecutable(): string
86
    {
87 1
        return $this->executable;
88
    }
89
90
    /**
91
     * Gets the process ID
92
     *
93
     * @return int|null process ID
94
     */
95
    public function getPid(): ?int
96
    {
97
        return $this->pid;
98
    }
99
100
    /**
101
     * Sets the process ID
102
     *
103
     * @param int $pid
104
     */
105 3
    public function setPid(int $pid): void
106
    {
107 3
        $this->pid = $pid;
108 3
    }
109
110
    /**
111
     * Tries to find the process' pid using ps
112
     *
113
     * @return int|null Null if the pid can't be found, otherwise the pid
114
     */
115 1
    public function findPid(): ?int
116
    {
117 1
        $processCommand = $this->executable;
118 1
        if (!empty($this->arguments)) {
119 1
            $processCommand .= ' ' . $this->arguments;
120
        }
121
122 1
        $ps = 'ps h --format pid,args -C ' . basename($this->executable);
123 1
        $output = [];
124 1
        exec($ps, $output);
125
126 1
        foreach ($output as $line) {
127 1
            [$pid, $command] = explode(' ', trim($line), 2);
128 1
            $command = $this->escapePsOutputCommand($command);
129 1
            if ($command == $processCommand) {
130
                return (int)$pid;
131
            }
132
        }
133
134 1
        return null;
135
    }
136
137
    /**
138
     * Escapes 'ps' command output to match what we expect to get as arguments
139
     * when executing a command.
140
     *
141
     * @param string $command
142
     * @return string
143
     */
144 1
    protected function escapePsOutputCommand(string $command): string
145
    {
146 1
        $command = explode(' ', $command);
147
148 1
        foreach ($command as $k => $v) {
149 1
            if ($k == 0) {
150
                // skip the executable
151 1
                continue;
152
            }
153
154
            if ($v[0] != '-') {
155
                $command[$k] = escapeshellarg($v);
156
            }
157
        }
158
159 1
        return implode(' ', $command);
160
    }
161
162
    /**
163
     * Starts the process.
164
     *
165
     * @return bool TRUE if the process could be started, FALSE otherwise
166
     */
167 1
    public function start(): bool
168
    {
169 1
        $this->runCommand();
170 1
        return $this->isRunning();
171
    }
172
173
    /**
174
     * Executes the command
175
     */
176 1
    protected function runCommand(): void
177
    {
178 1
        $command = 'nohup ' . $this->executable;
179 1
        if (!empty($this->arguments)) {
180 1
            $command .= ' ' . $this->arguments;
181
        }
182 1
        $command .= ' > /dev/null 2>&1 & echo $!';
183
184 1
        $output = [];
185 1
        exec($command, $output);
186
187 1
        $this->pid = (int)$output[0];
188 1
    }
189
190
    /**
191
     * Checks whether the process is running
192
     *
193
     * @return bool TRUE if the process is running, FALSE otherwise
194
     */
195 5
    public function isRunning(): bool
196
    {
197 5
        if (is_null($this->pid)) {
198 2
            return false;
199
        }
200
201 4
        $running = false;
202 4
        $output = [];
203
204 4
        $command = 'ps h -p ' . $this->pid;
205 4
        exec($command, $output);
206
207 4
        if (!empty($output)) {
208 4
            $running = true;
209
        }
210
211 4
        return $running;
212
    }
213
214
    /**
215
     * Stops the process
216
     *
217
     * @return bool
218
     */
219 1
    public function stop(): bool
220
    {
221 1
        $command = 'kill ' . $this->pid;
222 1
        exec($command);
223
224 1
        if ($this->isRunning() == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
225 1
            $stopped = true;
226
        } else {
227
            $stopped = false;
228
        }
229
230 1
        return $stopped;
231
    }
232
}
233