public function testEscapeGlue() { $this->assertEquals('cat dog', SafeHtml::escape(['cat', 'dog'])); $this->assertEquals('cat,dog', SafeHtml::escape(['cat', 'dog'], ',')); }
public function testCollection() { $tags = Paragraph::collection(['a', 'b', 'c']); $this->assertEquals('<p>a</p><p>b</p><p>c</p>', SafeHtml::escape($tags, '')); }
/** * @return SafeHtml|SafeHtml[] * @throws \Exception */ public function produceSafeHTML() { // If the `href` attribute is present: // - make sure it is not a "javascript:" URI. We never permit these. // - if the tag is an `<a>` and the link is to some foreign resource, // add `rel="nofollow"` by default. if (!empty($this->_attributes['href'])) { // This might be a URI object, so cast it to a string. $href = (string) $this->_attributes['href']; if (isset($href[0])) { $isAnchorHref = $href[0] == '#'; // Is this a link to a resource on the same domain? The second part of // this excludes "///evil.com/" protocol-relative hrefs. $isDomainHref = $href[0] == '/' && (!isset($href[1]) || $href[1] != '/'); // Block 'javascript:' hrefs at the tag level: no well-designed // application should ever use them, and they are a potent attack vector. // This function is deep in the core and performance sensitive, so we're // doing a cheap version of this test first to avoid calling preg_match() // on URIs which begin with '/' or `#`. These cover essentially all URIs // in Phabricator. if (!$isAnchorHref && !$isDomainHref) { // Chrome 33 and IE 11 both interpret "javascript\n:" as a Javascript // URI, and all browsers interpret " javascript:" as a Javascript URI, // so be aggressive about looking for "javascript:" in the initial // section of the string. $normalizedHref = preg_replace('([^a-z0-9/:]+)i', '', $href); if (preg_match('/^javascript:/i', $normalizedHref)) { throw new \Exception("Attempting to render a tag with an 'href' attribute that " . "begins with 'javascript:'. This is either a serious security " . "concern or a serious architecture concern. Seek urgent " . "remedy."); } } } } // For tags which can't self-close, treat null as the empty string -- for // example, always render `<div></div>`, never `<div />`. $selfClosingTags = ['area' => true, 'base' => true, 'br' => true, 'col' => true, 'command' => true, 'embed' => true, 'frame' => true, 'hr' => true, 'img' => true, 'input' => true, 'keygen' => true, 'link' => true, 'meta' => true, 'param' => true, 'source' => true, 'track' => true, 'wbr' => true]; $attrString = ''; foreach ($this->_attributes as $k => $v) { if ($v !== null) { $attrString .= ' ' . $k . '="' . SafeHtml::escape($v) . '"'; } else { $attrString .= ' ' . $k; } } $content = $this->_getContentForRender(); if ($content === null) { if (isset($selfClosingTags[$this->_tag])) { return new SafeHtml('<' . $this->_tag . $attrString . ' />'); } $content = ''; } else { $content = SafeHtml::escape($content, ''); } return new SafeHtml('<' . $this->_tag . $attrString . '>' . $content . '</' . $this->_tag . '>'); }