/** * Met à jour les tables SQL paquets et plugins pour qui concerne * les paquets locaux (ceux présents sur le site). * * On ne met à jour que ce qui a changé, sauf si on force le recalcule * de toutes les informations locales avec var_mode=vider_paquets_locaux * dans l'URL ou en mettant le paramètre $force à true. * * @param bool $force * - false : n'actualise que les paquets modifiés * - true : efface et recrée la liste de tous les paquets locaux * @param array $erreurs_xml * Si des erreurs XML sont présentes, elles se retrouvent dans ce tableau * @return string * Temps d'exécution **/ function svp_actualiser_paquets_locaux($force = false, &$erreurs_xml = array()) { spip_timer('paquets_locaux'); $paquets = svp_descriptions_paquets_locaux($erreurs_xml); // un mode pour tout recalculer sans désinstaller le plugin... ! if ($force or _request('var_mode') == 'vider_paquets_locaux') { svp_base_supprimer_paquets_locaux(); svp_base_inserer_paquets_locaux($paquets); } else { svp_base_modifier_paquets_locaux($paquets); } svp_base_actualiser_paquets_actifs(); $temps = spip_timer('paquets_locaux'); #spip_log('svp_actualiser_paquets_locaux', 'SVP'); #spip_log($temps, 'SVP'); return "Éxécuté en : " . $temps; }
function charger_dtd($grammaire, $avail, $rotlvl) { static $dtd = array(); # cache bien utile pour le validateur en boucle if (isset($dtd[$grammaire])) return $dtd[$grammaire]; if ($avail == 'SYSTEM') { $grammaire = find_in_path($grammaire); } if (!$grammaire) return $dtd[''] = array(); $file = _DIR_CACHE_XML . preg_replace('/[^\w.]/','_', $rotlvl) . '.gz'; if (lire_fichier($file, $r)) { if (($avail == 'SYSTEM') AND filemtime($file) < filemtime($grammaire)) $r = false; } if ($r) { $dtc = unserialize($r); } else { spip_timer('dtd'); $dtc = new DTC; // L'analyseur retourne un booleen de reussite et modifie $dtc. // Retourner vide en cas d'echec if (!analyser_dtd($grammaire, $avail, $dtc)) $dtc = array(); else { // tri final pour presenter les suggestions de corrections foreach ($dtc->peres as $k => $v) { asort($v); $dtc->peres[$k] = $v; } spip_log("Analyser DTD $avail $grammaire (" . spip_timer('dtd') . ") " . count($dtc->macros) . ' macros, ' . count($dtc->elements) . ' elements, ' . count($dtc->attributs) . " listes d'attributs, " . count($dtc->entites) . " entites"); # $r = $dtc->regles; ksort($r);foreach($r as $l => $v) {$t=array_keys($dtc->attributs[$l]);echo "<b>$l</b> '$v' ", count($t), " attributs: ", join (', ',$t);$t=$dtc->peres[$l];echo "<br />",count($t), " peres: ", @join (', ',$t), "<br />\n";}exit; ecrire_fichier($file, serialize($dtc), true); } } $dtd[$grammaire] = $dtc; return $dtc; }
function typographie_en($letexte) { # version core if (!$GLOBALS['tw']) { return typographie_en_dist($letexte); } $debug = _request('var_debug_wheel'); static $trans; if (!isset($trans)) { $trans = array(" " => '~', "'" => '’'); switch ($GLOBALS['meta']['charset']) { case 'utf-8': $trans["Â "] = '~'; break; default: $trans[" "] = '~'; break; } } # cette chaine ne peut pas exister, # cf. TYPO_PROTECTEUR dans inc/texte $pro = "--"; if ($debug) { spip_timer('trans'); } $letexte = str_replace(array_keys($trans), array_values($trans), $letexte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['trans'] += spip_timer('trans', true); } if ($debug) { spip_timer('cherche1'); } /* 2 */ $letexte = preg_replace('/ --?,|(?: %)(?:\\W|$)/S', '~$0', $letexte); /* 4 */ $letexte = preg_replace('/Mr\\.? /S', '$0~', $letexte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['cherche1'] += spip_timer('cherche1', true); } if ($debug) { spip_timer('chercheespaces'); } if (strpos($letexte, '~') !== false) { $letexte = preg_replace("/ *~+ */S", "~", $letexte); } if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['chercheespaces'] += spip_timer('chercheespaces', true); } if ($debug) { spip_timer('cherche2'); } $letexte = preg_replace("/--([^-]|\$)/S", "{$pro}—\$1", $letexte, -1, $c); if ($c) { $letexte = preg_replace("/([-\n]){$pro}—/S", "\$1--", $letexte); $letexte = str_replace($pro, '', $letexte); } $letexte = str_replace('~', ' ', $letexte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['cherche2'] += spip_timer('cherche2', true); } return $letexte; }
function recherche_en_base($recherche = '', $tables = NULL, $options = array(), $serveur = '') { include_spip('base/abstract_sql'); if (!is_array($tables)) { $liste = liste_des_champs(); if (is_string($tables) and $tables != '') { $toutes = array(); foreach (explode(',', $tables) as $t) { if (isset($liste[$t])) { $toutes[$t] = $liste[$t]; } } $tables = $toutes; unset($toutes); } else { $tables = $liste; } } if (!strlen($recherche) or !count($tables)) { return array(); } include_spip('inc/autoriser'); // options par defaut $options = array_merge(array('preg_flags' => 'UimsS', 'toutvoir' => false, 'champs' => false, 'score' => false, 'matches' => false, 'jointures' => false, 'serveur' => $serveur), $options); $results = array(); // Utiliser l'iterateur (DATA:recherche) // pour recuperer les couples (id_objet, score) // Le resultat est au format { // id1 = { 'score' => x, attrs => { } }, // id2 = { 'score' => x, attrs => { } }, // } include_spip('inc/memoization'); foreach ($tables as $table => $champs) { # lock via memoization, si dispo if (function_exists('cache_lock')) { cache_lock($lock = 'recherche ' . $table . ' ' . $recherche); } spip_timer('rech'); // TODO: ici plutot charger un iterateur via l'API iterateurs include_spip('inc/recherche_to_array'); $to_array = charger_fonction('recherche_to_array', 'inc'); $results[$table] = $to_array($recherche, array_merge($options, array('table' => $table, 'champs' => $champs))); ##var_dump($results[$table]); spip_log("recherche {$table} ({$recherche}) : " . count($results[$table]) . " resultats " . spip_timer('rech'), 'recherche'); if (isset($lock)) { cache_unlock($lock); } } return $results; }
/** * Valide la conformité XML d'une liste de fichiers dans un répertoire * * @param array $files * Liste des fichiers * @param string $ext * Extension des fichiers * @param string $dir * Chemin du répertoire * @return array **/ function valider_dir($files, $ext, $dir) { $res = array(); $transformer_xml = charger_fonction('valider', 'xml'); $valideur = $ext == 'php' ? 'valider_script' : 'valider_skel'; foreach ($files as $f) { spip_timer($f); $val = $valideur($transformer_xml, $f, $dir, $ext); $n = spip_timer($f); $val[] = $n; spip_log("validation de {$f} en {$n} secondes"); $res[] = $val; } return $res; }
function expanser_liens_tw($texte, $connect = '') { $debug = _request('var_debug_wheel'); $texte = pipeline('pre_liens', $texte); if ($debug) { spip_timer('liensmatch'); } tw_expanser_un_lien($connect, 'init'); if (strpos($texte, '->') !== false) { $texte = preg_replace_callback(_RACCOURCI_LIEN_TW, 'tw_expanser_un_lien', $texte); } if ($debug) { $GLOBALS['totaux']['expanser_liens:']['liensmatch'] += spip_timer('liensmatch', true); } // on passe a traiter_modeles la liste des liens reperes pour lui permettre // de remettre le texte d'origine dans les parametres du modele if ($debug) { spip_timer('traiter_modeles'); } $texte = traiter_modeles($texte, false, false, $connect, tw_expanser_un_lien('', 'sources')); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['traiter_modeles'] += spip_timer('traiter_modeles', true); } if ($debug) { spip_timer('corriger_typo'); } $texte = corriger_typo($texte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo'] += spip_timer('corriger_typo', true); } if ($debug) { spip_timer('reinserts'); } $texte = tw_expanser_un_lien($texte, 'reinsert'); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['reinserts'] += spip_timer('reinserts', true); } return $texte; }
function public_parametrer_dist($fond, $contexte = '', $cache = '', $connect = '') { static $composer, $styliser, $notes = null; $page = tester_redirection($fond, $contexte, $connect); if ($page) { return $page; } if (isset($contexte['lang'])) { $lang = $contexte['lang']; } elseif (!isset($lang)) { $lang = $GLOBALS['meta']['langue_site']; } $select = ((!isset($GLOBALS['forcer_lang']) or !$GLOBALS['forcer_lang']) and $lang != $GLOBALS['spip_lang']); if ($select) { $select = lang_select($lang); } $debug = defined('_VAR_MODE') && _VAR_MODE == 'debug'; if (!$styliser) { $styliser = charger_fonction('styliser', 'public'); } list($skel, $mime_type, $gram, $sourcefile) = $styliser($fond, $contexte, $GLOBALS['spip_lang'], $connect); if ($skel) { // sauver le nom de l'eventuel squelette en cours d'execution // (recursion possible a cause des modeles) if ($debug) { $courant = @$GLOBALS['debug_objets']['courant']; $GLOBALS['debug_objets']['contexte'][$sourcefile] = $contexte; } // charger le squelette en specifiant les langages cibles et source // au cas il faudrait le compiler (source posterieure au resultat) if (!$composer) { $composer = charger_fonction('composer', 'public'); } $fonc = $composer($skel, $mime_type, $gram, $sourcefile, $connect); } else { $fonc = ''; } if (!$fonc) { // squelette inconnu (==='') ou faux (===false) $page = $fonc; } else { // Preparer l'appel de la fonction principale du squelette spip_timer($a = 'calcul page ' . rand(0, 1000)); // On cree un marqueur de notes unique lie a cette composition // et on enregistre l'etat courant des globales de notes... if (is_null($notes)) { $notes = charger_fonction('notes', 'inc', true); } if ($notes) { $notes('', 'empiler'); } // Rajouter d'office ces deux parametres // (mais vaudrait mieux que le compilateur sache le simuler // car ca interdit l'usage de criteres conditionnels dessus). if (!isset($contexte['date'])) { $contexte['date'] = date("Y-m-d H:i:s"); $contexte['date_default'] = true; } else { $contexte['date'] = normaliser_date($contexte['date'], true); } if (!isset($contexte['date_redac'])) { $contexte['date_redac'] = date("Y-m-d H:i:s"); $contexte['date_redac_default'] = true; } else { $contexte['date_redac'] = normaliser_date($contexte['date_redac'], true); } // Passer le nom du cache pour produire sa destruction automatique $page = $fonc(array('cache' => $cache), array($contexte)); // Restituer les globales de notes telles qu'elles etaient avant l'appel // Si l'inclus n'a pas affiche ses notes, tant pis (elles *doivent* // etre dans son resultat, autrement elles ne seraient pas prises en // compte a chaque calcul d'un texte contenant un modele, mais seulement // quand le modele serait calcule, et on aurait des resultats incoherents) if ($notes) { $notes('', 'depiler'); } // reinjecter en dynamique la pile des notes // si il y a des inclure dynamiques // si la pile n'est pas vide // la generalisation de cette injection permettrait de corriger le point juste au dessus // en faisant remonter les notes a l'incluant (A tester et valider avant application) if ($notes) { $page['notes'] = $notes('', 'sauver_etat'); } // spip_log: un joli contexte $infos = array(); foreach (array_filter($contexte) as $var => $val) { if (is_array($val)) { $val = serialize($val); } if (strlen("{$val}") > 30) { $val = substr("{$val}", 0, 27) . '..'; } if (strstr($val, ' ')) { $val = "'{$val}'"; } $infos[] = $var . '=' . $val; } $profile = spip_timer($a); spip_log("calcul ({$profile}) [{$skel}] " . join(', ', $infos) . ' (' . strlen($page['texte']) . ' octets)'); if (defined('_CALCUL_PROFILER') and intval($profile) > _CALCUL_PROFILER) { spip_log("calcul ({$profile}) [{$skel}] " . join(', ', $infos) . ' (' . strlen($page['texte']) . ' octets) | ' . $_SERVER['REQUEST_URI'], "profiler" . _LOG_AVERTISSEMENT); } if ($debug) { // si c'est ce que demande le debusqueur, lui passer la main $t = strlen($page['texte']) ? $page['texte'] : " "; $GLOBALS['debug_objets']['resultat'][$fonc . 'tout'] = $t; $GLOBALS['debug_objets']['courant'] = $courant; $GLOBALS['debug_objets']['profile'][$sourcefile] = $profile; if ($GLOBALS['debug_objets']['sourcefile'] and _request('var_mode_objet') == $fonc and _request('var_mode_affiche') == 'resultat') { erreur_squelette(); } } // Si #CACHE{} n'etait pas la, le mettre a $delais if (!isset($page['entetes']['X-Spip-Cache'])) { // Dans l'espace prive ou dans un modeles/ on pose un cache 0 par defaut // si aucun #CACHE{} spécifié // le contexte implicite qui conditionne le cache assure qu'on retombe pas sur le meme // entre public et prive if (test_espace_prive() or strncmp($fond, 'modeles/', 8) == 0) { $page['entetes']['X-Spip-Cache'] = 0; } else { $page['entetes']['X-Spip-Cache'] = isset($GLOBALS['delais']) ? $GLOBALS['delais'] : 36000; } } $page['contexte'] = $contexte; // faire remonter le fichier source static $js_inclus = false; if (defined('_VAR_INCLURE') and _VAR_INCLURE) { $page['sourcefile'] = $sourcefile; $page['texte'] = "<div class='inclure_blocs'><h6>" . $page['sourcefile'] . "</h6>" . $page['texte'] . "</div>" . ($js_inclus ? "" : "<script type='text/javascript'>jQuery(function(){jQuery('.inclure_blocs > h6:first-child').hover(function(){jQuery(this).parent().addClass('hover')},function(){jQuery(this).parent().removeClass('hover')})});</script>"); $js_inclus = true; } // Si un modele contenait #SESSION, on note l'info dans $page if (isset($GLOBALS['cache_utilise_session'])) { $page['invalideurs']['session'] = $GLOBALS['cache_utilise_session']; unset($GLOBALS['cache_utilise_session']); } } if ($select) { lang_select(); } return $page; }
function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect = '') { static $trouver_table; spip_timer('calcul_skel'); if (defined('_VAR_MODE') and _VAR_MODE == 'debug') { $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette']; $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile; if (!isset($GLOBALS['debug_objets']['principal'])) { $GLOBALS['debug_objets']['principal'] = $nom; } } foreach ($boucles as $id => $boucle) { $GLOBALS['debug_objets']['boucle'][$nom . $id] = $boucle; } $descr['documents'] = compile_inclure_doublons($squelette); // Demander la description des tables une fois pour toutes // et reperer si les doublons sont demandes // pour un inclure ou une boucle document // c'est utile a la fonction champs_traitements if (!$trouver_table) { $trouver_table = charger_fonction('trouver_table', 'base'); } foreach ($boucles as $id => $boucle) { if (!($type = $boucle->type_requete)) { continue; } if (!$descr['documents'] and ($type == 'documents' and $boucle->doublons or compile_inclure_doublons($boucle->avant) or compile_inclure_doublons($boucle->apres) or compile_inclure_doublons($boucle->milieu) or compile_inclure_doublons($boucle->altern))) { $descr['documents'] = true; } if ($type != TYPE_RECURSIF) { if (!$boucles[$id]->sql_serveur and $connect) { $boucles[$id]->sql_serveur = $connect; } // chercher dans les iterateurs du repertoire iterateur/ if ($g = charger_fonction(preg_replace('/\\W/', '_', $boucle->type_requete), 'iterateur', true)) { $boucles[$id] = $g($boucle); // sinon, en cas de requeteur d'un type predefini, // utiliser les informations donnees par le requeteur // cas "php:xx" et "data:xx". } else { if ($boucle->sql_serveur and $requeteur = charger_fonction($boucle->sql_serveur, 'requeteur', true)) { $requeteur($boucles, $boucle, $id); // utiliser la description des champs transmis } else { $show = $trouver_table($type, $boucles[$id]->sql_serveur); // si la table n'existe pas avec le connecteur par defaut, // c'est peut etre une table qui necessite son connecteur dedie fourni // permet une ecriture allegee (GEO) -> (geo:GEO) if (!$show and $show = $trouver_table($type, strtolower($type))) { $boucles[$id]->sql_serveur = strtolower($type); } if ($show) { $boucles[$id]->show = $show; // recopie les infos les plus importantes $boucles[$id]->primary = isset($show['key']["PRIMARY KEY"]) ? $show['key']["PRIMARY KEY"] : ''; $boucles[$id]->id_table = $x = preg_replace(",^spip_,", "", $show['id_table']); $boucles[$id]->from[$x] = $nom_table = $show['table']; $boucles[$id]->iterateur = 'SQL'; $boucles[$id]->descr =& $descr; if (!$boucles[$id]->jointures and is_array($show['tables_jointures']) and count($x = $show['tables_jointures'])) { $boucles[$id]->jointures = $x; } if ($boucles[$id]->jointures_explicites) { $jointures = preg_split("/\\s+/", $boucles[$id]->jointures_explicites); while ($j = array_pop($jointures)) { array_unshift($boucles[$id]->jointures, $j); } } } else { // Pas une erreur si la table est optionnelle if ($boucles[$id]->table_optionnelle) { $boucles[$id]->type_requete = ''; } else { $boucles[$id]->type_requete = false; $boucle = $boucles[$id]; $x = (!$boucle->sql_serveur ? '' : $boucle->sql_serveur . ":") . $type; $msg = array('zbug_table_inconnue', array('table' => $x)); erreur_squelette($msg, $boucle); } } } } } } // Commencer par reperer les boucles appelees explicitement // car elles indexent les arguments de maniere derogatoire foreach ($boucles as $id => $boucle) { if ($boucle->type_requete == TYPE_RECURSIF and $boucle->param) { $boucles[$id]->descr =& $descr; $rec =& $boucles[$boucle->param[0]]; if (!$rec) { $msg = array('zbug_boucle_recursive_undef', array('nom' => $boucle->param[0])); erreur_squelette($msg, $boucle); $boucles[$id]->type_requete = false; } else { $rec->externe = $id; $descr['id_mere'] = $id; $boucles[$id]->return = calculer_liste(array($rec), $descr, $boucles, $boucle->param); } } } foreach ($boucles as $id => $boucle) { $id = strval($id); // attention au type dans index_pile $type = $boucle->type_requete; if ($type and $type != TYPE_RECURSIF) { $res = ''; if ($boucle->param) { // retourne un tableau en cas d'erreur $res = calculer_criteres($id, $boucles); } $descr['id_mere'] = $id; $boucles[$id]->return = calculer_liste($boucle->milieu, $descr, $boucles, $id); // Si les criteres se sont mal compiles // ne pas tenter d'assembler le code final // (mais compiler le corps pour detection d'erreurs) if (is_array($res)) { $boucles[$id]->type_requete = false; } } } // idem pour la racine $descr['id_mere'] = ''; $corps = calculer_liste($squelette, $descr, $boucles); // Calcul du corps de toutes les fonctions PHP, // en particulier les requetes SQL et TOTAL_BOUCLE // de'terminables seulement maintenant foreach ($boucles as $id => $boucle) { $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle); if ($boucle->return === false) { $corps = false; continue; } // appeler la fonction de definition de la boucle if ($req = $boucle->type_requete) { // boucle personnalisée ? $table = strtoupper($boucle->type_requete); $serveur = strtolower($boucle->sql_serveur); if ((!$serveur or !function_exists($f = "boucle_" . $serveur . "_" . $table) and !function_exists($f = $f . "_dist")) and !function_exists($f = "boucle_" . $table) and !function_exists($f = $f . "_dist")) { // fonction de boucle standard if (!function_exists($f = 'boucle_DEFAUT')) { $f = 'boucle_DEFAUT_dist'; } } $req = "\n\n\tstatic \$command = array();\n\t" . "static \$connect;\n\t" . "\$command['connect'] = \$connect = " . _q($boucle->sql_serveur) . ";" . $f($id, $boucles); } else { $req = "\n\treturn '';"; } $boucles[$id]->return = "\n\nfunction BOUCLE" . strtr($id, "-", "_") . $nom . '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' . $req . "\n}\n"; } // Au final, si le corps ou un critere au moins s'est mal compile // retourner False, sinon inserer leur decompilation if (is_bool($corps)) { return false; } $principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) { ' . ' if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"])) $doublons = nettoyer_env_doublons($Pile[0]["doublons"]); $connect = ' . _q($connect) . '; $page = ' . $corps . ";\n\n\treturn analyse_resultat_skel(" . var_export($nom, true) . ", \$Cache, \$page, " . var_export($sourcefile, true) . ");\n}"; $secondes = spip_timer('calcul_skel'); spip_log("COMPIL ({$secondes}) [{$sourcefile}] {$nom}.php"); // $connect n'est pas sûr : on nettoie $connect = preg_replace(',[^\\w],', '', $connect); // Assimiler la fct principale a une boucle anonyme, pour retourner un resultat simple $code = new Boucle(); $code->descr = $descr; $code->return = ' // // Fonction principale du squelette ' . $sourcefile . ($connect ? " pour {$connect}" : '') . (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: {$secondes}") . "\n//\n" . $principal; $boucles[''] = $code; return $boucles; }
function tw_propre($t, $connect = null) { // les appels directs a cette fonction depuis le php de l'espace // prive etant historiquement ecrits sans argment $connect // on utilise la presence de celui-ci pour distinguer les cas // ou il faut passer interdire_script explicitement // les appels dans les squelettes (de l'espace prive) fournissant un $connect // ne seront pas perturbes $interdire_script = false; if (is_null($connect)) { $connect = ''; $interdire_script = true; } if (!$t) { return strval($t); } $debug = _request('var_debug_wheel'); if ($debug) { spip_timer('echappe_html'); } $t = echappe_html($t); if ($debug) { $GLOBALS['totaux']['echappe_html'] += spip_timer('echappe_html', true); } if ($debug) { spip_timer('expanser_liens'); } $t = expanser_liens_tw($t, $connect); if ($debug) { $GLOBALS['totaux']['expanser_liens'] += spip_timer('expanser_liens', true); } if ($debug) { spip_timer('tw_traiter_raccourcis'); } $t = tw_traiter_raccourcis($t); if ($debug) { $GLOBALS['totaux']['tw_traiter_raccourcis'] += spip_timer('tw_traiter_raccourcis', true); } if ($debug) { spip_timer('tw_echappe_retour_modeles'); } $t = tw_echappe_retour_modeles($t, $interdire_script); if ($debug) { $GLOBALS['totaux']['tw_echappe_retour_modeles'] += spip_timer('tw_echappe_retour_modeles', true); } return $t; }
/** * Déclenche le cron en asynchrone ou retourne le code HTML pour le déclencher * * Retourne le HTML à ajouter à la page pour declencher le cron * ou rien si on a réussi à le lancer en asynchrone. * * Un verrou (cron.lock) empêche l'exécution du cron plus d'une fois par seconde. * * @uses queue_sleep_time_to_next_job() * @see action_cron() L'URL appelée pour déclencher le cron * * @return string */ function queue_affichage_cron() { $texte = ""; $time_to_next = queue_sleep_time_to_next_job(); // rien a faire si le prochain job est encore dans le futur if ($time_to_next > 0 or defined('_DEBUG_BLOCK_QUEUE')) { return $texte; } // ne pas relancer si on vient de lancer dans la meme seconde par un hit concurent if (file_exists($lock = _DIR_TMP . "cron.lock") and !(@filemtime($lock) < $_SERVER['REQUEST_TIME'])) { return $texte; } @touch($lock); // il y a des taches en attentes // si depuis plus de 5min, on essaye de lancer le cron par tous les moyens pour rattraper le coup // on est sans doute sur un site qui n'autorise pas http sortant ou avec peu de trafic $urgent = false; if ($time_to_next < -300) { $urgent = true; } $url_cron = generer_url_action('cron', '', false, true); if (!defined('_HTML_BG_CRON_FORCE') or !_HTML_BG_CRON_FORCE) { // 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_cron); 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) { $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: " . $parts['host'] . "\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); spip_timer('read'); $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('read', true); spip_timer('read'); } fclose($fp); if (!$urgent) { return $texte; } } } elseif (function_exists("curl_init")) { //setting the curl parameters. $ch = curl_init($url_cron); 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, 200); // lancer curl_exec($ch); // fermer curl_close($ch); if (!$urgent) { return $texte; } } } // si deja force, on retourne sans rien if (defined('_DIRECT_CRON_FORCE')) { return $texte; } // si c'est un bot // inutile de faire un appel par image background, // on force un appel direct en fin de hit if (defined('_IS_BOT') and _IS_BOT) { define('_DIRECT_CRON_FORCE', true); return $texte; } // en derniere solution, on insere une image background dans la page $texte = '<!-- SPIP-CRON --><div style="background-image: url(\'' . generer_url_action('cron') . '\');"></div>'; return $texte; }
function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect = ''){ global $tables_jointures; static $trouver_table; spip_timer('calcul_skel'); if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug'){ $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette']; $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile; if (!isset($GLOBALS['debug_objets']['principal'])) $GLOBALS['debug_objets']['principal'] = $nom; } foreach ($boucles as $id => $boucle){ $GLOBALS['debug_objets']['boucle'][$nom . $id] = $boucle; } $descr['documents'] = compile_inclure_doublons($squelette); // Demander la description des tables une fois pour toutes // et reperer si les doublons sont demandes // pour un inclure ou une boucle document // c'est utile a la fonction champs_traitements if (!$trouver_table) $trouver_table = charger_fonction('trouver_table', 'base'); foreach ($boucles as $id => $boucle){ if (!($type = $boucle->type_requete)) continue; if (!$descr['documents'] AND ( (($type=='documents') AND $boucle->doublons) OR compile_inclure_doublons($boucle->avant) OR compile_inclure_doublons($boucle->apres) OR compile_inclure_doublons($boucle->milieu) OR compile_inclure_doublons($boucle->altern)) ) $descr['documents'] = true; if ($type!='boucle'){ if (!$boucles[$id]->sql_serveur AND $connect) $boucles[$id]->sql_serveur = $connect; $show = $trouver_table($type, $boucles[$id]->sql_serveur); // si la table n'existe pas avec le connecteur par defaut, // c'est peut etre une table qui necessite son connecteur dedie fourni // permet une ecriture allegee (GEO) -> (geo:GEO) if (!$show AND $show = $trouver_table($type, strtolower($type))) $boucles[$id]->sql_serveur = strtolower($type); if ($show){ $boucles[$id]->show = $show; // recopie les infos les plus importantes $boucles[$id]->primary = $show['key']["PRIMARY KEY"]; $boucles[$id]->id_table = $x = $show['id_table']; $boucles[$id]->from[$x] = $nom_table = $show['table']; $boucles[$id]->descr = &$descr; if ((!$boucles[$id]->jointures) AND (isset($tables_jointures[$nom_table])) AND is_array($x = $tables_jointures[$nom_table]) ) $boucles[$id]->jointures = $x; if ($boucles[$id]->jointures_explicites){ $jointures = preg_split("/\s+/", $boucles[$id]->jointures_explicites); while ($j = array_pop($jointures)) array_unshift($boucles[$id]->jointures, $j); } } else { // Pas une erreur si la table est optionnelle if ($boucles[$id]->table_optionnelle) $boucles[$id]->type_requete = ''; else { $boucles[$id]->type_requete = false; $boucle = $boucles[$id]; $x = (!$boucle->sql_serveur ? '' : ($boucle->sql_serveur . ":")) . $type; $msg = array('zbug_table_inconnue', array('table' => $x)); erreur_squelette($msg, $boucle); } } } } // Commencer par reperer les boucles appelees explicitement // car elles indexent les arguments de maniere derogatoire foreach ($boucles as $id => $boucle){ if ($boucle->type_requete=='boucle' AND $boucle->param){ $boucles[$id]->descr = &$descr; $rec = &$boucles[$boucle->param[0]]; if (!$rec){ $msg = array('zbug_boucle_recursive_undef', array('nom' => $boucle->param[0])); erreur_squelette($msg, $boucle); $boucles[$id]->type_requete = false; } else { $rec->externe = $id; $descr['id_mere'] = $id; $boucles[$id]->return = calculer_liste(array($rec), $descr, $boucles, $boucle->param); } } } foreach ($boucles as $id => $boucle){ $id = strval($id); // attention au type dans index_pile $type = $boucle->type_requete; if ($type AND $type!='boucle'){ $crit = !$boucle->param ? true : calculer_criteres($id, $boucles); $descr['id_mere'] = $id; $boucles[$id]->return = calculer_liste($boucle->milieu, $descr, $boucles, $id); // Si les criteres se sont mal compiles // ne pas tenter d'assembler le code final // (mais compiler le corps pour detection d'erreurs) if (is_array($crit)) $boucles[$id]->type_requete = false; } } // idem pour la racine $descr['id_mere'] = ''; $corps = calculer_liste($squelette, $descr, $boucles); $debug = (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug'); if ($debug){ include_spip('public/decompiler'); include_spip('public/format_' . _EXTENSION_SQUELETTES); } // Calcul du corps de toutes les fonctions PHP, // en particulier les requetes SQL et TOTAL_BOUCLE // de'terminables seulement maintenant foreach ($boucles as $id => $boucle){ $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle); if ($boucle->return===false) continue; // appeler la fonction de definition de la boucle if ($req = $boucle->type_requete){ $f = 'boucle_' . strtoupper($req); // si pas de definition perso, definition spip if (!function_exists($f)) $f = $f . '_dist'; // laquelle a une definition par defaut if (!function_exists($f)) $f = 'boucle_DEFAUT'; if (!function_exists($f)) $f = 'boucle_DEFAUT_dist'; $req = "\n\n\tstatic \$connect = " . _q($boucle->sql_serveur) . ";" . $f($id, $boucles); } else $req = ("\n\treturn '';"); $boucles[$id]->return = "function BOUCLE" . strtr($id, "-", "_") . $nom . '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' . $req . "\n}\n\n"; if ($debug) $GLOBALS['debug_objets']['code'][$nom . $id] = $boucles[$id]->return; } // Au final, si le corps ou un critere au moins s'est mal compile // retourner False, sinon inserer leur decompilation if (is_bool($corps)) return false; foreach ($boucles as $id => $boucle){ if ($boucle->return===false) return false; $boucle->return = "\n\n/* BOUCLE " . $boucle->type_requete . " " . (!$debug ? '' : str_replace('*/', '* /', decompiler_criteres($boucle->param, $boucle->criteres))) . " */\n\n " . $boucle->return; } $secondes = spip_timer('calcul_skel'); spip_log("COMPIL ($secondes) [$sourcefile] $nom.php"); // $connect n'est pas sûr : on nettoie $connect = preg_replace(',[^\w],', '', $connect); // Assimiler la fct principale a une boucle anonyme, c'est plus simple $code = new Boucle; $code->descr = $descr; $code->return = ' // // Fonction principale du squelette ' . $sourcefile . ($connect ? " pour $connect" : '') . (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") . "\n//" . (!$debug ? '' : ("\n/*\n" . str_replace('*/', '* /', public_decompiler($squelette)) . "\n*/")) . " function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) { ' // reporter de maniere securisee les doublons inclus . ' if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"])) $doublons = nettoyer_env_doublons($Pile[0]["doublons"]); $connect = ' . _q($connect) . '; $page = ' . // ATTENTION, le calcul de l'expression $corps affectera $Cache // c'est pourquoi on l'affecte a la variable auxiliaire $page. // avant de referencer $Cache $corps . "; return analyse_resultat_skel(" . var_export($nom, true) . ", \$Cache, \$page, " . var_export($sourcefile, true) . "); }"; $boucles[''] = $code; return $boucles; }
function valider_dir($files, $ext, $dir) { $res = array(); $transformer_xml = charger_fonction('valider', 'xml'); $valideur = $ext=='php' ? 'valider_script' : 'valider_skel' ; include_spip('public/assembler'); foreach($files as $f) { spip_timer($f); $val = $valideur($transformer_xml, $f, $dir, $ext); // Ne pas saturer la memoire, donner juste la taille de la page // avec un nombre negatif quand c'est un message d'erreur if (is_string($val[0])) { $n = strlen($val[0]); $val[0] = strpos($val[0], "id='minipres'") ? (0-$n):$n; } $n = spip_timer($f); $val[]= $n; array_unshift($val, count($val[1])); spip_log("validation de $f en $n secondes"); $res[]= $val; } return $res; }
function typographie_fr($letexte) { # version core if (!$GLOBALS['tw']) { return typographie_fr_dist($letexte); } $debug = _request('var_debug_wheel'); static $trans; if (!isset($trans)) { $trans = array(" " => '~', "»" => '»', "«" => '«', "”" => '”', "“" => '“', "°" => '°', "'" => '’'); switch ($GLOBALS['meta']['charset']) { case 'utf-8': $trans[" "] = '~'; $trans["»"] = '»'; $trans["«"] = '«'; $trans["”"] = '”'; $trans["“"] = '“'; $trans["°"] = '°'; break; default: $trans["�"] = '~'; $trans["�"] = '«'; $trans["�"] = '»'; $trans["�"] = '°'; break; } } # cette chaine ne peut pas exister, # cf. TYPO_PROTECTEUR dans inc/texte $pro = "--"; if ($debug) { spip_timer('trans'); } $letexte = str_replace(array_keys($trans), array_values($trans), $letexte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['trans'] += spip_timer('trans', true); } if ($debug) { spip_timer('cherche1'); } # la typo du ; risque de clasher avec les entites &xxx; if (strpos($letexte, ';') !== false) { $letexte = str_replace(';', '~;', $letexte); $letexte = preg_replace(',(&#?[0-9a-z]+)~;,iS', '$1;', $letexte); } /* 2 */ $letexte = preg_replace('/»| --?,|(?::| %)(?:\\W|$)/S', '~$0', $letexte); /* 3 */ $letexte = preg_replace('/[!?][!?\\.]*/S', "{$pro}~\$0", $letexte, -1, $c); if ($c) { $letexte = preg_replace("/([\\[<\\(!\\?\\.]){$pro}~/S", '$1', $letexte); $letexte = str_replace("{$pro}", '', $letexte); } /* 4 */ $letexte = preg_replace('/«|M(?:M?\\.|mes?|r\\.?|°) |[nN]° /S', '$0~', $letexte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['cherche1'] += spip_timer('cherche1', true); } if ($debug) { spip_timer('chercheespaces'); } if (strpos($letexte, '~') !== false) { $letexte = preg_replace("/ *~+ */S", "~", $letexte); } if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['chercheespaces'] += spip_timer('chercheespaces', true); } if ($debug) { spip_timer('cherche2'); } $letexte = preg_replace("/--([^-]|\$)/S", "{$pro}—\$1", $letexte, -1, $c); if ($c) { $letexte = preg_replace("/([-\n]){$pro}—/S", "\$1--", $letexte); $letexte = str_replace($pro, '', $letexte); } $letexte = preg_replace(',(https?|ftp|mailto)~((://[^"\'\\s\\[\\]\\}\\)<>]+)~([?]))?,S', '$1$3$4', $letexte); $letexte = str_replace('~', ' ', $letexte); if ($debug) { $GLOBALS['totaux']['expanser_liens:']['corriger_typo:']['cherche2'] += spip_timer('cherche2', true); } return $letexte; }
function inc_genie_dist($taches = array()) { if (!$taches) $taches = taches_generales(); // Quelle est la tache la plus urgente ? $tache = ''; $tmin = $t = time(); foreach ($taches as $nom => $periode) { $celock = _DIR_TMP . $nom . '.lock'; $date_lock = @filemtime($celock); if ($date_lock + $periode < $tmin) { $tmin = $date_lock + $periode; $tache = $nom; $lock = $celock; $last = $date_lock; } // debug : si la date du fichier est superieure a l'heure actuelle, // c'est que les serveurs Http et de fichiers sont desynchro. // Ca peut mettre en peril les taches cron : signaler dans le log // (On laisse toutefois flotter sur une heure, pas la peine de s'exciter // pour si peu) else if ($date_lock > $t + 3600) spip_log("Erreur de date du fichier $lock : $date_lock > $t !"); } if ($tache) { spip_timer('tache'); spip_log('cron: debut '.$tache, 'genie'); touch($lock); $cron = charger_fonction($tache, 'genie'); $retour = $cron($last); // si la tache a eu un effet : log if ($retour) { spip_log("cron: $tache (" . spip_timer('tache') . ") $retour", 'genie'); if ($retour < 0) @touch($lock, 0 - $retour); } } }