Rev 609 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/***************************************************************************\* SPIP, Systeme de publication pour l'internet ** ** Copyright (c) 2001-2005 ** Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James ** ** Ce programme est un logiciel libre distribue sous licence GNU/GPL. ** Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *\***************************************************************************/// Ce fichier ne sera execute qu'une foisif (defined("_ECRIRE_INC_ORTHO")) return;define("_ECRIRE_INC_ORTHO", "1");// Mettre a jour la liste locale des miroirsfunction maj_miroirs_ortho() {$liste = explode(" ", lire_meta("liste_miroirs_ortho"));$miroirs_old = array();foreach ($liste as $index) {list($url) = explode(" ", lire_meta("miroir_ortho_$index"));$miroirs_old[$url] = $index;}// TODO: recuperer la liste dynamiquement depuis ortho.spip.net$urls = array('http://tony.ortho.spip.net/ortho_serveur.php','http://spip-ortho.linagora.org:18080/ortho_serveur.php','http://ortho.spip.net/ortho_serveur.php');$liste = array();$miroirs_new = array();$index = 1;foreach ($urls as $url) {if ($index_old = $miroirs_old[$url]) {$s = lire_meta("miroir_ortho_$index_old");}else {$s = $url." ".time();}$miroirs_new[$index] = $s;$liste[] = $index++;}foreach ($miroirs_old as $index) {effacer_meta("miroir_ortho_$index");}foreach ($miroirs_new as $index => $s) {ecrire_meta("miroir_ortho_$index", $s);}ecrire_meta("liste_miroirs_ortho", join(" ", $liste));}// Lire la liste des miroirs et les langues associeesfunction lire_miroirs_ortho() {global $miroirs_ortho, $index_miroirs_ortho, $duree_cache_miroirs_ortho;$miroirs_ortho = array();$index_miroirs_ortho = array();$t = time();$maj = lire_meta("maj_miroirs_ortho");if ($maj < $t - $duree_cache_miroirs_ortho) {maj_miroirs_ortho();ecrire_meta("maj_miroirs_ortho", $t);lire_metas();}$liste = explode(" ", lire_meta("liste_miroirs_ortho"));foreach ($liste as $index) {$s = explode(" ", lire_meta("miroir_ortho_$index"));$url = $s[0];$maj = $s[1];$langs = explode(",", $s[2]);// Reinitialiser periodiquement la liste des langues non-supporteesif ($maj < $t - $duree_cache_miroirs_ortho) {foreach ($langs as $key => $lang) {if (substr($lang, 0, 1) == '!') unset($langs[$key]);}$s[1] = $t;$s[2] = join(",", $langs);ecrire_meta("miroir_ortho_$index", join(" ", $s));}$index_miroirs_ortho[$url] = $index;$miroirs_ortho[$url] = array();foreach ($langs as $lang) {if ($lang) $miroirs_ortho[$url][$lang] = $lang;}}lire_metas();mt_srand(time());}// Sauvegarder les infos de langues pour le miroirfunction ecrire_miroir_ortho($url, $langs) {global $index_miroirs_ortho;$index = $index_miroirs_ortho[$url];$s = explode(" ", lire_meta("miroir_ortho_$index"));$s[2] = join(",", $langs);ecrire_meta("miroir_ortho_$index", join(" ", $s));}function ajouter_langue_miroir($url, $lang) {global $miroirs_ortho;$langs = $miroirs_ortho[$url];$langs[$lang] = $lang;unset($langs["!$lang"]);ecrire_miroir_ortho($url, $langs);}function enlever_langue_miroir($url, $lang) {global $miroirs_ortho;$langs = $miroirs_ortho[$url];unset($langs[$lang]);$langs["!$lang"] = "!$lang";ecrire_miroir_ortho($url, $langs);}function reset_miroir($url) {global $miroirs_ortho;ecrire_miroir_ortho($url, array());}//// Renvoie la liste des miroirs utilisables pour une langue donnee//function chercher_miroirs_ortho($lang) {global $miroirs_ortho;$result = array();$chercher = true;foreach ($miroirs_ortho as $url => $langs) {if ($langs[$lang]) {$result[] = $url;}else if ($chercher && !$langs["!$lang"]) {//echo "test $lang $url<br />";if (verifier_langue_miroir($url, $lang)) $result[] = $url;// Ne recuperer la langue d'un miroir qu'une seule fois par requeteif ($result) $chercher = false;}}return $result;}function choisir_miroirs_ortho($lang) {$liste = chercher_miroirs_ortho($lang);if (!count($liste)) return false;foreach ($liste as $url) {$miroirs[md5(mt_rand().$url.rand())] = $url;}ksort($miroirs);return $miroirs;}//// Envoyer une requete a un serveur d'orthographe//function post_ortho($url, $texte, $lang) {include_ecrire('inc_sites.php3');list($f, $fopen) = init_http('POST', $url);if (!$f OR $fopen) {spip_log("Echec connexion $url");return false;}// Si le texte est petit, l'overhead du multipart est dispendieuxif (!$GLOBALS['flag_gz'] || strlen($texte) < 200) {$gz = false;$body = "op=spell&lang=".urlencode($lang)."&texte=".urlencode($texte);fputs($f, "Content-Type: application/x-www-form-urlencoded\r\n");}// Sinon, on passe en multipart pour compresser la chaine a corrigerelse {// Il faut eliminer les caracteres 0 sinon PHP ne lit pas la suite du parametre// passe en multipart/form-data (gros hack bien sale)$texte_gz = gzcompress($texte);for ($echap = 255; $echap > 0; $echap--) {$str_echap = chr($echap ^ 1).chr($echap).chr($echap).chr($echap ^ 2);if (!is_int(strpos($texte_gz, $str_echap))) break;}$texte_gz = str_replace("\x00", $str_echap, $texte_gz);$gz = true;$vars = array('op' => 'spell', 'lang' => $lang, 'texte' => $texte_gz, 'gz' => 1, 'nul_echap' => $str_echap);$boundary = substr(md5(rand().'ortho'), 0, 8);$body = '';foreach ($vars as $key => $val) {$body .= "\r\n--$boundary\r\n";$body .= "Content-Disposition: form-data; name=\"$key\"\r\n";$body .= "\r\n";$body .= $val;}$body .= "\r\n--$boundary\r\n";fputs($f, "Content-Type: multipart/form-data; boundary=$boundary\r\n");}// On envoie le contenufputs($f, "Content-Length: ".strlen($body)."\r\n");fputs($f, "\r\n"); // Fin des entetesfputs($f, $body);// Lire les en-tetes HTTP de la reponse et decoder le Content-Length$length = 0;$s = fgets($f, 1000);$statut = 0;if (preg_match(',^HTTP/\d+\.\d+ (\d+) ,', $s, $r))$statut = intval($r[1]);if ($statut != 200) {fclose($f);return false;}while ($s = trim(fgets($f, 1000))) {if (preg_match(',Content-Length:(.*),i', $s, $r))$length = intval($r[1]);}$r = "";// Lire le corps de la reponse HTTPif ($length) {while (($l = strlen($r)) < $length) $r .= fread($f, $length - $l);}else while (!feof($f) AND $r .= fread($f, 1024));fclose($f);if ($gz) $r = gzuncompress($r);return $r;}//// Verifier si un serveur gere une langue donnee//function verifier_langue_miroir($url, $lang) {// Envoyer une requete bidon$result = post_ortho($url, " ", $lang);if (!preg_match(',<ortho>.*</ortho>,s', $result)) {reset_miroir($url);return false;}if (!preg_match(',<erreur>.*<code>E_LANG_ABSENT</code>.*</erreur>,s', $result)) {ajouter_langue_miroir($url, $lang);return true;}enlever_langue_miroir($url, $lang);return false;}//// Gestion du dictionnaire local//function suggerer_dico_ortho(&$mots, $lang) {$lang = addslashes($lang);$query = "SELECT mot FROM spip_ortho_dico WHERE lang='$lang' "."AND mot IN ('".join("', '", array_map('addslashes', $mots))."')";$result = spip_query($query);$mots = array_flip($mots);$bons = array();if (isset($mots[''])) unset($mots['']);while ($row = spip_fetch_array($result)) {$mot = $row['mot'];if (isset($mots[$mot])) {unset($mots[$mot]);$bons[] = $mot;}}if (count($mots)) $mots = array_flip($mots);else $mots = array();return $bons;}function ajouter_dico_ortho($mot, $lang) {global $connect_id_auteur;$lang = addslashes($lang);$mot = addslashes($mot);$id_auteur = intval($connect_id_auteur);$query = "INSERT IGNORE INTO spip_ortho_dico (lang, mot, id_auteur) "."VALUES ('$lang', '$mot', '$id_auteur')";spip_query($query);}function supprimer_dico_ortho($mot, $lang) {$lang = addslashes($lang);$mot = addslashes($mot);$query = "DELETE FROM spip_ortho_dico WHERE lang='$lang' AND mot='$mot'";spip_query($query);}function gerer_dico_ortho($lang) {global $ajout_ortho, $supp_ortho;if ($mot = strval($ajout_ortho)) {ajouter_dico_ortho($mot, $lang);}if ($mot = strval($supp_ortho)) {supprimer_dico_ortho($mot, $lang);}}//// Gestion du cache de corrections//function suggerer_cache_ortho(&$mots, $lang) {global $duree_cache_ortho;$lang = addslashes($lang);$query = "SELECT mot, ok, suggest FROM spip_ortho_cache WHERE lang='$lang' "."AND mot IN ('".join("', '", array_map('addslashes', $mots))."') "."AND maj > FROM_UNIXTIME(".(time() - $duree_cache_ortho).")";$result = spip_query($query);$mots = array_flip($mots);$suggest = array();if (isset($mots[''])) unset($mots['']);while ($row = spip_fetch_array($result)) {$mot = $row['mot'];if (isset($mots[$mot])) {unset($mots[$mot]);if (!$row['ok']) {if (strlen($row['suggest']))$suggest[$mot] = explode(",", $row['suggest']);else$suggest[$mot] = array();}}}if (count($mots)) $mots = array_flip($mots);else $mots = array();return $suggest;}function ajouter_cache_ortho($tous, $mauvais, $lang) {global $duree_cache_ortho;$values = array();$lang = addslashes($lang);if (count($mauvais)) {foreach ($mauvais as $mot => $suggest) {$values[] = "('$lang', '".addslashes($mot)."', 0, '".addslashes(join(",", $suggest))."')";}}if (count($tous)) {foreach ($tous as $mot) {if (!isset($mauvais[$mot]))$values[] = "('$lang', '".addslashes($mot)."', 1, '')";}}if (count($values)) {$query = "DELETE FROM spip_ortho_cache "."WHERE maj < FROM_UNIXTIME(".(time() - $duree_cache_ortho).")";spip_query($query);$query = "INSERT IGNORE INTO spip_ortho_cache (lang, mot, ok, suggest) "."VALUES ".join(", ", $values);spip_query($query);}}//// Cette fonction doit etre appelee pour reecrire le texte en utf-8 "propre"//function preparer_ortho($texte, $lang) {include_spip("charsets.php");$charset = lire_meta('charset');if ($charset == 'utf-8')return unicode_to_utf_8(html2unicode($texte));elsereturn unicode_to_utf_8(html2unicode(charset2unicode($texte, $charset, true)));}function afficher_ortho($texte) {$charset = lire_meta('charset');if ($charset == 'utf-8') return $texte;if (!is_array($texte)) return charset2unicode($texte, 'utf-8');foreach ($texte as $key => $val) {$texte[$key] = afficher_ortho($val);}return $texte;}//// Cette fonction envoie le texte prepare a un serveur d'orthographe// et retourne un tableau de mots mal orthographies associes chacun a un tableau de mots suggeres//function corriger_ortho($texte, $lang, $charset = 'AUTO') {include_spip("charsets.php");include_spip("index.php");include_spip("filtres.php");$texte = preg_replace(',<code>.*?</code>,is', '', $texte);$texte = preg_replace(',<cadre>.*?</cadre>,is', '', $texte);$texte = preg_replace(',\[([^][]*)->([^][]*)\],is', '\\1', $texte);$texte = supprimer_tags($texte);$texte = " ".$texte." ";// Virer les caracteres non-alphanumeriquesif (test_pcre_unicode()) {$texte = preg_replace(',[^-\''.pcre_lettres_unicode().']+,us', ' ', $texte);}else {// Ici bidouilles si PCRE en mode UTF-8 ne fonctionne pas correctement ...// Caracteres non-alphanumeriques de la plage latin-1 + saloperies non-conformes$texte = preg_replace(',\xC2[\x80-\xBF],', ' ', $texte);// Poncutation etendue (unicode)$texte = preg_replace(",".plage_punct_unicode().",", ' ', $texte);// Caracteres ASCII non-alphanumeriques$texte = preg_replace(",[^-a-zA-Z0-9\x80-\xFF']+,", ' ', $texte);}$texte = preg_replace(', [-\']+,', ' ', $texte); // tirets de typo$texte = preg_replace(',\' ,', ' ', $texte); // apostrophes utilisees comme guillemets//echo htmlspecialchars($texte)."<br>";// Virer les mots contenant au moins un chiffre$texte = preg_replace(', ([^ ]*\d[^ ]* )+,', ' ', $texte);// Melanger les mots$mots = preg_split(', +,', $texte);sort($mots);$mots = array_unique($mots);// 1. Enlever les mots du dico local$bons = suggerer_dico_ortho($mots, $lang);// 2. Enlever les mots du cache local$result_cache = suggerer_cache_ortho($mots, $lang);// 3. Envoyer les mots restants a un serveur$mauvais = array();if (count($mots)) {$texte = join(' ', $mots);// Hack : ligatures en francais pas gerees par aspellunset($trans_rev);$texte_envoi = $texte;if ($lang == 'fr') {$trans = array(chr(197).chr(146) => 'OE', chr(197).chr(147) => 'oe',chr(195).chr(134) => 'AE', chr(195).chr(166) => 'ae');$texte_envoi = strtr($texte_envoi, $trans);$trans_rev = array_flip($trans);}// POST de la requete et recuperation du resultat XML$urls = choisir_miroirs_ortho($lang);if (!$urls) return false;unset($ok);$erreur = false;foreach ($urls as $url) {$xml = post_ortho($url, $texte_envoi, $lang);if ($xml && preg_match(',<ortho>(.*)</ortho>,s', $xml, $r)) {$xml = $r[1];if (preg_match(',<erreur>.*<code>(.*)</code>.*</erreur>,s', $xml, $r))$erreur = $r[1];if (preg_match(',<ok>(.*)</ok>,s', $xml, $r)) {$ok = $r[1];break;}}reset_miroir($url);}if (!isset($ok)) return $erreur;// Remplir le tableau des resultats (mots mal orthographies)if ($trans_rev) {$assoc_mots = array_flip($mots);}while (preg_match(',<mot>(.*?)</mot>(\s*<suggest>(.*?)</suggest>)?,s', $ok, $r)) {$p = strpos($ok, $r[0]);$ok = substr($ok, $p + strlen($r[0]));$mot = $r[1];if ($suggest = $r[3])$s = preg_split('/[ ,]+/', $suggest);else$s = array();// Hack ligaturesif ($trans_rev) {$mot_rev = strtr($mot, $trans_rev);if ($mot != $mot_rev) {if ($assoc_mots[$mot])$mauvais[$mot] = $s;if ($assoc_mots[$mot_rev])$mauvais[$mot_rev] = $s;}else $mauvais[$mot] = $s;}else $mauvais[$mot] = $s;}}if (!$erreur) ajouter_cache_ortho($mots, $mauvais, $lang);// Retour a l'envoyeur$mauvais = array_merge($result_cache, $mauvais);$result = array('bons' => $bons,'mauvais' => $mauvais);if ($erreur) $result['erreur'] = $erreur;return $result;}//// Fonctions d'affichage HTML//function panneau_ortho($ortho_result) {global $id_suggest;$id_suggest = array();$i = 1;$mauvais = $ortho_result['mauvais'];$bons = $ortho_result['bons'];if (!count($mauvais) && !count($bons)) return;ksort($mauvais);echo "<script type='text/javascript'><!--var curr_suggest = null;function suggest(id) {var menu_box;if (curr_suggest)document.getElementById('suggest' + curr_suggest).className = 'suggest-inactif';if (1 || id!=curr_suggest) {document.getElementById('suggest' + id).className = 'suggest-actif';curr_suggest = id;}else curr_suggest = null;menu_box = document.getElementById('select_ortho');if (menu_box.length > id) menu_box.selectedIndex = id;}";echo "//--></script>";echo "<form class='form-ortho verdana2' action='' method='get'>\n";echo "<select name='select_ortho' id='select_ortho' onChange='suggest(this.selectedIndex);'>\n";echo "<option value='0'>... "._T('ortho_mots_a_corriger')." ...</option>\n";foreach ($mauvais as $mot => $suggest) {$id = $id_suggest[$mot] = "$i";$i++;$mot_html = afficher_ortho($mot);echo "<option value='$id'>$mot_html</option>\n";}foreach ($bons as $mot) {$id = $id_suggest[$mot] = "$i";$i++;}echo "</select>\n";echo "</form>\n";// Mots mal orthographies :// liste des suggestions plus lien pour ajouter au dicoforeach ($mauvais as $mot => $suggest) {$id = $id_suggest[$mot];$mot_html = afficher_ortho($mot);echo "<div class='suggest-inactif' id='suggest$id'>";echo "<span class='ortho'>$mot_html</span>\n";echo "<div class='detail'>\n";if (is_array($suggest) && count($suggest)) {echo "<ul>\n";$i = 0;foreach ($suggest as $sug) {if (++$i > 12) {echo "<li><i>(...)</i></li>\n";break;}echo "<li>".typo(afficher_ortho($sug))."</li>\n";}echo "</ul>\n";}else {echo "<i>"._T('ortho_aucune_suggestion')."</i>";}echo "<br />";$link = new Link;$link->delVar('supp_ortho');$link->addVar('ajout_ortho', $mot);icone_horizontale(_T('ortho_ajouter_ce_mot'), $link->getUrl(), "ortho-24.gif", "creer.gif");echo "</div>\n";echo "</div>\n\n";}// Mots trouves dans le dico :// message plus lien pour retirer du dicoforeach ($bons as $mot) {$id = $id_suggest[$mot];$mot_html = afficher_ortho($mot);echo "<div class='suggest-inactif' id='suggest$id'>";echo "<span class='ortho-dico'>$mot_html</span>";echo "<div class='detail'>\n";echo "<i>"._T('ortho_ce_mot_connu')."</i>";echo "<br />";$link = new Link;$link->delVar('ajout_ortho');$link->addVar('supp_ortho', $mot);icone_horizontale(_T('ortho_supprimer_ce_mot'), $link->getUrl(), "ortho-24.gif", "supprimer.gif");echo "</div>\n";echo "</div>\n";}}function souligner_match_ortho(&$texte, $cherche, $remplace) {// Eviter les —, etc.if ($cherche{0} == '&' AND $cherche{strlen($cherche) - 1} == ';') return;if ($cherche{0} == '>')$texte = str_replace($cherche, $remplace, $texte);else {// Ne pas remplacer a l'interieur des tags HTML$table = explode($cherche, $texte);unset($avant);$texte = '';foreach ($table as $s) {if (!isset($avant)) {$avant = $s;continue;}$ok = true;$texte .= $avant;// Detecter si le match a eu lieu dans un tag HTMLif (is_int($deb_tag = strrpos($texte, '<'))) {if (strrpos($texte, '>') <= $deb_tag)$ok = false;}if ($ok) $texte .= $remplace;else $texte .= $cherche;$avant = $s;}$texte .= $avant;}}function souligner_ortho($texte, $lang, $ortho_result) {global $id_suggest;$vu = array();$mauvais = $ortho_result['mauvais'];$bons = $ortho_result['bons'];// Neutraliser l'apostrophe unicode pour surligner correctement les fautes$texte = " ".str_replace("\xE2\x80\x99", "'", $texte)." ";// Chercher et remplacer les mots un par un$delim = '[^-\''.pcre_lettres_unicode().']';foreach ($mauvais as $mot => $suggest) {$pattern = ",$delim".$mot."$delim,us";// Recuperer les occurences du mot dans le texteif (preg_match_all($pattern, $texte, $regs, PREG_SET_ORDER)) {$id = $id_suggest[$mot];$mot_html = afficher_ortho($mot);foreach ($regs as $r) {if ($vu[$cherche = $r[0]]) continue;$vu[$cherche] = 1;$html = "<a class='ortho' onclick=\"suggest($id);return false;\" href=''>$mot_html</a>";$remplace = str_replace($mot, $html, $cherche);souligner_match_ortho($texte, $cherche, $remplace);}}}foreach ($bons as $mot) {$pattern = ",$delim".$mot."$delim,us";// Recuperer les occurences du mot dans le texteif (preg_match_all($pattern, $texte, $regs, PREG_SET_ORDER)) {$id = $id_suggest[$mot];$mot_html = afficher_ortho($mot);foreach ($regs as $r) {if ($vu[$cherche = $r[0]]) continue;$vu[$cherche] = 1;$html = "<a class='ortho-dico' onclick=\"suggest($id);return false;\" href=''>$mot_html</a>";$remplace = str_replace($mot, $html, $cherche);souligner_match_ortho($texte, $cherche, $remplace);}}}$texte = preg_replace(',(^ | $),', '', $texte);return $texte;}function init_ortho() {global $duree_cache_ortho, $duree_cache_miroirs_ortho;$duree_cache_ortho = 7 * 24 * 3600;$duree_cache_miroirs_ortho = 24 * 3600;lire_miroirs_ortho();}init_ortho();?>