Ejemplo n.º 1
0
/**
 * Analyser une URL de site distant, qui peut être une syndication.
 *
 * @param string $url
 *     URL du site à analyser
 * @return array|bool
 *     - array : informations du site
 *     - false : site impossible à récupérer
 **/
function analyser_site($url)
{
    include_spip('inc/filtres');
    include_spip('inc/distant');
    // Accepter les URLs au format feed:// ou qui ont oublie le http://
    $url = preg_replace(',^feed://,i', 'http://', $url);
    if (!preg_match(',^[a-z]+://,i', $url)) {
        $url = 'http://' . $url;
    }
    $texte = recuperer_page($url, true);
    if (!$texte) {
        return false;
    }
    include_spip('inc/syndic');
    cdata_echappe($texte, $echappe_cdata);
    if (preg_match(',<(channel|feed)([\\:[:space:]][^>]*)?' . '>(.*)</\\1>,ims', $texte, $regs)) {
        $result['syndication'] = 'oui';
        $result['url_syndic'] = $url;
        $channel = $regs[3];
        // Pour recuperer l'entete, on supprime tous les items
        $b = array_merge(extraire_balises($channel, 'item'), extraire_balises($channel, 'entry'));
        $header = str_replace($b, array(), $channel);
        if ($t = extraire_balise($header, 'title')) {
            cdata_echappe_retour($t, $echappe_cdata);
            $result['nom_site'] = filtrer_entites(supprimer_tags($t));
        }
        if ($t = extraire_balises($header, 'link')) {
            cdata_echappe_retour($t, $echappe_cdata);
            foreach ($t as $link) {
                $u = supprimer_tags(filtrer_entites($link));
                if (!strlen($u)) {
                    $u = extraire_attribut($link, 'href');
                }
                if (strlen($u)) {
                    // on installe l'url comme url du site
                    // si c'est non vide, en donnant la priorite a rel=alternate
                    if (preg_match(',\\balternate\\b,', extraire_attribut($link, 'rel')) or !isset($result['url_site'])) {
                        $result['url_site'] = filtrer_entites($u);
                    }
                }
            }
        }
        $result['url_site'] = url_absolue($result['url_site'], $url);
        if ($a = extraire_balise($header, 'description') or $a = extraire_balise($header, 'tagline')) {
            cdata_echappe_retour($a, $echappe_cdata);
            $result['descriptif'] = filtrer_entites(supprimer_tags($a));
        }
        if (preg_match(',<image.*<url.*>(.*)</url>.*</image>,Uims', $header, $r) and preg_match(',(https?://.*/.*(gif|png|jpg)),ims', $r[1], $r) and $image = recuperer_infos_distantes($r[1])) {
            if (in_array($image['extension'], array('gif', 'jpg', 'png'))) {
                $result['format_logo'] = $image['extension'];
                $result['logo'] = $r[1];
            } else {
                if ($image['fichier']) {
                    spip_unlink($image['fichier']);
                }
            }
        }
    } else {
        $result['syndication'] = 'non';
        $result['url_site'] = $url;
        if (preg_match(',<head>(.*(description|title).*)</head>,Uims', $texte, $regs)) {
            $head = filtrer_entites($regs[1]);
        } else {
            $head = $texte;
        }
        if (preg_match(',<title[^>]*>(.*),ims', $head, $regs)) {
            $titre = trim($regs[1]);
            if (!strlen($titre)) {
                $titre = substr($head, strpos($head, $regs[0]));
            }
            $result['nom_site'] = filtrer_entites(supprimer_tags(preg_replace(',</title>.*$,ims', '', $titre)));
        }
        if ($a = array_merge(extraire_balises($head, 'meta'), extraire_balises($head, 'http-equiv'))) {
            foreach ($a as $meta) {
                if (extraire_attribut($meta, 'name') == 'description') {
                    $desc = trim(extraire_attribut($meta, 'content'));
                    if (!strlen($desc)) {
                        $desc = trim(extraire_attribut($meta, 'value'));
                    }
                    $result['descriptif'] = $desc;
                }
            }
        }
        // Cherchons quand meme un backend
        include_spip('inc/distant');
        include_spip('inc/feedfinder');
        $feeds = get_feed_from_url($url, $texte);
        // si on a a trouve un (ou plusieurs) on le note avec select:
        // ce qui constitue un signal pour exec=sites qui proposera de choisir
        // si on syndique, et quelle url.
        if (count($feeds) >= 1) {
            spip_log("feedfinder.php :\n" . join("\n", $feeds));
            $result['url_syndic'] = "select: " . join(' ', $feeds);
        }
    }
    cdata_echappe_retour($result, $echappe_cdata);
    return $result;
}
Ejemplo n.º 2
0
function analyser_backend($rss, $url_syndic='') {
	include_spip('inc/texte'); # pour couper()

	$rss = pipeline('pre_syndication', $rss);

	// si true, les URLs de type feedburner sont dereferencees
	define('_SYNDICATION_DEREFERENCER_URL', false);

	// Echapper les CDATA
	$echappe_cdata = array();
	if (preg_match_all(',<!\[CDATA\[(.*)]]>,Uims', $rss,
	$regs, PREG_SET_ORDER)) {
		foreach ($regs as $n => $reg) {
			$echappe_cdata[$n] = $reg[1];
			$rss = str_replace($reg[0], "@@@SPIP_CDATA$n@@@", $rss);
		}
	}

	// supprimer les commentaires
	$rss = preg_replace(',<!--.*-->,Ums', '', $rss);

	// simplifier le backend, en supprimant les espaces de nommage type "dc:"
	$rss = preg_replace(',<(/?)(dc):,i', '<\1', $rss);

	// chercher auteur/lang dans le fil au cas ou les items n'en auraient pas
	list($header) = preg_split(',<(item|entry)\b,', $rss, 2);
	if (preg_match_all(
	',<(author|creator)\b(.*)</\1>,Uims',
	$header, $regs, PREG_SET_ORDER)) {
		$les_auteurs_du_site = array();
		foreach ($regs as $reg) {
			$nom = $reg[2];
			if (preg_match(',<name>(.*)</name>,Uims', $nom, $reg))
				$nom = $reg[1];
			$les_auteurs_du_site[] = trim(textebrut(filtrer_entites($nom)));
		}
		$les_auteurs_du_site = join(', ', array_unique($les_auteurs_du_site));
	} else
		$les_auteurs_du_site = '';

	if (preg_match(',<([^>]*xml[:])?lang(uage)?'.'>([^<>]+)<,i', $header, $match))
		$langue_du_site = $match[3];
	// atom
	elseif (preg_match(',<feed\s[^>]*xml:lang=[\'"]([^<>\'"]+)[\'"],i', $header, $match))
		$langue_du_site = $match[1];

	// Attention en PCRE 6.7 preg_match_all casse sur un backend avec de gros <content:encoded>
	$items = preg_split(',<(item|entry)\b.*>,Uims', $rss);
	array_shift($items);
	foreach ($items as $k=>$item)
		$items[$k] = preg_replace(',</(item|entry)\b.*>.*$,UimsS', '', $item);

	//
	// Analyser chaque <item>...</item> du backend et le transformer en tableau
	//

	if (!count($items)) return _T('avis_echec_syndication_01');

	foreach ($items as $item) {
		$data = array();

		// URL (semi-obligatoire, sert de cle)

		// guid n'est un URL que si marque de <guid ispermalink="true"> ;
		// attention la valeur par defaut est 'true' ce qui oblige a quelque
		// gymnastique
		if (preg_match(',<guid.*>[[:space:]]*(https?:[^<]*)</guid>,Uims',
		$item, $regs) AND preg_match(',^(true|1)?$,i',
		extraire_attribut($regs[0], 'ispermalink')))
			$data['url'] = $regs[1];
		// contourner les redirections feedburner
		else if (_SYNDICATION_DEREFERENCER_URL
		AND preg_match(',<feedburner:origLink>(.*)<,Uims',
		$item, $regs))
			$data['url'] = $regs[1];
		// <link>, plus classique
		else if (preg_match(
		',<link[^>]*[[:space:]]rel=["\']?alternate[^>]*>(.*)</link>,Uims',
		$item, $regs))
			$data['url'] = $regs[1];
		else if (preg_match(',<link[^>]*[[:space:]]rel=.alternate[^>]*>,Uims',
		$item, $regs))
			$data['url'] = extraire_attribut($regs[0], 'href');
		else if (preg_match(',<link[^>]*>\s*([^\s]+)\s*</link>,Uims', $item, $regs))
			$data['url'] = $regs[1];
		else if (preg_match(',<link[^>]*>,Uims', $item, $regs))
			$data['url'] = extraire_attribut($regs[0], 'href');

		// Aucun link ni guid, mais une enclosure
		else if (preg_match(',<enclosure[^>]*>,ims', $item, $regs)
		AND $url = extraire_attribut($regs[0], 'url'))
			$data['url'] = $url;

		// pas d'url, c'est genre un compteur...
		else
			$data['url'] = '';

		// Titre (semi-obligatoire)
		if (preg_match(",<title[^>]*>(.*?)</title>,ims",$item,$match))
			$data['titre'] = $match[1];
		else if (preg_match(',<link[[:space:]][^>]*>,Uims',$item,$mat)
		AND $title = extraire_attribut($mat[0], 'title'))
			$data['titre'] = $title; 
		if (!strlen($data['titre'] = trim($data['titre'])))
			$data['titre'] = _T('ecrire:info_sans_titre');

		// Date
		$la_date = '';
		if (preg_match(',<(published|modified|issued)>([^<]*)<,Uims',
		$item,$match))
			$la_date = my_strtotime($match[2]);
		if (!$la_date AND
		preg_match(',<(pubdate)>([^<]*)<,Uims',$item, $match))
			$la_date = my_strtotime($match[2]);
		if (!$la_date AND
		preg_match(',<([a-z]+:date)>([^<]*)<,Uims',$item,$match))
			$la_date = my_strtotime($match[2]);
		if (!$la_date AND
		preg_match(',<date>([^<]*)<,Uims',$item,$match))
			$la_date = my_strtotime($match[1]);

		// controle de validite de la date
		// pour eviter qu'un backend errone passe toujours devant
		// (note: ca pourrait etre defini site par site, mais ca risque d'etre
		// plus lourd que vraiment utile)
		if ($GLOBALS['controler_dates_rss']) {
			if (!$la_date
				OR $la_date > time() + 48 * 3600)
				$la_date = time();
		}

		$data['date'] = $la_date;

		// Honorer le <lastbuilddate> en forcant la date
		if (preg_match(',<(lastbuilddate|updated|modified)>([^<>]+)</\1>,i',
		$item, $regs)
		AND $lastbuilddate = my_strtotime(trim($regs[2]))
		// pas dans le futur
		AND $lastbuilddate < time())
			$data['lastbuilddate'] = $lastbuilddate;

		// Auteur(s)
		if (preg_match_all(
		',<(author|creator)>(.*)</\1>,Uims',
		$item, $regs, PREG_SET_ORDER)) {
			$auteurs = array();
			foreach ($regs as $reg) {
				$nom = $reg[2];
				if (preg_match(',<name>(.*)</name>,Uims', $nom, $reg))
					$nom = $reg[1];
				$auteurs[] = trim(textebrut(filtrer_entites($nom)));
			}
			$data['lesauteurs'] = join(', ', array_unique($auteurs));
		}
		else
			$data['lesauteurs'] = $les_auteurs_du_site;

		// Description
		if (preg_match(',<(description|summary)\b.*'
		.'>(.*)</\1\b,Uims',$item,$match)) {
			$data['descriptif'] = trim($match[2]);
		}
		if (preg_match(',<(content)\b.*'
		.'>(.*)</\1\b,Uims',$item,$match)) {
			$data['content'] = trim($match[2]);
		}

		// lang
		if (preg_match(',<([^>]*xml:)?lang(uage)?'.'>([^<>]+)<,i',
			$item, $match))
			$data['lang'] = trim($match[3]);
		else if ($lang = trim(extraire_attribut($item, 'xml:lang')))
			$data['lang'] = $lang;
		else
			$data['lang'] = trim($langue_du_site);

		// source et url_source  (pas trouve d'exemple en ligne !!)
		# <source url="http://www.truc.net/music/uatsap.mp3" length="19917" />
		# <source url="http://www.truc.net/rss">Site source</source>
		if (preg_match(',(<source[^>]*>)(([^<>]+)</source>)?,i',
		$item, $match)) {
			$data['source'] = trim($match[3]);
			$data['url_source'] = str_replace('&amp;', '&',
				trim(extraire_attribut($match[1], 'url')));
		}

		// tags
		# a partir de "<dc:subject>", (del.icio.us)
		# ou <media:category> (flickr)
		# ou <itunes:category> (apple)
		# on cree nos tags microformat <a rel="directory" href="url">titre</a>
		# http://microformats.org/wiki/rel-directory-fr
		$tags = array();
		if (preg_match_all(
		',<(([a-z]+:)?(subject|category|directory|keywords?|tags?|type))[^>]*>'
		.'(.*?)</\1>,ims',
		$item, $matches, PREG_SET_ORDER))
			$tags = ajouter_tags($matches, $item); # array()
		elseif (preg_match_all(
		',<(([a-z]+:)?(subject|category|directory|keywords?|tags?|type))[^>]*/>'
		.',ims',
		$item, $matches, PREG_SET_ORDER))
			$tags = ajouter_tags($matches, $item); # array()
		// Pieces jointes :
		// chercher <enclosure> au format RSS et les passer en microformat
		// ou des microformats relEnclosure,
		// ou encore les media:content
		if (!afficher_enclosures(join(', ', $tags))) {
			if (preg_match_all(',<enclosure[[:space:]][^<>]+>,i',
			$item, $matches, PREG_PATTERN_ORDER))
				$data['enclosures'] = join(', ',
					array_map('enclosure2microformat', $matches[0]));
			else if (
			preg_match_all(',<link\b[^<>]+rel=["\']?enclosure["\']?[^<>]+>,i',
			$item, $matches, PREG_PATTERN_ORDER))
				$data['enclosures'] = join(', ',
					array_map('enclosure2microformat', $matches[0]));
			else if (
			preg_match_all(',<media:content\b[^<>]+>,i',
			$item, $matches, PREG_PATTERN_ORDER))
				$data['enclosures'] = join(', ',
					array_map('enclosure2microformat', $matches[0]));
		}
		$data['item'] = $item;

		// Nettoyer les donnees et remettre les CDATA en place
		cdata_echappe_retour($data, $echappe_cdata);
		cdata_echappe_retour($tags, $echappe_cdata);

		// passer l'url en absolue
		$data['url'] = url_absolue(filtrer_entites($data['url']), $url_syndic);

		// Trouver les microformats (ecrase les <category> et <dc:subject>)
		if (preg_match_all(
		',<a[[:space:]]([^>]+[[:space:]])?rel=[^>]+>.*</a>,Uims',
		$data['item'], $regs, PREG_PATTERN_ORDER)) {
			$tags = $regs[0];
		}
		// Cas particulier : tags Connotea sous la forme <a class="postedtag">
		if (preg_match_all(
		',<a[[:space:]][^>]+ class="postedtag"[^>]*>.*</a>,Uims',
		$data['item'], $regs, PREG_PATTERN_ORDER))
			$tags = preg_replace(', class="postedtag",i',
			' rel="tag"', $regs[0]);

		$data['tags'] = $tags;
		// enlever le html des titre pour etre homogene avec les autres objets spip
		$data['titre'] = textebrut($data['titre']);

		$articles[] = $data;
	}

	return $articles;
}
Ejemplo n.º 3
0
function cdata_echappe_retour(&$x, &$echappe_cdata)
{
    if (is_string($x)) {
        if (strpos($x, '@@@SPIP_CDATA') !== false or strpos($x, '&lt;') !== false) {
            $x = filtrer_entites($x);
            foreach ($echappe_cdata as $n => $e) {
                $x = str_replace("@@@SPIP_CDATA{$n}@@@", $e, $x);
            }
        }
    } else {
        if (is_array($x)) {
            foreach ($x as $k => &$v) {
                cdata_echappe_retour($v, $echappe_cdata);
            }
        }
    }
}
Ejemplo n.º 4
0
function cdata_echappe_retour(&$x, &$echappe_cdata)
{
    if (is_string($x)) {
        if (strpos($x, '&lt;') !== false) {
            $x = filtrer_entites($x);
        }
        if (strpos($x, '@@@SPIP_CDATA') !== false) {
            $x = str_replace(array_keys($echappe_cdata), array_values($echappe_cdata), $x);
        }
    } else {
        if (is_array($x)) {
            foreach ($x as $k => &$v) {
                cdata_echappe_retour($v, $echappe_cdata);
            }
        }
    }
}