$page['contexte_implicite']), $lastinclude, $connect, cache_cool_get_global_context(), $_SERVER['REQUEST_TIME']); // mode de fonctionnement de cache_cool : QUEUE ou MEMORY if (!defined('_CACHE_COOL_MODE')) define('_CACHE_COOL_MODE','QUEUE'); if (_CACHE_COOL_MODE=="QUEUE"){ job_queue_add('public_produire_page',$c="Calcul du cache $fond [$where]",$args,"",TRUE); } else { if (!isset($GLOBALS['cache_cool_queue'])){ register_shutdown_function("cache_cool_process"); $GLOBALS['cache_cool_queue'] = array(); } $GLOBALS['cache_cool_queue'][] = $args; } spip_log("au frigo : $fond [$where]",'cachecool'._LOG_DEBUG); } gunzip_page($page); // decomprimer la page si besoin #spip_log($c,'cachedelai'); return $page; } // si c'est un cacul differe, verifier qu'on est dans le bon contexte if ($use_cache==2){ if ($cacher = charger_fonction('cacher','public', true)){ // le nom de chemin genere ici est ignore car faux // mais il faut que l'appel produise bien un chemin // sinon pb de contexte $chemin2 = $lastmodified = null; $cacher(is_null($contexte_cache)?array():$contexte_cache, $use_cache, $chemin2, $page, $lastmodified); } else $use_cache = -1; if (intval($use_cache)!==1 OR !$chemin2){ @define('_CACHE_COOL_ABORT_DELAI',600); if ( ($use_cache!=0) // le cache a deja ete mis a jour ! AND ($elapsed = time()-$init_time)<_CACHE_COOL_ABORT_DELAI // cette demande est moisie ){ // on n'est pas dans le bon contexte, il faut se reprogrammer ! $where = is_null($contexte_cache)?"principal":"inclure_page"; $args = func_get_args(); job_queue_add('public_produire_page',$c="[Re$elapsed] Calcul du cache $fond [$where]",$args,"",TRUE); #spip_log($c,'cachedelai'); } return; } if (!$processing) $processing = $background = true; } // positionner le contexte des globales si necessaire if (!is_null($global_context)) cache_cool_global_context($global_context); include_spip('public/assembler'); $page = public_produire_page_dist($fond, $contexte, $use_cache, $chemin_cache, $contexte_cache, $page, $lastinclude, $connect); if ($background){ if (function_exists($f='cache_cool_post_produire') OR function_exists($f=($f.'_dist'))){ $f($fond, $contexte, $use_cache, $chemin_cache, $contexte_cache, $page, $lastinclude, $connect); } } // restaurer le contexte des globales si necessaire if (!is_null($global_context)) cache_cool_global_context(false); if ($background) $processing = false; return $page; } function cache_cool_flush($content){ // on coupe la connection si il y a des caches a calculer // (mais dommage car on perd le benefice de KeepAlive=on) if (isset($GLOBALS['cache_cool_queue']) and is_array($GLOBALS['cache_cool_queue']) and $n=count($GLOBALS['cache_cool_queue'])) { $close = true; if (defined('_DIR_PLUGIN_MEMOIZATION')){ #spip_log('meta cache_cool_action_refresh : '.$GLOBALS['meta']['cache_cool_action_refresh']." (il y a ".($_SERVER['REQUEST_TIME']-$GLOBALS['meta']['cache_cool_action_refresh'])."s)",'cachecool'._LOG_DEBUG); if (!isset($GLOBALS['meta']['cache_cool_action_refresh']) OR $GLOBALS['meta']['cache_cool_action_refresh']<$_SERVER['REQUEST_TIME']-86400){ #spip_log('meta cache_cool_action_refresh_test : '.$GLOBALS['meta']['cache_cool_action_refresh_test']." (il y a ".($_SERVER['REQUEST_TIME']-$GLOBALS['meta']['cache_cool_action_refresh_test'])."s)",'cachecool'._LOG_DEBUG); if (!isset($GLOBALS['meta']['cache_cool_action_refresh_test']) OR $GLOBALS['meta']['cache_cool_action_refresh_test']<$_SERVER['REQUEST_TIME']-86400){ ecrire_meta('cache_cool_action_refresh_test',$_SERVER['REQUEST_TIME']); $url = generer_url_action('cache_cool_refresh','',true); if (strncmp($url,'http',4)!==0){ if (!function_exists('url_absolue')) include_spip('inc/filtres_mini'); $url = url_absolue($url); } cache_cool_async_curl($url); spip_log("Test mise a jour cache async $url",'cachecool'._LOG_DEBUG); } } else{ if (!function_exists('cache_set')) include_spip('inc/memoization'); $id = md5($GLOBALS['ip'].self().@getmypid().time().serialize($GLOBALS['visiteur_session'])); if (cache_set("cachecool-$id",$GLOBALS['cache_cool_queue'])){ $url = generer_url_action('cache_cool_refresh',"id=$id",true); if (strncmp($url,'http',4)!==0){ if (!function_exists('url_absolue')) include_spip('inc/filtres_mini'); $url = url_absolue($url); } if (cache_cool_async_curl($url)){ unset($GLOBALS['cache_cool_queue']); $close = false; spip_log("Mise a jour $n cache lancee en async sur $url",'cachecool'._LOG_DEBUG); } } else { spip_log("cache_set('cachecool-$id') return false",'cachecool'); } } } if ($close){ header("X-Cache-Cool: $n"); header("Content-Length: ".($l=ob_get_length())); header("Connection: close"); spip_log("Connection: close (length $l) ($n cache a calculer)",'cachecool'._LOG_DEBUG); } } return $content; } function cache_cool_process($force=false){ if (isset($GLOBALS['cache_cool_queue']) AND is_array($GLOBALS['cache_cool_queue'])){ // se remettre dans le bon dossier, car Apache le change parfois (toujours?) chdir(_ROOT_CWD); if (!$force){ $flush_level = ob_get_level(); // forcer le flush des tampons pas envoyes (declenche le content-length/conection:close envoye dans cache_cool_flush) while ($flush_level--) ob_end_flush(); flush(); if (function_exists('fastcgi_finish_request')) fastcgi_finish_request(); } while ( is_array($GLOBALS['cache_cool_queue']) AND $args = array_shift($GLOBALS['cache_cool_queue']) ) { spip_log( "calcul en fin de hit public_produire_page(" . (is_array($args[0]) ? 'Array' : (string) $args[0]) . ',' . (is_array($args[1]) ? 'Array' : (string) $args[1]) . ',' . (is_array($args[2]) ? 'Array' : (string) $args[2]) . ',' . (is_array($args[3]) ? 'Array' : (string) $args[3]) . ',' . (is_array($args[4]) ? 'Array' : (string) $args[4]) . ',' . (is_array($args[5]) ? 'Array' : (string) $args[5]) . ',' . (is_array($args[6]) ? 'Array' : (string) $args[6]) . ',' . (is_array($args[7]) ? 'Array' : (string) $args[7]) . ',' . (is_array($args[8]) ? 'Array' : (string) $args[8]) . ',' . (is_array($args[9]) ? 'Array' : (string) $args[9]) . ')', 'cachecool' . _LOG_DEBUG ); public_produire_page($args[0],$args[1],$args[2],$args[3],$args[4],$args[5],$args[6],$args[7],$args[8],$args[9]); } } } /** * Definir un nouveau contexte de globales (en sauvegardant l'ancien), * ou restaurer l'ancien contexte avec la valeur false * @staticvar array $pile * @param array/bool $push */ function cache_cool_global_context($push){ static $pile = array(); // restaurer le contexte if ($push===false AND count($pile)) { $pull = array_shift($pile); lang_select(); cache_cool_set_global_contexte($pull); } // definir un nouveau contexte else { // on empile le contexte actuel array_unshift($pile, cache_cool_get_global_context()); // et on le modifie en commencant par la langue courante lang_select($push['spip_lang']); cache_cool_set_global_contexte($push); } } /** * Lire les globales utilisees implicitement dans le calcul des * squelettes, et retourner un tableau les contenant * * @return array */ function cache_cool_get_global_context(){ $contexte = array(); $globals_to_save = array( 'spip_lang', 'visiteur_session', 'auteur_session', 'marqueur', 'marqueur_skel', 'dossier_squelettes', '_COOKIE', '_SERVER', '_GET', '_REQUEST', 'profondeur_url', 'REQUEST_URI', 'REQUEST_METHOD', ); if (defined('_CACHE_COOL_GLOBALS_TO_SAVE')) { $globals_to_save = array_merge($globals_to_save, explode(',', _CACHE_COOL_GLOBALS_TO_SAVE)); $globals_to_save = array_filter($globals_to_save); } foreach($globals_to_save as $v) { $contexte[$v] = (isset($GLOBALS[$v])?$GLOBALS[$v]:null); } $contexte['url_de_base'] = url_de_base(false); $contexte['nettoyer_uri'] = nettoyer_uri(); return $contexte; } /** * Assigner les globales fournies par $c * @param array $c * @return void */ function cache_cool_set_global_contexte($c){ if (!is_array($c)) return; // ne rien faire // precaution : spip_lang ne peut etre affecte brutalement // il faut passer par lang_select() unset($c['spip_lang']); url_de_base($c['url_de_base']); unset($c['url_de_base']); nettoyer_uri($c['nettoyer_uri']); unset($c['nettoyer_uri']); foreach($c as $k=>$v){ $GLOBALS[$k] = $v; } foreach(array( 'HTTP_SERVER_VARS'=>'_SERVER', 'HTTP_GET_VARS'=>'_GET', 'HTTP_COOKIE_VARS'=>'_COOKIE', ) as $k1=>$k2){ $GLOBALS[$k1] = $GLOBALS[$k2]; } } /** * Un curl async * @param $url * @return bool */ function cache_cool_async_curl($url){ #spip_log("cache_cool_async_curl $url","cachecool" . _LOG_DEBUG); // methode la plus rapide : // Si fsockopen est possible, on lance le cron via un socket en asynchrone // si fsockopen echoue (disponibilite serveur, firewall) on essaye pas cURL // car on a toutes les chances d'echouer pareil mais sans moyen de le savoir // on passe direct a la methode background-image if(function_exists('fsockopen')){ $parts=parse_url($url); spip_log("cache_cool_async_curl avec fsockopen ".json_encode($parts),"cachecool" . _LOG_DEBUG); switch ($parts['scheme']) { case 'https': $scheme = 'ssl://'; $port = 443; break; case 'http': default: $scheme = ''; $port = 80; } $fp = @fsockopen($scheme . $parts['host'], isset($parts['port']) ? $parts['port'] : $port, $errno, $errstr, 1); if ($fp) { $host_sent = $parts['host']; if (isset($parts['port']) and $parts['port'] !== $port) { $host_sent .= ':' . $parts['port']; } $timeout = 200; // ms stream_set_timeout($fp, 0, $timeout * 1000); $query = $parts['path'].($parts['query']?"?".$parts['query']:""); $out = "GET ".$query." HTTP/1.1\r\n"; $out.= "Host: ".$host_sent."\r\n"; $out.= "Connection: Close\r\n\r\n"; fwrite($fp, $out); spip_timer('cache_cool_async_curl'); $t = 0; // on lit la reponse si possible pour fermer proprement la connexion // avec un timeout total de 200ms pour ne pas se bloquer while (!feof($fp) and $t < $timeout) { @fgets($fp, 1024); $t += spip_timer('cache_cool_async_curl', true); spip_timer('cache_cool_async_curl'); } fclose($fp); return true; } } // ici lancer le cron par un CURL asynchrone si CURL est present elseif (function_exists("curl_init")){ spip_log("cache_cool_async_curl avec curl $url","cachecool" . _LOG_DEBUG); //setting the curl parameters. $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // cf bug : http://www.php.net/manual/en/function.curl-setopt.php#104597 curl_setopt($ch, CURLOPT_NOSIGNAL, 1); // valeur mini pour que la requete soit lancee curl_setopt($ch, CURLOPT_TIMEOUT_MS, 100); curl_exec($ch); curl_close($ch); return true; } return false; }