webForumDet fria alternativet

Ta bort <img> taggar med särskilda url:er

PHP

10 svar · 909 visningar · startad av UrMe

Medlem sedan apr. 2001762 inlägg
Frågan#1

Jag har denna kod idag som inte fungerar till 100%.

//Matchar vissa bilder som inte ska visas.
$exludedimages[] = 'http:\/\/(.*)feedsportal.com|';
$exludedimages[] = 'http:\/\/api.tweetmeme.com|';
$exludedimages[] = 'http:\/\/feeds.feedburner.com|';
$exludedimages[] = 'http:\/\/(.*)imrworldwide.com';

$search .= '/<img.*src="(';
foreach($exludedimages as $imageurl) {
	$search .= $imageurl;
}
$search .= ')(.*?)".*\/?>/';

$replace = '';
$news['description'] = preg_replace ($search, $replace, $news['description']);

Ibland tar den bort allt innehåll av någon anledning, varför fattar jag inte.

Två exempel här på html:

$news['description'] innehåller precis som det visas nedan i detta fall:

<p><a href="http://www.bullet.nu/" target="_blank">BULLET</a> är på gång med ett nytt album. Plattan som fått namnet "Highway Pirates" <br />beräknas att nå butikerna den 4 februari. <br /><br />Omslag och låtlista hittar du i vår kalender för skivsläpp som finns <a href="http://www.rocknytt.se/kalender/skivslaepp/icalrepeat.detail/2011/02/04/160/1/bullet-highway-pirates.html" target="_self"><strong>här</strong></a><br /><br /><img src="http://www.rocknytt.se/images/stories/Artister/bulletpirates2.jpg" border="0" /><br /><br /></p>

$news['description'] blir helt tom om jag kör denna html

<img src="http://www.idg.se/polopoly_fs/1.356358!idgTeaserImage/imageTypeSelector/localImage/4143341562.jpg" border="0"><br>Amerikanska myndigheter stängde och beslagtog 82 domäner. Nu riktar flera organisationer skarp kritik mot agerandet.<img src="http://feeds.feedburner.com/~r/idg/vzzs/~4/9NAZHtdycJw" height="1" width="1"/>

Skillnaden är ju att i den andra hittar den feeds.feedburner.com.

Men varför tar den bort allt i $news['description']?

Medlem sedan apr. 2001762 inlägg
#2

Tror jag att jag har allokerat problemet, om det är 2st img taggar och så matchar den allt från första <img till den andra src="http och därför tar den bort allting däremellan.

Så frågan är hur jag skriver min regexp på ett bättre sätt? För det kan ju stå <img border="0" height="0" width="0" src="http://....."> i img taggen och det vill jag ju också matcha.

Medlem sedan juni 20014 290 inlägg
#3

Tänk på regex's "greedy" matchning.

Ex:

$aaa="aa bb aa bb aa bb";

Med utrycket /aa.*aa/ så matchas "aa bb aa bb aa"

Med utrycket /aa.*?aa/ så matchas "aa bb aa"

Medlem sedan juni 20014 290 inlägg
#4

Att du inte får något kvar beror på att du matchar <img.*src="http:\/\/feedburner.com".*/> vilket gör att du matchar allt från första <img "allt mellan fram till" src="http://feedburner.com" "allt mellan fram till" />.

Om du ändrar "<img.*src" till "<img src" så stämmer det bättre.

Sedan har du ett fel om du inte tidigare nollställer search variabeln. Skriver man $search .= "aaa" så är det samma som $search=$search."aaa". Om du då innan inte använt $search variabeln så är det undefined. Gäller den raden innan for loopen.

Medlem sedan aug. 20039 340 inlägg
#5

.* matchar allt, och är greedy. Du vill att ')(.*?)".*\/?>/' ska matcha eventuella mellanslag innan />. Istället glufsar den glatt i sig allt annat, som du har upptäckt själv. En lösning är att matcha [^>] som betyder "alla tecken som inte är >".

För öfvrigt har jag gjort ett par andra förändringar i koden: Det stavas excluded, inte exluded. Ändrade till att använda den inbyggda funktionen implode för att sammanfoga strängarna. Det betyder även att du slipper ange | manuellt på varje rad och hålla reda på vilka rader som ska ha och inte ha | på slutet. Ändrade den inledande tecknet i regexet från / till #. Det gör att slasharna inte behöver escapeas. (I gengäld måste dock självklart eventuella # i uttrycket escapeas!)

//Matchar vissa bilder som inte ska visas. 
$excludedimages[] = 'http://(.*)feedsportal.com'; 
$excludedimages[] = 'http://api.tweetmeme.com'; 
$excludedimages[] = 'http://feeds.feedburner.com'; 
$excludedimages[] = 'http://(.*)imrworldwide.com'; 

$search = '#<img[^>]+src="('; 
$search .= implode('|', $excludedimages);
$search .= ')(.*?)"[^>]*/?>#'; 

$replace = ''; 
$news['description'] = preg_replace ($search, $replace, $news['description']);
Medlem sedan aug. 20039 340 inlägg
#6

GunnarD skrev:

Om du ändrar "<img.*src" till "<img src" så stämmer det bättre.

Bara en kommentar på detta. Det skulle funka, men bara halvvägs. "<img src" matchas då korrekt, men .* i .*\/?> skulle ändå glufsa på för fullt.

Medlem sedan apr. 2001762 inlägg
#7

Jo jag förstod att det blev fel att den matchade allt från första <img till sista src=" och därför tog bort allt.

Tack för stavfelet du hittade nitro2k01 :) och även koden som fungerar kanon!

Skulle dock behöva en liten förbättring och det är att den även matchar om det är "enkelfnuttar" runt src etc t.ex så här:

<img width='1' height='1' src='http://rss.feedsportal.com/c/mf.gif' border='0'/>

Dags att verkligen lära sig regexp känns det som, men man får grepp om det mer och mer.

Jag ändrade regexpen till detta för att matcha ovan också:

$search = '#<img[^>]+src=.('; 
$search .= implode('|', $excludedimages);
$search .= ')(.*?)[^>]*/?>#';

Satt en punkt efter src= och tog bort " efter (.*?).

Är detta den bästa lösningen?

Medlem sedan aug. 20039 340 inlägg
#8

Nu känner man sig dum. Jag kollade igenom koden .*? och kom på vad det står för, nämligen lat (lazy) matchning. Det gör helt enkelt att matchningen inte glufsar tecken så sjukligt. (Och denna metod skulle även kunna användas istället för [^>]* för att förhindra överdriven glufsning.)
Vad gäller din kod, jo visst funkar den men jag skulle hellre matcha så exakt som möjligt, dvs i detta fall ["']? alltså " eller ' en eller ingen gång. (Notera att ' är escapeat i strängen, eftersom strängen använder enkelfnuttar!)

$search = '#<img[^>]+src=["\']?('; 
$search .= implode('|', $excludedimages);
$search .= ')(.*?)["\']?[^>]*/?>#';

Detta uttryck är dock inte perfekt. Det skulle även matcha en IMG-tagg med olika sorters fnuttar, typ src="http://www.rocknytt.se/images/stories/Artister/bulletpirates2.jpg' men det får man väl ha överseende med. På samma sätt har deluttrycket http://api.tweetmeme.com en subtil sidoeffekt eftersom . matchar allt. Om någon skulle regga http://api-tweetmeme.com eller http://apixtweetmeme.com och lägga in bilder från de domänerna i feeden så skulle de också ryka. På liknande sätt så kräver inte uttrycket att domänen efterföljs av / så även något som http://api.tweetmeme.com.superskoj.nu/minbild.jpg skulle ryka. (Understruket: Vad domändelen matchar. Resten matchas av (.*?))

Detta är väl iofs relativt harmlöst i detta fall, och folk får skylla sig själv om de råkar göra något sånt kan man tycka, men ändå bra att känna till, och en bra tankeövning.

Medlem sedan apr. 2001762 inlägg
#9

Tackar så mycket! Det där med att . matchar allt på t.ex api.tweetme etc kommer nog inte bli några problem ändå. Men bra att veta om, jag hade aldrig tänkt på det :)

Medlem sedan aug. 20039 340 inlägg
#10

Precis. Nästa gång kanske du vill matcha URLer pga säkerhetsskäl, och då kan en harmlös bugg som denna bli till ett säkerhetshål som går att utnyttja.

För övrigt, din signatur innehåller ett fel. :)

Medlem sedan apr. 2001762 inlägg
#11

nitro2k01 skrev:

För övrigt, din signatur innehåller ett fel. :)

Tiden går så fort :)

335 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
122 ms — deklarationer (db)
0 ms — hämta statistik (cache)
205 ms — hämta tråd, inlägg och bilagor (db)
127 ms — ändringar (db)