Replace fragile HTML allowlist sanitizer
This commit is contained in:
@@ -51,19 +51,20 @@
|
||||
- Fehler enthalten Query-Kontext ohne Secrets.
|
||||
- Verhalten entspricht der definierten Error-Strategie.
|
||||
|
||||
- #TODO Replace fragile HTML allowlist sanitizer
|
||||
- Aufwand: `M`
|
||||
- Labels: `security`, `string`
|
||||
- Akzeptanzkriterien:
|
||||
- `onlySimpleHTML()` wird durch robusteren Ansatz ersetzt.
|
||||
- Erlaubte Tags sind konfigurierbar dokumentiert.
|
||||
- Regression-Tests fuer typische Eingaben vorhanden.
|
||||
|
||||
- #TODO Code-Qualitaet
|
||||
|
||||
- Sammel-Issue: Naming-Konvention, SQL-Binding-Refactor, Legacy-Markierung, Markdown-Konsolidierung, klare Modulgrenzen.
|
||||
- Code-Qualitaet (aufgeteilt in Unter-Issues)
|
||||
- Aufwand: `L`
|
||||
- Empfehlung: in 3-5 Unter-Issues aufteilen.
|
||||
- Labels: `quality`, `refactor`
|
||||
- Unter-Issues:
|
||||
- Define and enforce naming conventions for functions, files and constants.
|
||||
- Refactor SQL binding helpers to one consistent, typed API surface.
|
||||
- Mark legacy functions/modules (`@deprecated`) and document replacement path.
|
||||
- Consolidate Markdown docs (README + API notes) into one canonical structure.
|
||||
- Clarify module boundaries and ownership (I/O, SQL, parsing, formatting).
|
||||
- Akzeptanzkriterien:
|
||||
- Kurzer Styleguide in `README.md` vorhanden und auf bestehende Dateien angewendet.
|
||||
- Keine neuen Legacy-Einstiege ohne Markierung und Migrationshinweis.
|
||||
- SQL-Helper nutzen einheitliche Signaturen in geaenderten Modulen.
|
||||
- Modulgrenzen sind in Doku und Dateistruktur konsistent nachvollziehbar.
|
||||
|
||||
- #TODO Tests und Tooling
|
||||
|
||||
|
||||
209
string.php
209
string.php
@@ -129,137 +129,88 @@ function markUp(string $text): string {
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
function onlySimpleHTML(string $s): string {
|
||||
$s = str_replace ( array (
|
||||
'<',
|
||||
'>'
|
||||
), array (
|
||||
'{{|-<-|}}',
|
||||
'{{|->-|}}'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}b{{|->-|}}',
|
||||
'{{|-<-|}}b/{{|->-|}}'
|
||||
), array (
|
||||
'<b>',
|
||||
'<b/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}u{{|->-|}}',
|
||||
'{{|-<-|}}u/{{|->-|}}'
|
||||
), array (
|
||||
'<u>',
|
||||
'<u/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}i{{|->-|}}',
|
||||
'{{|-<-|}}i/{{|->-|}}'
|
||||
), array (
|
||||
'<i>',
|
||||
'<i/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}span{{|->-|}}',
|
||||
'{{|-<-|}}span/{{|->-|}}'
|
||||
), array (
|
||||
'<span>',
|
||||
'<span/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}b{{|->-|}}',
|
||||
'{{|-<-|}}b/{{|->-|}}'
|
||||
), array (
|
||||
'<b>',
|
||||
'<b/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}br{{|->-|}}',
|
||||
'{{|-<-|}}br/{{|->-|}}'
|
||||
), array (
|
||||
'<br>',
|
||||
'<br/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}h1{{|->-|}}',
|
||||
'{{|-<-|}}h1/{{|->-|}}'
|
||||
), array (
|
||||
'<h1>',
|
||||
'<h1/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}h2{{|->-|}}',
|
||||
'{{|-<-|}}h2/{{|->-|}}'
|
||||
), array (
|
||||
'<h2>',
|
||||
'<h2/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}h3{{|->-|}}',
|
||||
'{{|-<-|}}h3/{{|->-|}}'
|
||||
), array (
|
||||
'<h3>',
|
||||
'<h3/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}h4{{|->-|}}',
|
||||
'{{|-<-|}}h4/{{|->-|}}'
|
||||
), array (
|
||||
'<h4>',
|
||||
'<h4/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}h5{{|->-|}}',
|
||||
'{{|-<-|}}h5/{{|->-|}}'
|
||||
), array (
|
||||
'<h5>',
|
||||
'<h5/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}h6{{|->-|}}',
|
||||
'{{|-<-|}}h6/{{|->-|}}'
|
||||
), array (
|
||||
'<h6>',
|
||||
'<h6/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}li{{|->-|}}',
|
||||
'{{|-<-|}}li/{{|->-|}}'
|
||||
), array (
|
||||
'<li>',
|
||||
'<li/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}ul{{|->-|}}',
|
||||
'{{|-<-|}}ul/{{|->-|}}'
|
||||
), array (
|
||||
'<ul>',
|
||||
'<ul/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}ol{{|->-|}}',
|
||||
'{{|-<-|}}ol/{{|->-|}}'
|
||||
), array (
|
||||
'<ol>',
|
||||
'<ol/>'
|
||||
), $s );
|
||||
$s = str_replace ( array (
|
||||
'{{|-<-|}}pre{{|->-|}}',
|
||||
'{{|-<-|}}pre/{{|->-|}}'
|
||||
), array (
|
||||
'<pre>',
|
||||
'<pre/>'
|
||||
), $s );
|
||||
function onlySimpleHTML(string $s, ?array $allowedTags = null): string {
|
||||
if ($s === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// cleanup
|
||||
$s = str_replace ( array (
|
||||
'{{|-',
|
||||
'-|}}'
|
||||
), array (
|
||||
'',
|
||||
''
|
||||
), $s );
|
||||
if ($allowedTags === null) {
|
||||
$allowedTags = array (
|
||||
'b',
|
||||
'u',
|
||||
'i',
|
||||
'span',
|
||||
'br',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'li',
|
||||
'ul',
|
||||
'ol',
|
||||
'pre'
|
||||
);
|
||||
}
|
||||
|
||||
return $s;
|
||||
$allow = array_fill_keys ( array_map ( 'strtolower', $allowedTags ), true );
|
||||
$selfClosing = array (
|
||||
'br' => true
|
||||
);
|
||||
|
||||
$parts = preg_split ( '/(<[^>]*>)/', $s, - 1, PREG_SPLIT_DELIM_CAPTURE );
|
||||
if ($parts === false) {
|
||||
return htmlspecialchars ( $s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||
}
|
||||
|
||||
$out = '';
|
||||
foreach ( $parts as $part ) {
|
||||
if ($part === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($part[0] !== '<') {
|
||||
$out .= $part;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match ( '/^<\s*(\/?)\s*([a-z0-9]+)\s*(\/?)\s*>$/i', $part, $m ) !== 1) {
|
||||
$out .= htmlspecialchars ( $part, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||
continue;
|
||||
}
|
||||
|
||||
$isClose = ($m[1] === '/');
|
||||
$tag = strtolower ( $m[2] );
|
||||
$isSelfClose = ($m[3] === '/');
|
||||
|
||||
if (! isset ( $allow[$tag] )) {
|
||||
$out .= htmlspecialchars ( $part, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isClose) {
|
||||
if (isset ( $selfClosing[$tag] )) {
|
||||
continue;
|
||||
}
|
||||
$out .= "</{$tag}>";
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isSelfClose && ! isset ( $selfClosing[$tag] )) {
|
||||
$out .= "</{$tag}>";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset ( $selfClosing[$tag] )) {
|
||||
$out .= "<{$tag}>";
|
||||
continue;
|
||||
}
|
||||
|
||||
$out .= "<{$tag}>";
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
function linkify(string $input): string {
|
||||
$pattern = '@(http(s)?://[a-zA-Z0-9/\.\#\-\_]*)@';
|
||||
|
||||
Reference in New Issue
Block a user