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