<?php
/**
 * AgileBill - Open Billing Software
 *
 * This body of work is free software; you can redistribute it and/or
 * modify it under the terms of the Open AgileBill License
 * License as published at http://www.agileco.com/agilebill/license1-4.txt
 *
 * Originally authored by Tony Landis, AgileBill LLC
 *
 * Recent modifications by Deon George
 *
 * @author Deon George <deonATleenooksDOTnet>
 * @copyright 2009 Deon George
 * @link http://osb.leenooks.net
 *
 * @link http://www.agileco.com/
 * @copyright 2004-2008 Agileco, LLC.
 * @license http://www.agileco.com/agilebill/license1-4.txt
 * @author Tony Landis <tony@agileco.com>
 * @package AgileBill
 * @subpackage Core
 */

/**
 * The main AgileBill CORE Validation Class
 *
 * @package AgileBill
 * @subpackage Core
 */
class CORE_validate {
	# Store our VAR from the caller
	private $VAR;

	public function __construct($VAR=null,$module='') {
		$this->VAR = $VAR;
		$this->module = $module;
	}

	public function convert($field,$data,$type) {
		switch($type) {
			case 'date':
				return $this->convert_date($data);
				break;

			case 'time':
				return $this->convert_time($data);
				break;

			case 'date-time':
				return $this->convert_date_time($data);
				break;

			case 'date-now':
				return $this->convert_date_now();
				break;

			case 'md5':
				return $this->convert_md5($data);
				break;

			case 'sha':
				return $this->convert_sha($data);
				break;

			case 'rc5':
				return $this->convert_rc5($data);
				break;

			case 'crypt':
				return $this->convert_crypt($data);
				break;

			case 'encrypt':
				return $this->convert_encrypt($data);
				break;

			case 'gpg':
				return $this->convert_gpg($data);
				break;

			case 'pgp':
				return $this->convert_pgp($data);
				break;

			case 'array':
				return $this->convert_array($data);
				break;

			case 'html':
				return $this->convert_html($data);
				break;
		}
	}

	# Convert DEFAULT_TIME_FORMT to unix time stamp
	public function convert_time($data) {
		return strtotime($data);
	}

	# Convert DEFAULT_DATE_FORMT to unix time stamp
	public function convert_date($date,$format=UNIX_DATE_FORMAT) {
		if ($date == '0' || $date == '')
			return '';

		$Arr_format = explode(DEFAULT_DATE_DIVIDER,$format);
		$Arr_date = explode(DEFAULT_DATE_DIVIDER,$date);

		for ($i=0; $i<3; $i++) {
			if ($Arr_format[$i] == 'd')
				$day = $Arr_date[$i];

			if ($Arr_format[$i] == 'm')
				$month = $Arr_date[$i];

			if ($Arr_format[$i] == 'Y')
				$year = $Arr_date[$i];
		}


		return mktime(0,0,0,$month,$day,$year);
	}

	# Convert DEFAULT_DATE_TIME_FORMT to unix time stamp
	public function convert_date_time($date) {
		if ($date == '0' || $date == '')
			return '';

		$Arr_format = explode(DEFAULT_DATE_DIVIDER,UNIX_DATE_FORMAT);
		$Arr_date = explode(DEFAULT_DATE_DIVIDER,$date);

		for ($i=0; $i<3; $i++) {
			if ($Arr_format[$i] == 'd')
				$day = $Arr_date[$i];

			if ($Arr_format[$i] == 'm')
				$month = $Arr_date[$i];

			if ($Arr_format[$i] == 'Y')
				$year = $Arr_date[$i];
		}

		if (empty($day))
			$day = date('d');
		if (empty($month))
			$month = date('m');
		if (empty($year))
			$year = date('Y');

		return mktime(date('H'),date('i'),date('s'),$month,$day,$year);
	}

	public function convert_date_now() {
		return time();
	}

	public function convert_md5($data) {
		if ($data != '')
			return md5($data);
		else
			return '';
	}

	public function convert_rc5($data) {
		if ($data != '')
			return rc5($data);
		else
			return '';
	}

	public function convert_sha($data) {
		if ($data != '')
			return sha1($data);
		else
			return '';
	}

	public function convert_crypt($data) {
		if ($data != '')
			return crypt($data);
		else
			return '';
	}

	public function convert_encrypt($data) {
		if ($data != '') {
			include_once(PATH_CORE.'crypt.inc.php');
			return CORE_encrypt($data);

		} else
			return '';
	}

	public function convert_gpg($data) {
		if ($data != '')
			return gpg($data);
		else
			return '';
	}

	public function convert_pgp($data) {
		if ($data != '')
			return pgp($data);
		else
			return '';
	}


	public function convert_array($data) {
		if ($data != '')
			return serialize($data);
		else
			return serialize(array());
	}

	public function convert_html($data) {
		if ($data == '')
			return '';
		else
			return htmlspecialchars($data);
	}

	public function validate($field,$arr,$data,$type) {
		if (isset($arr['min_len']) && ($arr['min_len'] > 1)) {
			global $C_translate;

			if (strlen($data) < $arr['min_len']) {
				$C_translate->value['CORE']['min_length'] = $arr['min_len'];
				$this->error[$field] = $C_translate->translate('validate_min_length','CORE','');

				return false;
			}
		}

		if (isset($arr['max_len']) && ($arr['max_len'] > 1)) {
			global $C_translate;

			if (strlen($data) > $arr['max_len']) {
				$C_translate->value['CORE']['max_length'] = $arr['max_len'];
				$this->error[$field] = $C_translate->translate('validate_max_length','CORE','');

				return false;
			}
		}

		switch ($type) {
			case 'email':
				return $this->validate_email($data,$field);
				break;

			case 'date':
				return $this->validate_date($data,$field);
				break;

			case 'time':
				return $this->validate_time();
				break;

			case 'date-time':
				return $this->validate_date_time();
				break;

			case 'address':
				return $this->validate_address($data,$field);
				break;

			case 'zip':
				return $this->validate_zip($data,$field);
				break;

			case 'phone':
				return $this->validate_phone($data,$field);
				break;

			case 'cc':
				return $this->validate_cc($data,$field,false,false);
				break;

			case 'check':
				return $this->validate_check();
				break;

			case 'numeric':
				return $this->validate_numeric($data,$field);
				break;

			case 'alphanumeric':
				return $this->validate_alphanumeric($data,$field);
				break;

			case 'non_numeric':
				return $this->validate_non_numeric($data,$field);
				break;

			case 'float':
				return $this->validate_float($data,$field);
				break;

			case 'any':
				return $this->validate_any($data,$field);
				break;

			case 'domain':
				return $this->validate_domain($data,$field);
				break;

			case 'ip':
				return $this->validate_ip($data,$field);
				break;

			case 'password':
				return $this->validate_password($data,$field);
				break;
		}
	}

	public function validate_email($data,$field) {
		if (preg_match('/^[a-zA-Z0-9\._-]+@+[a-z0-9\._-]+\.+[a-z]{2,4}$/',$data)) {
			return true;

		} else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_email','CORE','');

			return false;
		}
	}

	public function validate_ip($data,$field) {
		$ip = $data;
		$valid = true;

		if (preg_match('/^((127)|(192)|(10).*)$/',$ip)) {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_ip','CORE','');

			return false;
		}

		$ip = explode('.',$ip);
		if (count($ip) != 4) {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_ip','CORE','');

			return false;
		}

		foreach($ip as $block)
			if (! is_numeric($block) || $block>255 || $block<1)
				$valid = false;

		if ($valid == false) {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_ip','CORE','');

			return false;

		} else
			return true;
	}

	public function validate_domain($data,$field) {
		if (! preg_match('#^[a-z0-9\-]+\.([a-z0-9\-]+\.)?[a-z]+#i',$data)) {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_domain','CORE','');

			return false;

		} else
			return true;
	}


	public function validate_date($data,$field) {
		if ($data == '0' || $data == '') {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_date','CORE','');

			return false;
		}

		$Arr_format = explode(DEFAULT_DATE_DIVIDER,UNIX_DATE_FORMAT);
		$Arr_date = explode(DEFAULT_DATE_DIVIDER,$data);

		if (! gettype($Arr_date) == 'array' || count($Arr_date) != 3) {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_date','CORE','');

			return false;
		}

		for ($i=0; $i<3; $i++) {
			if ($Arr_format[$i] == 'd')
				$day = $Arr_date[$i];

			if ($Arr_format[$i] == 'm')
				$month = $Arr_date[$i];

			if ($Arr_format[$i] == 'Y')
				$year = $Arr_date[$i];
		}

		$timestamp = mktime(0,0,0,$month,$day,$year);
		$check_ts = mktime(0,0,0,1,1,1979);

		if ($timestamp >= $check_ts)
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_date','CORE','');

			return false;
		}
	}

	public function validate_time() {
		return true;
	}

	public function validate_date_time() {
		return true;
	}

	public function validate_address($data,$field) {
		if (@strlen($data) >= 2 && preg_match('/[0-9]{1,}/',$data) && preg_match('/[a-z]{1,}/',$data)) {
			return true;

		} else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_address','CORE','');

			return false;
		}
	}

	public function validate_zip($data,$field) {
		if (@strlen($data) >= 4 && preg_match('/[0-9a-zA-Z-]{4,}/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_zip','CORE','');

			return false;
		}
	}

	public function validate_phone($data,$field) {
		if (@strlen($data) > 9 && preg_match('/[0-9()-]{10,}/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_phone','CORE','');

			return false;
		}
	}

	public function validate_fax($data,$field) {
		if (@strlen($data) > 9 && preg_match('/[0-9()-]{10,}/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_fax','CORE','');

			return false;
		}
	}

	public function validate_check() {
		return true;
	}

	public function validate_numeric($data,$field) {
		if (preg_match('/^[0-9]{1,}$/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_numeric','CORE','');

			return false;
		}
	}

	public function validate_alphanumeric($data,$field) {
		if (preg_match('/^[0-9a-zA-Z-]{1,}$/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_alphanumeric','CORE','');

			return false;
		}
	}

	public function validate_non_numeric($data,$field) {
		if (! preg_match('/[0-9]{1,}/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_non_numeric','CORE','');

			return false;
		}
	}

	public function validate_float($data,$field) {
		if (preg_match('/^[0-9\.]{1,}$/',$data))
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_float','CORE','');

			return false;
		}
	}

	public function validate_any($data,$field) {
		if ($data != '')
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_any','CORE','');

			return false;
		}
	}

	public function validate_unique($table,$field,$id,$value) {
		if ($value == '')
			return true;

		$db = &DB();

		# Quick check to see if we already have that value
		$result = $db->Execute(sqlSelect($db,$table,$field,array('id'=>$id,$field=>$value)));
		if ($result && $result->RecordCount())
			return true;

		$where = sprintf('%s=%s',$field,$db->qstr($value));

		if ($id != '' && $id != 'record_id')
			$where .= sprintf(' AND id !=%s',$db->qstr($id));

		$result = $db->Execute(sqlSelect($db,$table,$field,$where));

		if ($result === false) {
			global $C_debug;
			$C_debug->error('validate.inc.php','validate_unique',$db->ErrorMsg());

			return false;

		} else {
			if ($result->RecordCount() == 0)
				return true;
			else
				return false;
		}
	}

	public function validate_cc_exp($month,$year) {
		if (preg_replace('/^0/','',$year) > preg_replace('/^0/','',date('y')))
			return true;
		elseif (preg_replace('/^0/','',$year) == preg_replace('/^0/','',date('y')) &&
			preg_replace('/^0/','',$month) >= preg_replace('/^0/','',date('m')))
			return true;
		else
			return false;
	}

	public function validate_cc($ccNum,$field,$card_type,$card_type_accepted_arr) {
		$v_ccNum = false;

		# VISA
		if ($card_type == 'visa' || ! $card_type) {
			if (preg_match('/^4[0-9]{12}([0-9]{3})?$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'visa';
			}

		# MC
		} else if ($card_type == 'mc' || ! $card_type) {
			if (preg_match('/^5[1-5][0-9]{14}$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'mc';
			}

		# AMEX
		} else if ($card_type == 'amex' || ! $card_type) {
			if (preg_match('^/3[47][0-9]{13}$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'amex';
			}

		# DISCOVER
		} else if ($card_type == 'discover' || ! $card_type) {
			if (preg_match('^/6011[0-9]{12}/$',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'discover';
			}

		# DELTA ?
		} else if ($card_type == 'delta' || ! $card_type) {
			if (preg_match('/^4(1373[3-7]|462[0-9]{2}|5397[8-9]|54313|5443[2-5]|54742|567(2[5-9]|3[0-9]|4[0-5])|658[3-7][0-9]|659(0[1-9]|[1-4][0-9]|50)|844(09|10)|909[6-7][0-9]|9218[1-2]|98824)[0-9]{10}$/')) {
				$v_ccNum = true;
				$c_type = 'delta';
			}

		# SOLO ?
		} else if ($card_type == 'solo' || ! $card_type) {
			if (preg_match('^/6(3(34[5-9][0-9])|767[0-9]{2})[0-9]{10}([0-9]{2,3})?$/')) {
				$v_ccNum = true;
				$c_type = 'solo';
			}

		# SWITCH ?
		} else if ($card_type == 'switch' || ! $card_type) {
			if (preg_match('^/49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})[0-9]{10}([0-9]{2,3})?$/',$ccNum) ||
				preg_match('^/564182[0-9]{10}([0-9]{2,3})?$/',$ccNum) ||
				preg_match('^/6(3(33[0-4][0-9])|759[0-9]{2})[0-9]{10}([0-9]{2,3})?$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'switch';
			}

		# JCB
		} else if ($card_type == 'jcb' || ! $card_type) {
			if (preg_match('^/(3[0-9]{4}|2131|1800)[0-9]{11}$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'jcb';
			}

		# DINERS
		} else if ($card_type == 'diners' || ! $card_type) {
			if (preg_match('/^3(0[0-5]|[68][0-9])[0-9]{11}$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'diners';
			}

		# CARTEBLANCHE
		} else if ($card_type == 'carteblanche' || ! $card_type) {
			if (preg_match('/^3(0[0-5]|[68][0-9])[0-9]{11}$/',$ccNum)) {
				$v_ccNum = true;
				$c_type = 'carteblanche';
			}

		# ENROUTE
		} else if ($card_type == 'enroute' || ! $card_type) {
			if (in_array(substr($ccNum,0,4),array('2014','2149')) && (strlen($ccNum) == 15)) {
				$v_ccNum = true;
				$c_type = 'enroute';
			}
		}

		# Validate accepted card type
		if ($card_type_accepted_arr != false & $v_ccNum) {
			$v_ccNum = false;

			for ($i=0; $i<count($card_type_accepted_arr); $i++)
				if ($card_type_accepted_arr[$i] == $c_type)
					$v_ccNum = true;
		}

		if ($v_ccNum)
			return true;

		else {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_cc','CORE','');

			return false;
		}
	}

	/**
	 * Strong password validation
	 */
	public function validate_password($data,$field) {
		# Force numbers and letters
		if (! preg_match('/[0-9]{1,}/',$data) || ! preg_match('/[a-z]{1,}/',$data)) {
			global $C_translate;
			$this->error[$field] = $C_translate->translate('validate_password','CORE','');

			return false;
		}

		$exclude = array();

		# Values to exclude
		foreach (array('email','username','first_name','last_name') as $var) {
			$index = sprintf('%s_%s',$this->module,$var);

			if (isset($this->VAR[$index]) && trim($this->VAR[$index]))
				array_push($exclude,$this->VAR[$index]);
		}

		# Not in email eq to email
		if (isset($this->VAR[$this->module.'_email']) && trim($this->VAR[$this->module.'_email'])) {
			$e = explode('@',$this->VAR[$this->module.'_email']);

			array_push($exclude,$e[0]);
		}

		# not eq to initials
		if (isset($this->VAR[$this->module.'_first_name']) && trim($this->VAR[$this->module.'_first_name']) &&
			isset($this->VAR[$this->module.'_last_name']) && trim($this->VAR[$this->module.'_last_name'])) {

			array_push($exclude,sprintf('%s%s%s',
				substr($this->VAR[$this->module.'_first_name'],0,1),
				isset($this->VAR[$this->module.'_middle_name']) && trim($this->VAR[$this->module.'_middle_name']) ? substr($this->VAR[$this->module.'_middle_name'],0,1) : '',
				substr($this->VAR[$this->module.'_last_name'],0,1)));
		}

		# Check against data
		foreach($exclude as $bad_data) {
			if (! empty($bad_data) && preg_match("/{$bad_data}/",$data)) {
				global $C_translate;
				$this->error[$field] = $C_translate->translate('validate_password','CORE','');

				return false;
			}
		}

		return true;
	}
}
?>