Process::setArguments()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
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
     * Process ID
28
     *
29
     * @var int|null
30
     */
31
    protected ?int $pid = null;
32
33
    /**
34
     * Executable running the command
35
     *
36
     * @var string
37
     */
38
    protected string $executable;
39
40
    /**
41
     * Executable arguments
42
     *
43
     * @var string
44
     */
45
    protected string $arguments;
46
47
    /**
48
     * Constructor
49
     *
50
     * @param string $executable
51
     * @param string $arguments
52
     */
53 7
    public function __construct(string $executable, string $arguments = '')
54
    {
55 7
        $this->executable = $executable;
56 7
        $this->arguments = $arguments;
57
    }
58
59
    /**
60
     * Arguments getter
61
     *
62
     * @return string
63
     */
64 1
    public function getArguments(): string
65
    {
66 1
        return $this->arguments;
67
    }
68
69
    /**
70
     * Arguments setter
71
     *
72
     * @param string $arguments
73
     */
74
    public function setArguments(string $arguments): void
75
    {
76
        $this->arguments = $arguments;
77
    }
78
79
    /**
80
     * Gets the process executable
81
     *
82
     * @return string
83
     */
84 1
    public function getExecutable(): string
85
    {
86 1
        return $this->executable;
87
    }
88
89
    /**
90
     * Gets the process ID
91
     *
92
     * @return int|null process ID
93
     */
94
    public function getPid(): ?int
95
    {
96
        return $this->pid;
97
    }
98
99
    /**
100
     * Sets the process ID
101
     *
102
     * @param int $pid
103
     */
104 3
    public function setPid(int $pid): void
105
    {
106 3
        $this->pid = $pid;
107
    }
108
109
    /**
110
     * Tries to find the process' pid using ps
111
     *
112
     * @return int|null Null if the pid can't be found, otherwise the pid
113
     */
114 1
    public function findPid(): ?int
115
    {
116 1
        $processCommand = $this->executable;
117 1
        if (!empty($this->arguments)) {
118 1
            $processCommand .= ' ' . $this->arguments;
119
        }
120
121 1
        $ps = 'ps h --format pid,args -C ' . basename($this->executable);
122 1
        $output = [];
123 1
        exec($ps, $output);
124
125 1
        foreach ($output as $line) {
126 1
            [$pid, $command] = explode(' ', trim($line ?? ''), 2);
127 1
            $command = $this->escapePsOutputCommand($command);
128 1
            if ($command == $processCommand) {
129
                return (int)$pid;
130
            }
131
        }
132
133 1
        return null;
134
    }
135
136
    /**
137
     * Escapes 'ps' command output to match what we expect to get as arguments
138
     * when executing a command.
139
     *
140
     * @param string $command
141
     * @return string
142
     */
143 1
    protected function escapePsOutputCommand(string $command): string
144
    {
145 1
        $command = explode(' ', $command);
146
147 1
        foreach ($command as $k => $v) {
148 1
            if ($k == 0) {
149
                // skip the executable
150 1
                continue;
151
            }
152
153
            if ($v[0] != '-') {
154
                $command[$k] = escapeshellarg($v);
155
            }
156
        }
157
158 1
        return implode(' ', $command);
159
    }
160
161
    /**
162
     * Starts the process.
163
     *
164
     * @return bool TRUE if the process could be started, FALSE otherwise
165
     */
166 1
    public function start(): bool
167
    {
168 1
        $this->runCommand();
169 1
        return $this->isRunning();
170
    }
171
172
    /**
173
     * Executes the command
174
     */
175 1
    protected function runCommand(): void
176
    {
177 1
        $command = 'nohup ' . $this->executable;
178 1
        if (!empty($this->arguments)) {
179 1
            $command .= ' ' . $this->arguments;
180
        }
181 1
        $command .= ' > /dev/null 2>&1 & echo $!';
182
183 1
        $output = [];
184 1
        exec($command, $output);
185
186 1
        $this->pid = (int)$output[0];
187
    }
188
189
    /**
190
     * Checks whether the process is running
191
     *
192
     * @return bool TRUE if the process is running, FALSE otherwise
193
     */
194 5
    public function isRunning(): bool
195
    {
196 5
        if (is_null($this->pid)) {
197 2
            return false;
198
        }
199
200 4
        $running = false;
201 4
        $output = [];
202
203 4
        $command = 'ps h -p ' . $this->pid;
204 4
        exec($command, $output);
205
206 4
        if (!empty($output)) {
207 4
            $running = true;
208
        }
209
210 4
        return $running;
211
    }
212
213
    /**
214
     * Stops the process
215
     *
216
     * @return bool
217
     */
218 1
    public function stop(): bool
219
    {
220 1
        $command = 'kill ' . $this->pid;
221 1
        exec($command);
222
223 1
        return !$this->isRunning();
224
    }
225
}
226