显然,这比我想象的要难找到。而且它甚至是如此简单...

是否有等效于Javascript内置的PHP htmlspecialchars的函数?我知道自己很容易实现,但是使用内置函数(如果可用)会更好。

对于那些不熟悉PHP的人,htmlspecialchars会将类似<htmltag/>的东西转换为&lt;htmltag/&gt;

我知道escape()encodeURI()不能这样工作。

评论

php有一些非常好的工具,var_dump,print_r,htmlspecialchars等。不幸的是,我怀疑与js并不相同。 js警报是如此糟糕。看到一些意外的字符串(在警报框中不可见)的一种快速方法是警报字符串的长度,而不是字符串itslef。

使用jQuery转义HTML字符串的可能重复项

参见stackoverflow.com/a/12034334/8804293,它有很好的答案

#1 楼

解决方案代码有问题-它只会转义每个特殊字符的第一次出现。例如:
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;");
}


Update
以下代码将产生与上述相同的结果,但是性能更好,尤其是在大块文本上(感谢jbo5112)。
function escapeHtml(text) {
  var map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}


评论


这个函数的好处是它可以在默认情况下没有dom的node.js中工作

– booyaa
13年2月1日于10:46

使用单个替换和映射功能更快,并且单个替换扩展性更好。 (jsperf.com/escape-html-special-chars/11)

– jbo5112
2014年5月10日18:07

@ jbo5112好点,我没有意识到JS允许回调进行替换。这段代码更容易理解,而且我怀疑,除非由于某种原因连续调用数百次,否则将escapeHtml()缩短几毫秒会有所作为。

–基普
2014年5月21日在21:28

这会使文本中的URL变形,从而使它们无法用于Autolinker.js之类的插件。有什么办法可以解决这个问题吗?

–拉德克·马特杰
17-2-15在10:03



@RadekMatěj即使在那种情况下,当在HTML文档中使用这两个与号时,对两个与号进行编码也是完全有效的。我仍然认为它是插件的错误。

–基普
17年2月20日在19:48

#2 楼

那就是HTML编码。没有本地的javascript函数可以执行此操作,但是您可以在Google上搜索并完成一些不错的操作。

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

编辑:
这就是我要做的已测试:

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


输出:&lt;htmltag/&gt;

评论


太糟糕了,我只需要使用自定义函数即可。

–巴特·范·休克洛姆(Bart van Heukelom)
09年11月24日在2:06

您可以在我帖子中包含的链接中尝试该方法。确实很简洁的概念。

– o.k.w
09年11月24日在2:10

@ o.k.w:好的,首先,您链接到此:yuki-onna.co.uk/html/encode.html,它确实完成了encodeURIComponent的工作,而不是OP所要求的。那你可以编辑吗?我似乎无法撤消-1。

–新月鲜
09年11月24日在2:14

是的,该页面的代码看起来合乎逻辑,但我没有对其进行测试。新链接虽然有效,但我已亲自对其进行了验证。我已经有一段时间更新了帖子。

– o.k.w
09年11月24日在2:19

@BeauCielBleu:否。创建的唯一节点是单个div元素和一个文本节点。用文本``创建文本节点只会创建一个文本节点,而不是img元素。

– Tim Down
15年5月24日在10:25

#3 楼

值得一读:
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;

评论


这应该是被接受并获得最高投票的答案。我不确定为什么没有投票。在jsperf(jsperf.com/escape-html-special-chars/11)上使用长输入字符串(326KB Google搜索结果)和短输入字符串时,这是最快的基准测试。请对此投票。

– jbo5112
2014年5月10日18:05

这与获得最高票数的答案有什么区别?为什么还要附加内部功能?说明可以帮助用户更好地理解

– Kosem
5月5日1:27



#4 楼

使用jQuery可以像这样:

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


从相关问题开始,使用jQuery转义HTML字符串

如注释双引号和单引号中所述在此实施中保持原样。这意味着如果需要将element属性作为原始html字符串使用,则不应使用此解决方案。

评论


不知道是否有任何开销-向DOM添加虚拟对象吗?

–基普
2011年1月29日,下午5:39

还有其他优势(例如,如果您具有Unicode字符或其他字符)?

–基普
2011年1月29日,下午5:44

我发现的一些东西:双引号和单引号保持原样。如果要在属性值中使用它,这将带来问题。

–基普
2011年6月16日19:15

对于小块文本,这需要30倍的时间,只要运行所有替换操作即可。它确实可以更好地扩展。与Google搜索结果页(326KB)一样巨大的内容,它比替换或使用纯JavaScript进行处理的速度快25-30%。但是,它们都始终丢失一次替换和映射功能。

– jbo5112
2014年5月10日18:03



人们如何在这个答案上投票:答案有jquery:+1-不能转义单引号和双引号:ummmm ..(抓头).. +1。 <!-Caps rage开始->该答案的得分为负,因为它甚至没有回答“ HtmlSpecialChars等效”问题。 <!-Caps Rage结束->它不会逃避引用耶稣基督和其他神灵。天哪,你是jquery人。

–糟糕
2014年5月31日8:57



#5 楼

这是逃脱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,这比编写自己的函数更好。

评论


_.escape(string)也可以在lodash上使用

–کسریکرمی
11月22日8:01

#7 楼

这样做的另一种方法是完全放弃所有字符映射,而是将所有不需要的字符转换为它们各自的数字字符引用,例如:

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


请注意,指定的RegEx仅处理OP想要转义的特定字符,但是根据要使用转义的HTML的上下文,这些字符可能不足。 Ryan Grove的文章对HTML进行转义的内容远远超过&,<,>和“,这是该主题的不错的阅读方法。根据您的上下文,可能非常需要以下RegEx以避免XSS注入:

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


#8 楼

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());


#9 楼

您可能不需要这样的功能。由于您的代码已经在浏览器中*,因此您可以直接访问DOM,而不必生成和编码HTML,而这些HTML必须由浏览器向后解码才能实际使用。

使用innerText属性插入将纯文本安全地放入DOM中,比使用任何提供的转义功能要快得多。甚至比将静态预编码字符串分配给innerHTML更快。

使用classList编辑类,dataset设置data-属性,并为其他属性设置setAttribute

所有这些都将处理转义您。更准确地说,由于您正在处理DOM的文本表示形式HTML,因此不需要转义,并且也不会在下面进行编码**。




 // 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构造为在属性值的位置具有不可信或包含引号的数据的字符串时,需要使用引号转义。如果使用DOM API,则完全不必担心转义。

评论


谢谢你!我花了很长时间寻找这种简单的解决方案。我发现的一件重要事情是,如果您的文本包含换行符,那么您将不得不用HTML换行符替换它们(诸如el.textContent = str; el.innerHTML = el.innerHTML.replace(/ \ n / g,'
')),或将CSS空白属性设置为pre或pre-wrap

–星状六面体
18-4-20在19:15



@stellatedHexahedron,感谢您提出此问题。我已将答案更改为推荐使用innerText而不是textContent。尽管读取属性时速度较慢并且存在其他一些差异,但它更加直观,因为在分配属性时它会自动执行
替换。

–用户
18年4月25日在18:00



#10 楼

对于Node.JS用户(或在浏览器中使用Jade运行时的用户),可以使用Jade的转义功能。

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


如果别人是其他人,则无需自己编写它维护它。 :)

#11 楼

我正在详细说明o.k.w.的答案。

为此,您可以使用浏览器的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表示形式获取内容。

#12 楼

OWASP建议“除字母数字字符外,[您应]使用&#xHH;格式(或命名实体,如果可用)转义ASCII值小于256的所有字符,以防止切换出[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> 




免责声明:您应验证我提供的实体范围以亲自验证安全性。

#13 楼

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


#14 楼

希望这能因其性能而赢得比赛,最重要的是不要使用.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>'));


#15 楼

反转一个:

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


评论


问题不在于如何解码实体。这与问题的要求相反。

–昆汀
17年1月13日在12:47

This will only replace the first instances of < and &gr; in a string.

– Quentin
Jan 13 '17 at 12:47

这只会解码必须转义的五个字符(非Unicode文档之外),不会解码可能转义的五个字符。

–昆汀
17年1月13日在12:48

这没有考虑分号何时是可选的规则。

–昆汀
17年1月13日在12:48

If the HTML says: To write a greater than sign in HTML type &gt;, it will incorrectly display > instead of >

– Quentin
Jan 13 '17 at 12:49

#16 楼

这与这个问题没有直接关系,但是相反的情况可以通过以下方式在JS中完成:
 > String.fromCharCode(8212);
> "—"
 

TypeScript。

#17 楼

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


此解决方案使用字符的数字代码,例如<替换为&#60;

尽管其性能比使用地图的解决方案稍差,但它具有优点:


不依赖于库或DOM
很容易记住(您不需要记住5个HTML转义字符)
很少的代码
相当快(仍然比5链替换快)