mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Basic HTML constructs
This commit is contained in:
parent
5ab8839d04
commit
04581d0915
8
src/Html/Component.php
Normal file
8
src/Html/Component.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Erusev\Parsedown\Html;
|
||||
|
||||
interface Component
|
||||
{
|
||||
public function getHtml(): string;
|
||||
}
|
102
src/Html/Components/Element.php
Normal file
102
src/Html/Components/Element.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Erusev\Parsedown\Html\Components;
|
||||
|
||||
use Erusev\Parsedown\Html\Component;
|
||||
use Erusev\Parsedown\Html\Sanitisation\CharacterFilter;
|
||||
use Erusev\Parsedown\Html\Sanitisation\Escaper;
|
||||
|
||||
final class Element implements Component
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var array<string, string>*/
|
||||
private $attributes;
|
||||
|
||||
/** @var Component[]|null */
|
||||
private $Contents;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array<string, string> $attributes
|
||||
* @param Component[]|null $Contents
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
array $attributes,
|
||||
?array $Components
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->attributes = $attributes;
|
||||
$this->Components = $Components;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array<string, string> $attributes
|
||||
*/
|
||||
public static function selfClosing(string $name, array $attributes): self
|
||||
{
|
||||
return new self($name, $attributes, null);
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Component[]|null
|
||||
*/
|
||||
public function contents(): ?array
|
||||
{
|
||||
return $this->Contents;
|
||||
}
|
||||
|
||||
public function getHtml(): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
$elementName = CharacterFilter::htmlElementName($this->name);
|
||||
|
||||
$html .= '<' . $elementName;
|
||||
|
||||
if (! empty($this->attributes)) {
|
||||
foreach ($this->attributes as $name => $value) {
|
||||
$html .= ' '
|
||||
. CharacterFilter::htmlAttributeName($name)
|
||||
. '="'
|
||||
. Escaper::htmlAttributeValue($value)
|
||||
. '"'
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->Contents !== null) {
|
||||
$html .= '>';
|
||||
|
||||
if (! empty($this->Contents)) {
|
||||
$html .= "\n";
|
||||
|
||||
foreach ($this->Contents as $C) {
|
||||
$html .= $C->getHtml();
|
||||
}
|
||||
}
|
||||
|
||||
$html .= "</" . $elementName . ">\n";
|
||||
} else {
|
||||
$html .= ' />';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
23
src/Html/Components/Text.php
Normal file
23
src/Html/Components/Text.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Erusev\Parsedown\Html\Components;
|
||||
|
||||
use Erusev\Parsedown\Html\Component;
|
||||
use Erusev\Parsedown\Html\Sanitisation\CharacterFilter;
|
||||
use Erusev\Parsedown\Html\Sanitisation\Escaper;
|
||||
|
||||
final class Text implements Component
|
||||
{
|
||||
/** @var string */
|
||||
private $text;
|
||||
|
||||
public function __construct(string $text)
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
public function getHtml(): string
|
||||
{
|
||||
return Escaper::htmlElementValue($text);
|
||||
}
|
||||
}
|
36
src/Html/Sanitisation/CharacterFilter.php
Normal file
36
src/Html/Sanitisation/CharacterFilter.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Erusev\Parsedown\Html\Sanisisation;
|
||||
|
||||
final class CharacterFilter
|
||||
{
|
||||
public static function htmlAttributeName(string $text) : string
|
||||
{
|
||||
/**
|
||||
* https://www.w3.org/TR/html/syntax.html#name
|
||||
*
|
||||
* Attribute names must consist of one or more characters other than
|
||||
* the space characters, U+0000 NULL, U+0022 QUOTATION MARK ("),
|
||||
* U+0027 APOSTROPHE ('), U+003E GREATER-THAN SIGN (>),
|
||||
* U+002F SOLIDUS (/), and U+003D EQUALS SIGN (=) characters,
|
||||
* the control characters, and any characters that are not defined by
|
||||
* Unicode.
|
||||
*/
|
||||
return \preg_replace(
|
||||
'/(?:[[:space:]\0"\'>\/=[:cntrl:]]|[^\pC\pL\pM\pN\pP\pS\pZ])++/iu',
|
||||
'',
|
||||
$text
|
||||
);
|
||||
}
|
||||
|
||||
public static function htmlElementName(string $text) : string
|
||||
{
|
||||
/**
|
||||
* https://www.w3.org/TR/html/syntax.html#tag-name
|
||||
*
|
||||
* HTML elements all have names that only use alphanumeric
|
||||
* ASCII characters.
|
||||
*/
|
||||
return \preg_replace('/[^[:alnum:]]/', '', $text);
|
||||
}
|
||||
}
|
27
src/Html/Sanitisation/Escaper.php
Normal file
27
src/Html/Sanitisation/Escaper.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Erusev\Parsedown\Sanisisation;
|
||||
|
||||
final class Escaper
|
||||
{
|
||||
public static function htmlAttributeValue(string $text) : string
|
||||
{
|
||||
return self::escape($text);
|
||||
}
|
||||
|
||||
public static function htmlElementValue(string $text) : string
|
||||
{
|
||||
return self::escape($text, true);
|
||||
}
|
||||
|
||||
private static function escape(
|
||||
string $text,
|
||||
bool $allowQuotes = false
|
||||
) : string {
|
||||
return \htmlentities(
|
||||
$text,
|
||||
$allowQuotes ? \ENT_NOQUOTES : \ENT_QUOTES,
|
||||
'UTF-8'
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user