<?php
/**
 * @version $Id: bfVerify.php 139 2010-01-03 20:45:41Z  $
 * @package Blue Flame Framework (bfFramework)
 * @copyright Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Blue Flame IT Ltd. All rights reserved.
 * @license GNU General Public License
 * @link http://www.blueflameit.ltd.uk
 * @author Phil Taylor / Blue Flame IT Ltd.
 *
 * bfFramework 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.
 *
 * bfFramework 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 package.  If not, see http://www.gnu.org/licenses/
 */
defined ( '_JEXEC' ) or die ( 'Restricted access' );

final class bfVerify {
	
	public function __construct() {
		throw new Exception ( 'Call all class methods statically please :-) ' );
	}
	
	static public function numbergreaterthan($number, $comparison) {
		if ($number > $comparison)
			return true;
		return false;
	}
	
	static public function numberlessthan($number, $comparison) {
		if ($number < $comparison)
			return true;
		return false;
	}
	
	static public function regex($expression, $stringtomatch) {
		if (preg_match ( $expression, $stringtomatch ))
			return true;
		return false;
	}
	
	/**
	 * Comparing reals is difficult, so we'll use a tolerance
	 * to compare the square of the difference between the
	 * 2 numbers
	 *
	 * @param unknown_type $number
	 * @param unknown_type $comparison
	 * @return unknown
	 */
	static public function numberequals($number, $comparison) {
		$tolerance = 0.00000000000000001;
		$delta = $number - $comparison;
		$delta *= $delta;
		if ($delta < $tolerance)
			return true;
		return false;
	}
	
	static public function isinteger($number) {
		
		/* 0-9 +- */
		if (preg_match ( '/^[-+]*[0-9]+$/', $number ))
			return true;
			
		/* hexadecimal */
		if (preg_match ( '/^0[xX][0-9a-fA-F]+$/', $number ))
			return true;
		
		return false;
	}
	
	/**
	 *
	 *
	 * @param unknown_type $number
	 * @return unknown
	 */
	static public function isfloat($number) {
		return (is_float ( $number ));
	}
	
	/**
	 *
	 *
	 * @param unknown_type $number
	 * @return unknown
	 */
	static public function isnumeric($number) {
		return (is_numeric ( $number ));
	}
	
	static public function isalloweddomain($domainList, $domain) {
		$domain = substr ( $domain, strpos ( $domain, '@' ) + 1 );
		$alloweddomains = explode ( ',', $domainList );
		foreach ( $alloweddomains as $alloweddomain ) {
			if (trim ( strtolower ( $alloweddomain ) ) == trim ( strtolower ( $domain ) )) {
				return true;
			}
		}
		return false;
	}
	
	static public function isdenieddomain($domainList, $domain) {
		
		$domain = substr ( $domain, strpos ( $domain, '@' ) + 1 );
		$denieddomains = explode ( ',', $domainList );
		foreach ( $denieddomains as $denieddomain ) {
			if (trim ( strtolower ( $denieddomain ) ) == trim ( strtolower ( $domain ) )) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * @group testme
	 *
	 * @param unknown_type $address
	 * @return unknown
	 */
	static public function isemailaddress($address) {
		$mode = 3;
		$address = bfString::strtolower ( $address );
		switch (( int ) $mode) {
			case 2 : // Strict
				$regex = "/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i";
				break;
			case 1 : // Promiscuous
				$regex = "/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i";
				break;
			default : // Recommended
				$regex = "/^([*+!.&#$|0-9a-z^_=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i";
				break;
		}
		
		if (preg_match ( $regex, trim ( $address ) )) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 *
	 *
	 * @author Phil - Recently renamed to ISemailaddressbydns
	 * @param unknown_type $address
	 * @return unknown
	 */
	static public function isemailaddressbydns($address) {
		
		/**
		 * this is a bodge as windows doesnt support checkdnsrr
		 * @author Phil Taylor
		 */
		if (! function_exists ( 'checkdnsrr' )) {
			return true;
		}
		
		// take a given email address and split it into the username and domain.
		if (! preg_match ( '/@/', $address )) {
			return false;
		}
		list ( $userName, $mailDomain ) = preg_split ( "/@/", $address );
		if (strlen ( $userName ) == 0)
			return false;
		$on_win = substr ( PHP_OS, 0, 3 ) == "WIN" ? 1 : 0;
		if (! $on_win) {
			if (checkdnsrr ( $mailDomain, "MX" ))
				return true;
			if (checkdnsrr ( $mailDomain, "A" ))
				return true;
		}
		return false;
	}
	
	/*
	* Check DNSBL - WIN also - DD
	*/
	static public function isblacklisted($ip) {
		$dnsbl_lists = array ("bl.spamcop.net", "sbl.spamhaus.org", "xbl.spamhaus.org" );
		
		require_once _BF_FRAMEWORK_LIB_DIR . DS . 'libs' . DS . 'Pear' . DS . 'Net' . DS . 'DNSBL.php';
		
		$t = new Net_DNSBL ( );
		$t->setBlacklists ( $dnsbl_lists );
		$isListed = $t->isListed ( $ip, false );
		return $isListed;
	}
	
	/**
	 * Blank - Required Field
	 *
	 * @param unknown_type $input
	 * @return unknown
	 */
	static public function isblank($input) {
		if ($input == null || $input == '')
			return true;
		return false;
	}
	
	/**
	 * Blank - Required Field
	 *
	 * @param unknown_type $input
	 * @return unknown
	 */
	static public function isnotblank($input) {
		if ($input == null || $input == '')
			return false;
		return true;
	}
	
	/**
	 * Checkbox field is checked
	 *
	 * @param unknown_type $input
	 * @return unknown
	 */
	static public function ischecked($input) {
		if ($input == "on")
			return true;
		return false;
	}
	
	/**
	 * Checkbox field is not checked
	 *
	 * @param unknown_type $input
	 * @return unknown
	 */
	static public function isnotchecked($input = '') {
		if ($input == "on")
			return false;
		return true;
	}
	
	/**
	 * Length - Input to meet a certian length
	 *
	 * @param unknown_type $string
	 * @param unknown_type $length
	 * @return unknown
	 */
	static public function stringlengthequals($string, $length) {
		if (bfString::strlen ( $string ) == $length)
			return true;
		return false;
	}
	
	/**
	 * Length - Input to exceed a certian length
	 *
	 * @param unknown_type $string
	 * @param unknown_type $length
	 * @return unknown
	 */
	static public function stringlengthgreaterthan($string, $length) {
		if (bfString::strlen ( $string ) >= $length)
			return (true);
		return false;
	}
	
	/**
	 * Length - Input to be less than a certian length
	 *
	 * @param unknown_type $s1
	 * @param unknown_type $s2
	 * @return unknown
	 */
	static public function stringlengthlessthan($string, $length) {
		if (bfString::strlen ( $string ) <= $length)
			return (true);
		return false;
	}
	
	/**
	 * Equalto - Input must be equal to a input of another field (password validation), also < > >= <= != etc.
	 *
	 * @param unknown_type $input
	 * @param unknown_type $from
	 * @param unknown_type $to
	 * @return unknown
	 */
	
	static public function equalto($s1, $s2) {
		return ($s1 == $s2);
	}
	
	/**
	 * Range - check $input >= $from and $input <= $to
	 *
	 */
	static public function range($input, $str) {
		
		$str = bfString::trim ( $str );
		$str = str_replace ( ' ', '', $str );
		$arr = explode ( '-', $str );
		if (count ( $arr ) != 2)
			throw new exception ( 'Range must be in the format 1-100' );
		
		$from = $arr [0];
		$to = $arr [1];
		
		if ($input >= $from) {
			if ($input <= $to) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * I.P - Checks if a valid IP address has been submitted e.g. xxx.xxx.xxx.xxx
	 *
	 * @param string $addr
	 * @return bool
	 */
	static public function isipaddress($addr) {
		// Need something good here for verifying N < 255
		// Basic NN.NNN.NNNNNN.N type check
		if (! preg_match ( '/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/', $addr ))
			return false;
		$numbers = preg_split ( '/\./', $addr );
		if (sizeof ( $numbers ) < 4)
			return false;
		
		if (bfString::strlen ( $numbers [0] ) < 1)
			return false;
		if (bfString::strlen ( $numbers [1] ) < 1)
			return false;
		if (bfString::strlen ( $numbers [2] ) < 1)
			return false;
		if (bfString::strlen ( $numbers [3] ) < 1)
			return false;
		
		if (bfString::strlen ( $numbers [0] ) > 3)
			return false;
		if (bfString::strlen ( $numbers [1] ) > 3)
			return false;
		if (bfString::strlen ( $numbers [2] ) > 3)
			return false;
		if (bfString::strlen ( $numbers [3] ) > 3)
			return false;
		
		if (( int ) $numbers [0] > 255)
			return false;
		if (( int ) $numbers [1] > 255)
			return false;
		if (( int ) $numbers [2] > 255)
			return false;
		if (( int ) $numbers [3] > 255)
			return false;
		
		if (( int ) $numbers [0] < 0)
			return false;
		if (( int ) $numbers [1] < 0)
			return false;
		if (( int ) $numbers [2] < 0)
			return false;
		if (( int ) $numbers [3] < 0)
			return false;
		
		return true;
	}
	
	static public function isvalidUKNINumber($nino) {
		// 1. Must be 9 characters.
		// 2. First 2 characters must be alpha.
		// 3. Next 6 characters must be numeric.
		// 4. Final character can be A, B, C, D or space.
		// 5. First character must not be D,F,I,Q,U or V
		// 6. Second characters must not be D, F, I, O, Q, U or V.
		// 7. First 2 characters must not be combinations of GB, NK, TN or ZZ (the term combinations covers both GB and BG etc.)
		$nino = bfString::strtoupper ( trim ( $nino ) );
		$nino = str_replace ( ' ', '', $nino );
		if (bfString::strlen ( $nino ) != 9)
			return false;
		if (! preg_match ( '/^[A-Z][A-Z]\d{6}/', $nino ))
			return false;
		if (! preg_match ( '/[ABCD ]$/', $nino ))
			return false;
		if (preg_match ( '/^[DFIQUV]$/', $nino ))
			return false;
		if (preg_match ( '/^.[DFIQUVO]/', $nino ))
			return false;
		if (preg_match ( '/^GB/', $nino ))
			return false;
		if (preg_match ( '/^BG/', $nino ))
			return false;
		if (preg_match ( '/^NK/', $nino ))
			return false;
		if (preg_match ( '/^KN/', $nino ))
			return false;
		if (preg_match ( '/^TN/', $nino ))
			return false;
		if (preg_match ( '/^NT/', $nino ))
			return false;
		if (preg_match ( '/^ZZ/', $nino ))
			return false;
		return true;
	}
	
	/**
	 *  Check US Social Security Number (SSN)
	 */
	static public function isValidSSN($ssn) {
		bfLoad ( 'bfVerifyUSSSN' );
		// Instantiate the class
		$fngssn = new fngssn ( );
		return $fngssn->validateSSN ( $ssn );
	}
	
	/**
	 * Credit Card - A credit card type must be selected from a dropdown list
	 * and a valid credit card number must also be entered into a textbox
	 *
	 * @param unknown_type $number
	 * @return unknown
	 */
	static public function isValidCreditCardNumber($number) {
		bfLoad ( 'bfCreditCard' );
		$obj = new isValidCreditCard ( );
		return $obj->validate ( $number );
	}
	
	/**
	 *
	 *
	 * @param unknown_type $cctype
	 * @param unknown_type $number
	 * @return unknown
	 */
	static public function CreditCardType($cctype, $number) {
		bfLoad ( 'bfCreditCard' );
		$cc = new credit_card ( );
		$type = $cc->identify ( $number );
		return (! strcmp ( trim ( bfString::strtoupper ( $type ) ), trim ( bfString::strtoupper ( $cctype ) ) ));
	}
	
	/**
	 * US Zip code
	 *
	 * @param unknown_type $zip
	 * @return unknown
	 */
	static public function isValidUSZip($zip_code) {
		if (preg_match ( "/^([0-9]{5})(-[0-9]{4})?$/i", $zip_code )) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Alnum - Input must not have any non-alpha-numeric chars
	 *
	 * @param unknown_type $word
	 * @return unknown
	 */
	static public function alphanumeric($word) {
		if (preg_match ( "/^\w*$/", $word ))
			return true;
		return false;
	}
	//Decimal - Checks if the input was a decimal
	

	/**
	 *
	 *
	 * @param unknown_type $number
	 * @return unknown
	 */
	static public function decimal($number) {
		if (preg_match ( '/^-?\d*\.+\d*$/', $number ))
			return true;
		return false;
	}
	
	// Check that a date format is dd/mm/yyyy or mm/dd/yyyy or yyyy/mm/dd
	/**
	 *
	 *
	 * @param unknown_type $date
	 * @return unknown
	 */
	static public function dateformat($date) {
		$datearray = array ();
		if (preg_match ( '/^(\d{2}).(\d{2}).(\d{4})$/', $date, $datearray )) {
			$dd = $datearray [1];
			$mm = $datearray [2];
			$yyyy = $datearray [3];
			if ($this->checkdate ( $mm, $dd, $yyyy ))
				return true;
		}
		if (preg_match ( '/^(\d{2}).(\d{2}).(\d{4})$/', $date, $datearray )) {
			$mm = $datearray [1];
			$dd = $datearray [2];
			$yyyy = $datearray [3];
			if ($this->checkdate ( $mm, $dd, $yyyy ))
				return true;
		}
		if (preg_match ( '/^(\d{4}).(\d{2}).(\d{2})$/', $date, $datearray )) {
			$yyyy = $datearray [1];
			$mm = $datearray [2];
			$dd = $datearray [3];
			if ($this->checkdate ( $mm, $dd, $yyyy ))
				return true;
		}
		return false;
	}
	
	//Eitheror - Forces user to enter data to one of two elements
	/**
	 *
	 *
	 * @param unknown_type $first
	 * @param unknown_type $second
	 * @return unknown
	 */
	static public function eitheror($first, $second) {
		if (($first != '') && ($second == ''))
			return true;
		if (($first == '') && ($second != ''))
			return true;
		return false;
	}
	
	/**
	 * The format of UK postcodes is generally:
	 *
	 *    A9 9AA
	 *    A99 9AA
	 *    A9A 9AA
	 *    AA9 9AA
	 *    AA99 9AA
	 *    AA9A 9AA
	 */
	
	static public function isValidUKPostCode($code) {
		$postcode = bfString::strtoupper ( str_replace ( chr ( 32 ), '', $code ) );
		if (preg_match ( "/^(GIR0AA)|(TDCU1ZZ)|((([A-PR-UWYZ][0-9][0-9]?)|" . "(([A-PR-UWYZ][A-HK-Y][0-9][0-9]?)|" . "(([A-PR-UWYZ][0-9][A-HJKSTUW])|" . "([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))))" . "[0-9][ABD-HJLNP-UW-Z]{2})$/", $postcode )) {
			return true;
		} else {
			return false;
		}
	}
	
	static public function isValidVATNumber($num) {
		
		bfLoad ( 'bfVat' );
		$v = new bfVat ( );
		return $v->checkVATNumber ( $num );
	}
	
	/*
	static public functions Included In This File:
	validateUrlSyntax()
	validateEmailSyntax()
	validateFtpSyntax()
	*/
	
	/*
	About validateUrlSyntax():
	This static public function will verify if a http URL is formatted properly, returning
	either with true or false.

	I used rfc #2396 URI: Generic Syntax as my guide when creating the
	regular expression. For all the details see the comments below.


	Usage:
	validateUrlSyntax( url_to_check[, options])

	url_to_check - string - The url to check

	options - string - A optional string of options to set which parts of
	the url are required, optional, or not allowed. Each option
	must be followed by a "+" for required, "?" for optional, or
	"-" for not allowed.

	s - Scheme. Allows "+?-", defaults to "s?"
	H - http:// Allows "+?-", defaults to "H?"
	S - https:// (SSL). Allows "+?-", defaults to "S?"
	E - mailto: (email). Allows "+?-", defaults to "E-"
	F - ftp:// Allows "+?-", defaults to "F-"
	Dependant on scheme being enabled
	u - User section. Allows "+?-", defaults to "u?"
	P - Password in user section. Allows "+?-", defaults to "P?"
	Dependant on user section being enabled
	a - Address (ip or domain). Allows "+?-", defaults to "a+"
	I - Ip address. Allows "+?-", defaults to "I?"
	If I+, then domains are disabled
	If I-, then domains are required
	Dependant on address being enabled
	p - Port number. Allows "+?-", defaults to "p?"
	f - File path. Allows "+?-", defaults to "f?"
	q - Query section. Allows "+?-", defaults to "q?"
	r - Fragment (anchor). Allows "+?-", defaults to "r?"

	Paste the funtion code, or include_once() this template at the top of the page
	you wish to use this static public function.


	Examples:
	validateUrlSyntax('http://george@www.cnn.com/#top')

	validateUrlSyntax('https://games.yahoo.com:8080/board/chess.htm?move=true')

	validateUrlSyntax('http://www.hotmail.com/', 's+u-I-p-q-r-')

	validateUrlSyntax('/directory/file.php#top', 's-u-a-p-f+')


	if (validateUrlSyntax('http://www.canowhoopass.com/', 'u-'))
	{
	echo 'URL SYNTAX IS VERIFIED';
	} else {
	echo 'URL SYNTAX IS ILLEGAL';
	}


	Last Edited:
	December 15th 2004


	Changelog:
	December 15th 2004
	-Added new TLD's - .jobs, .mobi, .post and .travel. They are official, but not yet active.

	August 31th 2004
	-Fixed bug allowing empty username even when it was required
	-Changed and added a few options to add extra schemes
	-Added mailto: ftp:// and http:// options
	-https option was 'l' now it is 'S' (capital)
	-Added password option. Now passwords can be disabled while usernames are ok (for email)
	-IP Address option was 'i' now it is 'I' (capital)
	-Options are now case sensitive
	-Added validateEmailSyntax() and validateFtpSyntax() static public functions below<br>

	August 27th, 2004
	-IP group range is more specific. Used to allow 0-299. Now it is 0-255
	-Port range more specific. Used to allow 0-69999. Now it is 0-65535<br>
	-Fixed bug disallowing 'i-' option.<br>
	-Changed license to GPL

	July 8th, 2004
	-Fixed bug disallowing 'l-' option. Thanks Dr. Cheap

	June 15, 2004
	-Added options parameter to make it easier for people to plug the static public function in
	without needed to rework the code.
	-Split the example application away from the static public function

	June 1, 2004
	-Complete rewrite
	-Now more modular
	-Easier to disable sections
	-Easier to port to other languages
	-Easier to port to verify email addresses
	-Uses only simple regular expressions so it is more portable
	-Follows RFC closer for domain names. Some "play" domains may break
	-Renamed from 'verifyUrl()' to 'validateUrlSyntax()'
	-Removed extra code which added 'http://' and trailing '/' if it was missing
	-That code was better suited for a massaging static public function, not verifying
	-Bug fixes:
	-Now splits up and forces '/path?query#fragment' order
	-No longer requires a path when using a query or fragment

	August 29, 2003
	-Allowed port numbers above 9999. Now allows up to 69999

	Sometime, 2002
	-Added new top level domains
	-aero, coop, museum, name, info, biz, pro

	October 5, 2000
	-First Version


	Intentional Limitations:
	-Does not verify url actually exists. Only validates the syntax
	-Strictly follows the RFC standards. Some urls exist in the wild which will
	not validate. Including ones with square brackets in the query section '[]'


	Known Problems:
	-None at this time


	Author(s):
	Rod Apeldoorn - rod(at)canowhoopass(dot)com


	Homepage:
	http://www.canowhoopass.com/


	Thanks!:
	-WEAV -Several members of Weav helped to test - http://weav.bc.ca/
	-There were also a number of emails from other developers expressing
	thanks and suggestions. It is nice to be appreciated. Thanks!


	License:
	Copyright 2004, Rod Apeldoorn

	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 2 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, write to the Free Software Foundation, Inc.,
	59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

	To view the license online, go to: http://www.gnu.org/copyleft/gpl.html

	*/
	
	/*
	 *
	 *
	 * @param unknown_type $urladdr
	 * @param unknown_type $options
	 * @return unknown
	 */
	static public function isValidURL($urladdr, $options = "") {
		
		// Check Options Parameter
		if (! preg_match ( '/^([sHSEFuPaIpfqr][+?-])*$/i', $options )) {
			throw new Exception ( "Options attribute malformed" );
		}
		
		// Set Options Array, set defaults if options are not specified
		// Scheme
		if (bfString::strpos ( $options, 's' ) === false)
			$aOptions ['s'] = '?';
		else
			$aOptions ['s'] = bfString::substr ( $options, bfString::strpos ( $options, 's' ) + 1, 1 );
			// http://
		if (bfString::strpos ( $options, 'H' ) === false)
			$aOptions ['H'] = '?';
		else
			$aOptions ['H'] = bfString::substr ( $options, bfString::strpos ( $options, 'H' ) + 1, 1 );
			// https:// (SSL)
		if (bfString::strpos ( $options, 'S' ) === false)
			$aOptions ['S'] = '?';
		else
			$aOptions ['S'] = bfString::substr ( $options, bfString::strpos ( $options, 'S' ) + 1, 1 );
			// mailto: (email)
		if (bfString::strpos ( $options, 'E' ) === false)
			$aOptions ['E'] = '-';
		else
			$aOptions ['E'] = bfString::substr ( $options, bfString::strpos ( $options, 'E' ) + 1, 1 );
			// ftp://
		if (bfString::strpos ( $options, 'F' ) === false)
			$aOptions ['F'] = '-';
		else
			$aOptions ['F'] = bfString::substr ( $options, bfString::strpos ( $options, 'F' ) + 1, 1 );
			// User section
		if (bfString::strpos ( $options, 'u' ) === false)
			$aOptions ['u'] = '?';
		else
			$aOptions ['u'] = bfString::substr ( $options, bfString::strpos ( $options, 'u' ) + 1, 1 );
			// Password in user section
		if (bfString::strpos ( $options, 'P' ) === false)
			$aOptions ['P'] = '?';
		else
			$aOptions ['P'] = bfString::substr ( $options, bfString::strpos ( $options, 'P' ) + 1, 1 );
			// Address Section
		if (bfString::strpos ( $options, 'a' ) === false)
			$aOptions ['a'] = '+';
		else
			$aOptions ['a'] = bfString::substr ( $options, bfString::strpos ( $options, 'a' ) + 1, 1 );
			// IP Address in address section
		if (bfString::strpos ( $options, 'I' ) === false)
			$aOptions ['I'] = '?';
		else
			$aOptions ['I'] = bfString::substr ( $options, bfString::strpos ( $options, 'I' ) + 1, 1 );
			// Port number
		if (bfString::strpos ( $options, 'p' ) === false)
			$aOptions ['p'] = '?';
		else
			$aOptions ['p'] = bfString::substr ( $options, bfString::strpos ( $options, 'p' ) + 1, 1 );
			// File Path
		if (bfString::strpos ( $options, 'f' ) === false)
			$aOptions ['f'] = '?';
		else
			$aOptions ['f'] = bfString::substr ( $options, bfString::strpos ( $options, 'f' ) + 1, 1 );
			// Query Section
		if (bfString::strpos ( $options, 'q' ) === false)
			$aOptions ['q'] = '?';
		else
			$aOptions ['q'] = bfString::substr ( $options, bfString::strpos ( $options, 'q' ) + 1, 1 );
			// Fragment (Anchor)
		if (bfString::strpos ( $options, 'r' ) === false)
			$aOptions ['r'] = '?';
		else
			$aOptions ['r'] = bfString::substr ( $options, bfString::strpos ( $options, 'r' ) + 1, 1 );
			
		// Loop through options array, to search for and replace "-" to "{0}" and "+" to ""
		foreach ( $aOptions as $key => $value ) {
			if ($value == '-') {
				$aOptions [$key] = '{0}';
			}
			if ($value == '+') {
				$aOptions [$key] = '';
			}
		}
		
		// DEBUGGING - Unescape following line to display to screen current option values
		// echo '<pre>'; print_r($aOptions); echo '</pre>';
		

		// Preset Allowed Characters
		$alphanum = '[a-zA-Z0-9]'; // Alpha Numeric
		$unreserved = '[a-zA-Z0-9_.!~*' . '\'' . '()-]';
		$escaped = '(%[0-9a-fA-F]{2})'; // Escape sequence - In Hex - %6d would be a 'm'
		$reserved = '[;/?:@&=+$,]'; // Special characters in the URI
		

		// Beginning Regular Expression
		// Scheme - Allows for 'http://', 'https://', 'mailto:', or 'ftp://'
		$scheme = '(';
		if ($aOptions ['H'] === '') {
			$scheme .= 'http://';
		} elseif ($aOptions ['S'] === '') {
			$scheme .= 'https://';
		} elseif ($aOptions ['E'] === '') {
			$scheme .= 'mailto:';
		} elseif ($aOptions ['F'] === '') {
			$scheme .= 'ftp://';
		} else {
			if ($aOptions ['H'] === '?') {
				$scheme .= '|(http://)';
			}
			if ($aOptions ['S'] === '?') {
				$scheme .= '|(https://)';
			}
			if ($aOptions ['E'] === '?') {
				$scheme .= '|(mailto:)';
			}
			if ($aOptions ['F'] === '?') {
				$scheme .= '|(ftp://)';
			}
			$scheme = str_replace ( '(|', '(', $scheme ); // fix first pipe
		}
		$scheme .= ')' . $aOptions ['s'];
		// End setting scheme
		

		// User Info - Allows for 'username@' or 'username:password@'. Note: contrary to rfc, I removed ':' from username section, allowing it only in password.
		//   /---------------- Username -----------------------\  /-------------------------------- Password ------------------------------\
		$userinfo = '((' . $unreserved . '|' . $escaped . '|[;&=+$,]' . ')+(:(' . $unreserved . '|' . $escaped . '|[;:&=+$,]' . ')+)' . $aOptions ['P'] . '@)' . $aOptions ['u'];
		
		// IP ADDRESS - Allows 0.0.0.0 to 255.255.255.255
		$ipaddress = '((((2(([0-4][0-9])|(5[0-5])))|([01]?[0-9]?[0-9]))\.){3}((2(([0-4][0-9])|(5[0-5])))|([01]?[0-9]?[0-9])))';
		
		// Tertiary Domain(s) - Optional - Multi - Although some sites may use other characters, the RFC says tertiary domains have the same naming restrictions as second level domains
		$domain_tertiary = '(' . $alphanum . '(([a-zA-Z0-9-]{0,62})' . $alphanum . ')?\.)*';
		
		// Second Level Domain - Required - First and last characters must be Alpha-numeric. Hyphens are allowed inside.
		$domain_secondary = '(' . $alphanum . '(([a-zA-Z0-9-]{0,62})' . $alphanum . ')?\.)';
		
		/* // This regex is disabled on purpose in favour of the more exact version below
		// Top Level Domain - First character must be Alpha. Last character must be AlphaNumeric. Hyphens are allowed inside.
		$domain_toplevel   = '([a-zA-Z](([a-zA-Z0-9-]*)[a-zA-Z0-9])?)';
		*/
		
		// Top Level Domain - Required - Domain List Current As Of December 2004. Use above escaped line to be forgiving of possible future TLD's
		$domain_toplevel = '(aero|biz|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|post|pro|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ax|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)';
		
		// Address can be IP address or Domain
		if ($aOptions ['I'] === '{0}') { // IP Address Not Allowed
			$address = '(' . $domain_tertiary . $domain_secondary . $domain_toplevel . ')';
		} elseif ($aOptions ['I'] === '') { // IP Address Required
			$address = '(' . $ipaddress . ')';
		} else { // IP Address Optional
			$address = '((' . $ipaddress . ')|(' . $domain_tertiary . $domain_secondary . $domain_toplevel . '))';
		}
		$address = $address . $aOptions ['a'];
		
		// Port Number - :80 or :8080 or :65534 Allows range of :0 to :65535
		//    (0-59999)         |(60000-64999)   |(65000-65499)    |(65500-65529)  |(65530-65535)
		$port_number = '(:(([0-5]?[0-9]{1,4})|(6[0-4][0-9]{3})|(65[0-4][0-9]{2})|(655[0-2][0-9])|(6553[0-5])))' . $aOptions ['p'];
		
		// Path - Can be as simple as '/' or have multiple folders and filenames
		$path = '(/((;)?(' . $unreserved . '|' . $escaped . '|' . '[:@&=+$,]' . ')+(/)?)*)' . $aOptions ['f'];
		
		// Query Section - Accepts ?var1=value1&var2=value2 or ?2393,1221 and much more
		$querystring = '(\?(' . $reserved . '|' . $unreserved . '|' . $escaped . ')*)' . $aOptions ['q'];
		
		// Fragment Section - Accepts anchors such as #top
		$fragment = '(#(' . $reserved . '|' . $unreserved . '|' . $escaped . ')*)' . $aOptions ['r'];
		
		// Building Regular Expression
		$regexp = '±^' . $scheme . $userinfo . $address . $port_number . $path . $querystring . $fragment . '$±';
		
		// DEBUGGING - Uncomment Line Below To Display The Regular Expression Built
		// echo '<pre>' . htmlentities(wordwrap($regexp,70,"\n",1)) . '</pre>';
		

		// Running the regular expression
		if (preg_match ($regexp, $urladdr )) {
			return true; // The domain passed
		} else {
			return false; // The domain didn't pass the expression
		}
	
	} // END static public function validateUrlSyntax()
	

	static public function isExistingUsername($username) {
		$db = bfCompat::getDBO ();
		$sql = ' SELECT COUNT(*) FROM #__users WHERE username = "%s" ';
		$db->setQuery ( sprintf ( $sql, bfSecurity::cleanVar ( $username ) ) );
		
		if ($db->loadResult () > 0)
			return true;
		return false;
	}
	
	static public function isNotExistingUsername($username) {
		$db = bfCompat::getDBO ();
		$sql = ' SELECT COUNT(*) FROM #__users WHERE username = "%s" ';
		$db->setQuery ( sprintf ( $sql, bfSecurity::cleanVar ( $username ) ) );
		
		if ($db->loadResult () <= 0)
			return true;
		return false;
	}
	
	public function _trim(&$value) {
		$value = bfString::trim ( $value );
	}
	
	public function _upper(&$value) {
		$value = bfString::strtoupper ( $value );
	}
	
	public function array_trim($arr) {
		array_walk ( $arr, "_bfVerify_trim" );
		return $arr;
	}
	
	public function array_upper($arr) {
		array_walk ( $arr, "_bfVerify_upper" );
		return $arr;
	}
	/**
	 * Search for needle in haystack
	 *
	 * @param string $needle String to look for
	 * @param string $haystack Comma Separated Values, converted into an array
	 */
	static public function isInArray($needle, $haystack) {
		$array = explode ( ',', $haystack );
		$array = bfVerify::array_trim ( $array );
		$array = bfVerify::array_upper ( $array );
		if (in_array ( bfString::strtoupper ( $needle ), $array ))
			return true;
		return false;
	}
	
	static public function isValid_brazil_cpf($value) {
		bfLoad ( 'bfVerifybrazil' );
		$oCpf = new cpf ( );
		if ($oCpf->verifica_cpf ( $value )) {
			return true;
		} else {
			return false;
		}
	}
	
	static public function isValid_brazil_cnpj($value) {
		bfLoad ( 'bfVerifybrazil' );
		//		$cnpj = "61427258000759";
		$oCnpj = new cnpj ( );
		if ($oCnpj->verfica_cnpj ( $value ) == 1) {
			return true;
		} else {
			return false;
		}
	}
	
	static public function isValid_iban($value) {
		if (! class_exists ( 'Zend_Validate_Iban' ))
			require 'Zend/Validate/Iban.php';
		$value = str_replace ( ' ', '', $value );
		$validator = new Zend_Validate_Iban ( );
		return $validator->isValid ( $value );
	}
	
	/**
	 * @param $value
	 * @return bool true
	 */
	static public function isValidHostname($value) {
		if (! class_exists ( 'Zend_Validate_Hostname' ))
			require 'Zend/Validate/Hostname.php';
		if (preg_match ( '/@/', $value ))
			$value = substr ( $value, strpos ( $value, '@' ) + 1 );
		$validator = new Zend_Validate_Hostname ( Zend_Validate_Hostname::ALLOW_ALL );
		$validator->setIpValidator ( new Zend_Validate_Ip ( ) );
		return $validator->isValid ( $value );
	}
}

function _bfverify_trim(&$value) {
	$value = bfString::trim ( $value );
}

function _bfverify_upper(&$value) {
	$value = bfString::strtoupper ( $value );
}