<?php
/**
 * Australian postal code data geo location
 * @author Michael Baker <michael@phpandmore.org> 
 * irc://irc.efnet.net/#php Rejected
 * The SQL used for this can be downloaded here: http://www.phpandmore.org/aupost.sql
 *
 */
class ausGeoDb {
    
/**
     * Database driver to use in PDO
     *
     * @var string
     * @access private
     */
    
private $driver 'mysql';
    
    
/**
     * Database hostname to connect to
     *
     * @var string
     * @access private
     */
    
private $host '192.168.1.114';
    
    
/**
     * Database username to use
     *
     * @var string
     * @access private
     */
    
private $username 'michael';
    
    
/**
     * Password to use to connect to data
     *
     * @var string
     * @access private
     */
    
private $password 'lidder';
    
    
/**
     * Database to use
     *
     * @var string
     * @access private
     */
    
private $database 'mantis';
    

    
/**
     * Database connector
     *
     * @var object
     * @access private
     */
    
private $_dbh;
    
    
/**
     * Constructor
     * @access public
     *
     */
    
public function __construct() {
        try {
            
$this->_dbh = new PDO $this->driver.':host='.$this->host.';dbname='.$this->database$this->username$this->password );
        } catch ( 
Exception $e ) {
            echo 
'Error connecting to SQL: ' $e->getMessage ();
            exit();
        }
    }
    
    
/**
     * Get locations near Long/Lat location
     *
     * @param double $lon Longitude
     * @param double $lat Latituse
     * @param int $radius Distance in kilometeres eg 50
     * @return array PDO Result Set
     * @access public
     */
    
public function getLocationsNearBy($lat$lon$radius) {
        
$args func_get_args ();
        for(
$i 0$i sizeof $args ); ++ $i) {
            if (! 
is_numeric $args [$i] )) {
                throw new 
Exception 'getLocationsNearLonLat argument '$i 'Excpected int data type recieved ' gettype $args [$i] ) );
            }
        }
        
$radius $radius 0.621371192;
        
$stmt $this->_dbh->prepare 'SELECT * FROM postal WHERE (POW((69.1*(`long`-:long)*cos(:lat/57.3)),2)+POW((69.1*(`lat`-:lat)),2))<(:radius*:radius)' );
        
$stmt->bindParam(':long'$lonPDO::PARAM_INT);
        
$stmt->bindParam(':lat'$latPDO::PARAM_INT);
        
$stmt->bindParam(':radius'$radiusPDO::PARAM_INT);
        
$stmt->execute ();
        
$locationsArray = array ( );
        
$locationsArray $stmt->fetchAll PDO::FETCH_ASSOC );
        return 
$locationsArray;
    }
    
/**
     * Get locations near by post code
     *
     * @param int $post The postcode
     * @param int $radius Distance in km's to look
     * @return array An array containing the following keys postcode,suburb,state,long,lat
     * @access public
     */
    
public function getLocationsNearByPost($post,$radius) {
        
$args func_get_args ();
        for(
$i 0$i sizeof $args ); ++ $i) {
            if (! 
is_numeric $args [$i] )) {
                throw new 
Exception 'getLocationsNearByPost argument ' $i 'Excpected int data type recieved ' gettype $args [$i] ) );
            }
        }
        
$stmt $this->_dbh->prepare('SELECT `lat`,`long` FROM postal WHERE postcode = ? LIMIT 1');
        
$stmt->execute(array($post));
        
$row $stmt->fetch(PDO::FETCH_NUM);
        return 
$this->getLocationsNearBy($row[0],$row[1],$radius);
    }
    
/**
     * Calculate distance between 2 locations
     *
     * @param double $lat1 From latitiude
     * @param double $lon1 From longitude
     * @param double $lat2 To latitude
     * @param double $lon2 To longitude
     * @return int Total Distance
     * @access public
     */
    
public function getDistance($lat1$lon1$lat2$lon2) {
        
$args func_get_args ();
        for(
$i 0$i sizeof $args ); ++ $i) {
            if (! 
is_numeric $args [$i] )) {
                throw new 
Exception 'getDistance argument '$i .'Excpected int data type recieved ' gettype $args [$i] ) );
            }
        }
        
$lat1 deg2rad $lat1 );
        
$lon1 deg2rad $lon1 );
        
$lat2 deg2rad $lat2 );
        
$lon2 deg2rad $lon2 );
        
        
$delta_lat $lat2 $lat1;
        
$delta_lon $lon2 $lon1;
        
        
$temp pow sin $delta_lat 2.0 ), ) + cos $lat1 ) * cos $lat2 ) * pow sin $delta_lon 2.0 ), );
        
        
$earth_radius 3956;
        
$distance $earth_radius atan2 sqrt $temp ), sqrt $temp ) );
        
        
$distance $distance 1.609344;
        
        return 
$distance;
    }
    
    
/**
     * Get the distance between 2 post codes AU only
     *
     * @param int $post1 From postcode
     * @param int $post2 To postcode
     * @return int Distance
     * @access public
     */
    
public function getDistanceByPost($post1,$post2) {
        
$args func_get_args ();
        for(
$i 0$i sizeof $args ); ++ $i) {
            if (! 
is_numeric $args [$i] )) {
                throw new 
Exception 'getDistanceByPost argument ' .$i'Excpected int data type recieved ' gettype $args [$i] ) );
            }
        }
        
$stmt $this->_dbh->prepare('SELECT `lat`,`long` FROM postal WHERE postcode = ? OR postcode = ? GROUP BY postcode LIMIT 2');
        
$stmt->execute(array($post1,$post2));
        
$row $stmt->fetchAll(PDO::FETCH_NUM);
        return 
$this->getDistance($row[0][0], $row[0][1], $row[1][0],$row[1][1]);        
    }
    
/**
     * Get the long/lat/suburb data for a postcode
     *
     * @param int $postcode Search postcode
     * @return array long/lat/suburb mixed array of the values
     * @access public
     */
    
public function getPostData($postcode) {
        if (! 
is_numeric $postcode )) {
            throw new 
Exception 'getPostData argument 1 expected to be int data type we got ' gettype $postcode ) );
        }
        
$stmt $this->_dbh->prepare 'SELECT `long`,`lat`,`suburb` FROM postal WHERE postcode = ? ORDER by lat LIMIT 1' );
        
$stmt->execute ( array ($postcode ) );
        
$row $stmt->fetch PDO::FETCH_ASSOC );
        return 
$row;
    }
    
    
/**
     * Get the post code for an australian suburb
     *
     * @param string $suburb Suburb name
     * @param string $state Short version of the state eg WA,NSW not required
     * @return int The post code
     * @access public
     */
    
public function getPostCode($suburb$state NULL) {
        if (
$state != NULL) {
            
$stmt $this->_dbh->prepare 'SELECT `postcode` FROM postal WHERE `suburb` = ? AND `state` = ?' );
            
$stmt->execute ( array ($suburb$state ) );
        } else {
            
$stmt $this->_dbh->prepare 'SELECT `postcode` FROM postal WHERE `suburb` = ?' );
            
$stmt->execute ( array ($suburb ) );
        }
        
$row $stmt->fetch PDO::FETCH_NUM );
        return 
$row [0];
    }

}
?>