Grey Hat Programming on Big Commerce
Short URL for this post: http://plp.me/nYKFQx
One of my clients has a website constituting of two platforms: WordPress and Big Commerce. I was mandated to, among other things, create a symbiosis between the two platforms so that users didn't have to register twice. The only problem with that is being a commercial platform, Big Commerce doesn't want you messing around in their proprietary database - their API really is only for read stuff, you never write anywhere. Understandable... but my client still wants user synchronicity, and to be honest I don't think he's exaggerating.
So... how do we remotely create users on a platform that doesn't let you create users with their API? After a bit of looking around for solution, I stumbled upon my client's store registration form (which is hosted, like everything related to Big Commerce, on a server you don't control). Different domains, different servers, no API methods... but I have a form. Have you ever heard of XSS? In the world of developers, it's a real annoyance. Essentially, if you fail to secure your forms properly, anyone can grab your form, put it somewhere else on the internet and submit bogus data (because the form still sends to you, get it?). Anyway, it's usually really only a security concern, but for this particular project, it became a feature.
Big Commerce does not validate their registration form, so you can submit it from anywhere... like right after a WordPress (or in my case, BuddyPress) user is created for example! A simple cURL request with the proper data set and we've got ourselves a relatively easy bridge. Now, there are cons to this method... for example, if Big Commerce ever realizes that their lack of respect for good practices is used as a feature, I'm not sure they'll keep it up for long. Notice how this post doesn't have a single link...? Yeah.
If this reaches their ears, can we please make a compromise? You pull the non-feature in exchange for a user creation method in your API. Deal?
On to other things..
That wasn't the only thing I was tasked with doing. My client also wanted the ability to use the header from his WordPress theme on his Big Commerce site. Again, Big Commerce doesn't let you put any code on their servers (except static files like HTML and CSS) even though that's where your store resides. Not hating, it's a business model... it's just not a very convenient one. So I have a WordPress header (including a carousel and a drop-down menu of WordPress-centric items) and a lousy API. I initially tried to use BC's %%Include%% "feature", but as you can guess, it fails for remote resources.
Long story short, I created a new file at the root of my client's WordPress site and tossed this in:
define('WP_USE_THEMES', false);
require('./wp-blog-header.php');
get_header('store');
With that, I can essentially be inside WordPress while remaining outside of its scope. Notice the get_header() parameter that allows you to use specific files (such as, in my case, header-store.php). Alright, so I have a decent looking header (that's a few lines of random HTML, JavaScript and CSS) but I still can't fetch it from the store. So I had to get creative. After a fair amount of digging around, I found that I could upload files to Big Commerce - but only static (HTML, CSS, JS, etc) and only in a very specific location (that's /content by the way). With that, I can build something:
#!/usr/bin/php
$ch = curl_init('http://secret.url/headerForBC.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
$header = curl_exec($ch);
$file = tempnam('/tmp', 'bc2wp');
file_put_contents($file, $header);
$context = stream_context_create(array('ftp' => array('overwrite' => true)));
// Big Commerce requires a secure connection
$ftp = ftp_ssl_connect('server2600.bigcommerce.com');
$login_result = ftp_login($ftp, 'duh', 'ohai');
echo ftp_put($ftp, '/content/wpheader.html', $file, FTP_ASCII)? 'success' : 'fail';
ftp_close($ftp);
Then toss it in a cron that'll run it every 24 hours and use %%Include.http://my.store-url.com/content/wpheader.html%% to render it. That wasn't so bad, was it?
