HtmlSpecialChars еквівалент у Javascript?


167

Мабуть, це важче знайти, ніж я думав, що це буде. І це навіть так просто ...

Чи є функція, еквівалентна htmlspecialchars PHP, вбудована в Javascript? Я знаю, що реалізувати це досить просто, але використовувати вбудовану функцію, якщо вона є, просто приємніше.

Для тих, хто не знає PHP, htmlspecialchars перекладає речі, як <htmltag/>у&lt;htmltag/&gt;

Я це знаю escape()і encodeURI()не працюю так.


У php є кілька дійсно хороших інструментів, var_dump, print_r, htmlspecialchars і т. д. На жаль, я підозрюю, це не те саме з js. Попередження js настільки бідне. Швидкий спосіб переконатися, що якась несподівана (і невидима у вікні сповіщення) рядок - це попередження довжини рядка замість рядка itlef.
Мелсі

Можливий дублікат Escaping HTML-рядків з jQuery
nhahtdh

Дивіться stackoverflow.com/a/12034334/8804293 , у нього є чудова відповідь
Ілля Макет

Відповіді:


330

Існує проблема з вашим кодом рішення - він уникне лише першого появи кожного спеціального символу. Наприклад:

escapeHtml('Kip\'s <b>evil</b> "test" code\'s here');
Actual:   Kip&#039;s &lt;b&gt;evil</b> &quot;test" code's here
Expected: Kip&#039;s &lt;b&gt;evil&lt;/b&gt; &quot;test&quot; code&#039;s here

Ось код, який працює належним чином:

function escapeHtml(text) {
  return text
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#039;");
}

Оновлення

Наступний код дасть ідентичні результати вищезгаданому, але він працює краще, особливо на великих текстових блоках (дякую jbo5112 ).

function escapeHtml(text) {
  var map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}

5
Приємна річ у цій функції полягає в тому, що вона працює в node.js, у якого за замовчуванням немає
купола

6
Швидше використовувати функцію однієї заміни та картографування, а шкали однієї заміни набагато краще. ( jsperf.com/escape-html-special-chars/11 )
jbo5112

1
@ jbo5112 Хороший момент, я не розумів, JS дозволив зворотні дзвінки на заміну. Цей код легше зрозуміти, і я сумніваюся, що гоління за кілька мілісекунд від escapeHtml () призведе до зміни, якщо ви чомусь не називаєте його сотні разів поспіль.
Кіп

Це спотворить URL-адреси в тексті, що робить їх непридатними для плагінів, таких як Autolinker.js . Чи є спосіб, як підійти до цього?
Радек Матей

4
@ RadekMatěj Навіть у такому випадку це цілком справедливо (бажано, я заперечую), щоб обидва амперсенди були закодовані при використанні в документі HTML. Я б все-таки вважав це помилкою з плагіном.
Кіп

31

Це кодування HTML. Немає вбудованої функції JavaScript для цього, але ви можете перейти в Google і отримати якісь гарні роботи.

Наприклад, http://sanzon.wordpress.com/2008/05/01/neat-little-html-encoding-trick-in-javascript/

EDIT:
Це те, що я перевірив:

var div = document.createElement('div');
  var text = document.createTextNode('<htmltag/>');
  div.appendChild(text);
  console.log(div.innerHTML);

Вихід: &lt;htmltag/&gt;


Шкода, мені просто доведеться тоді користуватися спеціальною функцією.
Барт ван Хекелом

Ви можете спробувати метод за посиланням, яке я включив у свій пост. Дуже акуратне поняття справді.
okw

@okw: Добре, спочатку ви зв’язалися з цим: yuki-onna.co.uk/html/encode.html, який робить саме те, що encodeURIComponentробить, і зовсім не те, що просив ОП. Тож чи можете ви редагувати будь ласка? Я не можу, здається, скасувати свій -1.
Півмісяць Свіжий

Так, код цієї сторінки виглядає логічним, але я цього не перевіряв. Нове посилання, хоча працює, я сам його перевірив. Я вже оновлював публікацію за деякий час назад.
okw

@BeauCielBleu: Ні. Єдині створені вузли - це один divелемент та текстовий вузол. Створення текстового вузла з текстом `<img src = bogus onerror = alar (1337)>` просто створить текстовий вузол, а не imgелемент.
Тім Даун

26

Варто прочитати: http://bigdingus.com/2007/12/29/html-escaping-in-javascript/

escapeHTML: (function() {
 var MAP = {
   '&': '&amp;',
   '<': '&lt;',
   '>': '&gt;',
   '"': '&#34;',
   "'": '&#39;'
 };
  var repl = function(c) { return MAP[c]; };
  return function(s) {
    return s.replace(/[&<>'"]/g, repl);
  };
})()

Примітка : запустіть це лише один раз. І не запускайте його на вже закодованих рядках, наприклад, &amp;стає&amp;amp;


3
Це має бути прийнятою і найбільш голосовою відповіддю. Я не впевнений, чому не було голосів. Це тестування як найшвидше як з довгим (326 КБ результатом пошуку Google), так і з коротким рядком введення на jsperf ( jsperf.com/escape-html-special-chars/11 ). Будь ласка, проголосуйте за це.
jbo5112

Яка різниця між цим, у відповіді, яка отримала найвищі голоси? Чому додаткова внутрішня функція ?. Пояснення може допомогти користувачам зрозуміти краще
Косем

19

З jQuery це може бути таким:

var escapedValue = $('<div/>').text(value).html();

Із пов'язаного питання Уникнення HTML-рядків за допомогою jQuery

Як зазначається в коментарі, подвійні лапки та одиничні цитати залишаються такими, що є для цієї реалізації. Це означає, що це рішення не слід використовувати, якщо вам потрібно зробити атрибут елемента як необроблений HTML-рядок.


2
будь-яка ідея, якщо є щось накладне на це - додавання манекена об'єкта до DOM?
Кіп

і чи є інші переваги (скажімо, якщо у вас є символи unicode чи щось таке)?
Кіп

4
Щось із цього я знайшов: подвійні лапки та одинарні лапки залишаються як є. Це робить це проблематичним, якщо ви хочете використовувати його у значенні атрибута.
Кіп

1
Для невеликих шматочків тексту це займе 30 разів, ніж запуск усіх замінників. Це все-таки краще. Щось настільки ж гігантське, як сторінка результатів пошуку Google (326 КБ), це на 25-30% швидше, ніж замінює або робить це в прямому JavaScript. Однак всі вони послідовно програють одній заміні та функції відображення.
jbo5112

4
як люди голосують на цю відповідь: відповідь має jquery: +1 - НЕ уникає одинарних та подвійних лапок: ummmm .. (чухаючи голову) .. +1. <!-- Caps rage begin --> Ця відповідь повинна мати НЕГАТИВНУ бал, оскільки НЕ ВІДБАЄ БЛИЗЬКИЙ ЗАВДАННЯМ ЗАПИТАННЯ "Еквівалент HtmlSpecialChars". <!-- Caps rage end -->це не робить-не втече-цитати-Ісус-Христос-і-інші-божества. OMG ви jquery людей.
Шаркі

19

Ось функція виходу з HTML:

function escapeHtml(str)
{
    var map =
    {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, function(m) {return map[m];});
}

І розшифрувати:

function decodeHtml(str)
{
    var map =
    {
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"',
        '&#039;': "'"
    };
    return str.replace(/&amp;|&lt;|&gt;|&quot;|&#039;/g, function(m) {return map[m];});
}

6

Underscore.js надає функцію для цього:

_.escape(string)

Виходить з рядка для вставки в HTML, замінюючи символи &, <,>, "та".

http://underscorejs.org/#escape

Це не вбудована функція Javascript, але якщо ви вже використовуєте Underscore, це краща альтернатива, ніж написання власної функції, якщо ваші рядки для перетворення не надто великі.


5

Ще одне завдання - це взагалі відмовитись від відображення всіх символів і замість цього перетворити всі небажані символи у відповідні числові посилання, наприклад:

function escapeHtml(raw) {
    return raw.replace(/[&<>"']/g, function onReplace(match) {
        return '&#' + match.charCodeAt(0) + ';';
    });
}

Зауважте, що вказаний RegEx обробляє лише конкретні символи, з яких хотів уникнути ОП, але, залежно від контексту, в якому буде використовуватися відмічений HTML, цих символів може бути недостатньо. Стаття Райана Гроува Існує більше, ніж в HTML-програмі не виходить, ніж &, <,> і " - це добре читати по темі. І залежно від вашого контексту, наступний RegEx може бути дуже потрібен, щоб уникнути ін'єкції XSS:

var regex = /[&<>"'` !@$%()=+{}[\]]/g

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

зразок:

var toto = "test<br>";
alert(toto.escapeHTML());

3

Ймовірно, вам не потрібна така функція. Оскільки ваш код уже знаходиться в браузері *, ви можете отримати доступ до DOM безпосередньо, а не генерувати та кодувати HTML, який доведеться декодувати назад браузером, щоб він фактично використовувався.

Використовуйте innerTextвластивість, щоб вставити звичайний текст у DOM безпечно та набагато швидше, ніж будь-яка із представлених функцій евакуації. Навіть швидше, ніж призначати статичну попередньо закодовану рядок innerHTML.

Використовуйте classListдля редагування класів, datasetдля встановлення data-атрибутів та setAttributeінших.

Все це допоможе вам врятуватись. Точніше, не потрібно виконувати жодних епізодів, а під ними не виконуватись кодування **, оскільки ви працюєте навколо HTML, текстового представлення DOM.

// use existing element
var author = 'John "Superman" Doe <john@example.com>';
var el = document.getElementById('first');
el.dataset.author = author;
el.textContent = 'Author: '+author;

// or create a new element
var a = document.createElement('a');
a.classList.add('important');
a.href = '/search?q=term+"exact"&n=50';
a.textContent = 'Search for "exact" term';
document.body.appendChild(a);

// actual HTML code
console.log(el.outerHTML);
console.log(a.outerHTML);
.important { color: red; }
<div id="first"></div>

* Ця відповідь не призначена для користувачів сервера JavaScript (Node.js тощо )

** Якщо ви явно не перетворите його згодом у фактичний HTML. Наприклад, отримавши доступ innerHTML- ось що відбувається, коли ви запускаєте $('<div/>').text(value).html();запропоновані в інших відповідях. Отже, якщо ваша кінцева мета - вставити деякі дані в документ, зробивши це таким чином, ви будете виконувати роботу двічі. Також ви бачите, що в отриманому HTML кодується не все, лише мінімум, необхідний для того, щоб він був дійсним. Це робиться залежно від контексту, тому цей метод jQuery не кодує котирування, а тому не повинен використовуватися як загальнозміцнювач. Уникнення котирувань потрібно, коли ви створюєте HTML у вигляді рядка з недовіреними або містять цитати даними на місці значення атрибута. Якщо ви використовуєте API DOM, вам взагалі не потрібно дбати про втечу.


Дякую за це! Я витратив шлях на довгі пошуки такого простого рішення. Одне важливе, що я виявив - це те, що якщо ваш текст містить нові рядки, вам доведеться або замінити їх на розриви рядків HTML (щось на кшталт el.textContent = str; el.innerHTML = el.innerHTML.replace(/\n/g, '<br>')), або встановити white-spaceвластивість CSS на preабоpre-wrap
stellatedHexahedron

@stellatedHexahedron, дякую за те, що порушили цю проблему. Я змінив свою відповідь, щоб рекомендувати innerTextзамість цього textContent. Хоча трохи повільніше і має деякі інші відмінності при читанні властивості, він більш інтуїтивний тим, що він робить <br>заміну автоматично при призначенні до нього.
користувач

2

Для користувачів Node.JS (або користувачів, які використовують нефритовий час виконання у веб-переглядачі), ви можете скористатися функцією втечі Jade.

require('jade').runtime.escape(...);

Немає сенсу писати це самостійно, якщо хтось інший підтримує це. :)


1

Я детально розглядаю відповідь okw.

Для цього можна використовувати функції DOM браузера.

var utils = {
    dummy: document.createElement('div'),
    escapeHTML: function(s) {
        this.dummy.textContent = s
        return this.dummy.innerHTML
    }
}

utils.escapeHTML('<escapeThis>&')

Це повертається &lt;escapeThis&gt;&amp;

Він використовує стандартну функцію createElementдля створення невидимого елемента, потім використовує функцію textContentдля встановлення будь-якого рядка як його вмісту, а потім innerHTMLдля отримання вмісту в його HTML-представлення.


0
function htmlspecialchars(str) {
 if (typeof(str) == "string") {
  str = str.replace(/&/g, "&amp;"); /* must do &amp; first */
  str = str.replace(/"/g, "&quot;");
  str = str.replace(/'/g, "&#039;");
  str = str.replace(/</g, "&lt;");
  str = str.replace(/>/g, "&gt;");
  }
 return str;
 }

0

Сподіваюся, що це виграє гонку завдяки своїй продуктивності, а головне - не ланцюговою логікою, використовуючи .replace ('&', '&').

var mapObj = {
   '&':"&amp;",
   '<':"&lt;",
   '>':"&gt;",
   '"':"&quot;",
   '\'':"&#039;"
};
var re = new RegExp(Object.keys(mapObj).join("|"),"gi");

function escapeHtml(str) 
{   
    return str.replace(re, function(matched)
    {
        return mapObj[matched.toLowerCase()];
    });
}

console.log('<script type="text/javascript">alert('Hello World');</script>');
console.log(escapeHtml('<script type="text/javascript">alert('Hello World');</script>'));

0

Зворотній:

function decodeHtml(text) {
    return text
        .replace(/&amp;/g, '&')
        .replace(/&lt;/ , '<')
        .replace(/&gt;/, '>')
        .replace(/&quot;/g,'"')
        .replace(/&#039;/g,"'");
}

Питання не в тому, щоб розшифрувати об'єкти. Це робить протилежне тому, що задається питанням.
Квентін

Це замінить лише перші екземпляри &lt;та &gr;рядки.
Квентін

Це буде декодувати тільки п'ять символів , які (за межами не-Unicode документів) повинні бути екрановані, він не буде декодувати ті , які можуть бути екрановані.
Квентін

Це не враховує правила, коли напівкрапка є необов’язковою.
Квентін

Якщо HTML каже:, To write a greater than sign in HTML type &amp;gt;він буде неправильно відображатися >замість&gt;
Quentin

0

OWASP рекомендує "[e] xcept для буквено-цифрових символів, [вам слід] уникнути всіх символів зі значеннями ASCII менше 256 із&#xHH; форматі (або названому об'єкті, якщо він є), щоб уникнути вимикання атрибута [an]."

Ось ось функція, яка це робить, на прикладі використання:

function escapeHTML(unsafe) {
  return unsafe.replace(
    /[\u0000-\u002F]|[\u003A-\u0040]|[\u005B-\u00FF]/g,
    c => '&#' + ('000' + c.charCodeAt(0)).substr(-4, 4) + ';'
  )
}
document.querySelector('div').innerHTML =
  '<span class=' +
  escapeHTML('this should break it! " | / % * + , - / ; < = > ^') +
  '>' +
  escapeHTML('<script>alert("inspect the attributes")\u003C/script>') +
  '</span>'
<div></div>


-1
function htmlEscape(str){
    return str.replace(/[&<>'"]/g,x=>'&#'+x.charCodeAt(0)+';')
}

У цьому рішенні використовується числовий код символів, наприклад <замінений на&#60; .

Хоча його ефективність трохи гірша, ніж рішення з використанням карти , вона має переваги:

  • Не залежить від бібліотеки чи DOM
  • Досить легко запам’ятати (вам не потрібно запам’ятовувати 5 символів втечі HTML)
  • Маленький код
  • Розумно швидко (це все-таки швидше, ніж 5 ланцюгових заміни)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.