Як розшифрувати HTML-сутності за допомогою jQuery?


334

Як я можу використовувати jQuery для декодування об'єктів HTML у рядку?


Передчасний вибір технології (jQuery) пропонує відповіді з питаннями безпеки. Це може бути краще закритим як дублікат stackoverflow.com/questions/1912501/… .
Володимир Палант

Відповіді:


437

Примітка безпеки: використання цієї відповіді (збережена в початковій формі нижче) може ввести в вашу програму вразливість XSS . Ви не повинні використовувати цю відповідь. Прочитайте відповідь лукаскаро для пояснення вразливості цієї відповіді та скористайтеся підходом або з цієї відповіді, або замість відповіді Марка Амері .

Власне, спробуйте

var decoded = $("<div/>").html(encodedStr).text();

175
Як НЕ зробити це з ненадійними даними. Багато браузерів завантажують зображення та події, пов’язані з пожежею, навіть якщо вузол не приєднаний до DOM. Спробуйте запустити $("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>'). У Firefox або Safari він активує сповіщення.
Майк Самуель

@Mike, так що ти рекомендуєш замість цього? ваша відповідь .replace () не корисна, якщо ви не знаєте, що
заміняєте

7
@ekkis, вам потрібно зняти теги, перш ніж намагатися розшифрувати об'єкти. str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")чи щось подібне.
Майк Самуель

2
Краща реалізація (на мій погляд), яка знімає більшість тегів HTML (люб’язно надано Майком) з моїх даних, є моєю відповіддю на подібне запитання . Він також не має накладних витрат на jQuery, тому він цілком підходить для інших середовищ.
Роберт К

6
@MichaelStum ваша редакція тут визнала недійсним як коментар Майка Самуеля, так і відповідь наступного найвищого рівня, і зробив це, не фактично виправляючи вразливість XSS для всіх версій jQuery (як пояснено у відповіді нижче). Додавання попередження щодо безпеки до цієї відповіді було б розумним (і я це зроблю); надання інших обговорень на цій сторінці безглуздим, але фактично не вдалося виправити отвір у безпеці, безумовно, не є!
Марк Амері

211

Без жодного jQuery:

function decodeEntities(encodedString) {
  var textArea = document.createElement('textarea');
  textArea.innerHTML = encodedString;
  return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

Це працює аналогічно прийнятій відповіді , але безпечно використовувати при ненадійному введенні користувача.


Питання безпеки в подібних підходах

Як зауважив Майк Самуель , робити це <div>замість <textarea>ненадійного вводу користувача - це вразливість XSS, навіть якщо <div>до DOM ніколи не додається:

function decodeEntities(encodedString) {
  var div = document.createElement('div');
  div.innerHTML = encodedString;
  return div.textContent;
}

// Shows an alert
decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">')

Однак ця атака не можлива, <textarea>оскільки немає елементів HTML, дозволених вмістом <textarea>. Отже, будь-які теги HTML, які все ще присутні у рядку "закодовано", будуть автоматично кодовані суттю браузером.

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

// Safe, and returns the correct answer
console.log(decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">'))

Попередження : Виконайте це, використовуючи jQuery's .html()та .val()методи замість того, щоб використовувати, .innerHTMLа .valueтакож є незахищеним * для деяких версій jQuery, навіть коли використовуєте atextarea . Це тому, що старіші версії jQuery навмисно та явно оцінюють сценарії, що містяться в рядку, переданому до .html(). Отже, такий код показує попередження у jQuery 1.8:

//<!-- CDATA
// Shows alert
$("<textarea>")
.html("<script>alert(1337);</script>")
.text();

//-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

* Дякую Еру Пенкману за те, що подолала цю вразливість.


6
Можливо, буде гарною ідеєю знищити textarea після вилучення його значення:decodedString = textArea.value; textArea.remove(); return decodedString;
Вернер,

2
Або лише якщо версія javascript насправді підтримує delete ():if ('remove' in Element.prototype) textArea.remove();
Вернер,

6
@Werner Як тільки функція завершиться, більше не буде змінних, що містять посилання на неї, тому вона буде автоматично видалена сміттєзбірником .
користувач2428118

Я використовую це в поєднанні з .NET від затримки коду натискання кнопки, і чомусь прийнята відповідь викликала поштовий відклик. Ця відповідь не стала, тому це найкраща відповідь для мене. Дякую!
Снайлер

@Snailer $("<div />").html(string).text() виконає будь-який JavaScript у наданій рядку , і я підозрюю, що це спричинило вашу проблему. Прийняту відповідь слід оновити до цієї.
jbowman

80

Як сказав Майк Самуель, не використовуйте jQuery.html (). Text () для розшифровки html-об'єктів, оскільки це небезпечно.

Замість цього використовуйте візуалізатор шаблонів, як Mustache.js або decodeEntities з коментаря @ VyvIT.

Underscore.js бібліотека утиліти ременя поставляється з escapeі unescapeметодами, але вони не є безпечними для введення даних користувача:

_.escape (рядок)

_.unescape (рядок)


2
Це фактично заслуговує на більшу кількість грошей! Однозначно моє вподобане рішення. unescapeЗараз вони включені в документи, btw.
летальна гітара

5
_.unescape("&#39;")виходить лише в "& # 39;" замість одноцитати. Щось мені не вистачає чи підкреслення не переходить
Jason Axelson

6
Помилка на github була закрита як "Не виправлять"; це означає, що це рішення не працює і не працюватиме.
Ігор Чубін

3
Ви кажете, що підкреслення " escapeта unescapeметоди ... не є безпечними для введення користувачем" . Що ви маєте на увазі під цим? Це звучить як дурниця для мене, але, можливо, я чогось пропускаю - ви можете уточнити?
Марк Амерді

2
@VyvIT Спробував _.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(у Chrome / FF / IE). Але це не виявило жодної тривоги. Спробував це в консолі, а також помістив його у мій JS-файл. Той самий результат.
Vivek Athalye

28

Я думаю, що ви плутаєте текст та методи HTML. Подивіться на цей приклад, якщо ви використовуєте внутрішній HTML елемента як текст, ви отримаєте розшифровані HTML-теги (друга кнопка). Але якщо ви використовуєте їх як HTML, ви отримаєте перегляд у форматі HTML (перша кнопка).

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>

Перша кнопка пише: ось вміст HTML .

Друга кнопка пише: ось вміст <B> HTML </B>.

До речі, ви можете побачити плагін, який я знайшов у плагіні jQuery - HTML декодування та кодування, який кодує та декодує рядки HTML.


26

Питання обмежено "з jQuery", але це може допомогти деяким зрозуміти, що код jQuery, наведений у найкращій відповіді тут, робить наступне нижче ... це працює з або без jQuery:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}

20

Ви можете використовувати він бібліотеку, доступну з https://github.com/mathiasbynens/he

Приклад:

console.log(he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro "));
// Logs "Jörg & Jürgen rocked to & fro"

Я кинув виклик автору бібліотеки з питання про те, чи є якась причина використовувати цю бібліотеку в коді клієнта на користь <textarea>хаку, передбаченого в інших відповідях тут і в інших місцях. Він надав кілька можливих обгрунтування:

  • Якщо ви використовуєте сервер node.js, використання бібліотеки для кодування / декодування HTML дає вам єдине рішення, яке працює як на стороні клієнта, так і на сервері.

  • У деяких алгоритмах декодування сутностей браузерів є помилки або для деяких відсутні підтримка посилань на символи . Наприклад, Internet Explorer буде &nbsp;правильно декодувати і виводити нерозривні пробіли ( ), але повідомляє їх як звичайні пробіли, а не пробивні через innerTextвластивість елемента DOM , порушуючи <textarea>злом (хоча і лише другорядним способом). Крім того, IE 8 і 9 просто не підтримують жодну з нових посилань на іменні символи, додані в HTML 5. Автором він також влаштовує тест позначеної підтримки символів на http://mathias.html5.org/tests/html / ім'я-персонаж-посилання / . У IE 8 він повідомляє про тисячу помилок.

    Якщо ви хочете бути захищеними від помилок у веб-переглядачах, пов’язаних з розшифровкою об'єкта, та / або зможете обробляти весь спектр іменованих посилань символів, ви не зможете уникнути <textarea>злому; вам знадобиться бібліотека, як він .

  • Він просто божевільний, відчуває, що робити такі речі менш хакі.


4
+1 jQuery - це не рішення всього. Використовуйте правильний інструмент для роботи.
Mathias Bynens

Це найкращий спосіб декодування HTML-сутностей. Всі інші відповіді (на це та подібні запитання) або використовують innerHTML (створити новий HTML-елемент, обробити HTML-код і потім отримати innerHTML цього елемента, це може бути вразливим для XSS-атак, якщо ви ДУЖЕ не обережні, див. Більше ), або вони пропонуємо використовувати Underscore.js unescape або Lodash unescape, які є неповними (працює лише для декількох HTML-об'єктів). Бібліотека він є найбільш повним і безпечним варіантом!
ands

18

кодувати:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'

декодування:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'

3
вже є відповідь, яка працює, і вона майже ідентична цьому. Нам не потрібні повторювані відповіді
markasoftware

4
Це правильна відповідь. у відповіді tom використовується елемент DIV, який робить цю відповідь вразливою для XSS.
Франсіско Ходж

2
Це найкраща відповідь для ясності.
Ден Рендольф

4

Використовуйте

myString = myString.replace( /\&amp;/g, '&' );

Найпростіше це зробити на стороні сервера, тому що, мабуть, JavaScript не має вродженої бібліотеки для обробки об’єктів, а також я не знайшов жодного вгорі результатів пошуку для різних фреймворків, що розширюють JavaScript.

Шукайте "HTML-об'єкти JavaScript", і ви можете знайти декілька бібліотек саме для цієї мети, але вони, ймовірно, будуть побудовані навколо вищезгаданої логіки - заміни, сутності за сутністю.


0

Я просто повинен був мати характер HTML-сутності (⇓) як значення для кнопки HTML. HTML-код із самого початку добре виглядає в браузері:

<input type="button" value="Embed & Share  &dArr;" id="share_button" />

Тепер я додав перемикач, який також повинен відображати характер. Це моє рішення

$("#share_button").toggle(
    function(){
        $("#share").slideDown();
        $(this).attr("value", "Embed & Share " + $("<div>").html("&uArr;").text());
    }

Це знову відображається ⇓ на кнопці. Я сподіваюся, що це може комусь допомогти.


Простіше було б використовувати послідовність виходу Unicode (тобто "Embed & Share \u21d1"), а ще краще, лише "Embed & Share ⇑"якщо ви зможете обслуговувати свій скрипт у UTF-8 (або UTF-16, або будь-яке інше кодування, що підтримує символ ⇑). Використання елемента DOM для розбору сутності HTML просто для введення довільного символу Unicode в рядок JavaScript - хитрий та креативний підхід, який зробить Рубе Голдберга гордим, але це не є хорошою практикою; Юнікодні виводи є мовою, спеціально для обробки цього випадку використання.
Марк Амері

0

Ви повинні створити власну функцію для html-об'єктів:

function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
}

Я поняття не маю, це мені так допомогло +1 л-)
Szymon Toda

можливо, його було проголосовано, оскільки він обробляє лише деякі сутності.
Ясен

Оригінальне питання полягало в тому, як розшифрувати сутності - це робить протилежне бажаному; він кодує надзвичайно обмежений набір символів в сутності. Як йдеться в підказці про голосування, "ця відповідь не корисна". Я здивований, що через 4 роки він все ще має чистий позитивний бал.
Стівен П

0

Припустимо, у вас нижче String.

Наші кабіни Deluxe теплі, затишні та підсилювачі; зручні

var str = $("p").text(); // get the text from <p> tag
$('p').html(str).text();  // Now,decode html entities in your variable i.e 

str та призначити назад до

тег.

Це воно.


0

Для користувачів ExtJS, якщо у вас вже є кодована рядок, наприклад, коли повернене значення функції бібліотеки є внутрішнім вмістом HTMLML, врахуйте цю функцію ExtJS:

Ext.util.Format.htmlDecode(innerHtmlContent)

Це буде працювати лише для 5 HTML-об'єктів. Це можна побачити в документації та вихідному коді .
ands


0

Спробуйте це :

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

parseHTML - це функція в бібліотеці Jquery, і вона поверне масив, який включає деякі деталі щодо даної рядка ..

в деяких випадках рядок є великим, тому функція розділить вміст на багато індексів.

і щоб отримати всі дані індексів, вам слід перейти до будь-якого індексу, а потім отримати доступ до індексу під назвою "fullText".

Я вибрав індекс 0, тому що він буде працювати у всіх випадках (маленький рядок або великий рядок).


Хоча цей фрагмент коду може бути вирішенням, включаючи пояснення, справді допомагає покращити якість вашої публікації. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду.
Йохан


-1

Тут є ще одна проблема: уникнутий рядок не виглядає читабельним при призначенні вхідного значення

var string = _.escape("<img src=fake onerror=alert('boo!')>");
$('input').val(string);

Exapmle: https://jsfiddle.net/kjpdwmqa/3/


Це не відповідь на запитання. OP просить розшифрувати (unescape) HTML-сутність, але у цій відповіді ви використовуєте escapeметод Underscore.js. Також немає пояснень, як ваш зразок коду повинен вирішити проблему ОП.
ands

-1

Крім того, є також бібліотека для нього.

тут, https://cdnjs.com/libraries/he

npm install he                 //using node.js

<script src="js/he.js"></script>  //or from your javascript directory

Використання полягає в наступному ...

//to encode text 
he.encode('© Ande & Nonso® Company LImited 2018');  

//to decode the 
he.decode('&copy; Ande &amp; Nonso&reg; Company Limited 2018');

ура.


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

-3

Щоб розшифрувати HTML-об'єкти за допомогою jQuery, просто використовуйте цю функцію:

function html_entity_decode(txt){
    var randomID = Math.floor((Math.random()*100000)+1);
    $('body').append('<div id="random'+randomID+'"></div>');
    $('#random'+randomID).html(txt);
    var entity_decoded = $('#random'+randomID).html();
    $('#random'+randomID).remove();
    return entity_decoded;
}

Як користуватись:

Javascript:

var txtEncoded = "&aacute; &eacute; &iacute; &oacute; &uacute;";
$('#some-id').val(html_entity_decode(txtEncoded));

HTML:

<input id="some-id" type="text" />

-3

Найпростіший спосіб - встановити селектор класів для своїх елементів, а потім використовувати наступний код:

$(function(){
    $('.classSelector').each(function(a, b){
        $(b).html($(b).text());
    });
});

Більше нічого не потрібно!

У мене була ця проблема, і я знайшов це чітке рішення, і воно прекрасно працює.


Це не відповідь на питання ОП. ОП просить розшифрувати HTML-об’єкти в STRING, НЕ тільки це не вирішує проблему ОП, але й замінює втечені HTML-об'єкти в HTML-елементі на незахищені, які не слід робити.
ands

-3

Я думаю, що це якраз протилежне обраному рішенню.

var decoded = $("<div/>").text(encodedStr).html();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.