Location: PHPKode > projects > XMail Log Archiver > xmlogarch.d/xmlogarch_funcs.php
<?php
/*
	 License
    XMail Log Archiver
	 http://xmlogarch.sourceforge.net
    Copyright (C) 2006 Bryn Mosher

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License Version 2 as
	 published by the Free Software Foundation.

    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 contact , write to 
	 hide@address.com
	 - or -
	 Free Software Foundation, Inc.
	 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#
# PHP < 5 versions of PHP 5 functions
# see comment at the end of this file for a complete list of functions to watch out for

#
# This implements scandir() for those this PHP < 5
if ( !function_exists( "scandir" ) ) {
	function scandir ( $directory, $sorting_order = 0 ) { # note that the context option is not implemented
		# sorting order can be true or false (true for descending alpha order )
		$retVal = FALSE;
		if ( $opDir = opendir( $directory ) ) {
			while ( ( $file = readdir( $opDir ) ) !==  FALSE ) {
				$retVal[] = $file;
			}
			if ( $sorting_order ) {
				rsort( $retVal );
			} else {
				sort( $retVal );
			}
		}
		return $retVal;
	}
}

#
# This implements array_combine() for those this PHP < 5
if ( !function_exists( "array_combine" ) ) {
	function array_combine ( $keys, $values ) {
		$retVal = false;
		if ( is_array( $keys ) ) {
			if ( is_array( $values ) ) {
				if ( count( $keys ) == count( $values ) ) {
					$keyNames = array_values( $keys );
					$keyVals = array_values( $values );
					$keepUp = 0;
					while ( $keepUp < count( $keys ) ) {
						$thiskey = $keyNames[$keepUp];
						$retVal[$thiskey] = $keyVals[$keepUp];
						$keepUp++;
					}
				} else {
					debug_backtrace();
					$trace = debug_backtrace();
					$log = " array_combine(): Both parameters should have equal number of elements in " . $trace[0]["file"] . " on line " . $trace[0]["line"] . " triggered";
					trigger_error( $log, E_USER_WARNING );
				}
			} else {
				debug_backtrace();
				$trace = debug_backtrace();
				$log = "array_combine() expects parameter 2 to be array, " . gettype( $keys ) . " given in " . $trace[0]["file"] . " on line " . $trace[0]["line"] . " triggered";
				trigger_error( $log, E_USER_WARNING );
			}
		} else {
			debug_backtrace();
			$trace = debug_backtrace();
			$log = "array_combine() expects parameter 1 to be array, " . gettype( $keys ) . " given in " . $trace[0]["file"] . " on line " . $trace[0]["line"] . " triggered";
			trigger_error( $log, E_USER_WARNING );
		}
		return $retVal;
	}
}

#
# Now that compatibility is out of the way, we can make our functions

function binEncDec ( $toVert ) { //binary encoded decimal modified
	$cal = str_split( $toVert, 1 );
	foreach( $cal as $chr ) {
		$retVal .= str_pad( ord($chr), 3, "0", STR_PAD_LEFT);
	}
	return trim($retVal);
}

function cmdArgs () {
	# each of these is an array of ( code to execute, usage, help text, required )
	$retVal = array(
		"-a" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$allReps = listReports( $GLOBALS["repModsLoc"], TRUE, TRUE );
			foreach ( $allReps as $oRep ) {
				$GLOBALS[$oRep . "Report"] = TRUE;
			}',
				"[-a|--allreports]",
				"Report Directive. Run all available reports. Individual reoprts may be enabled or disabled by passing further report directives after passing this option to customize reporting on the command line." ),
		"-c" => array( '# this is set at runtime
			# this is here just for help text',
				"(-c|--conf)",
				"Specify a location to load the initial configuration file from. These settings may be overridden by options passed at runtime. The original configuration file is used as default settings.",
				"file" ),
		"-d" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["showDots"] = TRUE;',
				"[-d|--dots]",
				"Prints a character for every few operations. See -da, -dp and -dpe for more information." ),
		"-da" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["showDots"] = TRUE;
			$GLOBALS["dotAll"] = TRUE;',
				"[-da|--dotall]",
				"Prints a character for every option in verbose mode. See -v, -dp and -dpe for more information." ),
		"-dp" => array( '
			if ( ( is_numeric( $_SERVER["argv"][$parmCount + 1] ) ) && ( $_SERVER["argv"][$parmCount + 1] >= 0 ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["dotsPer"] = $_SERVER["argv"][$parmCount + 1];
				if ( $GLOBALS["dotsPer"] > 0 ) {
					$GLOBALS["showDots"] = TRUE;
				} else {
					$GLOBALS["showDots"] = FALSE;
				}
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). Using value of " . $GLOBALS["dotsPer"] . ".", me );
			}',
				"(-dp|--dotsper)",
				"Specifies the number of operations to count per character displayed in verbose operations. A setting of zero (0) will disable dots. See -v, -da and -dpe for more information.",
				"count" ),
		"-dpe" => array( '
			if ( ( is_numeric( $_SERVER["argv"][$parmCount + 1] ) ) && ( $_SERVER["argv"][$parmCount + 1] >= 0 ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["dotsPerEntry"] = $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["showDots"] = TRUE;
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). Using value of " . $GLOBALS["dotsPer"] . ".", me );
			}',
				"(-dpe|--dotsperentry)",
				"Specifies a multiplier to -dp for very large operations such as reading individual log lines. See -v, -da and -dp for more information.",
				"multiplier" ),
		"-gp" => array( '
			if ( isset( $_SERVER["argv"][$parmCount + 1] ) ) {
				$yourPass = genPassCr( $_SERVER["argv"][$parmCount + 1] );
				logIt( "The password to place in the config for XMail is: " . $yourPass . PHP_EOL, me );
				mex(0);
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). The password must contain text.", me );
				mex(0);
			}',
				"(-gp|--genpass)",
				"Generate encrypted XMail Server password to store in a config file for performing Server Status Reporting. Network characteristics of the machine the script is currently runing on and the XMail server settings are used to seed the encryption, so when either of these change the encrypted password in config files needs to be updated. When specifying an XMail server at runtime, please also provide a password with the -p option. The script will exit after the encrypted password is output. For more information see -p.",
				"password" ),
		"-h" => array( '# -h is used in cmdLine() as a switch example',
				"(-h|--help)",
				"Display help text and exit." ),
		"-l" => array( '
			if ( isset( $_SERVER["argv"][$parmCount + 1] ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["xmailLogin"] = trim( $_SERVER["argv"][$parmCount + 1] );
				$_SERVER["argv"][$parmCount + 1] = $_SERVER["argv"][$parmCount + 1];
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). The login name must contain text.", me );
			}',
				"(-l|--login)",
				"Uses provided XMail Server user name for performing Server Status Reporting.",
				"login-name" ),
		"-m" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["moveLogs"] = TRUE;',
				"[-m|--movelogs]",
				"Enable movement of stale logs if disabled in config file." ),
		"-mm" => array( '
			if ( ( is_numeric( $_SERVER["argv"][$parmCount + 1] ) ) && ( $_SERVER["argv"][$parmCount + 1] > 0 ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["maxMem"] = $_SERVER["argv"][$parmCount + 1];
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). Using value of " . $GLOBALS["maxMem"] . ".", me );
			}',
				"(-mm|--maxmem)",
				"Specify memory limit for PHP. The default is 32 Megabytes, but large and/or plentiful logs will require more or PHP exits with an error.",
				"memorylimit" ),
		"-n" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["noReports"] = TRUE;',
				"[-n|--noreports]",
				"Do not process any report modules. This may prevent archival depending on other passed or config file options." ),
		"-nl" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["toLogFile"] = FALSE;',
				"[-nl|--nolog]",
				"Do not write information to current xmlogarch-YYYYMMDDHHHH log file." ),
		"-p" => array( '
			if ( isset( $_SERVER["argv"][$parmCount + 1] ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . str_repeat( "*", strlen( $_SERVER["argv"][$parmCount + 1] ) );
				$GLOBALS["truePass"] = TRUE;
				$GLOBALS["xmailPass"] = trim( $_SERVER["argv"][$parmCount + 1] );
				$_SERVER["argv"][$parmCount + 1] = str_repeat( "*", strlen( $_SERVER["argv"][$parmCount + 1] ) );
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). The password must contain text.", me );
			}',
				"(-p|--pass)",
				"Uses provided XMail Server password for performing Server Status Reporting.",
				"xmailpassword" ),
		"-q" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["quiet"] = TRUE;',
				"[-q|--quiet]",
				"Do not print any output to the console. This will also disable -v. If other options are enabled, information may still be mailed or written to xmlogarch-YYYYMMDDHHHH log file." ),
		"-qs" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["quietSkip"] = TRUE;',
				"[-qs|--quietskip]",
				"Do not announce skipped report modules. This option does not change which reports will be run. Using a named report directive will also trigger this option. For more information, please see the report directives section." ),
		"--{reportdirective}" => array( '# this is set at runtime
			# this is here just for help text',
				"[--{reportdirective}]",
				"See the section about report directives below.." ),
		"-s" => array( '
			if ( ( is_numeric( $_SERVER["argv"][$parmCount + 1] ) ) && ( $_SERVER["argv"][$parmCount + 1] >= 0 ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["staleAge"] = $_SERVER["argv"][$parmCount + 1];
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). Using value of " . $GLOBALS["highScoreCount"] . ".", me );
			}',
				"(-s|--stale)",
				"Number of hours old a log must be before it is archived or reported on.",
				"hours" ),
		"-t" => array( '
			if ( ( is_numeric( $_SERVER["argv"][$parmCount + 1] ) ) && ( $_SERVER["argv"][$parmCount + 1] >= 0 ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["highScoreCount"] = $_SERVER["argv"][$parmCount + 1];
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). Using value of " . $GLOBALS["highScoreCount"] . ".", me );
			}',
				"(-t|--top)",
				"Number to High Score items to display in reports. A setting of zero (0) will disable High Scores. Not all reports calculate High Scores. Items listed in High Scores depend on the Report Module. See the individual Report Module for specific details of what will be shown.",
				"number" ),
		"-u" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["reportMemUse"] = TRUE;',
				"[-u|--memuse]",
				"Display memory usage during processing. Memory usage information is NOT written to the xmlogarch-YYYYMMDDHHHH log file. This option is for performance tuning and debugging." ),
		"-v" => array( '
			$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			$GLOBALS["verbose"] = TRUE;
			$GLOBALS["reportMemUse"] = TRUE;
			$GLOBALS["showDots"] = TRUE;',
				"[-v|--verbose]",
				"Verbose output enhances regular output by printing progress of file operations to the console as a series of characters. the number of characters per operation depend on other settings. This option also enables the -u option and like that option produces no logged output. Please see -u, -d -dp and -dpe for more information." ),
		"-xp" => array( '
			if ( ( is_numeric( $_SERVER["argv"][$parmCount + 1] ) ) && ( $_SERVER["argv"][$parmCount + 1] >= 0 ) ) {
				$GLOBALS["usedParms"][$parmCount] = $cmdParm . " " . $_SERVER["argv"][$parmCount + 1];
				$GLOBALS["xmailPort"] = $_SERVER["argv"][$parmCount + 1];
			} else {
				logIt( "Bad parameter passed to " . $cmdParm . " (" . $_SERVER["argv"][$parmCount + 1] . "). Using value of " . $GLOBALS["xmailPort"] . ".", me );
			}',
				"(-xp|--xmailport)",
				"Specifies the administrative port number for the XMail server. This is used for Server Status reporting.",
				"number"  ),
	);
	$retVal["--allreports"] = array( $retVal["-a"][0] );
	$retVal["--config"] = array( $retVal["-c"][0] );
	$retVal["--dots"] = array( $retVal["-d"][0] );
	$retVal["--dotall"] = array( $retVal["-da"][0] );
	$retVal["--dotsper"] = array( $retVal["-dp"][0] );
	$retVal["--dotsperentry"] = array( $retVal["-dpe"][0] );
	$retVal["--genpass"] = array( $retVal["-gp"][0] );
	$retVal["--help"] = array( $retVal["-h"][0] );
	$retVal["--login"] = array( $retVal["-l"][0] );
	$retVal["--movelogs"] = array( $retVal["-m"][0] );
	$retVal["--maxmem"] = array( $retVal["-mm"][0] );
	$retVal["--memuse"] = array( $retVal["-u"][0] );
	$retVal["--noreports"] = array( $retVal["-n"][0] );
	$retVal["--nolog"] = array( $retVal["-nl"][0] );
	$retVal["--pass"] = array( $retVal["-p"][0] );
	$retVal["--quiet"] = array( $retVal["-q"][0] );
	$retVal["--quietskip"] = array( $retVal["-qs"][0] );
	$retVal["--stale"] = array( $retVal["-s"][0] );
	$retVal["--top"] = array( $retVal["-t"][0] );
	$retVal["--verbose"] = array( $retVal["-v"][0] );
	$retVal["--xmailPort"] = array( $retVal["-xp"][0] );
	return $retVal;
}

function cmdLine () {
	$valid = cmdArgs();
	$parmCount = 0;
	$retVal = FALSE;
	foreach ( $_SERVER['argv'] as $cmdParm ) {
		switch ( $cmdParm ) { # for testing
			case "-h":
			case "--help":
				helpThem();
				mex( 0 );
				break;
		}
		$lowParm = strtolower( $cmdParm );
		if ( isset( $valid[$lowParm] ) ) {
			eval( $valid[$lowParm][0]);
		}
		#catch report directves
		if ( preg_match( "/\\-\\-?((no|only)?(\\S*)report(s)?)/i", $lowParm, $repParms ) ) {
			if ( !( strtolower( $repParms[count( $repParms ) - 1 ] ) == "s" ) ) { # not a report directive, it's another option
				if ( ( strtolower( $repParms[2] ) == "only" ) || ( strtolower( $repParms[2] ) == "" ) ) {
					$GLOBALS["onlyReport"][$repParms[3]] = $repParms[3];
					$otherReps = listReports( $GLOBALS["repModsLoc"], TRUE, TRUE );
					$GLOBALS["quietSkip"] = ( strtolower( $repParms[2] ) == "" ) ? TRUE : $GLOBALS["quietSkip"];
					foreach ( $otherReps as $oRep ) {
						$GLOBALS[$oRep . "Report"] = FALSE;
					}
				}
				$GLOBALS[strtolower( $repParms[3] ) . "Report"] = ( strtolower( $repParms[2] ) == "no" ) ? ( FALSE ) : ( TRUE );
				$GLOBALS["usedParms"][$parmCount] = $cmdParm;
			}
		}
		$parmCount++;
	}
	if ( count( $_SERVER["argc"] ) > 0 ) {
		$fullLine = "Command Line: '" . implode( " ", $_SERVER['argv'] ) . "'";
		$useLine = "Using Parameters: '" . implode( " ", $GLOBALS["usedParms"] ) . "'";
		$retVal = array( $fullLine, $useLine );
	}
	return $retVal;
}

function decEncBin ( $toVert ) {
	$cal = str_split( $toVert, 3 );
	$retVal = FALSE;
	foreach( $cal as $chr ) {
		$retVal .= chr( $chr );
	}
	return $retVal;
}

function dot ( $dots, $style = NULL, $dotAll = NULL, $dotsPer = NULL, $announce = TRUE ) {
	$retVal = FALSE;
	if ( $dotAll === NULL ) {
		$dotAll = $GLOBALS["dotAll"];
	}
	if ( $dotsPer === NULL ) {
		$dotsPer = $GLOBALS["dotsPer"];
	}
	if ( $dotsPer < 1 ) {
		$dotsPer = 1;
	}
	if ( $style === NULL ) {
		$style = "+";
	}
	if ( ( $dots == 1 ) && ( $announce ) ) {
		pIt( "(per " . $dotsPer . ") ", NULL, $GLOBALS["showDots"] );
		$retVal = TRUE;
	}
	$times = explode( ".", number_format( ( $dots / $dotsPer ), 6 ) );
	if ( ( $times[1] == 0 ) || ( $dotAll > 0 ) || ( $dots == 1 ) ) {
		pIt( $style, NULL, $GLOBALS["showDots"] );
		$retVal = TRUE;
	}
	return $retVal;
}

function genPassCr ( $pass ) {
	global $xmailServer, $encType, $encMode;
	$retVal = "";
	if ( function_exists( "mcrypt_encrypt" ) ) {
		$sec = md5( $xmailServer . gethostbyaddr( "127.0.0.1" ) );
		$mod = mcrypt_module_open( $encType, '', $encMode, '' );
		$max_key_size = mcrypt_enc_get_key_size( $mod );
		$sec = substr( $sec, 0, $max_key_size );
		$iv_size = mcrypt_get_iv_size( $encType, $encMode );
		$iv = mcrypt_create_iv( $iv_size, MCRYPT_RAND );
		$enc = mcrypt_encrypt( $encType, $sec, $pass, $encMode, $iv );
		$retVal = binEncDec( $enc );
	} else {
		mex( 40 );
	}
	return $retVal;
}

function genPassUcr ( $pass ) {
	$cpass = decEncBin( $pass );
	global $xmailServer, $encType, $encMode;
	$sec = md5( $xmailServer . gethostbyaddr( "127.0.0.1" ) );
	$mod = mcrypt_module_open( $encType, '', $encMode, '' );
	$max_key_size = mcrypt_enc_get_key_size( $mod );
	$sec = substr( $sec, 0, $max_key_size );
	$iv_size = mcrypt_get_iv_size( $encType, $encMode );
	$iv = mcrypt_create_iv( $iv_size, MCRYPT_RAND );
	$denc = trim( mcrypt_decrypt( $encType, $sec, $cpass, $encMode, $iv ) );
	return $denc;
}

function getElapsed ( $compTime, $negative = FALSE ) {
	global $begun;
	$retVal = 0;
	$dust = $negative ? $begun - $compTime : $compTime - $begun;
	$oneMin = 60;
	$oneHr = 60 * $oneMin;
	$oneDay = 24 * $oneHr;
	$hours = 0;
	$mins = 0;
	$days = 0;
	if ( $dust >= $oneDay ) {
		$days = $dust / $oneDay;
		$days = floor( $days );
		$dust = $dust - ( $days * $oneDay );
	} else {
		$days = 0;
	}
	if ( $dust >= $oneHr ) {
		$hours = $dust / $oneHr;
		$hours = floor( $hours );
		$dust = $dust - ( $hours * $oneHr );
	} else {
		$hours = 0;
	}
	if ( $dust >= $oneMin ) {
		$mins = $dust / $oneMin;
		$mins = floor( $mins );
		$dust = $dust - ( $mins * $oneMin );
	} else {
		$hours = 0;
	}
	$retVal = str_pad( $days, 2, "0", STR_PAD_LEFT ) . ":" . str_pad( $hours, 2, "0", STR_PAD_LEFT ) . ":" . str_pad( $mins, 2, "0", STR_PAD_LEFT ) . ":" . str_pad( $dust, 2, "0", STR_PAD_LEFT );
	return $retVal;
}

function getLogsToarch ( $logRoot, $staleAge = FALSE, $mask = FALSE ) {
	if ( $staleAge === FALSE ) {
		$staleAge = $GLOBALS["staleAge"];
	}
	$retVal = FALSE;
	$bestIfUsedby = ( $staleAge === -1 ) ? ( mktime() + mktime() ) : ( mktime() - ( _hour * $staleAge ) );
	$currLogs = scandir( $logRoot );
	$currSort = array();
	$grep = ( !$mask ) ? ( "/\\S*\\-[0-9]{12}/" ) : ( "/" . $mask . "\\-[0-9]{12}/i" );
	foreach ( $currLogs as $thisLog ) {
		if ( preg_match( $grep, $thisLog, $bob ) ) {
			if ( !is_dir( slashDir( $logRoot ) . $thisLog ) ) {
				if ( strlen( $thisLog ) > 2 ) {
					$thisStat = stat( slashDir( $logRoot ) . $thisLog );
					# Note: $thisStat[9] is mod time $thisStat[10] is creation time
					if ( $bestIfUsedby > $thisStat[9] ) {
						$currSort[$thisLog] = $thisStat[9] . $thisLog; // mod time
					}
					clearstatcache();
				}
			}
		}
	}
	asort( $currSort );
	$retVal = array_keys( $currSort );
	return $retVal;
}

function helpThem () {
	$valid = cmdArgs();
	$options = "Options:" . PHP_EOL;
	foreach ( $valid as $cArg ) {
		if ( $cArg[1] ) {
			$text = "";
			if ( $cArg[3] ) {
				$useLine .= " [" . $cArg[1] . " " . $cArg[3] . "]";
			} else {
				$useLine .= " " . $cArg[1];
			}
			$optage = str_replace( "|", ", ", $cArg[1] );
			$optage = str_replace( array( "(", ")" ) , "", $optage );
			$optage = "  " . str_replace( array( "[", "]" ) , "", $optage );
			if ( $cArg[2] ) {
				$text .= str_pad( $optage, 29, " ", STR_PAD_RIGHT );
				$firstLine = substr( $cArg[2], 0, strpos( wordwrap( $cArg[2], 50, PHP_EOL ) . PHP_EOL, PHP_EOL ) );
				$text .= $firstLine . PHP_EOL;
				$rest = str_replace( $firstLine, "",  $cArg[2] );
				if ( $cArg[3] ) {
					$rest .= " REQUIRED: " . $cArg[3] . PHP_EOL;
				}
				if ( !( trim( $rest ) == "" ) ) {
					$doc = trim( wordwrap( $rest, 49, PHP_EOL ) );
					$textExp = explode( PHP_EOL, $doc );
					foreach( $textExp as $key => $textLine ) {
						$text .= str_repeat( " " , 31 ) . $textLine . PHP_EOL ;
					}
				}
			} else {
				$text .= str_pad( $optage, 29, " ", STR_PAD_RIGHT );
				$text .= "No documentation written." . PHP_EOL;
			}
			$options .= trim( $text, PHP_EOL ) . PHP_EOL;
		}
	}
	if ( getenv("wpid") ) {
		if ( preg_match( "/win/i", $_SERVER["OS"] ) ) {
			print wordwrap( "CMD Wrapper Usage: xmlogarch.cmd" . $useLine . PHP_EOL, 78, PHP_EOL . "  " );
		} else {
			print wordwrap( "Bash Wrapper Usage: xmlogarch" . $useLine . PHP_EOL, 78, PHP_EOL . "  " );
		}
		$finale = wordwrap( "Alternate Usage: This script can also be run directly from a shell with the CLI version of PHP." . PHP_EOL, 78, PHP_EOL . "  " );
		$finale .= wordwrap( "PHP CLI Usage: php -f " . basename( $_SERVER['SCRIPT_NAME'] ) . " --" . $useLine . PHP_EOL, 78, PHP_EOL . "  " );
	} else {
		print wordwrap( "PHP CLI Usage: php -f " . basename( $_SERVER['SCRIPT_NAME'] ) . " --" . $useLine . PHP_EOL, 78, PHP_EOL . "  " );
		$finale = wordwrap( "Alternate Usage: This script can also be run with a bash wrapper called 'xmlogarch'." . PHP_EOL, 78, PHP_EOL . "  " );
		$finale .= wordwrap( "Bash Wrapper Usage: xmlogarch" . $useLine . PHP_EOL, 78, PHP_EOL . "  " );
	}
	$description = "Archive, report and/or zip XMail log files. All command line parameters and more oprions are available inside a config file. This is meant to be run by a scheduled cron job but may be run manually for testing and debugging. Please be aware that if you have anything that modifies, moves or removes log files specified in a configuration file, you must override the settings with command line options to avoid affecting your log files.";
	print wordwrap( $description, 78, PHP_EOL . "  " ) . PHP_EOL;
	print $options;
	$repDirectives = "Report Directives: There are three types of report directives - 'named' , 'only' and 'no'. 'Only' and 'no' are exactly what they seem. Using a 'no' report directive will skip the given report and using an 'only' directive will run only that report. The 'named' report is identical to running an 'only' report except that skipped reports are not announced (the -qs option).";
	$repDirectives .= " The format to specify a report directive is to start with the directive, add the report name and lastly add the word report. For example, the 'Zipped Log Files' (named 'zip') report can be skipped with the directive '--nozipreport'. The 'named' directive has no prefix, hence the term 'named'. So, running the 'Zipped Logged Files' report in 'named' mode would simply be '--zipreport'. The effects of the report directives are stackable as well. For example, you may specify report directives such as '--smtpreport --zipreport' to only run the 'SMTP Requests' and 'Zipped Log Files' reports without skipped reports.";
	print wordwrap( $repDirectives, 78, PHP_EOL . "  " ) . PHP_EOL;
	if ( $finale ) {
		print $finale;
	}
}

function highScores ( $allScores, $titles = array() ) {
	global $highScoreCount, $wrap, $wrapScores;
	if ( $highScoreCount < 1 ) {
		return NULL;
	}
	$retVal = FALSE;
	$repName = isset( $titles['report'] ) ? $titles['report'] . " " : "";
	memUse( "Generating " . $repName . "High Scores" );
	logIt( strtoupper( $repName ) . "HIGH SCORES:", _me, NULL, FALSE );
	if ( isset( $allScores['highScoreMethods'] ) ) {
		$methods = $allScores['highScoreMethods'];
		unset( $allScores['highScoreMethods'] );
	} else {
		$methods = array();
	}
	$altMess = FALSE;
	$allFields = array_keys( $allScores );
	foreach ( $allFields as $thisField ) {
		$thisMethod = isset( $methods[$thisField] ) ? $methods[$thisField] : "count";
		$curr = $allScores[$thisField];
		$themTotals = array();
		$currThem = array_unique( $curr );
		if ( count( $currThem ) >= 0 ) {
			$dotsPer = $GLOBALS["dotsPer"] * $GLOBALS["dotsPerEntry"];
			$dots = 0;
			$thisName = isset( $titles[$thisField] ) ? $titles[$thisField] : $thisField;
			switch( $thisMethod ) {
				case "age":
					pIt( "Calculating " . $thisName . " top " . $highScoreCount . " by age... ", NULL, $GLOBALS["showDots"]);
					asort( $currThem );
					foreach ( $currThem as $key => $them ) {
						$themTotals[$key] = getElapsed( $them, TRUE );
						$dots++;
						dot( $dots, "+", NULL, $dotsPer );
					}
					$pad = 16;
					pIt( "Done." . PHP_EOL, NULL, $GLOBALS["showDots"] );
					$topX = array_slice( $themTotals, 0, $highScoreCount );
					break;
				case "big":
					pIt( "Calculating " . $thisName . " top " . $highScoreCount . " by size... ", NULL, $GLOBALS["showDots"]);
					asort( $currThem );
					$currThem = array_slice( array_reverse( $currThem ), 0, $highScoreCount );
					foreach ( $currThem as $key => $them ) {
						$themTotals[$key] = sizeHumanReadable( $them );
						$dots++;
						dot( $dots, "+", NULL, $dotsPer );
					}
					$pad = 12;
					pIt( "Done." . PHP_EOL, NULL, $GLOBALS["showDots"] );
					$topX = $themTotals;
					break;
				case "count":
				default:
					pIt( "Calculating " . $thisName . " top " . $highScoreCount . " by count... ", NULL, $GLOBALS["showDots"]);
					foreach ( $currThem as $key => $them ) {
						$themTotals[$them] = count( array_keys( $curr, $them ) );
						$dots++;
						dot( $dots, "+", NULL, $dotsPer );
					}
					$pad = 8;
					pIt( "Done." . PHP_EOL, NULL, $GLOBALS["showDots"] );
					asort( $themTotals );
					$topX = array_slice( array_reverse( $themTotals ), 0, $highScoreCount );
					break;
			}
			$high = count( $topX );
			if ( !$altMess ) {
				$logOut = str_repeat( " ", 4 ) . $thisName . ": ";
			} else {
				$logOut = $altMess . PHP_EOL;
			}
			$topWhole = $logOut . PHP_EOL;
			logIt( $logOut, _me, NULL, FALSE, TRUE );
			memUse( "Generated " . $repName . $thisField . " High Scores" );
			$countOut = 0;
			$valCount = count( array_unique( $topX ) );
			$keyCount = count( array_unique( array_keys( $topX ) ) );
			if ( ( $valCount > 1 ) || ( $keyCount > 1 ) ) {
				foreach ( $topX as $value => $score ) {
					$countOut++;
					if ( ( $wrap ) || ( $wrapScores ) ) {
						$scoreOut = str_repeat( " ", 5 ) . str_pad( "#" . $countOut, 5, " ", STR_PAD_LEFT ) . " " . str_pad( "(" . trim( $score ) . ")", $pad, ".", STR_PAD_RIGHT ) . wordwrap( str_pad( " " . trim( $value ), 48 - $pad, ".", STR_PAD_LEFT ), 68 - $pad, PHP_EOL . str_repeat( " ", 12 + $pad ), 1 );
					} else {
						$scoreOut = str_repeat( " ", 5 ) . str_pad( "#" . $countOut, 5, " ", STR_PAD_LEFT ) . " " . str_pad( "(" . trim( $score ) . ")", $pad, ".", STR_PAD_RIGHT ) . str_pad( " " . trim( $value ), 48 - $pad, ".", STR_PAD_LEFT );
					}
					$topWhole .= $scoreOut . PHP_EOL;
					logIt( $scoreOut, _me, NULL, FALSE, TRUE );
				}
			} else {
				$sameness = array_unique( array_keys( $topX ) );
				if ( ( $wrap ) || ( $wrapScores ) ) {
					$scoreOut = str_repeat( " ", 11 ) . wordwrap( "All " . $thisName . " were the same (" . array_shift( $sameness ) . ").", 48, PHP_EOL . str_repeat( " ", 11 ) );
				} else {
					$scoreOut = str_repeat( " ", 11 ) . "All " . $thisName . " were the same (" . array_shift( $sameness ) . ").";
				}
				$topWhole .= $scoreOut . PHP_EOL;
				logIt( $scoreOut, _me, NULL, FALSE, TRUE );
			}
			$retVal .= $topWhole;
		}
	}
	return $retVal;
	memUse( "Finished generating " . $repName . "High Scores" );
}

function listReports ( $repModsLoc, $silent = FALSE, $forceReRead = FALSE ) {
	if ( ( isset( $GLOBALS["listReports"] ) ) && ( $forceReRead === FALSE ) ) {
		return $GLOBALS["listReports"];
	}
	$raw = scandir( $repModsLoc );
	sort( $raw );
	$modulesDir = implode( PHP_EOL, $raw );
	unset( $raw );
	$grep = "/([0-9a-z]{0,4}\\-)?([\\S^(\\.php)]*)\\.php/i";
	$none = FALSE;
	$retVal = FALSE;
	$modCount = 0;
	if ( preg_match_all( $grep, $modulesDir, $modGrep ) ) {
		$modules = array_combine( $modGrep[0], $modGrep[2] );
		foreach ( $modules as $modFile => $modName ) {
			$do = file_get_contents( slashDir( $repModsLoc ) . $modFile );
			if ( preg_match( "/\\<\\?php\\s[\\s\\S^(\\?\\>)]*\\?\\>/i", $do ) ) {
				if ( preg_match( "/function\\s*" . $modName . "Do\\s*?\\(\\s*?\\)/i", $do ) ) {
					$retArr[$modFile] = $modName;				
				} else {
					if ( $silent == TRUE ) {
						logIt ( "Report module '" . $modFile . "' has no '" . $modName . "Do()' function.", _me );
					}
				}
				$retArr[$modFile] = $modName;				
			} else {
				if ( $silent == TRUE ) {
					logIt ( "Report module '" . $modFile . "' has no php code tags.", _me );
				}
			}
		}
		if ( count( $retArr ) > 0 ) {
			$GLOBALS["listReports"] = $retArr;
			$retVal = $retArr;
		} else {
			$retVal= FALSE;
		}
	} else {
		$retVal= FALSE;
	}
	return $retVal;
}

function logIt ( $logText, $source = _me, $verbose = NULL, $toLogFile = NULL, $noTrim = FALSE ) {
	global $ourLogData, $logIsOpen;
	$logText = ( $noTrim ) ? $logText : trim( $logText );
	$source = trim( $source );
	if ( $verbose == NULL ) {
		$verbose = ( $GLOBALS['quiet'] ) ? ( 99 ) : ( TRUE );
	}
	if ( $toLogFile == NULL ) {
		$toLogFile = $GLOBALS['toLogFile'];
	}
	if ( preg_match( "/\\-\\- (end[\\s\\S^( \\-\\-)]*) \\-\\-/i", $logText, $report ) ) {
		$logText = "-- " . $report[1] . " --" . PHP_EOL;
	} else {
		if ( preg_match( "/\\-\\- (begin[\\s\\S^( \\-\\-)]*) \\-\\-/i", $logText, $report ) ) {
			if ( substr( $ourLogData, strlen( $ourLogData ) - 2, 2 ) == ( PHP_EOL . PHP_EOL ) ) {
				$logText = "-- " . $report[1] . " --";
			} else {
				$logText = PHP_EOL . "-- " . $report[1] . " --";
			}
		} else {
			if ( preg_match( "/\\-\\- ([\\s\\S^( \\-\\-)]*) \\-\\-/i", $logText, $report ) ) {
				if ( substr( $ourLogData, strlen( $ourLogData ) - 2, 2 ) == ( PHP_EOL . PHP_EOL ) ) {
					$logText = "-- " . $report[1] . " --" . PHP_EOL;
				} else {
					$logText = PHP_EOL . "-- " . $report[1] . " --" . PHP_EOL;
				}
			}
		}
	}
	$stamp = date( _dateFmt );
	if ( $toLogFile == TRUE ) {
		$ourLogLoc = findLog();
		$logFmt = "\"" . $stamp . "\"\t\"" . trim( $source ) . "\"\t\"" . trim( $logText ) . "\"" . PHP_EOL;
		if ( !$ourLog = fopen( $ourLogLoc, "a" ) ) {
			$logIsOpen = FALSE;
			mex( 3, $ourLogLoc );
		} else {
			$logIsOpen = TRUE;
			fwrite( $ourLog, $logFmt ); // 8 == FILE_APPEND
			fclose( $ourLog );
		}
	}
	if ( ( $verbose == -1 ) || ( $verbose === TRUE ) ){ //error flag is -1 *always print*
		$consOut = $GLOBALS['wrap'] ? wordwrap( $logText, 79, PHP_EOL, 1 ) : $logText;
		print $consOut . PHP_EOL;
	}
	$ourLogData .= $logText . PHP_EOL;
}

function mailReport () {
	global $sendMail, $ourLogData, $reportRecipient;
	if ( $sendMail == TRUE ) {
		logIt( "Using '" . ini_get("sendmail_path") . "' to send reports from " . ini_get( "sendmail_from" ) . " to " . $reportRecipient . "." );
		$headers = "Reply-To: hide@address.com\r\nX-Mailer: " . $_SERVER['SCRIPT_FILENAME'] . "\r\n";
		mail( $reportRecipient, "XMail Log Archiver for " . date( _dateFmt ), $ourLogData, $headers );
		$ended = mktime();
		memUse( "Ending Clean post mailing", FALSE, TRUE );
		$passed = getElapsed( $ended );
		logIt( "Amended Ended: " . date( _dateFmt, $ended ) . " (" . $ended . ") Elapsed: " . $passed );
	}
}

function memUse ( $text = NULL, $haveTo = FALSE, $finale = FALSE ) {
	global $reportMemUse, $peakMem, $peakText;
	if ( $haveTo || $reportMemUse ) {
		if ( !$text == NULL ) {
			$text = " (" . $text . ")";
		}
		$nowMem = round( ( ( memory_get_usage() / 1024 ) / 1024 ), 2 );
		if ( function_exists( "memory_get_usage" ) ) {
			logIt( " -> Current Memory Usage: " . $nowMem . "MB" . $text , _me, NULL, FALSE );
			if ( ( $peakMem < $nowMem ) || ( $finale ) ) {
				logIt( " --> Peak Memory Usage: " . $nowMem . "MB " . $text , _me, NULL, FALSE );
			}
		} else {
			logIt( " -> memory_get_usage() is not compiled in your version of PHP.", _me, NULL, FALSE );
	 	}
		$peakText = ( $peakMem < $nowMem ) ? $text : $peakText;
		$peakMem = ( $peakMem < $nowMem ) ? $nowMem : $peakMem;
	}
}

function pIt( $pri, $verbose = NULL, $showDots = FALSE ) {
	if ( $verbose === NULL ) {
		$verbose = $GLOBALS['verbose'];
	}
	if ( ( $verbose == -1 ) or ( $verbose == TRUE ) || ( $showDots == TRUE ) ){ //error flag is -1 *always print*
		print $pri;
	}
}

function runReports( $repModsLoc ) {
	if ( $GLOBALS["noReports"] == TRUE ) {
		logIt( "-- Reporting is turned off. --", _me );
		return TRUE;
	}
	memUse( "Starting report load" );
	if ( !is_dir( $repModsLoc ) ) {
		logIt( "Report module directory '" . $repModsLoc . "' is not a directory.", _me );
		return FALSE;
	}
	$modulesDir = implode( PHP_EOL, scandir( $repModsLoc ) );
	$grep = "/([0-9a-z^\\-]{0,4}\\-)?([\\S^(\\.php)]*)\\.php/i";
	$none = FALSE;
	$retVal = FALSE;
	$modTitle = FALSE;
	$modCount = 0;
	if ( $modules = listReports( $repModsLoc ) ) {
		foreach ( $modules as $modFile => $modName ) {
			if ( is_array( $GLOBALS['onlyReport'] ) ) {
				$GLOBALS[$modName . "Report"] = isset( $GLOBALS['onlyReport'][$modName] ) ? TRUE : $GLOBALS[$modName . "Report"];
			}
			if ( $GLOBALS[$modName . "Report"] == TRUE ) {
					include_once( slashDir( $repModsLoc ) . $modFile );
					memUse( "Included " . $modName . " report module" );
					if ( $modTitle === FALSE ) {
						$modTitle = strtoupper( $modName );
					}
					logIt ( "-- Begin " . $modTitle . " Report --", _me );
					memUse( "Executing " . $modName . "Do() report" );
					if ( function_exists( $modName . "Do" ) ) {
						call_user_func( $modName . "Do" );
					} else {
						logIt ( "Report module '" . $modFile . "' has no callable '" . $modName . "Do()' function.", _me );
					}
					$retVal = TRUE;
					$modCount++;
					memUse( "Ended " . $modName . "Do() report" );
					logIt ( "-- End " . $modTitle . " Report --", _me );
					$modTitle = FALSE;
			} else {
				if ( $GLOBALS["quietSkip"] == FALSE ) {
					logIt( "-- Report module '" . $modFile . "' skipped. \$" . $modName . "Report=" . var_export( $GLOBALS[$modName . "Report"], 1) . ". --", _me );
				}
			}
		}
	} else {
		$none= TRUE;
	}
	if ( ( $none ) || ( $modCount == 0 ) ) {
		logIt( "No report modules found in '" . $repModsLoc . "'.", _me );
		$retVal = FALSE;
	}
	memUse( "all reports complete" );
	return $retVal;
}

function sizeHumanReadable( $size, $precision = 2 ) {
	# modified version of php dot net at alan-smith dot no-ip dot com's
	# handy function at http://www.php.net/filesize
  $i=0;
  $iec = array( "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" );
  while ( ( $size / 1024 ) > 1 ) {
   $size = $size / 1024;
   $i++;
  }
  $precision = $precision > 0 ? $precision + 1 : $precision;
  $retVal = substr( $size, 0, strpos( $size, '.' ) + $precision ) . $iec[$i];
  return $retVal;
}

function slashDir ( $dir ) {
	# adds a slash to the end of a string
	$retVal = ( substr( $dir, strlen( $dir ) - 1, 1 )  == DIRECTORY_SEPARATOR ) ? $dir : $dir . DIRECTORY_SEPARATOR;
	return $retVal;
}

function slurpLog ( $logFile ) {
	$retVal = FALSE;
	if ( filesize( $logFile ) > 0 ) {
		$dirtyLog = trim( file_get_contents( $logFile ) );
		$dirtyLog = str_replace( PHP_EOL, "\n", $dirtyLog );
		$retVal = $dirtyLog;
	}
	return $retVal;
}

function sockOpts ( $socket ) {
	$opts=array(
		"SO_BROADCAST" => SO_BROADCAST,
		"SO_DONTROUTE" => SO_DONTROUTE,
		"SO_DEBUG" => SO_DEBUG,
		"SO_ERROR" => SO_ERROR,
		"SO_FREE" => SO_FREE,
		"SO_KEEPALIVE" => SO_KEEPALIVE,
		"SO_LINGER" => SO_LINGER,
		"SO_NOSERVER" => SO_NOSERVER,
		"SO_OOBINLINE" => SO_OOBINLINE,
		"SO_RCVBUF" => SO_RCVBUF,
		"SO_RCVLOWAT" => SO_RCVLOWAT,
		"SO_RCVTIMEO" => SO_RCVTIMEO,
		"SO_REUSEADDR" => SO_REUSEADDR,
		"SO_SNDBUF" => SO_SNDBUF,
		"SO_SNDLOWAT" => SO_SNDLOWAT,
		"SO_SNDTIMEO" => SO_SNDTIMEO,
		"SO_TYPE" => SO_TYPE
	);
	foreach ( $opts as $key => $val ) {
		$got = var_export( socket_get_option( $socket, SOL_SOCKET, $val ), 1 );
		if ( $got === FALSE ) {
			$got = "FALSE";
		} else {
			if ( $got === NULL ) {
				$got = "NULL";
			}
		}
		$opts[$key] = $got;
	}
	return $opts;
}

#
# Here is a list of PHP > 5 functions that would need PHP < 5 replacements
# Oddly enough, scandir() is missing from the official list.
#
/*
Arrays:
      array_combine() - Creates an array by using one array for keys and another for its values
      array_diff_uassoc() - Computes the difference of arrays with additional index check which is performed by a user supplied callback function
      array_udiff() - Computes the difference of arrays by using a callback function for data comparison
      array_udiff_assoc() - Computes the difference of arrays with additional index check. The data is compared by using a callback function
      array_udiff_uassoc() - Computes the difference of arrays with additional index check. The data is compared by using a callback function. The index check is done by a callback function also
      array_walk_recursive() - Apply a user function recursively to every member of an array
      array_uintersect_assoc() - Computes the intersection of arrays with additional index check. The data is compared by using a callback function
      array_uintersect_uassoc() - Computes the intersection of arrays with additional index check. Both the data and the indexes are compared by using a callback functions
      array_uintersect() - Computes the intersection of arrays. The data is compared by using a callback function 
InterBase:
      ibase_affected_rows() - Return the number of rows that were affected by the previous query
      ibase_backup() - Initiates a backup task in the service manager and returns immediately
      ibase_commit_ret() - Commit a transaction without closing it
      ibase_db_info() - Request statistics about a database
      ibase_drop_db() - Drops a database
      ibase_errcode() - Return an error code
      ibase_free_event_handler() - Cancels a registered event handler
      ibase_gen_id() - Increments the named generator and returns its new value
      ibase_maintain_db() - Execute a maintenance command on the database server
      ibase_name_result() - Assigns a name to a result set
      ibase_num_params() - Return the number of parameters in a prepared query
      ibase_param_info() - Return information about a parameter in a prepared query
      ibase_restore() - Initiates a restore task in the service manager and returns immediately
      ibase_rollback_ret() - Rollback transaction and retain the transaction context
      ibase_server_info() - Request statistics about a database
      ibase_service_attach() - Connect to the service manager
      ibase_service_detach() - Disconnect from the service manager
      ibase_set_event_handler() - Register a callback function to be called when events are posted
      ibase_wait_event() - Wait for an event to be posted by the database 
iconv:
      iconv_mime_decode() - Decodes a MIME header field
      iconv_mime_decode_headers() - Decodes multiple MIME header fields at once
      iconv_mime_encode() - Composes a MIME header field
      iconv_strlen() - Returns the character count of string
      iconv_strpos() - Finds position of first occurrence of a needle within a haystack
      iconv_strrpos() - Finds the last occurrence of a needle within the specified range of haystack
      iconv_substr() - Cut out part of a string 
Streams:
      stream_copy_to_stream() - Copies data from one stream to another
      stream_get_line() - Gets line from stream resource up to a given delimiter
      stream_socket_accept() - Accept a connection on a socket created by stream_socket_server()
      stream_socket_client() - Open Internet or Unix domain socket connection
      stream_socket_get_name() - Retrieve the name of the local or remote sockets
      stream_socket_recvfrom() - Receives data from a socket, connected or not
      stream_socket_sendto() - Sends a message to a socket, whether it is connected or not
      stream_socket_server() - Create an Internet or Unix domain server socket 
Date and time related:
      idate() - Format a local time/date as integer
      date_sunset() - Time of sunset for a given day and location
      date_sunrise() - Time of sunrise for a given day and location
      time_nanosleep() - Delay for a number of seconds and nano seconds 
Strings:
      str_split() - Convert a string to an array
      strpbrk() - Search a string for any of a set of characters
      substr_compare() - Binary safe optionally case insensitive comparison of two strings from an offset, up to length characters 
Other:
      convert_uudecode() - decode a uuencoded string
      convert_uuencode() - uuencode a string
      curl_copy_handle() - Copy a cURL handle along with all of it's preferences
      dba_key_split() - Splits a key in string representation into array representation
      dbase_get_header_info() - Get the header info of a dBase database
      dbx_fetch_row() - Fetches rows from a query-result that had the DBX_RESULT_UNBUFFERED flag set
      fbsql_set_password() - Change the password for a given user
      file_put_contents() - Write a string to a file
      ftp_alloc() - Allocates space for a file to be uploaded
      get_declared_interfaces() - Returns an array of all declared interfaces
      get_headers() - Fetches all the headers sent by the server in response to a HTTP request
      headers_list() - Returns a list of response headers sent (or ready to send)
      http_build_query() - Generate URL-encoded query string
      image_type_to_extension() - Get file extension for image-type returned by getimagesize(), exif_read_data(), exif_thumbnail(), exif_imagetype()
      imagefilter() - Applies Filter an image using a custom angle
      imap_getacl() - Gets the ACL for a given mailbox
      ldap_sasl_bind() - Bind to LDAP directory using SASL
      mb_list_encodings() - Returns an array of all supported encodings
      pcntl_getpriority() - Get the priority of any process
      pcntl_wait() - Waits on or returns the status of a forked child as defined by the waitpid() system call
      pg_version() - Returns an array with client, protocol and server version (when available)
      php_check_syntax() - Check the syntax of the specified file
      php_strip_whitespace() - Return source with stripped comments and whitespace
      proc_nice() - Change the priority of the current process
      pspell_config_data_dir() - Change location of language data files
      pspell_config_dict_dir() - Change location of the main word list
      setrawcookie() - Send a cookie with no url encoding of the value
      snmp_read_mib() - Reads and parses a MIB file into the active MIB tree
      sqlite_fetch_column_types() - Return an array of column types from a particular table 
*/

?>
Return current item: XMail Log Archiver