Cross-Domain POST With JavaScript

November 20th, 2008

Normally you can’t send cross-domain requests in JavaScript due to restrictions imposed by the same-origin security policy. There are many clever hacks that circumvent this by using remote script includes (even CSS includes) or proxy scripts, but so far I haven’t seen anything useful for client-side, cross-domain POST requests.

However, it turns out you can send them very easily if you don’t need to know the response to the request. This might sound useless at first, but there are certain situations where it’s all you really need. For example, blackhat SEO comes to mind…

The Basic Idea

Forms can use the POST method and JS can submit forms. This means you can dynamically generate a form with the action attribute set to any URL (including pages on other domains) and encode all query parameters as hidden <input> fields, then automatically submit the form.

The problem is this works exactly as if the user had filled out a form and clicked “Submit” - the browser will send the request and open a different page. That’s (usually) bad, so we need to put the form inside an invisible iframe to hide the redirect. Of course, you can’t get any response data from the frame, so it’s truly “fire and forget”.

As a result, the final script will have two components - a JavaScript function that creates the iframe, and another script that will run inside the frame and generate and submit the form.

Implementing It

The first part is the crossDomainPost() JS function. This is the function you will call from your script to initiate a POST request. The function accepts three arguments :

  • writer_url - the URL of the script that will generate the form (see below).
  • post_target_url - send the POST request to this URL.
  • params - query parameters for the POST request, formatted like this : {param1 : 'value1', param2 : 'value2', ...}

And here’s the source code :

<script type='text/javascript' language='JavaScript'>
function crossDomainPost(writer_url, post_target_url, params){
    var url_params = '';
    for (var key in params){
        url_params =url_params + '&' + key + '='+encodeURIComponent(params[key]);
    }
    var url = writer_url + '?post_target_url=' + encodeURIComponent(post_target_url) + url_params;
    var iframe = document.createElement('iframe');
    iframe.setAttribute('src', url);
    iframe.setAttribute('width', 1);
    iframe.setAttribute('height', 1);
    iframe.setAttribute('style', 'border: none;');
    var p = document.getElementsByTagName('html');
    p[0].appendChild(iframe);
}
</script>

The second component is the script that will generate and submit the form. There are several ways to create a form, but in this case I decided to stick with a mix of HTML & PHP. You can do it purely in JS, but the script would be a bit more complex. Either way, the form is still submitted by JavaScript, so the POST request will be done by the browser, not your server.

This script needs to be placed in a separate file (say, “form_writer.php”) because it will be loaded in a frame. Here’s the source :

<form method='post' action='<?php echo $_GET['post_target_url']; ?>' id='postform'>
<?php 
    unset($_GET['post_target_url']);
    foreach($_GET as $key => $value) {
        echo "<input type='hidden' name='$key' value='".htmlentities($value, ENT_QUOTES)."'>";
    }
?>
</form>
<script language='JavaScript'>
    document.getElementById('postform').submit();
</script>

Using The Script

Lets see a real life example, shall we? Here’s how you can use the above scripts to send a trackback in JavaScript :

crossDomainPost(
    'http://mydomain.com/form_writer.php',
    'http://random-site.com/blog/offtopic/an-example-post/trackback/',
    {
        title : 'My Cool Post',
        excerpt : '...like, totally and such...',
        url : 'http://mydomain.com/stuff/my-cool-post/',
        blog_name : 'My Cool Blog'
    }
);

Eeevil  ;-)


Equally Unaware Of Stupidity

November 18th, 2008

via just.K

via just.K

Ever heard of the Dunning-Kruger effect? Even if the name doesn’t ring any bells you’re probably familiar with the basic idea : stupid people tend to overestimate their competence and underestimate the competence of others. The effect was famously demonstrated in a series of experiments performed by two researchers (Justin Kruger and David Dunning) in December 1999. If you’re curious the research paper is available online [pdf].

This notion has become so popular that many probably consider it “common sense”. However, recent research shows that the original conclusions made by Dunning and Kruger were likely wrong :

We replicated, eliminated, or reversed the association between task performance and judgment accuracy reported by Kruger and Dunning (1999) depending on task difficulty. On easy tasks, where there is a positive bias, the best performers are also the most accurate in estimating their standing, but on difficult tasks, where there is a negative bias, the worst performers are the most accurate. This pattern is consistent with a combination of noisy estimates and overall bias, with no need to invoke differences in metacognitive abilities.

(Skilled or Unskilled, but Still Unaware of It [pdf], 2006)

To put it simply, everybody, regardless of their skill or lack thereof, tend to make incorrect estimates about their own ability. A different study [pdf] (2008) has indicated that there may be a weak correlation between skill and estimate quality, but the significance is marginal at best.

Disclosure : This post was heavily influenced by “All Are Skill Unaware” by Robin Hanson.


Displaying Recent Posts On a Non-WordPress Page

November 15th, 2008

Listing recent posts on a WordPress page is easy - there are various widgets and theme functions available just for that purpose. But what about a non-WP page, or even a different site? That’s not that hard either - simply grab some posts from the blog’s RSS feed and output them on your page. In this post I’ll explain how you can do that either with JavaScript or PHP.

JavaScript - The Easy Way

If you just want a simple box containing the most recent entries, you’re in luck - there won’t even be any programming involved. You can use one of the many free JavaScript scripts that can display RSS feeds in a variety of formats. Personally, I recommend Feed2JS. It’s straightforward and minimalistic, yet still fairly configurable. And if that doesn’t suite you, there are many alternatives available - just google “rss to javascript”.

JavaScript RSS widgets have the advantage of simplicity and minimal server performance impact (the feed is loaded client-side). However, if you want to do something more advanced, like filtering posts by author, a ready-made script might not be enough. Also, the output generated by JavaScript isn’t part of the page HTML - something to consider if you’re concerned about SEO.

PHP - The Slightly Advanced

You can also use a PHP script to fetch, parse and display recent posts. There are lots of ways to do this, but I’ll focus on one of the easiest approaches. We will use the SimplePie RSS parser to handle all the boring parts - loading the feed, parsing it, caching, etc.

Lets get started. First, Download SimplePie. You’ll get a .zip archive with a number of files, but for this you’ll only need one of them - simplepie.inc. Put this file somewhere your PHP script(s) can access it. For example, if you want to display your recent posts on http://example.com/stuff/page.php, you could put simplepie.inc in the stuff directory. Also, create a cache subdirectory in the same folder - SimplePie will automatically use it for caching the RSS feed.

Next, put this script somewhere on your page (change $feed_url to match your blog’s feed) :

<?php
$feed_url = 'http://w-shadow.com/feed/';
$max_items = 5;
 
//Load SimplePie
include 'includes/simplepie.inc';
 
//Fetch the RSS feed
$feed = new SimplePie($feed_url);
 
//Check for errors
if ($feed->error())
	echo 'Error : ',$feed->error();
 
//Output up to $max_items posts 
foreach ($feed->get_items(0, $max_items) as $item): ?>
 	<div class="item">
		<h3 class="title"><a href="<?php echo $item->get_permalink(); ?>"><?php echo $item->get_title(); ?></a></h3>
		<?php echo $item->get_description(); ?>
		<p><small>
		Posted  <?php if ($author = $item->get_author()){ echo ' by '.$author->get_name(); }?> 
		on <?php echo $item->get_date('j F Y | g:i a'); ?>
		</small></p>
	</div>
<?php 
endforeach; 
?>

The above script will load the specified RSS feed and display up to $max_items most recent posts. You can tweak the part between foreach and endforeach to format the output to your liking.

Additional Tips

To show recent posts from a single category use a category-specific feed URL instead of the blog’s main RSS feed. Usually you can get this URL by appending “/feed” to your category URL. For example, http://example.com/category/stuff/ => http://example.com/category/stuff/feed. More information is available in the WordPress Codex.

If you want to filter the feed to only show posts from a certain author or similar, you can check each item inside the foreach loop and skip those that you don’t want to show. For example, to only show posts from the author “James” :

if ($author = $feed->get_author()){
    if ( $author->get_name() != 'James') continue; //skip if not James
} else {
   continue; //no author specified, skip.

It’s also possible to aggregate multiple feeds with SimplePie - just replace the feed URL with an array of URLs and the parser will handle the rest. Example :

$feed_url = array(
    'http://domain.com/feed.rss', 
    'http://anothersite.org/blog/feed/',
    'http://www.example.com/rss'
 );

This way you can display recent posts from several blogs just as easily as from a single blog.

And that’s it. Good luck :) Feel free to drop a comment if you have any questions.


WordPress 2.7 (Beta) Mini-Review

November 14th, 2008

I’ve been trying to write a review ever since the first beta, but all I could come up can be summarized as “Meh. It’s okay.” WP 2.7 includes a lot of long-awaited features, which is great, but their implementation sometimes inflicts the aforementioned “meh” feeling.

For example, there’s the dashboard [...] Continue Reading…


Parse, Edit And Create Torrent Files With PHP

November 11th, 2008

A .torrent file contains assorted metadata that is stored in a “bencoded dictionary” format. Bencoding is a relatively simple cross-platform encoding used by BitTorrent and a dictionary is basically an associative array. You can find a high-level overview of the file structure here.

To open or edit a .torrent file [...] Continue Reading…