Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Failed Conditions
Pull Request — master (#1038)
by Dan
04:32
created

Template::checkDisableAJAX()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Smr;
4
5
use DOMDocument;
6
use DOMNode;
7
use DOMXpath;
8
use Exception;
9
use Globals;
10
use Smr\Container\DiContainer;
11
use Smr\Session;
12
use SmrAccount;
13
14
class Template {
15
	private $data = array();
16
	private $ignoreMiddle = false;
17
	private $nestedIncludes = 0;
18
	private $ajaxJS = array();
19
	protected $jsAlerts = array();
20
	private $displayCalled = false;
21
	private $listjsInclude = null;
22
	private $jsSources = [];
23
24
	/**
25
	 * Return the Smr\Template in the DI container.
26
	 * If one does not exist yet, it will be created.
27
	 * This is the intended way to construct this class.
28
	 */
29
	public static function getInstance() : self {
30
		return DiContainer::get(self::class);
31
	}
32
33
	public function __destruct() {
34
		if (!$this->displayCalled && !empty($this->data)) {
35
			error_log('Template destroyed before displaying the following assigned keys: ' . join(', ', array_keys($this->data)));
36
		}
37
	}
38
39
	public function hasTemplateVar($var) {
40
		return isset($this->data[$var]);
41
	}
42
43
	public function assign($var, $value) {
44
		if (!isset($this->data[$var])) {
45
			$this->data[$var] = $value;
46
		} else {
47
			// We insist that template variables not change once they are set
48
			throw new Exception("Cannot re-assign template variable '$var'!");
49
		}
50
	}
51
52
	public function unassign($var) {
53
		unset($this->data[$var]);
54
	}
55
56
	/**
57
	 * Displays the template HTML. Stores any ajax-enabled elements for future
58
	 * comparison, and outputs modified elements in XML for ajax if requested.
59
	 */
60
	public function display($templateName, $outputXml = false) {
61
		// If we already started output buffering before calling `display`,
62
		// we may have unwanted content in the buffer that we need to remove
63
		// before we send the Content-Type headers below.
64
		// Skip this for debug builds to help discover offending output.
65
		if (!ENABLE_DEBUG) {
66
			if (ob_get_length() > 0) {
67
				ob_clean();
68
			}
69
		}
70
		ob_start();
71
		$this->includeTemplate($templateName);
72
		$output = ob_get_clean();
73
74
		$ajaxEnabled = ($this->data['AJAX_ENABLE_REFRESH'] ?? false) !== false;
75
		if ($ajaxEnabled) {
76
			$ajaxXml = $this->convertHtmlToAjaxXml($output, $outputXml);
77
			if ($outputXml) {
78
				/* Left out for size: <?xml version="1.0" encoding="ISO-8859-1"?>*/
79
				$output = '<all>' . $ajaxXml . '</all>';
80
			}
81
			$session = Session::getInstance();
82
			$session->saveAjaxReturns();
83
		}
84
85
		// Now that we are completely done processing, we can output
86
		if ($outputXml) {
87
			header('Content-Type: text/xml; charset=utf-8');
88
		} else {
89
			header('Content-Type: text/html; charset=utf-8');
90
		}
91
		echo $output;
92
93
		// Record that display was called for error-checking in dtor
94
		$this->displayCalled = true;
95
	}
96
97
98
	protected function getTemplateLocation($templateName) {
99
		$templateDir = TEMPLATES_DIR;
100
		if (isset($this->data['ThisAccount']) && is_object($this->data['ThisAccount']) && $this->data['ThisAccount'] instanceof SmrAccount) {
101
			$templateDir .= $this->data['ThisAccount']->getTemplate() . '/';
102
		} else {
103
			$templateDir .= 'Default/';
104
		}
105
106
		$session = Session::getInstance();
107
		if ($session->hasGame()) {
108
			$gameDir = Globals::getGameType($session->getGameID()) . '/';
109
		} else {
110
			$gameDir = 'Default/';
111
		}
112
113
		if (file_exists($templateDir . 'engine/' . $gameDir . $templateName)) {
114
			return $templateDir . 'engine/' . $gameDir . $templateName;
115
		} elseif (file_exists($templateDir . 'engine/Default/' . $templateName)) {
116
			return $templateDir . 'engine/Default/' . $templateName;
117
		} elseif (file_exists(TEMPLATES_DIR . 'Default/engine/' . $gameDir . $templateName)) {
118
			return TEMPLATES_DIR . 'Default/engine/' . $gameDir . $templateName;
119
		} elseif (file_exists(TEMPLATES_DIR . 'Default/engine/Default/' . $templateName)) {
120
			return TEMPLATES_DIR . 'Default/engine/Default/' . $templateName;
121
		} elseif (file_exists($templateDir . 'admin/' . $gameDir . $templateName)) {
122
			return $templateDir . 'admin/' . $gameDir . $templateName;
123
		} elseif (file_exists($templateDir . 'admin/Default/' . $templateName)) {
124
			return $templateDir . 'admin/Default/' . $templateName;
125
		} elseif (file_exists(TEMPLATES_DIR . 'Default/admin/' . $gameDir . $templateName)) {
126
			return TEMPLATES_DIR . 'Default/admin/' . $gameDir . $templateName;
127
		} elseif (file_exists(TEMPLATES_DIR . 'Default/admin/Default/' . $templateName)) {
128
			return TEMPLATES_DIR . 'Default/admin/Default/' . $templateName;
129
		} elseif (file_exists($templateDir . $templateName)) {
130
			return $templateDir . $templateName;
131
		} elseif (file_exists(TEMPLATES_DIR . 'Default/' . $templateName)) {
132
			return TEMPLATES_DIR . 'Default/' . $templateName;
133
		} else {
134
			throw new Exception('No template found for ' . $templateName);
135
		}
136
	}
137
138
	protected function includeTemplate($templateName, array $assignVars = null) {
139
		if ($this->nestedIncludes > 15) {
140
			throw new Exception('Nested more than 15 template includes, is something wrong?');
141
		}
142
		foreach ($this->data as $key => $value) {
143
			$$key = $value;
144
		}
145
		if ($assignVars !== null) {
146
			foreach ($assignVars as $key => $value) {
147
				$$key = $value;
148
			}
149
		}
150
		$this->nestedIncludes++;
151
		require($this->getTemplateLocation($templateName));
152
		$this->nestedIncludes--;
153
	}
154
155
	protected function checkDisableAJAX($html) {
156
		return preg_match('/<input' . '[^>]*' . '[^(submit)(hidden)(image)]' . '[^>]*' . '>/i', $html) != 0;
157
	}
158
159
	protected function doDamageTypeReductionDisplay(&$damageTypes) {
160
		if ($damageTypes == 3) {
161
			echo ', ';
162
		} elseif ($damageTypes == 2) {
163
			echo ' and ';
164
		}
165
		$damageTypes--;
166
	}
167
168
	protected function doAn($wordAfter) {
169
		$char = strtoupper($wordAfter[0]);
170
		if ($char == 'A' || $char == 'E' || $char == 'I' || $char == 'O' || $char == 'U') {
171
			echo 'an';
172
		} else {
173
			echo 'a';
174
		}
175
	}
176
177
	/**
178
	 * Sets a listjs_include.js function to call at the end of the HTML body.
179
	 */
180
	public function setListjsInclude($func) {
181
		$this->listjsInclude = $func;
182
	}
183
184
	/*
185
	 * EVAL is special (well, will be when needed and implemented in the javascript).
186
	 */
187
	public function addJavascriptForAjax($varName, $obj) {
188
		if ($varName == 'EVAL') {
189
			if (!isset($this->ajaxJS['EVAL'])) {
190
				return $this->ajaxJS['EVAL'] = $obj;
191
			}
192
			return $this->ajaxJS['EVAL'] .= ';' . $obj;
193
		}
194
195
		if (isset($this->ajaxJS[$varName])) {
196
			throw new Exception('Trying to set javascript val twice: ' . $varName);
197
		}
198
		return $this->ajaxJS[$varName] = json_encode($obj);
199
	}
200
201
	protected function addJavascriptAlert($string) {
202
		$session = Session::getInstance();
203
		if (!$session->addAjaxReturns('ALERT:' . $string, $string)) {
204
			$this->jsAlerts[] = $string;
205
		}
206
	}
207
208
	/**
209
	 * Registers a JS target for inclusion at the end of the HTML body.
210
	 */
211
	protected function addJavascriptSource($src) {
212
		array_push($this->jsSources, $src);
213
	}
214
215
	protected function convertHtmlToAjaxXml($str, $returnXml) {
216
		if (empty($str)) {
217
			return '';
218
		}
219
220
		$session = Session::getInstance();
221
222
		// To get inner html, we need to construct a separate DOMDocument.
223
		// See PHP Bug #76285.
224
		$getInnerHTML = function(DOMNode $node) {
225
			$dom = new DOMDocument();
226
			$dom->formatOutput = false;
227
			foreach ($node->childNodes as $child) {
228
				$dom->appendChild($dom->importNode($child, true));
229
			}
230
			// Trim to remove trailing newlines
231
			return trim(@$dom->saveHTML());
232
		};
233
234
		$xml = '';
235
		$dom = new DOMDocument();
236
		$dom->loadHTML($str);
237
		$xpath = new DOMXpath($dom);
238
		$ajaxSelectors = array('//span[@id]', '//*[contains(@class,"ajax")]');
239
		foreach ($ajaxSelectors as $selector) {
240
			$matchNodes = $xpath->query($selector);
241
			foreach ($matchNodes as $node) {
242
				$id = $node->getAttribute('id');
243
				$inner = $getInnerHTML($node);
244
				if (!$session->addAjaxReturns($id, $inner) && $returnXml) {
245
					$xml .= '<' . $id . '>' . xmlify($inner) . '</' . $id . '>';
246
				}
247
			}
248
		}
249
250
		if (!$this->ignoreMiddle) {
251
			$mid = $dom->getElementById('middle_panel');
252
253
			$doAjaxMiddle = true;
254
			if ($mid === null) {
255
				// Skip if there is no middle_panel.
256
				$doAjaxMiddle = false;
257
			} else {
258
				// Skip if middle_panel has ajax-enabled children.
259
				$domMid = new DOMDocument();
260
				$domMid->appendChild($domMid->importNode($mid, true));
261
				$xpathMid = new DOMXpath($domMid);
262
				foreach ($ajaxSelectors as $selector) {
263
					if (count($xpathMid->query($selector)) > 0) {
264
						$doAjaxMiddle = false;
265
						break;
266
					}
267
				}
268
			}
269
270
			if ($doAjaxMiddle) {
271
				$inner = $getInnerHTML($mid);
272
				if (!$this->checkDisableAJAX($inner)) {
273
					$id = $mid->getAttribute('id');
274
					if (!$session->addAjaxReturns($id, $inner) && $returnXml) {
275
						$xml .= '<' . $id . '>' . xmlify($inner) . '</' . $id . '>';
276
					}
277
				}
278
			}
279
		}
280
281
		$js = '';
282
		foreach ($this->ajaxJS as $varName => $JSON) {
283
			if (!$session->addAjaxReturns('JS:' . $varName, $JSON) && $returnXml) {
284
				$js .= '<' . $varName . '>' . xmlify($JSON) . '</' . $varName . '>';
285
			}
286
		}
287
		if ($returnXml && count($this->jsAlerts) > 0) {
288
			$js = '<ALERT>' . json_encode($this->jsAlerts) . '</ALERT>';
289
		}
290
		if (strlen($js) > 0) {
291
			$xml .= '<JS>' . $js . '</JS>';
292
		}
293
		return $xml;
294
	}
295
296
	public function ignoreMiddle() {
297
		$this->ignoreMiddle = true;
298
	}
299
}
300