Category: PHP


Stupid osCommerce is still living in the dark ages, using things like register_globals and $HTTP_POST_VARS – come on guys – get with the program! Following my theme of being forced to fix every program I try to use, I have patched osCommerce 2.2 Milestone 2 Update 060817 to work with PHP 5. Luckily this is an easy fix. First download it from the link above and install the Register Globals Patch (look for VV 1.5 – ZIP Archive).

Now that we have that issue solved we just need to fix the $HTTP_*_VARS issue – these are old school PHP3 variables that were included in PHP4 for compatibility.

Copy this and put it in a file called php5fix.php in your catalog/includes directory:

<?php
// PHP5 Fix by Steve Kamerman, http://www.teratechnologies.net/stevekamerman

$phpversion = explode('.', phpversion());
if((int) $phpversion[0] >= 5){
// PHP 5 has no idea what this crap is
$HTTP_GET_VARS = &$_GET;
$HTTP_POST_VARS = &$_POST;
$HTTP_REQUEST_VARS = &$_REQUEST;
$HTTP_SESSION_VARS = &$_SESSION;
$HTTP_COOKIE_VARS = &$_COOKIE;
$HTTP_SERVER_VARS = &$_SERVER;
$HTTP_FILES_VARS = &$_FILES;
$HTTP_ENV_VARS = &$_ENV;
}
?>

Now edit catalog/admin/includes/application_top.php and add this just below the comments at the top:

// PHP5 fix
require_once("../includes/php5fix.php");

Edit catalog/includes/application_top.php and add this just below the comments at the top:

// PHP5 fix
require_once("includes/php5fix.php");

If you haven’t completed the installation yet, do this too:
Edit catalog/install/application.php and add this just below the comments at the top:

// PHP5 fix
require_once("../includes/php5fix.php");

Now you should be good to go! I’ll take a bow and pat myself on the back now – have a nice day 😀

P.S. I suppose I could fix up a fresh installation and provide you with a link to download it from if you want. Somebody please email me if you want it, otherwise I’m wasting my time.

After many many hours hunched over my keyboard, I have finished a major revamp of the Tera-WURFL code. Here's what's new:

Completely rewrote the error logging system and verified it's operation after a bug was discovered (thanks Neil!)
Added many features to the web administration console – seriously – check out the online demo!
Changed default DATADIR to the included 'data' directory
Completely rewrote the README file to include detailed installation instructions and other useful info
Optimized the clean installation process – now Tera-WURFL has a brain!
Included the current stable release of the wurfl.xml file so you don't need to download it
Included database statistics, log file monitoring and global configuration in new web interface
Changed default log level to LOG_WARNING instead of LOG_ERR
Described in great detail the purpose of the different database tables

If you are using Tera-WURFL 1.4.3 or earlier I would highly recommend that you upgrade to 1.4.4 due to some fairly significant bugs!

Tera-WURFL Website

Let me introduce my latest and greatest software: Tera-WURFL! What the heck is that?!?! Well, ‘Tera’ is just plain cool because it comes from Tera Technologies 🙂 and WURFL is the ‘Wireless Universal Resource FiLe. After a while of testing the WURFL PHP Tools by Andrea Trasatti, I began to notice some major downfalls in the package’s performance. Although the authors did all they could do to make it as fast as possible, the package still uses a file based caching method (albeit a fast one) so store device information. I found the lack of database support disturbing and decided to rewrite the class in my free time and release it myself [:)]. So here it is – Tera-WURFL. My version uses MySQL >= 4.1 and PHP >= 4.3 and performs up to 15x faster than the file based version! I am currently tied down trying to make non-free software and other things so I don’t have a whole lot of extra time to work on Tera-WURFL – sorry.

Basically, this software sits on your webserver and when a web browser requests your site, Tera-WURFL determines whether it’s a desktop web browser or a mobile WAP device, and if it is a mobile device it gives you a TON of information about it like the Make, Model, Screen Size, Ringtone Formats, Image Formats, etc… It’s really quite increadible!

Oh yeah – Tera-Tones.com also uses this detection method to deliver rich media content to handheld devices.

If you want to use Dreamweaver’s syntax highlighting features in PHP HEREDOC variables you can do it like this:

<?php
$something = 'test';
$output = <<<EOFEOF
<!-- ?> -->
<table><tr><td>{$something}</td></tr></table>
<!-- <?php -->
EOFEOF
;
?>

Since you’re in a HEREDOC, PHP will ignore the starting and ending symbols and include them literally
in the string, and the user’s browser will ignore them because they’re in HTML comments,
but Dreamweaver will think you’re breaking out of the PHP script and assume the string is HTML.
Yay! Syntax highlighting in HEREDOCs!

I’ve seen a lot of people trying to store IP Addresses in MySQL VARCHAR fields – this is very inefficient! There are two common ways to store ips that are database friendly: as a hexidecimal number and as a long integer. I recommend the long integer method since this functionality is already implemented in PHP. Here’s how it’s done:

1. Make a column in MySQL to store the ip address. Give it the type INT(11).

2. Get the client’s IP Address. I use this function to both retrieve and validate the client’s IP:

function getip() {
   if (validip($_SERVER["HTTP_CLIENT_IP"])) {
       return $_SERVER["HTTP_CLIENT_IP"];
   }
   foreach (explode(",",$_SERVER["HTTP_X_FORWARDED_FOR"]) as $ip) {
       if (validip(trim($ip))) {
           return $ip;
       }
   }
   if (validip($_SERVER["HTTP_PC_REMOTE_ADDR"])) {
        return $_SERVER["HTTP_PC_REMOTE_ADDR"];
   } elseif (validip($_SERVER["HTTP_X_FORWARDED"])) {
       return $_SERVER["HTTP_X_FORWARDED"];
   } elseif (validip($_SERVER["HTTP_FORWARDED_FOR"])) {
       return $_SERVER["HTTP_FORWARDED_FOR"];
   } elseif (validip($_SERVER["HTTP_FORWARDED"])) {
       return $_SERVER["HTTP_FORWARDED"];
   } else {
       return $_SERVER["REMOTE_ADDR"];
   }
}
function validip($ip) {
   if (!empty($ip) && ip2long($ip)!=-1) {
       $reserved_ips = array (
       array('0.0.0.0','2.255.255.255'),
       array('10.0.0.0','10.255.255.255'),
       array('127.0.0.0','127.255.255.255'),
       array('169.254.0.0','169.254.255.255'),
       array('172.16.0.0','172.31.255.255'),
       array('192.0.2.0','192.0.2.255'),
       array('192.168.0.0','192.168.255.255'),
       array('255.255.255.0','255.255.255.255')
       );

       foreach ($reserved_ips as $r) {
           $min = ip2long($r[0]);
           $max = ip2long($r[1]);
           if ((ip2long($ip) >= $min) && (ip2long($ip) <= $max)) return false;
       }
       return true;
   } else {
       return false;
   }
}

3. Store the IP in the database:

$ip = getip();
$longip = ip2long($ip);
$query = sprintf("INSERT INTO table (ipaddr) VALUES (%s)",$longip);
@mysql_query($query, $link) or die("Error inserting record: ".mysql_error());
if(mysql_affected_rows() != 1){
  //nothing was inserted
}else{
  //1 row was inserted
}

4. Retrieve the IP later (I’ll sort them descending)

$res = @mysql_query("SELECT * FROM table ORDER BY ipaddr DESC")
or die("Error selecting records".mysql_error());
while($row = mysql_fetch_assoc($res)){
   $ip = long2ip($row['ipaddr']);
   echo "IP: $ip<br />";
}

That’s it! It’s easy, huh? Now you can sleep well knowing you’re MySQL server doesn’t hate you!

I have come up with a practical use for MySQL Stored Procedures and developed a very useful example for the sceptics. The following is a MySQL SP that calculates the distance between two ZIP codes – all you pass it is the zip codes! This code assumes you have a database of US ZIP Codes with their Longitudes and Latitudes.

——————–MySQL CODE————————-

DELIMITER //
CREATE PROCEDURE `zipDist`(zipA INT, zipB INT)
BEGIN
 DECLARE latA DECIMAL(10,6);
 DECLARE lonA DECIMAL(10,6);
 DECLARE latB DECIMAL(10,6);
 DECLARE lonB DECIMAL(10,6);
 SELECT latitude, longitude INTO latA, lonA FROM zipcodes WHERE zip=zipA;
 SELECT latitude, longitude INTO latB, lonB FROM zipcodes WHERE zip=zipB;
 SELECT ACOS(SIN(RADIANS(latA)) * SIN(RADIANS(latB))  + COS(RADIANS(latA))
     * COS(RADIANS(latB))  * COS(RADIANS(lonB) - RADIANS(lonA)))
     * 3956 AS distance;
END//
DELIMITER ;

Using this stored procedure in your code will save you 2 MySQL queries and a little bit of math in your code.
The following is a stored procedure to find all ZIP codes within a given redius, plus a bit of PHP5 code that calls the procedure using the mysqli extension.

——————–MySQL CODE————————-

DELIMITER //
CREATE PROCEDURE `zipRad`(inZip INT, radius INT)
BEGIN
    DECLARE lat DOUBLE;
    DECLARE lon DOUBLE;
    SELECT latitude, longitude INTO lat, lon FROM zipcodes WHERE zip = inZip;
    SELECT zip FROM zipcodes WHERE (POW((69.1*(longitude - lon)
        *cos( lat /57.3)),2)+POW((69.1*(latitude - lat)),2))<(radius * radius);
END//
DELIMITER ;

———————PHP Code————————–

function zipRadius2($zip,$radius){
    $zipcon2 = mysqli_connect('127.0.0.1',"zipuser","zippass","zipdb")
        or die("Could not connect to DB: ".mysqli_connect_error());
    if($radius < 1 || $radius > 1000){return(false);}
    $query = "CALL zipRad($zip, $radius)";
    $result = mysqli_query($zipcon2, $query) or die(mysqli_error());
    $num = mysqli_num_rows($result);
    $i = 0;
    if($num != 0) {
        while($row = mysqli_fetch_assoc($result)) {
            $zipArray[$i] = $row["zip"];
            $i++;
        }
    }
 return $zipArray;
}