Til Top

Hvis du er aktiv i blogosfæren, er du sikkert stødt på Commentluv. Commentluv er et plugin til Wordpress, der i alt sin enkelthed henter dit seneste blogindlæg, når du afgiver kommentar på de sider, som har dette slået til. Dette gør at du, for det meste, får et godt do-follow link, med den helt rigtige ankertekst.

Ideen bag commentluv er fantastisk, og dette var en af de features jeg simpelthen måtte implementere her på bloggen, selvom jeg ikke bruger Wordpress. Princippet bag Commentluv er enkelt:

  1. Find RSS feed på det oplyste website
  2. Hent link og titel på seneste blogindlæg fra RSS feed
  3. Gem data

Ovenstående lyder jo simpelt, og det er det faktisk også. Vi skal bruge 2 funktioner, en til at finde et evt. RSS feed ud fra en given url, og en til at hente og behandle RSS feedet.

PHP Funktion til at finde RSS feed på et website

Kopier til udklipsholder | Vis uden linie #
01 <?php
02 /**
03 *  Forsøg  at  finde  et  rss  feed  fra  en  given  url
04 *  @param  string  url  til  siden
05 *  @return  array  med  alle  RSS  feeds  på  siden
06 */
07 function  hentFeedUrl($url)  {
08        $c  =  curl_init();
09        curl_setopt($c,  CURLOPT_URL,  $url);
10        curl_setopt($c,  CURLOPT_HEADER,  0);
11        curl_setopt($c,  CURLOPT_NOBODY,  0);  
12        curl_setopt($c,  CURLOPT_RETURNTRANSFER,  1);  
13        curl_setopt($c,  CURLOPT_FRESH_CONNECT,  1);
14        curl_setopt($c,  CURLOPT_CONNECTTIMEOUT,  2);
15        curl_setopt($c,  CURLOPT_TIMEOUT,10);  
16        /*  Fjern  denne  udkommentering  hvis  du  er  hostet  på  en  server  hvor  der  ikke  er  open_basedir  restriction
17        curl_setopt($c  ,  CURLOPT_FOLLOWLOCATION,  1);
18        curl_setopt($c,  CURLOPT_MAXREDIRS,  3);
19        */
20        $kildekode  =  curl_exec($c);
21        curl_close($c);
22        //hent  alle  <link>  tags  ud  -  disse  kan  være  andet  end  RSS  så  vi  gennemløber  og  henter  kun  href  for  dem  der  er  rss
23        preg_match_all('/<link([^>]*)>/i',  $kildekode,  $linkTags);
24        $feeds  =  array();
25        foreach  ($linkTags[1]  as  $linkTag)  {
26                //hvis  linktag  indeholder  application/rss+xml  henter  vi  href  fra  dette  ud
27                if(preg_match('/type=["\']application\/rss\+xml["\']/i',$linkTag)  &&  preg_match('/href=["\']([^"\']+)["\']/i',  $linkTag,  $href))  {
28                                $feeds[]=$href[1];
29                }
30        }
31        if(count($feeds)>0)  {
32                return  $feeds;
33        }  else{
34                return  false;
35        }
36 }
37 ?>

Hent kildekoden til hentFeedUrl.php

Har du en server hvor der ikke er nogen open_basedir restriction anbefaler jeg du fjerner udkommenteringen på linie 16 til 19, da dette vil gøre funktionen i stand til at følge redirects, dvs hvis brugeren angiver www.domæne.dk som website, og dette domæne redirecter til www.domæne.dk/blog vil funktionen stadig fange RSS feed på destinationsurlen. Vi bruger lib cURL() til at hente websitets indhold, hvis cURL ikke er tilgængelig kan du hente en file_get_contents version af funktionen her: hentFeedUrl_file_get_contents.php

Funktionen er nem at bruge, og giver dig et array retur med alle RSS feeds fundet på siden. Stopper du fx URLen www.martin-nielsen.com ind i ovenstående funktion får du et array der ser sådan her ud:

Kopier til udklipsholder | Vis uden linie #
01 <?php
02 Array
03 (
04        [0]  =>  http://www.martin-nielsen.com/rss-feeds/seneste.xml
05        [1]  =>  http://www.martin-nielsen.com/rss-feeds/andet-teknik/
06        [2]  =>  http://www.martin-nielsen.com/rss-feeds/arbejde/
07        [3]  =>  http://www.martin-nielsen.com/rss-feeds/gammelt-lort/
08        [4]  =>  http://www.martin-nielsen.com/rss-feeds/mit-vroevl/
09        [5]  =>  http://www.martin-nielsen.com/rss-feeds/motion--og--velvaere/
10        [6]  =>  http://www.martin-nielsen.com/rss-feeds/sitenews/
11        [7]  =>  http://www.martin-nielsen.com/rss-feeds/underholdning/
12        [8]  =>  http://www.martin-nielsen.com/rss-feeds/webudvikling/
13 )
14 ?>

De fleste blogsystemer er heldigvis lavet således at det vigtigste feed kommer først, og derfor antager vi det er sådan. Nu har vi som sagt et array med RSS links, nu skal vi så hente titel og link til det seneste blogindlæg.

NB Funktionen virker kun på sider som bruger rss autodiscovery, men det gør de mest populære blogsystemer heldigvis også, og hvis ikke er det en stor fejl at bruge disse

PHP Funktion til at hente blogindlæg fra et RSS Feed

Kopier til udklipsholder | Vis uden linie #
01 <?php
02 /**
03 *  Henter  indlæg  fra  et  rss  feed
04 *  @param  string  url  til  rss  feed
05 *  @param  integer  antal  poster  der  skal  hentes
06 *  @return  array  med  titler  og  links  til  indlæg
07 */
08 function  hentPost($url,$antal=1)  {
09        $poster=array();
10        //hent  feed  med  simplexml
11        if($feed  =  simplexml_load_file($url))  {
12                $i=0;
13                //gennemløb  feed  så  længe  der  er  poster  og  vi  ikke  har  hentet  max  $antal
14                do  {
15                        $postTitel  =  $feed->channel[0]->item[$i]->title;
16                        $postLink  =  $feed->channel[0]->item[$i]->link;
17                        $postTekst  =  $feed->channel[0]->item[$i]->description;
18                        $poster[]=array(
19                                                        'titel'=>(string)$postTitel,
20                                                        'link'=>(string)$postLink,
21                                                        'tekst'=>(string)$postTekst
22                                                        );
23                        $i++;
24                }  while  ($feed->channel[0]->item[$i]  &&  $i<$antal);
25              }
26        if(count($poster)>0)  {
27                return  $poster;
28        }  else{
29                return  false;        
30        }
31 }
32 ?>

Hent kildekoden til hentPost.php

Funktionen bruger simple_xml() til at tilgå den seneste post i RSS feedet. Titel og link til denne post retuneres i array, og vi er nu klar til at gemme i database sammen med kommentarens øvrige data. Her vil jeg anbefale at du laver en ekstra tabel med kommentar_id, seneste_link og seneste_titel. Alternativt kan du selvfølgelig tilføje link kode direkte til dit kommentar felt, men dette vil give dig mindre kontrol med data i længden, og bør generelt frarådes.

Ligeledes vil jeg på det kræftigeste fraråde at du henter seneste blogindlæg live, hent altid indlæget når brugeren skriver sin kommentar, og gem dette i databasen.

Samlet eksempel

Hvis du er i tvivl om hvordan ovenstående kan kodes ind i din blog, så er her et samlet eksempel, med en meget forenklet kommentarformular:

Live demo

Hent kildekoden til samlet eksempel

Afsluttende bemærkninger

En ting du skal være opmærksom på hvis du aktiverer denne feature på din blog, er at nogen vil begynde at kommentere på din side netop for at få et link til deres blogindlæg. Her må du som blogejer tage en beslutning om hvad du ønsker at tillade. Har selv haft problemstillingen oppe og vende: Hvornår er en kommentar spam?

Grunden til jeg har valgt at lave min commentluv klon i to funktioner i stedet for en er, at funktionerne jo også kan bruges uafhængigt af hinanden, ønsker du fx hente alle poster i et feed hvor du kender url kan du også bruge hentPost() til det, du kan selvfølgelig skrive funktionerne sammen til en funktion hvis du ønsker det.

Som altid håber jeg at kunne inspirere dig til at lege med din egen blogplatform, hvad enten det bare er for sjov eller mere seriøst.

Har du spørgsmål, rettelser eller generelle kommentarer så skriv endelig!

kommentarer

Skrevet d. 21. Januar 2010 20:49 af Jan Ebsen
Bruger billede Super fedt at du kommer med lidt guf til os "hjemmestrikkere" :P

Men må nok indrømme at jeg personligt er mere nysgerrig efter hvordan du har lavet din "Pingbacks" funktion, så den håber jeg der kommer mere om på en tidspunkt ;)
Skrevet d. 21. Januar 2010 21:02 af Jon Ussing
Bruger billede Cool Martin!

Superinspirerende blogpost

jeg elsker når du ruller ud med lidt php-nørderi. - Har tit haft stor glæde af det fif som du tidligere har delt om ping service:
http://www.martin-nielsen.com/php-blog-ping-v05-nemmere-end-nemt_184.html

Når man som mig ikke kun arbejder med Wordpress eller et andet out of the box system er det rigtig rart når der er hjælp og inspiration at hente.

Tak!
Skrevet d. 21. Januar 2010 21:22 af Martin Nielsen
Bruger billede Glad for det kan bruges, og det gør da også jeg vil fortsætte med at udgive nogle af mine blogfunktioner

@Xircow, der skal nok komme noget om pingback halløj - som dels er baseret på et gammelt xml-rpc library som vist ikke er tilgængeligt mere.
Skrevet d. 24. Januar 2010 01:22 af Mads Madsen
Bruger billede Edit: Hovsa, så ikke du havde sat NOBODY, så betyder resten af mit indlæg ikke så meget :p

Faktisk rigtig interessant, men synes dog dit script er lidt overkill, ville nok sætte curl_setopt($c, CURLOPT_RANGE, "1-5120") for at begrænse størrelsen af de data som du laver en regex på. :-)

Grunden til at jeg ville begrænse størrelsen af data'erne, er for at spare på ressourcerne, der er ingen ingen grund til at parse f.eks. 50kb, når det kun er de første 3kb der er relevant. :-)

Men ellers skide godt indlæg, er selv ved at skrive et lille bloging system i python, så det er dejligt med lidt inspiration ;)
Skrevet d. 5. Februar 2010 13:50 af Jacob Worsøe
Bruger billede Endnu en kanon artikel fra din hånd, Martin! Den skal helt sikkert implementeres ovre hos mig med det samme.

Lige et spørgsmål. Du skriver: "Her vil jeg anbefale at du laver en ekstra tabel med kommentar_id, seneste_link og seneste_titel."

Hvor egentlig det, fremfor bare at lave et par ekstra felter i ens nuværende kommentar tabel med seneste_link og seneste_titel?
Skrevet d. 5. Februar 2010 14:18 af Martin Nielsen
Bruger billede @Mads, god ide med curlopt_Range, har vist bare ladet timeout stå for det, men det er da væsentligt smartere at cutte den på den her måde

@Jacob, man kunne sagtens have det som to ekstra felter, men der sidder normalisering så dybt i mig, så felter der kan/vil være tomme i nogle rows bør splittes ud i en tabel for sig, således at du ikke har en masse null værdier i din hovedtabel
Skrevet d. 5. Februar 2010 14:20 af Jacob Worsøe
Bruger billede Martin: Okay, ja det kan jeg godt se ikke ser så pænt ud. Det ligger bare ikke så dybt i mig - jeg har faktisk aldrig hørt begrebet før :)
Skrevet d. 5. Februar 2010 14:25 af Jacob Worsøe
Bruger billede Nu sidder jeg lige og roder lidt med det, og hvordan finder du egentlig ud af hvilket id den pågældende kommentar får?

Man kan selvfølgelig smide kommentaren i databasen og så trække den seneste kommentar ud igen og se hvilket id den har, inden man så finder rss feed og smider det i den næste tabel. Men er det måden at gøre det på?
Skrevet d. 5. Februar 2010 14:31 af Martin Nielsen
Bruger billede Det betyder ikke så meget på små sider, men på trafiktunge sites er normalisering utrolig vigtig for at alt kører så hurtigt som muligt, selv ting som datatype på fx kommentar_id vil få betydning, hellere bruge en smallint unsigned end en int, med mindre man regner med at skrive mere end 65535 indlæg :-)

Nå nok om det,
Når kommentaren er indsat så kan du hente dens id efterfølgende med mysql_insert_id(); fx

Kopier til udklipsholder | Vis uden linie #
01 <?php
02 mysql_query("INSERT  blahblah;");
03 $id  =  mysql_insert_id();
04 ?>
Skrevet d. 5. Februar 2010 23:32 af Jacob Worsøe
Bruger billede Martin: lækkert tip! Det får jeg helt sikkert brug for i fremtiden. Hvis du lige skal hjælpe mig helt i mål, kan du så fortælle mig f.eks. $senestePost[0]['link'] ind i mysql?

Hvis jeg sætter den ind som denne:
VALUES ('$id','$senestePost[0]['link']','$senestePost[0]['titel']')

Får jeg denne fejl:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'link']','Array['titel']')' at line 1

Jeg har løst det ved at lave dem om til variabler, men det er da pænere hvis man kan sætte dem direkte ind istedet for at:
$link = $senestePost[0]['link'];
$titel = $senestePost[0]['titel'];
Skrevet d. 7. Februar 2010 20:38 af Martin Nielsen
Bruger billede Jacob, du skal bare ud af dine double quotes fx:

VALUES ('$id','".$senestePost[0]['link']."','".$senestePost[0]['titel']."')

ellers tror php du afslutter strengen inde i $senestePost
Skrevet d. 10. Februar 2010 18:51 af Jacob Worsøe
Bruger billede Martin: Kanon, mange tak for hjælpen.

Så, nu må du gerne fortælle hvordan du har lavet din pingback funktion :)
Skrevet d. 17. Februar 2010 14:38 af Jacob Worsøe
Bruger billede Martin: Har du lavet ændret noget i scriptet så den viser ÆØÅ korrekt? Hvis jeg bare bruger scriptet fra din demo, så kommer mit link f.eks. til at se således ud:
"I nærkontakt med Matt Cutts"

Man kunne selvfølgelig bare erstatte æ med æ eller "æ", men du har garanteret en bedre løsning :)
Skrevet d. 17. Februar 2010 14:57 af Martin Nielsen
Bruger billede @Jacob hvis du kører prøv en htmlentities(utf8_decode($output)) - burde klare ærterne
Skrevet d. 17. Februar 2010 15:34 af Jacob Worsøe
Bruger billede Lækkert, det virker perfekt. Men det skal åbenbart gøres inden man putter det i databasen. Man kan ikke gøre det når man trækker dem ud. Det kunne jeg i hvert fald ikke :)

skriv kommentar

Felter markeret med gult og * er påkrævet







Sikkerheds kode


Pingbacks

Hvis du linker til en af mine blog artikler fra et blogsystem der udsender pings vil du få et gratis do-follow link fra mig, du kna også twitte om en post og få et link til din twitter profil (Jeg forbeholder mig dog retten til at slette eller nofollow spam :P)

Pingback d. 21. Januar 2010 18:16 fra http://twitter.com/jarlskov
Tweetback fra: @jarlskov
RT @codenerd: Koder du selv din blog, så læs hvordan du kan lave en commentluv klon her ...]
Pingback d. 21. Januar 2010 17:21 fra http://twitter.com/henrik_andersen
Tweetback fra: @henrik_andersen
RT @codenerd: Koder du selv din blog, så læs hvordan du kan lave en commentluv klon her ...]
Pingback d. 21. Januar 2010 12:42 fra http://twitter.com/ulstrup
Tweetback fra: @ulstrup
RT @codenerd: [DK-BLOG] commentluv til din hjemmekodet blog - Hent seneste blogindlæg ...]