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-кодировать строку?

22 697

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, '&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 используют именно этот метод 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, '&#x2F;');

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

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

Я знаю, что это старый, но я хотел разместить вариант принято отвечать что будет работать в 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 &amp; cheese" );
  "chalk & cheese"

> _.escape( "chalk & cheese" );
  "chalk &amp; 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();
// -> "&lt;div class="article"&gt;This is an article&lt;/div&gt;"

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

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

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

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

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:

http://stilldesigning.com/dotstring/

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.

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

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

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

я столкнулся с некоторыми проблемами с обратной косой чертой в моей строке Domain\User.

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

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

который я нашел здесь: Как избежать обратной косой черты в 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,'&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;"

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