This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace yiicod\cron\commands\traits; |
||
4 | |||
5 | use Exception; |
||
6 | use Yii; |
||
7 | use yiicod\cron\commands\exceptions\IsNotRunningException; |
||
8 | use yiicod\cron\commands\exceptions\IsRunningException; |
||
9 | use yiicod\cron\commands\FileOutput; |
||
10 | |||
11 | /** |
||
12 | * Trait DaemonTrait |
||
13 | * |
||
14 | * @package yiicod\cron\commands\traits |
||
15 | */ |
||
16 | trait DaemonTrait |
||
17 | { |
||
18 | /** |
||
19 | * @var int |
||
20 | */ |
||
21 | public $daemonDelay = 15; |
||
22 | |||
23 | /** |
||
24 | * @var FileOutput |
||
25 | */ |
||
26 | private $fileOutput; |
||
27 | |||
28 | /** |
||
29 | * Daemon name |
||
30 | * |
||
31 | * @return string |
||
32 | */ |
||
33 | abstract protected function daemonName(): string; |
||
34 | |||
35 | /** |
||
36 | * Reload daemon |
||
37 | * |
||
38 | * @param callable $worker |
||
39 | */ |
||
40 | protected function restartDaemon(callable $worker) |
||
41 | { |
||
42 | try { |
||
43 | $this->stopDaemon(); |
||
44 | } finally { |
||
45 | $this->startDaemon($worker); |
||
46 | } |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * Creates daemon. |
||
51 | * Check is daemon already run and if false then starts daemon and update lock file. |
||
52 | * |
||
53 | * @param callable $worker |
||
54 | * |
||
55 | * @throws Exception |
||
56 | */ |
||
57 | protected function startDaemon(callable $worker) |
||
58 | { |
||
59 | if (true === $this->isAlreadyRunning()) { |
||
60 | throw new IsRunningException(sprintf('[%s] is running already.', $this->daemonName())); |
||
61 | } else { |
||
62 | $pid = pcntl_fork(); |
||
63 | if ($pid == -1) { |
||
64 | exit('Error while forking process.'); |
||
65 | } elseif ($pid) { |
||
66 | exit(); |
||
67 | } else { |
||
68 | $pid = getmypid(); |
||
69 | $this->addPid($pid); |
||
70 | } |
||
71 | |||
72 | // Automatically send every new message to available log routes |
||
73 | Yii::getLogger()->flushInterval = 1; |
||
74 | while (true) { |
||
75 | // Start daemon method |
||
76 | call_user_func($worker); |
||
77 | sleep($this->daemonDelay); |
||
78 | } |
||
79 | } |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * Stop daemon |
||
84 | * |
||
85 | * @throws Exception |
||
86 | */ |
||
87 | protected function stopDaemon() |
||
88 | { |
||
89 | if (false === $this->isAlreadyRunning()) { |
||
90 | throw new IsNotRunningException(sprintf('[%s] is not running.', $this->daemonName())); |
||
91 | } |
||
92 | if (file_exists($this->getPidsFilePath())) { |
||
93 | $pids = $this->getPids(); |
||
94 | foreach ($pids as $pid) { |
||
95 | $this->removePid($pid); |
||
96 | } |
||
97 | } |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Checks if daemon already running. |
||
102 | * |
||
103 | * @return bool |
||
104 | */ |
||
105 | protected function isAlreadyRunning(): bool |
||
106 | { |
||
107 | $result = true; |
||
108 | $runningPids = $this->getPids(); |
||
109 | if (empty($runningPids)) { |
||
110 | $result = false; |
||
111 | } else { |
||
112 | $systemPids = explode("\n", trim(shell_exec("ps -e | awk '{print $1}'"))); |
||
113 | if (false === empty(array_diff($runningPids, $systemPids))) { |
||
114 | foreach ($runningPids as $pid) { |
||
115 | $this->removePid($pid); |
||
116 | } |
||
117 | $result = false; |
||
118 | } |
||
119 | } |
||
120 | |||
121 | return $result; |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Add pid |
||
126 | * |
||
127 | * @param $pid |
||
128 | */ |
||
129 | protected function addPid($pid) |
||
130 | { |
||
131 | $pids = $this->getPids(); |
||
132 | $pids[] = $pid; |
||
133 | $this->setPids($pids); |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * Add pid |
||
138 | * |
||
139 | * @param $pid |
||
140 | */ |
||
141 | protected function removePid($pid) |
||
142 | { |
||
143 | $pids = $this->getPids(); |
||
144 | |||
145 | // Remove all process |
||
146 | $children[] = $pid; |
||
0 ignored issues
–
show
|
|||
147 | while ($child = exec('pgrep -P ' . reset($children))) { |
||
148 | array_unshift($children, $child); |
||
149 | } |
||
150 | foreach ($children as $child) { |
||
151 | exec("kill $child 2> /dev/null"); |
||
152 | } |
||
153 | |||
154 | $pids = array_diff($pids, [$pid]); |
||
155 | $this->setPids($pids); |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Get pids |
||
160 | * |
||
161 | * @return array |
||
162 | */ |
||
163 | protected function getPids() |
||
164 | { |
||
165 | $pids = []; |
||
166 | if (file_exists($this->getPidsFilePath())) { |
||
167 | $pids = explode(',', trim(file_get_contents($this->getPidsFilePath()))); |
||
168 | } |
||
169 | |||
170 | return array_filter($pids); |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Set pids |
||
175 | * |
||
176 | * @return @void |
||
0 ignored issues
–
show
The doc-type
@void could not be parsed: Unknown type name "@void" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
177 | */ |
||
178 | protected function setPids(array $pids) |
||
179 | { |
||
180 | $pidsFile = $this->getPidsFilePath(); |
||
181 | file_put_contents($pidsFile, implode(',', $pids)); |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Pids file path |
||
186 | * |
||
187 | * @return string |
||
188 | */ |
||
189 | protected function getPidsFilePath() |
||
190 | { |
||
191 | return $this->getDaemonFilePath('pids.bin'); |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Gets path to daemon data. |
||
196 | * Lock file keeps pids of started daemons. |
||
197 | * |
||
198 | * @param string $file |
||
199 | * |
||
200 | * @return string |
||
201 | */ |
||
202 | protected function getDaemonFilePath($file): string |
||
203 | { |
||
204 | $path = $this->getDaemonDirPath(); |
||
205 | |||
206 | if (false === is_dir($path)) { |
||
207 | @mkdir($path, 0755, true); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
208 | } |
||
209 | |||
210 | return $path . '/' . $file; |
||
211 | } |
||
212 | |||
213 | protected function getDaemonDirPath(): string |
||
214 | { |
||
215 | return Yii::$app->basePath . '/runtime/daemons/' . strtolower($this->daemonName()); |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * @return FileOutput |
||
220 | */ |
||
221 | protected function output($text) |
||
222 | { |
||
223 | if (null === $this->fileOutput) { |
||
224 | $this->fileOutput = new FileOutput($this->getDaemonFilePath('output.log')); |
||
225 | } |
||
226 | |||
227 | $this->fileOutput->stdout(trim($text)); |
||
228 | } |
||
229 | } |
||
230 |
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.