sandrokeil /
HtmlElement
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.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Sake |
||
| 4 | * |
||
| 5 | * @link http://github.com/sandrokeil/HtmlElement for the canonical source repository |
||
| 6 | * @copyright Copyright (c) 2014-2017 Sandro Keil |
||
| 7 | * @license http://github.com/sandrokeil/HtmlElement/blob/master/LICENSE.txt New BSD License |
||
| 8 | */ |
||
| 9 | |||
| 10 | namespace Sake\HtmlElement\View\Helper; |
||
| 11 | |||
| 12 | use Zend\Escaper\Escaper; |
||
| 13 | use Zend\View\Helper\AbstractHelper; |
||
| 14 | |||
| 15 | /** |
||
| 16 | * HtmlElement view helper |
||
| 17 | * |
||
| 18 | * This view helper creates a html tag object which can be configured and rendered. |
||
| 19 | */ |
||
| 20 | class HtmlElement extends AbstractHelper |
||
| 21 | { |
||
| 22 | /** |
||
| 23 | * Tag type e.g. div |
||
| 24 | * |
||
| 25 | * @var string |
||
| 26 | */ |
||
| 27 | protected $tag; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * Tag content |
||
| 31 | * |
||
| 32 | * @var string |
||
| 33 | */ |
||
| 34 | protected $text = ''; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Array of attribute / value pair |
||
| 38 | * |
||
| 39 | * @var array |
||
| 40 | */ |
||
| 41 | protected $attributes = array(); |
||
| 42 | |||
| 43 | /** |
||
| 44 | * Escape html |
||
| 45 | * |
||
| 46 | * @var bool |
||
| 47 | */ |
||
| 48 | protected $renderHtml = false; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * List of self closing tags for valid html |
||
| 52 | * |
||
| 53 | * @var array |
||
| 54 | */ |
||
| 55 | protected $singletonTags = array( |
||
| 56 | 'area', |
||
| 57 | 'base', |
||
| 58 | 'br', |
||
| 59 | 'col', |
||
| 60 | 'command', |
||
| 61 | 'embed', |
||
| 62 | 'hr', |
||
| 63 | 'img', |
||
| 64 | 'input', |
||
| 65 | 'keygen', |
||
| 66 | 'link', |
||
| 67 | 'meta', |
||
| 68 | 'param', |
||
| 69 | 'source', |
||
| 70 | 'track', |
||
| 71 | 'wbr', |
||
| 72 | ); |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Html/text escaper |
||
| 76 | * |
||
| 77 | * @var Escaper |
||
| 78 | */ |
||
| 79 | protected $escaper; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Should be html attributes escaped |
||
| 83 | * |
||
| 84 | * @var bool |
||
| 85 | */ |
||
| 86 | protected $escapeHtmlAttribute = true; |
||
| 87 | |||
| 88 | /** |
||
| 89 | * Should be text escaped |
||
| 90 | * |
||
| 91 | * @var bool |
||
| 92 | */ |
||
| 93 | protected $escapeText = true; |
||
| 94 | |||
| 95 | /** |
||
| 96 | * Create html object with provided settings. |
||
| 97 | * |
||
| 98 | * @param string $tag Html tag |
||
| 99 | * @param string $text Html content |
||
| 100 | * @param array $attributes Html attributes |
||
| 101 | * @param bool $renderHtml Escape html |
||
| 102 | * @return HtmlElement |
||
| 103 | */ |
||
| 104 | public function __invoke($tag, $text = '', array $attributes = array(), $renderHtml = false) |
||
| 105 | { |
||
| 106 | $html = clone $this; |
||
| 107 | |||
| 108 | $html->setTag($tag); |
||
| 109 | $html->setText($text); |
||
| 110 | $html->setAttributes($attributes); |
||
| 111 | $html->enableHtml($renderHtml); |
||
| 112 | return $html; |
||
| 113 | } |
||
| 114 | |||
| 115 | /** |
||
| 116 | * Renders element. Triggers an error instead of throw an exception, because it is not allowed here. |
||
| 117 | * |
||
| 118 | * @return string |
||
| 119 | */ |
||
| 120 | public function __toString() |
||
| 121 | { |
||
| 122 | try { |
||
| 123 | $html = $this->render(); |
||
| 124 | } catch (\Exception $exception) { |
||
| 125 | trigger_error($exception, E_USER_WARNING); |
||
| 126 | $html = ''; |
||
| 127 | } |
||
| 128 | return $html; |
||
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Alias for __toString |
||
| 133 | * |
||
| 134 | * @return string |
||
| 135 | */ |
||
| 136 | public function toString() |
||
| 137 | { |
||
| 138 | return $this->__toString(); |
||
| 139 | } |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Returns tag |
||
| 143 | * |
||
| 144 | * @return string |
||
| 145 | */ |
||
| 146 | public function getTag() |
||
| 147 | { |
||
| 148 | return $this->tag; |
||
| 149 | } |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Returns the current text (content) of tag |
||
| 153 | * |
||
| 154 | * @return string |
||
| 155 | */ |
||
| 156 | public function getText() |
||
| 157 | { |
||
| 158 | return $this->text; |
||
| 159 | } |
||
| 160 | |||
| 161 | /** |
||
| 162 | * Returns an array of html attribute / value pair for the current html element |
||
| 163 | * |
||
| 164 | * @return array |
||
| 165 | */ |
||
| 166 | public function getAttributes() |
||
| 167 | { |
||
| 168 | return $this->attributes; |
||
| 169 | } |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Sets an array of html attributes / value pair |
||
| 173 | * |
||
| 174 | * @param array $attributes Html attributes |
||
| 175 | * @return HtmlElement |
||
| 176 | */ |
||
| 177 | public function setAttributes(array $attributes) |
||
| 178 | { |
||
| 179 | $this->attributes = $attributes; |
||
| 180 | return $this; |
||
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * Sets html tag |
||
| 185 | * |
||
| 186 | * @param string $tag |
||
| 187 | * @return HtmlElement |
||
| 188 | */ |
||
| 189 | public function setTag($tag) |
||
| 190 | { |
||
| 191 | $this->tag = (string) $tag; |
||
| 192 | return $this; |
||
| 193 | } |
||
| 194 | |||
| 195 | /** |
||
| 196 | * Sets tag text (content) |
||
| 197 | * |
||
| 198 | * @param string $text |
||
| 199 | * @return HtmlElement |
||
| 200 | */ |
||
| 201 | public function setText($text) |
||
| 202 | { |
||
| 203 | $this->text = (string) $text; |
||
| 204 | return $this; |
||
| 205 | } |
||
| 206 | |||
| 207 | /** |
||
| 208 | * Appends text |
||
| 209 | * |
||
| 210 | * @param string $text |
||
| 211 | * @return HtmlElement |
||
| 212 | */ |
||
| 213 | public function appendText($text) |
||
| 214 | { |
||
| 215 | $this->text .= (string) $text; |
||
| 216 | return $this; |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Returns css classes |
||
| 221 | * |
||
| 222 | * @return string |
||
| 223 | */ |
||
| 224 | public function getClass() |
||
| 225 | { |
||
| 226 | return isset($this->attributes['class']) ? $this->attributes['class'] : ''; |
||
| 227 | } |
||
| 228 | |||
| 229 | /** |
||
| 230 | * Sets a css class for current element. This method overrides all existing css classes. To append css classes |
||
| 231 | * use appendClass() |
||
| 232 | * |
||
| 233 | * @param string $class Css class |
||
| 234 | * @return HtmlElement |
||
| 235 | */ |
||
| 236 | public function setClass($class) |
||
| 237 | { |
||
| 238 | $this->attributes['class'] = $class; |
||
| 239 | return $this; |
||
| 240 | } |
||
| 241 | |||
| 242 | /** |
||
| 243 | * Appends a css class to current element. |
||
| 244 | * |
||
| 245 | * @param string $class Css class |
||
| 246 | * @return HtmlElement |
||
| 247 | */ |
||
| 248 | public function appendClass($class) |
||
| 249 | { |
||
| 250 | if (!isset($this->attributes['class'])) { |
||
| 251 | $this->attributes['class'] = ''; |
||
| 252 | } else { |
||
| 253 | $this->attributes['class'] .= ' '; |
||
| 254 | } |
||
| 255 | $this->attributes['class'] .= (string) $class; |
||
| 256 | return $this; |
||
| 257 | } |
||
| 258 | |||
| 259 | /** |
||
| 260 | * Returns id attribute of current element |
||
| 261 | * |
||
| 262 | * @return string |
||
| 263 | */ |
||
| 264 | public function getId() |
||
| 265 | { |
||
| 266 | return isset($this->attributes['id']) ? $this->attributes['id'] : ''; |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * Sets id attribute for current element |
||
| 271 | * |
||
| 272 | * @param string $id Name |
||
| 273 | * @return HtmlElement |
||
| 274 | */ |
||
| 275 | public function setId($id) |
||
| 276 | { |
||
| 277 | $this->attributes['id'] = (string) $id; |
||
| 278 | return $this; |
||
| 279 | } |
||
| 280 | |||
| 281 | /** |
||
| 282 | * Return true or false to indicate escaping of text |
||
| 283 | * |
||
| 284 | * @return bool |
||
| 285 | */ |
||
| 286 | public function useHtml() |
||
| 287 | { |
||
| 288 | return $this->renderHtml; |
||
| 289 | } |
||
| 290 | |||
| 291 | /** |
||
| 292 | * Turn on / off html rendering text |
||
| 293 | * |
||
| 294 | * @param bool $renderHtml Render html or escape content |
||
| 295 | * @return HtmlElement |
||
| 296 | */ |
||
| 297 | public function enableHtml($renderHtml) |
||
| 298 | { |
||
| 299 | $this->renderHtml = (bool) $renderHtml; |
||
| 300 | return $this; |
||
| 301 | } |
||
| 302 | |||
| 303 | /** |
||
| 304 | * Builds html attributes |
||
| 305 | * |
||
| 306 | * @return string |
||
| 307 | */ |
||
| 308 | protected function buildAttributes() |
||
| 309 | { |
||
| 310 | $attributes = ''; |
||
| 311 | |||
| 312 | foreach ($this->attributes as $key => $value) { |
||
| 313 | $attributes .= ' ' . $key . '="' . $this->escapeHtmlAttribute($value) . '"'; |
||
| 314 | } |
||
| 315 | return $attributes; |
||
| 316 | } |
||
| 317 | |||
| 318 | /** |
||
| 319 | * Renders html element |
||
| 320 | * |
||
| 321 | * @return string |
||
| 322 | */ |
||
| 323 | public function render() |
||
| 324 | { |
||
| 325 | if (in_array($this->tag, $this->singletonTags)) { |
||
| 326 | // strict html 5 is omitted for backward compatibility, html 5 is still valid |
||
| 327 | return '<' . $this->tag . $this->buildAttributes() . ' />'; |
||
| 328 | } |
||
| 329 | |||
| 330 | if (false === $this->renderHtml) { |
||
| 331 | $text = $this->escapeText($this->text); |
||
| 332 | } else { |
||
| 333 | $text = $this->text; |
||
| 334 | } |
||
| 335 | return '<' . $this->tag . $this->buildAttributes() . '>' . $text . '</' . $this->tag . '>'; |
||
| 336 | } |
||
| 337 | |||
| 338 | /** |
||
| 339 | * Returns if html attributes should be escaped |
||
| 340 | * |
||
| 341 | * @return boolean |
||
| 342 | */ |
||
| 343 | public function isEscapeHtmlAttribute() |
||
| 344 | { |
||
| 345 | return $this->escapeHtmlAttribute; |
||
| 346 | } |
||
| 347 | |||
| 348 | /** |
||
| 349 | * Enable/disable escaping of html attributes |
||
| 350 | * |
||
| 351 | * @param boolean $escapeHtmlAttributes |
||
| 352 | * @return HtmlElement |
||
| 353 | */ |
||
| 354 | public function setEscapeHtmlAttribute($escapeHtmlAttributes) |
||
| 355 | { |
||
| 356 | $this->escapeHtmlAttribute = (bool) $escapeHtmlAttributes; |
||
| 357 | return $this; |
||
| 358 | } |
||
| 359 | |||
| 360 | /** |
||
| 361 | * Returns if text should be escaped |
||
| 362 | * |
||
| 363 | * @return boolean |
||
| 364 | */ |
||
| 365 | public function isEscapeText() |
||
| 366 | { |
||
| 367 | return $this->escapeText; |
||
| 368 | } |
||
| 369 | |||
| 370 | /** |
||
| 371 | * Enable/disable escaping of text |
||
| 372 | * |
||
| 373 | * @param boolean $escapeText |
||
| 374 | * @return HtmlElement |
||
| 375 | */ |
||
| 376 | public function setEscapeText($escapeText) |
||
| 377 | { |
||
| 378 | $this->escapeText = (bool) $escapeText; |
||
| 379 | return $this; |
||
| 380 | } |
||
| 381 | |||
| 382 | /** |
||
| 383 | * Returns escaper for html attributes, if no one is set, escaper of view will be used |
||
| 384 | * |
||
| 385 | * @return string |
||
| 386 | */ |
||
| 387 | protected function escapeHtmlAttribute($value) |
||
| 388 | { |
||
| 389 | if (false === $this->escapeHtmlAttribute) { |
||
| 390 | return $value; |
||
| 391 | } |
||
| 392 | return $this->getEscaper()->escapeHtmlAttr($value); |
||
| 393 | } |
||
| 394 | |||
| 395 | /** |
||
| 396 | * Returns escaper for html, if no one is set, escaper of view will be used |
||
| 397 | * |
||
| 398 | * @return string |
||
| 399 | */ |
||
| 400 | protected function escapeText($value) |
||
| 401 | { |
||
| 402 | if (false === $this->escapeText) { |
||
| 403 | return $value; |
||
| 404 | } |
||
| 405 | return $this->getEscaper()->escapeHtml($value); |
||
| 406 | } |
||
| 407 | |||
| 408 | /** |
||
| 409 | * Sets escaper for html |
||
| 410 | * |
||
| 411 | * @param Escaper $helperEscapeHtml |
||
| 412 | * @return HtmlElement |
||
| 413 | */ |
||
| 414 | public function setEscaper(Escaper $helperEscapeHtml) |
||
| 415 | { |
||
| 416 | $this->escaper = $helperEscapeHtml; |
||
| 417 | return $this; |
||
| 418 | } |
||
| 419 | |||
| 420 | /** |
||
| 421 | * Returns escaper for html, if no one is set, lazy loads escaper from view |
||
| 422 | * |
||
| 423 | * @return Escaper |
||
| 424 | */ |
||
| 425 | protected function getEscaper() |
||
| 426 | { |
||
| 427 | if (null === $this->escaper) { |
||
| 428 | $this->escaper = $this->getView()->plugin('escapehtml')->getEscaper(); |
||
|
0 ignored issues
–
show
|
|||
| 429 | } |
||
| 430 | return $this->escaper; |
||
| 431 | } |
||
| 432 | } |
||
| 433 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: