PHP MySQL Multiple (Batch) Queries

Did you know, you can execute multiple queries in PHP using the mysqli extension. Its pretty easy as you can see:

<?      
$connection = new mysqli($dbHost, $dbUser, $dbPass, $dbName);

if ($connection->connect_error) 
{
   echo "Error Occurred While Connection To DataBase";
}


//SQL statements separated by semi-colons

$sqlStatements = "INSERT INTO dbName (columnName) VALUES ('Value1');INSERT INTO dbName (columnName) VALUES ('Value2');INSERT INTO dbName (columnName) VALUES ('Value3');";
 
$sqlResult = $connection->multi_query($sqlStatements);
 
if($sqlResult == true) 
{
   echo 'Successfully executed all statements.';
} 
else 
{
   echo 'Error occurred executing statements.';
}
?>


Clearly, this is more efficient than executing queries one by one, and could save a bit of time in critical applications. Also, mysqli is object-orientated, so there are other useful variables and method that can be returned from the mysqli object to make your code more efficient.

Errors? You may need to enable the mysqli extensions, as these may not be enabled by default. See here http://www.php.net/manual/en/mysqli.installation.php for more info, or leave a comment with your problem.

PHP UK Postcode Validation

A great script by John Gardner for UK postcode validation. Conforms to the official postcode specification by the UK cabinet office. Enjoy!

<?php
/*==============================================================================
Application:   Utiity Function
Author:        John Gardner

Version:       V1.0
Date:          25th December 2004
Description:   Used to check the validity of a UK postcode

Version:       V2.0
Date:          8th March 2005
Description:   BFPO postcodes implemented.
               The rules concerning which alphabetic characters are alllowed in 
               which part of the postcode were more stringently implementd.
  
Parameters:    $postcode - postcodeto be checked. This is returned reformatted 
                           if valid.

This function checks the value of the parameter for a valid postcode format. The 
space between the inward part and the outward part is optional, although is 
inserted if not there as it is part of the official postcode.

The functions returns a value of false if the postcode is in an invalid format, 
and a value of true if it is in a valid format. If the postcode is valid, the 
parameter is loaded up with the postcode in capitals, and a space between the 
outward and the inward code to conform to the correct format.
  
Example call:
  
    if (!checkPostcode($postcode) ) {
      echo 'Invalid postcode 
'; } ------------------------------------------------------------------------------*/ function checkPostcode (&$toCheck) { // Permitted letters depend upon their position in the postcode. $alpha1 = "[abcdefghijklmnoprstuwyz]"; // Character 1 $alpha2 = "[abcdefghklmnopqrstuvwxy]"; // Character 2 $alpha3 = "[abcdefghjkstuw]"; // Character 3 $alpha4 = "[abehmnprvwxy]"; // Character 4 $alpha5 = "[abdefghjlnpqrstuwxyz]"; // Character 5 // Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA $pcexp[0] = '^('.$alpha1.'{1}'.$alpha2.'{0,1}[0-9]{1,2})([0-9]{1}'.$alpha5.'{2})$'; // Expression for postcodes: ANA NAA $pcexp[1] = '^('.$alpha1.'{1}[0-9]{1}'.$alpha3.'{1})([0-9]{1}'.$alpha5.'{2})$'; // Expression for postcodes: AANA NAA $pcexp[2] = '^('.$alpha1.'{1}'.$alpha2.'[0-9]{1}'.$alpha4.')([0-9]{1}'.$alpha5.'{2})$'; // Exception for the special postcode GIR 0AA $pcexp[3] = '^(gir)(0aa)$'; // Standard BFPO numbers $pcexp[4] = '^(bfpo)([0-9]{1,4})$'; // c/o BFPO numbers $pcexp[5] = '^(bfpo)(c\/o[0-9]{1,3})$'; // Load up the string to check, converting into lowercase and removing spaces $postcode = strtolower($toCheck); $postcode = str_replace (' ', '', $postcode); // Assume we are not going to find a valid postcode $valid = false; // Check the string against the six types of postcodes foreach ($pcexp as $regexp) { if (ereg($regexp,$postcode, $matches)) { // Load new postcode back into the form element $toCheck = strtoupper ($matches[1] . ' ' . $matches [2]); // Take account of the special BFPO c/o format $toCheck = ereg_replace ('C\/O', 'c/o ', $toCheck); // Remember that we have found that the code is valid and break from loop $valid = true; break; } } // Return with the reformatted valid postcode in uppercase if the postcode was // valid if ($valid){return true;} else {return false;}; } ?>

PHP Optimising MySQL Tables

If you are working with large MySQL databases and are deleting, inserting or updating a large number of rows, then you probably want all the optimisation you can get, since moving a lot of data around can leave the database a little inefficient.

So, here is a nice little PHP script to "defrag" all your tables - it can cut execution time of SELECT statements down to half in many cases!


dbConnect()

$tables = mysql_query("SHOW TABLES");

while ($table = mysql_fetch_assoc($tables))
{
   foreach ($table as $db => $tableName)
   {
       mysql_query("OPTIMIZE TABLE '".$tableName."'")
       or die(mysql_error());
   }
}

The MySQL command for running this on just one table is simply:

OPTIMIZE TABLE 'tableName';

An easy trick that can really speed up a sluggish database driven website or application. Enjoy.

High Performance MySQL: Optimization, Backups, Replication, and More

PHP Preventing SQL Injections

Often in PHP, we use SQL queries that make use of user input variables, for example:

$_POST['username'] = "aUser"; 

$query = " SELECT * FROM users WHERE username = '$_POST[username]' ";

//Executes SELECT * FROM users WHERE username = 'aUser';

This is a major security floor, since an SQL statement could in theory be passed in $_POST['username'] variable with disastrous results:
$_POST['username'] = "'; DELETE * FROM users"; 

$query = "SELECT * FROM users WHERE username = '$_POST[username]'";

//Executes SELECT * FROM users WHERE username = ''; DELETE * FROM customers !

So all your data could be deleted by a very simple but nasty trick :( . To stop this from happening, use mysql_real_escape_string() as shown below:


$_POST['username'] = "'; DELETE * FROM users";

$username = mysql_real_escape_string($_POST['username']);

$query = "SELECT * FROM users WHERE username = '$username'";

//Executes SELECT * FROM users WHERE username = '\'; DELETE * FROM users'



Now, the single quote is escaped thanks to mysql_real_escape_string() function and the query instead searches for " \'; DELETE * FROM users " as a username rather than executing the delete command.

Please go and add this to your code if you haven't already... I have seen too many amateur websites destroyed by something as simple as an SQL injection attack.

C For Dummies, 2nd Edition

Wicked Cool PHP: Real-World Scripts That Solve Difficult Problems

Remove All Characters except Letters and Numbers (alphanumeric)

Unwanted characters in HTML output can be a pain. Here's a quick way to get rid of them:

ereg_replace("[^A-Za-z0-9]", "", $string);

Send in any improvements via comments :)

Convert Integers to Roman Numerals

A nice little script to easily convert from a decimal integer into roman numerals.

<?php

function getRomanNumerals($decimalInteger) 
{
 $n = intval($decimalInteger);
 $res = '';

 $roman_numerals = array(
    'M'  => 1000,
    'CM' => 900,
    'D'  => 500,
    'CD' => 400,
    'C'  => 100,
    'XC' => 90,
    'L'  => 50,
    'XL' => 40,
    'X'  => 10,
    'IX' => 9,
    'V'  => 5,
    'IV' => 4,
    'I'  => 1);

 foreach ($roman_numerals as $roman => $numeral) 
 {
  $matches = intval($n / $numeral);
  $res .= str_repeat($roman, $matches);
  $n = $n % $numeral;
 }

 return $res;
}

echo getRomanNumerals(32);  ////Example Use - returns XXXII

?>


Any improvements? Drop us a comment. Thanks!

PHP Make URLs into Hyperlinks

On some blogs when you type an url or email address (not a hyperlink with <a> tags), it gets made into a link automatically. Here is a bit of code that does just that using regexp:

function add_html_links($string) 
{  
 //Make links beginning with 'ftp://' or 'http://'
 $string = eregi_replace('(((f|ht){1}tp://)[-a-zA-Z0-9@:%_+.~#?&//=]+)', '<a href="\1">\1</a>', $string);  

 //Make links beginning with 'www.'
 $string = eregi_replace('([[:space:]()[{}])(www.[-a-zA-Z0-9@:%_+.~#?&//=]+)', '\1<a href="http://\2">\2</a>', $string);

 //Make mailto: links out of text that is in email format
 $string = eregi_replace('([_.0-9a-z-]+@([0-9a-z][0-9a-z-]+.)+[a-z]{2,3})', '<a href="mailto:\1">\1</a>', $string);   

 return $string;
}

Enjoy :)



PHP MySQL Get Last Inserted Row ID

A simple function to get the id of the last inserted row into a mysql database is:

mysql_insert_id();

An example using a temporary table is shown here:
<?php

$conn = mysql_connect('localhost', 'username', 'password') or die ('Error connecting to mysql');

mysql_select_db('myDatabase');

mysql_query("CREATE TEMPORARY TABLE testTable (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), column1 VARCHAR(50) )") or die (mysql_error());

mysql_query("INSERT INTO testTable VALUES ()");
$id = mysql_insert_id();
echo $id; //Outputs 1

mysql_query("INSERT INTO testTable VALUES ()");
$id = mysql_insert_id();
echo $id; //Outputs 2

?>

Simple and useful PHP ;)

I use a temporary table in the example to demonstrate the concept, so that in case you do decide to test out the example, it will not leave a footprint on your MySQL server, since temporary tables are deleted when the MySQL session is over.

PHP echo() Simple Performance Enhancing

Not many people seem to know this, but PHP's echo() function (ok, it's not strictly a function) can actually take more than one argument. More importantly, it is more efficient to supply multiple arguments than using concatenation.

Most developers will tend to concatenate the argument to the echo function, like this:

$useful = "useful";
echo "This ".$useful." PHP blog is actually quite ".useful."!";

A more efficient way of achieving the same is:

$useful = "useful";
echo "This ",$useful," PHP blog is actually quite ",useful,"!";

It can save more than 20% in execution time, which may be just what the doctor ordered for larger projects.

It is good to remember here that echo is an input/output process, which tends to consume a lot of execution time. Therefore, at times it can be worthwhile in a script to have one long concatenated string with a single call to echo, rather than a lot of small calls to echo.


Stock Quotes with PHP

Yahoo! Finance provides quotes of virtually any stock in CSV format - all you need to supply is its ticker symbol. This is great for PHP developers who want to display quotes on a finance related website.

Now for a function that makes getting stock quotes feel like child's play:



function getQuote($symbol)
{

$symbol = urlencode( trim( substr(strip_tags($symbol),0,7) ) );
$yahooCSV = "http://finance.yahoo.com/d/quotes.csv?s=$symbol&f=sl1d1t1c1ohgvpnbaejkr&o=t";

$csv = fopen($yahooCSV,"r");

if($csv)
{
list($quote['symbol'], $quote['last'], $quote['date'], $quote['timestamp'], $quote['change'], $quote['open'],
$quote['high'], $quote['low'], $quote['volume'], $quote['previousClose'], $quote['name'], $quote['bid'],
$quote['ask'], $quote['eps'], $quote['YearLow'], $quote['YearHigh'], $quote['PE']) = fgetcsv($csv, ',');

fclose($csv);

return $quote;
}
else
{
return false;
}
}


The function returns an array of the stock's information. Here is a sample PHP script that uses the above function to display all the available stock information about the Royal Bank of Scotland (Ticker: RBS.L).


$RBSQuote = getQuote("RBS.L"); //Returns an array of stock information

echo "Symbol ".$RBSQuote['symbol']."<br/>";
echo "Last ".$RBSQuote['last']."<br/>";
echo "Date ".$RBSQuote['date']."<br/>";
echo "Timestamp ".$RBSQuote['timestamp']."<br/>";
echo "Change ".$RBSQuote['change']."<br/>";
echo "Open ".$RBSQuote['open']."<br/>";
echo "High ".$RBSQuote['high']."<br/>";
echo "Low ".$RBSQuote['low']."<br/>";
echo "Volume ".$RBSQuote['volume']."<br/>";
echo "Previous Close ".$RBSQuote['previousClose']."<br/>";
echo "Name ".$RBSQuote['name']."<br/>";
echo "Bid ".$RBSQuote['bid']."<br>";
echo "Ask ".$RBSQuote['ask']."<br/>";
echo "EPS ".$RBSQuote['eps']."<br/>";
echo "Year High ".$RBSQuote['YearLow']."<br/>";
echo "Year Low ".$RBSQuote['YearHigh']."<br/>";
echo "PE ".$RBSQuote['PE'];



A pretty nifty piece of code that adds extra utility to your website. I like it because it's simple and concise.

A PHP class called PHPQUOTE is available at Booyah Media that is capable of performing the same task as above in a more object orientated way. PHPQUOTE Download


Robust PHP Email Validator

Validating email addresses is important step in maintaining quality user data on any online application. Here is a simple PHP email validation function. Enjoy and provide any improvements via comments.


function isEmail($email)
{
if (preg_match("/^(\w+((-\w+)|(\w.\w+))*)\@(\w+((\.|-)\w+)*\.\w+$)/",$email))
{
return true;
}
else 
{
return false;
}
}

For something (a lot) more robust, a great piece of code by Cal Henderson is given below - it is a large piece of code, but it will ensure that you are validating 99% of all the possible email addresses correctly.

<?php

 #
 # RFC3696 Email Parser
 #
 # By Cal Henderson <cal@iamcal.com>
 #
 # This code is dual licensed:
 # CC Attribution-ShareAlike 2.5 - http://creativecommons.org/licenses/by-sa/2.5/
 # GPLv3 - http://www.gnu.org/copyleft/gpl.html
 #
 # $Revision: 5039 $
 #

 ##################################################################################

 function is_rfc3696_valid_email_address($email){


  ####################################################################################
  #
  # NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
  #                         %d11 /          ;  that do not include the
  #                         %d12 /          ;  carriage return, line feed,
  #                         %d14-31 /       ;  and white space characters
  #                         %d127
  # ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
  # DIGIT          =  %x30-39

  $no_ws_ctl = "[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]";
  $alpha  = "[\\x41-\\x5a\\x61-\\x7a]";
  $digit  = "[\\x30-\\x39]";
  $cr  = "\\x0d";
  $lf  = "\\x0a";
  $crlf  = "(?:$cr$lf)";


  ####################################################################################
  #
  # obs-char        =       %d0-9 / %d11 /          ; %d0-127 except CR and
  #                         %d12 / %d14-127         ;  LF
  # obs-text        =       *LF *CR *(obs-char *LF *CR)
  # text            =       %d1-9 /         ; Characters excluding CR and LF
  #                         %d11 /
  #                         %d12 /
  #                         %d14-127 /
  #                         obs-text
  # obs-qp          =       "\" (%d0-127)
  # quoted-pair     =       ("\" text) / obs-qp

  $obs_char = "[\\x00-\\x09\\x0b\\x0c\\x0e-\\x7f]";
  $obs_text = "(?:$lf*$cr*(?:$obs_char$lf*$cr*)*)";
  $text  = "(?:[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f]|$obs_text)";

  #
  # there's an issue with the definition of 'text', since 'obs_text' can
  # be blank and that allows qp's with no character after the slash. we're
  # treating that as bad, so this just checks we have at least one
  # (non-CRLF) character
  #

  $text  = "(?:$lf*$cr*$obs_char$lf*$cr*)";
  $obs_qp  = "(?:\\x5c[\\x00-\\x7f])";
  $quoted_pair = "(?:\\x5c$text|$obs_qp)";


  ####################################################################################
  #
  # obs-FWS         =       1*WSP *(CRLF 1*WSP)
  # FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
  #                         obs-FWS
  # ctext           =       NO-WS-CTL /     ; Non white space controls
  #                         %d33-39 /       ; The rest of the US-ASCII
  #                         %d42-91 /       ;  characters not including "(",
  #                         %d93-126        ;  ")", or "\"
  # ccontent        =       ctext / quoted-pair / comment
  # comment         =       "(" *([FWS] ccontent) [FWS] ")"
  # CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)

  #
  # note: we translate ccontent only partially to avoid an infinite loop
  # instead, we'll recursively strip *nested* comments before processing
  # the input. that will leave 'plain old comments' to be matched during
  # the main parse.
  #

  $wsp  = "[\\x20\\x09]";
  $obs_fws = "(?:$wsp+(?:$crlf$wsp+)*)";
  $fws  = "(?:(?:(?:$wsp*$crlf)?$wsp+)|$obs_fws)";
  $ctext  = "(?:$no_ws_ctl|[\\x21-\\x27\\x2A-\\x5b\\x5d-\\x7e])";
  $ccontent = "(?:$ctext|$quoted_pair)";
  $comment = "(?:\\x28(?:$fws?$ccontent)*$fws?\\x29)";
  $cfws  = "(?:(?:$fws?$comment)*(?:$fws?$comment|$fws))";


  #
  # these are the rules for removing *nested* comments. we'll just detect
  # outer comment and replace it with an empty comment, and recurse until
  # we stop.
  #

  $outer_ccontent_dull = "(?:$fws?$ctext|$quoted_pair)";
  $outer_ccontent_nest = "(?:$fws?$comment)";
  $outer_comment  = "(?:\\x28$outer_ccontent_dull*(?:$outer_ccontent_nest$outer_ccontent_dull*)+$fws?\\x29)";


  ####################################################################################
  #
  # atext           =       ALPHA / DIGIT / ; Any character except controls,
  #                         "!" / "#" /     ;  SP, and specials.
  #                         "$" / "%" /     ;  Used for atoms
  #                         "&" / "'" /
  #                         "*" / "+" /
  #                         "-" / "/" /
  #                         "=" / "?" /
  #                         "^" / "_" /
  #                         "`" / "{" /
  #                         "|" / "}" /
  #                         "~"
  # atom            =       [CFWS] 1*atext [CFWS]

  $atext  = "(?:$alpha|$digit|[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2f\\x3d\\x3f\\x5e\\x5f\\x60\\x7b-\\x7e])";
  $atom  = "(?:$cfws?(?:$atext)+$cfws?)";


  ####################################################################################
  #
  # qtext           =       NO-WS-CTL /     ; Non white space controls
  #                         %d33 /          ; The rest of the US-ASCII
  #                         %d35-91 /       ;  characters not including "\"
  #                         %d93-126        ;  or the quote character
  # qcontent        =       qtext / quoted-pair
  # quoted-string   =       [CFWS]
  #                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
  #                         [CFWS]
  # word            =       atom / quoted-string

  $qtext  = "(?:$no_ws_ctl|[\\x21\\x23-\\x5b\\x5d-\\x7e])";
  $qcontent = "(?:$qtext|$quoted_pair)";
  $quoted_string = "(?:$cfws?\\x22(?:$fws?$qcontent)*$fws?\\x22$cfws?)";

  #
  # changed the '*' to a '+' to require that quoted strings are not empty
  #

  $quoted_string = "(?:$cfws?\\x22(?:$fws?$qcontent)+$fws?\\x22$cfws?)";
  $word  = "(?:$atom|$quoted_string)";


  ####################################################################################
  #
  # obs-local-part  =       word *("." word)
  # obs-domain      =       atom *("." atom)

  $obs_local_part = "(?:$word(?:\\x2e$word)*)";
  $obs_domain = "(?:$atom(?:\\x2e$atom)*)";


  ####################################################################################
  #
  # dot-atom-text   =       1*atext *("." 1*atext)
  # dot-atom        =       [CFWS] dot-atom-text [CFWS]

  $dot_atom_text = "(?:$atext+(?:\\x2e$atext+)*)";
  $dot_atom = "(?:$cfws?$dot_atom_text$cfws?)";


  ####################################################################################
  #
  # domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
  # dcontent        =       dtext / quoted-pair
  # dtext           =       NO-WS-CTL /     ; Non white space controls
  # 
  #                         %d33-90 /       ; The rest of the US-ASCII
  #                         %d94-126        ;  characters not including "[",
  #                                         ;  "]", or "\"

  $dtext  = "(?:$no_ws_ctl|[\\x21-\\x5a\\x5e-\\x7e])";
  $dcontent = "(?:$dtext|$quoted_pair)";
  $domain_literal = "(?:$cfws?\\x5b(?:$fws?$dcontent)*$fws?\\x5d$cfws?)";


  ####################################################################################
  #
  # local-part      =       dot-atom / quoted-string / obs-local-part
  # domain          =       dot-atom / domain-literal / obs-domain
  # addr-spec       =       local-part "@" domain

  $local_part = "(($dot_atom)|($quoted_string)|($obs_local_part))";
  $domain  = "(($dot_atom)|($domain_literal)|($obs_domain))";
  $addr_spec = "$local_part\\x40$domain";



  #
  # see http://www.dominicsayers.com/isemail/ for details, but this should probably be 254
  #

  if (strlen($email) > 256) return 0;


  #
  # we need to strip nested comments first - we replace them with a simple comment
  #

  $email = rfc3696_strip_comments($outer_comment, $email, "(x)");


  #
  # now match what's left
  #

  if (!preg_match("!^$addr_spec$!", $email, $m)){

   return 0;
  }

  $bits = array(
   'local'   => isset($m[1]) ? $m[1] : '',
   'local-atom'  => isset($m[2]) ? $m[2] : '',
   'local-quoted'  => isset($m[3]) ? $m[3] : '',
   'local-obs'  => isset($m[4]) ? $m[4] : '',
   'domain'  => isset($m[5]) ? $m[5] : '',
   'domain-atom'  => isset($m[6]) ? $m[6] : '',
   'domain-literal' => isset($m[7]) ? $m[7] : '',
   'domain-obs'  => isset($m[8]) ? $m[8] : '',
  );


  #
  # we need to now strip comments from $bits[local] and $bits[domain],
  # since we know they're i the right place and we want them out of the
  # way for checking IPs, label sizes, etc
  #

  $bits['local'] = rfc3696_strip_comments($comment, $bits['local']);
  $bits['domain'] = rfc3696_strip_comments($comment, $bits['domain']);


  #
  # length limits on segments
  #

  if (strlen($bits['local']) > 64) return 0;
  if (strlen($bits['domain']) > 255) return 0;


  #
  # restrictuions on domain-literals from RFC2821 section 4.1.3
  #

  if (strlen($bits['domain-literal'])){

   $Snum   = "(\d{1,3})";
   $IPv4_address_literal = "$Snum\.$Snum\.$Snum\.$Snum";

   $IPv6_hex  = "(?:[0-9a-fA-F]{1,4})";

   $IPv6_full  = "IPv6\:$IPv6_hex(:?\:$IPv6_hex){7}";

   $IPv6_comp_part  = "(?:$IPv6_hex(?:\:$IPv6_hex){0,5})?";
   $IPv6_comp  = "IPv6\:($IPv6_comp_part\:\:$IPv6_comp_part)";

   $IPv6v4_full  = "IPv6\:$IPv6_hex(?:\:$IPv6_hex){5}\:$IPv4_address_literal";

   $IPv6v4_comp_part = "$IPv6_hex(?:\:$IPv6_hex){0,3}";
   $IPv6v4_comp  = "IPv6\:((?:$IPv6v4_comp_part)?\:\:(?:$IPv6v4_comp_part\:)?)$IPv4_address_literal";


   #
   # IPv4 is simple
   #

   if (preg_match("!^\[$IPv4_address_literal\]$!", $bits['domain'], $m)){

    if (intval($m[1]) > 255) return 0;
    if (intval($m[2]) > 255) return 0;
    if (intval($m[3]) > 255) return 0;
    if (intval($m[4]) > 255) return 0;

   }else{

    #
    # this should be IPv6 - a bunch of tests are needed here :)
    #

    while (1){

     if (preg_match("!^\[$IPv6_full\]$!", $bits['domain'])){
      break;
     }

     if (preg_match("!^\[$IPv6_comp\]$!", $bits['domain'], $m)){
      list($a, $b) = explode('::', $m[1]);
      $folded = (strlen($a) && strlen($b)) ? "$a:$b" : "$a$b";
      $groups = explode(':', $folded);
      if (count($groups) > 6) return 0;
      break;
     }

     if (preg_match("!^\[$IPv6v4_full\]$!", $bits['domain'], $m)){

      if (intval($m[1]) > 255) return 0;
      if (intval($m[2]) > 255) return 0;
      if (intval($m[3]) > 255) return 0;
      if (intval($m[4]) > 255) return 0;
      break;
     }

     if (preg_match("!^\[$IPv6v4_comp\]$!", $bits['domain'], $m)){
      list($a, $b) = explode('::', $m[1]);
      $b = substr($b, 0, -1); # remove the trailing colon before the IPv4 address
      $folded = (strlen($a) && strlen($b)) ? "$a:$b" : "$a$b";
      $groups = explode(':', $folded);
      if (count($groups) > 4) return 0;
      break;
     }

     return 0;
    }
   }   
  }else{

   #
   # the domain is either dot-atom or obs-domain - either way, it's
   # made up of simple labels and we split on dots
   #

   $labels = explode('.', $bits['domain']);


   #
   # this is allowed by both dot-atom and obs-domain, but is un-routeable on the
   # public internet, so we'll fail it (e.g. user@localhost)
   #

   if (count($labels) == 1) return 0;


   #
   # checks on each label
   #

   foreach ($labels as $label){

    if (strlen($label) > 63) return 0;
    if (substr($label, 0, 1) == '-') return 0;
    if (substr($label, -1) == '-') return 0;
   }


   #
   # last label can't be all numeric
   #

   if (preg_match('!^[0-9]+$!', array_pop($labels))) return 0;
  }


  return 1;
 }

 ##################################################################################

 function rfc3696_strip_comments($comment, $email, $replace=''){

  while (1){
   $new = preg_replace("!$comment!", $replace, $email);
   if (strlen($new) == strlen($email)){
    return $email;
   }
   $email = $new;
  }
 }

 ##################################################################################
?>

Very nice code by Mr. Henderson, I think you'll agree.

PHP Distance between Coordinates

Calculating the approximate shortest distance between two points on a sphere is simply the calculation of the arc length between them along a great circle (aka Riemannian circle, is a circle on the surface of a sphere that spits it into two equal halves).

The haversine formula is pretty useful in calculating this distance, and since the Earth is almost a sphere, it can provide a good approximation of distance between two coordinates. Enjoy!



function greatCircleDistance($latA, $lonA, $latB, $lonB, $radius = 6371)
{
$latA = deg2rad($latA);
$latB = deg2rad($latB);
$lonA = deg2rad($lonA);
$lonB = deg2rad($lonB);

$deltaLat = $latB - $latA;
$deltaLon = $lonB - $lonA;

$sinDeltaLat = sin($deltaLat/2);
$sinDeltaLon = sin($deltaLon/2);

$rhs = $sinDeltaLat * $sinDeltaLat + cos($latA) * cos($latB) * $sinDeltaLong * $sinDeltaLong;

$distance = $radius * 2 * asin(min(1,sqrt($rhs)));

return $distance; // Returns distance in kilometers
}



In case it was unclear,

$latA = Latitude of coordinate A
$lonA = Longitude of coordinate A
$latB = Latitude of coordinate B
$lonB = Longitude of coordinate B

$radius = Radius of sphere (in the above example, Earth's radius of 6371 km)

In whatever units you supply $radius will be the units in which the distance is returned by the function (i.e. if you supply miles, it will return distances in miles, meters in meters and so on....).

The formula is generally fairly accurate, but it does not take into consideration the road structure of the area (for example if the road has many bends you will travel a bit more), therefore it is likely to provide an underestimate of road travel distance. As expected, it is much more accurate for air travel, as planes tend to fly along great circles.


PHP in_array() Case Insensitive

A very nifty function to carry out a case insensitive in_array() search:



function in_array_case_insensitive($needle, $haystack)
{
return in_array( strtolower($needle), array_map('strtolower', $haystack) );
}



Easy, huh? Here's an example of it in use




$fileExtensionsArray = Array("php", "html", "ASP", "sql", "JSP");
$extension = "PHP";

if (in_array_case_insensitive($extension, $fileExtensionsArray))
{
echo "Yes, $extension is in array";
}
else
{
echo "No $extension is NOT in array";
}


PHP Uploading A File



With PHP, uploading a file is really easy!

Lets start with the upload form (this is just a simple bit of HTML) in file upload01.php

upload1.php


<form enctype="multipart/form-data" action="upload02.php" method="POST">
Choose a file to upload: <input name="upload_file" type="file" />
<input type="submit" value="Upload" />
</form>



This form simply posts data to upload02.php, a PHP file in the same directory as upload01.php.

In reality upload01.php uploads the file to a temporary storage location on your server. It is the job of upload02.php to move it from its temporary location into the location you want it at (if the file is not moved from its temporary location, it will simply be deleted).

Now let's deal with the code for upload02.php:

upload02.php


<?php

$targetDirectory = "files/";
$targetFile = $targetDirectory . basename( $_FILES['upload_file']['name']);

if(move_uploaded_file($_FILES['upload_file']['tmp_name'], $target_path))
{
echo basename( $_FILES['upload_file']['name'])." has been uploaded";
}
else
{
echo "Error uploading the file, please try again!";
}
?>


It's as easy as that!

Trouble with larger files?
In case you do get errors when trying to upload larger files, it may be because PHP limits the maximum file size to 2MB by default. This can be increased by editing php.ini and and changing the 'upload_max_filesize' and 'post_max_size' directives to larger values.