it-swarm.com.ru

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 из скрытого поля, JavaScript, похоже, теряет кодировку. Чтобы избежать " и ', я хочу, чтобы кодировка осталась.

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

708
AJM

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

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

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

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

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

1050
CMS

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

Основываясь на шаблонном теге escape в 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 года спустя) Джанго до сих пор не выполняет ни одну из этих вещей, поэтому я не уверен, насколько они важны:
https://github.com/Django/django/blob/1.8b1/Django/utils/html.py#L44

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

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

Вот не-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

Автор сценария:

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

Я знаю, что это старый, но я хотел опубликовать вариант принятый ответ который будет работать в 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();
} 
32
boca

Подчеркнуть предоставляет _.escape() и _.unescape() методы, которые делают это.

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

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

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

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

OR

Uncaught TypeError: Object has no method 'html'

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

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

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

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

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

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

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

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

5
JAAulde

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

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

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

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

Вот простое решение 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" .

4
Netsi1964

Основано на angit's 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};
3
Tracker1

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

JavaScript HTML Entities Кодировать и декодировать

2
Nick Tsai

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

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

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

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

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

2
Ken Egozi

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

<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());
2
cHao

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

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

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

а также

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

вы получите chalk%20%26%20cheese. Даже места сохранены.

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

encodeURIComponent('name/surname')

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

2
Dmyan

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

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

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

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

1
spacebread
<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 () будет доступен для всех строк после определения.

1
Stuart Eske

HtmlEncodes заданное значение

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

Вот немного, который эмулирует функцию 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;
}

Результат не кодирует апострофы, но кодирует другие специальные элементы HTML и любые символы вне диапазона 0x20-0x7e.

1
ReWrite

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

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

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

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

Правка: Также есть это, который является портом строковых утилит Prototype для jQuery:

http://stilldesigning.com/dotstring/

1
Sam Saint-Pettersen
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.

1
WaiKit Kung

Используя некоторые другие ответы здесь, я сделал версию, которая заменяет все соответствующие символы за один проход, независимо от количества различных закодированных символов (только один вызов 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;

0
Hashbrown

Выбор действия 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

0
new_user