HTML-кодирование теряется, когда атрибут читается из поля ввода

Я использую JavaScript, чтобы извлечь значение из скрытого поля и отобразить его в текстовом поле. Значение в скрытом поле закодировано.

Например,

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

втягивается в

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

через некоторый jQuery, чтобы получить значение из скрытого поля (в этот момент я теряю кодировку):

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

Проблема в том, что когда я читаю chalk &amp; cheese chalk &amp; cheese из скрытого поля, JavaScript, похоже, теряет кодировку. Я не хочу, чтобы ценность была chalk & cheese. Я хочу буквальный amp; быть сохраненным.

Есть ли библиотека JavaScript или метод jQuery, который будет кодировать строку в HTML?

Ответ 1

РЕДАКТИРОВАТЬ: Этот ответ был опубликован давно, и функция htmlDecode представил уязвимость XSS. Он был изменен, изменяя временный элемент с div на textarea уменьшая вероятность XSS. Но в настоящее время я бы рекомендовал вам использовать API DOMParser, как это предлагается в других ответах.


Я использую эти функции:

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

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

В основном элемент div создается в памяти, но он никогда не добавляется к документу.

В функции htmlEncode я устанавливаю innerText элемента и извлекаю закодированный innerHTML; в функции htmlDecode я устанавливаю значение innerHTML элемента и извлекаю innerText.

Проверьте работающий пример здесь.

Ответ 2

Трюк jQuery не кодирует метки кавычек, а в IE он лишит ваши пробелы.

На основе escape templatetag в Django, который, как мне кажется, уже давно используется/протестирован, я сделал эту функцию, которая делает то, что нужно.

Он, возможно, проще (и, возможно, быстрее), чем любой из обходных путей для проблемы удаления пробелов - и он кодирует кавычки, что существенно, если вы собираетесь использовать результат внутри значения атрибута, например.

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

Обновление 2013-06-17:
В поисках быстрого ускорения я нашел эту реализацию метода replaceAll:
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(также упоминается здесь: Самый быстрый способ заменить все экземпляры символа в строке)
Некоторые результаты работы здесь:
http://jsperf.com/htmlencoderegex/25

Он дает идентичную строку результата встроенным цепочкам replace выше. Я был бы очень рад, если бы кто-нибудь мог объяснить, почему это быстрее!?

Обновление 2015-03-04:
Я только заметил, что AngularJS использует именно этот метод выше:
https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js#L435

Они добавляют несколько уточнений - они, похоже, обрабатывают непонятную проблему Unicode, а также преобразуют все не-буквенно-цифровые символы в объекты. Мне показалось, что последнее не было необходимым, если у вас есть кодировка UTF8, указанная для вашего документа.

Отмечу, что (4 года спустя) Django все равно не делает ни одной из этих вещей, поэтому я не уверен, насколько они важны:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44

Обновление 2016-04-06:
Вы также можете избежать прокрутки вперед /. Это не требуется для правильной кодировки HTML, однако это рекомендованное OWASP в качестве меры безопасности для предотвращения XSS. (спасибо @JNF за предложение этого в комментариях)

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

Ответ 3

Здесь версия, отличная от jQuery, которая значительно быстрее, чем версия jQuery .html() и версия .replace(). Это сохраняет все пробелы, но, как и версия jQuery, не обрабатывает кавычки.

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

Скорость: http://jsperf.com/htmlencoderegex/17

speed test

Демо: jsFiddle

Вывод:

output

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>

Ответ 4

Я знаю, что это старый, но я хотел опубликовать вариант принятого ответа, который будет работать в IE без удаления строк:

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

Ответ 5

Underscore предоставляет _.escape() и _.unescape(), которые делают это.

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

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

Ответ 6

Хороший ответ. Обратите внимание, что если значение для кодирования составляет undefined или null с jQuery 1.4.2, вы можете получить такие ошибки, как:

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

ИЛИ

Uncaught TypeError: Object has no method 'html'

Решение состоит в том, чтобы изменить функцию, чтобы проверить фактическое значение:

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

Ответ 7

Для тех, кто предпочитает простой javascript, вот метод, который я использовал успешно:

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

Ответ 8

FWIW, кодировка не теряется. Кодировка используется парсером разметки (браузером) во время загрузки страницы. После того, как источник будет прочитан и проанализирован, а браузер загрузит DOM в память, кодировка была проанализирована в том, что она представляет. Таким образом, к тому моменту, когда ваш JS выполняется для чтения чего-либо в памяти, char он получает, что представляет собой кодировка.

Я могу работать строго по семантике здесь, но я хотел, чтобы вы поняли цель кодирования. Слово "потерянное" заставляет его звучать так, будто что-то не работает так, как должно.

Ответ 9

Прототип имеет встроенный класс String. Поэтому, если вы используете/планируете использовать Prototype, он делает что-то вроде:

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

Ответ 10

Быстрее без JQuery. Вы можете кодировать каждый символ в строке:

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

Или просто нацелитесь на главных героев, чтобы беспокоиться (&, inebreaks, <, > , "and '), например:

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>

Ответ 11

Вот простое решение для javascript. Он расширяет объект String с помощью метода "HTMLEncode", который может использоваться для объекта без параметра или с параметром.

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

Я создал gist "метод HTMLEncode для javascript" .

Ответ 12

На основе angular sanitize... (синтаксис модуля 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};

Ответ 13

afaik в javascript нет никаких прямых методов кодирования/декодирования HTML.

Однако, что вы можете сделать, это использовать JS для создания произвольного элемента, установить его внутренний текст, а затем прочитать его с помощью innerHTML.

скажем, с jQuery это должно работать:

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

или что-то в этом роде

Ответ 14

Вам не нужно выходить/кодировать значения, чтобы передавать их из одного поля ввода в другое.

<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 не идет вставлять необработанный HTML-код или что-то еще; он просто сообщает DOM установить свойство value (или атрибут; не уверен). В любом случае, DOM обрабатывает любые проблемы с кодировкой для вас. Если вы не делаете что-то странное, например, используя document.write или eval, HTML-кодирование будет эффективно прозрачным.

Если вы говорите о создании нового текстового поля для хранения результата... это все равно так же просто. Просто передайте статическую часть HTML в jQuery, а затем установите остальные свойства/атрибуты объекта, который он возвращает вам.

$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());

Ответ 15

У меня была аналогичная проблема и решить ее с помощью функции encodeURIComponent из JavaScript (документация)

Например, в вашем случае, если вы используете:

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

и

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

вы получите chalk%20%26%20cheese. Сохраняются даже пробелы.

В моем случае мне пришлось кодировать одну обратную косую черту, и этот код отлично работает

encodeURIComponent('name/surname')

и я получил name%2Fsurname

Ответ 16

Моя функция чистого 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;
}

HTML-объекты JavaScript кодируют и декодируют

Ответ 17

Если вы хотите использовать jQuery. Я нашел это:

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

(часть плагина jquery.string, предлагаемого jQuery SDK)

Проблема с Prototype, я считаю, заключается в том, что она расширяет базовые объекты в JavaScript и будет несовместима с любым jQuery, который вы, возможно, использовали. Конечно, если вы уже используете Prototype, а не jQuery, это не будет проблемой.

РЕДАКТИРОВАТЬ: Также есть это, который является портом строковых утилит Prototype для jQuery:

http://stilldesigning.com/dotstring/

Ответ 18

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

Это из исходного кода ExtJS.

Ответ 19

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

Выведет: &lt;script&gt;alert(&quot;I hack your site&quot;)&lt;/script&gt;

.htmlEncode() будет доступен для всех строк, определенных после определения.

Ответ 20

HtmlEnкодирует заданное значение

  var htmlEncodeContainer = $('<div />');
  function htmlEncode(value) {
    if (value) {
      return htmlEncodeContainer.text(value).html();
    } else {
      return '';
    }
  }

Ответ 21

Я столкнулся с некоторыми проблемами с обратной косой чертой в моей строке "Домен\Пользователь".

Я добавил это к другим экранам из ответа Anentropic

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

Что я нашел здесь: Как избежать обратной косой черты в JavaScript?

Ответ 22

Здесь немного, что эмулирует функцию Server.HTMLEncode из Microsoft ASP, написанную на чистом JavaScript:

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

Ответ 23

Выбор того, что escapeHTML() в prototype.js

Добавление этого скрипта поможет вам избежатьHTML:

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

теперь вы можете вызвать метод escapeHTML для строк в вашем скрипте, например:

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

Надеюсь, что это поможет любому, кто ищет простое решение без необходимости включать весь prototype.js

Ответ 24

Используя некоторые из других ответов здесь, я сделал версию, которая заменяет все соответствующие символы за один проход, независимо от количества различных кодированных символов (только один вызов для replace()), поэтому будет быстрее для больших строк.

Он не полагается на DOM API для существования или в других библиотеках.

window.encodeHTML = (function() {
    function escapeRegex(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    }
    var encodings = {
        '&'  : '&amp;',
        '"'  : '&quot;',
        '\'' : '&#39;',
        '<'  : '&lt;',
        '>'  : '&gt;',
        '\\' : '&#x2F;'
    };
    function encode(what) { return encodings[what]; };
    var specialChars = new RegExp('[' +
        escapeRegex(Object.keys(encodings).join('')) +
    ']', 'g');

    return function(text) { return text.replace(specialChars, encode); };
})();

Запустив это однажды, вы можете позвонить

encodeHTML('<>&"\'')

Чтобы получить &lt;&gt;&amp;&quot;&#39;

Ответ 25

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