This repository has been archived by the owner on Dec 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdaemon.php
234 lines (213 loc) · 6.72 KB
/
daemon.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<?php
/*
Author: Petr Bondarenko
E-mail: [email protected]
Date: 31 May 2012
License: BSD
Description: Class for create UNIX-daemon
*/
class DaemonException extends Exception {}
/**
* Класс для реализации UNIX-демонов
* @author Petr Bondarenko
* @copyright Petr Bondarenko 2012
* @version 1.0
* @abstract
*/
abstract class DaemonPHP {
protected $_baseDir;
protected $_chrootDir = null;
protected $_pid;
protected $_log;
protected $_err;
/**
* Конструктор класса. Принимает путь к pid-файлу
* @param string $path Абсолютный путь к PID-файлу
* @access public
*/
public function __construct($path=null) {
$this->_baseDir = dirname(__FILE__);
$this->_log = $this->_baseDir . '/daemon-php.log';
$this->_err = $this->_baseDir . '/daemon-php.err';
if ($path === null) {
$this->_pid = $this->_baseDir . '/daemon-php.pid';
} else {
$this->_pid = $path;
}
}
/**
* Метод устанавливает путь log-файла
* @param string $path Абсолютный путь к log-файлу
* @return DaemonPHP
* @access public
*/
final public function setLog($path) {
$this->_log = $path;
return $this;
}
/**
* Метод устанавливает путь err-файла
* @param string $path Абсолютный путь к err-файлу
* @return DaemonPHP
* @access public
*/
final public function setErr($path) {
$this->_err = $path;
return $this;
}
/**
* Метод позволяет установить директорию,
* в которую будет выполнен chroot после старта демона.
* Данный метод служит для решения проблем безопасности.
* @param string $path Абсолютный путь chroot-директории
* @throws DaemonException
* @access public
*/
final public function setChroot($path) {
if (!function_exists('chroot')) {
throw new DaemonException('Function chroot() has no. Please update you PHP version.');
}
$this->_chrootDir = $path;
return $this;
}
/**
* Метод выполняет демонизацию процесса, через double fork
* @throws DaemonException
* @access protected
*/
final protected function demonize() {
$pid = pcntl_fork();
if ($pid == -1) {
throw new DaemonException('Not fork process!');
} else if ($pid) {
exit(0);
}
posix_setsid();
chdir('/');
$pid = pcntl_fork();
if ($pid == -1) {
throw new DaemonException('Not double fork process!');
} else if ($pid) {
$fpid = fopen($this->_pid, 'wb');
fwrite($fpid, $pid);
fclose($fpid);
exit(0);
}
posix_setsid();
chdir('/');
ini_set('error_log', $this->_baseDir . '/php_error.log');
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$STDIN = fopen('/dev/null', 'r');
if ($this->_chrootDir !== null) {
chroot($this->_chrootDir);
}
$STDOUT = fopen($this->_log, 'ab');
if (!is_writable($this->_log))
throw new DaemonException('LOG-file is not writable!');
$STDERR = fopen($this->_err, 'ab');
if (!is_writable($this->_err))
throw new DaemonException('ERR-file is not writable!');
$this->run();
}
/**
* Метод возвращает PID процесса
* @return int PID процесса либо 0
* @access protected
*/
final protected function getPID() {
if (file_exists($this->_pid)) {
$pid = (int) file_get_contents($this->_pid);
if (posix_kill($pid, SIG_DFL)) {
return $pid;
} else {
//Если демон не откликается, а PID-файл существует
unlink($this->_pid);
return 0;
}
} else {
return 0;
}
}
/**
* Метод стартует работу и вызывает метод demonize()
* @access public
*/
final public function start() {
if (($pid = $this->getPID()) > 0) {
echo "Process is running on PID: " . $pid . PHP_EOL;
} else {
echo "Starting..." . PHP_EOL;
$this->demonize();
}
}
/**
* Метод останавливает демон
* @access public
*/
final public function stop() {
if (($pid = $this->getPID()) > 0) {
echo "Stopping ... ";
posix_kill($pid, SIGTERM);
unlink($this->_pid);
echo "OK" . PHP_EOL;
} else {
echo "Process not running!" . PHP_EOL;
}
}
/**
* Метод рестартует демон последовательно вызвав stop() и start()
* @see start()
* @see stop()
* @access public
*/
final public function restart() {
$this->stop();
$this->start();
}
/**
* Метод проверяет работу демона
* @access public
*/
final public function status() {
if (($pid = $this->getPID()) > 0) {
echo "Process is running on PID: " . $pid . PHP_EOL;
} else {
echo "Process not running!" . PHP_EOL;
}
}
/**
* Метод обрабатывает аргументы командной строки
* @param array $argv Массив с аргументами коммандной строки
* @access public
*/
final public function handle($argv) {
switch ($argv[1]) {
case 'start':
$this->start();
break;
case 'stop':
$this->stop();
break;
case 'restart':
$this->restart();
break;
case 'status':
$this->status();
break;
default:
echo "Unknown command!" . PHP_EOL .
"Use: " . $argv[0] . " start|stop|restart|status" . PHP_EOL;
break;
}
}
/**
* Основной класс демона, в котором выполняется работа.
* Его необходимо переопределить
* @access public
* @abstract
*/
abstract public function run();
}
?>