How to Build a Feed Reader with SimplePie and SQLite

A lot of us are familiar with these terms: RSS feeds or simply called feeds and feed readers.

Basically, a feed is a data format used by websites as a medium for providing users with its content.
To keep yourself abreast on latest update from your favorite websites, you usually will subscribe to the website feeds using a feed reader which can be a mobile-phone, computer or web application.

In this article, you will learn how to build a simple feed reader application using SimplePie ( a fast and easy-to-use PHP feed parser ) and SQLite database for the back-end.

Feed Reader Web Application

Planning the Database

We are only using a single table `feeds` with three column that will contain the id, name and URL of the feed.


CREATE TABLE feeds (
id INTEGER PRIMARY KEY, 
name VARCHAR(255), 
url VARCHAR(255) NOT NULL);

Unlike MySQL, you don’t need to specify AUTO_INCREMENT in the id column for auto-incrementation.

Declaring the column INTEGER PRIMARY KEY will do the trick.

The PHP Class

The class consist of a constant, six properties and seven methods including the __construct magic method.

Below is the list of the class constant, properties and their roles.

protected $conn: stores the PDO connection.

public $add_feed_status: set to TRUE if feed successfully added to DB.

public $delete_feed_status: set to TRUE if feed successfully deleted from DB.

public $feedoutput: save the fetched feed object retrieved from DB.

public $feedURLS: store all feeds URL retrieved from DB.

public $simplePie_object: stores the SimplePie object.

Let’s get started coding the class.

Create the class with name FeedReader containing the above constant and properties.


    <?php
    
    class FeedReader {
        // path to SQLite database
    
        const DSN = 'sqlite:C:\sqlite\feedreader.db';
    
        /**
         * PDO connection
         * @see self::__construct()
         */
        protected $conn;
    
        /**
         * TRUE if feed successfully added to DB
         * @see self::addFeed()
         */
        public $add_feed_status;
    
        /**
         * TRUE if feed successfully deleted from DB
         * @see self::deleteFeed()
         */
        public $delete_feed_status;
    
        /**
         * stores the fetched feed object retrieved from DB
         * @see self::retrieve_feed()
         */
        public $feedoutput;
    
        /**
         * stores all the feed URL in DB
         * @see self::feedURLS()
         */
        public $feedURLS;
    
        /**
         * save the SimplePie object
         * @see self::simplePie()
         */
        public $simplePie_object;

In __construct magic method, a connection to SQLite database using PDO_SQLITE DSN is made.


    public function __construct() {
        try {
            $pdo = new PDO(self::DSN);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->conn = $pdo;
        } catch (PDOException $e) {
            trigger_error('Unable to connect to the database server.');
            exit;
        }
    }

Create a method that fetches the feed ids, names & URLs from the database and save it to $feedoutput property which will come in handy in displaying the list of feed in the database when building the index.php and settings.php file.


    public function retrieve_feed() {
        $conn = $this->conn;
        $sql = 'SELECT id, name, url FROM feeds';
        $query = $conn->query($sql);
        $this->feedoutput = $query->fetchAll(PDO::FETCH_OBJ);
    }

The front page of our feed reader displays a mash-up of all feeds content stored in the database. It does so only if the simplePie method contains no argument (feed URL).

The feedURLS() method fetches only feed URL from DB and save it to the feedURLS property.


    public function feedURLS() {
        $conn = $this->conn;
        $sql = 'SELECT url FROM feeds';
        $query = $conn->query($sql);
        $this->feedURLS = $query->fetchAll(PDO::FETCH_OBJ);
    }

The settings.php file that handles the insertion and deletion of feeds; prior to adding a feed, displays this message: “You don’t have any feeds yet! Try adding some”.
This is achieve when the count_feed_record() method below returns no record.


    public function count_feed_record() {
        // get the PDO connection
        $conn = $this->conn;
        try {
            $sql = 'SELECT COUNT(*) FROM feeds';
            $query = $conn->query($sql);
            $count = $query->fetchColumn();
        } catch (PDOException $e) {
            trigger_error('fail to retrieve record count');
        }
        return $count;
    }

The addFeed() handles the insertion of feed record to the DB. It accepts two arguments (name and URL of feed).

If no name is specified, this method retrieves the feed title from the URL and set it as the name using SimplePie’s get_title() method.


    public function addFeed($name, $url) {
        // get the PDO connection
        $conn = $this->conn;

        // include SimplePie by calling the simplePie() method
        $this->simplePie($url);

        // get SimplePie object
        $feed = $this->simplePie_object;

        $names = (empty($name)) ? $feed->get_title() : $name;
        try {
            $sql = 'INSERT INTO feeds (name, url) VALUES (:name, :url)';
            $update = $conn->prepare($sql);
            $update->bindValue(':name', $names);
            $update->bindValue(':url', $url);
            $update->execute();
            if ($update) {
                $this->add_feed_status = TRUE;
            }
        } catch (PDOException $e) {
            echo $e->getMessage(), $e->getLine();
        }
    }

The deleteFeed() method handles the deletion of feed record specified with an ID pass as it argument.


    public function deleteFeed($id) {
        // get the PDO connection
        $conn = $this->conn;
        try {
            $sql = "DELETE FROM feeds WHERE id=:id";
            $delete = $conn->prepare($sql);
            $delete->bindValue(':id', $id);
            $delete->execute();
            if ($delete) {
                $this->delete_feed_status = TRUE;
            }
        } catch (Exception $e) {
            die('fail to delete');
        }
    }

Finally, the simplePie class that installs and configure SimplePie library.
We’ll be installing SimplePie on our project via Composer.

Create a composer.json file populated with this code:


{
    "require": {
        "simplepie/simplepie": "1.3.1"
    }
}

Run $ php composer.phar install to fetch the SimplePie source file.

To use SimplePie in our project, simply include require ‘vendor/autoload.php’; to our simplePie method.


    public function simplePie($feedurl = '') {
        //fetches only feed url from DB
        $this->feedURLS();

        // loop through and store the URLS to $feeds_url as array
        foreach ($this->feedURLS as $url) {
            $feeds_url[] = $url->url;
        }

        // if feed URL is empty, an array of feed urls in db is set
        $feedurl = (empty($feedurl)) ? $feeds_url : $feedurl;

        // Include SimplePie
        require_once 'vendor/autoload.php';

        // Instantiate SimplePie
        $feed = new SimplePie();

        // Set the feed to process.
        $feed->set_feed_url($feedurl);

        // Run SimplePie.
        $feed->init();

        // Send content to the browser as text/html and the UTF-8 character set.
        $feed->handle_content_type();

        // save simplepie object to @property $simplePie_object
        $this->simplePie_object = $feed;
    }

The front page (index.php) of the feed reader displays a mash-up of all feed contents with the individual feeds at the left sidebar. When a given feed link is clicked, only the content of that feed get displayed.


<?php
// include the feed reader class
include 'class.reader.php';

// instantiate the class
$instance = new FeedReader;

// retrieves the feed record from DB
$instance->retrieve_feed();

// get the feed URL for processing by SimplePie
$feedurl = (isset($_GET['feed'])) ? $_GET['feed'] : null;

// pass the feed url to SimplePie
$instance->simplePie($feedurl);
$feed = $instance->simplePie_object;

// below are just bunch of html mixed with SimplePie feed method
// for retrieving the feed content
?>


<!DOCTYPE html>
<html>
    <head>
        <title>Feed Reader web application</title>
    </head>
</html>
<body>
    <div><a href="settings.php" style="position: fixed">Add / remove feeds</a></div>
    <table> <tr><thead><th><h2 style="position: fixed">Feeds</h2></th><th><h2>Content</h2></th></thead></tr>
<tr>
    <td valign="top" width="30%">
        <span style="position: fixed">
            <p><a href="index.php">All feeds</a></p>
            <?php
            // loop through each feed content
            foreach ($instance->feedoutput as $rows) :
                $feed_name = ($rows->name == 'null') ? $feed->get_title() : $rows->name;
                ?>
                <p><a href="?feed=<?php echo $rows->url; ?>"><?php echo $feed_name; ?></a></p>
<?php endforeach; ?>
        </span>
    </td>
    <td>

        <div class="header">
            <h1><a href="<?php echo $feed->get_permalink(); ?>"><?php echo $feed->get_title(); ?></a></h1>
            <p><?php echo $feed->get_description(); ?></p>
        </div>

        <?php
        // Here, we'll loop through all of the items in the feed.
        // the $item represents the current item in the loop.

        foreach ($feed->get_items() as $item):
            ?>

            <div class="item">
                <h2><a href="<?php echo $item->get_permalink(); ?>"><?php echo $item->get_title(); ?></a></h2>
                <p><?php echo $item->get_description(); ?></p>
                <p><small>Posted on <?php echo $item->get_date('j F Y | g:i a'); ?></small></p>
            </div>

        <?php endforeach; ?>
    </td></tr></table>
</body>
</html>

The settings.php file handles the addition and removal of feeds from the database.


<?php
include 'class.reader.php';
$instance = new FeedReader;
include 'add-feed.html';
?>


<?php
if (isset($_POST['submit'])) {
    if (empty($_POST['url'])) {
        echo "complete the form";
    } else {
        $name = $_POST['name'];
        echo $name;
        $url = $_POST['url'];
        $instance->addFeed($name, $url);
        if ($instance->add_feed_status) {
            header('location: settings.php');
        }
    }
}
?>



<table>
    <thead>
        <tr>
        <th>Feed Name</th>
        <th>URL</th>
        <th>Remove Feed</th>
        </tr>
    </thead>
    <tbody>
        <?php if ($instance->count_feed_record() < 1) { ?>
            <tr><td>You don't have any feeds yet! Try adding some.</td></tr>
        <?php
        } else {
            $instance->retrieve_feed();

            foreach ($instance->feedoutput as $rows) {
                ?>
                <tr><td>
                <span style="padding: 2px; margin: 3px"><?php echo $rows->name; ?></span>
                </td>
                <td><span><?php echo $rows->url; ?></span></td>
                <td><a href="delete.php?id=<?php echo $rows->id; ?>">Delete</a></td>
                </tr>
            <?php } ?>
        </tbody>
    </table>

    <?php
}

The add-feed.html file that is included in the code above is just an HTML form code that collects the feed data to be inserted to the database. the code is as follows.


<!DOCTYPE html>
<head>
    <title>Add / Delete feeds</title>
</head>
<body>
    <h2><a href="index.php">Return to feed reader</a></h2>
    <div><h2>Add feed to Reader</h2></div>
    <form action="" method="post">
        <p><strong>Name</strong> (If no name is specified, it will be taken from the feed)</p>
        <input type="text" name="name"/>

        <p><strong>Feed address (URL):</strong></p>
        <input type="text" name="url"/>
        <input type="submit" name="submit" value="save"/>
    </form>
</body>

From the settings.php code above, you could see the delete.php file handles the deletion of feed record from the database.


<?php
include 'class.reader.php';
$instance = new FeedReader;

$id = $_GET['id'];
$instance->deleteFeed($id);
if ($instance->delete_feed_status) {
    header('location: settings.php');
}
Conclusion

There you have it, your own very feed reader. Here is a Demo.

A lot can be done to improve this application such as:

– Adding pagination to break the number of feed content into pages.
– Providing an option to reduce the number of feed using set_item_limit method or by passing a start and length argument to get_items.
– This application lack CSS design. you might want to add one.

Feel free to fork this feed reader code on GitHub and don’t forget to share your contributions and improvements.

Don’t miss out!
Subscribe to My Newsletter
Invalid email address