Completed
Push — master ( c909c6...1c541d )
by cam
07:39 queued 16s
created
ecrire/inc/queue.php 1 patch
Indentation   +501 added lines, -501 removed lines patch added patch discarded remove patch
@@ -16,7 +16,7 @@  discard block
 block discarded – undo
16 16
  * @package SPIP\Core\Queue
17 17
  **/
18 18
 if (!defined("_ECRIRE_INC_VERSION")) {
19
-	return;
19
+    return;
20 20
 }
21 21
 
22 22
 define('_JQ_SCHEDULED', 1);
@@ -50,98 +50,98 @@  discard block
 block discarded – undo
50 50
  *  id of job
51 51
  */
52 52
 function queue_add_job(
53
-	$function,
54
-	$description,
55
-	$arguments = array(),
56
-	$file = '',
57
-	$no_duplicate = false,
58
-	$time = 0,
59
-	$priority = 0
53
+    $function,
54
+    $description,
55
+    $arguments = array(),
56
+    $file = '',
57
+    $no_duplicate = false,
58
+    $time = 0,
59
+    $priority = 0
60 60
 ) {
61
-	include_spip('base/abstract_sql');
62
-
63
-	// cas pourri de ecrire/action/editer_site avec l'option reload=oui
64
-	if (defined('_GENIE_SYNDIC_NOW')) {
65
-		$arguments['id_syndic'] = _GENIE_SYNDIC_NOW;
66
-	}
67
-
68
-	// serialiser les arguments
69
-	$arguments = serialize($arguments);
70
-	$md5args = md5($arguments);
71
-
72
-	// si pas de date programee, des que possible
73
-	$duplicate_where = 'status=' . intval(_JQ_SCHEDULED) . ' AND ';
74
-	if (!$time) {
75
-		$time = time();
76
-		$duplicate_where = ""; // ne pas dupliquer si deja le meme job en cours d'execution
77
-	}
78
-	$date = date('Y-m-d H:i:s', $time);
79
-
80
-	$set_job = array(
81
-		'fonction' => $function,
82
-		'descriptif' => $description,
83
-		'args' => $arguments,
84
-		'md5args' => $md5args,
85
-		'inclure' => $file,
86
-		'priorite' => max(-10, min(10, intval($priority))),
87
-		'date' => $date,
88
-		'status' => _JQ_SCHEDULED,
89
-	);
90
-	// si option ne pas dupliquer, regarder si la fonction existe deja
91
-	// avec les memes args et file
92
-	if (
93
-		$no_duplicate
94
-		and
95
-		$id_job = sql_getfetsel('id_job', 'spip_jobs',
96
-			$duplicate_where =
97
-				$duplicate_where . 'fonction=' . sql_quote($function)
98
-				. (($no_duplicate === 'function_only') ? '' :
99
-					' AND md5args=' . sql_quote($md5args) . ' AND inclure=' . sql_quote($file)))
100
-	) {
101
-		return $id_job;
102
-	}
103
-
104
-	$id_job = sql_insertq('spip_jobs', $set_job);
105
-	// en cas de concurrence, deux process peuvent arriver jusqu'ici en parallele
106
-	// avec le meme job unique a inserer. Dans ce cas, celui qui a eu l'id le plus grand
107
-	// doit s'effacer
108
-	if (
109
-		$no_duplicate
110
-		and
111
-		$id_prev = sql_getfetsel('id_job', 'spip_jobs', "id_job<" . intval($id_job) . " AND $duplicate_where")
112
-	) {
113
-		sql_delete('spip_jobs', 'id_job=' . intval($id_job));
114
-
115
-		return $id_prev;
116
-	}
117
-
118
-	// verifier la non duplication qui peut etre problematique en cas de concurence
119
-	// il faut dans ce cas que seul le dernier ajoute se supprime !
120
-
121
-	// une option de debug pour verifier que les arguments en base sont bons
122
-	// ie cas d'un char non acceptables sur certains type de champs
123
-	// qui coupe la valeur
124
-	if (defined('_JQ_INSERT_CHECK_ARGS') and $id_job) {
125
-		$args = sql_getfetsel('args', 'spip_jobs', 'id_job=' . intval($id_job));
126
-		if ($args !== $arguments) {
127
-			spip_log('arguments job errones / longueur ' . strlen($args) . " vs " . strlen($arguments) . ' / valeur : ' . var_export($arguments,
128
-					true), 'queue');
129
-		}
130
-	}
131
-
132
-	if ($id_job) {
133
-		queue_update_next_job_time($time);
134
-	}
135
-	// si la mise en file d'attente du job echoue,
136
-	// il ne faut pas perdre l'execution de la fonction
137
-	// on la lance immediatement, c'est un fallback
138
-	// sauf en cas d'upgrade necessaire (table spip_jobs inexistante)
139
-	elseif ($GLOBALS['meta']['version_installee'] == $GLOBALS['spip_version_base']) {
140
-		$set_job['id_job'] = 0;
141
-		queue_start_job($set_job);
142
-	}
143
-
144
-	return $id_job;
61
+    include_spip('base/abstract_sql');
62
+
63
+    // cas pourri de ecrire/action/editer_site avec l'option reload=oui
64
+    if (defined('_GENIE_SYNDIC_NOW')) {
65
+        $arguments['id_syndic'] = _GENIE_SYNDIC_NOW;
66
+    }
67
+
68
+    // serialiser les arguments
69
+    $arguments = serialize($arguments);
70
+    $md5args = md5($arguments);
71
+
72
+    // si pas de date programee, des que possible
73
+    $duplicate_where = 'status=' . intval(_JQ_SCHEDULED) . ' AND ';
74
+    if (!$time) {
75
+        $time = time();
76
+        $duplicate_where = ""; // ne pas dupliquer si deja le meme job en cours d'execution
77
+    }
78
+    $date = date('Y-m-d H:i:s', $time);
79
+
80
+    $set_job = array(
81
+        'fonction' => $function,
82
+        'descriptif' => $description,
83
+        'args' => $arguments,
84
+        'md5args' => $md5args,
85
+        'inclure' => $file,
86
+        'priorite' => max(-10, min(10, intval($priority))),
87
+        'date' => $date,
88
+        'status' => _JQ_SCHEDULED,
89
+    );
90
+    // si option ne pas dupliquer, regarder si la fonction existe deja
91
+    // avec les memes args et file
92
+    if (
93
+        $no_duplicate
94
+        and
95
+        $id_job = sql_getfetsel('id_job', 'spip_jobs',
96
+            $duplicate_where =
97
+                $duplicate_where . 'fonction=' . sql_quote($function)
98
+                . (($no_duplicate === 'function_only') ? '' :
99
+                    ' AND md5args=' . sql_quote($md5args) . ' AND inclure=' . sql_quote($file)))
100
+    ) {
101
+        return $id_job;
102
+    }
103
+
104
+    $id_job = sql_insertq('spip_jobs', $set_job);
105
+    // en cas de concurrence, deux process peuvent arriver jusqu'ici en parallele
106
+    // avec le meme job unique a inserer. Dans ce cas, celui qui a eu l'id le plus grand
107
+    // doit s'effacer
108
+    if (
109
+        $no_duplicate
110
+        and
111
+        $id_prev = sql_getfetsel('id_job', 'spip_jobs', "id_job<" . intval($id_job) . " AND $duplicate_where")
112
+    ) {
113
+        sql_delete('spip_jobs', 'id_job=' . intval($id_job));
114
+
115
+        return $id_prev;
116
+    }
117
+
118
+    // verifier la non duplication qui peut etre problematique en cas de concurence
119
+    // il faut dans ce cas que seul le dernier ajoute se supprime !
120
+
121
+    // une option de debug pour verifier que les arguments en base sont bons
122
+    // ie cas d'un char non acceptables sur certains type de champs
123
+    // qui coupe la valeur
124
+    if (defined('_JQ_INSERT_CHECK_ARGS') and $id_job) {
125
+        $args = sql_getfetsel('args', 'spip_jobs', 'id_job=' . intval($id_job));
126
+        if ($args !== $arguments) {
127
+            spip_log('arguments job errones / longueur ' . strlen($args) . " vs " . strlen($arguments) . ' / valeur : ' . var_export($arguments,
128
+                    true), 'queue');
129
+        }
130
+    }
131
+
132
+    if ($id_job) {
133
+        queue_update_next_job_time($time);
134
+    }
135
+    // si la mise en file d'attente du job echoue,
136
+    // il ne faut pas perdre l'execution de la fonction
137
+    // on la lance immediatement, c'est un fallback
138
+    // sauf en cas d'upgrade necessaire (table spip_jobs inexistante)
139
+    elseif ($GLOBALS['meta']['version_installee'] == $GLOBALS['spip_version_base']) {
140
+        $set_job['id_job'] = 0;
141
+        queue_start_job($set_job);
142
+    }
143
+
144
+    return $id_job;
145 145
 }
146 146
 
147 147
 /**
@@ -150,11 +150,11 @@  discard block
 block discarded – undo
150 150
  * @return void
151 151
  */
152 152
 function queue_purger() {
153
-	include_spip('base/abstract_sql');
154
-	sql_delete('spip_jobs');
155
-	sql_delete("spip_jobs_liens", "id_job NOT IN (" . sql_get_select("id_job", "spip_jobs") . ")");
156
-	include_spip('inc/genie');
157
-	genie_queue_watch_dist();
153
+    include_spip('base/abstract_sql');
154
+    sql_delete('spip_jobs');
155
+    sql_delete("spip_jobs_liens", "id_job NOT IN (" . sql_get_select("id_job", "spip_jobs") . ")");
156
+    include_spip('inc/genie');
157
+    genie_queue_watch_dist();
158 158
 }
159 159
 
160 160
 /**
@@ -165,23 +165,23 @@  discard block
 block discarded – undo
165 165
  * @return bool
166 166
  */
167 167
 function queue_remove_job($id_job) {
168
-	include_spip('base/abstract_sql');
169
-
170
-	if ($row = sql_fetsel('fonction,inclure,date', 'spip_jobs', 'id_job=' . intval($id_job))
171
-		and $res = sql_delete('spip_jobs', 'id_job=' . intval($id_job))
172
-	) {
173
-		queue_unlink_job($id_job);
174
-		// est-ce une tache cron qu'il faut relancer ?
175
-		if ($periode = queue_is_cron_job($row['fonction'], $row['inclure'])) {
176
-			// relancer avec les nouveaux arguments de temps
177
-			include_spip('inc/genie');
178
-			// relancer avec la periode prevue
179
-			queue_genie_replan_job($row['fonction'], $periode, strtotime($row['date']));
180
-		}
181
-		queue_update_next_job_time();
182
-	}
183
-
184
-	return $res;
168
+    include_spip('base/abstract_sql');
169
+
170
+    if ($row = sql_fetsel('fonction,inclure,date', 'spip_jobs', 'id_job=' . intval($id_job))
171
+        and $res = sql_delete('spip_jobs', 'id_job=' . intval($id_job))
172
+    ) {
173
+        queue_unlink_job($id_job);
174
+        // est-ce une tache cron qu'il faut relancer ?
175
+        if ($periode = queue_is_cron_job($row['fonction'], $row['inclure'])) {
176
+            // relancer avec les nouveaux arguments de temps
177
+            include_spip('inc/genie');
178
+            // relancer avec la periode prevue
179
+            queue_genie_replan_job($row['fonction'], $periode, strtotime($row['date']));
180
+        }
181
+        queue_update_next_job_time();
182
+    }
183
+
184
+    return $res;
185 185
 }
186 186
 
187 187
 /**
@@ -194,18 +194,18 @@  discard block
 block discarded – undo
194 194
  *  ou un tableau composé de tableaux simples pour lieur plusieurs objets en une fois
195 195
  */
196 196
 function queue_link_job($id_job, $objets) {
197
-	include_spip('base/abstract_sql');
198
-
199
-	if (is_array($objets) and count($objets)) {
200
-		if (is_array(reset($objets))) {
201
-			foreach ($objets as $k => $o) {
202
-				$objets[$k]['id_job'] = $id_job;
203
-			}
204
-			sql_insertq_multi('spip_jobs_liens', $objets);
205
-		} else {
206
-			sql_insertq('spip_jobs_liens', array_merge(array('id_job' => $id_job), $objets));
207
-		}
208
-	}
197
+    include_spip('base/abstract_sql');
198
+
199
+    if (is_array($objets) and count($objets)) {
200
+        if (is_array(reset($objets))) {
201
+            foreach ($objets as $k => $o) {
202
+                $objets[$k]['id_job'] = $id_job;
203
+            }
204
+            sql_insertq_multi('spip_jobs_liens', $objets);
205
+        } else {
206
+            sql_insertq('spip_jobs_liens', array_merge(array('id_job' => $id_job), $objets));
207
+        }
208
+    }
209 209
 }
210 210
 
211 211
 /**
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
  *  resultat du sql_delete
218 218
  */
219 219
 function queue_unlink_job($id_job) {
220
-	return sql_delete("spip_jobs_liens", "id_job=" . intval($id_job));
220
+    return sql_delete("spip_jobs_liens", "id_job=" . intval($id_job));
221 221
 }
222 222
 
223 223
 /**
@@ -230,74 +230,74 @@  discard block
 block discarded – undo
230 230
  */
231 231
 function queue_start_job($row) {
232 232
 
233
-	// deserialiser les arguments
234
-	$args = unserialize($row['args']);
235
-	if ($args === false) {
236
-		spip_log('arguments job errones ' . var_export($row, true), 'queue');
237
-		$args = array();
238
-	}
239
-
240
-	$fonction = $row['fonction'];
241
-	if (strlen($inclure = trim($row['inclure']))) {
242
-		if (substr($inclure, -1) == '/') { // c'est un chemin pour charger_fonction
243
-			$f = charger_fonction($fonction, rtrim($inclure, '/'), false);
244
-			if ($f) {
245
-				$fonction = $f;
246
-			}
247
-		} else {
248
-			include_spip($inclure);
249
-		}
250
-	}
251
-
252
-	if (!function_exists($fonction)) {
253
-		spip_log("fonction $fonction ($inclure) inexistante " . var_export($row, true), 'queue');
254
-
255
-		return false;
256
-	}
257
-
258
-	spip_log("queue [" . $row['id_job'] . "]: $fonction() start", 'queue');
259
-	switch (count($args)) {
260
-		case 0:
261
-			$res = $fonction();
262
-			break;
263
-		case 1:
264
-			$res = $fonction($args[0]);
265
-			break;
266
-		case 2:
267
-			$res = $fonction($args[0], $args[1]);
268
-			break;
269
-		case 3:
270
-			$res = $fonction($args[0], $args[1], $args[2]);
271
-			break;
272
-		case 4:
273
-			$res = $fonction($args[0], $args[1], $args[2], $args[3]);
274
-			break;
275
-		case 5:
276
-			$res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4]);
277
-			break;
278
-		case 6:
279
-			$res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);
280
-			break;
281
-		case 7:
282
-			$res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6]);
283
-			break;
284
-		case 8:
285
-			$res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7]);
286
-			break;
287
-		case 9:
288
-			$res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8]);
289
-			break;
290
-		case 10:
291
-			$res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8],
292
-				$args[9]);
293
-			break;
294
-		default:
295
-			# plus lent mais completement generique
296
-			$res = call_user_func_array($fonction, $args);
297
-	}
298
-	spip_log("queue [" . $row['id_job'] . "]: $fonction() end", 'queue');
299
-
300
-	return $res;
233
+    // deserialiser les arguments
234
+    $args = unserialize($row['args']);
235
+    if ($args === false) {
236
+        spip_log('arguments job errones ' . var_export($row, true), 'queue');
237
+        $args = array();
238
+    }
239
+
240
+    $fonction = $row['fonction'];
241
+    if (strlen($inclure = trim($row['inclure']))) {
242
+        if (substr($inclure, -1) == '/') { // c'est un chemin pour charger_fonction
243
+            $f = charger_fonction($fonction, rtrim($inclure, '/'), false);
244
+            if ($f) {
245
+                $fonction = $f;
246
+            }
247
+        } else {
248
+            include_spip($inclure);
249
+        }
250
+    }
251
+
252
+    if (!function_exists($fonction)) {
253
+        spip_log("fonction $fonction ($inclure) inexistante " . var_export($row, true), 'queue');
254
+
255
+        return false;
256
+    }
257
+
258
+    spip_log("queue [" . $row['id_job'] . "]: $fonction() start", 'queue');
259
+    switch (count($args)) {
260
+        case 0:
261
+            $res = $fonction();
262
+            break;
263
+        case 1:
264
+            $res = $fonction($args[0]);
265
+            break;
266
+        case 2:
267
+            $res = $fonction($args[0], $args[1]);
268
+            break;
269
+        case 3:
270
+            $res = $fonction($args[0], $args[1], $args[2]);
271
+            break;
272
+        case 4:
273
+            $res = $fonction($args[0], $args[1], $args[2], $args[3]);
274
+            break;
275
+        case 5:
276
+            $res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4]);
277
+            break;
278
+        case 6:
279
+            $res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);
280
+            break;
281
+        case 7:
282
+            $res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6]);
283
+            break;
284
+        case 8:
285
+            $res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7]);
286
+            break;
287
+        case 9:
288
+            $res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8]);
289
+            break;
290
+        case 10:
291
+            $res = $fonction($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8],
292
+                $args[9]);
293
+            break;
294
+        default:
295
+            # plus lent mais completement generique
296
+            $res = call_user_func_array($fonction, $args);
297
+    }
298
+    spip_log("queue [" . $row['id_job'] . "]: $fonction() end", 'queue');
299
+
300
+    return $res;
301 301
 
302 302
 }
303 303
 
@@ -325,89 +325,89 @@  discard block
 block discarded – undo
325 325
  *     - true : une planification a été faite.
326 326
  */
327 327
 function queue_schedule($force_jobs = null) {
328
-	$time = time();
329
-	if (defined('_DEBUG_BLOCK_QUEUE')) {
330
-		spip_log("_DEBUG_BLOCK_QUEUE : schedule stop", 'jq' . _LOG_DEBUG);
331
-
332
-		return;
333
-	}
334
-
335
-	// rien a faire si le prochain job est encore dans le futur
336
-	if (queue_sleep_time_to_next_job() > 0 and (!$force_jobs or !count($force_jobs))) {
337
-		spip_log("queue_sleep_time_to_next_job", 'jq' . _LOG_DEBUG);
338
-
339
-		return;
340
-	}
341
-
342
-	include_spip('base/abstract_sql');
343
-	// on ne peut rien faire si pas de connexion SQL
344
-	if (!spip_connect()) {
345
-		return false;
346
-	}
347
-
348
-	if (!defined('_JQ_MAX_JOBS_TIME_TO_EXECUTE')) {
349
-		$max_time = ini_get('max_execution_time') / 2;
350
-		// valeur conservatrice si on a pas reussi a lire le max_execution_time
351
-		if (!$max_time) {
352
-			$max_time = 5;
353
-		}
354
-		define('_JQ_MAX_JOBS_TIME_TO_EXECUTE', min($max_time, 15)); // une valeur maxi en temps.
355
-	}
356
-	$end_time = $time + _JQ_MAX_JOBS_TIME_TO_EXECUTE;
357
-
358
-	spip_log("JQ schedule $time / $end_time", 'jq' . _LOG_DEBUG);
359
-
360
-	if (!defined('_JQ_MAX_JOBS_EXECUTE')) {
361
-		define('_JQ_MAX_JOBS_EXECUTE', 200);
362
-	}
363
-	$nbj = 0;
364
-	// attraper les jobs
365
-	// dont la date est passee (echus en attente),
366
-	// par ordre :
367
-	//	- de priorite
368
-	//	- de date
369
-	// lorsqu'un job cron n'a pas fini, sa priorite est descendue
370
-	// pour qu'il ne bloque pas les autres jobs en attente
371
-	if (is_array($force_jobs) and count($force_jobs)) {
372
-		$cond = "status=" . intval(_JQ_SCHEDULED) . " AND " . sql_in("id_job", $force_jobs);
373
-	} else {
374
-		$now = date('Y-m-d H:i:s', $time);
375
-		$cond = "status=" . intval(_JQ_SCHEDULED) . " AND date<=" . sql_quote($now);
376
-	}
377
-
378
-	register_shutdown_function('queue_error_handler'); // recuperer les erreurs auant que possible
379
-	$res = sql_allfetsel('*', 'spip_jobs', $cond, '', 'priorite DESC,date', '0,' . (_JQ_MAX_JOBS_EXECUTE + 1));
380
-	do {
381
-		if ($row = array_shift($res)) {
382
-			$nbj++;
383
-			// il faut un verrou, a base de sql_delete
384
-			if (sql_delete('spip_jobs', "id_job=" . intval($row['id_job']) . " AND status=" . intval(_JQ_SCHEDULED))) {
385
-				#spip_log("JQ schedule job ".$nbj." OK",'jq');
386
-				// on reinsert dans la base aussitot avec un status=_JQ_PENDING
387
-				$row['status'] = _JQ_PENDING;
388
-				$row['date'] = date('Y-m-d H:i:s', $time);
389
-				sql_insertq('spip_jobs', $row);
390
-
391
-				// on a la main sur le job :
392
-				// l'executer
393
-				$result = queue_start_job($row);
394
-
395
-				$time = time();
396
-				queue_close_job($row, $time, $result);
397
-			}
398
-		}
399
-		spip_log("JQ schedule job end time " . $time, 'jq' . _LOG_DEBUG);
400
-	} while ($nbj < _JQ_MAX_JOBS_EXECUTE and $row and $time < $end_time);
401
-	spip_log("JQ schedule end time " . time(), 'jq' . _LOG_DEBUG);
402
-
403
-	if ($row = array_shift($res)) {
404
-		queue_update_next_job_time(0); // on sait qu'il y a encore des jobs a lancer ASAP
405
-		spip_log("JQ encore !", 'jq' . _LOG_DEBUG);
406
-	} else {
407
-		queue_update_next_job_time();
408
-	}
409
-
410
-	return true;
328
+    $time = time();
329
+    if (defined('_DEBUG_BLOCK_QUEUE')) {
330
+        spip_log("_DEBUG_BLOCK_QUEUE : schedule stop", 'jq' . _LOG_DEBUG);
331
+
332
+        return;
333
+    }
334
+
335
+    // rien a faire si le prochain job est encore dans le futur
336
+    if (queue_sleep_time_to_next_job() > 0 and (!$force_jobs or !count($force_jobs))) {
337
+        spip_log("queue_sleep_time_to_next_job", 'jq' . _LOG_DEBUG);
338
+
339
+        return;
340
+    }
341
+
342
+    include_spip('base/abstract_sql');
343
+    // on ne peut rien faire si pas de connexion SQL
344
+    if (!spip_connect()) {
345
+        return false;
346
+    }
347
+
348
+    if (!defined('_JQ_MAX_JOBS_TIME_TO_EXECUTE')) {
349
+        $max_time = ini_get('max_execution_time') / 2;
350
+        // valeur conservatrice si on a pas reussi a lire le max_execution_time
351
+        if (!$max_time) {
352
+            $max_time = 5;
353
+        }
354
+        define('_JQ_MAX_JOBS_TIME_TO_EXECUTE', min($max_time, 15)); // une valeur maxi en temps.
355
+    }
356
+    $end_time = $time + _JQ_MAX_JOBS_TIME_TO_EXECUTE;
357
+
358
+    spip_log("JQ schedule $time / $end_time", 'jq' . _LOG_DEBUG);
359
+
360
+    if (!defined('_JQ_MAX_JOBS_EXECUTE')) {
361
+        define('_JQ_MAX_JOBS_EXECUTE', 200);
362
+    }
363
+    $nbj = 0;
364
+    // attraper les jobs
365
+    // dont la date est passee (echus en attente),
366
+    // par ordre :
367
+    //	- de priorite
368
+    //	- de date
369
+    // lorsqu'un job cron n'a pas fini, sa priorite est descendue
370
+    // pour qu'il ne bloque pas les autres jobs en attente
371
+    if (is_array($force_jobs) and count($force_jobs)) {
372
+        $cond = "status=" . intval(_JQ_SCHEDULED) . " AND " . sql_in("id_job", $force_jobs);
373
+    } else {
374
+        $now = date('Y-m-d H:i:s', $time);
375
+        $cond = "status=" . intval(_JQ_SCHEDULED) . " AND date<=" . sql_quote($now);
376
+    }
377
+
378
+    register_shutdown_function('queue_error_handler'); // recuperer les erreurs auant que possible
379
+    $res = sql_allfetsel('*', 'spip_jobs', $cond, '', 'priorite DESC,date', '0,' . (_JQ_MAX_JOBS_EXECUTE + 1));
380
+    do {
381
+        if ($row = array_shift($res)) {
382
+            $nbj++;
383
+            // il faut un verrou, a base de sql_delete
384
+            if (sql_delete('spip_jobs', "id_job=" . intval($row['id_job']) . " AND status=" . intval(_JQ_SCHEDULED))) {
385
+                #spip_log("JQ schedule job ".$nbj." OK",'jq');
386
+                // on reinsert dans la base aussitot avec un status=_JQ_PENDING
387
+                $row['status'] = _JQ_PENDING;
388
+                $row['date'] = date('Y-m-d H:i:s', $time);
389
+                sql_insertq('spip_jobs', $row);
390
+
391
+                // on a la main sur le job :
392
+                // l'executer
393
+                $result = queue_start_job($row);
394
+
395
+                $time = time();
396
+                queue_close_job($row, $time, $result);
397
+            }
398
+        }
399
+        spip_log("JQ schedule job end time " . $time, 'jq' . _LOG_DEBUG);
400
+    } while ($nbj < _JQ_MAX_JOBS_EXECUTE and $row and $time < $end_time);
401
+    spip_log("JQ schedule end time " . time(), 'jq' . _LOG_DEBUG);
402
+
403
+    if ($row = array_shift($res)) {
404
+        queue_update_next_job_time(0); // on sait qu'il y a encore des jobs a lancer ASAP
405
+        spip_log("JQ encore !", 'jq' . _LOG_DEBUG);
406
+    } else {
407
+        queue_update_next_job_time();
408
+    }
409
+
410
+    return true;
411 411
 }
412 412
 
413 413
 /**
@@ -425,22 +425,22 @@  discard block
 block discarded – undo
425 425
  * @param int $result
426 426
  */
427 427
 function queue_close_job(&$row, $time, $result = 0) {
428
-	// est-ce une tache cron qu'il faut relancer ?
429
-	if ($periode = queue_is_cron_job($row['fonction'], $row['inclure'])) {
430
-		// relancer avec les nouveaux arguments de temps
431
-		include_spip('inc/genie');
432
-		if ($result < 0) // relancer tout de suite, mais en baissant la priorite
433
-		{
434
-			queue_genie_replan_job($row['fonction'], $periode, 0 - $result, null, $row['priorite'] - 1);
435
-		} else // relancer avec la periode prevue
436
-		{
437
-			queue_genie_replan_job($row['fonction'], $periode, $time);
438
-		}
439
-	}
440
-	// purger ses liens eventuels avec des objets
441
-	sql_delete("spip_jobs_liens", "id_job=" . intval($row['id_job']));
442
-	// supprimer le job fini
443
-	sql_delete('spip_jobs', 'id_job=' . intval($row['id_job']));
428
+    // est-ce une tache cron qu'il faut relancer ?
429
+    if ($periode = queue_is_cron_job($row['fonction'], $row['inclure'])) {
430
+        // relancer avec les nouveaux arguments de temps
431
+        include_spip('inc/genie');
432
+        if ($result < 0) // relancer tout de suite, mais en baissant la priorite
433
+        {
434
+            queue_genie_replan_job($row['fonction'], $periode, 0 - $result, null, $row['priorite'] - 1);
435
+        } else // relancer avec la periode prevue
436
+        {
437
+            queue_genie_replan_job($row['fonction'], $periode, $time);
438
+        }
439
+    }
440
+    // purger ses liens eventuels avec des objets
441
+    sql_delete("spip_jobs_liens", "id_job=" . intval($row['id_job']));
442
+    // supprimer le job fini
443
+    sql_delete('spip_jobs', 'id_job=' . intval($row['id_job']));
444 444
 }
445 445
 
446 446
 /**
@@ -450,10 +450,10 @@  discard block
 block discarded – undo
450 450
  * @uses queue_update_next_job_time()
451 451
  */
452 452
 function queue_error_handler() {
453
-	// se remettre dans le bon dossier, car Apache le change parfois (toujours?)
454
-	chdir(_ROOT_CWD);
453
+    // se remettre dans le bon dossier, car Apache le change parfois (toujours?)
454
+    chdir(_ROOT_CWD);
455 455
 
456
-	queue_update_next_job_time();
456
+    queue_update_next_job_time();
457 457
 }
458 458
 
459 459
 
@@ -470,18 +470,18 @@  discard block
 block discarded – undo
470 470
  *     Périodicité de la tâche en secondes, si tâche périodique, sinon false.
471 471
  */
472 472
 function queue_is_cron_job($function, $inclure) {
473
-	static $taches = null;
474
-	if (strncmp($inclure, 'genie/', 6) == 0) {
475
-		if (is_null($taches)) {
476
-			include_spip('inc/genie');
477
-			$taches = taches_generales();
478
-		}
479
-		if (isset($taches[$function])) {
480
-			return $taches[$function];
481
-		}
482
-	}
483
-
484
-	return false;
473
+    static $taches = null;
474
+    if (strncmp($inclure, 'genie/', 6) == 0) {
475
+        if (is_null($taches)) {
476
+            include_spip('inc/genie');
477
+            $taches = taches_generales();
478
+        }
479
+        if (isset($taches[$function])) {
480
+            return $taches[$function];
481
+        }
482
+    }
483
+
484
+    return false;
485 485
 }
486 486
 
487 487
 /**
@@ -495,57 +495,57 @@  discard block
 block discarded – undo
495 495
  *  temps de la tache ajoutee ou 0 pour ASAP
496 496
  */
497 497
 function queue_update_next_job_time($next_time = null) {
498
-	static $nb_jobs_scheduled = null;
499
-	static $deja_la = false;
500
-	// prendre le min des $next_time que l'on voit passer ici, en cas de reentrance
501
-	static $next = null;
502
-	// queue_close_job peut etre reentrant ici
503
-	if ($deja_la) {
504
-		return;
505
-	}
506
-	$deja_la = true;
507
-
508
-	include_spip('base/abstract_sql');
509
-	$time = time();
510
-
511
-	// traiter les jobs morts au combat (_JQ_PENDING depuis plus de 180s)
512
-	// pour cause de timeout ou autre erreur fatale
513
-	$res = sql_allfetsel("*", "spip_jobs",
514
-		"status=" . intval(_JQ_PENDING) . " AND date<" . sql_quote(date('Y-m-d H:i:s', $time - 180)));
515
-	if (is_array($res)) {
516
-		foreach ($res as $row) {
517
-			queue_close_job($row, $time);
518
-			spip_log ("queue_close_job car _JQ_PENDING depuis +180s : ".print_r($row,1), "job_mort"._LOG_ERREUR);
519
-		}
520
-	}
521
-
522
-	// chercher la date du prochain job si pas connu
523
-	if (is_null($next) or is_null(queue_sleep_time_to_next_job())) {
524
-		$date = sql_getfetsel('date', 'spip_jobs', "status=" . intval(_JQ_SCHEDULED), '', 'date', '0,1');
525
-		$next = strtotime($date);
526
-	}
527
-	if (!is_null($next_time)) {
528
-		if (is_null($next) or $next > $next_time) {
529
-			$next = $next_time;
530
-		}
531
-	}
532
-
533
-	if ($next) {
534
-		if (is_null($nb_jobs_scheduled)) {
535
-			$nb_jobs_scheduled = sql_countsel('spip_jobs',
536
-				"status=" . intval(_JQ_SCHEDULED) . " AND date<" . sql_quote(date('Y-m-d H:i:s', $time)));
537
-		} elseif ($next <= $time) {
538
-			$nb_jobs_scheduled++;
539
-		}
540
-		// si trop de jobs en attente, on force la purge en fin de hit
541
-		// pour assurer le coup
542
-		if ($nb_jobs_scheduled > (defined('_JQ_NB_JOBS_OVERFLOW') ? _JQ_NB_JOBS_OVERFLOW : 10000)) {
543
-			define('_DIRECT_CRON_FORCE', true);
544
-		}
545
-	}
546
-
547
-	queue_set_next_job_time($next);
548
-	$deja_la = false;
498
+    static $nb_jobs_scheduled = null;
499
+    static $deja_la = false;
500
+    // prendre le min des $next_time que l'on voit passer ici, en cas de reentrance
501
+    static $next = null;
502
+    // queue_close_job peut etre reentrant ici
503
+    if ($deja_la) {
504
+        return;
505
+    }
506
+    $deja_la = true;
507
+
508
+    include_spip('base/abstract_sql');
509
+    $time = time();
510
+
511
+    // traiter les jobs morts au combat (_JQ_PENDING depuis plus de 180s)
512
+    // pour cause de timeout ou autre erreur fatale
513
+    $res = sql_allfetsel("*", "spip_jobs",
514
+        "status=" . intval(_JQ_PENDING) . " AND date<" . sql_quote(date('Y-m-d H:i:s', $time - 180)));
515
+    if (is_array($res)) {
516
+        foreach ($res as $row) {
517
+            queue_close_job($row, $time);
518
+            spip_log ("queue_close_job car _JQ_PENDING depuis +180s : ".print_r($row,1), "job_mort"._LOG_ERREUR);
519
+        }
520
+    }
521
+
522
+    // chercher la date du prochain job si pas connu
523
+    if (is_null($next) or is_null(queue_sleep_time_to_next_job())) {
524
+        $date = sql_getfetsel('date', 'spip_jobs', "status=" . intval(_JQ_SCHEDULED), '', 'date', '0,1');
525
+        $next = strtotime($date);
526
+    }
527
+    if (!is_null($next_time)) {
528
+        if (is_null($next) or $next > $next_time) {
529
+            $next = $next_time;
530
+        }
531
+    }
532
+
533
+    if ($next) {
534
+        if (is_null($nb_jobs_scheduled)) {
535
+            $nb_jobs_scheduled = sql_countsel('spip_jobs',
536
+                "status=" . intval(_JQ_SCHEDULED) . " AND date<" . sql_quote(date('Y-m-d H:i:s', $time)));
537
+        } elseif ($next <= $time) {
538
+            $nb_jobs_scheduled++;
539
+        }
540
+        // si trop de jobs en attente, on force la purge en fin de hit
541
+        // pour assurer le coup
542
+        if ($nb_jobs_scheduled > (defined('_JQ_NB_JOBS_OVERFLOW') ? _JQ_NB_JOBS_OVERFLOW : 10000)) {
543
+            define('_DIRECT_CRON_FORCE', true);
544
+        }
545
+    }
546
+
547
+    queue_set_next_job_time($next);
548
+    $deja_la = false;
549 549
 }
550 550
 
551 551
 
@@ -556,26 +556,26 @@  discard block
 block discarded – undo
556 556
  */
557 557
 function queue_set_next_job_time($next) {
558 558
 
559
-	// utiliser le temps courant reel plutot que temps de la requete ici
560
-	$time = time();
561
-
562
-	// toujours relire la valeur pour comparer, pour tenir compte des maj concourrantes
563
-	// et ne mettre a jour que si il y a un interet a le faire
564
-	// permet ausis d'initialiser le nom de fichier a coup sur
565
-	$curr_next = $_SERVER['REQUEST_TIME'] + max(0, queue_sleep_time_to_next_job(true));
566
-	if (
567
-		($curr_next <= $time and $next > $time) // le prochain job est dans le futur mais pas la date planifiee actuelle
568
-		or $curr_next > $next // le prochain job est plus tot que la date planifiee actuelle
569
-	) {
570
-		if (function_exists("cache_set") and defined('_MEMOIZE_MEMORY') and _MEMOIZE_MEMORY) {
571
-			cache_set(_JQ_NEXT_JOB_TIME_FILENAME, intval($next));
572
-		} else {
573
-			ecrire_fichier(_JQ_NEXT_JOB_TIME_FILENAME, intval($next));
574
-		}
575
-		queue_sleep_time_to_next_job($next);
576
-	}
577
-
578
-	return queue_sleep_time_to_next_job();
559
+    // utiliser le temps courant reel plutot que temps de la requete ici
560
+    $time = time();
561
+
562
+    // toujours relire la valeur pour comparer, pour tenir compte des maj concourrantes
563
+    // et ne mettre a jour que si il y a un interet a le faire
564
+    // permet ausis d'initialiser le nom de fichier a coup sur
565
+    $curr_next = $_SERVER['REQUEST_TIME'] + max(0, queue_sleep_time_to_next_job(true));
566
+    if (
567
+        ($curr_next <= $time and $next > $time) // le prochain job est dans le futur mais pas la date planifiee actuelle
568
+        or $curr_next > $next // le prochain job est plus tot que la date planifiee actuelle
569
+    ) {
570
+        if (function_exists("cache_set") and defined('_MEMOIZE_MEMORY') and _MEMOIZE_MEMORY) {
571
+            cache_set(_JQ_NEXT_JOB_TIME_FILENAME, intval($next));
572
+        } else {
573
+            ecrire_fichier(_JQ_NEXT_JOB_TIME_FILENAME, intval($next));
574
+        }
575
+        queue_sleep_time_to_next_job($next);
576
+    }
577
+
578
+    return queue_sleep_time_to_next_job();
579 579
 }
580 580
 
581 581
 /**
@@ -592,62 +592,62 @@  discard block
 block discarded – undo
592 592
  * @return string
593 593
  */
594 594
 function queue_affichage_cron() {
595
-	$texte = "";
596
-
597
-	$time_to_next = queue_sleep_time_to_next_job();
598
-	// rien a faire si le prochain job est encore dans le futur
599
-	if ($time_to_next > 0 or defined('_DEBUG_BLOCK_QUEUE')) {
600
-		return $texte;
601
-	}
602
-
603
-	// ne pas relancer si on vient de lancer dans la meme seconde par un hit concurent
604
-	if (file_exists($lock = _DIR_TMP . "cron.lock") and !(@filemtime($lock) < $_SERVER['REQUEST_TIME'])) {
605
-		return $texte;
606
-	}
607
-
608
-	@touch($lock);
609
-
610
-	// il y a des taches en attentes
611
-	// si depuis plus de 5min, on essaye de lancer le cron par tous les moyens pour rattraper le coup
612
-	// on est sans doute sur un site qui n'autorise pas http sortant ou avec peu de trafic
613
-	$urgent = false;
614
-	if ($time_to_next < -300) {
615
-		$urgent = true;
616
-	}
617
-
618
-	$url_cron = generer_url_action('cron', '', false, true);
619
-
620
-	if (!defined('_HTML_BG_CRON_FORCE') or !_HTML_BG_CRON_FORCE) {
621
-
622
-		if (queue_lancer_url_http_async($url_cron) and !$urgent) {
623
-			return $texte;
624
-		}
625
-
626
-	}
627
-
628
-	// si deja force, on retourne sans rien
629
-	if (defined('_DIRECT_CRON_FORCE')) {
630
-		return $texte;
631
-	}
632
-
633
-	// si c'est un bot
634
-	// inutile de faire un appel par image background,
635
-	// on force un appel direct en fin de hit
636
-	if ((defined('_IS_BOT') and _IS_BOT)) {
637
-		define('_DIRECT_CRON_FORCE', true);
638
-
639
-		return $texte;
640
-	}
641
-
642
-	if (!defined('_HTML_BG_CRON_INHIB') or !_HTML_BG_CRON_INHIB) {
643
-		// en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
644
-		$url_cron = generer_url_action('cron');
645
-		$texte = '<!-- SPIP-CRON -->'
646
-		  . "<script>setTimeout(function(){var xo = new XMLHttpRequest();xo.open('GET', '$url_cron', true);xo.send('');},100);</script>"
647
-		  . "<noscript><div style=\"background-image: url('$url_cron');\"></div></noscript>";
648
-	}
649
-
650
-	return $texte;
595
+    $texte = "";
596
+
597
+    $time_to_next = queue_sleep_time_to_next_job();
598
+    // rien a faire si le prochain job est encore dans le futur
599
+    if ($time_to_next > 0 or defined('_DEBUG_BLOCK_QUEUE')) {
600
+        return $texte;
601
+    }
602
+
603
+    // ne pas relancer si on vient de lancer dans la meme seconde par un hit concurent
604
+    if (file_exists($lock = _DIR_TMP . "cron.lock") and !(@filemtime($lock) < $_SERVER['REQUEST_TIME'])) {
605
+        return $texte;
606
+    }
607
+
608
+    @touch($lock);
609
+
610
+    // il y a des taches en attentes
611
+    // si depuis plus de 5min, on essaye de lancer le cron par tous les moyens pour rattraper le coup
612
+    // on est sans doute sur un site qui n'autorise pas http sortant ou avec peu de trafic
613
+    $urgent = false;
614
+    if ($time_to_next < -300) {
615
+        $urgent = true;
616
+    }
617
+
618
+    $url_cron = generer_url_action('cron', '', false, true);
619
+
620
+    if (!defined('_HTML_BG_CRON_FORCE') or !_HTML_BG_CRON_FORCE) {
621
+
622
+        if (queue_lancer_url_http_async($url_cron) and !$urgent) {
623
+            return $texte;
624
+        }
625
+
626
+    }
627
+
628
+    // si deja force, on retourne sans rien
629
+    if (defined('_DIRECT_CRON_FORCE')) {
630
+        return $texte;
631
+    }
632
+
633
+    // si c'est un bot
634
+    // inutile de faire un appel par image background,
635
+    // on force un appel direct en fin de hit
636
+    if ((defined('_IS_BOT') and _IS_BOT)) {
637
+        define('_DIRECT_CRON_FORCE', true);
638
+
639
+        return $texte;
640
+    }
641
+
642
+    if (!defined('_HTML_BG_CRON_INHIB') or !_HTML_BG_CRON_INHIB) {
643
+        // en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
644
+        $url_cron = generer_url_action('cron');
645
+        $texte = '<!-- SPIP-CRON -->'
646
+            . "<script>setTimeout(function(){var xo = new XMLHttpRequest();xo.open('GET', '$url_cron', true);xo.send('');},100);</script>"
647
+            . "<noscript><div style=\"background-image: url('$url_cron');\"></div></noscript>";
648
+    }
649
+
650
+    return $texte;
651 651
 }
652 652
 
653 653
 /**
@@ -656,69 +656,69 @@  discard block
 block discarded – undo
656 656
  * @return bool : true si l'url a pu être appelée en asynchrone, false sinon
657 657
  */
658 658
 function queue_lancer_url_http_async($url_cron) {
659
-	// methode la plus rapide :
660
-	// Si fsockopen est possible, on lance le cron via un socket en asynchrone
661
-	// si fsockopen echoue (disponibilite serveur, firewall) on essaye pas cURL
662
-	// car on a toutes les chances d'echouer pareil mais sans moyen de le savoir
663
-	// mais on renvoie false direct
664
-	if (function_exists('fsockopen')) {
665
-		$parts = parse_url($url_cron);
666
-
667
-		switch ($parts['scheme']) {
668
-			case 'https':
669
-				$scheme = 'ssl://';
670
-				$port = 443;
671
-				break;
672
-			case 'http':
673
-			default:
674
-				$scheme = '';
675
-				$port = 80;
676
-		}
677
-		$fp = @fsockopen($scheme . $parts['host'],
678
-			isset($parts['port']) ? $parts['port'] : $port,
679
-			$errno, $errstr, 1);
680
-
681
-		if ($fp) {
682
-			$host_sent = $parts['host'];
683
-			if (isset($parts['port']) and $parts['port'] !== $port) {
684
-				$host_sent .= ':' . $parts['port'];
685
-			}
686
-			$timeout = 200; // ms
687
-			stream_set_timeout($fp, 0, $timeout * 1000);
688
-			$query = $parts['path'] . ($parts['query'] ? "?" . $parts['query'] : "");
689
-			$out = "GET " . $query . " HTTP/1.1\r\n";
690
-			$out .= "Host: " . $host_sent . "\r\n";
691
-			$out .= "Connection: Close\r\n\r\n";
692
-			fwrite($fp, $out);
693
-			spip_timer('read');
694
-			$t = 0;
695
-			// on lit la reponse si possible pour fermer proprement la connexion
696
-			// avec un timeout total de 200ms pour ne pas se bloquer
697
-			while (!feof($fp) and $t < $timeout) {
698
-				@fgets($fp, 1024);
699
-				$t += spip_timer('read', true);
700
-				spip_timer('read');
701
-			}
702
-			fclose($fp);
703
-			return true;
704
-		}
705
-	}
706
-	// si fsockopen n'est pas dispo on essaye cURL :
707
-	// lancer le cron par un cURL asynchrone si cURL est present
708
-	elseif (function_exists("curl_init")) {
709
-		//setting the curl parameters.
710
-		$ch = curl_init($url_cron);
711
-		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
712
-		// cf bug : http://www.php.net/manual/en/function.curl-setopt.php#104597
713
-		curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
714
-		// valeur mini pour que la requete soit lancee
715
-		curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
716
-		// lancer
717
-		curl_exec($ch);
718
-		// fermer
719
-		curl_close($ch);
720
-		return true;
721
-	}
722
-
723
-	return false;
659
+    // methode la plus rapide :
660
+    // Si fsockopen est possible, on lance le cron via un socket en asynchrone
661
+    // si fsockopen echoue (disponibilite serveur, firewall) on essaye pas cURL
662
+    // car on a toutes les chances d'echouer pareil mais sans moyen de le savoir
663
+    // mais on renvoie false direct
664
+    if (function_exists('fsockopen')) {
665
+        $parts = parse_url($url_cron);
666
+
667
+        switch ($parts['scheme']) {
668
+            case 'https':
669
+                $scheme = 'ssl://';
670
+                $port = 443;
671
+                break;
672
+            case 'http':
673
+            default:
674
+                $scheme = '';
675
+                $port = 80;
676
+        }
677
+        $fp = @fsockopen($scheme . $parts['host'],
678
+            isset($parts['port']) ? $parts['port'] : $port,
679
+            $errno, $errstr, 1);
680
+
681
+        if ($fp) {
682
+            $host_sent = $parts['host'];
683
+            if (isset($parts['port']) and $parts['port'] !== $port) {
684
+                $host_sent .= ':' . $parts['port'];
685
+            }
686
+            $timeout = 200; // ms
687
+            stream_set_timeout($fp, 0, $timeout * 1000);
688
+            $query = $parts['path'] . ($parts['query'] ? "?" . $parts['query'] : "");
689
+            $out = "GET " . $query . " HTTP/1.1\r\n";
690
+            $out .= "Host: " . $host_sent . "\r\n";
691
+            $out .= "Connection: Close\r\n\r\n";
692
+            fwrite($fp, $out);
693
+            spip_timer('read');
694
+            $t = 0;
695
+            // on lit la reponse si possible pour fermer proprement la connexion
696
+            // avec un timeout total de 200ms pour ne pas se bloquer
697
+            while (!feof($fp) and $t < $timeout) {
698
+                @fgets($fp, 1024);
699
+                $t += spip_timer('read', true);
700
+                spip_timer('read');
701
+            }
702
+            fclose($fp);
703
+            return true;
704
+        }
705
+    }
706
+    // si fsockopen n'est pas dispo on essaye cURL :
707
+    // lancer le cron par un cURL asynchrone si cURL est present
708
+    elseif (function_exists("curl_init")) {
709
+        //setting the curl parameters.
710
+        $ch = curl_init($url_cron);
711
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
712
+        // cf bug : http://www.php.net/manual/en/function.curl-setopt.php#104597
713
+        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
714
+        // valeur mini pour que la requete soit lancee
715
+        curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
716
+        // lancer
717
+        curl_exec($ch);
718
+        // fermer
719
+        curl_close($ch);
720
+        return true;
721
+    }
722
+
723
+    return false;
724 724
 }
725 725
\ No newline at end of file
Please login to merge, or discard this patch.