erreur) // et volontaires (var_mode et var_profile) // Si pas d'autorisation, les erreurs ne sont pas affichees // (mais seront dans les logs) // Si l'erreur vient de SPIP, en parler sur spip@rezo.net function public_debusquer_dist($message = '', $lieu = ''){ global $visiteur_session; global $debug_objets; static $tableau_des_erreurs = array(); // Erreur ou appel final ? if ($message){ $message = debusquer_compose_message($message); $tableau_des_erreurs[] = array($message, $lieu); set_request('var_mode', 'debug'); $GLOBALS['bouton_admin_debug'] = true; // Permettre a la compil de continuer if (is_object($lieu) AND (!isset($lieu->code) OR !$lieu->code)) $lieu->code = "''"; // forcer l'appel au debusqueur en cas de boucles infernales $urgence = (_DEBUG_MAX_SQUELETTE_ERREURS AND count($tableau_des_erreurs)>_DEBUG_MAX_SQUELETTE_ERREURS); if (!$urgence) return; } if (empty($debug_objets['principal'])) $debug_objets['principal'] = $GLOBALS['fond']; include_spip('inc/autoriser'); if (!autoriser('debug')) return; include_spip('inc/headers'); include_spip('inc/filtres'); // en cas de squelette inclus, virer le code de l'incluant: // - il contient souvent une Div restreignant la largeur a 3 fois rien // - ca fait 2 headers ! // sauf si l'on se trouve deja dans un flux compresse (plugin compresseur // actif par exemple) if (ob_get_length() AND !in_array('ob_gzhandler', ob_get_status()) ){ ob_end_clean(); } lang_select($visiteur_session['lang']); $fonc = _request('var_mode_objet'); $mode = _request('var_mode_affiche'); $self = str_replace("\\'", ''', self()); $self = parametre_url($self, 'var_mode', 'debug'); $res = debusquer_bandeau($tableau_des_erreurs) . '
' . debusquer_squelette($fonc, $mode, $self); if (!_DIR_RESTREINT OR headers_sent()) return $res; if ($tableau_des_erreurs) http_status(503); http_no_cache(); if (isset($_GET['var_profile'])){ $titre = parametre_url($GLOBALS['REQUEST_URI'], 'var_profile', ''); $titre = parametre_url($titre, 'var_mode', ''); } else { if (!$fonc) $fonc = $debug_objets['principal']; $titre = !$mode ? $fonc : ($mode . ' ' . $debug_objets['sourcefile'][$fonc]); } if ($message===false){ lang_select(); return debusquer_entete($titre, $res); } else echo debusquer_entete($titre, $res); exit; } function debusquer_compose_message($msg){ if (is_array($msg)){ // si c'est un texte, c'est une traduction a faire, mais // sqlite renvoit aussi des erreurs alpha num (mais avec 3 arguments) if (!is_numeric($msg[0]) AND count($msg)==2) { // message avec argument: instancier $msg = _T($msg[0], $msg[1], 'spip-debug-arg'); } else { // message SQL: interpreter $msg = debusquer_requete($msg); } } // FIXME: le fond n'est pas la si on n'est pas dans un squelette // cela dit, ca serait bien d'indiquer tout de meme d'ou vient l'erreur $fond = isset($GLOBALS['fond']) ? $GLOBALS['fond'] : ""; // une erreur critique sort $message en array $debug = is_array($msg) ? $msg[1] : $msg; spip_log("Debug: " . $debug . " (" . $fond . ")"); return $msg; } function debusquer_bandeau($erreurs){ if (!empty($erreurs)){ $n = array(count($erreurs) . ' ' . _T('zbug_erreur_squelette')); return debusquer_navigation($erreurs, $n); } elseif (!empty($GLOBALS['tableau_des_temps'])) { include_spip('public/tracer'); list($temps, $nav) = chrono_requete($GLOBALS['tableau_des_temps']); return debusquer_navigation($temps, $nav, 'debug-profile'); } else return ''; } function debusquer_contexte($env){ if (is_array($env_tab = @unserialize($env))) $env = $env_tab; if (!$env) return ''; $res = ""; foreach ($env as $nom => $valeur){ if (is_array($valeur)) $valeur = '(' . count($valeur) . ' items) [' . join(',', $valeur) . ']'; $res .= "\n" . nl2br(entites_html($nom)) . ": " . nl2br(entites_html($valeur)) . "\n"; } return "
#ENV\n
$res
\n"; } // Affichage du tableau des erreurs ou des temps de calcul // Cliquer sur les numeros en premiere colonne permet de voir le code function debusquer_navigation($tableau, $caption = array(), $id = 'debug-nav'){ if (_request('exec')=='valider_xml') return ''; $GLOBALS['bouton_admin_debug'] = true; $res = ''; $href = quote_amp(parametre_url($GLOBALS['REQUEST_URI'], 'var_mode', 'debug')); foreach ($tableau as $i => $err){ $boucle = $ligne = $skel = ''; list($msg, $lieu) = $err; if (is_object($lieu)){ $ligne = $lieu->ligne; $boucle = $lieu->id_boucle ? $lieu->id_boucle : ''; if (isset($lieu->descr['nom'])){ $nom_code = $lieu->descr['nom']; $skel = $lieu->descr['sourcefile']; $h2 = parametre_url($href, 'var_mode_objet', $nom_code); $h3 = parametre_url($h2, 'var_mode_affiche', 'squelette') . '#L' . $ligne; $skel = "$skel"; if ($boucle){ $h3 = parametre_url($h2 . $boucle, 'var_mode_affiche', 'boucle'); $boucle = "$boucle"; } } } $j = ($i+1); $res .= "" . $j . " " . $msg . "" . ($skel ? $skel : "   /  ") . "" . ($boucle ? $boucle : "   /  ") . "" . $ligne . "\n"; } return "\n" . "" // fausse caption du chrono (mais vraie nav) . (!empty($caption[1]) ? $caption[1] : '') . "" . $res . "
" . $caption[0] ## aide locale courte a ecrire, avec lien vers une grosse page de documentation # aide('erreur_compilation'), . "
" . _T('numero') . "" . _T('public:message') . "" . _T('squelette') . "" . _T('zbug_boucle') . "" . _T('ligne') . "
"; } /** * Retourne le texte d'un message d'erreur de requête * * Si une boucle cree des soucis, on peut afficher la requete fautive * avec son code d'erreur * * @param array $message * Description du message en 3 éléments : * - numéro d'erreur * - texte de l'erreur * - requête en erreur * @return string|array * Retourne le texte de l'erreur a afficher * ou un tableau si l'erreur est critique **/ function debusquer_requete($message){ list($errno, $msg, $query) = $message; // FIXME: ces écritures mélangent divers syntaxe des moteurs SQL // il serait plus prudent certainement d'avoir une fonction d'analyse par moteur if (preg_match(',err(no|code):?[[:space:]]*([0-9]+),i', $msg, $regs)){ $errno = $regs[2]; } elseif (is_numeric($errno) and ($errno==1030 OR $errno<=1026) AND preg_match(',[^[:alnum:]]([0-9]+)[^[:alnum:]],', $msg, $regs) ) { $errno = $regs[1]; } // Erreur systeme if (is_numeric($errno) and $errno>0 AND $errno<200){ $retour = "

" . _T('info_erreur_systeme', array('errsys' => $errno)) . "
\n" . _T('info_erreur_systeme2', array('script' => generer_url_ecrire('base_repair'))) . '
'; spip_log("Erreur systeme $errno"); return array($retour, ''); } // Requete erronee $err = "" . _T('avis_erreur_mysql') . " $errno
\n" . spip_htmlspecialchars($msg) . "\n
" . spip_htmlspecialchars($query) . "

"; //. aide('erreur_mysql'); return $err; } // http://doc.spip.org/@trouve_boucle_debug function trouve_boucle_debug($n, $nom, $debut = 0, $boucle = ""){ global $debug_objets; $id = $nom . $boucle; if (is_array($debug_objets['sequence'][$id])){ foreach ($debug_objets['sequence'][$id] as $v){ if (!preg_match('/^(.*)(<\?.*\?>)(.*)$/s', $v[0], $r)) $y = substr_count($v[0], "\n"); else { if ($v[1][0]=='#') // balise dynamique $incl = $debug_objets['resultat'][$v[2]]; else // inclusion $incl = $debug_objets['squelette'][trouve_squelette_inclus($v[0])]; $y = substr_count($incl, "\n") +substr_count($r[1], "\n") +substr_count($r[3], "\n"); } if ($n<=($y+$debut)){ if ($v[1][0]=='?') return trouve_boucle_debug($n, $nom, $debut, substr($v[1], 1)); elseif ($v[1][0]=='!') { if ($incl = trouve_squelette_inclus($v[1])) return trouve_boucle_debug($n, $incl, $debut); } return array($nom, $boucle, $v[2]-1+$n-$debut); } $debut += $y; } } return array($nom, $boucle, $n-$debut); } // http://doc.spip.org/@trouve_squelette_inclus function trouve_squelette_inclus($script){ global $debug_objets; preg_match('/include\(.(.*).php3?.\);/', $script, $reg); // si le script X.php n'est pas ecrire/public.php // on suppose qu'il prend le squelette X.html (pas sur, mais y a pas mieux) if ($reg[1]=='ecrire/public') // si c'est bien ecrire/public on cherche le param 'fond' if (!preg_match("/'fond' => '([^']*)'/", $script, $reg)) // a defaut on cherche le param 'page' if (!preg_match("/'param' => '([^']*)'/", $script, $reg)) $reg[1] = "inconnu"; $incl = ',' . $reg[1] . '[.]\w$,'; foreach ($debug_objets['sourcefile'] as $k => $v){ if (preg_match($incl, $v)) return $k; } return ""; } // http://doc.spip.org/@reference_boucle_debug function reference_boucle_debug($n, $nom, $self){ list($skel, $boucle, $ligne) = trouve_boucle_debug($n, $nom); if (!$boucle) return !$ligne ? "" : (" (" . (($nom!=$skel) ? _T('squelette_inclus_ligne') : _T('squelette_ligne')) . " $ligne)"); else { $self .= "&var_mode_objet=$skel$boucle&var_mode_affiche=boucle"; return !$ligne ? " (boucle\n$boucle)" : " (boucle $boucle ligne\n$ligne)"; } } // affiche un texte avec numero de ligne et ancre. // http://doc.spip.org/@ancre_texte function ancre_texte($texte, $fautifs = array(), $nocpt = false){ $var_mode_ligne = _request('var_mode_ligne'); if ($var_mode_ligne) $fautifs[] = array($var_mode_ligne); $res = ''; $s = highlight_string($texte, true); if (substr($s, 0, 6)==''){ $s = substr($s, 6); $res = ''; } $s = preg_replace(',<(\w[^<>]*)>([^<]*)
([^<]*),', '<\1>\2
' . "\n" . '<\1>\3', $s); $tableau = explode("
", $s); $format = "%0" . strval(@strlen(count($tableau))) . "d %s
\n"; $format10 = str_replace('white', 'lightgrey', $format); $formaterr = "color: red;"; $i = 1; $flignes = array(); $loc = array(0, 0); foreach ($fautifs as $lc) if (is_array($lc)){ $l = array_shift($lc); $flignes[$l] = $lc; } else $flignes[$lc] = $loc; $ancre = md5($texte); foreach ($tableau as $ligne){ if (isset($flignes[$i])){ $ligne = str_replace(' ', ' ', $ligne); $indexmesg = $flignes[$i][1]; $err = textebrut($flignes[$i][2]); // tentative de pointer sur la colonne fautive; // marche pas car highlight_string rajoute des entites. A revoir. // $m = $flignes[$i][0]; // $ligne = substr($ligne, 0, $m-1) . // sprintf($formaterr, substr($ligne,$m)); $bg = $formaterr; } else { $indexmesg = $ancre; $err = $bg = ''; } $res .= sprintf((($i%10) ? $format : $format10), $i, $bg, $indexmesg, $err, $i, $ligne); $i++; } return "
" . '
' . ($nocpt ? '' : _T('info_numero_abbreviation')) . "
" . $res . "
\n"; } // l'environnement graphique du debuggueur function debusquer_squelette($fonc, $mode, $self){ global $debug_objets; if ($mode!=='validation'){ if (isset($debug_objets['sourcefile']) and $debug_objets['sourcefile']){ $res = "
\n" . debusquer_navigation_squelettes($self) . "
"; } else $res = ''; if ($fonc){ $id = " id='$fonc'"; if (!empty($GLOBALS['debug_objets'][$mode][$fonc])){ list($legend, $texte, $res2) = debusquer_source($fonc, $mode); $texte .= $res2; } elseif (!empty($debug_objets[$mode][$fonc . 'tout'])) { $legend = _T('zbug_' . $mode); $texte = $debug_objets[$mode][$fonc . 'tout']; $texte = ancre_texte($texte, array('', '')); } } else return strlen(trim($res)) ? "afficher-masquer le debug
$res
" // cas de l'appel sur erreur: montre la page : $GLOBALS['debug_objets']['resultat']['tout']; } else { $valider = charger_fonction('valider', 'xml'); $val = $valider($debug_objets['validation'][$fonc . 'tout']); // Si erreur, signaler leur nombre dans le formulaire admin $debug_objets['validation'] = $val->err ? count($val->err) : ''; list($texte, $err) = emboite_texte($val, $fonc, $self); if ($err===false) $err = _T('impossible'); elseif ($err===true) $err = _T('correcte'); else $err = ": $err"; $legend = _T('validation') . ' ' . $err; $res = $id = ''; } return !trim($texte) ? '' : ( "afficher-masquer le debug
$res" . "" . "
"); } // http://doc.spip.org/@emboite_texte function emboite_texte($res, $fonc = '', $self = ''){ $errs = $res->err; $texte = $res->entete . ($errs ? '' : $res->page); if (!$texte and !$errs) return array(ancre_texte('', array('', '')), false); if (!$errs) return array(ancre_texte($texte, array('', '')), true); if (!isset($GLOBALS['debug_objets'])){ $colors = array('#e0e0f0', '#f8f8ff'); $encore = count_occ($errs); $encore2 = array(); $fautifs = array(); $err = '' . _T('numero') . "" . _T('occurence') . "" . _T('ligne') . "" . _T('colonne') . "" . _T('erreur') . ""; $i = 0; $style = "style='text-align: right; padding-right: 5px'"; foreach ($errs as $r){ $i++; list($msg, $ligne, $col) = $r; #spip_log("$r = list($msg, $ligne, $col"); if (isset($encore2[$msg])) $ref = ++$encore2[$msg]; else { $encore2[$msg] = $ref = 1; } $err .= "" . $i . "" . "$ref/$encore[$msg]" . "" . $ligne . "" . $col . "$msg\n"; $fautifs[] = array($ligne, $col, $i, $msg); } $err = "

" . $i . "" . " " . _T('erreur_texte') . "

" . $err . "
"; return array(ancre_texte($texte, $fautifs), $err); } else { list($msg, $fermant, $ouvrant) = $errs[0]; $rf = reference_boucle_debug($fermant, $fonc, $self); $ro = reference_boucle_debug($ouvrant, $fonc, $self); $err = $msg . "$fermant$rf
" . "$ouvrant$ro"; return array(ancre_texte($texte, array(array($ouvrant), array($fermant))), $err); } } // http://doc.spip.org/@count_occ function count_occ($regs){ $encore = array(); foreach ($regs as $r){ if (isset($encore[$r[0]])) $encore[$r[0]]++; else $encore[$r[0]] = 1; } return $encore; } function debusquer_navigation_squelettes($self){ global $debug_objets, $spip_lang_right; $res = ''; $boucles = !empty($debug_objets['boucle']) ? $debug_objets['boucle'] : ''; $contexte = $debug_objets['contexte']; $t_skel = _T('squelette'); foreach ($debug_objets['sourcefile'] as $nom => $sourcefile){ $self2 = parametre_url($self, 'var_mode_objet', $nom); $nav = !$boucles ? '' : debusquer_navigation_boucles($boucles, $nom, $self, $sourcefile); $temps = !isset($debug_objets['profile'][$sourcefile]) ? '' : _T('zbug_profile', array('time' => $debug_objets['profile'][$sourcefile])); $res .= "
" . $t_skel . ' ' . $sourcefile . " :\n" . $t_skel . "\n" . _T('zbug_resultat') . "\n" . _T('zbug_code') . "\n" . _T('zbug_calcul') . "" . (!$temps ? '' : ("\n$temps
")) . debusquer_contexte($contexte[$sourcefile]) . (!$nav ? '' : ("\n$nav
\n")) . "
\n"; } return $res; } function debusquer_navigation_boucles($boucles, $nom_skel, $self, $nom_source){ $i = 0; $res = ''; $var_mode_objet = _request('var_mode_objet'); $gram = preg_match('/[.](\w+)$/', $nom_source, $r) ? $r[1] : ''; foreach ($boucles as $objet => $boucle){ if (substr($objet, 0, strlen($nom_skel))==$nom_skel){ $i++; $nom = $boucle->id_boucle; $req = $boucle->type_requete; $crit = public_decompiler($boucle, $gram, 0, 'criteres'); $self2 = $self . "&var_mode_objet=" . $objet; $res .= "\n$i\n" . "" . _T('zbug_boucle') . "\n" . _T('zbug_resultat') . "\n" . _T('zbug_code') . "\n" . _T('zbug_calcul') . "\n" . (($var_mode_objet==$objet) ? "$nom" : $nom) . "\n" . $req . "\n" . spip_htmlspecialchars($crit) . ""; } } return $res; } function debusquer_source($objet, $affiche){ $quoi = $GLOBALS['debug_objets'][$affiche][$objet]; $nom = $GLOBALS['debug_objets']['boucle'][$objet]->id_boucle; $res2 = ""; if ($affiche=='resultat'){ $legend = $nom; $req = $GLOBALS['debug_objets']['requete'][$objet]; if (function_exists('traite_query')){ $c = strtolower(_request('connect')); $c = $GLOBALS['connexions'][$c ? $c : 0]['prefixe']; $req = traite_query($req, '', $c); } // permettre le copier/coller facile // $res = ancre_texte($req, array(), true); $res = "
\n
\n" . $req . "
\n
\n"; // formatage et affichage des resultats bruts de la requete $ress_req = spip_query($req); $brut_sql = ''; $num = 1; // eviter l'affichage de milliers de lignes // personnalisation possible dans mes_options $max_aff = defined('_MAX_DEBUG_AFF') ? _MAX_DEBUG_AFF : 50; while ($retours_sql = sql_fetch($ress_req)){ if ($num<=$max_aff){ $brut_sql .= "

" . ($num==1 ? $num . " sur " . sql_count($ress_req) : $num) . "

"; $brut_sql .= "

"; foreach ($retours_sql as $key => $val){ $brut_sql .= "" . $key . " => " . spip_htmlspecialchars(couper($val, 150)) . "
\n"; } $brut_sql .= "

"; } $num++; } $res2 = interdire_scripts($brut_sql); foreach ($quoi as $view){ // ne pas afficher les $contexte_inclus $view = preg_replace(",<\?php.+\?[>],Uims", "", $view); if ($view){ $res2 .= "\n
" . interdire_scripts($view) . "
"; } } } elseif ($affiche=='code'){ $legend = $nom; $res = ancre_texte("<" . "?php\n" . $quoi . "\n?" . ">"); } elseif ($affiche=='boucle'){ $legend = _T('zbug_boucle') . ' ' . $nom; // Le compilateur prefixe le nom des boucles par l'extension du fichier source. $gram = preg_match('/^([^_]+)_/', $objet, $r) ? $r[1] : ''; $res = ancre_texte(public_decompiler($quoi, $gram, 0, 'boucle')); } elseif ($affiche=='squelette'){ $legend = $GLOBALS['debug_objets']['sourcefile'][$objet]; $res = ancre_texte($GLOBALS['debug_objets']['squelette'][$objet]); } return array($legend, $res, $res2); } // http://doc.spip.org/@debusquer_entete function debusquer_entete($titre, $corps){ global $debug_objets; include_spip('balise/formulaire_admin'); include_spip('public/assembler'); // pour inclure_balise_dynamique include_spip('inc/texte'); // pour corriger_typo return _DOCTYPE_ECRIRE . html_lang_attributes() . "\n" . ('SPIP ' . $GLOBALS['spip_version_affichee'] . ' ' . _T('admin_debug') . ' ' . $titre . ' (' . supprimer_tags(corriger_typo($GLOBALS['meta']['nom_site']))) . ")\n" . "\n" . http_script('', 'jquery.js') . "" . "\n" . "\n" . "
" . $corps . inclure_balise_dynamique(balise_FORMULAIRE_ADMIN_dyn('spip-admin-float', $debug_objets), false) . '
'; } ?>