@codenerd på twitter Mit seneste tweet:

commentluv til din hjemmekodet blog – Hent seneste blogindlæg

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

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
/**
* Forsøg at finde et rss feed fra en given url
* @param string url til siden
* @return array med alle RSS feeds på siden
*/
function hentFeedUrl($url) {
    $c = curl_init();
    curl_setopt($c, CURLOPT_URL, $url);
    curl_setopt($c, CURLOPT_HEADER, 0);
    curl_setopt($c, CURLOPT_NOBODY, 0);
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_FRESH_CONNECT, 1);
    curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 2);    
    curl_setopt($c, CURLOPT_TIMEOUT,10);
    /* Fjern denne udkommentering hvis du er hostet på en server hvor der ikke er open_basedir restriction
    curl_setopt($c , CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($c, CURLOPT_MAXREDIRS, 3);
    */
    $kildekode = curl_exec($c);
    curl_close($c);
    //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
    preg_match_all('/<link([^>]*)>/i', $kildekode, $linkTags);
    $feeds = array();
    foreach ($linkTags[1] as $linkTag) {
        //hvis linktag indeholder application/rss+xml henter vi href fra dette ud
        if (preg_match('/type=["\']application\/rss\\+xml["\']/i',$linkTag) && preg_match('/href=["\']([^"\']+)["\']/i', $linkTag, $href)) {
                $feeds[]=$href[1];
        }
    }
    if (count($feeds)>0) {
        return $feeds;
    } else {
        return false;
    }
}
?>

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 php: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:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
Array
(
[0] => /rss-feeds/seneste.xml
[1] => /rss-feeds/andet-teknik/
[2] => /rss-feeds/arbejde/
[3] => /rss-feeds/gammelt-lort/
[4] => /rss-feeds/mit-vroevl/
[5] => /rss-feeds/motion--og--velvaere/
[6] => /rss-feeds/sitenews/
[7] => /rss-feeds/underholdning/
[8] => /rss-feeds/webudvikling/
)
?>

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

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

Hent kildekoden til hentPost.php

Funktionen bruger php: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.

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!

15 kommentarer

  1. Super fedt at du kommer med lidt guf til os “hjemmestrikkere” 😛

    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 😉

    Svar på kommentaren
  2. 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!

    Svar på kommentaren
  3. 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.

    Svar på kommentaren
  4. Skrevet af Mads Madsen  d. 24/01/2010 kl 01:22

    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 😉

    Svar på kommentaren
  5. 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?

    Svar på kommentaren
  6. @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

    Svar på kommentaren
  7. 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å?

    Svar på kommentaren
  8. 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

    <?php
    mysql_query(\"INSERT blahblah;\");
    $id = mysql_insert_id();
    ?>
    
    Svar på kommentaren
  9. 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’];

    Svar på kommentaren
  10. 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 :)

    Svar på kommentaren

Leave a Reply to Jacob Worsøe Cancel reply

Krævede felter er markeret med *.

*