J'utilise JavaScript pour extraire une valeur d'un champ caché 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 & cheese' />
est tiré dans
<input type='text' value='chalk & cheese' />
via jQuery pour obtenir la valeur du champ caché (c’est à ce stade que je perds le codage):
$('#hiddenId').attr('value')
Le problème est que, lorsque je lis chalk & cheese
dans le champ masqué, JavaScript semble perdre le codage. Pour échapper à "
et '
, je veux que l'encodage reste.
Existe-t-il une bibliothèque JavaScript ou une méthode jQuery qui encodera une chaîne au format HTML?
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
, je définis la innerText
de l'élément et récupère la valeur encodée innerHTML
; sur la fonction htmlDecode
, je définis la valeur innerHTML
de l'élément et la variable innerText
est extraite.
Vérifiez un exemple en cours d'exécution ici .
L'astuce jQuery ne code pas les guillemets et, dans IE, elle supprime votre espace.
Sur la base du escape templatetag de Django, que je suppose déjà très utilisé/testé, j'ai créé cette fonction qui fait le nécessaire.
C’est sans doute plus simple (et peut-être plus rapide) que l’une quelconque des solutions de contournement pour le problème de suppression d’espaces blancs - et elle 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, '&')
.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 de l'échappement le plus rapide, 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: La 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 une chaîne de résultat identique aux chaînes replace
intégrées 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 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 améliorations - ils semblent gérer un problème obscur Unicode ainsi que convertir 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 spécifié un jeu de caractères UTF8 pour votre document.
Je noterai que (4 ans plus tard) Django ne fait toujours aucune de ces choses, alors 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 à forward-slash /
. Ceci n'est pas nécessaire pour un codage HTML correct. Toutefois, il s'agit de recommandé par OWASP en tant que mesure de sécurité anti-XSS. (merci à @JNF pour l'avoir suggéré dans les commentaires)
.replace(/\//g, '/');
Voici une version non-jQuery qui est considérablement plus rapide que la version jQuery .html()
et la version .replace()
. Cela préserve tous les espaces, mais comme la version jQuery, ne traite pas les guillemets.
function htmlEncode( html ) {
return document.createElement( 'a' ).appendChild(
document.createTextNode( html ) ).parentNode.innerHTML;
};
Speed:http://jsperf.com/htmlencoderegex/17
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 ) ) );
<input id="hidden" type="hidden" value="chalk & cheese" />
<input id="text" value="" />
<div id="same"></div>
Je sais que c’est un vieux problème, mais je voulais publier une variante de la réponse acceptée qui fonctionnera dans IE sans supprimer 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()
les méthodes qui le font.
> _.unescape( "chalk & cheese" );
"chalk & cheese"
> _.escape( "chalk & cheese" );
"chalk & cheese"
Bonne réponse. Notez que si la valeur à coder est undefined
ou null
avec jQuery 1.4.2, des erreurs telles que:
jQuery("<div/>").text(value).html is not a function
OR
Uncaught TypeError: Object has no method 'html'
La solution consiste à modifier la fonction pour rechercher 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;
}
FWIW, l'encodage n'est pas perdu. Le codage est utilisé par l'analyseur de balises (navigateur) lors du chargement de la page. Une fois que la source est lue et analysée et que le DOM a chargé le DOM dans la mémoire, le codage a été analysé dans ce qu’il représente. Donc, au moment où votre JS est exécuté pour lire quelque chose en mémoire, le caractère obtenu correspond à ce que représente le codage.
Ici, je travaille peut-être strictement sur la sémantique, 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 se doit.
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 ciblez simplement les personnages principaux pour vous 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 "méthode HTMLEncode pour javascript" .
Basé sur angular's sanitize ... (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};
Ma fonction pure-JS:
/**
* HTML entities encode
*
* @param {string} str Input text
* @return {string} Filtered text
*/
function htmlencode (str){
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
autant que je sache, il n’existe pas de méthodes simples d’encodage/décodage HTML en javascript.
Cependant, vous pouvez utiliser JS pour créer un élément arbitraire, définir son texte interne, puis le lire à l'aide de innerHTML.
par exemple, avec jQuery, cela devrait fonctionner:
var helper = $('chalk & cheese').hide().appendTo('body');
var htmled = helper.html();
helper.remove();
ou quelque chose dans ce sens
Vous ne devriez pas avoir à échapper/encoder des valeurs pour les faire passer d'un champ de saisie à 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 du HTML brut ou quoi que ce soit; il indique simplement au DOM de définir la propriété value
(ou un attribut; pas sûr). Dans les deux cas, le DOM gère les problèmes d’encodage pour vous. Sauf si vous faites quelque chose de bizarre comme utiliser document.write
ou eval
, le codage HTML sera efficacement transparent.
Si vous parlez de générer une nouvelle zone de texte pour conserver le résultat ... c'est toujours aussi facile. Passez simplement la partie statique du code HTML à jQuery, puis définissez 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 je l'ai résolu 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 une barre oblique inverse et ce code fonctionne parfaitement
encodeURIComponent('name/surname')
et j'ai eu name%2Fsurname
J'ai rencontré des problèmes avec la barre oblique inverse dans ma chaîne Domain\User.
J'ai ajouté ceci aux autres échappatoires de la réponse d'Anentropic
.replace(/\\/g, '\')
Ce que j'ai trouvé ici: Comment échapper à la barre oblique inverse en JavaScript?
<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>
Affichera: <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 '';
}
}
Voici un petit peu qui émule la fonction Server.HTMLEncode
de l'ASP de Microsoft, é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 pas code les apostrophes, mais code les autres promotions HTML et tout caractère en dehors de la plage 0x20-0x7e.
Si vous voulez utiliser jQuery. J'ai trouvé ça:
http://www.jquerysdk.com/api/jQuery.htmlspecialchars
(partie du plugin jquery.string proposé par jQuery SDK)
Le problème avec Prototype, je crois, est qu’il étend les objets de base en JavaScript et sera incompatible avec tout jQuery que vous avez utilisé. 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 utilitaires 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
};
})();
Cela provient du code source ExtJS.
En utilisant certaines des autres réponses ici, j’ai créé une version qui remplace tous les caractères pertinents en un seul passage, quel que soit le nombre de caractères codés distincts (un seul appel à replace()
).
Il ne repose pas sur l'API DOM pour exister ou sur d'autres bibliothèques.
window.encodeHTML = (function() {
function escapeRegex(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
var encodings = {
'&' : '&',
'"' : '"',
'\'' : ''',
'<' : '<',
'>' : '>',
'\\' : '/'
};
function encode(what) { return encodings[what]; };
var specialChars = new RegExp('[' +
escapeRegex(Object.keys(encodings).join('')) +
']', 'g');
return function(text) { return text.replace(specialChars, encode); };
})();
Après avoir couru cette fois, vous pouvez maintenant appeler
encodeHTML('<>&"\'')
Pour obtenir <>&"'
Choisir ce que escapeHTML()
fait dans le prototype.js
L'ajout de ce script vous aide à escapeHTML:
String.prototype.escapeHTML = function() {
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')
}
vous pouvez maintenant appeler la méthode escapeHTML sur les chaînes de votre script, comme suit:
var escapedString = "<h1>this is HTML</h1>".escapeHTML();
// gives: "<h1>this is HTML</h1>"
J'espère que cela aidera toute personne à la recherche d'une solution simple sans avoir à inclure l'intégralité du prototype.js
function encodeHTML(str) {
return document.createElement("a").appendChild(
document.createTextNode(str)).parentNode.innerHTML;
};
function decodeHTML(str) {
var element = document.createElement("a");
element.innerHTML = str;
return element.textContent;
};
var str = "<"
var enc = encodeHTML(str);
var dec = decodeHTML(enc);
console.log("str: " + str, "\nenc: " + enc, "\ndec: " + dec);