HtmlSpecialChars-Äquivalent in Javascript?


167

Anscheinend ist dies schwieriger zu finden, als ich gedacht hatte. Und es ist sogar so einfach ...

Gibt es eine Funktion, die den in Javascript integrierten htmlspecialchars von PHP entspricht? Ich weiß, dass es ziemlich einfach ist, dies selbst zu implementieren, aber die Verwendung einer integrierten Funktion, falls verfügbar, ist einfach besser.

Für diejenigen, die mit PHP nicht vertraut sind, übersetzt htmlspecialchars Dinge wie <htmltag/>in&lt;htmltag/&gt;

Ich weiß das escape()und encodeURI()arbeite nicht so.


PHP hat einige wirklich gute Tools, var_dump, print_r, htmlspecialchars usw. Leider vermute ich, dass es mit js nicht dasselbe ist. Js Alarm ist so schlecht. Ein schneller Weg, um zu sehen, dass eine unerwartete (und in der Warnbox unsichtbare) Zeichenfolge kommt, besteht darin, die Zeichenfolgenlänge anstelle der Zeichenfolge selbst zu benachrichtigen.
Melsi

Mögliches Duplikat von Escaping HTML-Strings mit jQuery
nhahtdh

Siehe stackoverflow.com/a/12034334/8804293 , es hat eine großartige Antwort
Elijah Mock

Antworten:


330

Es gibt ein Problem mit Ihrem Lösungscode - er wird nur dem ersten Auftreten jedes Sonderzeichens entgehen. Beispielsweise:

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

Hier ist Code, der richtig funktioniert:

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

Aktualisieren

Der folgende Code führt zu identischen Ergebnissen wie der oben beschriebene, bietet jedoch eine bessere Leistung, insbesondere bei großen Textblöcken (danke jbo5112 ).

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

5
Das Schöne an dieser Funktion ist, dass sie in node.js funktioniert, die standardmäßig keinen Dom hat
booyaa

6
Es ist schneller, eine einzelne Ersetzungs- und Zuordnungsfunktion zu verwenden, und die einzelne Ersetzungsskala skaliert viel besser. ( jsperf.com/escape-html-special-chars/11 )
jbo5112

1
@ jbo5112 guter Punkt, ich wusste nicht, dass JS Rückrufe zum Ersetzen zuließ. Dieser Code ist jedoch leichter zu verstehen, und ich bezweifle, dass das Rasieren einiger Millisekunden von EscapeHtml () einen Unterschied bewirken wird, es sei denn, Sie rufen ihn aus irgendeinem Grund hunderte Male hintereinander auf.
Kip

Dadurch werden URLs im Text verzerrt, sodass sie für Plugins wie Autolinker.js unbrauchbar werden . Gibt es eine Möglichkeit, dies zu erreichen?
Radek Matěj

4
@ RadekMatěj Auch in diesem Fall ist es vollkommen gültig (vorzugsweise würde ich argumentieren), dass beide kaufmännischen Und-Zeichen in einem HTML-Dokument codiert werden. Ich würde es immer noch als Fehler mit dem Plugin betrachten.
Kip

31

Das ist HTML-Codierung. Es gibt keine native Javascript-Funktion, um dies zu tun, aber Sie können googeln und einige gut gemachte erledigen.

ZB http://sanzon.wordpress.com/2008/05/01/neat-little-html-encoding-trick-in-javascript/

EDIT:
Das habe ich getestet:

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

Ausgabe: &lt;htmltag/&gt;


Schade, ich muss dann nur noch eine benutzerdefinierte Funktion verwenden.
Bart van Heukelom

Sie können die Methode in dem Link ausprobieren, den ich in meinen Beitrag aufgenommen habe. Ziemlich ordentliches Konzept.
OK,

@okw: Ok, zuerst haben Sie darauf verlinkt: yuki-onna.co.uk/html/encode.html, das genau das encodeURIComponenttut, was das OP verlangt und überhaupt nicht. Kannst du das bitte bearbeiten? Ich kann meine -1 nicht rückgängig machen.
Crescent Fresh

Yah, der Code dieser Seite sieht logisch aus, aber ich habe ihn nicht getestet. Der neue Link funktioniert zwar, ich habe ihn jedoch selbst überprüft. Ich habe den Beitrag bereits vor einiger Zeit aktualisiert.
OK,

@BeauCielBleu: Nein. Die einzigen Knoten, die erstellt werden, sind ein einzelnes divElement und ein Textknoten . Wenn Sie einen Textknoten mit dem Text "<img src = bogus onerror = alert (1337)>" erstellen, wird nur ein Textknoten erstellt, kein imgElement.
Tim Down

26

Eine Lektüre wert: 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);
  };
})()

Hinweis : Führen Sie dies nur einmal aus. Und führen Sie es nicht auf bereits kodierten Strings zB &amp;wird&amp;amp;


3
Dies sollte die akzeptierte und am höchsten bewertete Antwort sein. Ich bin mir nicht sicher, warum es keine Stimmen hatte. Dies ist das schnellste Benchmarking mit einer langen (326 KB Google-Suchergebnis) und einer kurzen Eingabezeichenfolge in jsperf ( jsperf.com/escape-html-special-chars/11 ). Bitte stimmen Sie ab.
jbo5112

Was ist der Unterschied zwischen diesem und der Antwort, die die höchsten Stimmen erhalten hat? Warum die zusätzliche innere Funktion? Eine Erklärung könnte den Benutzern helfen, besser zu verstehen
Kosem

19

Mit jQuery kann es so sein:

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

Aus verwandter Frage HTML-Zeichenfolgen mit jQuery entkommen

Wie im Kommentar erwähnt, bleiben doppelte Anführungszeichen und einfache Anführungszeichen für diese Implementierung unverändert. Das bedeutet, dass diese Lösung nicht verwendet werden sollte, wenn Sie ein Elementattribut als rohen HTML-String erstellen müssen.


2
Haben Sie eine Idee, ob dies mit einem Overhead verbunden ist - Hinzufügen eines Dummy-Objekts zum DOM?
Kip

und gibt es noch andere Vorteile (z. B. wenn Sie Unicode-Zeichen oder ähnliches haben)?
Kip

4
Etwas, das ich dabei gefunden habe: doppelte Anführungszeichen und einfache Anführungszeichen bleiben unverändert. Dies macht dies problematisch, wenn Sie es in einem Attributwert verwenden möchten.
Kip

1
Bei kleinen Textblöcken dauert dies 30-mal so lange, bis alle Ersetzungen ausgeführt wurden. Es skaliert jedoch besser. Mit etwas so Gigantischem wie einer Google-Suchergebnisseite (326 KB) ist es 25 bis 30% schneller als das Ersetzen oder dies in reinem Javascript. Sie alle verlieren jedoch durchweg gegen eine einzige Ersetzungs- und eine Zuordnungsfunktion.
jbo5112

4
wie Leute über diese Antwort abstimmen: Antwort hat jquery: +1 - entgeht NICHT einfachen und doppelten Anführungszeichen: ummmm .. (Kratzkopf) .. +1. <!-- Caps rage begin --> Diese Antwort sollte eine NEGATIVE Bewertung haben, da sie nicht einmal der Beantwortung der Frage "HtmlSpecialChars-Äquivalent" nahe kommt. <!-- Caps rage end -->es-entkommt-nicht-zitiert-jesus-christus-und-andere-gottheiten. OMG du fragst Leute.
Sharky

19

Hier ist eine Funktion, um HTML zu entkommen:

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

Und zu entschlüsseln:

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 bietet hierfür eine Funktion:

_.escape(string)

Entgeht eine Zeichenfolge zum Einfügen in HTML und ersetzt die Zeichen &, <,>, "und '.

http://underscorejs.org/#escape

Es ist keine integrierte Javascript-Funktion, aber wenn Sie bereits Unterstrich verwenden, ist dies eine bessere Alternative als das Schreiben einer eigenen Funktion, wenn die zu konvertierenden Zeichenfolgen nicht zu groß sind.


5

Eine weitere Möglichkeit besteht darin, auf die gesamte Zeichenzuordnung insgesamt zu verzichten und stattdessen alle unerwünschten Zeichen in ihre jeweiligen numerischen Zeichenreferenzen umzuwandeln, z.

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

Beachten Sie, dass der angegebene RegEx nur die spezifischen Zeichen verarbeitet, denen das OP entkommen wollte. Abhängig vom Kontext, in dem der maskierte HTML-Code verwendet werden soll, sind diese Zeichen möglicherweise nicht ausreichend. Der Artikel von Ryan Grove Es gibt mehr zu HTML als &, <,> und " ist eine gute Lektüre zu diesem Thema. Abhängig von Ihrem Kontext ist möglicherweise die folgende RegEx erforderlich, um eine XSS-Injektion zu vermeiden:

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

Stichprobe :

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

3

Möglicherweise benötigen Sie eine solche Funktion nicht. Da sich Ihr Code bereits im Browser * befindet, können Sie direkt auf das DOM zugreifen, anstatt HTML zu generieren und zu codieren, das vom Browser rückwärts decodiert werden muss, um tatsächlich verwendet zu werden.

Verwenden Sie die innerTextEigenschaft, um einfachen Text sicher und viel schneller in das DOM einzufügen als mit einer der vorgestellten Escape-Funktionen. Noch schneller als das Zuweisen einer statischen vorcodierten Zeichenfolge innerHTML.

Verwenden Sie classListzum Bearbeiten Klassen, datasetum Satz data-Attribute und setAttributefür andere.

All dies erledigt die Flucht für Sie. Genauer gesagt ist kein Escapezeichen erforderlich und es wird keine Codierung unter ** durchgeführt, da Sie HTML, die Textdarstellung von DOM, umgehen.

// 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>

* Diese Antwort ist nicht für serverseitige JavaScript-Benutzer (Node.js usw. ) gedacht .

** Es sei denn, Sie konvertieren es anschließend explizit in tatsächliches HTML. ZB durch Zugriff innerHTML- dies passiert, wenn Sie $('<div/>').text(value).html();in anderen Antworten vorgeschlagen ausführen . Wenn Ihr letztes Ziel darin besteht, einige Daten in das Dokument einzufügen, erledigen Sie die Arbeit auf diese Weise zweimal. Sie können auch sehen, dass im resultierenden HTML-Code nicht alles codiert ist, sondern nur das Minimum, das erforderlich ist, damit es gültig ist. Dies erfolgt kontextabhängig. Aus diesem Grund codiert diese jQuery-Methode keine Anführungszeichen und sollte daher nicht als Allzweck-Escaper verwendet werden. Das Enthalten von Anführungszeichen ist erforderlich, wenn Sie HTML als Zeichenfolge mit nicht vertrauenswürdigen oder in Anführungszeichen enthaltenden Daten an der Stelle des Attributwerts erstellen. Wenn Sie die DOM-API verwenden, müssen Sie sich überhaupt nicht darum kümmern, zu entkommen.


Danke dafür! Ich habe viel zu lange nach einer so einfachen Lösung gesucht. Eine wichtige Sache, die ich entdeckt habe, ist, dass wenn Ihr Text Zeilenumbrüche enthält, Sie diese entweder durch HTML-Zeilenumbrüche (so etwas wie el.textContent = str; el.innerHTML = el.innerHTML.replace(/\n/g, '<br>')) ersetzen oder die CSS- white-spaceEigenschaft auf preoderpre-wrap
stellatedHexahedron

@stellatedHexahedron, vielen Dank, dass Sie dieses Problem angesprochen haben. Ich habe meine Antwort auf empfehlen geändert innerTextstatt textContent. Es ist zwar etwas langsamer und weist beim Lesen der Eigenschaft einige andere Unterschiede auf , ist jedoch intuitiver, da das <br>Ersetzen beim Zuweisen automatisch erfolgt.
Benutzer

2

Für Node.JS-Benutzer (oder Benutzer, die die Jade-Laufzeit im Browser verwenden) können Sie die Escape-Funktion von Jade verwenden.

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

Es macht keinen Sinn, es selbst zu schreiben, wenn jemand anderes es pflegt. :) :)


1

Ich arbeite ein wenig an der Antwort von okw.

Sie können dafür die DOM-Funktionen des Browsers verwenden.

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

utils.escapeHTML('<escapeThis>&')

Dies kehrt zurück &lt;escapeThis&gt;&amp;

Es verwendet die Standardfunktion createElement, um ein unsichtbares Element zu erstellen, verwendet dann die Funktion textContent, um eine beliebige Zeichenfolge als Inhalt festzulegen und innerHTMLden Inhalt dann in seiner HTML-Darstellung abzurufen.


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

Hoffe, dass dies das Rennen aufgrund seiner Leistung gewinnt und vor allem keine verkettete Logik mit .replace ('&', '&'). 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

Umgekehrt:

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

Die Frage ist nicht, wie Entitäten dekodiert werden sollen. Dies ist das Gegenteil von dem, was die Frage verlangt.
Quentin

Dies ersetzt nur die ersten Instanzen von &lt;und &gr;in einer Zeichenfolge.
Quentin

Dadurch werden nur die fünf Zeichen dekodiert, die (außerhalb von Nicht-Unicode-Dokumenten) maskiert werden müssen . Es werden keine Zeichen dekodiert, die möglicherweise maskiert werden.
Quentin

Dies berücksichtigt nicht die Regeln, wenn das Semikolon optional ist.
Quentin

Wenn der HTML-Code sagt To write a greater than sign in HTML type &amp;gt;:, wird er >anstelle von&gt;
Quentin

0

OWASP empfiehlt, dass "[e] außer für alphanumerische Zeichen [Sie sollten] alle Zeichen mit ASCII-Werten unter 256 mit dem &#xHH;Format (oder einer benannten Entität, falls verfügbar) maskieren , um ein Ausschalten des Attributs [an] zu verhindern."

Hier ist eine Funktion, die dies anhand eines Verwendungsbeispiels tut:

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)+';')
}

Diese Lösung verwendet den numerischen Code der Zeichen, der beispielsweise <durch ersetzt wird&#60; .

Obwohl seine Leistung etwas schlechter ist als die Lösung mit einer Karte , hat es die Vorteile:

  • Nicht abhängig von einer Bibliothek oder einem DOM
  • Ziemlich leicht zu merken (Sie müssen sich die 5 HTML-Escape-Zeichen nicht merken)
  • Kleiner Code
  • Ziemlich schnell (es ist immer noch schneller als 5 verkettete ersetzen)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.