<?php
/* daCode http://www.dacode.org/
 * src/phplib/utils.php3
 * $Id: utils.php3,v 1.88 2001/07/21 21:28:45 penso Exp $
 *
 * Will contain all usefull functions that don't fit somewhere else
 *
 * Depends: Config Db
*/

Class Utils {
	var $db;

	Function Utils() {
		$this->db = LoadClass('Db');
		$this->ip_start();
	}

	/*
	 * We set up the right REMOTE_ADDR and right HTTP_HOST
	 */
	Function ip_start() {
		global $REMOTE_ADDR,$HTTP_X_FORWARDED_FOR,$config;
		global $HTTP_X_HOST, $HTTP_HOST;

		/*  Looks like we have a proxy. We try to get the real client IP.
		 *  We don't pay any attention to internal network IP as we don't
		 *  care. We want to real Internet IP of the remote client.
		 */
		if (!empty($HTTP_X_FORWARDED_FOR) &&
			$HTTP_X_FORWARDED_FOR != "unknown") {
			$ip_tmp = array();
			$ip_tmp = split(",",$HTTP_X_FORWARDED_FOR);

			while ($cur = current($ip_tmp)) {
				// We remove the space added by split().
				$cur = ereg_replace("^ ", "", $cur);
				/*  
				 *  We use substr to not use ereg which is apparently
				 *  slower 
				 */
				if (substr($cur,0,8) == "192.168." || 
					substr($cur,0,3) == "10." ||
					$cur == "unknown") {
					next($ip_tmp);
					continue;
				}
				
				// We remove 172.16/12
				for ($i=16;$i<=31;$i++) {
					if (substr($cur,0,7) == "172.$i.") {
						next($ip_tmp);
						continue 2;
					}
				}
					
				$config->REMOTE_ADDR = $cur;
						
				next($ip_tmp);
			}

			if (empty($config->REMOTE_ADDR)) {
				$config->REMOTE_ADDR = $REMOTE_ADDR;
			}

		} else {

			$config->REMOTE_ADDR = $REMOTE_ADDR;

		}

		if (!empty($HTTP_X_HOST)) {
			$config->HTTP_HOST = $HTTP_X_HOST;
		} else {
			$config->HTTP_HOST = $HTTP_HOST;
		}

	}

	/*
	 * Return IP of the $REMOTE_ADDR or $HTTP_X_FORWARDED_FOR if it exists
	 */
	Function ip($i=0) {
		global $config;
		$ip=$config->REMOTE_ADDR;
		if ($i==1) {
			return $ip;
		} else {
			$i=explode(".",$ip);
			return sprintf("%02x%02x%02x%02x",$i[0],$i[1],$i[2],$i[3]);
		}
	}

	/*
	 * Function which takes a timestamp(14) as input and returns the date
	 * Thanks to mose mose@mose.com
	 */
	Function stamp2date ($t, $mode, $type=0) {
		global $LANG;
		if ($type == 0) {
			$timestamp = mktime(substr($t,8,2),substr($t,10,2),substr($t,12,2),
					substr($t,4,2),substr($t,6,2),substr($t,0,4));
		} elseif ($type == 1) {
			$timestamp = $t;
		} elseif ($type == 2) {
			$timestamp = time();
		}

		$dval   = date("w",$timestamp);
		$mval   = (int) date("m",$timestamp);
		$nval   = date("d",$timestamp);
		$Yval   = date("Y",$timestamp);
		$hval   = date("h",$timestamp);
		$Hval   = date("H",$timestamp);
		$Aval   = date("A",$timestamp);
		$ival   = date("i",$timestamp);

		$day = array(lecho("sunday"),lecho("monday"),lecho("tuesday"),
				lecho("wednesday"),lecho("thursday"),lecho("friday"),
				lecho("saturday"));

		$month = array('',lecho("january"),lecho("february"),
				lecho("march"),lecho("april"),lecho("may"),lecho("june"),
				lecho("july"),lecho("august"), lecho("september"),
				lecho("october"),lecho("november"),lecho("december"));

		switch ($mode) {
		case "long":
			if ($LANG=="fr") {
				$out = ucfirst($day[$dval]). " $nval ".
				  ucfirst($month[$mval]) . " à $Hval:$ival";
			} else {
				$out = ucfirst($day[$dval]). " ".
				  ucfirst($month[$mval]) . " $nval, @$hval:$ival$Aval";
			}
			break;
		case "longwyear":
			if ($LANG=="fr") {
				$out = ucfirst($day[$dval]). " $nval ".
				  ucfirst($month[$mval]) . " $Yval à $Hval:$ival";
			} else {
				$out = ucfirst($day[$dval]). " ".
				  ucfirst($month[$mval]) . " $nval $Yval, @$hval:$ival$Aval";
			}
			break;
		case "short":
			if ($LANG=="fr") {
				$out = ucfirst($day[$dval]). " $nval ".
				  ucfirst($month[$mval]);
			} else {
				$out = ucfirst($day[$dval]). " ".
				  ucfirst($month[$mval]) . " $nval";
			}
			break;
		case "shortwyear":
			if ($LANG=="fr") {
				$out = ucfirst($day[$dval]). " $nval ".
				  ucfirst($month[$mval])." $Yval";
			} else {
				$out = ucfirst($day[$dval]). " ".
				  ucfirst($month[$mval]) . " $nval $Yval";
			}
			break;
		}

		return $out;
	}

	/*
	 * Function which takes a timestamp(14) as input and returns the time
	 * Thanks to mose mose@mose.com
	 */
	Function stamp2time ($t, $mode) {
		global $LANG;
		$timestamp = mktime(substr($t,8,2),substr($t,10,2),substr($t,12,2),
				substr($t,4,2),substr($t,6,2),substr($t,0,4));

		$hval   = date("h",$timestamp);
		$Hval   = date("H",$timestamp);
		$Aval   = date("A",$timestamp);
		$ival   = date("i",$timestamp);

		switch ($mode) {
			case "long":
				$out =  substr($t,8,2) . ":" . substr($t,10,2). ":" .
						substr($t,12,2);
				break;
			case "short":
				if ($LANG=="fr") {
					$out = "$Hval:$ival";
				} else {
					$out = "$hval:$ival$Aval";
				}
				break;
		}
		return $out;
	}

	/*
	 * This returns the time elapsed between two timestamps.
	 * "1, 10:20" means one day, ten hours, twenty minutes.
	 */
	Function interval($t1,$t2) {
		if ($t1>$t2) {
			return $this->interval($t2,$t1);
		}
		ereg("^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})",
			$t1, $r1);
		ereg("^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})",
			$t2, $r2);
		$d = date("U", gmmktime($r2[4],$r2[5],$r2[6],$r2[2],$r2[3],$r2[1]) -
				gmmktime($r1[4],$r1[5],$r1[6],$r1[2],$r1[3],$r1[1]))
			/60;
		$min = $d%60 ;  $d -= $min ;  $d /= 60;
		$hour = $d%24 ; $d -= $hour ; $d /= 24;
		return floor($d).", $hour:$min";
	}

	/*
	 * Returns random caracter
	 */
	Function makerand($nb=8) {
		mt_srand((double)microtime()*1000000);
		$r="";
		$r1=array(48,65,97);
		$r2=array(57,90,122);
		for($i=1; $i<=$nb; $i++) {
			$j=mt_rand(0,2);
			$r.=sprintf("%c",mt_rand($r1[$j],$r2[$j]));
		}
		return $r;
	}

	/* 
	 * Create new ipsession and returns it
	 */
	Function make_ipsession() {
		global $config;
		$idsession = $this->makerand(20);
		$sqlc_q = "INSERT INTO ".$config->tables['ip_sessions'].
			" (id,ip) VALUES ('".addslashes($idsession).
			"','".addslashes($this->ip())."')";
		$ret = $this->db->query($sqlc_q);
		if (!$ret) {
			echo "<!-- SQL failed: ".$this->db->error()." -->\n";
			exit;
		}
		return $idsession;
	}

	/* 
	 * Check ipsession
	 */
	Function check_ipsession($idsession="") {
		global $config;
		if (empty($idsession)) {
			echo "Something is wrong ...<BR>\n";
			exit;
		}
		$sqlc_q = "SELECT FROM ".$config->tables['ip_sessions'].
			" WHERE ip='".addslashes($this->ip())."' AND id='".
			addslashes($idsession)."'";
		$ret = $this->db->query($sqlc_q);
		if (!$ret) {
			echo "<!-- SQL failed: ".$this->db->error()." -->\n";
			exit;
		}
		if ($this->db->num_rows() >= 1) {
			return 1;
		} else {
			return 0;
		}
		$this->db->free();
	}

	/*
	 * Change accent to visible thing for WAP
	 */
	Function spec_chars($text) {

		for ($i = 161; $i < 255; $i++) {
			$text = str_replace(chr($i), "&#$i;", $text);
		}

		return $text;
	}

	/* 
	 * Create directories recursively
	 */
	Function createdir ($dir="",$mode=0755) {
		if (empty($dir)) {
			return 0;
		}
		if (file_exists($dir) &&
			is_dir($dir)) {
			return 1;
		}

		$dir_tmp = split("/", $dir);
		if (gettype($dir_tmp) != "array") {
			return 0;
		}
		$globaldir = (ereg("^/", $dir) ? "" : ".");
		while(list($key,$val) = each ($dir_tmp)) {
			if (!empty($val)) {
				$globaldir .= "/".$val;
				if (file_exists($globaldir) && 
					is_dir($globaldir)) {
					continue;
				} elseif (!mkdir ($globaldir, $mode)) {
					return 0;
				}
			}
		}
		return 1;
	}

	/* 
	 * Define the getcwd function, for compatibility with PHP 3
	 */
	Function getcwd () {
		if (function_exists(getcwd)) {
			return getcwd();
		}
		$pwd = getenv("PATH_TRANSLATED");
		return dirname($pwd);
	}

	/*
	 * Define the realpath function, for compatibility with PHP 3
	 */
	Function realpath ($path) {
		if (function_exists('realpath')) {
			return realpath($path);
		}
		$dir = dirname($path);
		$old_cwd = $this->getcwd();
		if (!chdir($dir)) {
			return;
		}
		$result = $this->getcwd();
		chdir($old_cwd);
		return $result;
	}

	/* 
	 * Write text to a file using a temporary file to avoid
	 * concurrent writings.
	 */
	Function write_file ($file,$text="") {
		global $config;
		$dir = dirname($file);
		if (!$this->createdir($dir)) {
			exit;
		}
		//  The realpath function can be called only after
		//  directory being created.
		$dir = $this->realpath($dir."/foo");
		$tempfile = tempnam($dir, "write");
		$fpwrite = @fopen($tempfile, 'w');
		if($fpwrite) {
			$bytes_written = fputs($fpwrite,$text);
			fclose($fpwrite);
			// the rename function does not work across filesystems
			if ($bytes_written == strlen($text)) {
				copy($tempfile,$file);
			} else {
				$config->nosave = 1;
			}
			unlink($tempfile);
		} else {
			//   Maybe SAFE MODE is activated
			//   In this case, write directly to file
			$fpwrite = @fopen($file, 'w');
			if(!$fpwrite) {
				exit;
			}
			$bytes_written = fputs($fpwrite,$text);
			fclose($fpwrite);
			if ($bytes_written != strlen($text)) {
				//   Something wrong happened, this file is
				//   corrupted and then removed
				@unlink($file);
				$config->nosave = 1;
			}
		}
	}

	/*
	 * Returns the timestamp of the news
	 */
	Function gettimestampnews($news_id) {
		global $config;

		$sqlc_q = "SELECT timestamp FROM ".$config->tables['news'].
			" WHERE id='".addslashes($news_id)."'";
		$ret = $this->db->query($sqlc_q);
		if (!$ret) {
			echo "<!-- SQL failed: ".$this->db->error()." -->\n";
			exit;
		}
		$row = $this->db->fetch_array();
		$this->db->free();
		if (ereg("^([0-9]{4})([0-9]{2})([0-9]{2})", $row[0], $res)) {
			return array($res[1],$res[2],$res[3],$news_id);
		}
	}

	/*
	 * Returns 1 if actual load is higher than a level which is configured in
	 * config.php3
	 * else returns 0
	 */
	Function loadishigh() {
		global $config;
		$loadtempo = file("/proc/loadavg");
		$loadtempo[0] = ereg("^([^ ]+)",$loadtempo[0], $regs);
		if ($regs[1] > $config->highload) {
			return 1;
		} else {
			return 0;
		}
	}

	/*
	 * Returns the actual load of the server
	 */
	Function loadis() {
		global $config;
		$loadtempo = file("/proc/loadavg");
		$loadtempo[0] = ereg("^([^ ]+)",$loadtempo[0], $regs);
		return $regs[1];
	}

	/*
	 * Compare two arrays and return true if they are equal.
	 * PHP3 does not handle compar. of objects.
	 */
	Function cmp_array($table1,$table2) {
		if (!is_array($table1) || !is_array($table2))
			return 0;

		reset($table1);
		while(list($key,$value)=each($table1)) {
			if (is_array($value) || is_array($table2[$key])) {
				if (!cmp_array($value, $table2[$key]))
					return 0;
			} elseif ($table2[$key] != $value) {
				return 0;
			}
		}
		reset($table2);
		while(list($key,$value)=each($table2)) {
			if (is_array($value) || is_array($table1[$key])) {
				if (!cmp_array($value, $table1[$key]))
					return 0;
			} elseif ($table1[$key] != $value) {
				return 0;
			}
		}
		return 1;
	}

	/*
	 * Returns the html <select> with the list of a topics
	 */
	Function make_topics_button() {
		global $config;
		$button = "<select name='topic'>\n".
			'<option value="-1" selected> '.lecho("All")." \n";

		$sqlc_q = "SELECT id,topic FROM ".$config->tables['topics'] ." ORDER BY topic";
		$ret = $this->db->query($sqlc_q);
		if (!$ret) return "Query wrong : ".$sqlc_q;
		while($topics_tmp=$this->db->fetch_array()) {
			$button .="<option value='".$topics_tmp[0]."'>".$topics_tmp[1]."\n";
		}
		$this->db->free();

		$button .= "</select>\n";
		return $button;
	}

	/*
	 * Returns the html <select> with the list of a sections
	 */
	Function make_sections_button() {
		global $config;
		$button = "<select name='section'>\n".
			'<option value="-1" selected> '.lecho("All")." \n";

		$sqlc_q = "SELECT id,section FROM ".$config->tables['sections'] ." ORDER BY section";
		$ret = $this->db->query($sqlc_q);
		if (!$ret) return "Query wrong : ".$sqlc_q;
		while ($sections_tmp=$this->db->fetch_array()) {
			$button .= "<option value='".$sections_tmp[0]."'>".$sections_tmp[1]."\n";
		}
		$this->db->free();

		$button .= "</select>\n";
		return $button;
	}

	/*
	 *  Escape unauthaurized tags
	 */
	Function htmlspecial_board($text) {
		global $config;

		$htmlright = htmlspecialchars($text);
		$newhtml = $htmlleft = '';
		if ($config->valid_tags_board) {
			$regexptag = '&lt;(' .
				join('|',$config->valid_tags_board) .
				'|/' .
				join('|/',$config->valid_tags_board) .
				')&gt;(.*)';
			$size = 0;
			//   Cut string into pieces
			while (eregi($regexptag, $htmlright, $regs)) {
				$thetag = strtoupper($regs[1]);
				$prefix = $htmlleft.substr($htmlright,0,-strlen($regs[0]));
				if ($thetag == '/'.$tag[$size]) {
					$htmlleft = $before[$size].
						"<$tag[$size]>$prefix<$thetag>";
					$size--;
				} else {
					$size++;
					$before[$size] = $prefix;
					$tag[$size] = $thetag;
					$htmlleft = "";
				}
				$htmlright = $regs[2];
			}
			//   Rebuild text
			for ($i=1 ; $i<=$size ; $i++) {
				$newhtml .= "$before[$i]&lt;$tag[$i]&gt;";
			}
		}
		$newhtml .= $htmlleft.$htmlright;

		$newhtml = ereg_replace(
					"((ftp|https?):\/\/[^ \"\>\<\)]+)",
					"<a href=\"\\0\"><b>[url]</b></a>",$newhtml);
		return $newhtml;
	}

	/*
	 *  Escape unauthaurized tags
	 */
	Function htmlspecial($text,$url_conv="0") {
		global $config;

		$htmlright = htmlspecialchars($text);
		$newhtml = $htmlleft = '';
		if ($config->valid_tags) {
			$regexptag = '&lt;(' .
				join('|',$config->valid_tags) .
				'|/' .
				join('|/',$config->valid_tags) .
				')&gt;(.*)';
			$size = 0;
			//   Cut string into pieces
			while (eregi($regexptag, $htmlright, $regs)) {
				$thetag = strtoupper($regs[1]);
				$prefix = $htmlleft.substr($htmlright,0,-strlen($regs[0]));
				if ($thetag == '/'.$tag[$size]) {
					$htmlleft = $before[$size].
						"<$tag[$size]>$prefix<$thetag>";
					$size--;
				} else {
					$size++;
					$before[$size] = $prefix;
					$tag[$size] = $thetag;
					$htmlleft = "";
				}
				$htmlright = $regs[2];
			}
			//   Rebuild text
			for ($i=1 ; $i<=$size ; $i++) {
				$newhtml .= "$before[$i]&lt;$tag[$i]&gt;";
			}
		}
		$newhtml .= $htmlleft.$htmlright;

		//   Additionnally replace URLs by links
		if ($url_conv) {
			$newhtml = ereg_replace(
				"((ftp|https?)://(([[:alnum:]]|[[:punct:]]){1,40})([[:alnum:]]|[[:punct:]])*)",
				"<a href=\"\\0\">\\3</a>",
				$newhtml);
		}
			

		return $newhtml;
	}

	/*
	 * Function to encrypt password so we can change the encrypt method if
	 * we need to.  
	 * Returns encrypted password if one argument.
	 * Returns 1 if 2 arguments and they match
	 * Returns 0 if 2 arguments and they don't match
 	 */
	Function crypt_dacode($passwd,$encrypted_password="") {

		if ($encrypted_password=="") {
			return crypt($passwd,$this->makerand("2"));
		} else {
			if ($encrypted_password == crypt($passwd,$encrypted_password)) {
				return 1;
			} else {
				return 0;
			}
		}
	}

	/*
	 * Function to send a mail.
	 */
	Function send_email($to="",$subject="",$message="") {
		global $config;
		if ($to == "" || $subject == "" || $message == "") {
			return 1;
		}

		$h = "From: ".$config->mailadmin."\nReply-To: ".$config->mailadmin.
			"\nX-Mailer: daCode ".$config->version;

		if ($config->mail_login != "" &&
			$config->mail_password != "") {
			$to = urlencode($to);
			$subject=urlencode($subject);
			$message=urlencode($message);
			$l=urlencode($config->mail_login);
			$p=urlencode($config->mail_password);
			$h = urlencode($h);

			$fp = @fopen("http://m.dacode.org/?login=$l&password=$p&to=$to&subject=$subject&message=$message&h=$h", "r");
			if (!$fp) {
				return 0;
			}
			$response = fread($fp, 256);
			fclose($fp);
			if (substr($response, 0, 2) != 'ok') {
				return 0;
			}
		} else {
			mail($to,$subject,$message,$h);
		}
		return 1;
	}

	/*
	 * Make sure there is no '<' sign in text
	 */
	Function html_safe($var) {
		if (is_array($var)) {
			reset($var);
			while (list($key,$val) = each($var)) {
				if (strstr($val, '<')) {
					return 0;
				}
			}
		} else {
			if (strstr($var, '<')) {
				return 0;
			}
		}
		return 1;
	}
}

?>
