1 | <?php |
||||
2 | /* For license terms, see /license.txt */ |
||||
3 | exit; |
||||
4 | /** |
||||
5 | * This file is a cron microclock script. |
||||
6 | * It will be used as replacement of setting individual |
||||
7 | * cron lines for all virtual instances. |
||||
8 | * |
||||
9 | * Setup this vcron to run at the smallest period possible, as |
||||
10 | * it will schedule all availables vchamilos to be run as required. |
||||
11 | * Note that one activaton of this cron may not always run real crons |
||||
12 | * or may be run more than one cron. |
||||
13 | * |
||||
14 | * If used on a big system with clustering, ensure hostnames are adressed |
||||
15 | * at the load balancer entry and not on physical hosts |
||||
16 | * |
||||
17 | * @package plugin/vchamilo |
||||
18 | * @category plugins |
||||
19 | * |
||||
20 | * @author Valery fremaux ([email protected]) |
||||
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL |
||||
22 | */ |
||||
23 | define('CLI_SCRIPT', true); // for chamilo imported code |
||||
24 | require_once dirname(dirname(__DIR__)).'/main/inc/global.inc.php'; |
||||
25 | |||||
26 | global $DB; |
||||
27 | $DB = new DatabaseManager(); |
||||
28 | |||||
29 | define('ROUND_ROBIN', 0); |
||||
30 | define('LOWEST_POSSIBLE_GAP', 1); |
||||
31 | |||||
32 | global $VCRON; |
||||
33 | |||||
34 | $VCRON = new stdClass(); |
||||
35 | $VCRON->ACTIVATION = 'cli'; // choose how individual cron are launched, 'cli' or 'web' |
||||
36 | $VCRON->STRATEGY = ROUND_ROBIN; // choose vcron rotation mode |
||||
37 | $VCRON->PERIOD = 15 * MINSECS; // used if LOWEST_POSSIBLE_GAP to setup the max gap |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
38 | $VCRON->TIMEOUT = 300; // time out for CURL call to effective cron |
||||
39 | // $VCRON->TRACE = $_configuration['root_sys'].'plugin/vchamilo/log/vcrontrace.log'; // Trace file where to collect cron outputs |
||||
40 | $VCRON->TRACE = '/data/log/chamilo/vcrontrace.log'; // Trace file where to collect cron outputs |
||||
41 | $VCRON->TRACE_ENABLE = true; // enables tracing |
||||
42 | |||||
43 | if (!is_dir($_configuration['root_sys'].'plugin/vchamilo/log')) { |
||||
44 | $mode = api_get_permissions_for_new_directories(); |
||||
45 | mkdir($_configuration['root_sys'].'plugin/vchamilo/log', $mode, true); |
||||
46 | } |
||||
47 | |||||
48 | /** |
||||
49 | * fire a cron URL using CURL. |
||||
50 | */ |
||||
51 | function fire_vhost_cron($vhost) |
||||
52 | { |
||||
53 | global $VCRON; |
||||
54 | |||||
55 | if ($VCRON->TRACE_ENABLE) { |
||||
56 | $CRONTRACE = fopen($VCRON->TRACE, 'a'); |
||||
57 | } |
||||
58 | $ch = curl_init($vhost->root_web.'/main/cron/run.php'); |
||||
59 | |||||
60 | $http_proxy_host = api_get_setting('vchamilo_httpproxyhost', 'vchamilo'); |
||||
61 | $http_proxy_port = api_get_setting('vchamilo_httpproxyport', 'vchamilo'); |
||||
62 | $http_proxy_bypass = api_get_setting('vchamilo_httpproxybypass', 'vchamilo'); |
||||
63 | $http_proxy_user = api_get_setting('vchamilo_httpproxyuser', 'vchamilo'); |
||||
64 | $http_proxy_password = api_get_setting('vchamilo_httpproxypassword', 'vchamilo'); |
||||
65 | |||||
66 | curl_setopt($ch, CURLOPT_TIMEOUT, $VCRON->TIMEOUT); |
||||
67 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
||||
68 | curl_setopt($ch, CURLOPT_POST, true); |
||||
69 | curl_setopt($ch, CURLOPT_USERAGENT, 'Chamilo'); |
||||
70 | curl_setopt($ch, CURLOPT_POSTFIELDS, ''); |
||||
71 | curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: text/xml charset=UTF-8"]); |
||||
72 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
||||
73 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); |
||||
74 | |||||
75 | // Check for proxy. |
||||
76 | if (!empty($http_proxy_host) && !is_proxybypass($uri)) { |
||||
77 | curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false); |
||||
78 | |||||
79 | if (empty($http_proxy_port)) { |
||||
80 | echo "Using proxy $http_proxy_host\n"; |
||||
81 | curl_setopt($ch, CURLOPT_PROXY, $http_proxy_host); |
||||
82 | } else { |
||||
83 | echo "Using proxy $http_proxy_host:$http_proxy_port\n"; |
||||
84 | curl_setopt($ch, CURLOPT_PROXY, $http_proxy_host.':'.$http_proxy_port); |
||||
85 | } |
||||
86 | |||||
87 | if (!empty($http_proxy_user) and !empty($http_proxy_password)) { |
||||
88 | curl_setopt($ch, CURLOPT_PROXYUSERPWD, $http_proxy_user.':'.$http_proxy_password); |
||||
89 | if (defined('CURLOPT_PROXYAUTH')) { |
||||
90 | // any proxy authentication if PHP 5.1 |
||||
91 | curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM); |
||||
92 | } |
||||
93 | } |
||||
94 | } |
||||
95 | |||||
96 | $timestamp_send = time(); |
||||
97 | $rawresponse = curl_exec($ch); |
||||
98 | $timestamp_receive = time(); |
||||
99 | |||||
100 | if ($rawresponse === false) { |
||||
101 | $error = curl_errno($ch).':'.curl_error($ch); |
||||
102 | if ($VCRON->TRACE_ENABLE) { |
||||
103 | if ($CRONTRACE) { |
||||
104 | fputs($CRONTRACE, "VCron start on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n"); |
||||
105 | fputs($CRONTRACE, "VCron Error : $error \n"); |
||||
106 | fputs($CRONTRACE, "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n"); |
||||
107 | fclose($CRONTRACE); |
||||
108 | } |
||||
109 | } |
||||
110 | echo "VCron started on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n"; |
||||
111 | echo "VCron Error : $error \n"; |
||||
112 | echo "VCron stop on $vhost->root_web : ".api_time_to_hms($timestamp_receive)."\n#################\n\n"; |
||||
113 | |||||
114 | return false; |
||||
115 | } |
||||
116 | |||||
117 | if ($VCRON->TRACE_ENABLE) { |
||||
118 | if ($CRONTRACE) { |
||||
119 | fputs($CRONTRACE, "VCron start on $vhost->vhostname : ".api_time_to_hms($timestamp_send)."\n"); |
||||
120 | fputs($CRONTRACE, $rawresponse."\n"); |
||||
0 ignored issues
–
show
Are you sure
$rawresponse of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
121 | fputs($CRONTRACE, "VCron stop on $vhost->vhostname : ".api_time_to_hms($timestamp_receive)."\n#################\n\n"); |
||||
122 | fclose($CRONTRACE); |
||||
123 | } |
||||
124 | } |
||||
125 | echo "VCron start on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n"; |
||||
126 | echo $rawresponse."\n"; |
||||
127 | echo "VCron stop on $vhost->root_web : ".api_time_to_hms($timestamp_receive)."\n#################\n\n"; |
||||
128 | $vhost->lastcrongap = time() - $vhost->lastcron; |
||||
129 | $vhost->lastcron = $timestamp_send; |
||||
130 | $vhost->croncount++; |
||||
131 | |||||
132 | $vhostid = $vhost->id; |
||||
133 | unset($vhost->id); |
||||
134 | |||||
135 | Database::update('vchamilo', (array) $vhost, ['id = ?' => $vhostid]); |
||||
136 | } |
||||
137 | |||||
138 | /** |
||||
139 | * fire a cron URL using cli exec. |
||||
140 | */ |
||||
141 | function exec_vhost_cron($vhost) |
||||
142 | { |
||||
143 | global $VCRON, $DB, $_configuration; |
||||
144 | |||||
145 | if ($VCRON->TRACE_ENABLE) { |
||||
146 | $CRONTRACE = fopen($VCRON->TRACE, 'a'); |
||||
147 | } |
||||
148 | |||||
149 | $cmd = 'php "'.$_configuration['root_sys'].'/plugin/vchamilo/cli/cron.php" --host='.$vhost->root_web; |
||||
150 | |||||
151 | $timestamp_send = time(); |
||||
152 | exec($cmd, $rawresponse); |
||||
153 | $timestamp_receive = time(); |
||||
154 | |||||
155 | if ($VCRON->TRACE_ENABLE) { |
||||
156 | if ($CRONTRACE) { |
||||
157 | fputs($CRONTRACE, "VCron start on $vhost->root_web : $timestamp_send\n"); |
||||
158 | fputs($CRONTRACE, $rawresponse."\n"); |
||||
159 | fputs($CRONTRACE, "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n"); |
||||
160 | fclose($CRONTRACE); |
||||
161 | } |
||||
162 | } |
||||
163 | |||||
164 | echo "VCron start on $vhost->root_web : $timestamp_send\n"; |
||||
165 | echo implode("\n", $rawresponse)."\n"; |
||||
166 | echo "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n"; |
||||
167 | |||||
168 | $vhost->lastcrongap = time() - $vhost->lastcron; |
||||
169 | $vhost->lastcron = $timestamp_send; |
||||
170 | $vhost->croncount++; |
||||
171 | |||||
172 | $DB->update_record('vchamilo', $vhost, 'id'); |
||||
173 | } |
||||
174 | |||||
175 | /** |
||||
176 | * check if $url matches anything in proxybypass list. |
||||
177 | * |
||||
178 | * any errors just result in the proxy being used (least bad) |
||||
179 | * |
||||
180 | * @global object |
||||
181 | * |
||||
182 | * @param string $url url to check |
||||
183 | * |
||||
184 | * @return bool true if we should bypass the proxy |
||||
185 | */ |
||||
186 | function is_proxybypass($url) |
||||
187 | { |
||||
188 | $http_proxy_host = api_get_setting('vchamilo_httpproxyhost', 'vchamilo'); |
||||
189 | $http_proxy_port = api_get_setting('vchamilo_httpproxyport', 'vchamilo'); |
||||
190 | $http_proxy_bypass = api_get_setting('vchamilo_httpproxybypass', 'vchamilo'); |
||||
191 | |||||
192 | // sanity check |
||||
193 | if (empty($http_proxy_host) or empty($http_proxy_bypass)) { |
||||
194 | return false; |
||||
195 | } |
||||
196 | |||||
197 | // get the host part out of the url |
||||
198 | if (!$host = parse_url($url, PHP_URL_HOST)) { |
||||
199 | return false; |
||||
200 | } |
||||
201 | |||||
202 | // get the possible bypass hosts into an array |
||||
203 | $matches = explode(',', $http_proxy_bypass); |
||||
204 | |||||
205 | // check for a match |
||||
206 | // (IPs need to match the left hand side and hosts the right of the url, |
||||
207 | // but we can recklessly check both as there can't be a false +ve) |
||||
208 | $bypass = false; |
||||
209 | foreach ($matches as $match) { |
||||
210 | $match = trim($match); |
||||
211 | |||||
212 | // try for IP match (Left side) |
||||
213 | $lhs = substr($host, 0, strlen($match)); |
||||
214 | if (strcasecmp($match, $lhs) == 0) { |
||||
215 | return true; |
||||
216 | } |
||||
217 | |||||
218 | // try for host match (Right side) |
||||
219 | $rhs = substr($host, -strlen($match)); |
||||
220 | if (strcasecmp($match, $rhs) == 0) { |
||||
221 | return true; |
||||
222 | } |
||||
223 | } |
||||
224 | |||||
225 | // nothing matched. |
||||
226 | return false; |
||||
227 | } |
||||
228 | |||||
229 | // Main execution sequence |
||||
230 | |||||
231 | if (!$vchamilos = Database::select('*', 'vchamilo', [], 'all')) { |
||||
232 | exit("Nothing to do. No Vhosts"); |
||||
233 | } |
||||
234 | |||||
235 | $allvhosts = array_values($vchamilos); |
||||
236 | |||||
237 | echo "<pre>"; |
||||
238 | echo "Chamilo VCron... start\n"; |
||||
239 | echo "Last croned : ".api_get_setting('vchamilo_cron_lasthost', 'vchamilo')."\n"; |
||||
240 | |||||
241 | if ($VCRON->STRATEGY == ROUND_ROBIN) { |
||||
242 | $rr = 0; |
||||
243 | foreach ($allvhosts as $vhostassoc) { |
||||
244 | $vhost = (object) $vhostassoc; |
||||
245 | if ($rr == 1) { |
||||
246 | api_set_setting('vchamilo_cron_lasthost', $vhost->id); |
||||
247 | echo "Round Robin : ".$vhost->root_web."\n"; |
||||
248 | if ($VCRON->ACTIVATION == 'cli') { |
||||
249 | exec_vhost_cron($vhost); |
||||
250 | } else { |
||||
251 | fire_vhost_cron($vhost); |
||||
252 | } |
||||
253 | |||||
254 | exit('Done.'); |
||||
255 | } |
||||
256 | if ($vhost->id == api_get_setting('vchamilo_cron_lasthost', 'vchamilo')) { |
||||
257 | $rr = 1; // take next one |
||||
258 | } |
||||
259 | } |
||||
260 | |||||
261 | // We were at last. Loop back and take first. |
||||
262 | $firsthost = (object) $allvhosts[0]; |
||||
263 | api_set_setting('vchamilo_cron_lasthost', $firsthost->id, 'vchamilo'); |
||||
264 | echo "Round Robin : ".$firsthost->root_web."\n"; |
||||
265 | if ($VCRON->ACTIVATION == 'cli') { |
||||
266 | exec_vhost_cron($firsthost); |
||||
267 | } else { |
||||
268 | fire_vhost_cron($firsthost); |
||||
269 | } |
||||
270 | } elseif ($VCRON->STRATEGY == LOWEST_POSSIBLE_GAP) { |
||||
271 | // First make measurement of cron period. |
||||
272 | if (api_get_setting('vcrontickperiod', 'vchamilo')) { |
||||
273 | api_set_setting('vcrontime', time(), 'vchamilo'); |
||||
274 | |||||
275 | return; |
||||
276 | } |
||||
277 | api_set_setting('vcrontickperiod', time() - api_get_setting('vcrontime', 'vchamilo'), 'vchamilo'); |
||||
278 | $hostsperturn = max(1, $VCRON->PERIOD / api_get_setting('vcrontickperiod', 'vchamilo') * count($allvhosts)); |
||||
279 | $i = 0; |
||||
280 | foreach ($allvhosts as $vhostassoc) { |
||||
281 | $vhost = (object) $vhostassoc; |
||||
282 | if ((time() - $vhost->lastcron) > $VCRON->PERIOD) { |
||||
283 | if ($VCRON->ACTIVATION == 'cli') { |
||||
284 | exec_vhost_cron($vhost); |
||||
285 | } else { |
||||
286 | fire_vhost_cron($vhost); |
||||
287 | } |
||||
288 | $i++; |
||||
289 | if ($i >= $hostsperturn) { |
||||
290 | return; |
||||
291 | } |
||||
292 | } |
||||
293 | } |
||||
294 | } |
||||
295 |