Question Codage HTML perdu lorsque l'attribut est lu dans le champ de saisie


J'utilise JavaScript pour extraire une valeur d'un champ masqué et l'afficher dans une zone de texte. La valeur dans le champ masqué est codée.

Par exemple,

<input id='hiddenId' type='hidden' value='chalk &amp; cheese' />

se fait tirer dans

<input type='text' value='chalk &amp; cheese' />

via un certain jQuery pour obtenir la valeur du champ caché (c'est à ce moment que je perds l'encodage):

$('#hiddenId').attr('value')

Le problème est que quand je lis chalk &amp; cheese du champ caché, JavaScript semble perdre l'encodage. Pour échapper à " et ', Je veux que l'encodage reste.

Existe-t-il une bibliothèque JavaScript ou une méthode jQuery qui code HTML une chaîne?


692
2017-08-02 21:08


origine


Réponses:


J'utilise ces fonctions:

function htmlEncode(value){
  // Create a in-memory div, set its inner text (which jQuery automatically encodes)
  // Then grab the encoded contents back out. The div never exists on the page.
  return $('<div/>').text(value).html();
}

function htmlDecode(value){
  return $('<div/>').html(value).text();
}

Fondamentalement, un élément div est créé en mémoire, mais il n'est jamais ajouté au document.

Sur le htmlEncode fonction que je définis le innerText de l'élément, et récupérer le codé innerHTML; sur le htmlDecode fonction que je définis le innerHTML la valeur de l'élément et la innerText est récupéré.

Vérifier un exemple en cours ici.


1029
2017-08-02 22:03



L'astuce jQuery n'encode pas les guillemets et dans IE, elle supprimera vos espaces.

Basé sur échapper templatetag dans Django, qui je suppose est fortement utilisé / testé déjà, j'ai fait cette fonction qui fait ce qui est nécessaire.

Il est sans doute plus simple (et peut-être plus rapide) que toutes les solutions de contournement pour le problème d'effacement des espaces - et il code les guillemets, ce qui est essentiel si vous voulez utiliser le résultat dans une valeur d'attribut par exemple.

function htmlEscape(str) {
    return str
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');
}

// I needed the opposite function today, so adding here too:
function htmlUnescape(str){
    return str
        .replace(/&quot;/g, '"')
        .replace(/&#39;/g, "'")
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&amp;/g, '&');
}

Mise à jour le 2013-06-17:
Dans la recherche de l'échappement le plus rapide, j'ai trouvé cette implémentation d'un replaceAll méthode:
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(également référencé ici: Méthode la plus rapide pour remplacer toutes les occurrences d'un caractère dans une chaîne)
Quelques résultats de performance ici:
http://jsperf.com/htmlencoderegex/25

Il donne la chaîne de résultat identique à l'intégré replace chaînes ci-dessus. Je serais très heureux si quelqu'un pouvait expliquer pourquoi c'est plus rapide!

Mise à jour 2015-03-04:
Je viens de remarquer qu'AngularJS utilise exactement la méthode ci-dessus:
https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js#L435

Ils ajoutent quelques raffinements - ils semblent gérer un problème Unicode obscur ainsi que la conversion de tous les caractères non alphanumériques en entités. J'étais sous l'impression que ce dernier n'était pas nécessaire tant que vous avez un jeu de caractères UTF8 spécifié pour votre document.

Je noterai que (4 ans plus tard) Django ne fait toujours aucune de ces choses, donc je ne suis pas sûr de leur importance:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44

Mise à jour 2016-04-06:
Vous pouvez également souhaiter échapper à la barre oblique /. Ceci n'est pas requis pour l'encodage HTML correct, mais il est recommandé par OWASP comme mesure de sécurité anti-XSS. (merci à @JNF de suggérer cela dans les commentaires)

        .replace(/\//g, '&#x2F;');

524
2017-08-19 15:41



Voici une version non-jQuery qui est considérablement plus rapide que les deux jQuery .html()version et la .replace() version. Cela préserve tous les espaces, mais comme la version de jQuery, ne gère pas les guillemets.

function htmlEncode( html ) {
    return document.createElement( 'a' ).appendChild( 
        document.createTextNode( html ) ).parentNode.innerHTML;
};

La vitesse:  http://jsperf.com/htmlencoderegex/17

speed test

Démonstration  jsFiddle

Sortie:

output

Scénario:

function htmlEncode( html ) {
    return document.createElement( 'a' ).appendChild( 
        document.createTextNode( html ) ).parentNode.innerHTML;
};

function htmlDecode( html ) {
    var a = document.createElement( 'a' ); a.innerHTML = html;
    return a.textContent;
};

document.getElementById( 'text' ).value = htmlEncode( document.getElementById( 'hidden' ).value );

//sanity check
var html = '<div>   &amp; hello</div>';
document.getElementById( 'same' ).textContent = 
      'html === htmlDecode( htmlEncode( html ) ): ' 
    + ( html === htmlDecode( htmlEncode( html ) ) );

HTML:

<input id="hidden" type="hidden" value="chalk    &amp; cheese" />
<input id="text" value="" />
<div id="same"></div>

76
2018-03-11 20:48



Je sais que c'est un ancien, mais je voulais poster une variation de la réponse acceptée cela fonctionnera dans IE sans enlever les lignes:

function multiLineHtmlEncode(value) {
    var lines = value.split(/\r\n|\r|\n/);
    for (var i = 0; i < lines.length; i++) {
        lines[i] = htmlEncode(lines[i]);
    }
    return lines.join('\r\n');
}

function htmlEncode(value) {
    return $('<div/>').text(value).html();
} 

32
2017-10-26 16:32



Souligner fournit _.escape() et _.unescape() méthodes qui font cela.

> _.unescape( "chalk &amp; cheese" );
  "chalk & cheese"

> _.escape( "chalk & cheese" );
  "chalk &amp; cheese"

28
2018-01-10 15:04



Bonne réponse. Notez que si la valeur à encoder est undefined ou null avec jQuery 1.4.2, vous pourriez obtenir des erreurs telles que:

jQuery("<div/>").text(value).html is not a function

OU

Uncaught TypeError: Object has no method 'html'

La solution consiste à modifier la fonction pour vérifier une valeur réelle:

function htmlEncode(value){ 
    if (value) {
        return jQuery('<div/>').text(value).html(); 
    } else {
        return '';
    }
}

12
2017-11-02 22:40



Pour ceux qui préfèrent le javascript simple, voici la méthode que j'ai utilisée avec succès:

function escapeHTML (str)
{
    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;
}

9
2017-10-12 21:13



Prototype a-t-il intégré dans le Classe de corde. Donc, si vous utilisez / planifiez d'utiliser Prototype, il fait quelque chose comme:

'<div class="article">This is an article</div>'.escapeHTML();
// -> "&lt;div class="article"&gt;This is an article&lt;/div&gt;"

5
2017-08-02 21:17



FWIW, l'encodage n'est pas perdu. L'encodage est utilisé par l'analyseur de balisage (navigateur) pendant le chargement de la page. Une fois que la source est lue et analysée et que le navigateur a chargé le DOM en mémoire, le codage a été analysé en fonction de ce qu'il représente. Ainsi, au moment où votre JS s'exécute pour lire quelque chose en mémoire, le char obtenu est ce que l'encodage représente.

Je peux opérer strictement sur la sémantique ici, mais je voulais que vous compreniez le but de l'encodage. Le mot "perdu" donne l'impression que quelque chose ne fonctionne pas comme il le devrait.


5
2018-01-24 12:13



Plus rapide sans Jquery. Vous pouvez encoder tous les caractères de votre chaîne:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

Vous pouvez également vous soucier des caractères principaux (&,, inebreaks, <,>, "et") comme:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

test.value=encode('Encode HTML entities!\n\n"Safe" escape <script id=\'\'> & useful in <pre> tags!');

testing.innerHTML=test.value;

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55"></textarea>

<div id="testing">www.WHAK.com</div>


5
2017-07-26 13:49