source: spip-zone/_plugins_/oembed/inc/oembed.php @ 103884

Last change on this file since 103884 was 103884, checked in by cedric@…, 16 months ago

Prise en charge de mastodon que l'on oembed comme twitter :

  • il faut que l'autodetection du provider soit activee dans la configuration puisque chaque instance est un provider, on ne peut pas les whitelister
  • on est oblige de faire la detection de mastodon dans le HTML de la page source, pour unifier, sinon chaque instance a son provider_name
  • on va extraire le texte et la date dans le contenu de l'iframe pour generer un blockquote comme pour twitter, ce qui permet d'etre homogene

(l'iframe est moche, et pose plein de problemes de rendu)

On verra si c'est stable dans le temps !

File size: 13.7 KB
Line 
1<?php
2/**
3 * Plugin oEmbed
4 * Licence GPL3
5 *
6 */
7
8if (!defined('_ECRIRE_INC_VERSION')) {
9        return;
10}
11
12/**
13 * Lister les providers connus
14 * @return array
15 */
16function oembed_lister_providers() {
17
18        // liste des providers par defaut
19
20        // voir
21        // http://oembed.com/
22        // http://code.google.com/p/oohembed/source/browse/app/provider/endpoints.json
23        // https://github.com/starfishmod/jquery-oembed-all/blob/master/jquery.oembed.js
24        // https://github.com/panzi/oembedendpoints/blob/master/endpoints-simple.json
25        // voir aussi http://embed.ly/providers qui donne les scheme mais pas les endpoint
26        $providers = array(
27                'http://*.youtube.com/watch*'             => 'https://www.youtube.com/oembed',
28                'http://*.youtube.com/playlist*'          => 'https://www.youtube.com/oembed',
29                'http://youtu.be/*'                       => 'https://www.youtube.com/oembed',
30                'http://*.vimeo.com/*'                    => 'https://vimeo.com/api/oembed.json',
31                'http://vimeo.com/*'                      => 'https://vimeo.com/api/oembed.json',
32                'http://*.dailymotion.com/*'              => 'https://www.dailymotion.com/services/oembed',
33                'http://dai.ly/*'                         => 'https://www.dailymotion.com/services/oembed',
34                'http://*.flickr.com/*'                   => 'https://www.flickr.com/services/oembed/',
35                'http://flickr.com/*'                     => 'https://www.flickr.com/services/oembed/',
36                'http://flic.kr/*'                        => 'https://www.flickr.com/services/oembed/',
37                'http://soundcloud.com/*'                 => 'https://soundcloud.com/oembed',
38                'http://mixcloud.com/*'                   => 'https://mixcloud.com/oembed',
39                'http://*.soundcloud.com/*'               => 'https://soundcloud.com/oembed',
40                'http://*.mixcloud.com/*'                 => 'https://mixcloud.com/oembed',
41                'http://*.slideshare.net/*/*'             => 'https://www.slideshare.net/api/oembed/2',
42                'http://www.slideshare.net/*/*'           => 'https://www.slideshare.net/api/oembed/2',
43                'http://instagr.am/*'                     => 'https://api.instagram.com/oembed',
44                'http://*.instagr.am/*'                   => 'https://api.instagram.com/oembed',
45                'http://instagram.com/*'                  => 'https://api.instagram.com/oembed',
46                'http://*.instagram.com/*'                => 'https://api.instagram.com/oembed',
47                'http://huffduffer.com/*/*'               => 'http://huffduffer.com/oembed',
48                'http://nfb.ca/film/*'                    => 'http://www.nfb.ca/remote/services/oembed/',
49                'http://dotsub.com/view/*'                => 'http://dotsub.com/services/oembed',
50                'http://clikthrough.com/theater/video/*'  => 'http://clikthrough.com/services/oembed',
51                'http://kinomap.com/*'                    => 'http://www.kinomap.com/oembed',
52                'http://photobucket.com/albums/*'         => 'http://api.photobucket.com/oembed',
53                'http://photobucket.com/groups/*'         => 'http://api.photobucket.com/oembed',
54                'http://*.smugmug.com/*'                  => 'https://api.smugmug.com/services/oembed/',
55                'http://meetup.com/*'                     => 'https://api.meetup.com/oembed',
56                'http://meetup.ps/*'                      => 'http://api.meetup.com/oembed',
57                'http://*.wordpress.com/*'                => 'https://public-api.wordpress.com/oembed/1.0/',
58                'http://twitter.com/*/status/*'           => 'https://publish.twitter.com/oembed',
59                'http://twitter.com/*/likes'              => 'https://publish.twitter.com/oembed',
60                'http://twitter.com/*/lists/*'            => 'https://publish.twitter.com/oembed',
61                'http://twitter.com/*/timelines/*'        => 'https://publish.twitter.com/oembed',
62                'http://twitter.com/i/moments/*'          => 'https://publish.twitter.com/oembed',
63                'http://techcrunch.com/*'                 => 'http://public-api.wordpress.com/oembed/1.0/',
64                'http://wp.me/*'                          => 'http://public-api.wordpress.com/oembed/1.0/',
65                'http://my.opera.com/*'                   => 'http://my.opera.com/service/oembed',
66                'http://www.collegehumor.com/video/*'     => 'http://www.collegehumor.com/oembed.json',
67                'http://imgur.com/*'                      => 'http://api.imgur.com/oembed',
68                'http://*.imgur.com/*'                    => 'http://api.imgur.com/oembed',
69                'http://*.onf.ca/*'                       => 'http://www.onf.ca/remote/services/oembed/',
70                'http://vine.co/v/*'                      => 'https://vine.co/oembed.json',
71                'http://*.tumblr.com/post/*'              => 'https://www.tumblr.com/oembed/1.0',
72                'http://*.kickstarter.com/projects/*'     => 'https://www.kickstarter.com/services/oembed',
73                'http://speakerdeck.com/*'                => 'https://speakerdeck.com/oembed.json',
74                'http://issuu.com/*'                      => 'https://issuu.com/oembed',
75                'http://www.facebook.com/*/posts/*'       => 'https://www.facebook.com/plugins/post/oembed.json/',
76                'http://www.facebook.com/*/activity/*'    => 'https://www.facebook.com/plugins/post/oembed.json/',
77                'http://www.facebook.com/*/photos/*'      => 'https://www.facebook.com/plugins/post/oembed.json/',
78                'http://www.facebook.com/media/*'         => 'https://www.facebook.com/plugins/post/oembed.json/',
79                'http://www.facebook.com/questions/*'     => 'https://www.facebook.com/plugins/post/oembed.json/',
80                'http://www.facebook.com/notes/*'         => 'https://www.facebook.com/plugins/post/oembed.json/',
81                'http://www.facebook.com/*/videos/*'      => 'https://www.facebook.com/plugins/video/oembed.json/',
82
83                'http://egliseinfo.catholique.fr/*'       => 'http://egliseinfo.catholique.fr/api/oembed',
84
85                #'https://gist.github.com/*' => 'http://github.com/api/oembed?format=json'
86        );
87
88        // pipeline pour permettre aux plugins d'ajouter/supprimer/modifier des providers
89        $providers = pipeline('oembed_lister_providers', $providers);
90
91        // merger avec la globale pour perso mes_options dans un site
92        // pour supprimer un scheme il suffit de le renseigner avec un endpoint vide
93        if (isset($GLOBALS['oembed_providers'])) {
94                $providers = array_merge($providers, $GLOBALS['oembed_providers']);
95                // retirer les providers avec un endpoint vide
96                $providers = array_filter($providers);
97        }
98
99        return $providers;
100}
101
102// Merci WordPress :)
103// http://core.trac.wordpress.org/browser/trunk/wp-includes/class-oembed.php
104
105/**
106 * Récupérer les données oembed d'une url
107 *
108 * @param string $url url de la page qui contient le document à récupérer avec oembed
109 * @param int $maxwidth largeur max du document
110 *   null : la valeur configuree par defaut ou pour le provider est utilisee
111 *   '' : pas de valeur max
112 * @param int $maxheight hauteur max du document
113 *   null : la valeur configuree par defaut ou pour le provider est utilisee
114 *   '' : pas de valeur max
115 * @param string $format format à utiliser pour la requete oembed (json ou xml)
116 * @param string $detecter_lien tenter la détection automatique de lien oembed dans la page indiquée
117 * @return bool|array false si aucun retour ou erreur ; tableau des éléménents de la réponse oembed
118 */
119function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $format = 'json', $detecter_lien = 'non') {
120        static $cache = array();
121        $provider = false;
122
123        $provider = oembed_verifier_provider($url);
124
125        if ((!$provider)
126                and (($detecter_lien != 'non')
127                or lire_config('oembed/detecter_lien', 'non') == 'oui')) {
128                $provider = oembed_detecter_lien($url);
129        }
130
131        if (!$provider) {
132                return false;
133        }
134
135        $data_url = url_absolue($provider['endpoint'], url_de_base());
136
137        // certains oembed fournissent un endpoint qui contient deja l'URL, parfois differente de celle de la page
138        if (!parametre_url($data_url, 'url')) {
139                $data_url = parametre_url($data_url, 'url', $url, '&');
140        }
141
142        include_spip('inc/config');
143        if (!$maxwidth) {
144                $maxwidth = lire_config('oembed/maxwidth', '600');
145        }
146        if (!$maxheight) {
147                $maxheight = lire_config('oembed/maxheight', '400');
148        }
149
150        $data_url = parametre_url($data_url, 'maxwidth', $maxwidth, '&');
151        $data_url = parametre_url($data_url, 'maxheight', $maxheight, '&');
152        $data_url = parametre_url($data_url, 'format', $format, '&');
153
154        if (isset($provider['provider_name']) and $provider['provider_name']) {
155                $provider_name = $provider['provider_name'];
156        }
157        else {
158                // pre-traitement du provider si besoin
159                $provider_name = explode('//', $provider['endpoint']);
160                $provider_name = explode('/', $provider_name[1]);
161                $provider_name = reset($provider_name);
162        }
163        $provider_name = preg_replace(',\W+,', '_', strtolower($provider_name));
164
165        if ($oembed_endpoint_pretraite = charger_fonction("pretraite_$provider_name", 'oembed/input', true)) {
166                $a = func_get_args();
167                $args = array('url'=>array_shift($a));
168                if (count($a)) {
169                        $args['maxwidth'] = array_shift($a);
170                }
171                if (count($a)) {
172                        $args['maxheight'] = array_shift($a);
173                }
174                if (count($a)) {
175                        $args['format'] = array_shift($a);
176                }
177                $args['endpoint'] = $provider['endpoint'];
178                $data_url = $oembed_endpoint_pretraite($data_url, $args);
179        }
180
181        if (isset($cache[$data_url])) {
182                return $cache[$data_url];
183        }
184
185        $oembed_cache = sous_repertoire(_DIR_CACHE, 'oembed').md5($data_url). '.'.$format;
186        // si cache oembed dispo et pas de recalcul demande, l'utiliser (perf issue)
187        if (file_exists($oembed_cache) and _VAR_MODE !== 'recalcul') {
188                lire_fichier($oembed_cache, $cache[$data_url]);
189                $cache[$data_url]=unserialize($cache[$data_url]);
190                return $cache[$data_url];
191        }
192
193        $oembed_recuperer_url = charger_fonction('oembed_recuperer_url', 'inc');
194        $cache[$data_url] = $oembed_recuperer_url($data_url, $url, $format);
195
196        // si une fonction de post-traitement est fourni pour ce provider+type, l'utiliser
197        if ($cache[$data_url]) {
198                $provider_name2= str_replace(' ', '_', strtolower($cache[$data_url]['provider_name']));
199                $type = strtolower($cache[$data_url]['type']);
200                // securisons le nom de la fonction (provider peut contenir n'importe quoi)
201                $f1 = preg_replace(',\W,', '', "posttraite_{$provider_name2}_$type");
202                $f2 = preg_replace(',\W,', '', "posttraite_{$provider_name2}");
203                $f3 = preg_replace(',\W,', '', "posttraite_{$provider_name}_$type");
204                $f4 = preg_replace(',\W,', '', "posttraite_{$provider_name}");
205                if (
206                     $oembed_provider_posttraite = charger_fonction($f1, 'oembed/input', true)
207                  or $oembed_provider_posttraite = charger_fonction($f2, 'oembed/input', true)
208                  or $oembed_provider_posttraite = charger_fonction($f3, 'oembed/input', true)
209                  or $oembed_provider_posttraite = charger_fonction($f4, 'oembed/input', true) ) {
210                        $cache[$data_url] = $oembed_provider_posttraite($cache[$data_url], $url);
211                }
212
213                ecrire_fichier($oembed_cache, serialize($cache[$data_url]));
214        }
215        spip_log('infos oembed pour '.$url.' : '.var_export($cache[$data_url], true), 'oembed.'._LOG_DEBUG);
216
217        return $cache[$data_url];
218}
219
220/**
221 * Vérfier qu'une url est dans la liste des providers autorisés
222 *
223 * @param string $url l'url à tester
224 * @return bool|array
225 *   false si non ; details du provider dans un tabeau associatif si oui
226 */
227function oembed_verifier_provider($url) {
228        if (strncmp($url, $GLOBALS['meta']['adresse_site'], strlen($GLOBALS['meta']['adresse_site'])) == 0) {
229                return false;
230        }
231        $providers = oembed_lister_providers();
232        foreach ($providers as $scheme => $endpoint) {
233                $regex = '#' . str_replace('\*', '(.+)', preg_quote($scheme, '#')) . '#';
234                $regex = preg_replace('|^#http\\\://|', '#https?\://', $regex);
235                if (preg_match($regex, $url)) {
236                        return array('endpoint' => $endpoint);
237                }
238        }
239        return false;
240}
241
242/**
243 * Détecter les liens oembed dans le head d'une page web
244 *
245 * @param string $url url de la page à analyser
246 * @return bool|string false si pas de lien ; url du contenu oembed
247 */
248function oembed_detecter_lien($url) {
249        $providers = array();
250
251        $oembed_recuperer_url = charger_fonction('oembed_recuperer_url', 'inc');
252        // on recupere le contenu de la page
253        include_spip('inc/distant');
254
255        if ($html = recuperer_page($url)) {
256                // types de liens oembed à détecter
257                $linktypes = array(
258                        'application/json+oembed' => 'json',
259                        'text/json+oembed' => 'json', // ex de 500px
260                        'text/xml+oembed' => 'xml',
261                        'application/xml+oembed' => 'xml', // uniquement pour Vimeo
262                );
263
264                // on ne garde que le head de la page
265                $head = substr($html, 0, stripos($html, '</head>'));
266
267                // un test rapide...
268                $tagfound = false;
269                foreach ($linktypes as $linktype => $format) {
270                        if (stripos($head, $linktype)) {
271                                $tagfound = true;
272                                break;
273                        }
274                }
275
276                if ($tagfound && preg_match_all('/<link([^<>]+)>/i', $head, $links)) {
277                        foreach ($links[0] as $link) {
278                                $type = extraire_attribut($link, 'type');
279                                $href = extraire_attribut($link, 'href');
280                                if (!empty($type) and !empty($linktypes[$type]) and !empty($href)) {
281                                        $providers[$linktypes[$type]] = $href;
282                                        // on a le json, ça nous suffit
283                                        if ('json' == $linktypes[$type]) {
284                                                break;
285                                        }
286                                }
287                        }
288                }
289        }
290
291        $res = array();
292
293        // on préfère le json au xml
294        if (!empty($providers['json'])) {
295                $res['endpoint'] = $providers['json'];
296        } elseif (!empty($providers['xml'])) {
297                $res['endpoint'] = $providers['xml'];
298        } else {
299                return false;
300        }
301
302        // detecter certains providers specifiques : ex mastodon, chaque instance a son nom et on peut pas l'identifier par son URL
303        if (strpos($html, '//github.com/tootsuite/mastodon') !== false) {
304                $res['provider_name'] = 'Mastodon';
305        }
306
307        return $res;
308}
309
310
311/**
312 * Embarquer un lien oembed si possible
313 * @param string $lien
314 * @return string
315 */
316function oembed_embarquer_lien($lien) {
317        static $base = null;
318
319        $url = extraire_attribut($lien, 'href');
320        $texte = null;
321        if ($url
322                and (
323                        oembed_verifier_provider($url)
324                        or (lire_config('oembed/detecter_lien', 'non') == 'oui'))
325                ) {
326                if (is_null($base)) {
327                        $base = url_de_base();
328                }
329                // on embarque jamais un lien de soi meme car c'est une mise en abime qui donne le tourni
330                // (et peut provoquer une boucle infinie de requetes http)
331                if (strncmp($url, $base, strlen($base)) != 0) {
332                        $fond = recuperer_fond('modeles/oembed', array('url' => $url, 'lien' => $lien));
333                        if ($fond = trim($fond)) {
334                                $texte = $fond;
335                        }
336                }
337        }
338
339        return $texte;
340}
Note: See TracBrowser for help on using the repository browser.