Comment décoder des entités HTML à l'aide de jQuery?

334

Comment utiliser jQuery pour décoder des entités HTML dans une chaîne?

EddyR
la source
Le choix prématuré de la technologie (jQuery) invite à des réponses aux problèmes de sécurité. Cela pourrait être mieux fermé comme un doublon de stackoverflow.com/questions/1912501/… .
Wladimir Palant

Réponses:

437

Note de sécurité: l' utilisation de cette réponse (conservée dans sa forme originale ci-dessous) peut introduire une vulnérabilité XSS dans votre application. Vous ne devez pas utiliser cette réponse. Lisez la réponse de lucascaro pour une explication des vulnérabilités de cette réponse et utilisez plutôt l'approche de cette réponse ou celle de Mark Amery .

En fait, essayez

var decoded = $("<div/>").html(encodedStr).text();
à M
la source
175
Ne faites pas cela avec une entrée non fiable. De nombreux navigateurs chargent des images et déclenchent des événements liés même si le nœud n'est pas attaché au DOM. Essayez de courir $("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>'). Dans Firefox ou Safari, il déclenche l'alerte.
Mike Samuel
@Mike, alors que recommandez-vous à la place? votre réponse de .replace () n'est pas bonne si vous ne savez pas ce que vous remplacez ...
ekkis
7
@ekkis, vous devez supprimer les balises avant d'essayer de décoder des entités. str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")ou quelque chose de similaire.
Mike Samuel
2
Une meilleure implémentation (à mon avis) qui supprime la plupart des balises HTML (gracieuseté de Mike) de l'entrée est dans ma réponse à une question similaire . Il n'a pas non plus la surcharge de jQuery, il est donc tout à fait adapté à d'autres environnements.
Robert K
6
@MichaelStum, votre modification ici a invalidé à la fois le commentaire de Mike Samuel et la réponse au vote le plus élevé, et l'a fait sans corriger la vulnérabilité XSS pour toutes les versions de jQuery (comme expliqué dans la réponse ci-dessous). L'ajout d'un avertissement de sécurité à cette réponse serait raisonnable (et je vais le faire); rendre les autres discussions sur cette page absurdes tout en ne réussissant pas à corriger le trou de sécurité ne l'est certainement pas!
Mark Amery
211

Sans jQuery:

function decodeEntities(encodedString) {
  var textArea = document.createElement('textarea');
  textArea.innerHTML = encodedString;
  return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

Cela fonctionne de manière similaire à la réponse acceptée , mais est sûr à utiliser avec des entrées utilisateur non fiables.


Problèmes de sécurité dans des approches similaires

Comme l'a noté Mike Samuel , faire cela avec une entrée utilisateur <div>au lieu d'une <textarea>entrée non approuvée est une vulnérabilité XSS, même si la <div>n'est jamais ajoutée au DOM:

function decodeEntities(encodedString) {
  var div = document.createElement('div');
  div.innerHTML = encodedString;
  return div.textContent;
}

// Shows an alert
decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">')

Cependant, cette attaque n'est pas possible contre a <textarea>car aucun élément HTML n'est autorisé à contenir un <textarea>. Par conséquent, toutes les balises HTML encore présentes dans la chaîne «encodée» seront automatiquement encodées par le navigateur.

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

// Safe, and returns the correct answer
console.log(decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">'))

Avertissement : cette opération à l'aide de jQuery .html()et de .val()méthodes au lieu d'utiliser .innerHTMLet .valuen'est pas sécurisée * pour certaines versions de jQuery, même lorsque vous utilisez atextarea . En effet, les anciennes versions de jQuery évalueraient délibérément et explicitement les scripts contenus dans la chaîne passée à .html(). Par conséquent, un code comme celui-ci affiche une alerte dans jQuery 1.8:

//<!-- CDATA
// Shows alert
$("<textarea>")
.html("<script>alert(1337);</script>")
.text();

//-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

* Merci à Eru Penkman d' avoir rattrapé cette vulnérabilité.

lucascaro
la source
6
Ce pourrait être une bonne idée de détruire la zone de texte après avoir extrait sa valeur:decodedString = textArea.value; textArea.remove(); return decodedString;
Werner
2
Ou seulement si la version de javascript prend en charge remove ():if ('remove' in Element.prototype) textArea.remove();
Werner
6
@Werner Dès que la fonction sera terminée, il n'y aura plus de variables contenant une référence à elle, elle sera donc automatiquement supprimée par le garbage collector .
user2428118
J'utilise cela en combinaison avec .NET à partir du code derrière un clic de bouton, et pour une raison quelconque, la réponse acceptée a provoqué une publication. Cette réponse ne l'a pas fait, c'est donc la meilleure réponse pour moi. Merci!
Snailer
@Snailer $("<div />").html(string).text() exécutera tout javascript dans la chaîne fournie , ce qui, à mon avis, est à l'origine de votre problème. La réponse acceptée doit être mise à jour pour celle-ci.
jbowman
80

Comme Mike Samuel l'a dit, n'utilisez pas jQuery.html (). Text () pour décoder des entités html car cela n'est pas sûr.

Utilisez plutôt un rendu de modèle comme Mustache.js ou decodeEntities du commentaire de @ VyvIT.

La bibliothèque de ceinture utilitaire Underscore.js est livrée avec les méthodes escapeet unescape, mais elles ne sont pas sûres pour l'entrée utilisateur:

_.escape (chaîne)

_.unescape (chaîne)

Alan Hamlett
la source
2
Cela mérite bien plus de votes positifs! Certainement ma solution préférée. Ils ont inclus unescapedans les documents maintenant, btw.
létale-guitare
5
_.unescape("&#39;")résulte en "& # 39;" au lieu d'un guillemet simple. Y a-t-il quelque chose qui me manque ou qui ne souligne pas ne s'échappe pas aux codes d'entité HTML comme indiqué sur: w3schools.com/tags/ref_entities.asp
Jason Axelson
6
Le bug sur github a été fermé comme "ne sera pas corrigé"; cela signifie que cette solution ne fonctionne pas et ne fonctionnera pas.
Igor Chubin
3
Vous dites que Underscore " escapeet les unescapeméthodes ... ne sont pas sécuritaires pour la saisie utilisateur" . Que veux-tu dire par là? Cela me semble absurde, mais peut-être que je manque quelque chose - pouvez-vous clarifier?
Mark Amery
2
@VyvIT Tried _.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(dans Chrome / FF / IE). Mais il n'a montré aucune alerte. Je l'ai essayé dans la console ainsi que dans mon fichier JS. Même résultat.
Vivek Athalye
28

Je pense que vous confondez le texte et les méthodes HTML. Regardez cet exemple, si vous utilisez le HTML interne d'un élément comme texte, vous obtiendrez des balises HTML décodées (deuxième bouton). Mais si vous les utilisez comme HTML, vous obtiendrez la vue au format HTML (premier bouton).

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>

Premier bouton écrit: voici un contenu HTML .

Le deuxième bouton écrit: voici un contenu <B> HTML </B>.

À propos, vous pouvez voir un plug-in que j'ai trouvé dans le plug-in jQuery - décodage HTML et encodage qui encode et décode les chaînes HTML.

Canavar
la source
26

La question est limitée par 'avec jQuery' mais cela pourrait aider certains à savoir que le code jQuery donné dans la meilleure réponse ici fait ce qui suit en dessous ... cela fonctionne avec ou sans jQuery:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}
Rondo
la source
20

Vous pouvez utiliser la bibliothèque he , disponible sur https://github.com/mathiasbynens/he

Exemple:

console.log(he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro "));
// Logs "Jörg & Jürgen rocked to & fro"

J'ai défié l'auteur de la bibliothèque sur la question de savoir s'il y avait une raison d'utiliser cette bibliothèque dans le code côté client en faveur du <textarea>hack fourni dans d' autres réponses ici et ailleurs. Il a fourni quelques justifications possibles:

  • Si vous utilisez node.js côté serveur, l'utilisation d'une bibliothèque pour l'encodage / décodage HTML vous offre une solution unique qui fonctionne à la fois côté client et côté serveur.

  • Certains algorithmes de décodage d'entités de certains navigateurs comportent des bogues ou ne prennent pas en charge certaines références de caractères nommées . Par exemple, Internet Explorer décode et restitue &nbsp;correctement les espaces insécables ( ) mais les signale comme des espaces ordinaires au lieu d'espaces insécables via la innerTextpropriété d' un élément DOM , brisant le <textarea>hack (bien que de manière mineure). De plus, IE 8 et 9 ne prennent tout simplement en charge aucune des nouvelles références de caractères nommées ajoutées dans HTML 5. L'auteur de ce dernier héberge également un test de prise en charge des références de caractères nommées sur http://mathias.html5.org/tests/html / références-de-caractères-nommés / . Dans IE 8, il signale plus de mille erreurs.

    Si vous voulez être isolé des bogues du navigateur liés au décodage d'entité et / ou être capable de gérer la gamme complète des références de caractères nommées, vous ne pouvez pas vous en tirer avec le <textarea>hack; vous aurez besoin d'une bibliothèque comme lui .

  • Il a vraiment bien l'impression que faire les choses de cette façon est moins hacky.

Mark Amery
la source
4
+1 jQuery n'est pas la solution à tout. Utilisez le bon outil pour le travail.
Mathias Bynens
C'est le meilleur moyen de décoder les entités HTML. Toutes les autres réponses (sur cette question et des questions similaires) utilisent soit innerHTML (créer un nouvel élément HTML, traiter le code HTML et ensuite obtenir innerHTML de cet élément, cela peut être vulnérable aux attaques XSS si vous n'êtes pas TRÈS prudent, voir plus ), ou ils suggérons d' utiliser Underscore.js unescape ou Lodash unescape méthodes qui sont à la fois incomplète (ne fonctionne que pour quelques entités HTML). La bibliothèque he est l'option la plus complète et la plus sûre!
et
18

encoder:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'

décoder:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'
user4064396
la source
3
il y a déjà une réponse qui fonctionne, et elle est presque identique à celle-ci. Nous n'avons pas besoin de réponses en double
markasoftware
4
Ceci est la bonne réponse. la réponse de tom utilise un élément DIV, ce qui rend cette réponse vulnérable à XSS.
Francisco Hodge
2
C'est la meilleure réponse pour plus de clarté.
Dan Randolph
4

Utilisation

myString = myString.replace( /\&amp;/g, '&' );

Il est plus facile de le faire côté serveur car, apparemment, JavaScript n'a pas de bibliothèque native pour gérer les entités, et je n'en ai trouvé aucune en haut des résultats de recherche pour les différents cadres qui étendent JavaScript.

Recherchez "Entités HTML JavaScript", et vous trouverez peut-être quelques bibliothèques à cet effet, mais elles seront probablement toutes construites autour de la logique ci-dessus - remplacer, entité par entité.

Peter Mortensen
la source
0

Je devais juste avoir un caractère d'entité HTML (⇓) comme valeur pour un bouton HTML. Le code HTML semble bon depuis le début dans le navigateur:

<input type="button" value="Embed & Share  &dArr;" id="share_button" />

Maintenant, j'ajoutais une bascule qui devrait également afficher le caractère. C'est ma solution

$("#share_button").toggle(
    function(){
        $("#share").slideDown();
        $(this).attr("value", "Embed & Share " + $("<div>").html("&uArr;").text());
    }

Cela affiche à nouveau ⇓ dans le bouton. J'espère que cela pourrait aider quelqu'un.

philippe
la source
Le plus simple serait d'utiliser une séquence d'échappement unicode (c'est-à-dire "Embed & Share \u21d1"), ou mieux encore "Embed & Share ⇑"si vous êtes en mesure de servir votre script en UTF-8 (ou UTF-16, ou tout autre encodage prenant en charge le caractère ⇑). Utiliser un élément DOM pour analyser une entité HTML juste pour créer un caractère unicode arbitraire dans une chaîne JavaScript est une approche astucieuse et créative qui rendrait Rube Goldberg fier, mais ce n'est pas une bonne pratique; les échappements unicode sont dans le langage spécifiquement pour gérer ce cas d'utilisation.
Mark Amery
0

Vous devez créer une fonction personnalisée pour les entités html:

function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
}
Ali
la source
Je n'en ai aucune idée, ça m'a aidé donc +1 l-)
Szymon Toda
il a peut-être été rejeté parce qu'il ne gère que certaines entités.
Jasen
La question initiale était de savoir comment décoder les entités - cela fait le contraire de ce qui est souhaité; il code un ensemble extrêmement limité de caractères en entités. Comme l'indique l'info-bulle du vote négatif, «Cette réponse n'est pas utile». Je suis surpris qu'après 4 ans, il ait toujours un score net positif.
Stephen P
0

Supposons que vous ayez sous String.

Nos cabines de luxe sont chaleureuses, confortables & amp; confortable

var str = $("p").text(); // get the text from <p> tag
$('p').html(str).text();  // Now,decode html entities in your variable i.e 

str et attribuer à nouveau

marque.

c'est tout.

Anirudh Sood
la source
0

Pour les utilisateurs ExtJS, si vous avez déjà la chaîne codée, par exemple lorsque la valeur retournée d'une fonction de bibliothèque est le contenu innerHTML, considérez cette fonction ExtJS:

Ext.util.Format.htmlDecode(innerHtmlContent)
Ilan
la source
Cela ne fonctionnera que pour 5 entités HTML. Vous pouvez le voir dans la documentation et le code source .
et
0

Étendez une classe String:

String::decode = ->
  $('<textarea />').html(this).text()

et utiliser comme méthode:

"&lt;img src='myimage.jpg'&gt;".decode()
Sergio Belevskij
la source
0

Essaye ça :

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

parseHTML est une fonction dans la bibliothèque Jquery et elle renverra un tableau qui inclut quelques détails sur la chaîne donnée.

dans certains cas, la chaîne est grande, de sorte que la fonction séparera le contenu de nombreux index.

et pour obtenir toutes les données d'index, vous devez aller dans n'importe quel index, puis accéder à l'index appelé "wholeText".

J'ai choisi l'index 0 car il fonctionnera dans tous les cas (petite chaîne ou grande chaîne).

Fawaz Al Romy
la source
Bien que cet extrait de code puisse être la solution, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir et que ces personnes ne connaissent peut-être pas les raisons de votre suggestion de code.
Johan
L'explication est ajoutée ... Merci :)
Fawaz Al Romy
-1

Voici encore un problème: la chaîne échappée ne semble pas lisible lorsqu'elle est affectée à la valeur d'entrée

var string = _.escape("<img src=fake onerror=alert('boo!')>");
$('input').val(string);

Exapmle: https://jsfiddle.net/kjpdwmqa/3/

Lauris Kuznecovs
la source
Ce n'est pas une réponse à la question. OP demande de décoder (décompresser) l'entité HTML, mais dans cette réponse, vous utilisez la escapeméthode Underscore.js. Il n'y a également aucune explication sur la façon dont votre exemple de code devrait résoudre le problème d'OP.
et
-1

Alternativement, il existe également une bibliothèque pour cela.

ici, https://cdnjs.com/libraries/he

npm install he                 //using node.js

<script src="js/he.js"></script>  //or from your javascript directory

L'utilisation est la suivante ...

//to encode text 
he.encode('© Ande & Nonso® Company LImited 2018');  

//to decode the 
he.decode('&copy; Ande &amp; Nonso&reg; Company Limited 2018');

à votre santé.

Ande Caleb
la source
Il existe déjà une réponse à propos de la bibliothèque he qui est complète, avec un exemple de code simple et une bonne explication pourquoi et quand devriez-vous utiliser la bibliothèque he .
et
-3

Pour décoder des entités HTML avec jQuery, utilisez simplement cette fonction:

function html_entity_decode(txt){
    var randomID = Math.floor((Math.random()*100000)+1);
    $('body').append('<div id="random'+randomID+'"></div>');
    $('#random'+randomID).html(txt);
    var entity_decoded = $('#random'+randomID).html();
    $('#random'+randomID).remove();
    return entity_decoded;
}

Comment utiliser:

Javascript:

var txtEncoded = "&aacute; &eacute; &iacute; &oacute; &uacute;";
$('#some-id').val(html_entity_decode(txtEncoded));

HTML:

<input id="some-id" type="text" />
Fred
la source
-3

Le moyen le plus simple consiste à définir un sélecteur de classe sur vos éléments et à utiliser le code suivant:

$(function(){
    $('.classSelector').each(function(a, b){
        $(b).html($(b).text());
    });
});

Rien de plus nécessaire!

J'ai eu ce problème et j'ai trouvé cette solution claire et cela fonctionne bien.

Hamidreza
la source
Ce n'est pas une réponse à la question d'OP. OP demande de décoder les entités HTML dans STRING, NON seulement cela ne résout pas le problème de l'OP mais il remplace également les entités HTML échappées dans l'élément HTML par celles qui sont conçues, ce qui ne devrait pas être fait.
et
-3

Je pense que c'est exactement le contraire de la solution choisie.

var decoded = $("<div/>").text(encodedStr).html();
Pedro
la source