Przycinanie stringów
Przy okazji przygotowywania do publikacji ostatniego artykułu, trafiłem na pewien problem. W oryginalnym tekście jest kilka bardzo długich adresów URL. Długie ciągi pozbawione spacji lub innych białych znaków mają niemiłą skłonność niszczenia układu strony i tak było też w tym wypadku. Jak sobie z tym poradzić?
Najprostsze rozwiązanie to reguła CSS:
#content {
overflow: hidden;
}
Ale skorzystanie z overflow
tworzy nowe problemy. Układ strony jest określony dość precyzyjnie (z
pikselową dokładnością) i aby równie dokładnie ustalić, co ma zostać
ukryte przez overflow
, musiałbym skorzystać z kolejnej własności CSS, clip
.
Tu z kolei okazuje się, że nie działa ona ani w IE, ani w Mozilli,
jeśli element nie jest pozycjonowany absolutnie. Specyfikacja milczy na
ten temat, a ja nie miałem ochoty zagłębiać się w temat. Przed chwilą,
dla pewności, stworzyłem sobie prosty dokument, w którym znajduje się
warstwa z określonym parametrem clip
. I rzeczywiście, działa on tylko wtedy, gdy warstwie nada się własność position: absolute
.
Jak nie pięścią, to młotkiem… W tym wypadku młotkiem okazały się wyrażenia regularne. Napisałem filtr wyjścia dla Smarty, który zawierał taki fragment:
preg_replace('/(?<=s|>)([^"'s<>]{50,})(?=s|<)/e',
'substr("$1", 0, 47)."..."',
$tpl_output);
Co robi ten kod? Wyszukuje wszystkie łańcuchy znaków pozbawione białych znaków, cudzysłowów oraz znaków <
i >
,
które dodatkowo są poprzedzone spacją, domknięciem znacznika (X)HTML, a
po nich następuje spacja lub początek nowego znacznika. Innymi słowy,
dopasowane zostają tylko te z długich stringów, które znajdują się we
wnętrzu znaczników (a więc w tekście strony), a nie zostaną
uwzględnione wartości atrybutów znaczników XHTML. Dzięki takiemu
rozwiązaniu można np. bez obaw podawać długie adresy URL w znaczniku <a>
i nie zostaną one obcięte. Natomiast długie ciągi (tu: powyżej 50
znaków) wewnątrz tagów zostaną skrócone, a na ich końcu pojawi się
trzykropek, aby poinformować, że coś zostało usunięte.
Jeśli ktoś nie rozumie, o czym tu piszę i chciałby to zmienić, zapraszam do rozdziału poświęconego wyrażeniom regularnym w manualu PHP.
Jak napisałem, filtrowanie odbywa się na etapie wyświetlania strony przez Smarty. Bardziej efektywne byłoby obcinanie stringów przed zapisem w bazie danych – dzięki temu przy ich wyświetlaniu nie trzeba by by się martwić o ich długość. Zdecydowałem się jednak na to rozwiązanie, bo nigdy nie wiadomo, czy ten długi łańcuch kiedyś nie będzie potrzebny – zawsze dobrze mieć go w bazie :).
Już po fakcie znalazłem w podręczniku Smarty wbudowaną funkcję wordwrap
. Myślałem, że może zastąpić mój filtr, ale ma jedną sporą wadę: dodaje znaki nowego wiersza (\n
) także w obrębie długich atrybutów XHTML, psuje więc np. długie URL-e.
Ale przecież wyrażeń regularnych należy unikać jak ognia! Dokładnie. Szczególnie ten wzorzec, który napisałem powyżej, jest dość zabójczy – wystarczy że kilku użytkowników zacznie stosować go na często odwiedzanych stronach i można wykończyć niejeden serwer. Z ciekawości zrobiłem testy szybkości: włączenie tego filtra wydłużało czas generowania strony z artykułem średnio 10%. To bardzo dużo, jak na jedną funkcję. Na pewno nie należy stosować takich rozwiązań, jeśli strona generuje spory ruch. W takim wypadku lepiej filtrować przed zapisaniem tekstu w bazie.
Przy okazji, moja klasa PHP do testowania szybkości generowania stron jest na serwerze. Jeśli ktoś nie potrzebuje kombajnu w rodzaju pakietu Benchmark z PEAR, może przydać mu się mój 1,5-kilobajtowy skrypt. W pliku jest również dokumentacja.
Comments are closed