PageRenderTime 8ms CodeModel.GetById 4ms app.highlight 52ms RepoModel.GetById 111ms app.codeStats 0ms

/lib/core/functions.inc.php

https://github.com/ifthisandthat/devbox
PHP | 1604 lines | 1190 code | 128 blank | 286 comment | 159 complexity | 1eaf2fae6bcc036a6c231487be06b3b3 MD5 | raw file
   1<?php
   2
   3	// Class Autloader
   4	spl_autoload_register('framework_autoload');
   5
   6	function framework_autoload($class_name)
   7	{
   8	    $filename = LIBRARY . '/class.' . strtolower($class_name) . '.php';
   9	    if(file_exists($filename))
  10	        require $filename;
  11	}
  12
  13	// SET DEFAULT FOR A GIVEN VARIABLE
  14	function set_default(&$var, $default="") 
  15	{
  16		if ($var === TRUE) return TRUE; 
  17		$var = (!isset($var) || (($var == "" || $var == "0000-00-00 00:00:00" || $var == "0000-00-00"))) ? $default : $var;
  18		return $var;
  19	}
  20	
  21	function shuffle_assoc($array)
  22	{
  23	   $keys = array_keys($array);
  24	   shuffle($keys);
  25	   return array_merge(array_flip($keys) , $array);
  26	}
  27	
  28	/**
  29	 * Convert UTF-8 characters to their equivalent ISO map
  30	 *
  31	 * @param string $str 
  32	 * @return string
  33	 * @author j4kp07
  34	 */
  35	function utf82iso($str)
  36	{
  37		$output = str_replace('™', ' (TM)', $str);
  38		$output = str_replace('None', '', $output);
  39		return iconv("UTF-8", "ISO-8859-1//TRANSLIT", $output);
  40	}
  41	
  42	/**
  43	 * Searches the array (recursively) for a given value and returns the corresponding key if successful
  44	 *
  45	 * @param string $needle 
  46	 * @param array $haystack 
  47	 * @param boolean $partial_matches 
  48	 * @param boolean $search_keys 
  49	 * @author j4kp07
  50	 */
  51	function array_find_r($needle, $haystack, $partial_matches = false, $search_keys = false) 
  52	{
  53		if(!is_array($haystack)) return false;
  54		
  55		foreach($haystack as $key=>$value) 
  56		{
  57			$what = ($search_keys) ? $key : $value;
  58			if($needle===$what) return $key;
  59			else if($partial_matches && @strpos($what, $needle)!==false) return $key;
  60			else if(is_array($value) && self::array_find_r($needle, $value, $partial_matches, $search_keys)!==false) return $key;
  61		}
  62		return false;
  63	}
  64	
  65	/**
  66	 * Convert an object to an array
  67	 *
  68	 * @param string $object 
  69	 * @return array
  70	 * @author j4kp07
  71	 */
  72	function object2array($object) 
  73	{
  74		$array = array();
  75	   	if (is_object($object)) 
  76		{
  77			$array = $object->result_array();
  78		}
  79	   	return $array;
  80	}
  81	
  82	/**
  83	 * Convert an array to a comma delimited list
  84	 *
  85	 * @param string $array 
  86	 * @return string 
  87	 * @author j4kp07
  88	 */
  89	function array2list($array = '')
  90	{
  91		$output = '';
  92		
  93		if(is_array($array)) 
  94		{
  95			foreach ($array as $key => $value) 
  96			{
  97				$output .= "{$value},";
  98			}
  99
 100			$output = trim($output, ',');
 101		}
 102		
 103		return $output;
 104	}
 105	
 106	/**
 107	 * Convert an array to an object
 108	 *
 109	 * @param string $array 
 110	 * @return object
 111	 * @author j4kp07
 112	 */
 113	function array2object($array) 
 114	{
 115		$object = new stdClass();
 116	   	if (is_array($array) && count($array) > 0) 
 117		{
 118	    	foreach ($array as $name=>$value) 
 119			{
 120	        	$name = strtolower(trim($name));
 121	         	if (!empty($name)) 
 122				{
 123	            	$object->$name = $value;
 124	         	}
 125	      	}
 126	   	}
 127	   	return $object;
 128	}
 129	
 130	/**
 131	 * Sort and array of objects by its properties
 132	 *
 133	 * @param object $object 
 134	 * @param object $property
 135	 * @return object
 136	 * @author j4kp07
 137	 */
 138	function osort(&$object, $property) 
 139	{
 140	    usort($object, create_function('$a,$b', 'if ($a->' . $property . '== $b->' . $property .') return 0; return ($a->' . $property . '< $b->' . $property .') ? -1 : 1;'));
 141	}
 142	
 143	/**
 144	 * Applies the callback to the elements of the given arrays (recursively)
 145	 *
 146	 * @param callback $func 
 147	 * @param array $arr 
 148	 * @return void
 149	 * @author j4kp07
 150	 */
 151	function array_map_recursive($func, $arr)
 152	{
 153		$result = array();
 154		do
 155		{
 156			$key = key($arr);
 157			if (is_array(current($arr))) 
 158			{
 159				$result[$key] = self::array_map_recursive($func, $arr[$key]);
 160			} 
 161			else 
 162			{
 163				$result[$key] = self::$func(current($arr));
 164			}     
 165		} 
 166		while (next($arr) !== false);
 167		return $result;
 168	}
 169	
 170	/**
 171	 * Quote string with slashes (recursively)
 172	 *
 173	 * @param array $arr 
 174	 * @return array
 175	 * @author j4kp07
 176	 */
 177	function addslashes_array($arr)
 178	{
 179	    if(is_array($arr))
 180		{
 181	        $tmp = array();
 182	        foreach ($arr as $key1 => $val)
 183			{
 184	            $tmp[$key1] = self::addslashes_array($val);
 185	        }
 186	        return $tmp;
 187	    }
 188		else
 189		{
 190	        return addslashes(stripslashes($arr));
 191	    }
 192	}	
 193	
 194	/**
 195	 * Un-quotes a quoted string (recursively)
 196	 *
 197	 * @param array $arr 
 198	 * @return array
 199	 * @author j4kp07
 200	 */
 201	function stripslashes_array($arr)
 202	{
 203	    if(is_array($arr))
 204		{
 205	        $tmp = array();
 206	        foreach ($arr as $key1 => $val)
 207			{
 208	            $tmp[$key1] = self::stripslashes_array($val);
 209	        }
 210	        return $tmp;
 211	    }
 212		else
 213		{
 214	        return stripslashes($arr);
 215	    }
 216	}
 217	
 218	/**
 219	 * Tests if the current request is an AJAX request by checking the X-Requested-With HTTP
 220	 * request header that most popular JS frameworks now set for AJAX calls.
 221	 *
 222	 * @return  boolean
 223	 */
 224	function is_ajax()
 225	{
 226		return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
 227	}
 228	
 229	// Returns the first $num characters of $strText with a trailing $strTrail
 230	function max_chars ($str, $num, $trail)
 231	{
 232		$wsCount = 0;
 233		$intTempSize = 0;
 234		$intTotalLen = 0;
 235		$intLength = $num - strlen($trail);
 236		$strTemp = NULL;
 237		
 238		if (strlen($str) > $num) :
 239			$arrTemp = explode(" ", $str);
 240			foreach ($arrTemp as $x) :
 241				$strTemp .= (strlen($strTemp) <= $num) ? ' ' . $x : $strTemp;
 242			endforeach;
 243			$output = $strTemp . $trail;
 244		else :
 245			$output = $strText;
 246		endif;
 247	
 248		return $output;
 249	}
 250	
 251	// Returns the first $num words of $str
 252    function max_words($str, $num, $suffix = '')
 253    {
 254        $words = explode(' ', $str);
 255        if(count($words) < $num) :
 256            return $str;
 257        else :
 258            return implode(' ', array_slice($words, 0, $num)) . $suffix;
 259		endif;
 260    }
 261
 262	// GENERATE RANDOM HASH 
 263	function get_hash($num)
 264	{
 265		$chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 266		$max = strlen($chars)-1;
 267		for($i=0; $i<$num; $i++) :
 268			$output .= $chars[rand(0,$max)];
 269		endfor;
 270		return $output;
 271	}
 272
 273	// GET SUFFIX FOR AN INTEGER
 274	function get_suffix($x) 
 275	{
 276		$x = substr($x,-1);
 277		if($x == 1) : 
 278			$output = "st";
 279		elseif ($x == 2) : 
 280			$output = "nd";
 281		elseif($x == 3) :
 282			$output = "rd";
 283		else :
 284			$output = "th";
 285		endif;
 286		
 287		return $output;
 288	}
 289
 290	function get_time($name, $id, $class, $thistime) 
 291	{
 292		echo "<select name=\"{$name}\" id=\"{$id}\" class=\"{$class}\">";
 293		$i = 0;
 294		$time = date('H:i',mktime(0, 0, 0));
 295		while($i < 1440) :
 296			$v = date('H:i:s',mktime(0, 0 + $i, 0));
 297			$k = date('g:i a',mktime(0, 0 + $i, 0));
 298			$selected = ($v == $thistime) ? 'selected' : NULL;
 299			echo "<option value=\"{$v}\" {$selected}>{$k}</option>\r\n";
 300			$i = $i + 15;
 301		endwhile;
 302		echo "</select>";
 303	}
 304	
 305	// Grabs the contents of a remote URL. Can perform basic authentication if un/pw are provided.
 306    function get_url($url, $username = null, $password = null)
 307    {
 308        if(function_exists('curl_init'))
 309        {
 310            $ch = curl_init();
 311            if(!is_null($username) && !is_null($password))
 312                curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Basic ' .  base64_encode("$username:$password")));
 313            curl_setopt($ch, CURLOPT_URL, $url);
 314            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 315            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
 316            $html = curl_exec($ch);
 317            curl_close($ch);
 318            return $html;
 319        }
 320        elseif(ini_get('allow_url_fopen') == true)
 321        {
 322            if(!is_null($username) && !is_null($password))
 323                $url = str_replace("://", "://$username:$password@", $url);
 324            $html = file_get_contents($url);
 325            return $html;
 326        }
 327        else
 328        {
 329            // Cannot open url. Either install curl-php or set allow_url_fopen = true in php.ini
 330            return false;
 331        }
 332    }
 333
 334	// SEND EMAIL WITH/WITHOUT ATTACHMENTS
 335	function sendmail($to, $from, $subject, $msg, $file=NULL) 
 336	{
 337		$uid = md5(uniqid(time()));
 338		$headers  = "MIME-Version: 1.0\r\n";
 339		$headers .= "From: {$from}\r\n";
 340		$headers .= "Reply-To: {$from}\r\n";
 341		$headers .= "X-Mailer: PHP/".phpversion()."\r\n";
 342		if($file == NULL) :
 343			$headers .= 'Content-type: text/html; charset=iso-8859-1'."\r\n";
 344		else :
 345			$file_size = filesize($file);
 346			$handle = fopen($file, "r");
 347			$content = fread($handle, $file_size);
 348			fclose($handle);
 349			$content = chunk_split(base64_encode($content));
 350			$headers .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
 351			$headers .= "This is a multi-part message in MIME format.\r\n";
 352			$headers .= "--{$uid}\r\n";
 353			$headers .= "Content-type:text/html; charset=iso-8859-1\r\n";
 354			$headers .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
 355			$headers .= "{$msg}\r\n\r\n";
 356			$headers .= "--{$uid}\r\n";
 357			$headers .= "Content-Type: application/pdf; name=\"{$attachment}\"\r\n"; 
 358			// $headers .= "Content-Type: application/octet-stream; name=\"{$attachment}\"\r\n"; 
 359			$headers .= "Content-Transfer-Encoding: base64\r\n";
 360			$headers .= "Content-Disposition: attachment; filename=\"{$attachment}\"\r\n\r\n";
 361			$headers .= "{$content}\r\n\r\n";
 362			$headers .= "--{$uid}--";
 363		endif;
 364		
 365		$pattern = '/^([a-z0-9])(([-a-z0-9._\+])*([a-z0-9]))*\@([a-z0-9])' . '(([a-z0-9-])*([a-z0-9]))+' . '(\.([a-z0-9])([-a-z0-9_-])?([a-z0-9])+)+$/i';
 366		if(preg_match($pattern, $to)) :
 367			mail($to, $subject, $msg, $headers);
 368		endif;
 369	}
 370	
 371	function datediff($month,$day,$year) 
 372	{
 373		$today = time();
 374		$thisdate = mktime(0,0,0,$month,$day,$year);
 375		$dateDiff = $today - $thisdate;
 376		$fullyears = floor($dateDiff/(60*60*24*365));
 377		return $fullyears;
 378	}
 379	
 380    function printr($var)
 381    {
 382        $output = print_r($var, true);
 383        $output = str_replace("\n", "<br>", $output);
 384        $output = str_replace(' ', '&nbsp;', $output);
 385        echo "<div style='font-family:courier;'>$output</div>";
 386    }
 387
 388    // Given a string such as "comment_123" or "id_57", it returns the final, numeric id.
 389    function split_id($str)
 390    {
 391        return match('/[_-]([0-9]+)$/', $str, 1);
 392    }
 393
 394    // Creates a friendly URL slug from a string
 395    function slugify($str)
 396    {
 397        $str = preg_replace('/[^a-zA-Z0-9 -]/', '', $str);
 398        $str = strtolower(str_replace(' ', '-', trim($str)));
 399        $str = preg_replace('/-+/', '-', $str);
 400        return $str;
 401    }
 402
 403    // Computes the *full* URL of the current page (protocol, server, path, query parameters, etc)
 404    function full_url()
 405    {
 406        $s = empty($_SERVER['HTTPS']) ? '' : ($_SERVER['HTTPS'] == 'on') ? 's' : '';
 407        $protocol = substr(strtolower($_SERVER['SERVER_PROTOCOL']), 0, strpos(strtolower($_SERVER['SERVER_PROTOCOL']), '/')) . $s;
 408        $port = ($_SERVER['SERVER_PORT'] == '80') ? '' : (":".$_SERVER['SERVER_PORT']);
 409        return $protocol . "://" . $_SERVER['HTTP_HOST'] . $port . $_SERVER['REQUEST_URI'];
 410    }
 411
 412    // Returns an English representation of a date
 413    // Graciously stolen from http://ejohn.org/files/pretty.js
 414    function time2str($ts)
 415    {
 416        if(!ctype_digit($ts))
 417            $ts = strtotime($ts);
 418
 419        $diff = time() - $ts;
 420        if($diff == 0)
 421            return 'now';
 422        elseif($diff > 0)
 423        {
 424            $day_diff = floor($diff / 86400);
 425            if($day_diff == 0)
 426            {
 427                if($diff < 60) return 'just now';
 428                if($diff < 120) return '1 minute ago';
 429                if($diff < 3600) return floor($diff / 60) . ' minutes ago';
 430                if($diff < 7200) return '1 hour ago';
 431                if($diff < 86400) return floor($diff / 3600) . ' hours ago';
 432            }
 433            if($day_diff == 1) return 'Yesterday';
 434            if($day_diff < 7) return $day_diff . ' days ago';
 435            if($day_diff < 31) return ceil($day_diff / 7) . ' weeks ago';
 436            if($day_diff < 60) return 'last month';
 437            $ret = date('F Y', $ts);
 438            return ($ret == 'December 1969') ? '' : $ret;
 439        }
 440        else
 441        {
 442            $diff = abs($diff);
 443            $day_diff = floor($diff / 86400);
 444            if($day_diff == 0)
 445            {
 446                if($diff < 120) return 'in a minute';
 447                if($diff < 3600) return 'in ' . floor($diff / 60) . ' minutes';
 448                if($diff < 7200) return 'in an hour';
 449                if($diff < 86400) return 'in ' . floor($diff / 3600) . ' hours';
 450            }
 451            if($day_diff == 1) return 'Tomorrow';
 452            if($day_diff < 4) return date('l', $ts);
 453            if($day_diff < 7 + (7 - date('w'))) return 'next week';
 454            if(ceil($day_diff / 7) < 4) return 'in ' . ceil($day_diff / 7) . ' weeks';
 455            if(date('n', $ts) == date('n') + 1) return 'next month';
 456            $ret = date('F Y', $ts);
 457            return ($ret == 'December 1969') ? '' : $ret;
 458        }
 459    }
 460
 461    // Returns an array representation of the given calendar month.
 462    // The array values are timestamps which allow you to easily format
 463    // and manipulate the dates as needed.
 464    function calendar($month = null, $year = null)
 465    {
 466        if(is_null($month)) $month = date('n');
 467        if(is_null($year)) $year = date('Y');
 468
 469        $first = mktime(0, 0, 0, $month, 1, $year);
 470        $last = mktime(23, 59, 59, $month, date('t', $first), $year);
 471
 472        $start = $first - (86400 * date('w', $first));
 473        $stop = $last + (86400 * (7 - date('w', $first)));
 474
 475        $out = array();
 476        while($start < $stop)
 477        {
 478            $week = array();
 479            if($start > $last) break;
 480            for($i = 0; $i < 7; $i++)
 481            {
 482                $week[$i] = $start;
 483                $start += 86400;
 484            }
 485            $out[] = $week;
 486        }
 487
 488        return $out;
 489    }
 490
 491    // Processes mod_rewrite URLs into key => value pairs
 492    // See .htacess for more info.
 493    function pick_off($grab_first = false, $sep = '/')
 494    {
 495        $ret = array();
 496        $arr = explode($sep, trim($_SERVER['REQUEST_URI'], $sep));
 497        if($grab_first) $ret[0] = array_shift($arr);
 498        while(count($arr) > 0)
 499            $ret[array_shift($arr)] = array_shift($arr);
 500        return (count($ret) > 0) ? $ret : false;
 501    }
 502
 503    // More robust strict date checking for string representations
 504    function chkdate($str)
 505    {
 506        // Requires PHP 5.2
 507        if(function_exists('date_parse'))
 508        {
 509            $info = date_parse($str);
 510            if($info !== false && $info['error_count'] == 0)
 511            {
 512                if(checkdate($info['month'], $info['day'], $info['year']))
 513                    return true;
 514            }
 515
 516            return false;
 517        }
 518
 519        // Else, for PHP < 5.2
 520        return strtotime($str);
 521    }
 522
 523    // Converts a date/timestamp into the specified format
 524	function dater($date = null, $format = null)
 525    {
 526        if(is_null($format))
 527            $format = 'Y-m-d H:i:s';
 528
 529        if(is_null($date))
 530            $date = time();
 531
 532		if(is_int($date))
 533			return date($format, $date);
 534		if(is_float($date))
 535			return date($format, $date);
 536		if(is_string($date)) {
 537	        if(ctype_digit($date) === true)
 538	            return date($format, $date);
 539			if((preg_match('/[^0-9.]/', $date) == 0) && (substr_count($date, '.') <= 1))
 540				return date($format, floatval($date));
 541			return date($format, strtotime($date));
 542		}
 543		
 544		// If $date is anything else, you're doing something wrong,
 545		// so just let PHP error out however it wants.
 546		return date($format, $date);
 547    }
 548
 549	function format_date($d,$format) 
 550	{
 551		$y = substr($d,0,4);
 552		$m = str_pad(substr($d,4,2),'/',STR_PAD_BOTH);
 553		$d = substr($d,6,2);
 554		$output = (strlen($d) > 0) ? date($format,strtotime($y.$m.$d)):NULL;
 555
 556		return $output;
 557	}
 558
 559	function format_phone($n) 
 560	{
 561		$n = preg_replace("/[^0-9]/", "", $n);
 562		if(strlen($n) == 7) :
 563			return preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2", $n);
 564		elseif (strlen($n) == 10) :
 565			return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $n);
 566		else :
 567			return $n;
 568		endif;
 569	}
 570	
 571	// Formats a given number of seconds into proper mm:ss format
 572    function format_time($seconds)
 573    {
 574        return floor($seconds / 60) . ':' . str_pad($seconds % 60, 2, '0');
 575    }
 576
 577	function format_url($url) 
 578	{
 579		if (!empty($url)) :
 580			$output = (preg_match("/http(s?):\/\//", $url)) ? $url : "http://{$url}";
 581		else : 
 582			$output = FALSE;
 583		endif;
 584		
 585		return $output;
 586	}
 587
 588    // Outputs hour, minute, am/pm dropdown boxes
 589    function hourmin($hid = 'hour', $mid = 'minute', $pid = 'ampm', $hval = null, $mval = null, $pval = null)
 590    {
 591        // Dumb hack to let you just pass in a timestamp instead
 592        if(func_num_args() == 1)
 593        {
 594            list($hval, $mval, $pval) = explode(' ', date('g i a', strtotime($hid)));
 595            $hid = 'hour';
 596            $mid = 'minute';
 597            $aid = 'ampm';
 598        }
 599        else
 600        {
 601            if(is_null($hval)) $hval = date('h');
 602            if(is_null($mval)) $mval = date('i');
 603            if(is_null($pval)) $pval = date('a');
 604        }
 605
 606        $hours = array(12, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11);
 607        $out = "<select name='$hid' id='$hid'>";
 608        foreach($hours as $hour)
 609            if(intval($hval) == intval($hour)) $out .= "<option value='$hour' selected>$hour</option>";
 610            else $out .= "<option value='$hour'>$hour</option>";
 611        $out .= "</select>";
 612
 613        $minutes = array('00', 15, 30, 45);
 614        $out .= "<select name='$mid' id='$mid'>";
 615        foreach($minutes as $minute)
 616            if(intval($mval) == intval($minute)) $out .= "<option value='$minute' selected>$minute</option>";
 617            else $out .= "<option value='$minute'>$minute</option>";
 618        $out .= "</select>";
 619
 620        $out .= "<select name='$pid' id='$pid'>";
 621        $out .= "<option value='am'>am</option>";
 622        if($pval == 'pm') $out .= "<option value='pm' selected>pm</option>";
 623        else $out .= "<option value='pm'>pm</option>";
 624        $out .= "</select>";
 625
 626        return $out;
 627    }
 628
 629    // Returns the HTML for a month, day, and year dropdown boxes.
 630    // You can set the default date by passing in a timestamp OR a parseable date string.
 631    // $prefix_ will be appened to the name/id's of each dropdown, allowing for multiple calls in the same form.
 632    // $output_format lets you specify which dropdowns appear and in what order.
 633    function mdy($date = null, $prefix = null, $output_format = 'm d y')
 634    {
 635        if(is_null($date)) $date = time();
 636        if(!ctype_digit($date)) $date = strtotime($date);
 637        if(!is_null($prefix)) $prefix .= '_';
 638        list($yval, $mval, $dval) = explode(' ', date('Y n j', $date));
 639
 640        $month_dd = "<select name='{$prefix}month' id='{$prefix}month'>";
 641        for($i = 1; $i <= 12; $i++)
 642        {
 643            $selected = ($mval == $i) ? ' selected="selected"' : '';
 644            $month_dd .= "<option value='$i'$selected>" . date('F', mktime(0, 0, 0, $i, 1, 2000)) . "</option>";
 645        }
 646        $month_dd .= "</select>";
 647
 648        $day_dd = "<select name='{$prefix}day' id='{$prefix}day'>";
 649        for($i = 1; $i <= 31; $i++)
 650        {
 651            $selected = ($dval == $i) ? ' selected="selected"' : '';
 652            $day_dd .= "<option value='$i'$selected>$i</option>";
 653        }
 654        $day_dd .= "</select>";
 655
 656        $year_dd = "<select name='{$prefix}year' id='{$prefix}year'>";
 657        for($i = date('Y'); $i < date('Y') + 10; $i++)
 658        {
 659            $selected = ($yval == $i) ? ' selected="selected"' : '';
 660            $year_dd .= "<option value='$i'$selected>$i</option>";
 661        }
 662        $year_dd .= "</select>";
 663
 664        $trans = array('m' => $month_dd, 'd' => $day_dd, 'y' => $year_dd);
 665        return strtr($output_format, $trans);
 666    }
 667
 668    // Redirects user to $url
 669    function redirect($url = null)
 670    {
 671        if(is_null($url)) $url = $_SERVER['PHP_SELF'];
 672        header("Location: $url");
 673        exit();
 674    }
 675
 676    // Ensures $str ends with a single /
 677    function slash($str)
 678    {
 679        return rtrim($str, '/') . '/';
 680    }
 681
 682    // Ensures $str DOES NOT end with a /
 683    function unslash($str)
 684    {
 685        return rtrim($str, '/');
 686    }
 687
 688    // Returns an array of the values of the specified column from a multi-dimensional array
 689    function gimme($arr, $key = null)
 690    {
 691        if(is_null($key))
 692            $key = current(array_keys($arr));
 693
 694        $out = array();
 695        foreach($arr as $a)
 696            $out[] = $a[$key];
 697
 698        return $out;
 699    }
 700
 701    // Fixes MAGIC_QUOTES
 702    function fix_slashes($arr = '')
 703    {
 704        if(is_null($arr) || $arr == '') return null;
 705        if(!get_magic_quotes_gpc()) return $arr;
 706        return is_array($arr) ? array_map('fix_slashes', $arr) : stripslashes($arr);
 707    }
 708
 709    // Serves an external document for download as an HTTP attachment.
 710    function download_document($filename, $mimetype = 'application/octet-stream')
 711    {
 712        if(!file_exists($filename) || !is_readable($filename)) return false;
 713        $base = basename($filename);
 714        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
 715        header("Content-Disposition: attachment; filename=$base");
 716        header("Content-Length: " . filesize($filename));
 717        header("Content-Type: $mimetype");
 718        readfile($filename);
 719        exit();
 720    }
 721
 722    // Retrieves the filesize of a remote file.
 723    function remote_filesize($url, $user = null, $pw = null)
 724    {
 725        $ch = curl_init($url);
 726        curl_setopt($ch, CURLOPT_HEADER, 1);
 727        curl_setopt($ch, CURLOPT_NOBODY, 1);
 728        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 729
 730        if(!is_null($user) && !is_null($pw))
 731        {
 732            $headers = array('Authorization: Basic ' .  base64_encode("$user:$pw"));
 733            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 734        }
 735
 736        $head = curl_exec($ch);
 737        curl_close($ch);
 738
 739        preg_match('/Content-Length:\s([0-9].+?)\s/', $head, $matches);
 740
 741        return isset($matches[1]) ? $matches[1] : false;
 742    }
 743
 744	// Inserts a string within another string at a specified location
 745	function str_insert($needle, $haystack, $location)
 746	{
 747	   $front = substr($haystack, 0, $location);
 748	   $back  = substr($haystack, $location);
 749
 750	   return $front . $needle . $back;
 751	}
 752
 753    // Outputs a filesize in human readable format.
 754    function bytes2str($val, $round = 0)
 755    {
 756        $unit = array('','K','M','G','T','P','E','Z','Y');
 757        while($val >= 1000)
 758        {
 759            $val /= 1024;
 760            array_shift($unit);
 761        }
 762        return round($val, $round) . array_shift($unit) . 'B';
 763    }
 764
 765    // Returns the user's browser info.
 766    // browscap.ini must be available for this to work.
 767    // See the PHP manual for more details.
 768    function browser_info()
 769    {
 770        $info    = get_browser(null, true);
 771        $browser = $info['browser'] . ' ' . $info['version'];
 772        $os      = $info['platform'];
 773        $ip      = $_SERVER['REMOTE_ADDR'];
 774        return array('ip' => $ip, 'browser' => $browser, 'os' => $os);
 775    }
 776
 777    // Quick wrapper for preg_match
 778    function match($regex, $str, $i = 0)
 779    {
 780        if(preg_match($regex, $str, $match) == 1)
 781            return $match[$i];
 782        else
 783            return false;
 784    }
 785
 786    // Returns the lat, long of an address via Yahoo!'s geocoding service.
 787    // You'll need an App ID, which is available from here:
 788    // http://developer.yahoo.com/maps/rest/V1/geocode.html
 789    // Note: needs to be updated to use PlaceFinder instead.
 790    function geocode($location, $appid)
 791    {
 792        $location = urlencode($location);
 793        $appid    = urlencode($appid);
 794        $data     = file_get_contents("http://local.yahooapis.com/MapsService/V1/geocode?output=php&appid=$appid&location=$location");
 795        $data     = unserialize($data);
 796
 797        if($data === false) return false;
 798
 799        $data = $data['ResultSet']['Result'];
 800
 801        return array('lat' => $data['Latitude'], 'lng' => $data['Longitude']);
 802    }
 803
 804    // A stub for Yahoo!'s reverse geocoding service
 805    // http://developer.yahoo.com/geo/placefinder/
 806    function reverse_geocode($lat, $lng)
 807    {
 808
 809    }
 810
 811    // Quick and dirty wrapper for curl scraping.
 812    function curl($url, $referer = null, $post = null)
 813    {
 814        static $tmpfile;
 815
 816        if(!isset($tmpfile) || ($tmpfile == '')) $tmpfile = tempnam('/tmp', 'FOO');
 817
 818        $ch = curl_init($url);
 819        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 820        curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfile);
 821        curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfile);
 822        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
 823        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061024 BonEcho/2.0");
 824        // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 825        // curl_setopt($ch, CURLOPT_VERBOSE, 1);
 826
 827        if($referer) curl_setopt($ch, CURLOPT_REFERER, $referer);
 828        if(!is_null($post))
 829        {
 830            curl_setopt($ch, CURLOPT_POST, true);
 831            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
 832        }
 833
 834        $html = curl_exec($ch);
 835
 836        // $last_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
 837        return $html;
 838    }
 839
 840    // Accepts any number of arguments and returns the first non-empty one
 841    function pick()
 842    {
 843        foreach(func_get_args() as $arg)
 844            if(!empty($arg))
 845                return $arg;
 846        return '';
 847    }
 848
 849    // Secure a PHP script using basic HTTP authentication
 850    function http_auth($un, $pw, $realm = "Secured Area")
 851    {
 852        if(!(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_USER'] == $un && $_SERVER['PHP_AUTH_PW'] == $pw))
 853        {
 854            header('WWW-Authenticate: Basic realm="' . $realm . '"');
 855            header('Status: 401 Unauthorized');
 856            exit();
 857        }
 858    }
 859
 860    // Returns a file's mimetype based on its extension
 861    function mime_type($filename, $default = 'application/octet-stream')
 862    {
 863        $mime_types = array(
 864			'323'     => 'text/h323',
 865			'acx'     => 'application/internet-property-stream',
 866			'ai'      => 'application/postscript',
 867			'aif'     => 'audio/x-aiff',
 868			'aifc'    => 'audio/x-aiff',
 869			'aiff'    => 'audio/x-aiff',
 870			'asf'     => 'video/x-ms-asf',
 871			'asr'     => 'video/x-ms-asf',
 872			'asx'     => 'video/x-ms-asf',
 873			'au'      => 'audio/basic',
 874			'avi'     => 'video/x-msvideo',
 875			'axs'     => 'application/olescript',
 876			'bas'     => 'text/plain',
 877			'bcpio'   => 'application/x-bcpio',
 878			'bin'     => 'application/octet-stream',
 879			'bmp'     => 'image/bmp',
 880			'c'       => 'text/plain',
 881			'cat'     => 'application/vnd.ms-pkiseccat',
 882			'cdf'     => 'application/x-cdf',
 883			'cer'     => 'application/x-x509-ca-cert',
 884			'class'   => 'application/octet-stream',
 885			'clp'     => 'application/x-msclip',
 886			'cmx'     => 'image/x-cmx',
 887			'cod'     => 'image/cis-cod',
 888			'cpio'    => 'application/x-cpio',
 889			'crd'     => 'application/x-mscardfile',
 890			'crl'     => 'application/pkix-crl',
 891			'crt'     => 'application/x-x509-ca-cert',
 892			'csh'     => 'application/x-csh',
 893			'css'     => 'text/css',
 894			'dcr'     => 'application/x-director',
 895			'der'     => 'application/x-x509-ca-cert',
 896			'dir'     => 'application/x-director',
 897			'dll'     => 'application/x-msdownload',
 898			'dms'     => 'application/octet-stream',
 899			'doc'     => 'application/msword',
 900			'dot'     => 'application/msword',
 901			'dvi'     => 'application/x-dvi',
 902			'dxr'     => 'application/x-director',
 903			'eps'     => 'application/postscript',
 904			'etx'     => 'text/x-setext',
 905			'evy'     => 'application/envoy',
 906			'exe'     => 'application/octet-stream',
 907			'fif'     => 'application/fractals',
 908			'flac'    => 'audio/flac',
 909			'flr'     => 'x-world/x-vrml',
 910			'gif'     => 'image/gif',
 911			'gtar'    => 'application/x-gtar',
 912			'gz'      => 'application/x-gzip',
 913			'h'       => 'text/plain',
 914			'hdf'     => 'application/x-hdf',
 915			'hlp'     => 'application/winhlp',
 916			'hqx'     => 'application/mac-binhex40',
 917			'hta'     => 'application/hta',
 918			'htc'     => 'text/x-component',
 919			'htm'     => 'text/html',
 920			'html'    => 'text/html',
 921			'htt'     => 'text/webviewhtml',
 922			'ico'     => 'image/x-icon',
 923			'ief'     => 'image/ief',
 924			'iii'     => 'application/x-iphone',
 925			'ins'     => 'application/x-internet-signup',
 926			'isp'     => 'application/x-internet-signup',
 927			'jfif'    => 'image/pipeg',
 928			'jpe'     => 'image/jpeg',
 929			'jpeg'    => 'image/jpeg',
 930			'jpg'     => 'image/jpeg',
 931			'js'      => 'application/x-javascript',
 932			'latex'   => 'application/x-latex',
 933			'lha'     => 'application/octet-stream',
 934			'lsf'     => 'video/x-la-asf',
 935			'lsx'     => 'video/x-la-asf',
 936			'lzh'     => 'application/octet-stream',
 937			'm13'     => 'application/x-msmediaview',
 938			'm14'     => 'application/x-msmediaview',
 939			'm3u'     => 'audio/x-mpegurl',
 940			'man'     => 'application/x-troff-man',
 941			'mdb'     => 'application/x-msaccess',
 942			'me'      => 'application/x-troff-me',
 943			'mht'     => 'message/rfc822',
 944			'mhtml'   => 'message/rfc822',
 945			'mid'     => 'audio/mid',
 946			'mny'     => 'application/x-msmoney',
 947			'mov'     => 'video/quicktime',
 948			'movie'   => 'video/x-sgi-movie',
 949			'mp2'     => 'video/mpeg',
 950			'mp3'     => 'audio/mpeg',
 951			'mpa'     => 'video/mpeg',
 952			'mpe'     => 'video/mpeg',
 953			'mpeg'    => 'video/mpeg',
 954			'mpg'     => 'video/mpeg',
 955			'mpp'     => 'application/vnd.ms-project',
 956			'mpv2'    => 'video/mpeg',
 957			'ms'      => 'application/x-troff-ms',
 958			'mvb'     => 'application/x-msmediaview',
 959			'nws'     => 'message/rfc822',
 960			'oda'     => 'application/oda',
 961			'oga'     => 'audio/ogg',
 962			'ogg'     => 'audio/ogg',
 963			'ogv'     => 'video/ogg',
 964			'ogx'     => 'application/ogg',
 965			'p10'     => 'application/pkcs10',
 966			'p12'     => 'application/x-pkcs12',
 967			'p7b'     => 'application/x-pkcs7-certificates',
 968			'p7c'     => 'application/x-pkcs7-mime',
 969			'p7m'     => 'application/x-pkcs7-mime',
 970			'p7r'     => 'application/x-pkcs7-certreqresp',
 971			'p7s'     => 'application/x-pkcs7-signature',
 972			'pbm'     => 'image/x-portable-bitmap',
 973			'pdf'     => 'application/pdf',
 974			'pfx'     => 'application/x-pkcs12',
 975			'pgm'     => 'image/x-portable-graymap',
 976			'pko'     => 'application/ynd.ms-pkipko',
 977			'pma'     => 'application/x-perfmon',
 978			'pmc'     => 'application/x-perfmon',
 979			'pml'     => 'application/x-perfmon',
 980			'pmr'     => 'application/x-perfmon',
 981			'pmw'     => 'application/x-perfmon',
 982			'pnm'     => 'image/x-portable-anymap',
 983			'pot'     => 'application/vnd.ms-powerpoint',
 984			'ppm'     => 'image/x-portable-pixmap',
 985			'pps'     => 'application/vnd.ms-powerpoint',
 986			'ppt'     => 'application/vnd.ms-powerpoint',
 987			'prf'     => 'application/pics-rules',
 988			'ps'      => 'application/postscript',
 989			'pub'     => 'application/x-mspublisher',
 990			'qt'      => 'video/quicktime',
 991			'ra'      => 'audio/x-pn-realaudio',
 992			'ram'     => 'audio/x-pn-realaudio',
 993			'ras'     => 'image/x-cmu-raster',
 994			'rgb'     => 'image/x-rgb',
 995			'rmi'     => 'audio/mid',
 996			'roff'    => 'application/x-troff',
 997			'rtf'     => 'application/rtf',
 998			'rtx'     => 'text/richtext',
 999			'scd'     => 'application/x-msschedule',
1000			'sct'     => 'text/scriptlet',
1001			'setpay'  => 'application/set-payment-initiation',
1002			'setreg'  => 'application/set-registration-initiation',
1003			'sh'      => 'application/x-sh',
1004			'shar'    => 'application/x-shar',
1005			'sit'     => 'application/x-stuffit',
1006			'snd'     => 'audio/basic',
1007			'spc'     => 'application/x-pkcs7-certificates',
1008			'spl'     => 'application/futuresplash',
1009			'src'     => 'application/x-wais-source',
1010			'sst'     => 'application/vnd.ms-pkicertstore',
1011			'stl'     => 'application/vnd.ms-pkistl',
1012			'stm'     => 'text/html',
1013			'svg'     => "image/svg+xml",
1014			'sv4cpio' => 'application/x-sv4cpio',
1015			'sv4crc'  => 'application/x-sv4crc',
1016			't'       => 'application/x-troff',
1017			'tar'     => 'application/x-tar',
1018			'tcl'     => 'application/x-tcl',
1019			'tex'     => 'application/x-tex',
1020			'texi'    => 'application/x-texinfo',
1021			'texinfo' => 'application/x-texinfo',
1022			'tgz'     => 'application/x-compressed',
1023			'tif'     => 'image/tiff',
1024			'tiff'    => 'image/tiff',
1025			'tr'      => 'application/x-troff',
1026			'trm'     => 'application/x-msterminal',
1027			'tsv'     => 'text/tab-separated-values',
1028			'txt'     => 'text/plain',
1029			'uls'     => 'text/iuls',
1030			'ustar'   => 'application/x-ustar',
1031			'vcf'     => 'text/x-vcard',
1032			'vrml'    => 'x-world/x-vrml',
1033			'wav'     => 'audio/x-wav',
1034			'wcm'     => 'application/vnd.ms-works',
1035			'wdb'     => 'application/vnd.ms-works',
1036			'wks'     => 'application/vnd.ms-works',
1037			'wmf'     => 'application/x-msmetafile',
1038			'wps'     => 'application/vnd.ms-works',
1039			'wri'     => 'application/x-mswrite',
1040			'wrl'     => 'x-world/x-vrml',
1041			'wrz'     => 'x-world/x-vrml',
1042			'xaf'     => 'x-world/x-vrml',
1043			'xbm'     => 'image/x-xbitmap',
1044			'xla'     => 'application/vnd.ms-excel',
1045			'xlc'     => 'application/vnd.ms-excel',
1046			'xlm'     => 'application/vnd.ms-excel',
1047			'xls'     => 'application/vnd.ms-excel',
1048			'xlt'     => 'application/vnd.ms-excel',
1049			'xlw'     => 'application/vnd.ms-excel',
1050			'xof'     => 'x-world/x-vrml',
1051			'xpm'     => 'image/x-xpixmap',
1052			'xwd'     => 'image/x-xwindowdump',
1053			'z'       => 'application/x-compress',
1054			'zip'     => 'application/zip',
1055		);
1056        $ext = pathinfo($filename, PATHINFO_EXTENSION);
1057        return isset($mime_types[$ext]) ? $mime_types[$ext] : $default;
1058    }
1059
1060	/**
1061	* Filter Attributes
1062	*
1063	* Filters tag attributes for consistency and safety
1064	*
1065	* @access	public
1066	* @param	string
1067	* @return	string
1068	*/
1069	function _filter_attributes($str) {
1070		$out = '';
1071
1072		if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
1073		{
1074			foreach ($matches[0] as $match)
1075			{
1076				$out .= preg_replace("#/\*.*?\*/#s", '', $match);
1077			}
1078		}
1079
1080		return $out;
1081	}
1082	
1083	/**
1084	* JS Link Removal
1085	*
1086	* Callback function for xss_clean() to sanitize links
1087	* This limits the PCRE backtracks, making it more performance friendly
1088	* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
1089	* PHP 5.2+ on link-heavy strings
1090	*
1091	* @param	array
1092	* @return	string
1093	*/
1094	function _js_link_removal($match) {
1095		$attributes = _filter_attributes(str_replace(array('<', '>'), '', $match[1]));
1096		return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
1097	}
1098
1099	/**
1100	* JS Image Removal
1101	*
1102	* Callback function for xss_clean() to sanitize image tags
1103	* This limits the PCRE backtracks, making it more performance friendly
1104	* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
1105	* PHP 5.2+ on image tag heavy strings
1106	*
1107	* @param	array
1108	* @return	string
1109	*/
1110	function _js_img_removal($match) {
1111		$attributes = _filter_attributes(str_replace(array('<', '>'), '', $match[1]));
1112		return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
1113	}
1114
1115	/**
1116	* Sanitize Naughty HTML
1117	*
1118	* Callback function for xss_clean() to remove naughty HTML elements
1119	*
1120	* @param	array
1121	* @return	string
1122	*/
1123	function _sanitize_naughty_html($matches) {
1124		// encode opening brace
1125		$str = '&lt;'.$matches[1].$matches[2].$matches[3];
1126
1127		// encode captured opening or closing brace to prevent recursive vectors
1128		$str .= str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);
1129
1130		return $str;
1131	}
1132			
1133	/**
1134	* Compact Exploded Words
1135	*
1136	* Callback function for xss_clean() to remove whitespace from
1137	* things like j a v a s c r i p t
1138	*
1139	* @param	type
1140	* @return	type
1141	*/
1142	function _compact_exploded_words($matches) {
1143		return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
1144	}
1145	
1146	/**
1147	* Attribute Conversion
1148	*
1149	* Used as a callback for XSS Clean
1150	*
1151	* @param	array
1152	* @return	string
1153	*/
1154	function _convert_attribute($match)	{
1155		return str_replace(array('>', '<', '\\'), array('&gt;', '&lt;', '\\\\'), $match[0]);
1156	}
1157
1158	// --------------------------------------------------------------------
1159
1160	/**
1161	* HTML Entity Decode Callback
1162	*
1163	* Used as a callback for XSS Clean
1164	*
1165	* @param	array
1166	* @return	string
1167	*/
1168	function _html_entity_decode_callback($match) {
1169		return html_entity_decode($match[0]);
1170	}
1171	
1172	/**
1173	* Remove Invisible Characters
1174	*
1175	* Used as a callback for XSS Clean
1176	* 
1177	* This prevents sandwiching null characters
1178	* between ascii characters, like Java\0script.
1179	*
1180	* @param	string
1181	* @return	string
1182	*/
1183	function _remove_invisible_characters($str) {
1184		static $non_displayables;
1185
1186		if ( ! isset($non_displayables))
1187		{
1188			// every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09),
1189			$non_displayables = array(
1190										'/%0[0-8bcef]/',			// url encoded 00-08, 11, 12, 14, 15
1191										'/%1[0-9a-f]/',				// url encoded 16-31
1192										'/[\x00-\x08]/',			// 00-08
1193										'/\x0b/', '/\x0c/',			// 11, 12
1194										'/[\x0e-\x1f]/'				// 14-31
1195									);
1196		}
1197
1198		do
1199		{
1200			$cleaned = $str;
1201			$str = preg_replace($non_displayables, '', $str);
1202		}
1203		while ($cleaned != $str);
1204
1205		return $str;
1206	}
1207
1208	/**
1209	* Random Hash for protecting URLs
1210	*
1211	* @access	public
1212	* @return	string
1213	*/
1214	function xss_hash()	{
1215		if (phpversion() >= 4.2)
1216			mt_srand();
1217		else
1218			mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);
1219
1220		$output = md5(time() + mt_rand(0, 1999999999));
1221
1222		return $output;
1223	}
1224	
1225	/**
1226	* XSS Clean
1227	*
1228	* Sanitizes data so that Cross Site Scripting Hacks can be
1229	* prevented.  This function does a fair amount of work but
1230	* it is extremely thorough, designed to prevent even the
1231	* most obscure XSS attempts.  Nothing is ever 100% foolproof,
1232	* of course, but I haven't been able to get anything passed
1233	* the filter.
1234	*
1235	* Note: This function should only be used to deal with data
1236	* upon submission.  It's not something that should
1237	* be used for general runtime processing.
1238	*
1239	* This function was based in part on some code and ideas I
1240	* got from Bitflux: http://blog.bitflux.ch/wiki/XSS_Prevention
1241	*
1242	* To help develop this script I used this great list of
1243	* vulnerabilities along with a few other hacks I've
1244	* harvested from examining vulnerabilities in other programs:
1245	* http://ha.ckers.org/xss.html
1246	*
1247	* @param	string
1248	* @return	string
1249	*/
1250	function xss_clean($str, $is_image = FALSE)	{
1251		global $never_allowed_str;
1252		global $never_allowed_regex;
1253		$xss_hash = xss_hash();
1254		
1255		/*
1256		* Is the string an array?
1257		*/
1258		if (is_array($str)) {
1259			while (list($key) = each($str))	{
1260				$str[$key] = xss_clean($str[$key]);
1261			}
1262			return $str;
1263		}
1264
1265		/*
1266		* Remove Invisible Characters
1267		*/
1268		$str = _remove_invisible_characters($str);
1269
1270		/*
1271		* Protect GET variables in URLs
1272		*/
1273
1274		// 901119URL5918AMP18930PROTECT8198
1275
1276		$str = preg_replace('|\&([a-z\_0-9]+)\=([a-z\_0-9]+)|i', $xss_hash."\\1=\\2", $str);
1277
1278		/*
1279		* Validate standard character entities
1280		*
1281		* Add a semicolon if missing.  We do this to enable
1282		* the conversion of entities to ASCII later.
1283		*
1284		*/
1285		$str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str);
1286
1287		/*
1288		* Validate UTF16 two byte encoding (x00) 
1289		*
1290		* Just as above, adds a semicolon if missing.
1291		*
1292		*/
1293		$str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);
1294
1295		/*
1296		* Un-Protect GET variables in URLs
1297		*/
1298		$str = str_replace($xss_hash, '&', $str);
1299
1300		/*
1301		* URL Decode
1302		*
1303		* Just in case stuff like this is submitted:
1304		*
1305		* <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
1306		*
1307		* Note: Use rawurldecode() so it does not remove plus signs
1308		*
1309		*/
1310		$str = rawurldecode($str);
1311
1312		/*
1313		* Convert character entities to ASCII 
1314		*
1315		* This permits our tests below to work reliably.
1316		* We only convert entities that are within tags since
1317		* these are the ones that will pose security problems.
1318		*
1319		*/
1320		$str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", _convert_attribute, $str);
1321		$str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", _html_entity_decode_callback, $str);
1322		
1323		/*
1324		* Remove Invisible Characters Again!
1325		*/
1326		$str = _remove_invisible_characters($str);
1327
1328		/*
1329		* Convert all tabs to spaces
1330		*
1331		* This prevents strings like this: ja	vascript
1332		* NOTE: we deal with spaces between characters later.
1333		* NOTE: preg_replace was found to be amazingly slow here on large blocks of data,
1334		* so we use str_replace.
1335		*
1336		*/
1337
1338 		if (strpos($str, "\t") !== FALSE) {
1339			$str = str_replace("\t", ' ', $str);
1340		}
1341
1342		/*
1343		* Capture converted string for later comparison
1344		*/
1345		$converted_string = $str;
1346
1347		/*
1348		* Not Allowed Under Any Conditions
1349		*/
1350
1351		foreach ($never_allowed_str as $key => $val) {
1352			$str = str_replace($key, $val, $str);   
1353		}
1354
1355		foreach ($never_allowed_regex as $key => $val) {
1356			$str = preg_replace("#".$key."#i", $val, $str);   
1357		}
1358
1359		/*
1360		* Makes PHP tags safe
1361		*
1362		*  Note: XML tags are inadvertently replaced too:
1363		*
1364		*	<?xml
1365		*
1366		* But it doesn't seem to pose a problem.
1367		*
1368		*/
1369		if ($is_image === TRUE)	{
1370			// Images have a tendency to have the PHP short opening and closing tags every so often
1371			// so we skip those and only do the long opening tags.
1372			$str = str_replace(array('<?php', '<?PHP'),  array('&lt;?php', '&lt;?PHP'), $str);
1373		} else {
1374			$str = str_replace(array('<?php', '<?PHP', '<?', '?'.'>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
1375		}
1376
1377		/*
1378		* Compact any exploded words
1379		*
1380		* This corrects words like:  j a v a s c r i p t
1381		* These words are compacted back to their correct state.
1382		*
1383		*/
1384		$words = array('javascript', 'expression', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
1385		foreach ($words as $word) {
1386			$temp = '';
1387
1388			for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)	{
1389				$temp .= substr($word, $i, 1)."\s*";
1390			}
1391
1392			// We only want to do this when it is followed by a non-word character
1393			// That way valid stuff like "dealer to" does not become "dealerto"
1394			$str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', _compact_exploded_words, $str);
1395		}
1396
1397		/*
1398		* Remove disallowed Javascript in links or img tags
1399		* We used to do some version comparisons and use of stripos for PHP5, but it is dog slow compared
1400		* to these simplified non-capturing preg_match(), especially if the pattern exists in the string
1401		*/
1402		do {
1403			$original = $str;
1404
1405			if (preg_match("/<a/i", $str)) {
1406				$str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", _js_link_removal, $str);
1407			}
1408
1409			if (preg_match("/<img/i", $str)) {
1410				$str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", _js_img_removal, $str);
1411			}
1412
1413			if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str)) {
1414				$str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);
1415			}
1416		}
1417		while($original != $str);
1418
1419		unset($original);
1420
1421		/*
1422		* Remove JavaScript Event Handlers
1423		*
1424		* Note: This code is a little blunt.  It removes
1425		* the event handler and anything up to the closing >,
1426		* but it's unlikely to be a problem.
1427		*
1428		*/
1429		$event_handlers = array('[^a-z_\-]on\w*','xmlns');
1430
1431		if ($is_image === TRUE)	{
1432			/*
1433			* Adobe Photoshop puts XML metadata into JFIF images, including namespacing, 
1434			* so we have to allow this for images. -Paul
1435			*/
1436			unset($event_handlers[array_search('xmlns', $event_handlers)]);
1437		}
1438
1439		$str = preg_replace("#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str);
1440
1441		/*
1442		* Sanitize naughty HTML elements
1443		*
1444		* If a tag containing any of the words in the list
1445		* below is found, the tag gets converted to entities.
1446		*
1447		* So this: <blink>
1448		* Becomes: &lt;blink&gt;
1449		*
1450		*/
1451		$naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
1452		$str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', _sanitize_naughty_html, $str);
1453
1454		/*
1455		* Sanitize naughty scripting elements
1456		*
1457		* Similar to above, only instead of looking for
1458		* tags it looks for PHP and JavaScript commands
1459		* that are disallowed.  Rather than removing the
1460		* code, it simply converts the parenthesis to entities
1461		* rendering the code un-executable.
1462		*
1463		* For example:	eval('some code')
1464		* Becomes:		eval&#40;'some code'&#41;
1465		*
1466		*/
1467		$str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);
1468
1469		/*
1470		* Final clean up
1471		*
1472		* This adds a bit of extra precaution in case
1473		* something got through the above filters
1474		*
1475		*/
1476		foreach ($never_allowed_str as $key => $val) {
1477			$str = str_replace($key, $val, $str);   
1478		}
1479
1480		foreach ($never_allowed_regex as $key => $val) {
1481			$str = preg_replace("#".$key."#i", $val, $str);
1482		}
1483
1484		/*
1485		*  Images are Handled in a Special Way
1486		*  - Essentially, we want to know that after all of the character conversion is done whether
1487		*  any unwanted, likely XSS, code was found.  If not, we return TRUE, as the image is clean.
1488		*  However, if the string post-conversion does not matched the string post-removal of XSS,
1489		*  then it fails, as there was unwanted XSS code found and removed/changed during processing.
1490		*/
1491
1492		if ($is_image === TRUE) {
1493			if ($str == $converted_string) {
1494				return TRUE;
1495			} else {
1496				return FALSE;
1497			}
1498		}
1499
1500		return $str;
1501	}
1502	
1503	/**
1504	 * Simple variable dump
1505	 *
1506	 * @param mixed $var 
1507	 * @return void
1508	 * @author j4kp07
1509	 */
1510	function dump($var = NULL)
1511	{
1512		echo '<pre>';
1513		print_r($var);
1514		exit();
1515	}
1516	
1517	/**
1518	 * var_dump for php debugging
1519	 * 
1520	 * Source: http://us2.php.net/manual/en/function.var-dump.php
1521	 *
1522	 * @author j4kp07
1523	 */
1524	function _vardump(&$var, $info = FALSE)
1525	{
1526	    $scope = false;
1527	    $prefix = 'unique';
1528	    $suffix = 'value';
1529
1530	    if($scope) $vals = $scope;
1531	    else $vals = $GLOBALS;
1532
1533	    $old = $var;
1534	    $var = $new = $prefix.rand().$suffix; $vname = FALSE;
1535	    foreach($vals as $key => $val) if($val === $new) $vname = $key;
1536	    $var = $old;
1537
1538	    echo "<pre style='margin: 0px 0px 10px 0px; display: block; background: white; color: black; font-family: Verdana; border: 1px solid #cccccc; padding: 5px; font-size: 10px; line-height: 13px;'>";
1539	    if($info != FALSE) echo "<b style='color: red;'>$info:</b><br>";
1540	    do_dump($var, '$'.$vname);
1541	    echo "</pre>";
1542		exit();
1543	}
1544	
1545	/**
1546	 * Better UI than print_r or var_dump
1547	 *
1548	 * Source: http://us2.php.net/manual/en/function.var-dump.php
1549	 * 
1550	 * @author j4kp07
1551	 */
1552	function do_dump(&$var, $var_name = NULL, $indent = NULL, $reference = NULL)
1553	{
1554	    $do_dump_indent = "<span style='color:#eeeeee;'>|</span> &nbsp;&nbsp; ";
1555	    $reference = $reference.$var_name;
1556	    $keyvar = 'the_do_dump_recursion_protection_scheme'; $keyname = 'referenced_object_name';
1557
1558	    if (is_array($var) && isset($var[$keyvar]))
1559	    {
1560	        $real_var = &$var[$keyvar];
1561	        $real_name = &$var[$keyname];
1562	        $type = ucfirst(gettype($real_var));
1563	        echo "$indent$var_name <span style='color:#a2a2a2'>$type</span> = <span style='color:#e87800;'>&amp;$real_name</span><br>";
1564	    }
1565	    else
1566	    {
1567	        $var = array($keyvar => $var, $keyname => $reference);
1568	        $avar = &$var[$keyvar];
1569
1570	        $type = ucfirst(gettype($avar));
1571	        if($type == "String") $type_color = "<span style='color:green'>";
1572	        elseif($type == "Integer") $type_color = "<span style='color:red'>";
1573	        elseif($type == "Double"){ $type_color = "<span style='color:#0099c5'>"; $type = "Float"; }
1574	        elseif($type == "Boolean") $type_color = "<span style='color:#92008d'>";
1575	        elseif($type == "NULL") $type_color = "<span style='color:black'>";
1576
1577	        if(is_array($avar))
1578	        {
1579	            $count = count($avar);
1580	            echo "$indent" . ($var_name ? "$var_name => ":"") . "<span style='color:#a2a2a2'>$type ($count)</span><br>$indent(<br>";
1581	            $keys = array_keys($avar);
1582	            foreach($keys as $name)
1583	            {
1584	                $value = &$avar[$name];
1585	                do_dump($value, "['$name']", $indent.$do_dump_indent, $reference);
1586	            }
1587	            echo "$indent)<br>";
1588	        }
1589	        elseif(is_object($avar))
1590	        {
1591	            echo "$indent$var_name <span style='color:#a2a2a2'>$type</span><br>$indent(<br>";
1592	            foreach($avar as $name=>$value) do_dump($value, "$name", $indent.$do_dump_indent, $reference);
1593	            echo "$indent)<br>";
1594	        }
1595	        elseif(is_int($avar)) echo "$indent$var_name = <span style='color:#a2a2a2'>$type(".strlen($avar).")</span> $type_color$avar</span><br>";
1596	        elseif(is_string($avar)) echo "$indent$var_name = <span style='color:#a2a2a2'>$type(".strlen($avar).")</span> $type_color\"$avar\"</span><br>";
1597	        elseif(is_float($avar)) echo "$indent$var_name = <span style='color:#a2a2a2'>$type(".strlen($avar).")</span> $type_color$avar</span><br>";
1598	        elseif(is_bool($avar)) echo "$indent$var_name = <span style='color:#a2a2a2'>$type(".strlen($avar).")</span> $type_color".($avar == 1 ? "TRUE":"FALSE")."</span><br>";
1599	        elseif(is_null($avar)) echo "$indent$var_name = <span style='color:#a2a2a2'>$type(".strlen($avar).")</span> {$type_color}NULL</span><br>";
1600	        else echo "$indent$var_name = <span style='color:#a2a2a2'>$type(".strlen($avar).")</span> $avar<br>";
1601
1602	        $var = $var[$keyvar];
1603	    }
1604	}