This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
Check that arguments can be used as reference when one is expected
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Whoops - php errors for cool kids |
||
4 | * @author Filipe Dobreira <http://github.com/filp> |
||
5 | */ |
||
6 | |||
7 | namespace Whoops\Util; |
||
8 | |||
9 | use Symfony\Component\VarDumper\Caster\Caster; |
||
10 | use Symfony\Component\VarDumper\Cloner\AbstractCloner; |
||
11 | use Symfony\Component\VarDumper\Cloner\VarCloner; |
||
12 | use Symfony\Component\VarDumper\Dumper\HtmlDumper; |
||
13 | use Whoops\Exception\Frame; |
||
14 | |||
15 | /** |
||
16 | * Exposes useful tools for working with/in templates |
||
17 | */ |
||
18 | class TemplateHelper |
||
19 | { |
||
20 | /** |
||
21 | * An array of variables to be passed to all templates |
||
22 | * @var array |
||
23 | */ |
||
24 | private $variables = []; |
||
25 | |||
26 | /** |
||
27 | * @var HtmlDumper |
||
28 | */ |
||
29 | private $htmlDumper; |
||
30 | |||
31 | /** |
||
32 | * @var HtmlDumperOutput |
||
33 | */ |
||
34 | private $htmlDumperOutput; |
||
35 | |||
36 | /** |
||
37 | * @var AbstractCloner |
||
38 | */ |
||
39 | private $cloner; |
||
40 | |||
41 | /** |
||
42 | * @var string |
||
43 | */ |
||
44 | private $applicationRootPath; |
||
45 | |||
46 | 2 | public function __construct() |
|
47 | { |
||
48 | // root path for ordinary composer projects |
||
49 | 2 | $this->applicationRootPath = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); |
|
50 | 2 | } |
|
51 | |||
52 | /** |
||
53 | * Escapes a string for output in an HTML document |
||
54 | * |
||
55 | * @param string $raw |
||
56 | * @return string |
||
57 | */ |
||
58 | 2 | public function escape($raw) |
|
59 | { |
||
60 | 2 | $flags = ENT_QUOTES; |
|
61 | |||
62 | // HHVM has all constants defined, but only ENT_IGNORE |
||
63 | // works at the moment |
||
64 | 2 | if (defined("ENT_SUBSTITUTE") && !defined("HHVM_VERSION")) { |
|
65 | 2 | $flags |= ENT_SUBSTITUTE; |
|
66 | 2 | } else { |
|
67 | // This is for 5.3. |
||
68 | // The documentation warns of a potential security issue, |
||
69 | // but it seems it does not apply in our case, because |
||
70 | // we do not blacklist anything anywhere. |
||
71 | $flags |= ENT_IGNORE; |
||
72 | } |
||
73 | |||
74 | 2 | $raw = str_replace(chr(9), ' ', $raw); |
|
75 | |||
76 | 2 | return htmlspecialchars($raw, $flags, "UTF-8"); |
|
77 | } |
||
78 | |||
79 | /** |
||
80 | * Escapes a string for output in an HTML document, but preserves |
||
81 | * URIs within it, and converts them to clickable anchor elements. |
||
82 | * |
||
83 | * @param string $raw |
||
84 | * @return string |
||
85 | */ |
||
86 | 1 | public function escapeButPreserveUris($raw) |
|
87 | { |
||
88 | 1 | $escaped = $this->escape($raw); |
|
89 | 1 | return preg_replace( |
|
90 | 1 | "@([A-z]+?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@", |
|
91 | 1 | "<a href=\"$1\" target=\"_blank\" rel=\"noreferrer noopener\">$1</a>", |
|
92 | $escaped |
||
93 | 1 | ); |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * Makes sure that the given string breaks on the delimiter. |
||
98 | * |
||
99 | * @param string $delimiter |
||
100 | * @param string $s |
||
101 | * @return string |
||
102 | */ |
||
103 | 1 | public function breakOnDelimiter($delimiter, $s) |
|
104 | { |
||
105 | 1 | $parts = explode($delimiter, $s); |
|
106 | 1 | foreach ($parts as &$part) { |
|
107 | 1 | $part = '<span class="delimiter">' . $part . '</span>'; |
|
108 | 1 | } |
|
109 | |||
110 | 1 | return implode($delimiter, $parts); |
|
111 | } |
||
112 | |||
113 | /** |
||
114 | * Replace the part of the path that all files have in common. |
||
115 | * |
||
116 | * @param string $path |
||
117 | * @return string |
||
118 | */ |
||
119 | 1 | public function shorten($path) |
|
120 | { |
||
121 | 1 | if ($this->applicationRootPath != "/") { |
|
122 | 1 | $path = str_replace($this->applicationRootPath, '…', $path); |
|
123 | 1 | } |
|
124 | |||
125 | 1 | return $path; |
|
126 | } |
||
127 | |||
128 | private function getDumper() |
||
129 | { |
||
130 | if (!$this->htmlDumper && class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) { |
||
131 | $this->htmlDumperOutput = new HtmlDumperOutput(); |
||
132 | // re-use the same var-dumper instance, so it won't re-render the global styles/scripts on each dump. |
||
133 | $this->htmlDumper = new HtmlDumper($this->htmlDumperOutput); |
||
134 | |||
135 | $styles = [ |
||
136 | 'default' => 'color:#FFFFFF; line-height:normal; font:12px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace !important; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: normal', |
||
137 | 'num' => 'color:#BCD42A', |
||
138 | 'const' => 'color: #4bb1b1;', |
||
139 | 'str' => 'color:#BCD42A', |
||
140 | 'note' => 'color:#ef7c61', |
||
141 | 'ref' => 'color:#A0A0A0', |
||
142 | 'public' => 'color:#FFFFFF', |
||
143 | 'protected' => 'color:#FFFFFF', |
||
144 | 'private' => 'color:#FFFFFF', |
||
145 | 'meta' => 'color:#FFFFFF', |
||
146 | 'key' => 'color:#BCD42A', |
||
147 | 'index' => 'color:#ef7c61', |
||
148 | ]; |
||
149 | $this->htmlDumper->setStyles($styles); |
||
150 | } |
||
151 | |||
152 | return $this->htmlDumper; |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Format the given value into a human readable string. |
||
157 | * |
||
158 | * @param mixed $value |
||
159 | * @return string |
||
160 | */ |
||
161 | public function dump($value) |
||
162 | { |
||
163 | $dumper = $this->getDumper(); |
||
164 | |||
165 | if ($dumper) { |
||
166 | // re-use the same DumpOutput instance, so it won't re-render the global styles/scripts on each dump. |
||
167 | // exclude verbose information (e.g. exception stack traces) |
||
168 | if (class_exists('Symfony\Component\VarDumper\Caster\Caster')) { |
||
169 | $cloneVar = $this->getCloner()->cloneVar($value, Caster::EXCLUDE_VERBOSE); |
||
170 | // Symfony VarDumper 2.6 Caster class dont exist. |
||
171 | } else { |
||
172 | $cloneVar = $this->getCloner()->cloneVar($value); |
||
173 | } |
||
174 | |||
175 | $dumper->dump( |
||
176 | $cloneVar, |
||
177 | $this->htmlDumperOutput |
||
178 | ); |
||
179 | |||
180 | $output = $this->htmlDumperOutput->getOutput(); |
||
181 | $this->htmlDumperOutput->clear(); |
||
182 | |||
183 | return $output; |
||
184 | } |
||
185 | |||
186 | return htmlspecialchars(print_r($value, true)); |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Format the args of the given Frame as a human readable html string |
||
191 | * |
||
192 | * @param Frame $frame |
||
193 | * @return string the rendered html |
||
194 | */ |
||
195 | public function dumpArgs(Frame $frame) |
||
196 | { |
||
197 | // we support frame args only when the optional dumper is available |
||
198 | if (!$this->getDumper()) { |
||
199 | return ''; |
||
200 | } |
||
201 | |||
202 | $html = ''; |
||
203 | $numFrames = count($frame->getArgs()); |
||
204 | |||
205 | if ($numFrames > 0) { |
||
206 | $html = '<ol class="linenums">'; |
||
207 | foreach ($frame->getArgs() as $j => $frameArg) { |
||
208 | $html .= '<li>'. $this->dump($frameArg) .'</li>'; |
||
209 | } |
||
210 | $html .= '</ol>'; |
||
211 | } |
||
212 | |||
213 | return $html; |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * Convert a string to a slug version of itself |
||
218 | * |
||
219 | * @param string $original |
||
220 | * @return string |
||
221 | */ |
||
222 | 1 | public function slug($original) |
|
223 | { |
||
224 | 1 | $slug = str_replace(" ", "-", $original); |
|
225 | 1 | $slug = preg_replace('/[^\w\d\-\_]/i', '', $slug); |
|
226 | 1 | return strtolower($slug); |
|
227 | } |
||
228 | |||
229 | /** |
||
230 | * Given a template path, render it within its own scope. This |
||
231 | * method also accepts an array of additional variables to be |
||
232 | * passed to the template. |
||
233 | * |
||
234 | * @param string $template |
||
235 | * @param array $additionalVariables |
||
236 | */ |
||
237 | 1 | public function render($template, array $additionalVariables = null) |
|
238 | { |
||
239 | 1 | $variables = $this->getVariables(); |
|
240 | |||
241 | // Pass the helper to the template: |
||
242 | 1 | $variables["tpl"] = $this; |
|
243 | |||
244 | 1 | if ($additionalVariables !== null) { |
|
245 | 1 | $variables = array_replace($variables, $additionalVariables); |
|
246 | 1 | } |
|
247 | |||
248 | 1 | call_user_func(function () { |
|
249 | 1 | extract(func_get_arg(1)); |
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
250 | 1 | require func_get_arg(0); |
|
251 | 1 | }, $template, $variables); |
|
252 | 1 | } |
|
253 | |||
254 | /** |
||
255 | * Sets the variables to be passed to all templates rendered |
||
256 | * by this template helper. |
||
257 | * |
||
258 | * @param array $variables |
||
259 | */ |
||
260 | 1 | public function setVariables(array $variables) |
|
261 | { |
||
262 | 1 | $this->variables = $variables; |
|
263 | 1 | } |
|
264 | |||
265 | /** |
||
266 | * Sets a single template variable, by its name: |
||
267 | * |
||
268 | * @param string $variableName |
||
269 | * @param mixed $variableValue |
||
270 | */ |
||
271 | 1 | public function setVariable($variableName, $variableValue) |
|
272 | { |
||
273 | 1 | $this->variables[$variableName] = $variableValue; |
|
274 | 1 | } |
|
275 | |||
276 | /** |
||
277 | * Gets a single template variable, by its name, or |
||
278 | * $defaultValue if the variable does not exist |
||
279 | * |
||
280 | * @param string $variableName |
||
281 | * @param mixed $defaultValue |
||
282 | * @return mixed |
||
283 | */ |
||
284 | 1 | public function getVariable($variableName, $defaultValue = null) |
|
285 | { |
||
286 | 1 | return isset($this->variables[$variableName]) ? |
|
287 | 1 | $this->variables[$variableName] : $defaultValue; |
|
288 | } |
||
289 | |||
290 | /** |
||
291 | * Unsets a single template variable, by its name |
||
292 | * |
||
293 | * @param string $variableName |
||
294 | */ |
||
295 | 1 | public function delVariable($variableName) |
|
296 | { |
||
297 | 1 | unset($this->variables[$variableName]); |
|
298 | 1 | } |
|
299 | |||
300 | /** |
||
301 | * Returns all variables for this helper |
||
302 | * |
||
303 | * @return array |
||
304 | */ |
||
305 | 1 | public function getVariables() |
|
306 | { |
||
307 | 1 | return $this->variables; |
|
308 | } |
||
309 | |||
310 | /** |
||
311 | * Set the cloner used for dumping variables. |
||
312 | * |
||
313 | * @param AbstractCloner $cloner |
||
314 | */ |
||
315 | 1 | public function setCloner($cloner) |
|
316 | { |
||
317 | 1 | $this->cloner = $cloner; |
|
318 | 1 | } |
|
319 | |||
320 | /** |
||
321 | * Get the cloner used for dumping variables. |
||
322 | * |
||
323 | * @return AbstractCloner |
||
324 | */ |
||
325 | public function getCloner() |
||
326 | { |
||
327 | if (!$this->cloner) { |
||
328 | $this->cloner = new VarCloner(); |
||
329 | } |
||
330 | return $this->cloner; |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Set the application root path. |
||
335 | * |
||
336 | * @param string $applicationRootPath |
||
337 | */ |
||
338 | public function setApplicationRootPath($applicationRootPath) |
||
339 | { |
||
340 | $this->applicationRootPath = $applicationRootPath; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * Return the application root path. |
||
345 | * |
||
346 | * @return string |
||
347 | */ |
||
348 | public function getApplicationRootPath() |
||
349 | { |
||
350 | return $this->applicationRootPath; |
||
351 | } |
||
352 | } |
||
353 |