Compare commits

...

61 Commits

Author SHA1 Message Date
b_b e3c12bd182 fix: utliser un try/catch sur `json_decode()` quand on utilise `JSON_THROW_ON_ERROR` 2 months ago
touti a60dafa124 eviter une erreur sur la constante _DEFINIR_CONTEXTE_TYPE_PAGE si déjà definie 3 months ago
Cerdic ae123e8f6f Suppression .gitattributes 5 months ago
Cerdic a45db28d3a fix: Rétablir le passage de propre sur les credirs, malgré le plugin medias de SPIP 4.1 5 months ago
b_b d039350d95 chore: une passe de rector UP_TO_PHP_73 5 months ago
Maïeul 0ab594c1b6 Fix #18 8 months ago
Cerdic eaed6c5f0a Eviter des warning quand la reponse oembed n'est pas complète 9 months ago
b_b 678dae8b50 pétouilles de coding standards 9 months ago
b_b c514abfd20 ignorer le répertoire de spip-cli 9 months ago
b_b ea72ff32b7 phpstan : fix Variable xxx might not be defined 9 months ago
b_b f38750bea6 phpstan level 1 + ajout d'un fichier bootstrap pour y définir les constantes du core utilisées dans le plugin 9 months ago
b_b 8af85f5cf8 baseline phpstan au propre 9 months ago
b_b 5c677a7372 Fix Function assocToXML not found 9 months ago
b_b e2315f4742 conf phpstan de base : level 0 + exclure uniquement les fichiers de langue 9 months ago
b_b 3dcbd31367 oups 9 months ago
b_b 837efde315 phpstan : éviter une erreur Undefined variable '$res' 9 months ago
cy_altern f9bc3e5f52 micro modification pour que les liens vers l'auteur de la vidéo soient compatibles avec la syntaxe des regexp dérivées de |liens_ouvrant (= href puis class) 10 months ago
b_b 8d5fc9eeaf retrait de code commenté 11 months ago
Cerdic 73307d3ee5 Adopter la meme structure de markup que les documents SPIP 4 avec un div.spip_documents qui contient un figure.spip_doc_inner ce qui devrait resoudre #15 11 months ago
Cerdic 7b919ab163 Passage en test 11 months ago
Cerdic 05c7d98989 Je ne sais pas si ça durera, mais voila le retour d'une jolie presentation pour les oembed twitter 11 months ago
Cerdic 7b8e28e362 Petites corrections visuelles sur les oembed toot 11 months ago
Cerdic b335358908 Quand on veut verifier le provider sur une URL, s'assurer que c'est bien une URL vers du html : si elle a une extension on n'accepte que html ou html, sinon on se retrouve a recuperer des medias distants pour rien 11 months ago
Cerdic be1bae166c Code mort sur mastodon : on essaye plus de recuperer le .atom qui n'existe plus en principe 11 months ago
Cerdic 74194bb778 Retour sur 9146311a : on utilise recuperer_url_cache() pour detecter les serveurs oembed non declares plutot que oembed_recuperer_url() qui avait été choisie pour contourner un bug SSL sur certains serveurs mastodon 11 months ago
Cerdic 4f67c37a17 PSR 11 months ago
Cerdic 8bfc813af7 Tripaille composer 11 months ago
Cerdic df9b5be7a1 Suppression .gitattributes 11 months ago
Cerdic 6f75e06056 Un peu de nettoyage de code 11 months ago
Cerdic 0c029326ea Fix #14 : suppression fichier inutile 11 months ago
Cerdic eaec667f46 Fix les modeles doc/img sur les documents oembed : on remplace modeles_styliser de medias par notre fonction oembed_medias_modeles_styliser qui force un rendu <emb> pour tous les documents oembed en base 11 months ago
Glop 2ea144eb25 Utiliser aussi `oembed_provider_from_url()` dans le filtre `|oembed` pour prendre en compte les providers interdit ainsi que la configuration de la detection de liens si elle est activee 11 months ago
Cerdic f48b114cb7 Une fonction oembed_provider_from_url() qui prend en compte la liste declarative + la detection eventuelle, que l'on peut reutiliser dans oembed_embarquer_lien() pour eviter de calculer un modele pour rien 11 months ago
Glop 2f7eb65f62 Test désormais inutile dans oembed_embarquer_lien() 11 months ago
Cerdic 43180a6ac5 on eviter de changer le comportement par defaut de la fonction oembed_lister_providers() en lui ajoutant un parametre pour avoir la liste complete avec les providers interdits 11 months ago
Glop cdc6ad45cd Pouvoir interdire explicitement certains providers 11 months ago
Cerdic c8fcf920dd Fix #13 : sur les document oembed, utiliser le modele legend si possible, tout en gardant un lien vers le document d'origine 11 months ago
Cerdic 964adea37d Icone SVG pour soundcloud aussi 11 months ago
Cerdic f9a4608dd6 Utiliser les icones svg 11 months ago
Cerdic 66dadb47a3 Une branche oembed compat 4.0+ pour gerer plus finement les documents sans risquer de casser le rendu avec les anciennes versions 11 months ago
b_b 9c1cadebdc suivre spip-cli 11 months ago
Alberto 408725f34f [Salvatore] [source:lang/ paquet-oembed] Export depuis https://trad.spip.net de la langue it 1 year ago
Alberto bffa6ad934 [Salvatore] [source:lang/ oembed] Export depuis https://trad.spip.net de la langue it 1 year ago
b_b 79466da936 version 2.4.0 1 year ago
b_b de15316583 retrait de code spécifique à fb & instatruc 1 year ago
b_b cd0cbeac20 RIP FB & Instatruc 1 year ago
Cerdic 09065b7d40 Garder la trace de la copie locale du document oembed qu'on renseigne le cas echeant 1 year ago
Cerdic a97a96ced9 Class spip_doc_legende conventionnelle SPIP 4 manquante sur figcaption 1 year ago
Cerdic 0e556b4bbb Ce modele englobant n'avait pas ete passe en <figure> et provoquait donc un markup bancal(realet) 1 year ago
Yohooo d954558461 Prise en compte de la variable async pour les player video 2 years ago
Cerdic 5a8d01c0d3 Fix #5 : recuperer des vignettes vimeo en resolution adaptee au site au lieu de la resolution faible par defaut 2 years ago
Cerdic b77308ae05 C'etait bien tente, mais le DEFAULT@SECLEVEL=1 provoque une erreur 59 sur certains systems 2 years ago
Cerdic 73ec37226c Ameliorer la requete curl vers les serveurs qui generent potentiellement une erreur SSL en etant plus tolerant sur le cipher 2 years ago
Cerdic 009ca9958f Compat SPIP 4 2 years ago
b_b 580206085a éviter un warning "Trying to access array offset on value of type null" lors de la suppression d'un document 2 years ago
erational 19a8acbe88 [ui] couleur charte 2 years ago
Matthieu Marcillaud e8d9915253 Null plutôt si pas de page. Parait plus logique. 2 years ago
Eric Lupinacci 20d5d8bc35 Remplacer recuperer_page par recuperer_url mais gestion de spip 3.0 qui ne possède pas la nouvelle fonction... 2 years ago
b_b def4018544 warning en mois 2 years ago
b_b dd2ad42621 versin 2.3.4 : vie privée, ajout de l'option DNT aux embeds vimeo 2 years ago
Matthieu Marcillaud 25013e7006 Étrangement, il semble qu'une erreur s'est glissée dès a514f1d7e6 qui tente d'insérer du texte dans la clé 'data' qui est un tableau. 2 years ago
  1. 66
      .gitattributes
  2. 10
      .gitignore
  3. 40
      action/api_oembed.php
  4. 101
      action/oembed_nettoyer_iframes.php
  5. 20
      composer.json
  6. 6
      css/oembed.css
  7. 28
      formulaires/configurer_oembed.html
  8. 222
      inc/oembed.php
  9. 59
      inc/oembed_recuperer_url.php
  10. 24
      inc/ressource.php
  11. 3
      lang/oembed.xml
  12. 49
      lang/oembed_it.php
  13. 3
      lang/paquet-oembed.xml
  14. 15
      lang/paquet-oembed_it.php
  15. 8
      modeles/oembed.html
  16. 1
      modeles/oembed_fonctions.php
  17. 4
      modeles/oembed_link.html
  18. 6
      modeles/oembed_photo.html
  19. 6
      modeles/oembed_rich.html
  20. 8
      modeles/oembed_video.html
  21. 35
      modeles/text_oembed.html
  22. 4
      modeles/toot.html
  23. 9
      oembed/input/posttraite_api_arte_tv.php
  24. 41
      oembed/input/posttraite_facebook_video.php
  25. 1
      oembed/input/posttraite_huffduffer_rich.php
  26. 27
      oembed/input/posttraite_instagram_rich.php
  27. 1
      oembed/input/posttraite_issuu.php
  28. 44
      oembed/input/posttraite_mastodon.php
  29. 1
      oembed/input/posttraite_oeproxy_default_rich.php
  30. 1
      oembed/input/posttraite_oeproxy_imdb_rich.php
  31. 1
      oembed/input/posttraite_office_national_du_film_du_canada_video.php
  32. 1
      oembed/input/posttraite_rdio_rich.php
  33. 1
      oembed/input/posttraite_slideshare_rich.php
  34. 3
      oembed/input/posttraite_soundcloud_rich.php
  35. 163
      oembed/input/posttraite_twitter.php
  36. 45
      oembed/input/posttraite_vimeo_video.php
  37. 19
      oembed/input/posttraite_youtube_video.php
  38. 1
      oembed/input/pretraite_api_arte_tv.php
  39. 3
      oembed/input/pretraite_publish_twitter_com.php
  40. 18
      oembed/input/pretraite_vimeo_com.php
  41. 1
      oembed/input/pretraite_www_youtube_com.php
  42. BIN
      oembed/input/vignettes/soundcloud.png
  43. 112
      oembed/input/vignettes/soundcloud.svg
  44. 5
      oembed/output/json.php
  45. 12
      oembed/output/modeles/article-photo.json.html
  46. 15
      oembed/output/xml.php
  47. 15
      oembed_administrations.php
  48. 165
      oembed_fonctions.php
  49. 196
      oembed_pipelines.php
  50. 15
      paquet.xml
  51. 20
      phpcs.xml.dist
  52. 617
      phpstan-baseline.neon
  53. 11
      phpstan-constants.php
  54. 13
      phpstan.neon.dist
  55. 2
      prive/objets/liste/oembed_providers.html
  56. BIN
      prive/themes/spip/images/oembed-16.png
  57. BIN
      prive/themes/spip/images/oembed-24.png
  58. BIN
      prive/themes/spip/images/oembed-32.png
  59. BIN
      prive/themes/spip/images/oembed-64.png
  60. 6
      prive/themes/spip/images/oembed-xx.svg
  61. 8
      spip-cli/OembedRecupererData.php

66
.gitattributes vendored

@ -1,66 +0,0 @@
* text=auto !eol
action/api_oembed.php -text
action/oembed_nettoyer_iframes.php -text
css/oembed.css -text
formulaires/configurer_oembed.html -text
inc/oembed.php -text
inc/oembed_recuperer_url.php -text
inc/ressource.php -text
javascript/oembed_restaurer_clics_sanitises.js -text
lang/oembed.xml -text
lang/oembed_de.php -text
lang/oembed_en.php -text
lang/oembed_es.php -text
lang/oembed_fr.php -text
lang/oembed_sk.php -text
lang/paquet-oembed.xml -text
lang/paquet-oembed_de.php -text
lang/paquet-oembed_en.php -text
lang/paquet-oembed_es.php -text
lang/paquet-oembed_fr.php -text
lang/paquet-oembed_sk.php -text
lib/php-emoji/emoji.css -text
lib/php-emoji/emoji.php -text
lib/php-emoji/emoji.png -text
modeles/oembed.html -text
modeles/oembed_fonctions.php -text
modeles/oembed_link.html -text
modeles/oembed_photo.html -text
modeles/oembed_rich.html -text
modeles/oembed_video.html -text
modeles/text_oembed.html -text
modeles/toot.html -text
oembed/input/posttraite_api_arte_tv.php -text
oembed/input/posttraite_facebook_video.php -text
oembed/input/posttraite_huffduffer_rich.php -text
oembed/input/posttraite_instagram_rich.php -text
oembed/input/posttraite_issuu.php -text
oembed/input/posttraite_mastodon.php -text
oembed/input/posttraite_oeproxy_default_rich.php -text
oembed/input/posttraite_oeproxy_imdb_rich.php -text
oembed/input/posttraite_office_national_du_film_du_canada_video.php -text
oembed/input/posttraite_rdio_rich.php -text
oembed/input/posttraite_slideshare_rich.php -text
oembed/input/posttraite_soundcloud_rich.php -text
oembed/input/posttraite_twitter.php -text
oembed/input/posttraite_youtube_video.php -text
oembed/input/pretraite_api_arte_tv.php -text
oembed/input/pretraite_publish_twitter_com.php -text
oembed/input/pretraite_www_youtube_com.php -text
oembed/input/vignettes/soundcloud.png -text
oembed/output/json.php -text
oembed/output/modeles/article-photo.json.html -text
oembed/output/modeles/article.json.html -text
oembed/output/xml.php -text
/oembed_administrations.php -text
/oembed_fonctions.php -text
/oembed_pipelines.php -text
/paquet.xml -text
prive/objets/liste/oembed_providers.html -text
prive/squelettes/contenu/configurer_oembed.html -text
prive/themes/spip/images/oembed-16.png -text
prive/themes/spip/images/oembed-24.png -text
prive/themes/spip/images/oembed-32.png -text
prive/themes/spip/images/oembed-64.png -text svneol=unset#unset
prive/themes/spip/images/oembed-xx.svg -text
spip-cli/OembedRecupererData.php -text

10
.gitignore vendored

@ -0,0 +1,10 @@
/vendor/
/composer.phar
/composer.lock
/phpcs.xml
/phpstan.neon
/.php_cs.cache
/.php_cs.txt
/.phpunit.cache
/phpunit.xml
/rector.php

40
action/api_oembed.php

@ -1,55 +1,61 @@
<?php
/**
* Plugin oEmbed
* Licence GPL3
*
*/
if (!defined('_ECRIRE_INC_VERSION')){
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
function action_api_oembed_dist(){
function action_api_oembed_dist() {
$args = array(
$args = [
'url' => $url = _request('url'),
'maxheight' => _request('maxheight'),
'maxwidth' => _request('maxwidth'),
'format' => _request('format'),
// support du jsonp: http://json-p.org/
'callback_jsonp' => _request('callback_jsonp'),
);
];
// Un pipeline pour pouvoir manipuler les arguments (en ajouter des spécifiques par ex.)
$args = pipeline('oembed_liste_arguments', $args);
$format = ($args['format']=='xml' ? 'xml' : 'json');
$format = ($args['format'] == 'xml' ? 'xml' : 'json');
$md5 = md5(serialize($args));
$oembed_cache = sous_repertoire(_DIR_CACHE, substr($md5, 0, 1)) . 'oe-' . $md5 . '.' . $format;
// si cache oembed dispo et pas de recalcul demande, l'utiliser (perf issue)
if (file_exists($oembed_cache)
and _VAR_MODE!=='recalcul'
$res = '';
if (
file_exists($oembed_cache)
and _VAR_MODE !== 'recalcul'
and (!defined('_VAR_NOCACHE')
or !_VAR_NOCACHE)){
or !_VAR_NOCACHE)
) {
lire_fichier($oembed_cache, $res);
} else {
include_spip('inc/urls');
define('_DEFINIR_CONTEXTE_TYPE_PAGE', true);
list($fond, $contexte, $url_redirect) = urls_decoder_url($url, '', $args);
if (!isset($contexte['type-page'])
or !$type = $contexte['type-page']){
defined('_DEFINIR_CONTEXTE_TYPE_PAGE') || define('_DEFINIR_CONTEXTE_TYPE_PAGE', true);
[$fond, $contexte, $url_redirect] = urls_decoder_url($url, '', $args);
if (
!isset($contexte['type-page'])
or !$type = $contexte['type-page']
) {
return '';
}
$res = '';
// chercher le modele json si il existe
if (trouver_fond($f = "oembed/output/modeles/$type.json")){
if (trouver_fond($f = "oembed/output/modeles/$type.json")) {
$res = trim(recuperer_fond($f, $contexte));
if ($format=='xml'){
$res = json_decode($res, true);
if ($format == 'xml') {
$res = json_decode($res, true, 512, JSON_THROW_ON_ERROR);
$output = charger_fonction('xml', 'oembed/output');
$res = $output($res, false);
}
@ -57,12 +63,12 @@ function action_api_oembed_dist(){
ecrire_fichier($oembed_cache, $res);
}
if (!$res){
if (!$res) {
include_spip('inc/headers');
http_status(404);
echo '404 Not Found';
} else {
$content_type = ($format=='xml' ? 'text/xml' : 'application/json');
$content_type = ($format == 'xml' ? 'text/xml' : 'application/json');
header("Content-type: $content_type; charset=utf-8");
echo $res;
}

101
action/oembed_nettoyer_iframes.php

@ -1,11 +1,12 @@
<?php
/**
* Plugin oEmbed
* Licence GPL3
*
*/
if (!defined('_ECRIRE_INC_VERSION')){
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
@ -15,71 +16,71 @@ if (!defined('_ECRIRE_INC_VERSION')){
* appeler manuellement avec ?action=oembed_nettoyer_iframes
* autorise pour les seuls webmestres
*/
function action_oembed_nettoyer_iframes_dist(){
function action_oembed_nettoyer_iframes_dist() {
include_spip('inc/autoriser');
include_spip('inc/filtres');
include_spip('action/editer_objet');
if (!autoriser('webmestre')){
if (!autoriser('webmestre')) {
die('Pas autorise');
}
echo '<h1>Conversion des &lt;iframe&gt; en liens oembed</h1>';
$simu = true;
if (_request('modif')){
if (_request('modif')) {
$simu = false;
}
if ($simu){
if ($simu) {
echo "<p><strong>mode SIMULATION</strong> (ajoutez &modif=1 dans l'url pour modifier les contenus)</p>";
}
$tables = array(
'spip_articles' => array('descriptif', 'chapo', 'texte', 'ps'),
);
$tables = [
'spip_articles' => ['descriptif', 'chapo', 'texte', 'ps'],
];
foreach ($tables as $table => $champs){
foreach ($tables as $table => $champs) {
$objet = objet_type($table);
foreach ($champs as $champ){
foreach ($champs as $champ) {
$primary = id_table_objet($table);
$res = sql_select("$primary,$champ", $table, "$champ LIKE '%iframe%' OR $champ LIKE '%object%'");
while ($row = sql_fetch($res)){
while ($row = sql_fetch($res)) {
$pre = "$primary=" . $row[$primary] . ":$champ:";
$texte = $row[$champ];
$iframes = extraire_balises($texte, 'iframe');
if (count($iframes)){
foreach ($iframes as $iframe){
if (count($iframes)) {
foreach ($iframes as $iframe) {
$url = '';
$src = extraire_attribut($iframe, 'src');
if (strncmp($src, '//', 2)==0){
if (strncmp($src, '//', 2) == 0) {
$src = 'http:' . $src;
}
if (strpos($iframe, 'youtube')!==false){
if (strpos($src, '/embed/')!==false){
if (strpos($iframe, 'youtube') !== false) {
if (strpos($src, '/embed/') !== false) {
$url = str_replace('?', '&', $src);
$url = str_replace('/embed/videoseries&', '/playlist?', $url);
$url = str_replace('/embed/', '/watch?v=', $url);
$url = str_replace('&feature=player_embedded', '', $url);
echo "$pre Youtube $url<br />";
}
if (!$url){
if (!$url) {
var_dump($row);
var_dump(entites_html($iframe));
die('youtube inconnue');
}
} elseif (strpos($iframe, 'dailymotion')!==false) {
if (strpos($src, '/embed/')!==false){
} elseif (strpos($iframe, 'dailymotion') !== false) {
if (strpos($src, '/embed/') !== false) {
$url = str_replace('/embed/', '/', $src);
$url = explode('?', $url);
$url = reset($url);
#var_dump($url);
echo "$pre DailyMotion $url<br />";
}
if (!$url){
if (!$url) {
var_dump($row);
var_dump($iframe);
die('dailymotion inconnue');
}
} elseif (strpos($iframe, 'player.vimeo')!==false) {
if (strpos($src, '/video/')!==false){
} elseif (strpos($iframe, 'player.vimeo') !== false) {
if (strpos($src, '/video/') !== false) {
$url = str_replace('/video/', '/', $src);
$url = str_replace('player.vimeo', 'vimeo', $url);
$url = explode('?', $url);
@ -87,7 +88,7 @@ function action_oembed_nettoyer_iframes_dist(){
#var_dump($url);
echo "$pre Vimeo $url<br />";
}
if (!$url){
if (!$url) {
var_dump($row);
var_dump($iframe);
die('vimeo inconnue');
@ -117,75 +118,77 @@ function action_oembed_nettoyer_iframes_dist(){
}
} */ else {
echo "$pre iframe inconnue : " . entites_html($iframe) . '<br />';
}
if ($url){
}
if ($url) {
$texte = str_replace($iframe, "\n\n" . $url . "\n\n", $texte);
if (preg_match(',<center>\s*' . preg_quote($url, ',') . '.*</center>,Uims', $texte, $m)){
if (preg_match(',<center>\s*' . preg_quote($url, ',') . '.*</center>,Uims', $texte, $m)) {
$texte = str_replace($m[0], "\n\n" . $url . "\n\n", $texte);
}
$texte = preg_replace(',\s+' . preg_quote($url, ',') . '\s+,ims', "\n\n" . $url . "\n\n", $texte);
}
}
if ($texte!==$row[$champ]){
if ($texte !== $row[$champ]) {
echo "$pre Corrige $champ <br />";
if (!$simu){
if (!$simu) {
echo "$pre Corrige $champ <br />";
objet_modifier($objet, $row[$primary], array($champ => $texte));
objet_modifier($objet, $row[$primary], [$champ => $texte]);
} else {
echo "SIMU : $pre Corrige $champ <br />";
}
}
}
$objects = extraire_balises($texte, 'object');
if (count($objects)){
foreach ($objects as $object){
if (count($objects)) {
foreach ($objects as $object) {
$url = '';
$embed = extraire_balise($object, 'embed');
$src = extraire_attribut($embed, 'src');
if (strncmp($src, '//', 2)==0){
if (strncmp($src, '//', 2) == 0) {
$src = 'http:' . $src;
}
if (strpos($embed, 'youtube')!==false){
if (strpos($src, '/v/')!==false){
if (strpos($embed, 'youtube') !== false) {
if (strpos($src, '/v/') !== false) {
$url = str_replace('?', '&', $src);
$url = str_replace('/v/', '/watch?v=', $url);
echo "$pre Youtube $url<br />";
} elseif (strpos($src, '/embed/')!==false) {
} elseif (strpos($src, '/embed/') !== false) {
$url = str_replace('?', '&', $src);
$url = str_replace('/embed/', '/watch?v=', $url);
echo "$pre Youtube $url<br />";
}
if (!$url){
if (!$url) {
var_dump($row);
var_dump(entites_html($object));
die('youtube inconnue');
}
} elseif (strpos($embed, 'dailymotion')!==false) {
if (strpos($src, '/swf/video/')!==false){
} elseif (strpos($embed, 'dailymotion') !== false) {
if (strpos($src, '/swf/video/') !== false) {
$url = str_replace('/swf/video/', '/video/', $src);
$url = explode('?', $url);
$url = reset($url);
#var_dump($url);
echo "$pre DailyMotion $url<br />";
} elseif (strpos($src, '/swf/')!==false) {
} elseif (strpos($src, '/swf/') !== false) {
$url = str_replace('/swf/', '/video/', $src);
$url = explode('?', $url);
$url = reset($url);
#var_dump($url);
echo "$pre DailyMotion $url<br />";
}
if (!$url){
if (!$url) {
var_dump($row);
var_dump($object);
die('dailymotion inconnue');
}
} elseif (strpos($embed, 'vimeo.com')!==false) {
if (strpos($src, 'moogaloop')!==false
and $id = parametre_url($src, 'clip_id')){
} elseif (strpos($embed, 'vimeo.com') !== false) {
if (
strpos($src, 'moogaloop') !== false
and $id = parametre_url($src, 'clip_id')
) {
$url = "https://vimeo.com/$id";
echo "$pre Vimeo $url<br />";
}
if (!$url){
if (!$url) {
var_dump($row);
var_dump(entites_html($object));
die('vimeo inconnue');
@ -196,18 +199,18 @@ function action_oembed_nettoyer_iframes_dist(){
} else {
echo "$pre object inconnue : " . entites_html($object) . '<br />';
}
if ($url){
if ($url) {
$texte = str_replace($object, "\n\n" . $url . "\n\n", $texte);
if (preg_match(',<center>\s*' . preg_quote($url, ',') . '.*</center>,Uims', $texte, $m)){
if (preg_match(',<center>\s*' . preg_quote($url, ',') . '.*</center>,Uims', $texte, $m)) {
$texte = str_replace($m[0], "\n\n" . $url . "\n\n", $texte);
}
$texte = preg_replace(',\s+' . preg_quote($url, ',') . '\s+,ims', "\n\n" . $url . "\n\n", $texte);
}
}
if ($texte!==$row[$champ]){
if (!$simu){
if ($texte !== $row[$champ]) {
if (!$simu) {
echo "$pre Corrige $champ <br />";
objet_modifier($objet, $row[$primary], array($champ => $texte));
objet_modifier($objet, $row[$primary], [$champ => $texte]);
} else {
echo "SIMU : $pre Corrige $champ <br />";
}

20
composer.json

@ -0,0 +1,20 @@
{
"autoload": {
},
"autoload-dev": {
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"spip/coding-standards": "^1.2",
"phpstan/phpstan": "^1.4",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
"rector/rector": "^0.12.13"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

6
css/oembed.css

@ -98,7 +98,7 @@ figure.oe-image-block figcaption {background:#eee;padding: 10px;text-align: left
.oembed_mastodon .rwd-rich-container {height: auto !important;}
.oembed_mastodon .oembed-source {display: none;}
.oembed_mastodon .spip_doc_titre {display: none;}
.mastodon-toot {padding:0;margin:0;border:0;padding-left:63px;font-family: Arial,Helvetica,Sans-Serif;font-size: 1.0em;line-height: 1.5em;}
.mastodon-toot {padding:0;margin:0;border:0;padding-left:63px;font-family: Arial,Helvetica,Sans-Serif;font-size: 1.0em;line-height: 1.5em;text-align: inherit}
.mastodon-toot a {background: transparent !important;text-decoration: none !important;}
.mastodon-toot .emoji-sizer {vertical-align: top;}
.mastodon-toot .toot-published {float: right;color:#9baec8;}
@ -107,12 +107,12 @@ figure.oe-image-block figcaption {background:#eee;padding: 10px;text-align: left
.mastodon-toot .toot-author-thumbnail {float: left;margin-left:-63px;margin-top:4px;width: 48px;height: 48px;border-radius: 4px;}
.mastodon-toot .toot-author-screen-name {color:#282c37;}
.mastodon-toot .toot-author-url:active .toot-author-screen-name,.mastodon-toot .toot-author-url:focus .toot-author-screen-name,.mastodon-toot .toot-author-url:hover .toot-author-screen-name {text-decoration: underline;}
.mastodon-toot .toot-content {display:block;margin: 0.75em 0 0.25em;}
.mastodon-toot .toot-content {display:block;margin: 0.75em 0 0.25em;text-align: inherit;max-width: 80em;}
.mastodon-toot .toot-content p {margin-bottom: 0.75em;}
.mastodon-toot .toot-content p:last-child {margin-bottom: 0;}
.mastodon-toot .toot-content a {color:#2b90d9;}
.mastodon-toot .toot-content a:active,.mastodon-toot .toot-content a:focus,.mastodon-toot .toot-content a:hover {text-decoration: underline !important;}
.mastodon-toot .invisible {display: none}
.mastodon-toot .ellipsis::after {display: inline;content:'\2026'}
.mastodon-toot .toot-enclosure {display: inline-block;position: relative;width: 100%;height: 0;padding-bottom:40%;margin: 0.25em 0;}
.mastodon-toot .toot-enclosure {display: inline-block;position: relative;width: 100%;height: 0;padding-bottom:50%;margin: 0.25em 0;}
.mastodon-toot .toot-enclosure .toot-enclosure-inner {display:block;position:absolute;top:0;left: 0;height: 100%;width: 100%;vertical-align: middle;overflow: hidden;background-position: center;background-repeat: no-repeat;background-size: cover;}

28
formulaires/configurer_oembed.html

@ -1,27 +1,27 @@
<!-- presentation=non -->
<!-- nom=oembed -->
<div class="formulaire_spip formulaire_cfg formulaire_configurer formulaire_#FORM">
<h3 class='titrem'><img src="#CHEMIN_IMAGE{oembed-24.png}" class="cadre-icone" /><:oembed:titre_configurer_oembed:></h3>
<h3 class='titrem'><img src="#CHEMIN_IMAGE{oembed-24.svg}" class="cadre-icone" /><:oembed:titre_configurer_oembed:></h3>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
<form method='post' action='#ENV{action}'><div>
#ACTION_FORMULAIRE{#ENV{action}}
<ul>
<div class="editer-groupe">
#SET{fl,oembed}
#SET{name,maxwidth}#SET{obli,''}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
<li class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<div class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<label for="#GET{name}">[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>[
<span class='erreur_message'>(#GET{erreurs})</span>
]<input type="text" name="#GET{name}" class="text" value="#ENV*{#GET{name},600}" id="#GET{name}"/>
</li>
</div>
#SET{name,maxheight}#SET{obli,''}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
<li class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<div class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<label for="#GET{name}">[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>[
<span class='erreur_message'>(#GET{erreurs})</span>
]<input type="text" name="#GET{name}" class="text" value="#ENV*{#GET{name},400}" id="#GET{name}"/>
</li>
</div>
#SET{name,embed_auto}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
<li class="editer long_label editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<div class="editer long_label editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<label for="#GET{name}"><:oembed:label_embed_auto:></label>[
<span class='erreur_message'>(#GET{erreurs})</span>
]<div class="choix">
@ -31,9 +31,9 @@
<input type="radio" name="#GET{name}" class="radio" id="#GET{name}_non" value="non"
[(#ENV{#GET{name},oui}|=={oui}|non)checked="checked"] /><label for="#GET{name}_non"><:item_non:></label>
</div>
</li>
</div>
#SET{name,detecter_lien}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
<li class="editer long_label editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<div class="editer long_label editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<label for="#GET{name}"><:oembed:label_detecter_lien:></label>[
<span class='erreur_message'>(#GET{erreurs})</span>
]<div class="choix">
@ -43,9 +43,9 @@
<input type="radio" name="#GET{name}" class="radio" id="#GET{name}_non" value="non"
[(#ENV{#GET{name},non}|=={oui}|non)checked="checked"] /><label for="#GET{name}_non"><:item_non:></label>
</div>
</li>
</div>
#SET{name,inserer_head}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
<li class="editer long_label editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<div class="editer long_label editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
<label for="#GET{name}"><:oembed:label_inserer_head:></label>[
<span class='erreur_message'>(#GET{erreurs})</span>
]<div class="choix">
@ -55,10 +55,10 @@
<input type="radio" name="#GET{name}" class="radio" id="#GET{name}_non" value="non"
[(#ENV{#GET{name},oui}|=={oui}|non)checked="checked"] /><label for="#GET{name}_non"><:item_non:></label>
</div>
</li>
</ul>
</div>
</div>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
<p class='boutons'><span class='image_loading'>&nbsp;</span><input type='submit' class='submit' value='<:bouton_enregistrer:>' /></p>
</div></form>
</div>
</div>

222
inc/oembed.php

@ -1,11 +1,12 @@
<?php
/**
* Plugin oEmbed
* Licence GPL3
*
*/
if (!defined('_ECRIRE_INC_VERSION')){
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
@ -13,7 +14,7 @@ if (!defined('_ECRIRE_INC_VERSION')){
* Lister les providers connus
* @return array
*/
function oembed_lister_providers(){
function oembed_lister_providers($avec_provider_interdits = false) {
// liste des providers par defaut
@ -23,7 +24,7 @@ function oembed_lister_providers(){
// 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 = array(
$providers = [
'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',
@ -40,10 +41,6 @@ function oembed_lister_providers(){
'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',
@ -74,34 +71,66 @@ function oembed_lister_providers(){
'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']);
// retirer les providers avec un endpoint vide
}
if (!$avec_provider_interdits) {
$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
@ -116,36 +145,40 @@ function oembed_lister_providers(){
* 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 string $detecter_lien tenter la détection automatique de lien oembed dans la page indiquée
* @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 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 = 'non', $force_reload = false){
static $cache = array();
$provider = false;
include_spip('inc/config');
function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $format = 'json', $detecter_lien = null, $force_reload = false) {
static $cache = [];
$provider = oembed_verifier_provider($url);
if ((!$provider)
and (($detecter_lien!='non')
or lire_config('oembed/detecter_lien', 'non')=='oui')){
$provider = oembed_detecter_lien($url);
// 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;
}
if (!$provider){
$provider = oembed_provider_from_url($url, $detecter_lien);
// inconnu ou interdit ?
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');
}
@ -153,7 +186,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
@ -162,29 +195,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 = array('url' => array_shift($a));
if (count($a)){
$args = ['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];
@ -193,8 +226,12 @@ 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]){
$provider_name2 = str_replace(' ', '_', strtolower($cache[$data_url]['provider_name']));
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 = '';
}
$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");
@ -205,7 +242,8 @@ 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]));
@ -220,18 +258,25 @@ function oembed_recuperer_data($url, $maxwidth = null, $maxheight = null, $forma
*
* @param string $url l'url à tester
* @return bool|array
* false si non ; details du provider dans un tabeau associatif si oui
* 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)
*/
function oembed_verifier_provider($url){
if (strncmp($url, $GLOBALS['meta']['adresse_site'], strlen($GLOBALS['meta']['adresse_site']))==0){
return false;
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' => ''];
}
$providers = oembed_lister_providers();
foreach ($providers as $scheme => $endpoint){
$providers = oembed_lister_providers(true);
foreach ($providers as $scheme => $endpoint) {
$regex = '#' . str_replace('\*', '(.+)', preg_quote($scheme, '#')) . '#';
$regex = preg_replace('|^#http\\\://|', '#https?\://', $regex);
if (preg_match($regex, $url)){
return array('endpoint' => $endpoint);
if (preg_match($regex, $url)) {
return ['endpoint' => $endpoint];
}
}
return false;
@ -241,45 +286,66 @@ 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|string false si pas de lien ; url du contenu oembed
* @return bool|array false si pas de lien ; description du provider oembed associe au lien
*/
function oembed_detecter_lien($url){
$providers = array();
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;
}
}
}
$oembed_recuperer_url = charger_fonction('oembed_recuperer_url', 'inc');
// on recupere le contenu de la page
if ($html = $oembed_recuperer_url($url, $url, 'html')){
// 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'];
// types de liens oembed à détecter
$linktypes = array(
$linktypes = [
'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;
}
}
@ -287,10 +353,10 @@ function oembed_detecter_lien($url){
}
}
$res = array();
$res = [];
// 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'];
@ -299,7 +365,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';
}
@ -312,26 +378,14 @@ function oembed_detecter_lien($url){
* @param string $lien
* @return string
*/
function oembed_embarquer_lien($lien){
static $base = null;
function oembed_embarquer_lien($lien) {
$url = extraire_attribut($lien, 'href');
$texte = null;
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;
}
if ($url and oembed_provider_from_url($url)) {
$fond = recuperer_fond('modeles/oembed', ['url' => $url, 'lien' => $lien]);
if ($fond = trim($fond)) {
$texte = $fond;
}
}

59
inc/oembed_recuperer_url.php

@ -1,11 +1,12 @@
<?php
/**
* Plugin oEmbed
* Licence GPL3
*
*/
if (!defined('_ECRIRE_INC_VERSION')){
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
@ -17,13 +18,12 @@ if (!defined('_ECRIRE_INC_VERSION')){
* @param string $format
* @return bool|mixed|string
*/
function inc_oembed_recuperer_url($oembed_url, $url, $format){
$erreur = "";
function inc_oembed_recuperer_url($oembed_url, $url, $format) {
$erreur = '';
// on recupere le contenu de la page
// si possible via curl en IPv4 car youtube bug en IPv6
// uniquement si PHP >= 5.3.0 pour utiliser l'option CURLOPT_IPRESOLVE
if (function_exists('curl_init') and version_compare(phpversion(), '5.3.0', '>=')){
if (function_exists('curl_init')) {
spip_log('Requete oembed (curl) pour ' . $url . ' : ' . $oembed_url, 'oembed.' . _LOG_DEBUG);
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
@ -35,14 +35,19 @@ function inc_oembed_recuperer_url($oembed_url, $url, $format){
curl_setopt($c, CURLOPT_USERAGENT, $browser);
//curl_setopt($c, CURLOPT_SSLVERSION, 1);
// essayer d'eviter l'erreur 35 sur le protocole SSL
// https://stackoverflow.com/questions/58342699/php-curl-curl-error-35-error1414d172ssl-routinestls12-check-peer-sigalgwr
// non supporte partout, provoque une erreur 59
// curl_setopt($c, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1');
// indiquer un referer : si jamais la diffusion du contenu est limitee au site, ca permet d'en recuperer les infos
// ou en tout cas ca donne plus de chance...
$referer = $GLOBALS['meta']['adresse_site'] . '/';
curl_setopt($c, CURLOPT_REFERER, $referer);
if (isset($GLOBALS['meta']['http_proxy']) and $GLOBALS['meta']['http_proxy']){
if (isset($GLOBALS['meta']['http_proxy']) and $GLOBALS['meta']['http_proxy']) {
curl_setopt($c, CURLOPT_PROXY, $GLOBALS['meta']['http_proxy']);
if (isset($GLOBALS['meta']['http_noproxy'])){
if (isset($GLOBALS['meta']['http_noproxy'])) {
curl_setopt($c, CURLOPT_NOPROXY, $GLOBALS['meta']['http_proxy']);
}
}
@ -51,42 +56,50 @@ function inc_oembed_recuperer_url($oembed_url, $url, $format){
// http://stackoverflow.com/questions/26089067/youtube-oembed-api-302-then-503-errors
curl_setopt($c, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$data = curl_exec($c);
$status = curl_getinfo($c, CURLINFO_HTTP_CODE);
if (!$data or intval($status/100)==4){
/** code mort : vieux patch introduit par https://git.spip.net/spip-contrib-extensions/oembed/commit/9146311a
* pour fixer les erreurs SSL sur certains serveurs masto mais pas très viable en prod
$status = curl_getinfo($c, CURLINFO_HTTP_CODE);
if (!$data or intval($status / 100) == 4) {
$errno = curl_errno($c);
$erreur = "Status $status Error " . curl_errno($c) . " " . curl_error($c);
$erreur = "Status $status Error $errno " . curl_error($c);
// si c'est une erreur de protocole SSL, on tente avec un exec mechant car ca peut venir de la version de CURL PHP
// (ca marche au moins en local)
if (!$data and $errno==35){
exec('curl "' . $oembed_url . '"', $output);
if (!$data and $errno == 35 and function_exists('exec')) {
exec('curl --silent --location ' . escapeshellarg($oembed_url), $output);
$data = implode("\n", $output);
} else {
$data = '';
}
}
curl_close($c);
*/
curl_close($c);
} else {
spip_log('Requete oembed (recuperer_page) pour ' . $url . ' : ' . $oembed_url, 'oembed.' . _LOG_DEBUG);
spip_log('Requete oembed (recuperer_page / recuperer_url) pour ' . $url . ' : ' . $oembed_url, 'oembed.' . _LOG_DEBUG);
include_spip('inc/distant');
// recuperer_page utilise par defaut l'adresse du site comme $referer
$data = recuperer_page($oembed_url);
$data = recuperer_url($oembed_url);
$data = ($data['page'] ?? null);
}
if (!$data){
if (!$data) {
spip_log('infos oembed brutes pour ' . "$url | $oembed_url" . ' : ' . "ECHEC $erreur", 'oembed.' . _LOG_ERREUR);
} else {
spip_log('infos oembed brutes pour ' . "$url | $oembed_url" . ' : ' . (($format=='html') ? substr($data, 0, 100) : $data), 'oembed.' . _LOG_DEBUG);
spip_log('infos oembed brutes pour ' . "$url | $oembed_url" . ' : ' . (($format == 'html') ? substr($data, 0, 100) : $data), 'oembed.' . _LOG_DEBUG);
}
if ($data){
if ($format=='json'){
$data = json_decode($data, true);
$data['oembed_url_source'] = $url;
$data['oembed_url'] = $oembed_url;
if ($data) {
if ($format == 'json') {
try {
$data = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
$data['oembed_url_source'] = $url;
$data['oembed_url'] = $oembed_url;
} catch (JsonException $e) {
$data = null;
spip_log('Failed to parse Json data : ' . $e->getMessage(), 'oembed.' . _LOG_ERREUR);
}
}
// TODO : format xml
//if ($format == 'xml')

24
inc/ressource.php

@ -10,17 +10,17 @@ define('_EXTRAIRE_RESSOURCES', ',' . '<"?(https?://|[\w][\w -]*\.[\w -]+).*>' .
/* pipeline pour typo, evitons une erreur dans les logs */
function tw_post_typo($t){
function tw_post_typo($t) {
return $t;
}
/* pipeline pour propre, evitons une erreur dans les logs */
function tw_pre_liens($t){
function tw_pre_liens($t) {
return $t;
}
function traiter_ressources($r){
if ($ressource = charger_fonction('ressource', 'inc', true)){
function traiter_ressources($r) {
if ($ressource = charger_fonction('ressource', 'inc', true)) {
$html = $ressource($r[0]);
} else {
$html = htmlspecialchars($r[0]);
@ -29,27 +29,29 @@ function traiter_ressources($r){
return $html;
}
function inc_ressource_dist($html){
return tw_traiter_ressources(array(0 => $html));
function inc_ressource_dist($html) {
return tw_traiter_ressources([0 => $html]);
}
function tw_traiter_ressources($r){
function tw_traiter_ressources($r) {
$html = null;
include_spip('inc/lien');
$url = explode(' ', trim($r[0], '<>'));
$url = $url[0];
# <http://url/absolue>
if (preg_match(',^https?://,i', $url)){
if (preg_match(',^https?://,i', $url)) {
$html = PtoBR(propre("<span class='ressource spip_out'>&lt;[->" . $url . ']&gt;</span>'));
} # <url/relative>
else {
if (false!==strpos($url, '/')){
if (false !== strpos($url, '/')) {
$html = PtoBR(propre("<span class='ressource spip_in'>&lt;[->" . $url . ']&gt;</span>'));
} # <fichier.rtf>
else {
if (preg_match(',\.([^.]+)$,', $url, $regs)
and file_exists($f = _DIR_IMG . $regs[1] . '/' . $url)){
if (
preg_match(',\.([^.]+)$,', $url, $regs)
and file_exists($f = _DIR_IMG . $regs[1] . '/' . $url)
) {
$html = PtoBR(propre("<span class='ressource spip_in'>&lt;[" . $url . '->' . $f . ']&gt;</span>'));
} else {
$html = PtoBR(propre("<span class='ressource'>&lt;" . $url . '&gt;</span>'));

3
lang/oembed.xml

@ -17,6 +17,9 @@
<traducteur nom="Raquel S. Bujaldón" lien="https://trad.spip.net/auteur/raquel-s-bujaldon" />
</langue>
<langue code="fr" url="https://trad.spip.net/tradlang_module/oembed?lang_cible=fr" total="22" traduits="22" relire="0" modifs="0" nouveaux="0" pourcent="100.00" />
<langue code="it" url="https://trad.spip.net/tradlang_module/oembed?lang_cible=it" total="22" traduits="22" relire="0" modifs="0" nouveaux="0" pourcent="100.00">
<traducteur nom="Alberto" lien="https://trad.spip.net/auteur/alberto" />
</langue>
<langue code="sk" url="https://trad.spip.net/tradlang_module/oembed?lang_cible=sk" total="22" traduits="19" relire="0" modifs="1" nouveaux="2" pourcent="86.36">
<traducteur nom="jaro" lien="https://trad.spip.net/auteur/jaro" />
</langue>

49
lang/oembed_it.php

@ -0,0 +1,49 @@
<?php
// This is a SPIP language file -- Ceci est un fichier langue de SPIP
// extrait automatiquement de https://trad.spip.net/tradlang_module/oembed?lang_cible=it
// ** ne pas modifier le fichier **
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
$GLOBALS[$GLOBALS['idx_lang']] = array(
// A
'aucun_provider' => 'Nessun provider',
// B
'bouton_lecture' => 'Lettura',
// E
'erreur_ajout_provider' => 'Errore durante l’aggiunta del provider.',
'erreur_scheme_doublon' => 'Questo schema è già presente nell’elenco.',
'explication_scheme' => 'usa * come carattere jolly',
'explication_upload_url' => 'Inserisci semplicemente l’URL della pagina che contiene il documento per <a href="https://contrib.spip.net/4595"> i siti più popolari</a>.',
// I
'info_1_provider' => '1 provider',
'info_nb_providers' => '@nb@ provider',
// L
'label_detecter_lien' => 'Rileva automaticamente i provider (ignora la whitelist)?',
'label_embed_auto' => 'Trasforma automaticamente gli URL inseriti nel testo?',
'label_endpoint' => 'Endpoint',
'label_inserer_head' => 'Il sito stesso è un provider oEmbed',
'label_maxheight' => 'Altezza massima predefinita (px)',
'label_maxwidth' => 'Larghezza massima predefinita (px)',
'label_scheme' => 'Schema',
// O
'ok_ajout_provider' => 'Provider aggiunto',
// S
'supprimer_provider' => 'Eliminare',
// T
'titre_ajouter_provider' => 'Aggiungi un provider',
'titre_configuration_avancee_providers' => 'Accedi alla configurazione avanzata dei provider oEmbed',
'titre_configurer_oembed' => 'Configura oEmbed',
'titre_configurer_providers' => 'Provider oEmbed',
'titre_oembed' => 'oEmbed'
);

3
lang/paquet-oembed.xml

@ -15,6 +15,9 @@
<traducteur nom="Raquel S. Bujaldón" lien="https://trad.spip.net/auteur/raquel-s-bujaldon" />
</langue>