Rozszerzone strip_tags()

12 listopada 2008

Ostatnio poprawiałem funkcjonalność get_meta_tags(), teraz przyszedł czas na strip_tags().

Najpierw kilka zdań o samej funkcji strip_tags() (dla tych, którzy jej nie znają chociaż każdy programista PHP znać ją powinien :P ).

Funkcja służy do łatwego, szybkiego i bezbolesnego pozbywania się tagów HTML z tekstu i przyjmuje dwa argumenty. Pierwszy to oczywiście tekst na którym ma pracować a drugi (opcjonalny) to lista tagów, które mają zostać pominięte podczas usuwania.

Przykład:

PHP:
  1. $tekst = 'To jest <b>test</b> działania <i>funkcji</i> strip_tags()';
  2. echo strip_tags($tekst);
  3. echo "\r\n";
  4. echo strip_tags($tekst, '<b>');

Powyższy kod PHP da nam taki wynik:

CODE:
  1. To jest test działania funkcji strip_tags()
  2. To jest <b>test</b> działania funkcji strip_tags()

Pierwsze wywołanie funkcji spowodowało usunięcie wszystkich tagów z tekstu. W drugim nakazaliśmy pominąć tagi <b> i tak też się stało.

Niestety czasami funkcja strip_tags() nie wystarcza. Oto przykład problematycznej sytuacji:

PHP:
  1. $tekst = 'Jakiś tekst
  2. <script type="text/javascript">
  3. jakiś kod JavaScript
  4. </script>
  5. dalsza część strony';
  6. echo strip_tags($tekst);

Wynik:

CODE:
  1. Jakiś tekst
  2.  
  3. jakiś kod JavaScript
  4.  
  5. dalsza część strony

Funkcja oczywiście zadziałała poprawnie ale w tym konkretnym przypadku pewnie większość osób wolałaby aby razem z tagami zostało usunięte to co było między nimi czyli kod JavaScript. Z tym jednak musimy sobie poradzić sami i tu z pomocą przychodzi moja funkcja:

PHP:
  1. function strip_tags_content($text, $tags = '', $invert = FALSE) {
  2.  
  3.   preg_match_all('/<(.+?)[\s]*\/?[\s]*>/si', trim($tags), $tags);
  4.   $tags = array_unique($tags[1]);
  5.    
  6.   if(is_array($tags) AND count($tags)> 0) {
  7.     if($invert == FALSE) {
  8.       return preg_replace('@<(?!(?:'. implode('|', $tags) .')\b)(\w+)\b.*?>.*?</\1>@si', '', $text);
  9.     }
  10.     else {
  11.       return preg_replace('@<('. implode('|', $tags) .')\b.*?>.*?</\1>@si', '', $text);
  12.     }
  13.   }
  14.   elseif($invert == FALSE) {
  15.     return preg_replace('@<(\w+)\b.*?>.*?</\1>@si', '', $text);
  16.   }
  17.   return $text;
  18. }

Funkcja przyjmuje trzy parametry. Pierwszy to tekst na którym pracujemy, drugi to lista tagów, które będą pominięte (o ile parametr trzeci jest ustawiony na FALSE, ustawienie domyślne) lub zostaną usunięte (gdy trzeci parametr ustawimy na TRUE).

Najlepiej zobrazuje to przykład. Tekst na którym będziemy pracować:

HTML:
  1. przykładowy tekst
  2. <script type="text/javascript">
  3. jakiś skrypt JavaScript
  4. </script>
  5. tekst abc
  6. <br /><br />
  7. <b>pogrubiony tekst</b>
  8. bla bla <span>lala</span> ble ble
  9. i jeszcze jedna linijka
  10. <div>kolejny tekst</div>

Efekt strip_tags():

HTML:
  1. przykładowy tekst
  2.  
  3. jakiś skrypt JavaScript
  4.  
  5. tekst abc
  6.  
  7. pogrubiony tekst
  8. bla bla lala ble ble
  9. i jeszcze jedna linijka
  10. kolejny tekst

Wywołanie strip_tags_content() bez parametrów (usunie wszystkie tagi z zawartością umieszczoną między nimi):

HTML:
  1. przykładowy tekst
  2.  
  3. tekst abc
  4. <br /><br />
  5.  
  6. bla bla  ble ble
  7. i jeszcze jedna linijka

Wywołanie strip_tags_content() z drugim parametrem o wartości '<script><span>' (ma usunąć wszystkie tagi oprócz <script> i <span>):

HTML:
  1. przykładowy tekst
  2. <script type="text/javascript">
  3. jakiś skrypt JavaScript
  4. </script>
  5. tekst abc
  6. <br /><br />
  7.  
  8. bla bla <span>lala</span> ble ble
  9. i jeszcze jedna linijka

Wywołanie strip_tags_content() z drugim parametrem o wartości '<span><b>' i trzecim parametrem ustawionym na TRUE (ma usunąć tylko tagi <span> i <b>):

HTML:
  1. przykładowy tekst
  2. <script type="text/javascript">
  3. jakiś skrypt JavaScript
  4. </script>
  5. tekst abc
  6. <br /><br />
  7.  
  8. bla bla  ble ble
  9. i jeszcze jedna linijka
  10. <div>kolejny tekst</div>

Mam nadzieję, że przykłady są jasne i nie trzeba nic wyjaśniać. Wyposażeni w obie funkcje (standardową strip_tags() i moją strip_tags_content() ) mamy pełną kontrolę nad tym co ma pozostać w tekście a co ma być z niego usunięte.

Dodaj komentarz

16 odpowiedzi dla tego wpisu

  1. cymerus napisał:

    jest tylko jedno ale :) „inline javascript” :) czyli javascript w tagach, chetnie zobaczylbym jaki masz pomysl na pozostawianie tagow, ale bezpiecznych tagow bez javascriptu

  2. MariuszT napisał:

    Jeżeli potrzebujesz usunąć wszystkie argumenty z tagów to sprawa jest prosta. Trochę więcej trzeba się narobić jeżeli chcesz usuwać tylko wybrane argumenty lub tylko wybrane zostawić.

    W komentarzach na stronie http://pl.php.net/strip_tags masz kilka prób usuwania argumentów dla tagów. Nie wiem jak to działa bo nie testowałem ;)

  3. Firenze_Alessio napisał:

    Hi guys. You made a great job with the strip_tags_content function..I have a question: i need to use regular expressions to replace a string that is not inside a tag < a > or inside a tag . This string can be inside other tags but not inside < a >. I’m not as good as you guys are with regular expressions, but i guess it’s the fastest way to do something like this.
    As strip_tags_content() shows, the regular expression should be something like this:
    @.*?@si
    but for example if i want to replace the word Hello with Bye, how should i edit the regex?
    Thanks in advance.

  4. MariuszT napisał:

    Hi, I got an email from you.

    Hi, sorry, i just posted a comment on your blog at this page http://www.tarnaski.eu/blog/ro.....trip_tags/ but i used a wrong syntax.
    If you read the comment, i wanted to replace a string that is not inside a tag a or inside a tag h1. I asked you how could i replace the word Hello with Bye for example where the word hello is not inside a tag a or h1.
    As your function shows, the regular expression should be something like this:
    @< (?!(?:a|h1)\b)(\w+)\b.*?>.*?@si
    But i don’t know what to do to look for the word hello.
    Thanks in advance

    What you want exactly to do:
    1) Replace all strings Hello (inside and outside all tags) except those in A tags?
    2) Replace all strings Hello in all tags except A tags but not outside the tags?
    3) Replace all strings Hello only in H1 tags (not inside and outside other tags).
    4) Replace all strings Hello only in H1 tags and outside other tags.
    5) …. ?

    Explain exactly what you want.

  5. Firenze_Alessio napisał:

    Sorry, i can tell that my explanation was really bad. I want to replace all strings Hello inside and outside all tags except those in A tags and except when the string Hello is an attribute of a tag, for example img alt=”Hello” shouldn’t be replaced. The regular expression above looks for tags a and h1, but i don’t really care to avoid strings between h1 tags. That regular expression is the one that your function strip_tags_content uses in the first case when it returns preg_replace(…)
    I don’t know if you can help me! Thanks!

  6. MariuszT napisał:

    Check this:
    $word1 = 'abc';
    $word2 = 'xyz';

    $text = 'abc def <a abc="abc">abc</a> <h1>abc</h1> <abc abc="abc">def abc def</abc> abc';
    echo htmlspecialchars($text), '<br />';

    $return = preg_replace('@(?:'. preg_quote($word1) .'(?!(?:[^<]+)?>))(?!</a[ >])@si', $word2, $text);

    echo htmlspecialchars($return);

    Result:
    abc def <a abc="abc">abc</a> <h1>abc</h1> <abc abc="abc">def abc def</abc> abc
    xyz def <a abc="abc">abc</a> <h1>xyz</h1> <abc abc="abc">def xyz def</abc> xyz

  7. Firenze_Alessio napisał:

    I think you are a genius! Thanks a lot! I hope this helps also someone else…It was pretty hard as regular expression or maybe i’m just an ignorant in that!

  8. MariuszT napisał:

    Regular expressions are very cool and powerful tool but it requires a lot of practice. I also did not immediately write each regexp.

    I am glad that I helped you. Greetings from Poland and Merry Christmas ;)

  9. Firenze_Alessio napisał:

    Yes you are right! Thanks again. Greetings from Italy and Merry Christmas!

  10. anonim napisał:

    Próbuje sprawić by funkcja dla wartości <b>znaki</b> nie usuwała wszystkie – a to robi..to zamierzone? Chyba powinna zostawić słowo ‘znaki’ ?

    echo strip_tags_content(‘<b>znaki</b>’);

  11. MariuszT napisał:

    Po to właśnie powstała ta funkcja aby w łatwy sposób móc usuwać tagi z całą ich zawartością. Jeżeli chcesz usunąć tylko taki B i zostawić to co między nimi to użyj zwykłej funkcji strip_tags().

  12. ebooki napisał:

    Świetny skrypt do użycia w każdym formularzu ładującym dane do bazy.

  13. mxf napisał:

    A co w przypadku bardziej złożonego kodu do ataku na strony?
    Zrobiłem test, powyższy skrypt przepuszcza taki kod.
    A co w przypadku bardziej złożonego kodu do ataku na strony?
    Np. „><script>JavaScript:alert(„Test XSS”);</script>

  14. MariuszT napisał:

    @mxf
    Przetestowałem Twój przykład, usunęło mi prawidłowo tag script z całą jego zawartością. Może coś przeoczyłeś?

  15. Flashstar napisał:

    Świetna funkcja zamierzam ją wykorzystać na moich stronach. Pozdrawiam i stawiam piwko… :)

  16. Konrad napisał:

    Dobra funkcja.

Odpowiedz



Podobne wpisy: