<?php
$module["functions"]["name"]="Functions Module";
$module["functions"]["ver"]="1.0.1";
/**
 * Project:   BeCast WebEngine - simple site engine
 * File:      /inc/functions.class.php
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * @link http://www.becast.at
 * @copyright 2010-2025 becast.at
 * @author Bernhard Jaud <bernhard at becast dot at>
 * @package BcWe core
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 * @version $Id: 03a0bb3ba3c616ebb75bfcaa4a10268a9f2574d8 $
*/
class functions {

	function my_inet_pton($ip)
	{
		if(function_exists('inet_pton'))
		{
			return @inet_pton($ip);
		}
		else
		{
			/**
			 * Replace inet_pton()
			 *
			 * @category    PHP
			 * @package     PHP_Compat
			 * @license     LGPL - http://www.gnu.org/licenses/lgpl.html
			 * @copyright   2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
			 * @link        http://php.net/inet_pton
			 * @author      Arpad Ray <arpad@php.net>
			 * @version     $Revision: 269597 $
			 */
			$r = ip2long($ip);
			if($r !== false && $r != -1)
			{
				return pack('N', $r);
			}

			$delim_count = substr_count($ip, ':');
			if($delim_count < 1 || $delim_count > 7)
			{
				return false;
			}

			$r = explode(':', $ip);
			$rcount = count($r);
			if(($doub = array_search('', $r, 1)) !== false)
			{
				$length = (!$doub || $doub == $rcount - 1 ? 2 : 1);
				array_splice($r, $doub, $length, array_fill(0, 8 + $length - $rcount, 0));
			}

			$r = array_map('hexdec', $r);
			array_unshift($r, 'n*');
			$r = call_user_func_array('pack', $r);

			return $r;
		}
	}

	/**
	 * Converts a packed internet address to a human readable representation
	 *
	 * @param string $ip IP in 32bit or 128bit binary format
	 * @return string IP in human readable format
	 */
	function my_inet_ntop($ip)
	{
		if(function_exists('inet_ntop'))
		{
			return @inet_ntop($ip);
		}
		else
		{
			/**
			 * Replace inet_ntop()
			 *
			 * @category    PHP
			 * @package     PHP_Compat
			 * @license     LGPL - http://www.gnu.org/licenses/lgpl.html
			 * @copyright   2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
			 * @link        http://php.net/inet_ntop
			 * @author      Arpad Ray <arpad@php.net>
			 * @version     $Revision: 269597 $
			 */
			switch(strlen($ip))
			{
				case 4:
					list(,$r) = unpack('N', $ip);
					return long2ip($r);
				case 16:
					$r = substr(chunk_split(bin2hex($ip), 4, ':'), 0, -1);
					$r = preg_replace(
						array('/(?::?\b0+\b:?){2,}/', '/\b0+([^0])/e'),
						array('::', '(int)"$1"?"$1":"0$1"'),
						$r);
					return $r;
			}
			return false;
		}
	}
	
	function get_ip(){
		global $config;
		$ip = strtolower($_SERVER['REMOTE_ADDR']);
        if(empty($config['ip_forwarded_check'])){
            $config['ip_forwarded_check'] = false;
        }
		if($config['ip_forwarded_check'])
		{
			$addresses = array();

			if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
			{
				$addresses = explode(',', strtolower($_SERVER['HTTP_X_FORWARDED_FOR']));
			}
			elseif(isset($_SERVER['HTTP_X_REAL_IP']))
			{
				$addresses = explode(',', strtolower($_SERVER['HTTP_X_REAL_IP']));
			}

			if(is_array($addresses))
			{
				foreach($addresses as $val)
				{
					$val = trim($val);
					// Validate IP address and exclude private addresses
					if($this->my_inet_ntop($this->my_inet_pton($val)) == $val && !preg_match("#^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|fe80:|fe[c-f][0-f]:|f[c-d][0-f]{2}:)#", $val))
					{
						$ip = $val;
						break;
					}
				}
			}
		}

		if(!$ip)
		{
			if(isset($_SERVER['HTTP_CLIENT_IP']))
			{
				$ip = strtolower($_SERVER['HTTP_CLIENT_IP']);
			}
		}

		return $ip;
	}
	
	function my_rand($min=0, $max=PHP_INT_MAX){
		// backward compatibility
		if($min === null || $max === null || $max < $min)
		{
			$min = 0;
			$max = PHP_INT_MAX;
		}

		if(version_compare(PHP_VERSION, '7.0', '>='))
		{
			try
			{
				$result = random_int($min, $max);
			} catch (Exception $e) {
			}

			if(isset($result))
			{
				return $result;
			}
		}

		$seed = $this->secure_seed_rng();

		$distance = $max - $min;
		return $min + floor($distance * ($seed / PHP_INT_MAX) );
	}

	function random_str($length=8, $complex=false){
		$set = array_merge(range(0, 9), range('A', 'Z'), range('a', 'z'));
		$str = array();

		// Complex strings have always at least 3 characters, even if $length < 3
		if($complex == true)
		{
			// At least one number
			$str[] = $set[$this->my_rand(0, 9)];

			// At least one big letter
			$str[] = $set[$this->my_rand(10, 35)];

			// At least one small letter
			$str[] = $set[$this->my_rand(36, 61)];

			$length -= 3;
		}

		for($i = 0; $i < $length; ++$i)
		{
			$str[] = $set[$this->my_rand(0, 61)];
		}
		
		// Make sure they're in random order and convert them to a string
		shuffle($str);

		return implode($str);
	}
	
	function secure_seed_rng(){
		$bytes = PHP_INT_SIZE;

		do
		{

			$output = $this->secure_binary_seed_rng($bytes);

			// convert binary data to a decimal number
			if ($bytes == 4)
			{
				$elements = unpack('i', $output);
				$output = abs($elements[1]);
			}
			else
			{
				$elements = unpack('N2', $output);
				$output = abs($elements[1] << 32 | $elements[2]);
			}

		} while($output > PHP_INT_MAX);

		return $output;
	}
	
	function secure_binary_seed_rng($bytes){
		$output = null;

		if(version_compare(PHP_VERSION, '7.0', '>='))
		{
			try
			{
				$output = random_bytes($bytes);
			} catch (Exception $e) {
			}
		}

		if(strlen($output) < $bytes)
		{
			if(@is_readable('/dev/urandom') && ($handle = @fopen('/dev/urandom', 'rb')))
			{
				$output = @fread($handle, $bytes);
				@fclose($handle);
			}
		}
		else
		{
			return $output;
		}

		if(strlen($output) < $bytes)
		{
			if(function_exists('mcrypt_create_iv'))
			{
				if (DIRECTORY_SEPARATOR == '/')
				{
					$source = MCRYPT_DEV_URANDOM;
				}
				else
				{
					$source = MCRYPT_RAND;
				}

				$output = @mcrypt_create_iv($bytes, $source);
			}
		}
		else
		{
			return $output;
		}

		if(strlen($output) < $bytes)
		{
			if(function_exists('openssl_random_pseudo_bytes'))
			{
				// PHP <5.3.4 had a bug which makes that function unusable on Windows
				if ((DIRECTORY_SEPARATOR == '/') || version_compare(PHP_VERSION, '5.3.4', '>='))
				{
					$output = openssl_random_pseudo_bytes($bytes, $crypto_strong);
					if ($crypto_strong == false)
					{
						$output = null;
					}
				}
			}
		}
		else
		{
			return $output;
		}

		if(strlen($output) < $bytes)
		{
			if(class_exists('COM'))
			{
				try
				{
					$CAPI_Util = new COM('CAPICOM.Utilities.1');
					if(is_callable(array($CAPI_Util, 'GetRandom')))
					{
						$output = $CAPI_Util->GetRandom($bytes, 0);
					}
				} catch (Exception $e) {
				}
			}
		}
		else
		{
			return $output;
		}

		if(strlen($output) < $bytes)
		{
			// Close to what PHP basically uses internally to seed, but not quite.
			$unique_state = microtime().@getmypid();

			$rounds = ceil($bytes / 16);

			for($i = 0; $i < $rounds; $i++)
			{
				$unique_state = md5(microtime().$unique_state);
				$output .= md5($unique_state);
			}

			$output = substr($output, 0, ($bytes * 2));

			$output = pack('H*', $output);

			return $output;
		}
		else
		{
			return $output;
		}
	}
}