HTML-кодировка теряется при чтении атрибута из поля ввода
Я использую JavaScript, чтобы вытащить значение из скрытого поля и отобразить его в текстовом поле. Значение в скрытом поле кодируется.
например,
<input id='hiddenId' type='hidden' value='chalk & cheese' />
встрял в
<input type='text' value='chalk & cheese' />
через некоторый jQuery, чтобы получить значение из скрытого поля (именно в этот момент я теряю кодировку):
$('#hiddenId').attr('value')
проблема в том, что когда я читал chalk & cheese
из скрытого поля JavaScript, похоже, теряет кодировку. Чтобы избежать "
и '
, Я хочу, чтобы кодировка останется.
есть ли библиотека JavaScript или метод jQuery, который будет HTML-кодировать строку?
22 ответа:
Я использую эти функции:
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 создается в памяти, но он никогда не добавляется к документу.
на
трюк jQuery не кодирует кавычки, и в IE он будет лишать вас пробелов.
на основе побег templatetag в Django, который, я думаю, уже сильно используется / тестируется, я сделал эту функцию, которая делает то, что нужно.
это, возможно, проще (и, возможно, быстрее), чем любой из обходных путей для проблемы удаления пробелов - и он кодирует кавычки, что важно, если вы собираетесь использовать результат внутри значения атрибута например.
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, '&'); }
2013-06-17 обновления:
В поисках самого быстрого побега я нашел эту реализациюreplaceAll
метод:
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(также упоминается здесь:самый быстрый способ заменить все экземпляры символа в строке)
Некоторые результаты здесь:
http://jsperf.com/htmlencoderegex/25Он дает идентичную строку результата для встроенного
replace
выше цепи. Я был бы очень рад, если бы кто-нибудь мог объяснить, почему это быстрее!?2015-03-04 обновления:
Я просто заметил, что AngularJS используют именно этот метод above:
https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js#L435они добавляют пару уточнения их обработки неясная проблема Юникода а также преобразование всех не буквенно-цифровых символов в сущности. Я был под впечатлением, что последнее не было необходимо, пока у вас есть кодировка UTF8, указанная для вашего документа.
я отмечу ,что (4 года спустя) Django все еще не делает ни одной из этих вещей, поэтому я не уверен, насколько они важны are:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44обновление 2016-04-06:
Вы также можете бежать вперед-Слэш/
. Это не требуется для правильного кодирования HTML, однако это рекомендуется OWASP как мера безопасности анти-XSS. (спасибо @JNF за предложение этого в комментариях).replace(/\//g, '/');
вот не-jQuery версия, которая значительно быстрее, чем оба jQuery
.html()
версии.replace()
версия. Это сохраняет все пробелы, но, как и версия jQuery, не обрабатывает кавычки.function htmlEncode( html ) { return document.createElement( 'a' ).appendChild( document.createTextNode( html ) ).parentNode.innerHTML; };
скорость: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 ) ) );
HTML:
<input id="hidden" type="hidden" value="chalk & cheese" /> <input id="text" value="" /> <div id="same"></div>
Я знаю, что это старый, но я хотел разместить вариант принято отвечать что будет работать в 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(); }
подчеркивание предоставляет
_.escape()
и_.unescape()
методы, которые делают это.> _.unescape( "chalk & cheese" ); "chalk & cheese" > _.escape( "chalk & cheese" ); "chalk & cheese"
хороший ответ. Обратите внимание, что если значение для кодирования
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 ''; } }
для тех, кто предпочитает простой javascript, вот метод, который я успешно использовал:
function escapeHTML (str) { var div = document.createElement('div'); var text = document.createTextNode(str); div.appendChild(text); return div.innerHTML; }
прототип был построен в String class. Поэтому, если вы используете / планируете использовать прототип, он делает что-то вроде:
'<div class="article">This is an article</div>'.escapeHTML(); // -> "<div class="article">This is an article</div>"
FWIW, кодировка не теряется. Кодировка используется синтаксическим анализатором разметки (браузером) во время загрузки страницы. Как только источник прочитан и проанализирован, и браузер загрузил DOM в память, кодировка была проанализирована в то, что она представляет. Поэтому к тому времени, когда ваш JS выполняется для чтения чего-либо в памяти, символ, который он получает, представляет собой кодировку.
Я могу работать строго на семантике здесь, но я хотел, чтобы вы поняли цель кодирования. Этот слово "потерянный" звучит так, как будто что-то не работает так, как должно.
быстрее без 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 &ersand (it has to be first), * \x0A is newline, *************/
<textarea id=test rows="9" cols="55"></textarea> <div id="testing">www.WHAK.com</div>
вот простое решение javascript. Он расширяет строковый объект с помощью метода "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("æåøåæå"))
вам не нужно экранировать/кодировать значения, чтобы перенести их из одного поля ввода в другое.
<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-кодирование будет эффективно прозрачной.если вы говорите о создании нового текстовое поле для хранения result...it-все так же просто. Просто передайте статическую часть HTML в jQuery, а затем установите остальные свойства/атрибуты объекта, который он возвращает вам.
$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());
у меня была аналогичная проблема и решить ее с помощью функции
encodeURIComponent
из JavaScript (документация)например, в вашем случае, если вы используете:
<input id='hiddenId' type='hidden' value='chalk & cheese' />
и
encodeURIComponent($('#hiddenId').attr('value'))
вы получаете
chalk%20%26%20cheese
. Даже пробелы сохраняются.в моем случае мне пришлось закодировать одну обратную косую черту, и этот код отлично работает
encodeURIComponent('name/surname')
и я
name%2Fsurname
на основе угловой санирует... (синтаксис модуля ЕС6)
// 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 в javascript нет прямых методов кодирования/декодирования HTML.
однако, что вы можете сделать, это использовать JS для создания произвольного элемента, установить его внутренний текст, а затем прочитать его с помощью innerHTML.
скажем, с jQuery это должно работать:
var helper = $('chalk & cheese').hide().appendTo('body'); var htmled = helper.html(); helper.remove();
или что-то в этом роде
Если вы хотите использовать jQuery. Я нашел это:
http://www.jquerysdk.com/api/jQuery.htmlspecialchars
(часть jquery.строки, которые предоставляет плагин на jQuery СДК)
проблема с прототипом я считаю, что он расширяет базовые объекты в JavaScript и будет несовместим с любым jQuery, который вы, возможно, использовали. Конечно, если вы уже используете Prototype, а не jQuery, это не будет проблемой.
EDIT: также есть это, который является портом строковых утилит прототипа для 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 }; })();
Это из исходного кода 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>
вывод:
<script>alert("I hack your site")</script>
.htmlEncode () будет доступен для всех строк после определения.
HtmlEncodes заданное значение
var htmlEncodeContainer = $('<div />'); function htmlEncode(value) { if (value) { return htmlEncodeContainer.text(value).html(); } else { return ''; } }
я столкнулся с некоторыми проблемами с обратной косой чертой в моей строке Domain\User.
Я добавил Это к другим побегам от ответа Anentropic
.replace(/\/g, '\')
который я нашел здесь: Как избежать обратной косой черты в JavaScript?
вот немного, что эмулирует
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.
выбрать
escapeHTML()
делает в прототипе.jsдобавление этого скрипта поможет вам escapeHTML:
String.prototype.escapeHTML = function() { return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') }
Теперь вы можете вызвать метод escapeHTML для строк в вашем скрипте, например:
var escapedString = "<h1>this is HTML</h1>".escapeHTML(); // gives: "<h1>this is HTML</h1>"
надеюсь, что это помогает любому, кто ищет простое решение без необходимости включать весь прототип.js