HTML-encoding perdu lorsque l'attribut est lu depuis le champ d'entrée
J'utilise JavaScript pour extraire une valeur d'un champ caché et l'afficher dans une zone de texte. La valeur dans le champ caché est codée.
par exemple,
<input id='hiddenId' type='hidden' value='chalk & cheese' />
est tiré dans
<input type='text' value='chalk & cheese' />
via un 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 & cheese
de la caché field, 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 encodera HTML une chaîne de caractères?
22 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 la fonction htmlEncode
j'ai mis la valeur innerText
de l'élément, et j'ai récupéré le code innerHTML
; sur la fonction htmlDecode
j'ai mis la valeur innerHTML
de l'élément et le innerText
est récupéré.
Vérification de l'exécution d'un exemple ici .
le jquery trick ne Code pas les guillemets et dans IE il va dépouiller votre espace blanc.
basé sur le escape templatetag à Django, qui je suppose est déjà largement utilisé/testé, j'ai fait cette fonction qui fait ce qui est nécessaire.
c'est sans doute plus simple (et peut-être plus rapide) que n'importe laquelle des solutions de rechange pour le problème de strippage des espaces - et il Code les guillemets, ce qui est essentiel si vous allez utiliser le résultat à l'intérieur d'une valeur d'attribut par exemple.
function htmlEscape(str) {
return str
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
// I needed the opposite function today, so adding here too:
function htmlUnescape(str){
return str
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
}
mise à Jour 2013-06-17:
Dans la recherche des échappées les plus rapides j'ai trouvé cette implémentation d'une méthode replaceAll
:
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 chaîne de résultat identique à la chaîne intégrée replace
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 que les AngularJS utilisent 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'avais 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 vais noter que (4 ans plus tard) Django ne fait toujours pas l'une de ces choses, donc je ne suis pas sûr à quel point ils sont importants:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44
mise à Jour 2016-04-06:
Vous pouvez également vouloir échapper à l'avant-slash /
. Ce n'est pas nécessaire pour le codage HTML correct, mais c'est recommandé par L'OWASP comme mesure de sécurité anti-XSS. (merci à @JNF pour avoir suggéré ceci dans les commentaires)
.replace(/\//g, '/');
Voici une version non-jQuery qui est considérablement plus rapide que la version .html()
et la version .replace()
. Cela préserve tout espace blanc, mais comme la version jQuery, ne gère pas les citations.
function htmlEncode( html ) {
return document.createElement( 'a' ).appendChild(
document.createTextNode( html ) ).parentNode.innerHTML;
};
vitesse: http://jsperf.com/htmlencoderegex/17
sortie:
Script:
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> & hello</div>';
document.getElementById( 'same' ).textContent =
'html === htmlDecode( htmlEncode( html ) ): '
+ ( html === htmlDecode( htmlEncode( html ) ) );
HTML:
<input id="hidden" type="hidden" value="chalk & cheese" />
<input id="text" value="" />
<div id="same"></div>
je sais que c'est un vieux, mais je voulais poster une variation de la réponse acceptée qui 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();
}
"Underscore fournit _.escape()
et _.unescape()
méthodes qui font cela.
> _.unescape( "chalk & cheese" );
"chalk & cheese"
> _.escape( "chalk & cheese" );
"chalk & cheese"
bonne réponse. Notez que si la valeur à Encoder est undefined
ou null
avec jQuery 1.4.2 vous pourriez avoir des erreurs telles que:
jQuery("<div/>").text(value).html is not a function
ou
Uncaught TypeError: Object has no method 'html'
La solution est de modifier la fonction pour vérifier une valeur réelle:
function htmlEncode(value){
if (value) {
return jQuery('<div/>').text(value).html();
} else {
return '';
}
}
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;
}
Prototype a été intégré dans la classe String . Donc, si vous utilisez / prévoyez d'utiliser Prototype, il fait quelque chose comme:
'<div class="article">This is an article</div>'.escapeHTML();
// -> "<div class="article">This is an article</div>"
FWIW, l'encodage n'est pas perdu. L'encodage est utilisé par le markup parser (browser) pendant le chargement de la page. Une fois que la source est lue et analysée et que le navigateur a le DOM chargé dans la mémoire, l'encodage a été analysé dans ce qu'il représente. Donc au moment où votre JS est exécuté pour lire n'importe quoi en mémoire, le char qu'il obtient Est ce que l'encodage a représenté.
il se peut que je travaille strictement sur la sémantique ici, mais je voulais que vous compreniez le but de encodage. Le mot "perdu" donne l'impression que quelque chose ne fonctionne pas comme prévu.
plus rapide sans Jquery. Vous pouvez encoder chaque caractère de votre chaîne:
function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
ou tout simplement cibler les caractères principaux à s'inquiéter ( & , 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 &ersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55"></textarea>
<div id="testing">www.WHAK.com</div>
Voici une solution javascript simple. Il étend L'objet String avec une méthode "HTMLEncode" qui peut être utilisée sur un objet sans paramètre, ou avec un paramètre.
String.prototype.HTMLEncode = function(str) {
var result = "";
var str = (arguments.length===1) ? str : this;
for(var i=0; i<str.length; i++) {
var chrcode = str.charCodeAt(i);
result+=(chrcode>128) ? "&#"+chrcode+";" : str.substr(i,1)
}
return result;
}
// TEST
console.log("stetaewteaw æø".HTMLEncode());
console.log("stetaewteaw æø".HTMLEncode("æåøåæå"))
j'ai fait un gist" HtmlEncode méthode pour javascript " .
vous ne devriez pas avoir à échapper/encoder des valeurs pour les faire passer d'un champ d'entrée à un autre.
<form>
<input id="button" type="button" value="Click me">
<input type="hidden" id="hiddenId" name="hiddenId" value="I like cheese">
<input type="text" id="output" name="output">
</form>
<script>
$(document).ready(function(e) {
$('#button').click(function(e) {
$('#output').val($('#hiddenId').val());
});
});
</script>
JS ne va pas insérer de HTML brut ou quoi que ce soit; il dit juste au DOM de définir la propriété value
(ou l'attribut; pas sûr). Dans tous les cas, le DOM s'occupe des problèmes d'encodage pour vous. À moins que vous ne fassiez quelque chose de bizarre comme utiliser document.write
ou eval
, l'encodage HTML sera effectivement transparent.
si vous parlez de générer une nouvelle boîte de texte pour maintenir le résultat...c'est toujours aussi facile. Il suffit de passer la partie statique du HTML à jQuery, puis de définir le reste des propriétés/attributs sur l'objet qu'il vous renvoie.
$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());
j'ai eu un problème similaire et le résoudre en utilisant la fonction encodeURIComponent
de JavaScript ( documentation )
Par exemple, dans votre cas, si vous utilisez:
<input id='hiddenId' type='hidden' value='chalk & cheese' />
et
encodeURIComponent($('#hiddenId').attr('value'))
, vous obtiendrez chalk%20%26%20cheese
. Même les espaces sont conservés.
dans mon cas, j'ai dû encoder un antislash et ce code fonctionne parfaitement
encodeURIComponent('name/surname')
et j'ai eu name%2Fsurname
Basé sur angulaire de désinfecter ... (syntaxe du module es6)
// ref: https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js
const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
const NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
const decodeElem = document.createElement('pre');
/**
* Decodes html encoded text, so that the actual string may
* be used.
* @param value
* @returns {string} decoded text
*/
export function decode(value) {
if (!value) return '';
decodeElem.innerHTML = value.replace(/</g, '<');
return decodeElem.textContent;
}
/**
* Encodes all potentially dangerous characters, so that the
* resulting string can be safely inserted into attribute or
* element text.
* @param value
* @returns {string} encoded text
*/
export function encode(value) {
if (value === null || value === undefined) return '';
return String(value).
replace(/&/g, '&').
replace(SURROGATE_PAIR_REGEXP, value => {
var hi = value.charCodeAt(0);
var low = value.charCodeAt(1);
return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
}).
replace(NON_ALPHANUMERIC_REGEXP, value => {
return '&#' + value.charCodeAt(0) + ';';
}).
replace(/</g, '<').
replace(/>/g, '>');
}
export default {encode,decode};
afaik il n'y a pas de méthode directe D'encodage/décodage HTML dans javascript.
cependant, ce que vous pouvez faire, c'est d'utiliser JS pour créer un élément arbitraire, définir son texte intérieur, puis le lire en utilisant innerHTML.
dire, avec jQuery, cela devrait fonctionner:
var helper = $('chalk & cheese').hide().appendTo('body');
var htmled = helper.html();
helper.remove();
ou quelque chose le long de ces lignes
si vous voulez utiliser jQuery. J'ai trouvé ceci:
http://www.jquerysdk.com/api/jQuery.htmlspecialchars
(partie de jquery.string plugin offert par jQuery SDK)
le problème avec Prototype I believe est qu'il étend les objets de base en JavaScript et sera incompatible avec tout jQuery que vous avez pu utiliser. Bien sûr, si vous utilisez déjà Prototype et pas jQuery, ce ne sera pas un problème.
EDIT: il y a aussi ceci, qui est un port des utilités de chaîne de Prototype pour jQuery:
var htmlEnDeCode = (function() {
var charToEntityRegex,
entityToCharRegex,
charToEntity,
entityToChar;
function resetCharacterEntities() {
charToEntity = {};
entityToChar = {};
// add the default set
addCharacterEntities({
'&' : '&',
'>' : '>',
'<' : '<',
'"' : '"',
''' : "'"
});
}
function addCharacterEntities(newEntities) {
var charKeys = [],
entityKeys = [],
key, echar;
for (key in newEntities) {
echar = newEntities[key];
entityToChar[key] = echar;
charToEntity[echar] = key;
charKeys.push(echar);
entityKeys.push(key);
}
charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
}
function htmlEncode(value){
var htmlEncodeReplaceFn = function(match, capture) {
return charToEntity[capture];
};
return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
}
function htmlDecode(value) {
var htmlDecodeReplaceFn = function(match, capture) {
return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
};
return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
}
resetCharacterEntities();
return {
htmlEncode: htmlEncode,
htmlDecode: htmlDecode
};
})();
extrait du code source D'ExtJS.
<script>
String.prototype.htmlEncode = function () {
return String(this)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
var aString = '<script>alert("I hack your site")</script>';
console.log(aString.htmlEncode());
</script>
sortira: <script>alert("I hack your site")</script>
.htmlEncode () sera accessible sur toutes les chaînes une fois définies.
HtmlEncodes la valeur donnée
var htmlEncodeContainer = $('<div />');
function htmlEncode(value) {
if (value) {
return htmlEncodeContainer.text(value).html();
} else {
return '';
}
}
j'ai rencontré quelques problèmes avec backslash dans ma chaîne Domain\User.
j'ai ajouté ceci aux autres évasions de la réponse D'Anentropic
.replace(/\/g, '\')
que j'ai trouvé ici: comment échapper à backslash en JavaScript?
voici un petit morceau qui émule la fonction Server.HTMLEncode
de Microsoft ASP, écrite en JavaScript pur:
function htmlEncode(s) {
var ntable = {
"&": "amp",
"<": "lt",
">": "gt",
"\"": "quot"
};
s = s.replace(/[&<>"]/g, function(ch) {
return "&" + ntable[ch] + ";";
})
s = s.replace(/[^ -\x7e]/g, function(ch) {
return "&#" + ch.charCodeAt(0).toString() + ";";
});
return s;
}
le résultat ne Code pas les apostrophes, mais code les autres Spéciaux HTML et tout caractère en dehors de la gamme 0x20-0x7e.
la Cueillette de ce escapeHTML()
est en train de faire dans le prototype.js
L'ajout de ce script vous aide à vous échapper:
String.prototype.escapeHTML = function() {
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')
}
maintenant vous pouvez appeler la méthode escapeHTML sur les chaînes dans votre script, comme:
var escapedString = "<h1>this is HTML</h1>".escapeHTML();
// gives: "<h1>this is HTML</h1>"
espère que cela aidera quiconque recherche une solution simple sans avoir à inclure le prototype entier.js