Jump to Content

Negotiating RSS Headers with PHP

RSS clients usually check every hour or so to see if your feed has changed. Often, the entire RSS feed is downloaded and reloaded. With many subscribers, or a large feed, this process consumes a lot of (unnecessary) bandwidth. It is unnecessary as most feeds don't change every hour. In this article, a technique known as HTTP conditional GET is discussed, implementated in PHP. The headers sent by a client requesting the RSS feed are parsed to see if the client already has an up-to-date copy. A new copy of the feed is only sent back if the feed has changed since the client last downloaded it. This significantly reduces the bandwidth consumed by serving RSS feeds.

To negotiate with the client, we will be using two pairs of headers: If-Modified-Since and Last-Modified, If-None-Match and Etag. The Last-Modified header is sent by the server whenever a feed is requested, and indicates the last modification date of the file. This date is sent back to the server by the client on subsequent requests in the If-Modified-Since header. The Etag header is sent by the server to the client: it is a unique string summarising the state of the feed. Identical feeds will result in identical Etag header values. The If-None-Match header is sent back by the client on subsequent requests for the feed, and contains the Etag string from the last downloaded feed version.

Sending the response

The last-modified time of your feed will be the date of the most recent content, and extracting this value will depend on your own RSS implementation. We will summarise our feed (for the Etag header) by taking the hash of this last modification date. We send the Last-Modified and Etag headers for every request. However, if the client already has an up to date copy of the feed, we will send back a 304 status code rather than the full content.

PHP 5

  1. <?php
  2. /**
  3. * Parses headers to perform conditional GET.
  4. *
  5. * @param int $last_modified UNIX last modified time
  6. */
  7. function executeConditionalGet($last_modified)
  8. {
  9. $rfc822_fmt = 'D, d M Y H:i:s \G\M\T';
  10. $rfc822 = gmdate($rfc822_fmt,$last_modified);
  11. header("Last-Modified: $rfc822");
  12. header('Etag: '.md5($last_modified));
  13. if (clientContentIsCurrent($last_modified)) {
  14. header('HTTP/1.0 304 Not Modified');
  15. exit(); /* no need to send content, so exit. */
  16. }
  17. }
  18. ?>

Parsing the Request Headers

The request headers we are interested in are parsed into PHP's $_SERVER superglobal. To be conservative, we will only not send the full content if both the If-Modified-Since and If-None-Match headers match the current version of the RSS feed.

PHP 5

  1. <?php
  2. /**
  3. * Whether the client already has a current copy.
  4. *
  5. * @param int $last_modified UNIX time RSS last mod
  6. * @return bool whether the client copy is current
  7. */
  8. function clientContentIsCurrent($last_modified)
  9. {
  10. $etag = md5($last_modified);
  11. if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ||
  12. !isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
  13. return false;
  14. }
  15. $modified = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
  16. $client_etag = $_SERVER['HTTP_IF_NONE_MATCH'];
  17. if (strtotime($modified,$last_modified)!==0) {
  18. return false;
  19. }
  20. if (strcasecmp($client_etag,$etag)!==0) {
  21. return false;
  22. }
  23. return true;
  24. }
  25. ?>

To Wrap Up

Using these two functions along with the last modification time of your feed can save you a lot of bandwidth. If you want to truly optimise your RSS feeds, make sure you also use the inbuilt tags to influence client behaviour (ttl, skipDays and skipHours) and consider transparently gzipping your feed before sending it.

Snapshot

RSS feeds typically consume large amounts of bandwidth as they are frequently polled for new content. This can be reduced by examining the request headers, and only sending the feed contents when it has been updated.

Share

Articles

Who we are

Openknot is the web design agency of Rob Tuley. We specialise in creating visually clean, dynamic sites with PHP and MySQL.

Find out more

Find out what we do. Browse our previous work. Take a closer look at who we are. Enjoy our articles. We hope you'll see we are passionate about our work.

Get in touch

Want us to work for you? Have a question about what we do?