Plug and Graph

April 23, 2007

We know Alexa ranks are not completely accurate (wink), but sometimes it’s helpful to know what Alexa sees. So, we developed a little Alexa reporting code for our own needs, since Amazon Web Services only include sample code for 3-month ranks (and not 1-day ranks). We offer this code with a BSD-style license  in case it can be helpful to you as well.

The code provides a few easy PHP5 functions to build the query for Amazon Web Information Services (AWIS), perform the query, and parse the results for 3-month and 1-day ranks. We also offer a friendly stub to get it all working; it’s nothing fancy like “site traffic on roids“, but it’s plug and play.

If PHP is not your flavor, here’s a place where you can find some other good samples from Alexa Web Information Service.

<?php 
// ---- BSD LICENSE ------ //       

#Copyright (c) 2007, Renkoo, Inc. 
#All rights reserved.       

#Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 
#    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
#    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
#    * Neither the name of the Renkoo, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.       

// ---- BSD LICENSE ------ //       

/* 
*  Friendly functions for AWIS. Some code taken from the original code provided by amazon at: 
*  http://developer.amazonwebservices.com/connect/entry.jspa?entryID=402 
*  Author: F.A. Lee     Contact: alee@renkoo.com        Date: 01/25/07 
*/       

define("ACCESS_KEY_ID", "-- INSERT YOUR ACCESS KEY ID -- "); 
define("SECRET_ACCESS_KEY", "-- INSERT YOUR SECRET ACCESS KEY --"); 
define("SERVICE_ENDPOINT", "http://awis.amazonaws.com?"); 
define("ACTION", "UrlInfo"); 
define("RESPONSE_GROUP", "Rank"); 
define("RESPONSE_GROUP_ALL", "TrafficData");       

// SOME functions below provided by http://developer.amazonwebservices.com/connect/entry.jspa?externalID=402&categoryID=34       

// Returns the _3-month_ rank when given a url 
// AWIS process: 1. make a awis formatted url called $awis_url 
// 2. make an http request with the awis_url, and curl :P~ 
// 3. parse the XML response by giving it to a DOM and accessing the nodes of the DOM 
//    if the node called "Rank" has NULL then there is an error, otherwise return that value 
function awis_rank($site_url) {       

    $awis_url = generate_url($site_url, 3); 
    $result = make_http_request($awis_url); 
    $response_doc = new DOMDocument(); 
    $response_doc->loadXML($result);       

    //$AE = awisError($response_doc); echo("----- i'm in the function awis_rank and the awisError msg is $AEn");       

    if (!awisError($response_doc)) { 
        $rank_nodes = $response_doc->getElementsByTagName("Rank"); 
        $rank = (!is_null($rank_nodes)) ? $rank_nodes->item(0)->firstChild->nodeValue : "Error"; 
        return $rank; 
    } else { 
        return awisError($response_doc); 
    } 
}       

// Returns TODAY'S rank when given a url 
// AWIS process is same as the 3-month, but after loading 
// looks for the elements of Day versus Rank, and then parses 
// around the DOMDoc to get the <Value> for <Rank> in <Day> 
function awis_rank_today($site_url) {       

    $awis_url = generate_url($site_url, 1); 
    $result = make_http_request($awis_url); 
    $response_doc = new DOMDocument(); 
    $response_doc->loadXML($result); 
    // if AWIS response is not an error msg 
    if (!awisError($response_doc)) { 
        $days = $response_doc->getElementsByTagName("Days");         

        foreach($days as $day) {       

          if ($day->nodeValue == 1) { 
              $dv = $day->nodeValue; // day value OK 
              $timerange = $day->parentNode; // go up to TimeRange parent 
              $usagestat = $timerange->parentNode; // gives the values of everything under usagestatistic 
              $children = $usagestat->childNodes; //timerange, rank, reach, etc.       

              foreach($children as $child) { //look through all the children of usagestat 
                  $x = $child->nodeName;       

                  if (strstr($x, 'Rank')) { // aws:Rank 
                      $value = $child->nodeValue; 
                      $split_result = preg_split("/s+/", $value);       

                      foreach ($split_result as $sp) {       

                          if ($sp != NULL) { 
                              $make_number = $sp; 
                              $make_number = preg_split("/W+/",$sp); 
                              $rank = implode($make_number); 
                              break; 
                          }       

                      } 
                  } 
              } 
          } 
        } 
    } else { 
      // return the error message 
      return awisError($response_doc); 
    } 
    return $rank;       

}       

// takes in a response from AWIS in xml format 
// looks for a node named "Error" and then returns 0 if there is 
// no error or the error msg if there is an error 
function awisError($xml_response_doc) {       

    $error_nodes = $xml_response_doc->getElementsByTagName("Error"); 
    $error_tag = $error_nodes->item(0)->nodeName; 
    $errorCode_tag = $error_nodes->item(0)->firstChild->nodeName; 
    if (($error_tag == "Error") and ($errorCode_tag == "Code")) { 
        return $error_nodes->item(0)->firstChild->nodeValue; 
    } else { 
        return 0; 
    } 
}       

// Returns the AWS url to get AWIS information for the given site 
function generate_url($site_url, $responseGroup) {       

    $timestamp =  generate_timestamp(); 
    $site_enc = urlencode($site_url); 
    $timestamp_enc = urlencode($timestamp); 
    $signature_enc = urlencode(calculate_RFC2104HMAC(ACTION . $timestamp, SECRET_ACCESS_KEY));       

    // response group constants for 1 day vs 3-month ranks 
    if ($responseGroup == 3) { 
        $rg = RESPONSE_GROUP; 
    } elseif ($responseGroup == 1) { 
        $rg = RESPONSE_GROUP_ALL; 
    }       

    return SERVICE_ENDPOINT 
        . "AWSAccessKeyId=".ACCESS_KEY_ID 
        . "&Action=".ACTION 
        . "&ResponseGroup=".$rg 
        . "&Timestamp=$timestamp_enc" 
        . "&Signature=$signature_enc" 
        . "&Url=$site_enc";       

}       

// Calculate signature using HMAC: http://www.faqs.org/rfcs/rfc2104.html 
function calculate_RFC2104HMAC ($data, $key) { 
    return base64_encode ( 
                          pack("H*", sha1((str_pad($key, 64, chr(0x00)) 
                                           ^(str_repeat(chr(0x5c), 64))) . 
                                          pack("H*", sha1((str_pad($key, 64, chr(0x00)) 
                                                           ^(str_repeat(chr(0x36), 64))) . $data)))) 
                          ); 
}       

// Timestamp format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'                                                                                                                                                         

function generate_timestamp () { 
    return gmdate("Y-m-dTH:i:s.Z", time()); 
}       

function make_http_request($url){ 
    $ch = curl_init($url); 
    curl_setopt($ch, CURLOPT_TIMEOUT, 4); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    $result = curl_exec($ch); 
    curl_close($ch); 
    return $result; 
}       

?>

<?php 
// ---- BSD LICENSE ---- //       

#Copyright (c) 2007, Renkoo, Inc. 
#All rights reserved.       

#Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:       

#    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
#    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
#    * Neither the name of the Renkoo, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.       

#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.       

// ---- BSD LICENSE ---- //       

/* 
*  Stub to utilize bsd_awis_cfg.inc configuration file 
*  AUTHOR: F.A. Lee        CONTACT: alee@renkoo.com        DATE: 01/25/07 
*/       

require_once("bsd_awis_cfg.inc");       

$site_url = "Amazon.com"; 
$rank = awis_rank_today("$site_url"); 
$rank_three_month = awis_rank("$site_url"); 
echo("For site: " . $site_url." the rank today is: ". $rank . ", and 3-month is: " . $rank_three_month);       

?>

One Response to “Plug and Graph”

  1. Yan Says:

    I recommend Quantcast (http://quantcast.com). They have some really cool demographic info and information about what other sites your visitors like. They ask you to put a bit of javascript on your page to get accurate ranks but it seems like a good way to collect all sorts of useful info!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: