Skip to content
This repository has been archived by the owner on Feb 9, 2021. It is now read-only.

Commit

Permalink
Reliable timezone detection using systeminfo for Windows and addition…
Browse files Browse the repository at this point in the history
…al IP Geolocation-based detection. Added a warning message for when auto-detection fails. Fixes #2015.
  • Loading branch information
msjyoo committed Oct 4, 2014
1 parent c8cf6b7 commit 42c7322
Showing 1 changed file with 99 additions and 30 deletions.
129 changes: 99 additions & 30 deletions src/pocketmine/PocketMine.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,36 +111,6 @@ function dummy(){

set_time_limit(0); //Who set it to 30 seconds?!?!

if(ini_get("date.timezone") == ""){ //No Timezone set
date_default_timezone_set("GMT");
if(strpos(" " . strtoupper(php_uname("s")), " WIN") !== false){
$time = time();
$time -= $time % 60;
//TODO: Parse different time & date formats by region. ¬¬ world
//Example: USA
@exec("time.exe /T", $hour);
$i = array_map("intval", explode(":", trim($hour[0])));
@exec("date.exe /T", $date);
$j = array_map("intval", explode(substr($date[0], 2, 1), trim($date[0])));
$offset = @round((mktime($i[0], $i[1], 0, $j[1], $j[0], $j[2]) - $time) / 60) * 60;
}else{
@exec("date +%s", $t);
$offset = @round((intval(trim($t[0])) - time()) / 60) * 60;
}

$daylight = (int) date("I");
$d = timezone_name_from_abbr("", $offset, $daylight);
@ini_set("date.timezone", $d);
@date_default_timezone_set($d);
}else{
$d = @date_default_timezone_get();
if(strpos($d, "/") === false){
$d = timezone_name_from_abbr($d);
@ini_set("date.timezone", $d);
@date_default_timezone_set($d);
}
}

gc_enable();
error_reporting(-1);
ini_set("allow_url_fopen", 1);
Expand All @@ -158,8 +128,107 @@ function dummy(){

define("pocketmine\\ANSI", ((strpos(strtoupper(php_uname("s")), "WIN") === false or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"])));

//Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone.
date_default_timezone_set("UTC");
$logger = new MainLogger(\pocketmine\DATA . "server.log", \pocketmine\ANSI);

if(!ini_get("date.timezone")){
if($timezone = detect_system_timezone() and date_default_timezone_set($timezone)){
//Success! Timezone has already been set and validated in the if statement.
//This here is just for redundancy just in case some stupid program wants to read timezone data from the ini.
ini_set("date.timezone", $timezone);
}else{
//If system timezone detection fails or timezone is an invalid value.
if($response = Utils::getURL("http://ip-api.com/json")
and $ip_geolocation_data = json_decode($response, true)
and $ip_geolocation_data['status'] != 'fail'
and date_default_timezone_set($ip_geolocation_data['timezone']))
{
//Again, for redundancy.
ini_set("date.timezone", $ip_geolocation_data['timezone']);
}else{
ini_set("date.timezone", "UTC");
date_default_timezone_set("UTC");
$logger->warning("Timezone could not be automatically determined. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
}
}
}else{
/*
* This is here so that stupid idiots don't come to us complaining and fill up the issue tracker when they put an incorrect timezone abbreviation in php.ini apparently.
*/
$default_timezone = date_default_timezone_get();
if(strpos($default_timezone, "/") === false){
$default_timezone = timezone_name_from_abbr($default_timezone);
ini_set("date.timezone", $default_timezone);
date_default_timezone_set($default_timezone);
}
}

function detect_system_timezone()
{
switch(Utils::getOS()){
case 'win':
$regex = '/(?:Time Zone:\s*\()(UTC)(\+*\-*\d*\d*\:*\d*\d*)(?:\))/';

exec("systeminfo", $output);

$string = implode("\n", $output);

//Detect the Time Zone string in systeminfo
preg_match($regex, $string, $matches);

$offset = $matches[2];

if($offset == ""){
return "UTC";
}else{
//Make signed offsets unsigned for date_parse
if(strpos($offset, '-') !== false){
$negative_offset = true;
$offset = str_replace('-', '', $offset);
}else if(strpos($offset, '+') !== false){
$negative_offset = false;
$offset = str_replace('+', '', $offset);
}else{
return false;
}

$parsed = date_parse($offset);
$offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];

//After date_parse is done, put the sign back
if($negative_offset == true){
$offset = -abs($offset);
}

//And then, look the offset up.
//timezone_name_from_abbr is not used because it returns false on some(most) offsets because it's mapping function is weird.
//That's been a bug in PHP since 2008!
foreach(timezone_abbreviations_list() as $zones){
foreach($zones as $timezone){
if($timezone['offset'] == $offset){
return $timezone['timezone_id'];
}
}
}
}
break;
case 'linux':
exec("date +%s", $buffer);
$offset = round((intval(trim($buffer[0])) - time()) / 60) * 60;

$daylight = (integer) date("I");
$timezone = timezone_name_from_abbr("", $offset, $daylight);

return $timezone;
break;
default:
return false;
}

return false;
}

if(isset($opts["enable-profiler"])){
if(function_exists("profiler_enable")){
\profiler_enable();
Expand Down

0 comments on commit 42c7322

Please sign in to comment.