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:
- Find RSS feed på det oplyste website
- Hent link og titel på seneste blogindlæg fra RSS feed
- 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
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:
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
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:
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!
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 😉
Link til seneste blogindlæg: CAPTCHA
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!
Link til seneste blogindlæg: Twitterbogen
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.
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 😉
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?
Link til seneste blogindlæg: I nærkontakt med Matt Cutts
@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
Link til seneste blogindlæg: Anmeldelse af Need for Speed Shift til Xbox 360
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
Link til seneste blogindlæg: I nærkontakt med Matt Cutts
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å?
Link til seneste blogindlæg: I nærkontakt med Matt Cutts
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
Link til seneste blogindlæg: Anmeldelse af Need for Speed Shift til Xbox 360
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’];
Link til seneste blogindlæg: I nærkontakt med Matt Cutts
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
Link til seneste blogindlæg: Anmeldelse af Need for Speed Shift til Xbox 360
Martin: Kanon, mange tak for hjælpen.
Så, nu må du gerne fortælle hvordan du har lavet din pingback funktion
Link til seneste blogindlæg: I nærkontakt med Matt Cutts
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
Link til seneste blogindlæg: I nærkontakt med Matt Cutts
@Jacob hvis du kører prøv en htmlentities(utf8_decode($output)) – burde klare ærterne
Link til seneste blogindlæg: Anmeldelse af Edge of Darkness
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
Link til seneste blogindlæg: I nærkontakt med Matt Cutts