diff --git a/ecrire/action/editer_site.php b/ecrire/action/editer_site.php index 3555441a11d4c68815b4cae9924158ccc8654c97..6767215ff920dfdcd7c3f20d66e672aace20ddf9 100644 --- a/ecrire/action/editer_site.php +++ b/ecrire/action/editer_site.php @@ -107,8 +107,12 @@ function action_editer_site_dist() { } if ($resyndiquer) { - include_spip('inc/syndic'); - syndic_a_jour($id_syndic); + // ah si PHP connaisait les fermetures... + // Cette globale est utilisee exclusivement dans la fct suivante. + $GLOBALS['genie_syndic_now'] = $id_syndic; + // forcer l'execution immediate de cette tache + // (i.e. appeler la fct suivante avec gestion du verrou) + cron(0, array('syndic' => -91)); } // Rediriger le navigateur $redirect = parametre_url(urldecode(_request('redirect')), diff --git a/ecrire/genie/syndic.php b/ecrire/genie/syndic.php index bc4ef2e0fc9163555c03ff0af10f9f10f38b239a..55cdbc2a6c748b421f0cf79177393dfed88ee330 100644 --- a/ecrire/genie/syndic.php +++ b/ecrire/genie/syndic.php @@ -11,11 +11,218 @@ \***************************************************************************/ if (!defined("_ECRIRE_INC_VERSION")) return; - include_spip('inc/syndic'); function genie_syndic_dist($t) { + define('_GENIE_SYNDIC', 1); // pour message de compatibilite ci-dessous return executer_une_syndication(); } +// +// Effectuer la syndication d'un unique site, +// retourne 0 si aucun a faire ou echec lors de la tentative +// + +// http://doc.spip.org/@executer_une_syndication +function executer_une_syndication() { + + spip_connect(); + + ## valeurs modifiables dans mes_options + ## attention il est tres mal vu de prendre une periode < 20 minutes + define('_PERIODE_SYNDICATION', 2*60); + define('_PERIODE_SYNDICATION_SUSPENDUE', 24*60); + + // On va tenter un site 'sus' ou 'off' de plus de 24h, et le passer en 'off' + // s'il echoue + $where = "syndication IN ('sus','off') + AND statut='publie' + AND date_syndic < DATE_SUB(NOW(), INTERVAL + "._PERIODE_SYNDICATION_SUSPENDUE." MINUTE)"; + $row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1")); + if ($row) { + $id_syndic = $row["id_syndic"]; + $res1 = syndic_a_jour($id_syndic, 'off'); + } else $res1 = true; + + // Et un site 'oui' de plus de 2 heures, qui passe en 'sus' s'il echoue + $where = "syndication='oui' + AND statut='publie' + AND date_syndic < DATE_SUB(NOW(), INTERVAL "._PERIODE_SYNDICATION." MINUTE)"; + $row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1")); + + if ($row) { + $id_syndic = $row["id_syndic"]; + $res2 = syndic_a_jour($id_syndic, 'sus'); + } else $res2 = true; + + return ($res1 OR $res2) ? 0 : $id_syndic; +} + + +// +// Mettre a jour le site +// +// Attention, cette fonction ne doit pas etre appellee simultanement +// sur un meme site: un verrouillage a du etre pose en amont. +// + +// http://doc.spip.org/@syndic_a_jour +function syndic_a_jour($now_id_syndic, $statut = 'off') { + include_spip('inc/texte'); + if (!defined('_GENIE_SYNDIC')) + spip_log("syndic_a_jour doit etre appelee par Cron. Cf. " . + "http://trac.rezo.net/trac/spip/changeset/10294", + 'vieilles_defs'); + $result = spip_query("SELECT * FROM spip_syndic WHERE id_syndic=$now_id_syndic"); + + if (!$row = sql_fetch($result)) + return; + + $url_syndic = $row['url_syndic']; + $url_site = $row['url_site']; + + if ($row['moderation'] == 'oui') + $moderation = 'dispo'; // a valider + else + $moderation = 'publie'; // en ligne sans validation + + spip_query("UPDATE spip_syndic SET syndication='$statut', date_syndic=NOW() WHERE id_syndic=$now_id_syndic"); + + // Aller chercher les donnees du RSS et les analyser + include_spip('inc/distant'); + $rss = recuperer_page($url_syndic, true); + if (!$rss) + $articles = _T('avis_echec_syndication_02'); + else + $articles = analyser_backend($rss, $url_syndic); + + // Renvoyer l'erreur le cas echeant + if (!is_array($articles)) return $articles; + + // Les enregistrer dans la base + + $faits = array(); + foreach ($articles as $data) { + inserer_article_syndique ($data, $now_id_syndic, $moderation, $url_site, $url_syndic, $row['resume'], $row['documents'], $faits); + } + + // moderation automatique des liens qui sont sortis du feed + if (count($faits) > 0) { + $faits = join(",", $faits); + if ($row['miroir'] == 'oui') { + spip_query("UPDATE spip_syndic_articles SET statut='off', maj=maj WHERE id_syndic=$now_id_syndic AND NOT (id_syndic_article IN ($faits))"); + } + // suppression apres 2 mois des liens qui sont sortis du feed + if ($row['oubli'] == 'oui') { + + sql_delete('spip_syndic_articles', "id_syndic=$now_id_syndic AND maj < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND date < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND NOT (id_syndic_article IN ($faits))"); + } + } + + // Noter que la syndication est OK + spip_query("UPDATE spip_syndic SET syndication='oui' WHERE id_syndic=$now_id_syndic"); + + return false; # c'est bon +} + + +// +// Insere un article syndique (renvoie true si l'article est nouveau) +// +// http://doc.spip.org/@inserer_article_syndique +function inserer_article_syndique ($data, $now_id_syndic, $statut, $url_site, $url_syndic, $resume, $documents, &$faits) { + // Creer le lien s'il est nouveau - cle=(id_syndic,url) + // On coupe a 255 caracteres pour eviter tout doublon + // sur une URL de plus de 255 qui exloserait la base de donnees + $le_lien = substr($data['url'], 0,255); + + // Chercher les liens de meme cle + $s = spip_query("SELECT id_syndic_article,titre FROM spip_syndic_articles WHERE url=" . _q($le_lien) . " AND id_syndic=$now_id_syndic ORDER BY maj DESC"); + + // S'il y a plusieurs liens qui repondent, il faut choisir le plus proche + // (ie meme titre et pas deja fait), le mettre a jour et ignorer les autres + if (spip_num_rows($s) > 1) { + while ($a = sql_fetch($s)) + if ($a['titre'] == $data['titre'] + AND !in_array($a['id_syndic_article'], $faits)) { + $id_syndic_article = $a['id_syndic_article']; + break; + } + } + + // Sinon, s'il y en a un, on verifie qu'on ne vient pas de l'ecrire avec + // un autre item du meme feed qui aurait le meme link + else if ($a = sql_fetch($s) + AND !in_array($a['id_syndic_article'], $faits)) { + $id_syndic_article = $a['id_syndic_article']; + } + + // Si l'article n'existe pas, on le cree + if (!isset($id_syndic_article)) { + $ajout = $id_syndic_article = sql_insertq('spip_syndic_articles', + array('id_syndic' => $now_id_syndic, + 'url' => $le_lien, + 'date' => date("Y-m-d H:i:s", $data['date']), + 'statut' => $statut)); + if (!$ajout) return; + } + $faits[] = $id_syndic_article; + + // Descriptif, en mode resume ou mode 'full text' + // on prend en priorite data['descriptif'] si on est en mode resume, + // et data['content'] si on est en mode "full syndication" + if ($resume != 'non') { + // mode "resume" + $desc = strlen($data['descriptif']) ? + $data['descriptif'] : $data['content']; + $desc = couper(trim(textebrut($desc)), 300); + } else { + // mode "full syndication" + // choisir le contenu pertinent + // & refaire les liens relatifs + $desc = strlen($data['content']) ? + $data['content'] : $data['descriptif']; + $desc = liens_absolus($desc, $url_syndic); + } + + // tags & enclosures (preparer spip_syndic_articles.tags) + $tags = $data['enclosures']; + # eviter les doublons (cle = url+titre) et passer d'un tableau a une chaine + if ($data['tags']) { + $vus = array(); + foreach ($data['tags'] as $tag) { + $cle = supprimer_tags($tag).extraire_attribut($tag,'href'); + $vus[$cle] = $tag; + } + $tags .= ($tags ? ', ' : '') . join(', ', $vus); + } + + // Mise a jour du contenu (titre,auteurs,description,date?,source...) + $vals = array( + 'titre' => $data['titre'], + 'lesauteurs' => $data['lesauteurs'], + 'descriptif' => $desc, + 'lang'=> substr($data['lang'],0,10), + 'source' => substr($data['source'],0,255), + 'url_source' => substr($data['url_source'],0,255), + 'tags' => $tags); + + // Mettre a jour la date si lastbuilddate + if ($data['lastbuilddate']) + $vals['date']= date("Y-m-d H:i:s", $data['lastbuilddate']); + + sql_updateq('spip_syndic_articles', $vals, "id_syndic_article=$id_syndic_article"); + + // Point d'entree post_syndication + pipeline('post_syndication', + array( + $le_lien, + $now_id_syndic, + $data + ) + ); + + return $ajout; +} ?> diff --git a/ecrire/inc/syndic.php b/ecrire/inc/syndic.php index c6a7156f896cba21fe62fa18a6498aa754f33a06..8b6f6befe6942c39acd1492975e3bcb28f26e29b 100644 --- a/ecrire/inc/syndic.php +++ b/ecrire/inc/syndic.php @@ -12,6 +12,12 @@ if (!defined("_ECRIRE_INC_VERSION")) return; +// ATTENTION +// Cette inclusion charge executer_une_syndication pour compatibilite, +// mais cette fonction ne doit plus etre invoquee directement: +// il faut passer par cron() pour avoir un verrou portable +// Voir un exemple dans action/editer/site +include_spip('genie/syndic'); // prend un fichier backend et retourne un tableau des items lus, // et une chaine en cas d'erreur @@ -372,211 +378,4 @@ function cdata_echappe_retour(&$table, &$echappe_cdata) { $e, $table[$var]); } } - - -// -// Effectuer la syndication d'un unique site, -// retourne 0 si aucun a faire ou echec lors de la tentative -// - -// http://doc.spip.org/@executer_une_syndication -function executer_une_syndication() { - - spip_connect(); - - ## valeurs modifiables dans mes_options - ## attention il est tres mal vu de prendre une periode < 20 minutes - define('_PERIODE_SYNDICATION', 2*60); - define('_PERIODE_SYNDICATION_SUSPENDUE', 24*60); - - // On va tenter un site 'sus' ou 'off' de plus de 24h, et le passer en 'off' - // s'il echoue - $where = "syndication IN ('sus','off') - AND statut='publie' - AND date_syndic < DATE_SUB(NOW(), INTERVAL - "._PERIODE_SYNDICATION_SUSPENDUE." MINUTE)"; - $row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1")); - if ($row) { - $id_syndic = $row["id_syndic"]; - $res1 = syndic_a_jour($id_syndic, 'off'); - } else $res1 = true; - - // Et un site 'oui' de plus de 2 heures, qui passe en 'sus' s'il echoue - $where = "syndication='oui' - AND statut='publie' - AND date_syndic < DATE_SUB(NOW(), INTERVAL "._PERIODE_SYNDICATION." MINUTE)"; - $row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1")); - - if ($row) { - $id_syndic = $row["id_syndic"]; - $res2 = syndic_a_jour($id_syndic, 'sus'); - } else $res2 = true; - - return ($res1 OR $res2) ? 0 : $id_syndic; -} - - -// -// Mettre a jour le site -// -// Attention, cette fonction ne doit pas etre appellee simultanement -// sur un meme site: un verrouillage a du etre pose en amont. -// - -// http://doc.spip.org/@syndic_a_jour -function syndic_a_jour($now_id_syndic, $statut = 'off') { - include_spip('inc/texte'); - - $result = spip_query("SELECT * FROM spip_syndic WHERE id_syndic=$now_id_syndic"); - - if (!$row = sql_fetch($result)) - return; - - $url_syndic = $row['url_syndic']; - $url_site = $row['url_site']; - - if ($row['moderation'] == 'oui') - $moderation = 'dispo'; // a valider - else - $moderation = 'publie'; // en ligne sans validation - - spip_query("UPDATE spip_syndic SET syndication='$statut', date_syndic=NOW() WHERE id_syndic=$now_id_syndic"); - - // Aller chercher les donnees du RSS et les analyser - include_spip('inc/distant'); - $rss = recuperer_page($url_syndic, true); - if (!$rss) - $articles = _T('avis_echec_syndication_02'); - else - $articles = analyser_backend($rss, $url_syndic); - - // Renvoyer l'erreur le cas echeant - if (!is_array($articles)) return $articles; - - // Les enregistrer dans la base - - $faits = array(); - foreach ($articles as $data) { - inserer_article_syndique ($data, $now_id_syndic, $moderation, $url_site, $url_syndic, $row['resume'], $row['documents'], $faits); - } - - // moderation automatique des liens qui sont sortis du feed - if (count($faits) > 0) { - $faits = join(",", $faits); - if ($row['miroir'] == 'oui') { - spip_query("UPDATE spip_syndic_articles SET statut='off', maj=maj WHERE id_syndic=$now_id_syndic AND NOT (id_syndic_article IN ($faits))"); - } - // suppression apres 2 mois des liens qui sont sortis du feed - if ($row['oubli'] == 'oui') { - - sql_delete('spip_syndic_articles', "id_syndic=$now_id_syndic AND maj < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND date < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND NOT (id_syndic_article IN ($faits))"); - } - } - - // Noter que la syndication est OK - spip_query("UPDATE spip_syndic SET syndication='oui' WHERE id_syndic=$now_id_syndic"); - - return false; # c'est bon -} - - -// -// Insere un article syndique (renvoie true si l'article est nouveau) -// -// http://doc.spip.org/@inserer_article_syndique -function inserer_article_syndique ($data, $now_id_syndic, $statut, $url_site, $url_syndic, $resume, $documents, &$faits) { - // Creer le lien s'il est nouveau - cle=(id_syndic,url) - // On coupe a 255 caracteres pour eviter tout doublon - // sur une URL de plus de 255 qui exloserait la base de donnees - $le_lien = substr($data['url'], 0,255); - - // Chercher les liens de meme cle - $s = spip_query("SELECT id_syndic_article,titre FROM spip_syndic_articles WHERE url=" . _q($le_lien) . " AND id_syndic=$now_id_syndic ORDER BY maj DESC"); - - // S'il y a plusieurs liens qui repondent, il faut choisir le plus proche - // (ie meme titre et pas deja fait), le mettre a jour et ignorer les autres - if (spip_num_rows($s) > 1) { - while ($a = sql_fetch($s)) - if ($a['titre'] == $data['titre'] - AND !in_array($a['id_syndic_article'], $faits)) { - $id_syndic_article = $a['id_syndic_article']; - break; - } - } - - // Sinon, s'il y en a un, on verifie qu'on ne vient pas de l'ecrire avec - // un autre item du meme feed qui aurait le meme link - else if ($a = sql_fetch($s) - AND !in_array($a['id_syndic_article'], $faits)) { - $id_syndic_article = $a['id_syndic_article']; - } - - // Si l'article n'existe pas, on le cree - if (!isset($id_syndic_article)) { - $ajout = $id_syndic_article = sql_insertq('spip_syndic_articles', - array('id_syndic' => $now_id_syndic, - 'url' => $le_lien, - 'date' => date("Y-m-d H:i:s", $data['date']), - 'statut' => $statut)); - if (!$ajout) return; - } - $faits[] = $id_syndic_article; - - // Descriptif, en mode resume ou mode 'full text' - // on prend en priorite data['descriptif'] si on est en mode resume, - // et data['content'] si on est en mode "full syndication" - if ($resume != 'non') { - // mode "resume" - $desc = strlen($data['descriptif']) ? - $data['descriptif'] : $data['content']; - $desc = couper(trim(textebrut($desc)), 300); - } else { - // mode "full syndication" - // choisir le contenu pertinent - // & refaire les liens relatifs - $desc = strlen($data['content']) ? - $data['content'] : $data['descriptif']; - $desc = liens_absolus($desc, $url_syndic); - } - - // tags & enclosures (preparer spip_syndic_articles.tags) - $tags = $data['enclosures']; - # eviter les doublons (cle = url+titre) et passer d'un tableau a une chaine - if ($data['tags']) { - $vus = array(); - foreach ($data['tags'] as $tag) { - $cle = supprimer_tags($tag).extraire_attribut($tag,'href'); - $vus[$cle] = $tag; - } - $tags .= ($tags ? ', ' : '') . join(', ', $vus); - } - - // Mise a jour du contenu (titre,auteurs,description,date?,source...) - $vals = array( - 'titre' => $data['titre'], - 'lesauteurs' => $data['lesauteurs'], - 'descriptif' => $desc, - 'lang'=> substr($data['lang'],0,10), - 'source' => substr($data['source'],0,255), - 'url_source' => substr($data['url_source'],0,255), - 'tags' => $tags); - - // Mettre a jour la date si lastbuilddate - if ($data['lastbuilddate']) - $vals['date']= date("Y-m-d H:i:s", $data['lastbuilddate']); - - sql_updateq('spip_syndic_articles', $vals, "id_syndic_article=$id_syndic_article"); - - // Point d'entree post_syndication - pipeline('post_syndication', - array( - $le_lien, - $now_id_syndic, - $data - ) - ); - - return $ajout; -} - ?> diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php index 8ecfb946ae226821e08e09b1665b881bf0baa3c9..f123c9fe2ca2e2af7776aad51c8ca43647a1f591 100644 --- a/ecrire/inc/utils.php +++ b/ecrire/inc/utils.php @@ -613,7 +613,7 @@ function spip_touch($fichier, $duree=0, $touch=true) { if ((@$f=filemtime($fichier)) AND ($f >= time() - $duree)) return false; } - if ($touch) { + if ($touch!==false) { if (!@touch($fichier)) { spip_unlink($fichier); @touch($fichier); }; @chmod($fichier, _SPIP_CHMOD & ~0111); } @@ -632,12 +632,13 @@ function action_cron() { include_spip('inc/headers'); http_status(204); // No Content header("Connection: close"); - cron (true); + cron (2); } // cron() : execution des taches de fond -// quand il est appele par public.php il n'est pas gourmand; -// quand il est appele par ?action=cron, il est gourmand +// Le premier argument indique l'intervalle demande entre deux taches +// par defaut, 60 secondes (quand il est appele par public.php) +// il vaut 2 quand il est appele par ?action=cron, voire 0 en urgence // On peut lui passer en 2e arg le tableau de taches attendu par inc_genie() // Retourne Vrai si un tache a pu etre effectuee @@ -651,7 +652,7 @@ function cron ($gourmand=false, $taches= array()) { // ou est trop vieux (> 60 sec), on va voir si un cron est necessaire. // Au passage si on est gourmand on le dit aux autres if (spip_touch(_DIR_TMP.'cron.lock-gourmand', 60, $gourmand) - OR $gourmand) { + OR ($gourmand!==false)) { // Le fichier cron.lock indique la date de la derniere tache // Il permet d'imposer qu'il n'y ait qu'une tache a la fois @@ -659,7 +660,8 @@ function cron ($gourmand=false, $taches= array()) { // ca soulage le serveur et ca evite // les conflits sur la base entre taches. - if (spip_touch(_DIR_TMP.'cron.lock', 2)) { + if (spip_touch(_DIR_TMP.'cron.lock', + (is_int($gourmand) ? $gourmand : 2))) { $genie = charger_fonction('genie', 'inc', true); if ($genie) { $genie($taches);