Completed
Push — master ( ae8cc7...bdc62e )
by Josh
21:01
created

SetRelNoreferrerOnTargetedLinks::normalize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2016 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\TemplateNormalizations;
9
10
use DOMElement;
11
use DOMNodeList;
12
use s9e\TextFormatter\Configurator\TemplateNormalization;
13
14
class SetRelNoreferrerOnTargetedLinks extends TemplateNormalization
15
{
16
	/**
17
	* Add rel="noreferrer" on link elements with a target attribute
18
	*
19
	* Adds a "noreferrer" on links that open in a new context that would allow window.opener to be
20
	* accessed.
21
	*
22
	* @link https://mathiasbynens.github.io/rel-noopener/
23
	* @link https://wiki.whatwg.org/wiki/Links_to_Unrelated_Browsing_Contexts
24
	*
25
	* @param  DOMElement $template <xsl:template/> node
26
	* @return void
27
	*/
28
	public function normalize(DOMElement $template)
29
	{
30
		$this->normalizeElements($template->ownerDocument->getElementsByTagName('a'));
31
		$this->normalizeElements($template->ownerDocument->getElementsByTagName('area'));
32
	}
33
34
	/**
35
	* Add a rel="noreferrer" attribute to given element
36
	*
37
	* @param  DOMElement $element
38
	* @return void
39
	*/
40
	protected function addRelAttribute(DOMElement $element)
41
	{
42
		$rel = $element->getAttribute('rel');
43
		if (preg_match('(\\S$)', $rel))
44
		{
45
			$rel .= ' ';
46
		}
47
		$rel .= 'noreferrer';
48
49
		$element->setAttribute('rel', $rel);
50
	}
51
52
	/**
53
	* Test whether given link element will let the target access window.opener
54
	*
55
	* @param  DOMElement $element
56
	* @return bool
57
	*/
58
	protected function linkTargetCanAccessOpener(DOMElement $element)
59
	{
60
		// Can't access window.opener if the link doesn't have a target
61
		if (!$element->hasAttribute('target'))
62
		{
63
			return false;
64
		}
65
66
		// Can't access window.opener if the link already has rel="noopener" or rel="noreferrer"
67
		if (preg_match('(\\bno(?:open|referr)er\\b)', $element->getAttribute('rel')))
68
		{
69
			return false;
70
		}
71
72
		return true;
73
	}
74
75
	/**
76
	* Normalize a list of links
77
	*
78
	* @param  DOMNodeList $elements
79
	* @return void
80
	*/
81
	protected function normalizeElements(DOMNodeList $elements)
82
	{
83
		foreach ($elements as $element)
84
		{
85
			if ($this->linkTargetCanAccessOpener($element))
86
			{
87
				$this->addRelAttribute($element);
88
			}
89
		}
90
	}
91
}