@ -1,12 +1,11 @@
<?php
/**
* Plugin oEmbed
* Licence GPL3
*
*/
if (!defined('_ECRIRE_INC_VERSION')) {
if (!defined('_ECRIRE_INC_VERSION')){
return;
}
@ -14,7 +13,7 @@ if (!defined('_ECRIRE_INC_VERSION')) {
* Lister les providers connus
* @return array
*/
function oembed_lister_providers($avec_provider_interdits = false ) {
function oembed_lister_providers(){
// liste des providers par defaut
@ -24,7 +23,7 @@ function oembed_lister_providers($avec_provider_interdits = false) {
// https://github.com/starfishmod/jquery-oembed-all/blob/master/jquery.oembed.js
// https://github.com/panzi/oembedendpoints/blob/master/endpoints-simple.json
// voir aussi http://embed.ly/providers qui donne les scheme mais pas les endpoint
$providers = [
$providers = array(
'http://*.youtube.com/watch*' => 'https://www.youtube.com/oembed',
'http://*.youtube.com/playlist*' => 'https://www.youtube.com/oembed',
'http://youtu.be/*' => 'https://www.youtube.com/oembed',
@ -41,6 +40,10 @@ function oembed_lister_providers($avec_provider_interdits = false) {
'http://*.mixcloud.com/*' => 'https://mixcloud.com/oembed',
'http://*.slideshare.net/*/*' => 'https://www.slideshare.net/api/oembed/2',
'http://www.slideshare.net/*/*' => 'https://www.slideshare.net/api/oembed/2',
'http://instagr.am/*' => 'https://api.instagram.com/oembed',
'http://*.instagr.am/*' => 'https://api.instagram.com/oembed',
'http://instagram.com/*' => 'https://api.instagram.com/oembed',
'http://*.instagram.com/*' => 'https://api.instagram.com/oembed',
'http://huffduffer.com/*/*' => 'http://huffduffer.com/oembed',
'http://nfb.ca/film/*' => 'http://www.nfb.ca/remote/services/oembed/',
'http://dotsub.com/view/*' => 'http://dotsub.com/services/oembed',
@ -71,66 +74,34 @@ function oembed_lister_providers($avec_provider_interdits = false) {
'http://issuu.com/*/docs/*' => 'https://issuu.com/oembed',
'http://*.calameo.com/books/*' => 'https://www.calameo.com/services/oembed',
'http://*.calameo.com/read/*' => 'https://www.calameo.com/services/oembed',
'http://www.facebook.com/*/posts/*' => 'https://www.facebook.com/plugins/post/oembed.json/',
'http://www.facebook.com/*/activity/*' => 'https://www.facebook.com/plugins/post/oembed.json/',
'http://www.facebook.com/*/photos/*' => 'https://www.facebook.com/plugins/post/oembed.json/',
'http://www.facebook.com/media/*' => 'https://www.facebook.com/plugins/post/oembed.json/',
'http://www.facebook.com/questions/*' => 'https://www.facebook.com/plugins/post/oembed.json/',
'http://www.facebook.com/notes/*' => 'https://www.facebook.com/plugins/post/oembed.json/',
'http://www.facebook.com/*/videos/*' => 'https://www.facebook.com/plugins/video/oembed.json/',
'http://*.arte.tv/*/videos/*' => 'https://api.arte.tv/api/player/v1/oembed/',
'http://egliseinfo.catholique.fr/*' => 'http://egliseinfo.catholique.fr/api/oembed',
#'https://gist.github.com/*' => 'http://github.com/api/oembed?format=json'
];
) ;
// pipeline pour permettre aux plugins d'ajouter/supprimer/modifier des providers
$providers = pipeline('oembed_lister_providers', $providers);
// merger avec la globale pour perso mes_options dans un site
// pour supprimer un scheme il suffit de le renseigner avec un endpoint vide
if (isset($GLOBALS['oembed_providers'])) {
if (isset($GLOBALS['oembed_providers'])){
$providers = array_merge($providers, $GLOBALS['oembed_providers']);
}
if (!$avec_provider_interdits) {
// retirer les providers avec un endpoint vide
$providers = array_filter($providers);
}
return $providers;
}
/**
* @param string $url
* @param bool|null $detecter_lien
* false : bloque la detection des liens quelle que soit la config du plugin
* true : force la detection des liens quelle que soit la config du plugin
* null : utilise la config du plugin
* @return array|null
*/
function oembed_provider_from_url($url, bool $detecter_lien = null) {
static $providers = [];
if (!isset($providers[$detecter_lien])) {
$providers[$detecter_lien] = [];
}
if (isset($providers[$detecter_lien][$url])) {
return $providers[$detecter_lien][$url];
}
include_spip('inc/config');
$provider = oembed_verifier_provider($url);
// inconnu ?
if (!$provider and $detecter_lien !== false) {
if ($detecter_lien or lire_config('oembed/detecter_lien', 'non') == 'oui') {
$provider = oembed_detecter_lien($url);
}
}
// inconnu ou interdit ?
if (!$provider or empty($provider['endpoint'])) {
return $providers[$detecter_lien][$url] = null;
}
return $providers[$detecter_lien][$url] = $provider;
}
// Merci WordPress :)
// http://core.trac.wordpress.org/browser/trunk/wp-includes/class-oembed.php
@ -145,40 +116,36 @@ function oembed_provider_from_url($url, bool $detecter_lien = null) {
* null : la valeur configuree par defaut ou pour le provider est utilisee
* '' : pas de valeur max
* @param string $format format à utiliser pour la requete oembed (json ou xml)
* @param bool|null $detecter_lien tenter la détection automatique de lien oembed dans la page indiquée
* false : bloque la detection des liens quelle que soit la config du plugin
* true : force la detection des liens quelle que soit la config du plugin
* null : utilise la config du plugin
* @param string $detecter_lien tenter la détection automatique de lien oembed dans la page indiquée
* @param bool $force_reload forcer le rechargement de l'oembed depuis la source sans utiliser le cache local
* @return bool|array false si aucun retour ou erreur ; tableau des éléménents de la réponse oembed
*/
function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $format = 'json', $detecter_lien = null, $force_reload = false) {
static $cache = [];
function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $format = 'json', $detecter_lien = 'non', $force_reload = false){
static $cache = array();
$provider = false;
include_spip('inc/config');
// compatibilite avec l'ancienne signature de la fonction : non equivalait a 'auto' (c'est a dire on applique la config du plugin)
if ($detecter_lien === 'non') {
$detecter_lien = null;
}
elseif ($detecter_lien) {
$detecter_lien = true;
$provider = oembed_verifier_provider($url);
if ((!$provider)
and (($detecter_lien!='non')
or lire_config('oembed/detecter_lien', 'non')=='oui')){
$provider = oembed_detecter_lien($url);
}
$provider = oembed_provider_from_url($url, $detecter_lien);
// inconnu ou interdit ?
if (!$provider) {
if (!$provider){
return false;
}
$data_url = url_absolue($provider['endpoint'], url_de_base());
// certains oembed fournissent un endpoint qui contient deja l'URL, parfois differente de celle de la page
if (!parametre_url($data_url, 'url')) {
if (!parametre_url($data_url, 'url')){
$data_url = parametre_url($data_url, 'url', $url, '&');
}
if (!$maxwidth) {
if (!$maxwidth){
$maxwidth = lire_config('oembed/maxwidth', '600');
}
if (!$maxheight) {
if (!$maxheight){
$maxheight = lire_config('oembed/maxheight', '400');
}
@ -186,7 +153,7 @@ function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $forma
$data_url = parametre_url($data_url, 'maxheight', $maxheight, '&');
$data_url = parametre_url($data_url, 'format', $format, '&');
if (isset($provider['provider_name']) and $provider['provider_name']) {
if (isset($provider['provider_name']) and $provider['provider_name']){
$provider_name = $provider['provider_name'];
} else {
// pre-traitement du provider si besoin
@ -195,29 +162,29 @@ function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $forma
$provider_name = reset($provider_name);
}
$provider_name = preg_replace(',\W+,', '_', strtolower($provider_name));
if ($oembed_endpoint_pretraite = charger_fonction("pretraite_$provider_name", 'oembed/input', true)) {
if ($oembed_endpoint_pretraite = charger_fonction("pretraite_$provider_name", 'oembed/input', true)){
$a = func_get_args();
$args = ['url' => array_shift($a)] ;
if (count($a)) {
$args = array('url' => array_shift($a)) ;
if (count($a)){
$args['maxwidth'] = array_shift($a);
}
if (count($a)) {
if (count($a)){
$args['maxheight'] = array_shift($a);
}
if (count($a)) {
if (count($a)){
$args['format'] = array_shift($a);
}
$args['endpoint'] = $provider['endpoint'];
$data_url = $oembed_endpoint_pretraite($data_url, $args);
}
if (isset($cache[$data_url])) {
if (isset($cache[$data_url])){
return $cache[$data_url];
}
$oembed_cache = sous_repertoire(_DIR_CACHE, 'oembed') . md5($data_url) . '.' . $format;
// si cache oembed dispo et pas de recalcul demande, l'utiliser (perf issue)
if (!$force_reload and file_exists($oembed_cache) and _VAR_MODE !== 'recalcul') {
if (!$force_reload and file_exists($oembed_cache) and _VAR_MODE!=='recalcul'){
lire_fichier($oembed_cache, $cache[$data_url]);
$cache[$data_url] = unserialize($cache[$data_url]);
return $cache[$data_url];
@ -226,12 +193,8 @@ function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $forma
$oembed_recuperer_url = charger_fonction('oembed_recuperer_url', 'inc');
$cache[$data_url] = $oembed_recuperer_url($data_url, $url, $format);
// si une fonction de post-traitement est fourni pour ce provider+type, l'utiliser
if ($cache[$data_url]) {
if (isset($cache[$data_url]['provider_name']) and $cache[$data_url]['provider_name']) {
$provider_name2 = str_replace(' ', '_', strtolower($cache[$data_url]['provider_name']));
} else {
$provider_name2 = '';
}
if ($cache[$data_url]){
$provider_name2 = str_replace(' ', '_', strtolower($cache[$data_url]['provider_name']));
$type = strtolower($cache[$data_url]['type']);
// securisons le nom de la fonction (provider peut contenir n'importe quoi)
$f1 = preg_replace(',\W,', '', "posttraite_{$provider_name2}_$type");
@ -242,8 +205,7 @@ function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $forma
$oembed_provider_posttraite = charger_fonction($f1, 'oembed/input', true)
or $oembed_provider_posttraite = charger_fonction($f2, 'oembed/input', true)
or $oembed_provider_posttraite = charger_fonction($f3, 'oembed/input', true)
or $oembed_provider_posttraite = charger_fonction($f4, 'oembed/input', true)
) {
or $oembed_provider_posttraite = charger_fonction($f4, 'oembed/input', true)){
$cache[$data_url] = $oembed_provider_posttraite($cache[$data_url], $url);
}
ecrire_fichier($oembed_cache, serialize($cache[$data_url]));
@ -258,25 +220,18 @@ function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $forma
*
* @param string $url l'url à tester
* @return bool|array
* false si l'url n'est pas dans la liste (provider inconnu) ; details du
* provider dans un tabeau associatif si oui (avec un endpoint vide si
* le provider est explicitement interdit)
* false si non ; details du provider dans un tabeau associatif si oui
*/
function oembed_verifier_provider($url) {
static $base = null;
if (is_null($base)) {
$base = url_de_base();
}
if (strpos($url, (string) $GLOBALS['meta']['adresse_site']) === 0 or strpos($url, (string) $base) === 0) {
return ['endpoint' => ''];
function oembed_verifier_provider($url){
if (strncmp($url, $GLOBALS['meta']['adresse_site'], strlen($GLOBALS['meta']['adresse_site']))==0){
return false;
}
$providers = oembed_lister_providers(true);
foreach ($providers as $scheme => $endpoint) {
$providers = oembed_lister_providers();
foreach ($providers as $scheme => $endpoint){
$regex = '#' . str_replace('\*', '(.+)', preg_quote($scheme, '#')) . '#';
$regex = preg_replace('|^#http\\\://|', '#https?\://', $regex);
if (preg_match($regex, $url)) {
return ['endpoint' => $endpoint] ;
if (preg_match($regex, $url)){
return array('endpoint' => $endpoint) ;
}
}
return false;
@ -286,66 +241,45 @@ function oembed_verifier_provider($url) {
* Détecter les liens oembed dans le head d'une page web
*
* @param string $url url de la page à analyser
* @return bool|array false si pas de lien ; description du provider oembed associe au lien
* @return bool|string false si pas de lien ; url du contenu oembed
*/
function oembed_detecter_lien($url) {
$providers = [];
// s'assurer que l'URL n'est pas une url direct vers un media mais ressemble bien à l'URL d'une page HTML
// pour eviter de faire des
$parts = parse_url($url);
// si on trouve une extension, verifier que c'est html ou htm, le reste ne nous interesse pas
if (!empty($parts['path'])) {
if (preg_match(',\.(\w+)$,', $parts['path'], $m)) {
if (!in_array(strtolower($m[1]), ['html', 'htm'])) {
spip_log("oembed_detecter_lien $url : on ignore l'extension " . $m[1], 'oembed' . _LOG_DEBUG);
return false;
}
}
}
function oembed_detecter_lien($url){
$providers = array();
$oembed_recuperer_url = charger_fonction('oembed_recuperer_url', 'inc');
// on recupere le contenu de la page
// on utilise recuperer_url_cache() avec un cache 24h pour ne pas passer son temps à faire de la detection sur les memes liens
include_spip('inc/distant');
$options = [
'delai_cache' => in_array(_VAR_MODE, ['preview', 'recalcul']) ? 0 : 24 * 3600,
'taille_max' => min(_INC_DISTANT_MAX_SIZE, 256000),
];
$res = recuperer_url_cache($url, $options);
$html = '';
if ($res and intval($res['status'] / 100) < 4 and ! empty ( $ res [ ' page ' ] ) ) {
$html = $res['page'];
if ($html = $oembed_recuperer_url($url, $url, 'html')){
// types de liens oembed à détecter
$linktypes = [
$linktypes = array(
'application/json+oembed' => 'json',
'text/json+oembed' => 'json', // ex de 500px
'text/xml+oembed' => 'xml',
'application/xml+oembed' => 'xml', // uniquement pour Vimeo
] ;
);
// on ne garde que le head de la page
$head = substr($html, 0, stripos($html, '< / head > '));
// un test rapide...
$tagfound = false;
foreach ($linktypes as $linktype => $format) {
if (stripos($head, $linktype)) {
foreach ($linktypes as $linktype => $format){
if (stripos($head, $linktype)){
$tagfound = true;
break;
}
}
if ($tagfound & & preg_match_all('/< link ( [ ^ < > ]+)>/i', $head, $links)) {
if (!function_exists('extraire_attribut')) {
if ($tagfound & & preg_match_all('/< link ( [ ^ < > ]+)>/i', $head, $links)){
if (!function_exists('extraire_attribut')){
include_spip('inc/filtres');
}
foreach ($links[0] as $link) {
foreach ($links[0] as $link){
$type = extraire_attribut($link, 'type');
$href = extraire_attribut($link, 'href');
if (!empty($type) and !empty($linktypes[$type]) and !empty($href)) {
if (!empty($type) and !empty($linktypes[$type]) and !empty($href)){
$providers[$linktypes[$type]] = $href;
// on a le json, ça nous suffit
if ('json' == $linktypes[$type]) {
if ('json'==$linktypes[$type]){
break;
}
}
@ -353,10 +287,10 @@ function oembed_detecter_lien($url) {
}
}
$res = [] ;
$res = array() ;
// on préfère le json au xml
if (!empty($providers['json'])) {
if (!empty($providers['json'])){
$res['endpoint'] = $providers['json'];
} elseif (!empty($providers['xml'])) {
$res['endpoint'] = $providers['xml'];
@ -365,7 +299,7 @@ function oembed_detecter_lien($url) {
}
// detecter certains providers specifiques : ex mastodon, chaque instance a son nom et on peut pas l'identifier par son URL
if (strpos($html, '//github.com/tootsuite/mastodon') !== false or strpos($html, '//joinmastodon.org') !== false) {
if (strpos($html, '//github.com/tootsuite/mastodon')!==false or strpos($html, '//joinmastodon.org')!==false){
$res['provider_name'] = 'Mastodon';
}
@ -378,14 +312,26 @@ function oembed_detecter_lien($url) {
* @param string $lien
* @return string
*/
function oembed_embarquer_lien($lien) {
function oembed_embarquer_lien($lien){
static $base = null;
$url = extraire_attribut($lien, 'href');
$texte = null;
if ($url and oembed_provider_from_url($url)) {
$fond = recuperer_fond('modeles/oembed', ['url' => $url, 'lien' => $lien]);
if ($fond = trim($fond)) {
$texte = $fond;
if ($url
and (
oembed_verifier_provider($url)
or (lire_config('oembed/detecter_lien', 'non')=='oui'))
){
if (is_null($base)){
$base = url_de_base();
}
// on embarque jamais un lien de soi meme car c'est une mise en abime qui donne le tourni
// (et peut provoquer une boucle infinie de requetes http)
if (strncmp($url, $base, strlen($base))!=0){
$fond = recuperer_fond('modeles/oembed', array('url' => $url, 'lien' => $lien));
if ($fond = trim($fond)){
$texte = $fond;
}
}
}