Home     Articles & Projects     Products & Web Services

dmorison's blog

WordPress Price Comparison Plugin launched

A WordPress price comparison plugin for use in conjunction with my Price Tapestry price comparison script is now available, under soft launch / BETA at the moment and seems to be going down well more info at PriceTapestry.org... (Joomla version coming soon!)

Amazon API Request Authentication

I have Amazon authentication working with the following code - a couple of people are testing it out and once I know it's OK i'll update the Amazon page on Price Tapestry. This method requires PHP4+mhash, PHP5+mhash or PHP5 >= 5.1.2.

The commented steps relate to the Amazon AWS documentation on this page.

<?php
 
function amazonEncode($text)
  {
   
$encodedText = "";
   
$j = strlen($text);
    for(
$i=0;$i<$j;$i++)
    {
     
$c = substr($text,$i,1);
      if (!
preg_match("/[A-Za-z0-9\-_.~]/",$c))
      {
       
$encodedText .= sprintf("%%%02X",ord($c));
      }
      else
      {
       
$encodedText .= $c;
      }
    }
    return
$encodedText;
  }

  function
amazonSign($url,$secretAccessKey)
  {
   
// 0. Append Timestamp parameter
   
$url .= "&Timestamp=".gmdate("Y-m-d\TH:i:s\Z");

   
// 1a. Sort the UTF-8 query string components by parameter name
   
$urlParts = parse_url($url);
   
parse_str($urlParts["query"],$queryVars);
   
ksort($queryVars);

   
// 1b. URL encode the parameter name and values
   
$encodedVars = array();
    foreach(
$queryVars as $key => $value)
    {
     
$encodedVars[amazonEncode($key)] = amazonEncode($value);
    }

   
// 1c. 1d. Reconstruct encoded query
   
$encodedQueryVars = array();
    foreach(
$encodedVars as $key => $value)
    {
     
$encodedQueryVars[] = $key."=".$value;
    }
   
$encodedQuery = implode("&",$encodedQueryVars);

   
// 2. Create the string to sign
   
$stringToSign  = "GET";
   
$stringToSign .= "\n".strtolower($urlParts["host"]);
   
$stringToSign .= "\n".$urlParts["path"];
   
$stringToSign .= "\n".$encodedQuery;

   
// 3. Calculate an RFC 2104-compliant HMAC with the string you just created,
    //    your Secret Access Key as the key, and SHA256 as the hash algorithm.
   
if (function_exists("hash_hmac"))
    {
     
$hmac = hash_hmac("sha256",$stringToSign,$secretAccessKey,TRUE);
    }
    elseif(
function_exists("mhash"))
    {
     
$hmac = mhash(MHASH_SHA256,$stringToSign,$secretAccessKey);
    }
    else
    {
      die(
"No hash function available!");
    }

   
// 4. Convert the resulting value to base64
   
$hmacBase64 = base64_encode($hmac);

   
// 5. Use the resulting value as the value of the Signature request parameter
    // (URL encoded as per step 1b)
   
$url .= "&Signature=".amazonEncode($hmacBase64);

    return
$url;
  }
?>

To use, construct $url without the Timestamp parameter, and then sign using:

$url = amazonSign($url,"YOUR_SECRET_ACCESS_KEY");

Note: If you have been using the REST API for some time, you may be using the old SubscriptionId parameter. Authenticated URLs require the newer AWSAccessKeyId parameter, which together with your secret access key can be found on this page.

PHP Star Sign function

Something I just put together for a Magic Parser customer which might come in handy for someone, somewhere! A PHP function to return the current star sign of the Zodiac (or the star sign of any given date as a PHP time() value), taking leap years into account.

<?php
 
function getStarSign($date="")
  {
   
$zodiac[356] = "Capricorn";
   
$zodiac[326] = "Sagittarius";
   
$zodiac[296] = "Scorpio";
   
$zodiac[266] = "Libra";
   
$zodiac[235] = "Virgo";
   
$zodiac[203] = "Leo";
   
$zodiac[172] = "Cancer";
   
$zodiac[140] = "Gemini";
   
$zodiac[111] = "Taurus";
   
$zodiac[78]  = "Aries";
   
$zodiac[51]  = "Pisces";
   
$zodiac[20]  = "Aquarius";
   
$zodiac[0]   = "Capricorn";
    if (!
$date) $date = time();
   
$dayOfTheYear = date("z",$date);
   
$isLeapYear = date("L",$date);
    if (
$isLeapYear && ($dayOfTheYear > 59)) $dayOfTheYear = $dayOfTheYear - 1;
    foreach(
$zodiac as $day => $sign) if ($dayOfTheYear > $day) break;
    return
$sign;
  }
?>

To get the current star sign (today's date), simply use

$sign = getStarSign();

...or for the star sign of any given date, provide a standard time() value, e.g.

$sign = getStarSign(strtotime("2007-03-25"));

Generic PHP Google Sitemap script based on any MySQL database table containing page URLs

The following PHP code will enable you to generate a Google Sitemaps compatible XML URL list from any MySQL database table containing each page URL - or at least enough information for you to construct the page URL from the fields of each row, for example by appending an ID field to a common prefix. Simply edit the first 4 lines with your database and table details as required, and then modify the following line:

    $loc = $row["url"];

...to construct the URL of the page you wish to include in the sitemap. $row will be an associative array of each of the fields in the database table. As an alternative to the above, you may have the situation where each page on your site can be generated from an id field, for example:

    $loc = "http://www.example.com/page.php?id=".$row["id"];

You can submit sitemap.php directly to Google (it doesn't matter that the filename does not end in .xml), as the correct content-type header will be sent when the page is requested.

sitemap.php

<?php
  $databaseServer
= "localhost";
 
$databaseUsername = "username";
 
$databasePassword = "password";
 
$databaseName = "database";
 
$databaseTable = "tablename";
 
header("Content-Type: text/xml");
  function
xmlentities($text)
  {
   
$search = array('&','<','>','"','\'');
   
$replace = array('&amp;','&lt;','&gt;','&quot;','&apos;');
    return
str_replace($search,$replace,$text);  
  }
  print
chr(60)."?xml version='1.0' encoding='UTF-8'?".chr(62);
  print
chr(60)."urlset xmlns='http://www.google.com/schemas/sitemap/0.84' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://www.google.com/schemas/sitemap/0.84 http://www.google.com/schemas/sitemap/0.84/sitemap.xsd'".chr(62);
 
$sql = "SELECT * FROM `".$databaseTable."`";
 
$link = @mysql_connect($databaseServer,$databaseUsername,$databasePassword);
  @
mysql_select_db($databaseName,$link);
 
$result = mysql_unbuffered_query($sql,$link);
  while(
$row = mysql_fetch_array($result,MYSQL_ASSOC))
  {
   
// create the loc (URL) value based on the $row array, for example:
   
$loc = $row["url"];
    print
"<url>";
    print
"<loc>".xmlentities($loc)."</loc>";
    print
"</url>";
  }
  print
"</urlset>";
?>

How to find out what user PHP is running as

When configuring security and managing other aspects on your server it is often necessary to find out what user PHP is running as. In most installations, PHP is running as an Apache module, so it will be running as whatever user Apache is running as. Common examples are "apache" or "deamon". You can find out for sure by running the following script, which will display the output of the Linux "whoami" command:

<?php
  passthru
("whoami");
?>

Beware of free domain name offers

It has become quite common for a new TLD (top level domain) to offer, in conjunction with registrars, a free first 12 months registration, and also for hosting companies to offer a free domain name if you signup for their services.

Think very carefully before taking up an offer such as this unless you are sure you know what the subsequent annual renewal cost for that domain name will be and would be comfortable paying it. I would rather build a site on a £2.95 per annum .co.uk domain name than take up a free .foo domain name and then have to pay £40 per annum thereafter!

Brief introduction to Affiliate Marketing

Affiliate marketing is pretty much as old as commerce itself - so pre-dates the Internet by thousands of years! It is basically the promotion of a 3rd party's product or service in return for a commission payment for sales generated via that promotion.

Anybody with a website (and visitors to that website!) can earn money through affiliate marketing simply by placing special links on their website that contain information that identifies them / their website as the source, and then if one of the visitors they have referred subsequently makes a purchase; a commission is paid on their account - simple as that!

To see affiliate marketing in action; simply take a look at the banner for easyDNS just over to the right. If you hover your mouse over the banner and take a look at the destination URL in the status bar of your web browser you will notice that it contains a code. That code is unique to me and identifies me to easyDNS as the source of any visitors that reach their website by clicking on that banner. If you were to click that banner, and then decide that you like the service and want to sign up; I would be rewarded with a commission - which in the case of easyDNS is "paid" not in money, but in return for their services.

Most online merchants that offer an affiliate program make use of cookies in order to "remember" who has referred their visitors so that commission can still be paid even if a sale is not made immediately.

Finally, it is not even necessary to create affiliate accounts with every merchant who's product or service you wish to promote because of what's called an "Affiliate Network". Affiliate networks act as a middle-man between web publishers and merchants who wish to offer an affiliate program. This has lots of benefits for everyone involved, but primarily as a publisher; you don't need to maintain relationships with hundreds of merchants - you just have one relationship with the affiliate network. The same applies to the merchant; who likewise only has to maintain a relationship with the network instead of hundreds of affiliates directly.

Unversal redirection script

This is a simple way to store links in a database, and then redirect your visitors to those links via a jump script and a "link ID" instead of rendering the actual link into your page. This could be used, for example, where you have obtained product URLs from an Affiliate API, and instead of displaying the actual affiliate URLs in your page you want to use a local URL that will redirect to the actual affiliate URL.

This project requires a single table called "links", containing the following fields:

id (INT, Auto-Increment, Primary Key)
hash (VARCHAR(32), Unique)
url (TEXT)

You can either create this table manually using a tool such as phpMyAdmin, or use the following script to create the table for you. This script only needs to be run once:

create.php

<?php
 
// don't forget to set your own database connection settings!!
 
$connection = mysql_connect("localhost","username","password");
  if (!
$connection) {print mysql_error();exit();}
 
mysql_select_db("database", $connection);
 
$sql = "
CREATE TABLE `links` (
  `id` int(11) NOT NULL auto_increment,
  `hash` varchar(32) NOT NULL,
  `url` text NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `uid` (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  "
;
 
$result = mysql_query($sql,$connection);
  if (!
$result) print mysql_error($connection);
  print
"Done.";
?>

We are going to implement this as a PHP library file, which will be included by the redirection script (jump.php) and your main script. Here's the code:

jumplib.php

<?php
 
// As this is a library file for you to include in any project, notice how I
  // have prefixed every variable and function name with the library name.....
  // **************************************************************************
  // don't forget to set your own database username password and database name
 
$jumplib_connection = mysql_connect("localhost","username","password");
  if (!
$jumplib_connection) { print mysql_error();exit(); }
 
mysql_select_db("database", $jumplib_connection);
 
// **************************************************************************
  // FUNCTION: jumplib_getID($url)
  // Get a jump ID for $url.  First check to see if the URL already exists in the
  // database, and if so return the ID.  Otherwise, insert and return the new ID
  // We index and search by a hash value as this is far more efficient than
  // having an index on the actual URL field!
  // **************************************************************************
 
function jumplib_getID($url)
  {
    global
$jumplib_connection;
   
$hash = md5($url);
   
$sql = "SELECT id FROM links WHERE hash='".$hash."'";
   
$result = mysql_query($sql,$jumplib_connection);
    if (
mysql_numrows($result))
    {
     
$link = mysql_fetch_assoc($result);
      return
$link["id"];
    }
    else
    {
     
$sql = "INSERT INTO links SET hash='".$hash."',url='".mysql_escape_string($url)."'";
     
mysql_query($sql,$jumplib_connection);
      return
mysql_insert_id($jumplib_connection);
    }
  }
 
// **************************************************************************
  // FUNCTION: jumplib_getURL($id)
  // Get the URL for an ID
  // **************************************************************************
 
function jumplib_getURL($id)
  {
    global
$jumplib_connection;
   
$sql = "SELECT url FROM links WHERE id='".mysql_escape_string($id)."'";
   
$result = mysql_query($sql,$jumplib_connection);
   
$link = mysql_fetch_assoc($result);
    return
$link["url"];
  }
?>

Finally, the jump script itself:

jump.php

<?php
 
require("jumplib.php");
 
$url = jumplib_getURL($_GET["id"]);
 
// redirect using HTTP status code 302 (Moved)
 
header("Location: ".$url);
  exit();
?>

To use this in your own application, simply require("jumplib.php") at the top, and then call jumplib_getID($url) wherever you want to get an ID for a URL, and then render the link as:

"jump.php?id=".jumplib_getID("http://www.example.com/")

Here's an example script to test the library and show it in action:

test.php

<?php
 
require("jumplib.php");
 
  print
"<p><a href='jump.php?id=".jumplib_getID("http://www.example.com/")."'>example.com</a></p>";

  print
"<p><a href='jump.php?id=".jumplib_getID("http://www.example.org/")."'>example.org</a></p>";
?>

Click here to see this running on this server...

If you run the script, and hover your mouse over the links, you should see jump.php in the address bar instead of the actual URL...

Syndicate content