Demotywatory.pl, znany polski serwis humorystyczny. Jednak serwis ma jedną niedogodność – trzeba wchodzić na strone internetową aby zobaczyć obrazki. Podobnie w przypadku kanału RSS – nie ma możliwości obejrzenia obrazka w treści wiadomości. Jest problem jest i fix:
5 plików rozwiązujących problem:
- Remote.php
- FeedException.php
- Debug.php
- Feed.php
- index.php
Pierwszy z nich, rozbudowany aż nadto co powinien być, jednak faza testowania wymagała porównania prędkości działania kilku rozwiązań. Curl został domyślnym, ze względu na jego szybkość i niezawodność.
<?php
/*
* Read remote file with some methods
*
* @author drymek
*
*/
class Remote
{
/*
* Read file with default method
*/
public static function get_remote_file_content($url)
{
return self::get_with_curl($url);
}
/*
* Curl - default method for Remote
*/
public function get_with_curl($url)
{
// create a new cURL resource
$ch = curl_init();
// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// grab URL and pass it to the browser
$content = curl_exec($ch);
// close cURL resource, and free up system resources
curl_close($ch);
return $content;
}
/*
* file_get_contents use buildin PHP function
*/
public function get_with_file_get_contents($url)
{
return file_get_contents($url);
}
/*
* fopen and fgets functions to read file
*/
public function get_with_fopen($url)
{
$fh = fopen($url, 'rb');
if (!$fh)
{
return '';
}
$content = '';
while (!feof($fh))
{
$content .= fgets($fh, 1024);
}
fclose($fh);
return $content;
}
}
Drugi z plików zapewnia jedynie możliwość wyrzucania wyjątków z klasy Feed.
<?php
/*
* Feed Exception class
*
* @author drymek
*
*/
class FeedException extends Exception
{
}
Klasa Debug umożliwia wypisywanie informacji kontrolnych podczas pisania kodu:
<?php
/*
* Simple debug class
*
* @author drymek
*
*/
class Debug
{
/*
* Print debug message on default output
*/
public static function Log($message)
{
//Check debug mode
if (DEBUG)
{
echo $message."\n";
}
}
}
Klasa Feed! Czyli mięso właściwe. To co pobiera wszystkie informacje, przetwarza je i zapisuje:
<?php
require_once 'Remote.php'; //Read remote files
require_once 'FeedException.php'; //Implementation of Feed Exception
require_once 'Debug.php'; //Debug message
/*
* Class to convert demotywatory.pl rss
*
* @author drymek
*
*/
class Feed
{
private
$url, //rss.xml file url
$orginalContent, //rss.xml file content
$transformedDom; //rss.xml file DOMDocument
/*
* Set feed url
*/
public function setUrl($url)
{
$this->url = $url;
}
/*
* Read remote rss file
*/
public function getOrginalContent()
{
if (is_null($this->url))
{
throw new FeedException("You have to set url first!");
}
$this->orginalContent = Remote::get_remote_file_content($this->url);
return $this->orginalContent;
}
/*
* Create a DOMDocument from rss.xml file
*/
public function getDomOrginalContent()
{
if (false === $this->orginalContent || is_null($this->orginalContent))
{
throw new FeedException("Can not download rss file");
}
$domDocument = new DOMDocument();
$domDocument->loadXML($this->orginalContent);
return $domDocument;
}
/*
* Get image URL from remote webpage
*/
public function getImage($item)
{
if ('link' == $item->nodeName)
{
$htmlContent = Remote::get_remote_file_content($item->nodeValue);
if (false !== $htmlContent)
{
//Search image tag
$pattern = "/bigurl=\".*\"/";
preg_match($pattern, $htmlContent, $urls);
//Finally url to the image
return substr($urls[0], 8, -1);
}
return 'http://demotywatory.pl/res/img/demotywatory-logo.gif';
}
}
/*
* Set new description for current item
*/
public function setImage($item)
{
//Find element link
foreach ($item->childNodes as $rssDomItemChild)
{
if ('link' == $rssDomItemChild->nodeName)
{
//Download demot page
$url = $this->getImage($rssDomItemChild);
break;
}
}
//Find element description
foreach ($item->childNodes as $rssDomItemChild)
{
if ('description' == $rssDomItemChild->nodeName)
{
$rssDomItemChild->nodeValue = '<img src="'.$url.'">';
break;
}
}
Debug::Log('Found url: ['.$url.']');
}
/*
* Convert rss.xml to rss.xml with images in description
*/
public function transform()
{
//Get DOMDocument
$this->transformedDom = $this->getDomOrginalContent();
//Find all items
$rssItems = $this->transformedDom->getElementsByTagName('item');
//Foreach feed
Debug::Log('Starting retriving feeds');
foreach ($rssItems as $rssItem)
{
//Set image in description for node
$this->setImage($rssItem);
}
Debug::Log('Finished retriving feeds!');
}
/*
* Get transformed XML
*/
public function getResults()
{
return $this->transformedDom->saveXml();
}
/*
* Save results to file (xml)
*/
public function save($filename)
{
Debug::Log('Saving file ('.$filename.')');
$fh = fopen($filename, 'w');
if (!$fh)
{
throw new FeedException('Can not open file ('.$filename.') to write!');
}
fwrite($fh, $this->getResults());
fclose($fh);
}
}
I ostatni z plików który wszystko uruchamia:
<?php
define('DEBUG', true); //Set debug on
require_once 'Feed.php'; //Include Feed class
//Create new Feed instance
$feed = new Feed();
//Set feed url
$feed->setUrl('http://demotywatory.pl/rss.xml');
//Get rss file content
$feed->getOrginalContent();
//Convert to new format
$feed->transform();
//Save to file
$feed->save('result.xml');
Teraz wystarczy umieścić pliki na serwerze lub jeśli takiego nie posiadamy to można skorzytać np. z hostei.com (webhosting umożliwiający otwieranie plikow curl/fopen).
I magia! Mamy rss z obrazkami demotywatorów w wiadomości! (Należy oczywiście odświeżać co jakiś czas nasze domotywatory, jednak użycie crona i wgeta w tej sytuacji jest w 100% wystarczające
Demotywatorator
« Druga część.
3
komentarzy