-
Mój problem: chcę uzyskać coś, co byłoby w pewnym sensie połączeniem wyposażonej w rozumienie składni funkcji strip_tags() i funkcji htmlspecialchars(). Mianowicie przepuszczającą konkretne tagi, a resztę zamieniającą na encje. Dodatkowym wymogiem jest to, żeby uniknąć niezamkniętych tagów lub tagów z krzyżowym zamknięciem (coś w stylu przykładowo
<b><i>tekst</b></i>
) - innymi słowy generowany dokument ma być prawidłowo parsowany - dodajmy - w XHTML 1.1. -
Moje dotychczasowe próby: W sumie cały dzisiejszy dzień (odkąd wstałem, tj. ok 14 ;) ) poświęciłem tej funkcji, z przerwami na jedzenie i inne takie, oraz zajrzenie parę razy na 4p i forum.jabberpl.org, ale mniejsza o to. Dotychczas udało mi się sklecić coś takiego:
function htmlallowtags($string = '')
{
$string = htmlspecialchars($string, ENT_NOQUOTES);
$string = str_replace('>', '>', $string);
$string = preg_replace('/<br\s*\/>/', "\n", $string);
$string = nl2br($string);
$string = str_replace("\n", ' ', $string);
$pattern = '/<((a)|(q|blockquote|strong|ins|em|b|u|i))(?(2)( href="[^<>"]*")?|())?>((([^<])|(<br\s*\/>)|(<[^<>]*?>[^<]*?<[^<>]*?>))*?)<\/\1>/';
$replacement = '<$1$4>$6</$1>';
$oldstring = '';
while($oldstring!=$string) { $oldstring=$string; $string = preg_replace($pattern, $replacement, $string); }
$string = str_replace(Array('<blockquote>', '</blockquote>'), Array('<blockquote><div>', '</div></blockquote>'), $string);
$string = preg_replace(Array('/<(\/?)b>/', '/<(\/?)u>/', '/<(\/?)i>/'), Array('<$1strong>', '<$1ins>', '<$1em>'), $string);
return $string;
}
?>
Już wyjaśniam po kolei co funkcja ma za zadanie robić po kolei: Najpierw wszystko zamieniane jest przez funkcję htmlspecialchars. Efekt chyba wiadomy. Następnie zamieniam > na >, coby mieć uproszczone zadanie potem. Następnym krokiem jest zamiana wszystkich
na znak końca linii, zastosowanie nl2br i usunięcie znaków końca linii - wszystko w celu unormalizowania przykładowo
,
i
do jednego
, zamianę znaków końca linii na
i pozbycie się znaków końca linii, żeby regexp działał jak trzeba (na dmkhost "\n" nie jest znakiem podlegającym pod . w regexp Perla).
Następnym krokiem jest moje wyrażenie regularne.
Na koniec zamieniane są <u>
na <ins></code>, <code><b>
na <strong></code>, <code><i></code> na <code><em></code> i <code><blockquote>
na <blockquote><div></code> - wszystko w celu uniknięcia problemów z faktem, że blockquote nie może zawierać czystego tekstu, tylko elementy blokowe, a
nie istnieje w xhtml, zaś <code><b></code> i <code><i>
zamieniam jakoby "przy okazji".
<blockquote><blockquote>cytat w cytacie</blockquote>cytat</blockquote>
wszystko się rozjeżdża, w związku z zabezpieczeniem przed krzyżowaniem tagów. Niestety nie mogę zamienić zachłanności przeszukiwania, bo wtedy przykładowo <b>tekst</b> tekst <b>tekst</b>
będzie zamieniane na <b>tekst</b> tekst <b>tekst</b>
, gdyż najpierw zamienione zostaną pierwszy tag otwierający z ostatnim zamykającym, a reszta nie będzie się zgadzać.
Ma ktoś jakiś pomysł, jak ten problem możnaby rozwiązać?
P.S. Właściwie zaczynam dopiero z RegExp, pewnie to jest nieoptymalne i dałoby się zrobić prościej. Jak ktoś podpowie jak, będę wielce wdzięczny.
//Dodano:
Przepraszam za kiepskie formatowanie, ale użycie <u>
i innych takich bez znacznika <code>
powodowało, że były one interpretowane jako znaczniki formatowania.
P.S.2. Funkcja do zamykania tagów się tu rozjeżdża :P
</b></b></i></i></u></u></u>