phpbar.de logo

Mailinglisten-Archive

[php] Alle noch nicht anklickbaren Links anklickbar machen

[php] Alle noch nicht anklickbaren Links anklickbar machen

Yannik Hampe yannik at cipher-code.de
Fr Apr 16 14:25:49 CEST 2010



Ralf Eggert wrote:
> Hallo Yannik,
> 
> danke für deine Mühe. Habe mittlerweile den Holzhammer raus geholt und
> das Ganze anders aufgezogen:
> 
> ------------------------------------------------------------------------
> preg_match_all(
>   '=(http:|https:)//[^ )\r\n!<"\']++=i', $htmlBody, $linkList
> );
> 
> $linkList = array_unique($linkList[0]);
> 
> if (count($linkList) > 0)
> {
>   foreach ($linkList as $key => $link)
>   {
>     if (preg_match_all(
>       '^<a(.*)' . $link . '(.*)>(.*)</a>^iU', $htmlBody, $linkListSingle

1. Solltest du $link escapen bevor du es einfach in eine preg-funktion 
schmeißt: preg_quote($link)
2. Muss ich dich trotzdem enttäuschen. Versuch's mal mit diesen inputs:
$htmlBody='<a href="http://foo.bar">http://foo.bar</a> http://foo.bar';
$htmlBody='<img src="http://foo.bar" />';

Bei ersterem wird der zweite Link nicht klickbar gemacht und bei dem 
zweiten... Naja... Das Bild ist danach hin.

> ------------------------------------------------------------------------
> 
> D.h. zuerst werden alle Links gefunden, die mit http oder https
> beginnen. Danach wird dann für jeden einzelnen Link geprüft, ob er sich
> innerhalb eines <a> Tags befinden. Wenn nein, wird er ersetzt. Ansonsten
> eben nicht.
> 
> Performancemäßig ist das sicherlich auch suboptimal, aber es
> funktioniert. Sogar bei sowas Ekelhaftem wie ein OnClick, um ein Popup
> zu öffnen...

onclick? Aber auch nur wenn sich das onclick in einem <a>-tag befindet...
> 
> Danke und Gruss,
> 
> Ralf

Ich habe da auch nochmal was gebastelt. Ist auch garnicht so lang, wenn 
du dir die Kommentare wegdenkst, sollte zumindest /relativ/ performant 
sein und tut was es soll. Mir fällt zumindest gerade nichts ein, wie man 
den folgenden qt verwirren kann:

snip
---
preg_match_all(
   '=(?:http:|https:)//[^ )\r\n!<"\']++=i', $htmlBody, $linkList, 
PREG_OFFSET_CAPTURE);
$newlist = array();
foreach($linkList[0] as $listItem)
{
   $newlist[$listItem[1]] = $listItem[0];
}
krsort($newlist);
foreach($newlist as $offset => $link)
{
   $linkLen = strlen($link);
   // Is the link within an attribute of a tag?
   if (($nextClosePos = strpos($htmlBody, '>', $offset + $linkLen)) !== 
false)
   {
     // It could be. There is a > in the sourcecode somewhere following 
the link
     // check if it is the closing tag of our link
     $nextOpeningTag = strpos($htmlBody, '<', $offset + $linkLen);
     if ($nextOpeningTag === false || $nextOpeningTag > $nextClosePos)
     {
       // now we proved that there is no opening tag before our tag that 
we found closes.
       // Thus we are in an attribute and we ignore that one.
       continue;
     }
     // If we made it to this point, we ware not in an attribute
   }
   // Is there a closing tag behind that one?
   if (($closeTagPos = strpos($htmlBody, '</a', $offset + $linkLen)) !== 
false)
   {
     echo "Found a closing tag at pos $closeTagPos\nchecking ", 
substr($htmlBody, $offset + $linkLen, $closeTagPos - $offset - 
$linkLen), "\n";
     // yes, there is a closing tag behind that one. Check if that 
closing-tag belongs to this link
     // We do this by checking if there is an <a\s between the end of 
the link and the </a we found
     // if there is none, then this element has already got an <a> tag 
and so we ignore it
     if (!preg_match('/<a(?:\s|>)/', substr($htmlBody, $offset + 
$linkLen, $closeTagPos - $offset - $linkLen)))
       continue;
   }
   // We need to add the tag
   $htmlBody = substr($htmlBody, 0, $offset).'<a 
href="'.$link.'">'.$link.'</a>'.substr($htmlBody, $offset + $linkLen);
}
---
/snip
Code comes with 14-days-money back guarantee - oh wait, it's free :-).


Yannik

php::bar PHP Wiki   -   Listenarchive