HTML-la codificación se pierde cuando el atributo se lee desde el campo de entrada


Estoy usando JavaScript para extraer un valor de un campo oculto y mostrarlo en un cuadro de texto. El valor en el campo oculto está codificado.

Por ejemplo,

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

Es arrastrado hacia

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

A través de algún jQuery para obtener el valor del campo oculto (es en este punto que pierdo la codificación):

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

El problema es que cuando leo chalk &amp; cheese desde el campo oculto, JavaScript parece perder la codificación. Para escapar " y ', quiero que la codificación permanecer.

¿Hay una biblioteca JavaScript o un método jQuery que codifique HTML una cadena?

Author: nothingisnecessary, 2009-08-03

22 answers

Utilizo estas funciones:

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();
}

Básicamente se crea un elemento div en memoria, pero nunca se añade al documento.

En la función htmlEncode establezco el innerText del elemento, y recupero el codificado innerHTML; en la función htmlDecode establezco el valor innerHTML del elemento y se recupera el innerText.

Marque un ejemplo en ejecución aquí.

 1036
Author: CMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-17 16:19:50

El truco de jQuery no codifica comillas y en IE eliminará tu espacio en blanco.

Basado en el escape templatetag en Django, que supongo que ya está muy usado/probado, hice esta función que hace lo que se necesita.

Podría decirse que es más simple (y posiblemente más rápido) que cualquiera de las soluciones para el problema de eliminación de espacios en blanco , y codifica comillas, lo cual es esencial si va a usar el resultado dentro de un valor de atributo para ejemplo.

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, '&');
}

Actualizar 2013-06-17:
En la búsqueda del escape más rápido he encontrado esta implementación de un método replaceAll :
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(también se hace referencia aquí: Método más rápido para reemplazar todas las instancias de un carácter en una cadena )
Algunos resultados de rendimiento aquí:
http://jsperf.com/htmlencoderegex/25

Da una cadena de resultado idéntica a las cadenas incorporadas replace arriba. ¡Sería muy feliz si alguien pudiera explicar por qué es más rápido!?

Actualizar 2015-03-04:
Acabo de notar que AngularJS están utilizando exactamente el método above:
https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js#L435

Agregan un par de refinamientos - parecen estar manejando un problema de Unicode oscuro así como convirtiendo todos los caracteres no alfanuméricos en entidades. Tenía la impresión de que este último era no es necesario siempre y cuando tenga un conjunto de caracteres UTF8 especificado para su documento.

Observaré que (4 años después) Django todavía no hace ninguna de estas cosas, por lo que no estoy seguro de cuán importantes son:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44

Actualizar 2016-04-06:
También es posible que desee escapar de la barra diagonal /. Esto no es necesario para la codificación HTML correcta, sin embargo es recomendado por OWASP como un medida de seguridad anti-XSS. (gracias a @JNF por sugerir esto en los comentarios)

        .replace(/\//g, '&#x2F;');
 532
Author: Anentropic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59

Aquí hay una versión que no es de jQuery que es considerablemente más rápida que la versión de jQuery .html() y la versión de .replace(). Esto preserva todos los espacios en blanco, pero al igual que la versión de jQuery, no maneja comillas.

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

Velocidad: http://jsperf.com/htmlencoderegex/17

ensayo de velocidad

Demo: jsFiddle

Salida:

salida

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>   &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
Author: ThinkingStiff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-11 21:06:34

Sé que esto es antiguo, pero quería publicar una variación de la respuesta aceptada que funcionará en IE sin eliminar líneas:

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
Author: boca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59

Underscore proporciona _.escape() y _.unescape() métodos que hacen esto.

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

> _.escape( "chalk & cheese" );
  "chalk &amp; cheese"
 28
Author: TJ VanToll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-10 15:04:59

Buena respuesta. Tenga en cuenta que si el valor a codificar es undefined o null con jQuery 1.4.2 puede obtener errores como:

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

O

Uncaught TypeError: Object has no method 'html'

La solución es modificar la función para comprobar un valor real:

function htmlEncode(value){ 
    if (value) {
        return jQuery('<div/>').text(value).html(); 
    } else {
        return '';
    }
}
 12
Author: leepowers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-02 22:40:13

Para aquellos que prefieren javascript simple, aquí está el método que he utilizado con éxito:

function escapeHTML (str)
{
    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;
}
 9
Author: backtestbroker.com,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-12 21:13:14

Prototype lo tiene incorporado en la clase de cadena . Así que si estás usando/planeas usar Prototype, hace algo como:

'<div class="article">This is an article</div>'.escapeHTML();
// -> "&lt;div class="article"&gt;This is an article&lt;/div&gt;"
 5
Author: Sinan Taifour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-02 21:17:14

FWIW, la codificación no se pierde. La codificación es utilizada por el analizador de marcado (navegador) durante la carga de la página. Una vez que se lee y analiza la fuente y el navegador tiene el DOM cargado en la memoria, la codificación se ha analizado en lo que representa. Así que por el momento su JS se ejecuta para leer cualquier cosa en la memoria, el carácter que obtiene es lo que la codificación representada.

Puede que esté operando estrictamente en semántica aquí, pero quería que entendieran el propósito de la codificación. Palabra "perdido" hace que suene como si algo no estuviera funcionando como debería.

 5
Author: JAAulde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-24 12:13:28

Más rápido sin Jquery. Puedes codificar cada carácter en tu cadena:

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

O simplemente dirígete a los personajes principales de los que preocuparte ( & , inebreaks,, " y ') como:

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
Author: Dave Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-26 14:16:45

Aquí hay una solución simple de javascript. Extiende el objeto String con un método "HtmlEncode" que se puede usar en un objeto sin parámetro, o con un parámetro.

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("æåøåæå"))

He creado un gist "método HtmlEncode para javascript".

 4
Author: Netsi1964,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-12 06:33:47

No debería tener que escapar/codificar valores para transferirlos de un campo de entrada a otro.

<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 no va insertando HTML sin procesar ni nada; solo le dice al DOM que establezca la propiedad value (o atributo; no estoy seguro). De cualquier manera, el DOM maneja cualquier problema de codificación por usted. A menos que esté haciendo algo extraño como usar document.write o eval, la codificación HTML será efectivamente transparente.

Si estás hablando de generar un nuevo cuadro de texto para mantener result...it ' s igual de fácil. Simplemente pase la parte estática del HTML a jQuery, y luego establezca el resto de las propiedades/atributos en el objeto que le devuelve.

$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());
 2
Author: cHao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 16:09:32

Tuve un problema similar y lo resolví usando la función encodeURIComponent de JavaScript ( documentación )

Por ejemplo, en su caso si utiliza:

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

Y

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

Obtendrá chalk%20%26%20cheese. Incluso los espacios se mantienen.

En mi caso, tuve que codificar una barra invertida y este código funciona perfectamente

encodeURIComponent('name/surname')

Y tengo name%2Fsurname

 2
Author: Dmyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-05 23:00:30

Basado en sanitize de angular... (sintaxis del módulo 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, '&lt;');
  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, '&amp;').
    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, '&lt;').
    replace(/>/g, '&gt;');
}

export default {encode,decode};
 2
Author: Tracker1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-19 23:01:12

Afaik no hay ningún método sencillo de codificar/Decodificar HTML en javascript.

Sin embargo, lo que puede hacer es usar JS para crear un elemento arbitrario, establecer su texto interno y luego leerlo usando innerHTML.

Digamos, con jQuery esto debería funcionar:

var helper = $('chalk & cheese').hide().appendTo('body');
var htmled = helper.html();
helper.remove();

O algo por el estilo

 1
Author: Ken Egozi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-17 11:20:19

Si desea utilizar jQuery. Encontré esto:

Http://www.jquerysdk.com/api/jQuery.htmlspecialchars

(parte de jquery.string plugin ofrecido por jQuery SDK)

El problema con Prototype creo que es que extiende los objetos base en JavaScript y será incompatible con cualquier jQuery que haya utilizado. Por supuesto, si ya está utilizando Prototype y no jQuery, no será un problema.

EDITAR: También hay esto, que es un puerto de Prototipo utilidades de cadena para jQuery:

Http://stilldesigning.com/dotstring /

 1
Author: Sam Saint-Pettersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-25 20:35:11
var htmlEnDeCode = (function() {
    var charToEntityRegex,
        entityToCharRegex,
        charToEntity,
        entityToChar;

    function resetCharacterEntities() {
        charToEntity = {};
        entityToChar = {};
        // add the default set
        addCharacterEntities({
            '&amp;'     :   '&',
            '&gt;'      :   '>',
            '&lt;'      :   '<',
            '&quot;'    :   '"',
            '&#39;'     :   "'"
        });
    }

    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
    };
})();

Esto es del código fuente de ExtJS.

 1
Author: WaiKit Kung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-02 10:42:02
<script>
String.prototype.htmlEncode = function () {
    return String(this)
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');

}

var aString = '<script>alert("I hack your site")</script>';
console.log(aString.htmlEncode());
</script>

Producirá: &lt;script&gt;alert(&quot;I hack your site&quot;)&lt;/script&gt;

.HtmlEncode () será accesible en todas las cadenas una vez definidas.

 1
Author: Stuart Eske,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-03 14:11:39

Htmlencodifica el valor dado

  var htmlEncodeContainer = $('<div />');
  function htmlEncode(value) {
    if (value) {
      return htmlEncodeContainer.text(value).html();
    } else {
      return '';
    }
  }
 1
Author: Sky Yip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-20 03:04:53

Me encontré con algunos problemas con la barra invertida en mi cadena Domain\User.

He añadido esto a los otros escapes de la respuesta de Anentropic

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

Que encontré aquí: ¿Cómo escapar de la barra invertida en JavaScript?

 1
Author: spacebread,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:42

Aquí hay un poco que emula la función Server.HTMLEncode del ASP de Microsoft, escrita en JavaScript puro:

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;
}

El resultado no codifica apóstrofes, pero codifica los otros especiales HTML y cualquier carácter fuera del rango 0x20-0x7e.

 1
Author: ReWrite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-20 17:40:21

Escogiendo lo que escapeHTML() está haciendo en el prototipo.js

Añadir este script te ayuda a escapeHtml:

String.prototype.escapeHTML = function() { 
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
}

Ahora puedes llamar al método escapeHtml en cadenas en tu script, como:

var escapedString = "<h1>this is HTML</h1>".escapeHTML();
// gives: "&lt;h1&gt;this is HTML&lt;/h1&gt;"

Espero que ayude a cualquiera que busque una solución simple sin tener que incluir el prototipo completo.js

 0
Author: new_user,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-22 13:20:10