Your IP : 18.118.49.198


Current Path : /home/bitrix/initial_sites/coffe.land_1/bitrix/modules/statistic/classes/general/
Upload File :
Current File : /home/bitrix/initial_sites/coffe.land_1/bitrix/modules/statistic/classes/general/city.php

<?
/*.
	require_module 'standard';
	require_module 'bitrix_main';
	require_module 'bitrix_statistic_include';
.*/
IncludeModuleLangFile(__FILE__);

class CCityLookup
{
	public $is_installed = false;
	public $ip_addr = "";
	public $ip_number = "";
	public $country_code = "";
	public $country_short_name = "";
	public $country_full_name = "";
	public $region_name = "";
	public $city_name = "";
	public $city_id = "";
	public $charset = "";

	/**
	 * @param array[string]string $arDBRecord
	*/
	function __construct($arDBRecord = /*.(array[string]string).*/array())
	{
		if(is_array($arDBRecord))
		{
			if(array_key_exists("IPA", $arDBRecord)) $this->ip_addr = $arDBRecord["IPA"];
			if(array_key_exists("IPN", $arDBRecord)) $this->ip_number = $arDBRecord["IPN"];
			if(array_key_exists("COC", $arDBRecord)) $this->country_code = $arDBRecord["COC"];
			if(array_key_exists("COS", $arDBRecord)) $this->country_short_name = $arDBRecord["COS"];
			if(array_key_exists("COF", $arDBRecord)) $this->country_full_name = $arDBRecord["COF"];
			if(array_key_exists("REN", $arDBRecord)) $this->region_name = $arDBRecord["REN"];
			if(array_key_exists("CIN", $arDBRecord)) $this->city_name = $arDBRecord["CIN"];
			if(array_key_exists("CID", $arDBRecord)) $this->city_id = $arDBRecord["CID"];
		}
		else
		{
			$ip = $this->ip_addr = $_SERVER["REMOTE_ADDR"];
			$this->ip_number = ip2number($ip);
		}
	}

	/**
	 * @param array[string]string $arDBRecord
	 * @return CCityLookup
	*/
	public static function OnCityLookup($arDBRecord = /*.(array[string]string).*/array())
	{
		return new CCityLookup($arDBRecord);
	}

	/**
	 * @return array[string]string
	*/
	function ArrayForDB()
	{
		$ar = /*.(array[string]string).*/array();
		if(strlen($this->ip_addr) > 0) $ar["IPA"] = $this->ip_addr;
		if(strlen($this->ip_number) > 0) $ar["IPN"] = $this->ip_number;
		if(strlen($this->country_code) > 0) $ar["COC"] = $this->country_code;
		if(strlen($this->country_short_name) > 0) $ar["COS"] = $this->country_short_name;
		if(strlen($this->country_full_name) > 0) $ar["COF"] = $this->country_full_name;
		if(strlen($this->region_name) > 0) $ar["REN"] = $this->region_name;
		if(strlen($this->city_name) > 0) $ar["CIN"] = $this->city_name;
		if(strlen($this->city_id) > 0) $ar["CID"] = $this->city_id;
		return $ar;
	}

	/**
	 * @return array[string][string]string
	*/
	function GetFullInfo()
	{
		return array(
			"IP_ADDR" => array(
				"TITLE" => GetMessage("STAT_CITY_IP_ADDR"),
				"VALUE~" => $this->ip_addr,
				"VALUE" => htmlspecialcharsbx($this->ip_addr),
			),
			"COUNTRY_CODE" => array(
				"TITLE" => GetMessage("STAT_CITY_COUNTRY_CODE"),
				"VALUE~" => $this->country_code,
				"VALUE" => htmlspecialcharsbx($this->country_code),
			),
			"COUNTRY_NAME" => array(
				"TITLE" => GetMessage("STAT_CITY_COUNTRY_NAME"),
				"VALUE~" => $this->country_full_name,
				"VALUE" => htmlspecialcharsbx($this->country_full_name),
			),
			"REGION_NAME" => array(
				"TITLE" => GetMessage("STAT_CITY_REGION_NAME"),
				"VALUE~" => $this->region_name,
				"VALUE" => htmlspecialcharsbx($this->region_name),
			),
			"CITY_NAME" => array(
				"TITLE" => GetMessage("STAT_CITY_CITY_NAME"),
				"VALUE~" => $this->city_name,
				"VALUE" => htmlspecialcharsbx($this->city_name),
			),
		);
	}

	/**
	 * @return array[string]mixed
	*/
	function GetDescription()
	{
		$res = /*.(array[string]mixed).*/array();
		$res["ID"] = "CCityLookup";
		$res["DESCRIPTION"] = "";
		$res["IS_INSTALLED"] = false;
		$res["CAN_LOOKUP_COUNTRY"] = true;
		$res["CAN_LOOKUP_CITY"] = false;
		return $res;
	}

	/**
	 * @return bool
	*/
	function IsInstalled()
	{
		return false;
	}

	/**
	 * @return void
	*/
	function Lookup()
	{
		$this->country_code = "N0";
		$this->country_short_name = "N00";
		$this->country_full_name = "NA";
	}
}

class CStatRegion
{
	/**
	 * @param array[string]string $arOrder
	 * @param array[string]string $arFilter
	 * @return CDBResult
	*/
	function GetList($arOrder = /*.(array[string]string).*/array(), $arFilter = /*.(array[string]string).*/array())
	{
		$DB = CDatabase::GetModuleConnection('statistic');

		$arQueryOrder = array();
		if(is_array($arOrder))
		{
			foreach($arOrder as $strColumn => $strDirection)
			{
				$strColumn = strtoupper($strColumn);
				$strDirection = strtoupper($strDirection)==="ASC"? "ASC": "DESC";
				switch($strColumn)
				{
					case "COUNTRY_ID":
					case "COUNTRY_SHORT_NAME":
					case "COUNTRY_NAME":
					case "REGION_NAME":
						$arQueryOrder[$strColumn] = $strColumn." ".$strDirection;
						break;
					case "REGION":
						$arQueryOrder["COUNTRY_ID"] = "COUNTRY_ID ".$strDirection;
						$arQueryOrder["REGION_NAME"] = "REGION_NAME ".$strDirection;
						break;
					default:
						break;
				}
			}
		}

		$obQueryWhere = new CSQLWhere;
		$obQueryWhere->SetFields(array(
			"COUNTRY_ID" => array(
				"TABLE_ALIAS" => "R",
				"FIELD_NAME" => "R.COUNTRY_ID",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"COUNTRY_SHORT_NAME" => array(
				"TABLE_ALIAS" => "C",
				"FIELD_NAME" => "C.SHORT_NAME",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"COUNTRY_NAME" => array(
				"TABLE_ALIAS" => "C",
				"FIELD_NAME" => "C.NAME",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"REGION_NAME" => array(
				"TABLE_ALIAS" => "R",
				"FIELD_NAME" => "R.REGION",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
		));

		$strSql = "
			SELECT
				R.COUNTRY_ID
				,C.SHORT_NAME COUNTRY_SHORT_NAME
				,C.NAME COUNTRY_NAME
				,R.REGION REGION_NAME
			FROM
				b_stat_city R
				INNER JOIN b_stat_country C on C.ID = R.COUNTRY_ID
		";

		$strQueryWhere = $obQueryWhere->GetQuery($arFilter);

		if(strlen($strQueryWhere) > 0)
		{
			$strSql .= "
				WHERE
				".$strQueryWhere."
			";
		}
		$strSql .= "
			GROUP BY
				R.COUNTRY_ID, R.REGION, C.SHORT_NAME, C.NAME
			";

		if(count($arQueryOrder) > 0)
		{
			$strSql .= "
				ORDER BY
				".implode(", ", $arQueryOrder)."
			";
		}

		return $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
	}
}

class CCity
{
	private $lookup_class = "";
	private $lookup = /*.(CCityLookup).*/null;
	private $country_code = "";
	private $city_id = "";

	/**
	 * @param string $dbRecord
	*/
	function __construct($dbRecord = "")
	{
		if(strlen($dbRecord) > 0)
			$arDBRecord = unserialize($dbRecord);
		else
			$arDBRecord = false;

		if(is_array($arDBRecord))
		{
			$this->lookup_class = $arDBRecord["LC"];
			if(!$this->lookup_class || !class_exists(strtolower($this->lookup_class)))
				$this->lookup_class = "CCityLookup";

			$this->lookup = call_user_func_array(array($this->lookup_class, "OnCityLookup"), array($arDBRecord["LD"]));

			$this->country_code = $arDBRecord["CC"];
			$this->city_id = $arDBRecord["CI"];
		}
		else
		{
			$this->lookup_class = $this->GetHandler();
			if(!$this->lookup_class || !class_exists(strtolower($this->lookup_class)))
				$this->lookup_class = "CCityLookup";

			$ob = call_user_func_array(array($this->lookup_class, "OnCityLookup"), array());

			if(!$ob || !$ob->IsInstalled())
			{
				$this->lookup_class = "CCityLookup";
				$this->lookup = new CCityLookup;
			}
			else
			{
				$this->lookup = $ob;
			}
		}
	}

	/**
	 * @param array[string]string $arOrder
	 * @param array[string]string $arFilter
	 * @return CDBResult
	*/
	public static function GetList($arOrder = /*.(array[string]string).*/array(), $arFilter = /*.(array[string]string).*/array())
	{
		$DB = CDatabase::GetModuleConnection('statistic');

		if(!is_array($arOrder))
			$arOrder = array();

		$arQueryOrder = array();
		foreach($arOrder as $strColumn => $strDirection)
		{
			$strColumn = strtoupper($strColumn);
			$strDirection = strtoupper($strDirection)==="ASC"? "ASC": "DESC";
			switch($strColumn)
			{
				case "COUNTRY_ID":
				case "COUNTRY_SHORT_NAME":
				case "COUNTRY_NAME":
				case "REGION_NAME":
				case "CITY_NAME":
					$arQueryOrder[$strColumn] = $strColumn." ".$strDirection;
					break;
				case "CITY":
					$arQueryOrder["COUNTRY_ID"] = "COUNTRY_ID ".$strDirection;
					$arQueryOrder["REGION_NAME"] = "REGION_NAME ".$strDirection;
					$arQueryOrder["CITY_NAME"] = "CITY_NAME ".$strDirection;
					break;
				default:
					break;
			}
		}

		$obQueryWhere = new CSQLWhere;
		$obQueryWhere->SetFields(array(
			"CITY_ID" => array(
				"TABLE_ALIAS" => "CITY",
				"FIELD_NAME" => "CITY.ID",
				"FIELD_TYPE" => "int",
				"JOIN" => "",
			),
			"COUNTRY_ID" => array(
				"TABLE_ALIAS" => "CITY",
				"FIELD_NAME" => "CITY.COUNTRY_ID",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"COUNTRY_SHORT_NAME" => array(
				"TABLE_ALIAS" => "C",
				"FIELD_NAME" => "C.SHORT_NAME",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"COUNTRY_NAME" => array(
				"TABLE_ALIAS" => "C",
				"FIELD_NAME" => "C.NAME",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"REGION_NAME" => array(
				"TABLE_ALIAS" => "CITY",
				"FIELD_NAME" => "CITY.REGION",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
			"CITY_NAME" => array(
				"TABLE_ALIAS" => "CITY",
				"FIELD_NAME" => "CITY.NAME",
				"FIELD_TYPE" => "string",
				"JOIN" => "",
			),
		));

		$strSql = "
			SELECT
				CITY.ID CITY_ID
				,CITY.COUNTRY_ID
				,C.SHORT_NAME COUNTRY_SHORT_NAME
				,C.NAME COUNTRY_NAME
				,CITY.REGION REGION_NAME
				,CITY.NAME CITY_NAME
			FROM
				b_stat_city CITY
				INNER JOIN b_stat_country C on C.ID = CITY.COUNTRY_ID
		";
		$strQueryWhere = $obQueryWhere->GetQuery($arFilter);

		if(strlen($strQueryWhere) > 0)
		{
			$strSql .= "
				WHERE
				".$strQueryWhere."
			";
		}

		if(count($arQueryOrder) > 0)
		{
			$strSql .= "
				ORDER BY
				".implode(", ", $arQueryOrder)."
			";
		}

		return $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
	}


	/**
	 * @return string
	*/
	function ForSQL()
	{
		$DB = CDatabase::GetModuleConnection('statistic');
		return $DB->ForSQL(serialize(array(
			"LC" => $this->lookup_class,
			"LD" => $this->lookup->ArrayForDB(),
			"CC" => $this->country_code,
			"CI" => $this->city_id,
		)));
	}

	function GetFullInfo()
	{
		$this->GetCityID();
		return $this->lookup->GetFullInfo();
	}

	public static function GetHandler()
	{
		$selected = COption::GetOptionString("statistic", "IP_LOOKUP_CLASS", "");
		if(!$selected)
		{
			$arResolvers = array();
			foreach(GetModuleEvents("statistic", "OnCityLookup", true) as $arEvent)
			{
				$ob = ExecuteModuleEventEx($arEvent);
				$ar = $ob->GetDescription();
				$arResolvers[$ar["CLASS"]] = $ob;
			}
			if(!array_key_exists($selected, $arResolvers))
			{
				foreach($arResolvers as $ID => $ob)
				{
					if($ob->IsInstalled())
					{
						$selected = $ID;
						break;
					}
				}
			}
			COption::SetOptionString("statistic", "IP_LOOKUP_CLASS", $selected);
		}
		return $selected;
	}

	function GetCountryCode()
	{
		if(!$this->country_code)
		{
			$this->lookup->Lookup();
			$this->country_code = $this->lookup->country_code;
		}
		return $this->country_code? $this->country_code: "N0";
	}

	function Recode($str)
	{
		if($str && $this->lookup->charset)
		{
			global $APPLICATION;
			$str = $APPLICATION->ConvertCharset($str, $this->lookup->charset, LANG_CHARSET);
		}
		return $str;
	}

	function GetCityID()
	{
		$DB = CDatabase::GetModuleConnection('statistic');
		$country_code = $this->GetCountryCode();

		if(!$this->city_id)
			$this->city_id = $this->lookup->city_id;

		if(!$this->city_id)
		{
			$city_name = $this->Recode($this->lookup->city_name);
			$region_name = $this->Recode($this->lookup->region_name);

			$rs = $DB->Query("
				SELECT ID
				FROM b_stat_city
				WHERE COUNTRY_ID = '".$DB->ForSQL($country_code, 2)."'
				AND ".($region_name? "REGION = '".$DB->ForSQL($region_name, 255)."'": "REGION IS NULL")."
				AND ".($city_name? "NAME = '".$DB->ForSQL($city_name, 255)."'": "NAME IS NULL")."
			");
			$ar = $rs->Fetch();
			if($ar)
			{
				$this->city_id = $ar["ID"];
			}
			else
			{
				$rs = $DB->Query("
					SELECT ID
					FROM b_stat_country
					WHERE ID = '".$DB->ForSQL($country_code, 2)."'
				");
				$ar = $rs->Fetch();
				if(!$ar)
				{
					$country_short_name = $this->Recode($this->lookup->country_short_name);
					$country_full_name = $this->Recode($this->lookup->country_full_name);
					$DB->Query("
						INSERT INTO b_stat_country (ID, SHORT_NAME, NAME) VALUES (
							'".$DB->ForSql($country_code, 2)."',
							".($country_short_name? "'".$DB->ForSql($country_short_name, 3)."'": "'N00'").",
							".($country_full_name? "'".$DB->ForSql($country_full_name, 50)."'": "'NA'")."
						)
					");
				}
				$this->city_id = $DB->Add("b_stat_city", array(
					"COUNTRY_ID" => $country_code,
					"REGION" => $region_name ? $region_name: false,
					"NAME" => $city_name ? $city_name: false,
				));
			}
		}
		return $this->city_id > 0? intval($this->city_id): "";
	}

	public static function GetGraphArray($arFilter, &$arLegend, $sort = false, $top = 0)
	{
		$err_mess = "File: ".__FILE__."<br>Line: ";
		global $arCityColor;
		$DB = CDatabase::GetModuleConnection('statistic');
		$arSqlSearch = Array();
		if(is_array($arFilter))
		{
			foreach ($arFilter as $key => $val)
			{
				if(is_array($val))
				{
					if(count($val) <= 0)
						continue;
				}
				else
				{
					if( (strlen($val) <= 0) || ($val === "NOT_REF") )
						continue;
				}
				$match_value_set = array_key_exists($key."_EXACT_MATCH", $arFilter);
				$key = strtoupper($key);
				switch($key)
				{
					case "COUNTRY_ID":
						if ($val!="NOT_REF")
							$arSqlSearch[] = GetFilterQuery("C.COUNTRY_ID",$val,"N");
						break;
					case "DATE1":
						if (CheckDateTime($val))
							$arSqlSearch[] = "D.DATE_STAT>=".$DB->CharToDateFunction($val, "SHORT");
						break;
					case "DATE2":
						if (CheckDateTime($val))
							$arSqlSearch[] = "D.DATE_STAT<=".$DB->CharToDateFunction($val." 23:59:59", "FULL");
						break;
				}
			}
		}
		$arrDays = array();
		$arLegend = array();
		$strSqlSearch = GetFilterSqlSearch($arSqlSearch);
		$strSql = "
			SELECT
				".$DB->DateToCharFunction("D.DATE_STAT","SHORT")." DATE_STAT,
				".$DB->DateFormatToDB("DD", "D.DATE_STAT")." DAY,
				".$DB->DateFormatToDB("MM", "D.DATE_STAT")." MONTH,
				".$DB->DateFormatToDB("YYYY", "D.DATE_STAT")." YEAR,
				D.CITY_ID,
				D.SESSIONS,
				D.NEW_GUESTS,
				D.HITS,
				D.C_EVENTS,
				C.NAME,
				C.SESSIONS TOTAL_SESSIONS,
				C.NEW_GUESTS TOTAL_NEW_GUESTS,
				C.HITS TOTAL_HITS,
				C.C_EVENTS TOTAL_C_EVENTS
			FROM
				b_stat_city_day D
				INNER JOIN b_stat_city C ON (C.ID = D.CITY_ID)
			WHERE
				".$strSqlSearch."
			ORDER BY
				D.DATE_STAT, D.CITY_ID
		";

		$rsD = $DB->Query($strSql, false, $err_mess.__LINE__);
		while ($arD = $rsD->Fetch())
		{
			$arrDays[$arD["DATE_STAT"]]["D"] = $arD["DAY"];
			$arrDays[$arD["DATE_STAT"]]["M"] = $arD["MONTH"];
			$arrDays[$arD["DATE_STAT"]]["Y"] = $arD["YEAR"];
			$arrDays[$arD["DATE_STAT"]][$arD["CITY_ID"]]["SESSIONS"] = $arD["SESSIONS"];
			$arrDays[$arD["DATE_STAT"]][$arD["CITY_ID"]]["NEW_GUESTS"] = $arD["NEW_GUESTS"];
			$arrDays[$arD["DATE_STAT"]][$arD["CITY_ID"]]["HITS"] = $arD["HITS"];
			$arrDays[$arD["DATE_STAT"]][$arD["CITY_ID"]]["C_EVENTS"] = $arD["C_EVENTS"];

			$arLegend[$arD["CITY_ID"]]["CITY_ID"] = intval($arD["CITY_ID"]);
			$arLegend[$arD["CITY_ID"]]["NAME"] = $arD["NAME"];
			$arLegend[$arD["CITY_ID"]]["SESSIONS"] += $arD["SESSIONS"];
			$arLegend[$arD["CITY_ID"]]["NEW_GUESTS"] += $arD["NEW_GUESTS"];
			$arLegend[$arD["CITY_ID"]]["HITS"] += $arD["HITS"];
			$arLegend[$arD["CITY_ID"]]["C_EVENTS"] += $arD["C_EVENTS"];

			$arLegend[$arD["CITY_ID"]]["TOTAL_SESSIONS"] = $arD["TOTAL_SESSIONS"];
			$arLegend[$arD["CITY_ID"]]["TOTAL_NEW_GUESTS"] = $arD["TOTAL_NEW_GUESTS"];
			$arLegend[$arD["CITY_ID"]]["TOTAL_HITS"] = $arD["TOTAL_HITS"];
			$arLegend[$arD["CITY_ID"]]["TOTAL_C_EVENTS"] = $arD["TOTAL_C_EVENTS"];
		}

		if($sort)
		{
			CStatisticSort::Sort($arLegend, $sort);
		}

		if($top)
		{
			$totals = array(
				"CITY_ID" => 0,
				"NAME" => GetMessage("STAT_CITY_OTHER"),
				"SESSIONS" => 0,
				"NEW_GUESTS" => 0,
				"HITS" => 0,
				"C_EVENTS" => 0,
				"TOTAL_SESSIONS" => 0,
				"TOTAL_NEW_GUESTS" => 0,
				"TOTAL_HITS" => 0,
				"TOTAL_C_EVENTS" => 0,
			);
			$i = 0;
			while(count($arLegend) > $top)
			{
				$i++;
				$tail = array_pop($arLegend);
				$totals["SESSIONS"] += $tail["SESSIONS"];
				$totals["NEW_GUESTS"] += $tail["NEW_GUESTS"];
				$totals["HITS"] += $tail["HITS"];
				$totals["C_EVENTS"] += $tail["C_EVENTS"];
				$totals["TOTAL_SESSIONS"] += $tail["TOTAL_SESSIONS"];
				$totals["TOTAL_NEW_GUESTS"] += $tail["TOTAL_NEW_GUESTS"];
				$totals["TOTAL_HITS"] += $tail["TOTAL_HITS"];
				$totals["TOTAL_C_EVENTS"] += $tail["TOTAL_C_EVENTS"];
			}
			if($i)
				$arLegend[0] = $totals;

			foreach($arrDays as $DATE_STAT => $arDate)
			{
				foreach($arDate as $CITY_ID => $arCity)
				{
					if(intval($CITY_ID) > 0)
					{
						if(!array_key_exists($CITY_ID, $arLegend))
						{
							$arrDays[$DATE_STAT][0]["CITY_ID"] = 0;
							$arrDays[$DATE_STAT][0]["NAME"] = GetMessage("STAT_CITY_OTHER");
							$arrDays[$DATE_STAT][0]["SESSIONS"] += $arCity["SESSIONS"];
							$arrDays[$DATE_STAT][0]["NEW_GUESTS"] += $arCity["NEW_GUESTS"];
							$arrDays[$DATE_STAT][0]["HITS"] += $arCity["HITS"];
							$arrDays[$DATE_STAT][0]["C_EVENTS"] += $arCity["C_EVENTS"];
							unset($arrDays[$DATE_STAT][$CITY_ID]);
						}
					}
				}
			}
		}

		$color_getnext = '';
		$total = count($arLegend);
		foreach($arLegend as $key => $arr)
		{
			if (strlen($arCityColor[$key])>0)
			{
				$color = $arCityColor[$key];
			}
			else
			{
				$color = GetNextRGB($color_getnext, $total);
				$color_getnext = $color;
			}
			$arr["COLOR"] = $color;
			$arLegend[$key] = $arr;
		}

		return $arrDays;
	}

	public static function FindFiles($type = 'country', $path = '/bitrix/modules/statistic/ip2country')
	{
		$arFiles = array();
		$handle = opendir($_SERVER["DOCUMENT_ROOT"].$path);
		if($handle)
		{
			while(false!==($fname = readdir($handle)))
			{
				if (is_file($_SERVER["DOCUMENT_ROOT"].$path."/".$fname) && $fname!="." && $fname!="..")
				{
					$ext = substr(strtolower($fname), -4);
					if($ext === ".csv" || $ext === ".txt")
					{
						$arFiles[] = $fname;
					}
				}
			}
			closedir($handle);
		}

		$arResult = array();
		foreach($arFiles as $file)
		{
			$fp = fopen($_SERVER["DOCUMENT_ROOT"].$path."/".$file, "r");
			if($fp)
			{
				switch(CCity::GetCSVFormatType($fp))
				{
				case "MAXMIND-IP-COUNTRY":
					if($type == 'country')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "MAXMIND-IP-COUNTRY",
						);
					break;
				case "IP-TO-COUNTRY":
					if($type == 'country')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "IP-TO-COUNTRY",
						);
					break;
				case "MAXMIND-IP-LOCATION":
					if($type == 'city')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "MAXMIND-IP-LOCATION",
						);
					break;
				case "MAXMIND-CITY-LOCATION":
					if($type == 'city')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "MAXMIND-CITY-LOCATION",
						);
					break;
				case "IPGEOBASE":
					if($type == 'city')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "IPGEOBASE",
						);
					break;
				case "IPGEOBASE2":
					if($type == 'city')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "IPGEOBASE2",
						);
					break;
				case "IPGEOBASE2-CITY":
					if($type == 'city')
						$arResult[] = array(
							"FILE" => $file,
							"SIZE" => filesize($_SERVER["DOCUMENT_ROOT"].$path."/".$file),
							"SOURCE" => "IPGEOBASE2-CITY",
						);
					break;
				}
				fclose($fp);
			}
		}
		return $arResult;
	}

	public static function GetCSVFormatType($fp)
	{
		$line = trim(fgets($fp, 1024), " \t\n\r");
		if(preg_match('/maxmind/i', $line))
			$line = trim(fgets($fp, 1024), " \t\n\r");

		if(
			preg_match('/^"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})","(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})","(\d+)","(\d+)","..",".*?"$/', $line, $match)
			&& (ip2number($match[1]) == $match[3])
			&& (ip2number($match[2]) == $match[4])
		)
		{
			return "MAXMIND-IP-COUNTRY";
		}
		elseif(
			preg_match('/^"\d+","\d+","..","...",".*?"$/', $line)
		)
		{
			return "IP-TO-COUNTRY";
		}
		elseif(
			preg_match('/^startIpNum,endIpNum,locId$/', $line)
		)
		{
			return "MAXMIND-IP-LOCATION";
		}
		elseif(
			preg_match('/^locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode$/', $line)
		)
		{
			return "MAXMIND-CITY-LOCATION";
		}
		elseif(
			preg_match('/^(\d+)\t(\d+)\t(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\t(..)\t(.+?)\t(.+?)\t(.+?)\t(.+?)\t(.+)$/', $line, $match)
			&& (ip2number($match[3]) == $match[1])
			&& (ip2number($match[4]) == $match[2])
		)
		{
			return "IPGEOBASE";
		}
		elseif(
			preg_match('/^(\d+)\t(\d+)\t(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\t(..)/', $line, $match)
			&& (ip2number($match[3]) == $match[1])
			&& (ip2number($match[4]) == $match[2])
		)
		{
			return "IPGEOBASE2";
		}
		elseif(
			preg_match('/^\d+\t(.+?)\t(.+?)\t(.+?)\t([0-9.]+?)\t([0-9.]+?)$/', $line)
		)
		{
			return "IPGEOBASE2-CITY";
		}
		else
		{
			return "UNKNOWN";
		}
	}

	public static function ResolveIPRange($newStartIP, $newEndIP)
	{
		global $DB;

		$rsConflictIP = $DB->Query("
			select * from b_stat_city_ip
			where start_ip between ".$newStartIP." and ".$newEndIP."
			union
			select * from b_stat_city_ip
			where  end_ip between ".$newStartIP." and ".$newEndIP."
			union
			select * from b_stat_city_ip
			where START_IP = (
				SELECT MAX(START_IP)
				FROM b_stat_city_ip
				WHERE START_IP <= ".$newStartIP."
			)
			AND END_IP >= ".$newStartIP."
		");

		$arToUpdate = false;
		while($arConflictIP = $rsConflictIP->Fetch())
		{
			//Exact match
			if(
				$arConflictIP["START_IP"] == $newStartIP
				&& $arConflictIP["END_IP"] == $newEndIP
			)
			{
				$arToUpdate = $arConflictIP;
			}
			//Left overlap
			elseif(
				$newStartIP <= $arConflictIP["START_IP"]
				&& $newEndIP < $arConflictIP["END_IP"]
			)
			{
				//Move conflict to the right
				$rs = $DB->Query("
					UPDATE b_stat_city_ip
					SET START_IP = '".($newEndIP+1)."'
					WHERE START_IP  = '".$arConflictIP["START_IP"]."'
				", true);
				//Delete if there is new conflict raises
				if(!$rs)
					$rs = $DB->Query("
						DELETE FROM b_stat_city_ip
						WHERE START_IP  = '".$arConflictIP["START_IP"]."'
					");
			}
			//Full overlap
			elseif(
				$newStartIP <= $arConflictIP["START_IP"]
				&& $arConflictIP["END_IP"] < $newEndIP
			)
			{
				//Delete
				$rs = $DB->Query("
					DELETE FROM b_stat_city_ip
					WHERE START_IP  = '".$arConflictIP["START_IP"]."'
				");
			}
			//Right overlap
			elseif(
				$arConflictIP["START_IP"] < $newStartIP
				&& $arConflictIP["END_IP"] <= $newEndIP
			)
			{
				//Move conflict to the left
				$rs = $DB->Query("
					UPDATE b_stat_city_ip
					SET END_IP = '".($newStartIP-1)."'
					WHERE START_IP  = '".$arConflictIP["START_IP"]."'
				");
			}
			//Inside
			else/*if(
				$arConflictIP["START_IP"] < $newStartIP
				&& $newEndIP < $arConflictIP["END_IP"]
			)*/
			{
				//Split
				$rs = $DB->Query("
					UPDATE b_stat_city_ip
					SET END_IP = '".($newStartIP-1)."'
					WHERE START_IP  = '".$arConflictIP["START_IP"]."'
				");
				$rs = $DB->Query("
					INSERT INTO b_stat_city_ip
					(START_IP, END_IP, COUNTRY_ID, CITY_ID)
					VALUES
					('".($newEndIP+1)."', '".$arConflictIP["END_IP"]."', '".$arConflictIP["COUNTRY_ID"]."', '".$arConflictIP["CITY_ID"]."')
				", true);
				//Delete if there is new conflict raises
				if(!$rs)
					$rs = $DB->Query("
						DELETE FROM b_stat_city_ip
						WHERE START_IP  = '".$arConflictIP["START_IP"]."'
					");
			}
		}

		return $arToUpdate;
	}


	public static function LoadCSV($file_name, $step, &$file_position)
	{
		global $APPLICATION;
		$DB = CDatabase::GetModuleConnection('statistic');
		$arCache = array();
		$arLookupCache = array();
		$arCountryCache = array();

		$fp = fopen($_SERVER["DOCUMENT_ROOT"].$file_name, "rb");
		if(!$fp)
			return "Y";

		$file_format = CCity::GetCSVFormatType($fp);
		$file_position = intval($file_position);
		fseek($fp, $file_position);

		if($step > 0)
			$end_time = getmicrotime() + $step;
		else
			$end_time = 0;

		switch($file_format)
		{
		case "MAXMIND-IP-COUNTRY":
			$delimiter = ",";
			$char_set = LANG_CHARSET;
			$table_name = "b_stat_country";
			$arFieldsMap = array(
				"ID" => array("key" => true, "index" => 4, "type" => "varchar", "len" => 2, "default" => "NA"),
				"NAME" => array("index" => 5, "type" => "varchar", "len" => 50, "default" => "N00", "enc" => true),
			);
			break;
		case "IP-TO-COUNTRY":
			$delimiter = ",";
			$char_set = LANG_CHARSET;
			$table_name = "b_stat_country";
			$arFieldsMap = array(
				"ID" => array("key" => true, "index" => 2, "type" => "varchar", "len" => 2, "default" => "NA"),
				"SHORT_NAME" => array("index" => 3, "type" => "varchar", "len" => 3, "default" => "N00"),
				"NAME" => array("index" => 4, "type" => "varchar", "len" => 50, "enc" => true),
			);
			break;
		case "MAXMIND-IP-LOCATION":
			$delimiter = ",";
			$char_set = LANG_CHARSET;
			$table_name = "b_stat_city_ip";
			$arFieldsMap = array(
				"START_IP" => array("key" => true,"index" => 0, "type" => "ipnum"),
				"END_IP" => array("index" => 1, "type" => "ipnum"),
				"XML_ID" => array("index" => 2, "type" => "lookup"),
				"COUNTRY_ID" => array("index" => -1, "type" => "varchar"),
				"CITY_ID" => array("index" => -2, "type" => "number"),
			);
			//Some files need to skip first line
			if($file_position <= 0)
			{
				fgets($fp, 4096);
				fgets($fp, 4096);
			}
			break;
		case "MAXMIND-CITY-LOCATION":
			$delimiter = ",";
			$char_set = "iso-8859-1";
			$table_name = "b_stat_city";
			$arFieldsMap = array(
				"COUNTRY_ID" => array("index" => 1, "type" => "varchar", "len" => 2, "default" => "NA"),
				"REGION" => array("index" => 2, "type" => "varchar", "len" => 255, "enc" => true),
				"NAME" => array("index" => 3, "type" => "varchar", "len" => 255, "enc" => true),
				"XML_ID" => array("key" => true, "index" => 0, "type" => "varchar", "len" => 255),
			);
			//Some files need to skip first line
			if($file_position <= 0)
			{
				fgets($fp, 4096);
				fgets($fp, 4096);
			}
			break;
		case "IPGEOBASE":
			$delimiter = "\t";
			$char_set = "Windows-1251";
			$table_name = "b_stat_city_ip";
			$arFieldsMap = array(
				"START_IP" => array("key" => true,"index" => 0, "type" => "ipnum"),
				"END_IP" => array("index" => 1, "type" => "ipnum"),
				"COUNTRY_ID" => array("index" => 3, "type" => "varchar", "len" => 2, "default" => "NA"),
				"XML_ID" => array("index" => array(3, 4, 5), "type" => "upsert", "enc" => true,
					"master" => array(
						"COUNTRY_ID" => array("index" => 3, "type" => "varchar", "len" => 2, "default" => "NA"),
						"REGION" => array("index" => 5, "type" => "varchar", "len" => 255, "enc" => true),
						"NAME" => array("index" => 4, "type" => "varchar", "len" => 255, "enc" => true),
					),
				),
				"CITY_ID" => array("index" => -1, "type" => "number"),
			);
			break;
		case "IPGEOBASE2":
			$delimiter = "\t";
			$char_set = "Windows-1251";
			$table_name = "b_stat_city_ip";
			$arFieldsMap = array(
				"START_IP" => array("key" => true,"index" => 0, "type" => "ipnum"),
				"END_IP" => array("index" => 1, "type" => "ipnum"),
				"COUNTRY_ID" => array("index" => 3, "type" => "varchar", "len" => 2, "default" => "NA", "update_city" => 4),
				"XML_ID" => array("index" => 4, "type" => "lookup"),
				"CITY_ID" => array("index" => -1, "type" => "number"),
			);
			break;
		case "IPGEOBASE2-CITY":
			$delimiter = "\t";
			$char_set = "Windows-1251";
			$table_name = "b_stat_city";
			$arFieldsMap = array(
				"COUNTRY_ID" => array("skip_update" => true, "index" => 100, "type" => "varchar", "len" => 2, "default" => "NA"),
				"REGION" => array("index" => 2, "type" => "varchar", "len" => 255, "enc" => true),
				"NAME" => array("index" => 1, "type" => "varchar", "len" => 255, "enc" => true),
				"XML_ID" => array("key" => true, "index" => 0, "type" => "varchar", "len" => 255),
			);
			break;
		default:
			return "Y";
		}

		$bConv = $char_set != LANG_CHARSET;

		while(!feof($fp))
		{
			//$arr = fgetcsv($fp, 4096, $delimiter);
			$arr = fgets($fp, 4096);
			if($bConv && preg_match("/[^a-zA-Z0-9 \t\n\r]/", $arr))
				$arr = $APPLICATION->ConvertCharset($arr, $char_set, LANG_CHARSET);
			$arr = preg_split("/".$delimiter."/".BX_UTF_PCRE_MODIFIER, $arr);

			$arAllSQLFields = array();
			$arFields = array();
			$strUpdate = "";
			$strWhere = "";
			$strInsert1 = "";
			$strInsert2 = "";
			$bEmptyKey = false;
			foreach($arFieldsMap as $FIELD_ID => $arField)
			{
				if(is_array($arField["index"]))
				{
					$value = "";
					foreach($arField["index"] as $index)
						$value .= trim($arr[$index], "\" \n\r\t");
					$value = md5($value);
				}
				else
				{
					$value = trim($arr[$arField["index"]], "\" \n\r\t");
				}
				//if($bConv && $arField["enc"] && preg_match("/[^a-zA-Z0-9 \t\n\r]/", $value))
				//	$value = $APPLICATION->ConvertCharset($value, $char_set, LANG_CHARSET);
				if(!$value && $arField["default"])
					$value = $arField["default"];

				if($arField["type"] == "upsert")
				{
					if(!array_key_exists($value, $arLookupCache))
					{
						$rs = $DB->Query("SELECT ID as CITY_ID FROM b_stat_city WHERE XML_ID = '".$DB->ForSQL($value)."'");
						$ar = $rs->Fetch();
						if(!$ar)
						{
							$arNewMaster = array(
								"XML_ID" => $value,
							);
							foreach($arField["master"] as $MASTER_FIELD_ID => $arMasterField)
							{
								$m_value = trim($arr[$arMasterField["index"]], "\"");
								//if($bConv && $arMasterField["enc"] && preg_match("/[^a-zA-Z0-9 \t\n\r]/", $m_value))
								//	$m_value = $APPLICATION->ConvertCharset($m_value, $char_set, LANG_CHARSET);
								if(!$m_value && $arMasterField["default"])
									$m_value = $arMasterField["default"];
								$arNewMaster[$MASTER_FIELD_ID] = $m_value;
							}
							$ar = array("CITY_ID" => $DB->Add("b_stat_city", $arNewMaster));
						}
						$arLookupCache[$value] = $ar;
					}
					foreach($arLookupCache[$value] as $key => $val)
						$arr[$arFieldsMap[$key]["index"]] = $val;
					continue;
				}

				if($arField["type"] == "lookup")
				{
					if(!array_key_exists($value, $arLookupCache))
					{
						$rs = $DB->Query("SELECT COUNTRY_ID, ID as CITY_ID FROM b_stat_city WHERE XML_ID = '".$DB->ForSQL($value)."'");
						$ar = $rs->Fetch();
						if(!$ar)
							$ar = array("COUNTRY_ID" => "NA", "CITY_ID" => 0);
						$arLookupCache[$value] = $ar;
					}
					foreach($arLookupCache[$value] as $key => $val)
						$arr[$arFieldsMap[$key]["index"]] = $val;
					continue;
				}

				if(
					$FIELD_ID === "COUNTRY_ID"
					&& !array_key_exists($value, $arCountryCache)
					&& strlen($value) > 0
				)
				{
					$cid = $DB->ForSQL($value, 2);
					$rs = $DB->Query("SELECT ID FROM b_stat_country WHERE ID = '".$cid."'");
					if(!$rs->Fetch())
						$DB->Query("insert into b_stat_country (ID) values ('".$cid."')");
					$arCountryCache[$value] = true;
				}

				if(
					$FIELD_ID === "COUNTRY_ID"
					&& isset($arField["update_city"])
					&& strlen($value) > 0
				)
				{
					$city_id = $DB->ForSQL(trim($arr[$arField["update_city"]], "\" \n\r\t"));
					$cid = $DB->ForSQL($value, 2);
					$rs = $DB->Query("UPDATE b_stat_city SET COUNTRY_ID = '".$cid."' WHERE XML_ID = '".$city_id."'");
				}

				switch($arField["type"])
				{
					case "varchar":
						$sql_value = "'".$DB->ForSQL($value, $arField["len"])."'";
						break;
					case "ipnum":
					case "number":
						$sql_value = preg_replace("/[^0-9]/", "", $value);
						break;
					default:
						$sql_value = "'".$DB->ForSQL($value)."'";
						break;
				}

				$arAllSQLFields[$FIELD_ID] = $sql_value;

				if($arField["key"])
				{
					if($value)
					{
						if($strWhere)
							$strWhere .= " AND ";
						$strWhere .= $FIELD_ID." = ".$sql_value;
					}
					else
					{
						$bEmptyKey = true;
					}
				}
				else
				{
					$arFields[$FIELD_ID] = $value;
					if($strUpdate)
						$strUpdate .= ", ";
					$strUpdate .= $FIELD_ID." = ".$sql_value;
				}

				if($strInsert1)
					$strInsert1 .= ", ";
				$strInsert1 .= $FIELD_ID;

				if($strInsert2)
					$strInsert2 .= ", ";
				$strInsert2 .= $sql_value;
			}

			if(!$bEmptyKey && $strWhere && $strUpdate && !array_key_exists($strWhere, $arCache))
			{
				if($table_name == "b_stat_city_ip" && $arAllSQLFields["START_IP"] && $arAllSQLFields["END_IP"])
				{
					$arToUpdate = CCity::ResolveIPRange($arAllSQLFields["START_IP"], $arAllSQLFields["END_IP"]);
				}
				else
				{
					$rs = $DB->Query("SELECT * FROM $table_name WHERE $strWhere");
					$arToUpdate = $rs->Fetch();
				}
				if($arToUpdate)
				{
					$bNeedUpdate = false;
					foreach($arFields as $UPD_FIELD_ID => $upd_value)
					{
						if(!isset($arFieldsMap[$UPD_FIELD_ID]["skip_update"]))
						{
							if($upd_value != $arToUpdate[$UPD_FIELD_ID])
							{
								$bNeedUpdate = true;
								break;
							}
						}
					}
					if($bNeedUpdate)
						$DB->Query("UPDATE $table_name SET $strUpdate WHERE $strWhere");
				}
				else
				{
					$DB->Query("INSERT INTO $table_name ($strInsert1) VALUES ($strInsert2)");
				}
				$arCache[$strWhere] = true;
			}

			if($end_time && getmicrotime() > $end_time)
			{
				$file_position = ftell($fp);
				return "N";
			}
		}
		$file_position = ftell($fp);
		return "Y";
	}
}