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

Last change on this file since 103149 was 103149, checked in by brunobergot@…, 20 months ago

prise en charge des likes, lists, timelines & moments de twitter

File size: 12.6 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 = parametre_url(url_absolue($provider['endpoint'], url_de_base()), 'url', $url, '&');
136        include_spip('inc/config');
137        if (!$maxwidth) {
138                $maxwidth = lire_config('oembed/maxwidth', '600');
139        }
140        if (!$maxheight) {
141                $maxheight = lire_config('oembed/maxheight', '400');
142        }
143
144        $data_url = parametre_url($data_url, 'maxwidth', $maxwidth, '&');
145        $data_url = parametre_url($data_url, 'maxheight', $maxheight, '&');
146        $data_url = parametre_url($data_url, 'format', $format, '&');
147
148        // pre-traitement du provider si besoin
149        $endpoint = explode('//', $provider['endpoint']);
150        $endpoint = explode('/', $endpoint[1]);
151        $endpoint = reset($endpoint);
152        $endpoint = preg_replace(',\W+,', '_', $endpoint);
153        if ($oembed_endpoint_pretraite = charger_fonction("pretraite_$endpoint", 'oembed/input', true)) {
154                $a = func_get_args();
155                $args = array('url'=>array_shift($a));
156                if (count($a)) {
157                        $args['maxwidth'] = array_shift($a);
158                }
159                if (count($a)) {
160                        $args['maxheight'] = array_shift($a);
161                }
162                if (count($a)) {
163                        $args['format'] = array_shift($a);
164                }
165                $data_url = $oembed_endpoint_pretraite($data_url, $args);
166        }
167
168        if (isset($cache[$data_url])) {
169                return $cache[$data_url];
170        }
171
172        $oembed_cache = sous_repertoire(_DIR_CACHE, 'oembed').md5($data_url). '.'.$format;
173        // si cache oembed dispo et pas de recalcul demande, l'utiliser (perf issue)
174        if (file_exists($oembed_cache) and _VAR_MODE !== 'recalcul') {
175                lire_fichier($oembed_cache, $cache[$data_url]);
176                $cache[$data_url]=unserialize($cache[$data_url]);
177                return $cache[$data_url];
178        }
179
180        $oembed_recuperer_url = charger_fonction('oembed_recuperer_url', 'inc');
181        $cache[$data_url] = $oembed_recuperer_url($data_url, $url, $format);
182
183        // si une fonction de post-traitement est fourni pour ce provider+type, l'utiliser
184        if ($cache[$data_url]) {
185                $provider_name= str_replace(' ', '_', strtolower($cache[$data_url]['provider_name']));
186                $type = strtolower($cache[$data_url]['type']);
187                // securisons le nom de la fonction (provider peut contenir n'importe quoi)
188                $f1 = preg_replace(',\W,', '', "posttraite_{$provider_name}_$type");
189                $f2 = preg_replace(',\W,', '', "posttraite_{$provider_name}");
190                if ($oembed_provider_posttraite = charger_fonction($f1, 'oembed/input', true)
191                        or $oembed_provider_posttraite = charger_fonction($f2, 'oembed/input', true)) {
192                        $cache[$data_url] = $oembed_provider_posttraite($cache[$data_url], $url);
193                }
194
195                ecrire_fichier($oembed_cache, serialize($cache[$data_url]));
196        }
197        spip_log('infos oembed pour '.$url.' : '.var_export($cache[$data_url], true), 'oembed.'._LOG_DEBUG);
198
199        return $cache[$data_url];
200}
201
202/**
203 * Vérfier qu'une url est dans la liste des providers autorisés
204 *
205 * @param string $url l'url à tester
206 * @return bool|array
207 *   false si non ; details du provider dans un tabeau associatif si oui
208 */
209function oembed_verifier_provider($url) {
210        if (strncmp($url, $GLOBALS['meta']['adresse_site'], strlen($GLOBALS['meta']['adresse_site'])) == 0) {
211                return false;
212        }
213        $providers = oembed_lister_providers();
214        foreach ($providers as $scheme => $endpoint) {
215                $regex = '#' . str_replace('\*', '(.+)', preg_quote($scheme, '#')) . '#';
216                $regex = preg_replace('|^#http\\\://|', '#https?\://', $regex);
217                if (preg_match($regex, $url)) {
218                        return array('endpoint' => $endpoint);
219                }
220        }
221        return false;
222}
223
224/**
225 * Détecter les liens oembed dans le head d'une page web
226 *
227 * @param string $url url de la page à analyser
228 * @return bool|string false si pas de lien ; url du contenu oembed
229 */
230function oembed_detecter_lien($url) {
231        $providers = array();
232
233        // on recupere le contenu de la page
234        include_spip('inc/distant');
235        if ($html = recuperer_page($url)) {
236                // types de liens oembed à détecter
237                $linktypes = array(
238                        'application/json+oembed' => 'json',
239                        'text/json+oembed' => 'json', // ex de 500px
240                        'text/xml+oembed' => 'xml',
241                        'application/xml+oembed' => 'xml', // uniquement pour Vimeo
242                );
243
244                // on ne garde que le head de la page
245                $head = substr($html, 0, stripos($html, '</head>'));
246
247                // un test rapide...
248                $tagfound = false;
249                foreach ($linktypes as $linktype => $format) {
250                        if (stripos($head, $linktype)) {
251                                $tagfound = true;
252                                break;
253                        }
254                }
255
256                if ($tagfound && preg_match_all('/<link([^<>]+)>/i', $head, $links)) {
257                        foreach ($links[0] as $link) {
258                                $type = extraire_attribut($link, 'type');
259                                $href = extraire_attribut($link, 'href');
260                                if (!empty($type) and !empty($linktypes[$type]) and !empty($href)) {
261                                        $providers[$linktypes[$type]] = $href;
262                                        // on a le json, ça nous suffit
263                                        if ('json' == $linktypes[$type]) {
264                                                break;
265                                        }
266                                }
267                        }
268                }
269        }
270
271        // on préfère le json au xml
272        if (!empty($providers['json'])) {
273                return array('endpoint'=>$providers['json']);
274        } elseif (!empty($providers['xml'])) {
275                return array('endpoint' => $providers['xml']);
276        } else {
277                return false;
278        }
279}
280
281
282/**
283 * Embarquer un lien oembed si possible
284 * @param string $lien
285 * @return string
286 */
287function oembed_embarquer_lien($lien) {
288        static $base = null;
289
290        $url = extraire_attribut($lien, 'href');
291        $texte = null;
292        if ($url
293                and (
294                        oembed_verifier_provider($url)
295                        or (lire_config('oembed/detecter_lien', 'non') == 'oui'))
296                ) {
297                if (is_null($base)) {
298                        $base = url_de_base();
299                }
300                // on embarque jamais un lien de soi meme car c'est une mise en abime qui donne le tourni
301                // (et peut provoquer une boucle infinie de requetes http)
302                if (strncmp($url, $base, strlen($base)) != 0) {
303                        $fond = recuperer_fond('modeles/oembed', array('url' => $url, 'lien' => $lien));
304                        if ($fond = trim($fond)) {
305                                $texte = $fond;
306                        }
307                }
308        }
309
310        return $texte;
311}
Note: See TracBrowser for help on using the repository browser.