Showing posts with label php. Show all posts
Showing posts with label php. Show all posts

Thursday, September 9, 2010

The Facebook Like button PITA: fb_xd_fragment=

So I have been using Facebook's like button for awhile now. I have it on a couple blogs, and a site I maintain using drupal. I started noticing that I was getting requests with a query of "?fb_xd_fragment=". This is a problem, because it shows a blank page.

I did some investigating, and this seems to be caused by two bugs (that I can tell). One, that Facebook's API causes a bug in IE that sends this query in the first place, and second that my website, because of the Facebook API, causes the page to become visibly blank because of it.

So, what to do? I decided to kill the query string at the source: my apache web server using mod_rewrite.

So here's what I added to the apache config for just this web server:

RewriteEngine On
RewriteCond %{QUERY_STRING} fb_xd_fragment=
RewriteRule (.*) $1? [R=301]

So this basically sends a 301 HTTP code (Moved Permanently) with the same request, minus the query string. Note that the "?" on the RewriteRule is needed so that mod_rewrite doesn't append the old query back on. Seems to be doing the trick, and now I'm not losing traffic due to a Facebook API bug.

Friday, June 11, 2010

Feedburner: Adding Flattr to your FeedFlare (Part: 2)

This is a follow up to my previous post: Feedburner: Adding Flattr to your FeedFlare.

I've been wrestling around with FeedBurner's FeedFlare API for a few nights now. Most notably I've had trouble getting some of the documented xPath functions to work, and dealing with what appears to be delays in updating the flare after you add it.

My goal was to add categories to the DynamicFlare href so you could pass those along to Flattr. The problem is that if you add something like ${a:category[1]/@term} to the href, and a:category[1] doesn't exist in your feed, it will not add the flare to your feed (sort of like a filter if the attribute proves false()).

In a final decision of anger, I decided to drop any passing of information from the DynamicFlare href other than the feedUrl. This in itself proved difficult, since ${feedUrl} doesn't work as advertised. I instead opted to pass ${a:link[@rel="self"]/@href} which appears to work on my feed. YMMV.

I've gotten rid of the files I linked to in my last post so people don't use them. For the quick and dirty, here's the URL to use for Personal FeedFlare now:

http://www.swissdisk.com/~bcollins/feedflare/flattr-me-dynamic-v2.php

There are two options you can pass to this script:

  • uid: Your Flattr UID (required)
  • lng: Your preferred language (defaults to en_GB, aka English)

I used this for mine:

http://www.swissdisk.com/~bcollins/feedflare/flattr-me-dynamic-v2.php?uid=17833&lng=en_GB

That's it! The new script will parse the feed in the second script and pass up to 980 characters as the desc, up to 80 characters of the title and all of the categories as tags.

You can also check here for all the PHP-Source files so you can modify to your liking.

Tuesday, June 8, 2010

Feedburner: Adding Flattr to your FeedFlare

Update 2010-06-11: This article and information with-in are superseded by Feedburner: Adding Flattr to your FeedFlare (Part: 2)

I've added Flattr to my blog and also wanted to add it to my feedburner FeedFlare, but alas, no one has yet to create one. So I've gone through the trouble of doing it for you :)

First, I went to the Feedburner FeedFlare API documentation. I wont go into the details of writing your own flare, but I opted for the dynamic type, since it would allow me to show how many times one of my blog posts had been flattered.

Second, I dove into the Flattr JavaScript API. I don't think they recommend this, but it's the only way I could get to the button information contained in their default IFrame.

Third, I downloaded the PHP Simple HTML DOM Parser. There's probably a simpler way to parse the IFrame sent back from Flattr, but I opted for this method since it was pretty straight forward.

For the lazy, you can use my existing FeedFlare URLs as your own. You will need to go to your feedburner page, login, select the feed you want to add this to, click on "Optimize" and then "FeedFlare". Below the stock list you will see a place to enter a URL. Enter the URL below and BE SURE to replace "your_uid" with your Flattr UID, else you wont get the money.

http://www.swissdisk.com/~bcollins/flattr-me-dynamic.php?uid=your_uid

For the interested, here are the two files I've created. First is the dynamic PHP FeedFlare file:

<FeedFlareUnit>
  <Catalog>
    <Title>Flattr Me</Title>
    <Description>
      Adds a Flattr link including flattr count for each feed unit.
    </Description>
    <Link href="http://www.swissdisk.com/~bcollins/flattr-me-dynamic.php?uid=flattr_uid"/>
    <Author email="benmcollins13@gmail.com">Ben Collins
  </Catalog>
  <DynamicFlare href="http://www.swissdisk.com/~bcollins/flattr-me-static.php?uid=<?
        print $_GET['uid']; ?>&title=${title}&link=${link}"/>
  <Sample>Flattr (11)</Sample>
</FeedFlareUnit>

Note that the <Link> element references another PHP script, and that this is in fact PHP. This allows us to pass along the Flattr UID to the second script, which is the one that actually produces the FeedFlare (feedburner periodically checks the second URL it gets from this file for updates to the FeedFlare).

Now, the second script is the one that uses the simple_html_dom.php library I spoke of. You will see it referenced in the file below. Basically I pack the data just like the original Flattr load.js script does, and request the Flattr button, and then rip a few bits of information from it:

<?
include_once("simple_html_dom.php");

$btn_url = "http://api.flattr.com/button/view/";

$data = "button=compact&uid=" . $_GET['uid'] .
        "&url=" . $_GET['link'] . "&lng=en_US&hide=0&title=" .
        $_GET['title'] . "&cat=text&tag=&desc=";

$html = file_get_html($btn_url . bin2hex($data));

$els = $html->find("span.flattr-count");
$count = $els[0]->innertext;

$els = $html->find("a.flattr-pop");
$link = $els[0]->href;

$els = $html->find("span.flattr-link");
$txt = $els[0]->innertext;

?>
<FeedFlare>
  <Text><? print "$txt ($count)"; ?></Text>
  <Link href="<? print $link; ?>"/>
</FeedFlare>

Those familiar with Flattr will note that I did not pass in the description, which could probably be added in the first script (or at least a shortened version of it) and then passed to the button. Usually the description is the first few hundred characters of the post in this case.

Hope all works well. Please post back if you take the time to add the description to this!

Friday, June 4, 2010

PHP: Sending Motion-JPEG

As you may know from past posts, I was trying to send Motion-JPEG from a PHP script. This proved (for many reason) not so easy. After I conquered writing php extension modules, I was still left with nuances in PHP that made it difficult to send MJPEG from my script.

Here's the basic run-down of difficulties:
  • PHP buffers output to the client and this keeps you from doing continuous streams of data easily
  • PHP doesn't allow you to send headers after it thinks the headers have already been sent
  • Apache has some other handlers that also cause buffering
  • Apache does some client negotiation that conflicts with MJPEG (mod_gzip)

Searching the Eentarnets did not produce good results on how to handle this. At least, not in a single place and easily findable. So here's my solution for others to use:

<?
# Used to separate multipart
$boundary = "my_mjpeg";

# We start with the standard headers. PHP allows us this much
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");

# From here out, we no longer expect to be able to use the header() function
print "--$boundary\n";

# Set this so PHP doesn't timeout during a long stream
set_time_limit(0);

# Disable Apache and PHP's compression of output to the client
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);

# Set implicit flush, and flush all current buffers
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
    ob_end_flush();
ob_implicit_flush(1);

# The loop, producing one jpeg frame per iteration
while (true) {
    # Per-image header, note the two new-lines
    print "Content-type: image/jpeg\n\n";

    # Your function to get one jpeg image
    print get_one_jpeg();

    # The separator
    print "--$boundary\n";
}
?>

That's it in a nutshell. Make sure that your PHP script does not contain any newlines or data before or after the PHP enclosures (<? ... ?>).