Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch the HTTP POST request sent by a Shopify Webhook

I'm somewhat of a noob, and not afraid to admit that, I'm working on this project as a learning experience to get better with php and serverside script/ing handling.

I'm trying to come up with a way to use Shopify and simultaneously update an off server database every time an order is fulfilled from my Shopify cart. So for example, someone buys something from my online store, I want it to update my home databases inventory to show that it now has one less item.

I've come to the conclusion that the best way to do this would be to setup a webhook notification that sends an HTTP POST request to my server, then I'd have my server catch the POST and parse it into an XML. I will then read the XML via a php script that will update my database.

I dont have a problem with the php, but what I can't seem to figure out is how to catch the webhook on my server. Webhook asks me for a URL to send the POST request to, my question to you is; what is the url?

I've done some research and found that you can catch the POST request a number of ways, through html, php, Access-Control-Allow-Origin, etc. However, since I'm still new to this, I don't really understand exactly how to do these. I've tried with an HTML hidden action form but couldn't seem to get it to catch the XML.

All I want to do is have the webhook send its POST request, and have it caught as a .xml. So that I can read the xml at the end of each day, and update the database accordingly.

If you can think of a better or simpler way to do this, by all means please give me your suggestions. I'd like this to be secure, so methods like Access-Control-Allow-Origin are out of the question.

tl;dr: What do I have to do on my server to catch a webhook notification? What script should I have on my server to give to the webhook? How do I write the callback script?

like image 924
Gabe Steinberg Avatar asked Jun 07 '12 17:06

Gabe Steinberg


2 Answers

Create a public URL at http://example.com/whatever.php, where example.com is your domain name and whatever.php is a PHP file that you can edit.

Then put this code into whatever.php:

<?php
$webhookContent = "";

$webhook = fopen('php://input' , 'rb');
while (!feof($webhook)) {
    $webhookContent .= fread($webhook, 4096);
}
fclose($webhook);

error_log($webhookContent);
?>

Then in the Shopify admin you can create a new webhook and point it at http://example.com/whatever.php, and when you click the 'test webhook' button in the Shopify admin, Shopify will POST to your script above, which should in turn write the body of the webhook to your PHP error log.

like image 135
Ben Dunlap Avatar answered Oct 10 '22 03:10

Ben Dunlap


Sorry, I don't have enough reputation to post comments, but here is the contents of the dead link from Edward Ocampo-Gooding's answer:

PHP Example w/ SimpleXML (PHP 5+)

The script below shows you how to get the XML data in from Shopify into your script, archive the file, and send the proper headers ...

Given that the new order subscription setup in the admin for the webhook is: http://example.com/some-script.php?key=123456789

Contents of some-script.php on http://example.com/:

<?     
// Protect URL from rogue attacks/exploits/spiders
// Grab from GET variable as given in Shopify admin URL
// for the webhook
//
// NOTE: This is not necessary, just a simple verification
//
// A digital signature is also passed along from Shopify,
// as is the shop's domain name, so you can use one or both of those
// to ensure a random person isn't jacking with your script (or some
// spider just randomly hitting it to see what's there).
//
// If $key doesn't matched what should be passed in from the
// webhook url, the script simply exits
$key = $_GET['key']; 

if ($key != '123456789') {
  header('HTTP/1.0 403 Forbidden');
  exit();
}

// Variables used for processing/saving
$xmlString = ;  // Used to get data from Shopify into script
$name = ;  // Saves the billing address name to be used for later ...
$email = ;  // Save the email address of the user to be used for later ...
$productTitles = array();  // Saves all titles of products purchased to be used for later ... 

// Get XML data and read it into a string for use with SimpleXML
// Thanks to David Oxley (http://www.numeriq.co.uk) for help with this
$xmlData = fopen('php://input' , 'rb'); 
while (!feof($xmlData)) { $xmlString .= fread($xmlData, 4096); }
fclose($xmlData);

// Save order XML in file in orders directory
// This creates a file, write the xml for archival purposes, and closes the file ...
// If the file already exists, it appends the data ... this should create a separate
// file for every order but if two orders are processed the same second, they'll both
// be in the same file
file_put_contents('orders/order' . date('m-d-y') . '-' . time() . '.xml', $xmlString, FILE_APPEND);

// Use SimpleXML to get name, email, and product titles
// SimpleXML allows you to use the $xml object to easily
// retrieve the data ...
// Please note, if hyphens are used in the xml node, you must
// surround the call to that member with {'member-name'} as is
// shown below when getting the billing-address name & the
// line items
$xml = new SimpleXMLElement($xmlString);

$name = trim($xml->{'billing-address'}->name);
$email = trim($xml->email);

// Create productTitles array with titles from products
foreach ($xml->{'line-items'}->{'line-item'} as $lineItem) {
  array_push($productTitles, trim($lineItem->title));
}

// You would then go on using $name, $email, $productTitles in your script
// to do whatever the heck you please ...

// Once you are done doing what you need to do, let Shopify know you have 
// the data and all is well!
header('HTTP/1.0 200 OK');
exit();

// If you want to tell Shopify to try sending the data again, i.e. something
// failed with your processing and you want to try again later
header('HTTP/1.0 400 Bad request');
exit();
?>
like image 21
Gifford N. Avatar answered Oct 10 '22 03:10

Gifford N.