<?php

/*******************************************************
 Sauen PHP Zupdate v0.0.1 unfinished
 Copyright 2007 Sauen.Com and J.T.Stokkeland

 License for this program (Script):

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.


 This script is intended to be used from CLI (NOT web)
 It is intended for developers, not someone who has no clue about PHP/SQL.


 Actually, I started this to be a generic thing to solve a common issue
 with corrupt data where states dont match zip codes..  
 Basically matching state entries with zip codes.

 2007-12-18 ---- Well, as I was
 writing it with the intention of fixing an osCommerce cart that uses the
 insanely idiotic free text entry, I discovered that the way osCommerce
 does states is insanely stupid, it looks to see if the data entered
 matches a "Zone code" and then saves that id if it does.. wtf?
 Well, it goes along with all the other bad crap they made in that system,
 They did a lot of extra work for no gain, it wastes a lot of resources.
 Well anyhow, in this script you will see the first part is sort of 
 generic, counting bad zips and states etc, then at the end when I 
 discovered the stupidity being used in osCommerce I just did a dirty
 trick and generated update statements..
 I posted it here so others can use it as well, as I had no luck
 finding anything when I was looking for something like this.

 You need to uncomment/comment the sections you want to use.

 FAQ:
  
   ?: May I see a demo?
   !: No, if you need that you dont want this script.

  
*******************************************************/

  # mysql options 

  
$dbhost 'localhost';
  
$dbuser 'username';
  
$dbpass 'somesecret';
  
$dbname 'mydborsomething';


  
#  global info - zip/state related

  
$table     'address_book';
  
$colState     'entry_state';
  
$colZip     'entry_postcode';
  
$colID    'customers_id';
  
$zipLen     5;
  

  
# -----------------------------------------------------------
  #
  #  Near static info - also global

  
$ranges = array(
   
     
#  Starting Zip => array('Ending Zip','State);
     
'01001' => array('02791','MA'),
     
'02801' => array('02940','RI'),
     
'03031' => array('03897','NH'),
     
'03901' => array('04992','ME'),
     
'05001' => array('05495','VT'),
     
'05501' => array('05544','MA'),
     
'05601' => array('05907','VT'),
     
'06001' => array('06389','CT'),
     
'06390' => array('06390','NY'),
     
'06401' => array('06928','CT'),
     
'07001' => array('08989','NJ'),
     
'10001' => array('14975','NY'),
     
'15001' => array('19640','PA'),
     
'19701' => array('19980','DE'),
     
'20001' => array('20039','DC'),
     
'20040' => array('20041','VA'),
     
'20040' => array('20167','VA'),
     
'20042' => array('20599','DC'),
     
'20042' => array('20042','VA'),
     
'20331' => array('20331','MD'),
     
'20335' => array('20797','MD'),
     
'20799' => array('20799','DC'),
     
'20812' => array('21930','MD'),
     
'22001' => array('24658','VA'),
     
'24701' => array('26886','WV'),
     
'27006' => array('28909','NC'),
     
'29001' => array('29948','SC'),
     
'30001' => array('31999','GA'),
     
'32004' => array('34997','FL'),
     
'35004' => array('36925','AL'),
     
'37010' => array('38589','TN'),
     
'38601' => array('39776','MS'),
     
'39901' => array('39901','GA'),
     
'40003' => array('42788','KY'),
     
'43001' => array('45999','OH'),
     
'46001' => array('47997','IN'),
     
'48001' => array('49971','MI'),
     
'50001' => array('52809','IA'),
     
'53001' => array('54990','WI'),
     
'55001' => array('56763','MN'),
     
'57001' => array('57799','SD'),
     
'58001' => array('58856','ND'),
     
'59001' => array('59937','MT'),
     
'60001' => array('62999','IL'),
     
'63001' => array('65899','MO'),
     
'66002' => array('67954','KS'),
     
'68001' => array('68118','NE'),
     
'68119' => array('68120','IA'),
     
'68122' => array('69367','NE'),
     
'70001' => array('71232','LA'),
     
'71233' => array('71233','MS'),
     
'71234' => array('71497','LA'),
     
'71601' => array('72959','AR'),
     
'73001' => array('73199','OK'),
     
'73301' => array('73301','TX'),
     
'73401' => array('74966','OK'),
     
'75001' => array('75501','TX'),
     
'75502' => array('75502','AR'),
     
'75503' => array('79999','TX'),
     
'80001' => array('81658','CO'),
     
'82001' => array('83128','WY'),
     
'83201' => array('83876','ID'),
     
'84001' => array('84784','UT'),
     
'85001' => array('86556','AZ'),
     
'87001' => array('88441','NM'),
     
'88510' => array('88589','TX'),
     
'88901' => array('89883','NV'),
     
'90001' => array('96162','CA'),
     
'96701' => array('96898','HI'),
     
'97001' => array('97920','OR'),
     
'98001' => array('99403','WA'),
     
'99501' => array('99950','AK')

  );


  
# ------------------------------------
  #  methods and Functions and stuff

  
function where_zip ()
  {
    global 
$ranges$table$colZip$zipLen;
    
$w ' 0 ';
    foreach (
$ranges as $fromZip => $r)
    {
       
$w .= "\n  OR ( left($table.$colZip,$zipLen)>='$fromZip' AND left($table.$colZip,$zipLen)<='".$r[0]."') ";
    }
    return 
$w;
  }

  function 
where_zip_not ()
  {
    global 
$ranges$table$colZip$zipLen;
    
$w ' 1 ';
    foreach (
$ranges as $fromZip => $r)
    {
       
$w .= "\n  AND NOT (left($table.$colZip,$zipLen)>='$fromZip' AND left($table.$colZip,$zipLen)<='".$r[0]."') ";
    }
    return 
$w;
  }


  function 
zipquery($q)
  {
    
$r = &mysql_query($q);
    if (!
$r) die ("Query Failed:\n $q\n\n---\n".mysql_error()."\n");
    return 
$r;
  }

  function 
ziptabulate($r)
  {
     
$ret '';
     while (
$row mysql_fetch_assoc($r))
     {
        if (!
$ret) foreach(array_keys($row) as $k$ret .= ">\t$k";
        
$ret .= "\n";
        foreach(
$row as $v$ret .= "\t".($v $v '~');
     }
     return 
$ret;
  }

  function 
zip_query_tabulate_print($q,$prefix="\n",$suffix="\n")
  {
     
$r = &zipquery($q);
     if (
mysql_num_rows($r)) echo $prefix.ziptabulate($r).$suffix;
     
mysql_free_result($r);
  }

#### -----------------------------------------------
#  
#   Sequential stuff


  # Connect to DB

  
$db mysql_connect($dbhost,$dbuser,$dbpass);
  if (!
$db) die ('Unable to connect to DB');
  if (!
mysql_select_db($dbname)) die ('Unable to Select Database');



#######################################################
#######################################################
#######################################################
#######################################################
#
#  Here is the stuff you need to edit/add etc to make
#  the goal you want, along with the variables on top

  

  # Get total count, and count of those out of ranges and inside ranges
  
  
$q =  "SELECT count(*) as totalcount FROM $table";
  
zip_query_tabulate_print($q);

  
$q =  "SELECT count(*) as ZipCountInRange FROM $table WHERE \n".where_zip();
  
zip_query_tabulate_print($q);

  
$q =  "SELECT count(*) as ZipCountNotInRange FROM $table WHERE \n".where_zip_not();
  
zip_query_tabulate_print($q);


  
# Inspect the stuff that is outside any valid range

  # first the counts
  
$q =  "SELECT $colState, count($colZip) as ZipCount \n"
    
." FROM $table WHERE \n".where_zip_not()
        .
" GROUP BY $colState";
  
zip_query_tabulate_print($q,"\nList of zipcount in states with zip's out of any range\n");


  
# Now details - use with care, could output a crapload of stuff
  
$q =  "SELECT $colID$colState$colZip \n"
    
." FROM $table WHERE \n".where_zip_not();
  
zip_query_tabulate_print($q,"\nList of entries where Zip is not in any valid range\n");



  
# Now lets inspect the valid ranges and see how many bad boys we have

  # counts
  
foreach ($ranges as $fromZip => $rd)
  {
    
$q "SELECT '".$rd[1]."' AS ShouldBe, $colState, count($colID) as BadCount \n"
     
." FROM $table WHERE \n"
     
."       left($colZip,$zipLen)>=$fromZip \n"
         
."   AND left($colZip,$zipLen)<=".$rd[0]." \n"
         
."   AND $colState NOT LIKE '".$rd[1]."' \n"
         
."   GROUP BY ShouldBe, $colState ";
    
zip_query_tabulate_print($q,"\nCount of entries in ".$rd[1]." with bad zip codes\n");
  }





  
### Dirty workaround duct tape for osCommerce starts here...

  
$states = array();
  foreach (
$ranges as $rd$states[$rd[1]] = '';
  
$where ' 0 ';
  foreach (
$states as $k => $v$where .= " OR zone_code='".$k."' ";
  
$q 'SELECT zone_id,zone_code FROM zones WHERE '.$where.' ORDER BY zone_code';
  
$r = &zipquery($q);

  while (
$row mysql_fetch_assoc($r))
  {
    if (!isset(
$states[$row['zone_code']])) die ($row['zone_code'].' Not in state list');
    
$states[$row['zone_code']] = $row['zone_id'];
  }
  
mysql_free_result($r);


  foreach (
$ranges as $fromZip => $rd)
  {
    echo 
"\nUPDATE $table SET entry_state='',entry_zone_id=".$states[$rd[1]]." WHERE "
         
."left($colZip,$zipLen)>=$fromZip "
         
."AND left($colZip,$zipLen)<=".$rd[0]. ';';
  }


  echo 
"\n.\n";
?>