致命错误:DateTimeZone :: __ construct()中未捕获的PHP异常?

时间:2013-09-05 12:52:18

标签: php

这有点难以解释,但我会尽力解释它尽可能好。

我将数据从一页input textfield上的(page1.php)传递到另一页Select form上的(page2.php)。 这应该是有效的。

Select Form包含一些PHP timezones,当选择时区时,页面将回显该时区的当前时间。 这也可行。

问题是当我在(page1.php)的输入文本字段中输入时区名称时,它会在(page2.php)的选择表单中显示名称,但它不会回显当前时间,它会抛出出了这个错误:

Fatal error: Uncaught exception 'Exception' with message 'DateTimeZone::__construct(): Unknown or bad timezone (London)' in page2.php:16 Stack trace: #0 on line 16.

当事实时区伦敦存在于Select Form Options时,如果我直接在选择表格中输入/搜索伦敦,它将回显该时区的当前时间,但如果输入时区名称则不会page1.php上的输入文本字段,它被传递给page2.php!

上的选择表单

这是我在page2.php上的内容:

<?php

if( isset($_POST['submit']))
{
    //be sure to validate and clean your variables
    $timezone2 = htmlentities($_POST['timezone2']);

    //then you can use them in a PHP function. 
    function get_timezone_offset( $remote_tz ) {
        $timezone2 = new DateTimeZone ( $remote_tz ); ----->>> Line 16 is here.

        $datetime2 = new DateTime ("now", $timezone2);

        $offset = $timezone2->getOffset($datetime2);
        return $offset;

    }

$offset = get_timezone_offset($timezone2);

}

?>

<?php
$options = array();
$options[$_POST["location"]] = $_POST["location"]; <<<<<<----- Data from input textfield on page1.php
$options["Africa/Addis_Ababa"] = "Addis Ababa"; <<<<<<----- Select Form Options
$options["Europe/London"] = "London"; <<<<<<----- Select Form Options

?>

以下是page2.php上的选择表单

<form id="myForm" name="myForm" class="myForm" method="post" action="page2.php">
  <select style="font-size:9px;" name="timezone2" id="timezone2" class="timezone2">
                        <?php
                    foreach($options as $key => $value)
                    {
                        echo '<option value="'. $key .'" label="'. $value .'">'.$value.'</option>';
                    }
                    ?>
<option value="<?php echo $_POST["location"]; ?>"><?php echo $_POST["location"]; ?></option>
</select>
</div>

<div id="myBtn" style="position:relative; float:left; width: 228px; margin-top:50px; margin-left:350px;"><input type="submit" name="submit" id="submit" class="submit" value="Search"/></div>

</form>

,这是page1.php

上的输入文本字段
<form method="post" action="../page2.php">
  <input name="location" type="text" value="Search"/>
  <button type="submit">Search</button>
</form>
有人可以指出我正确的方向吗?

1 个答案:

答案 0 :(得分:2)

出于某些原因,你会出现这种错误。首先,可能的时区列表是有限的,所以摆脱文本字段,只需使用下拉列表。

其次,您可以删除\重命名下拉列表中的所有项目,但只记得因为您要保存偏移量而不是tz名称,所以您永远无法返回(我的示例将向您显示为什么如果您玩它)。通常,最好存储名称而不是偏移量,以便您可以正确管理夏令时。你会注意到为了让这个系统工作,我需要调用date('I')来查看它是否真的很糟糕的夏令时(因为它在我的服务器TZ中的夏令时并不意味着它在用户TZ)。如果您保存了TZ名称,则可以将该逻辑推迟到PHP并使用当前的任何偏移量。在这个简单的例子中,这似乎并不重要,但如果您曾尝试存储该偏移量或使用它来计算未来\过去时间,那么您肯定会遇到麻烦。

另一个小问题是将函数定义放在'if'语句中是很奇怪的。在PHP中,所有函数定义都是全局的,因此无论'if'条件是否为真,它都可用。这样做的问题是你现在已经模糊了你的逻辑而没有任何收获。将其放在别处更容易也更清楚。

我已经重新编写了你的​​代码,以便在使用它时实际工作但是我遗漏了一些细节(比如别名TZ名称[你似乎已经掌握了如何做并切换到使用TZ名称而不是偏移[因为这可能会破坏你的其他代码])但我鼓励你也修复它们。

<?php
$tz_offset=0;

function get_offset_time($offset=0) {
    $original=new DateTime("now");
    $timezoneName=timezone_name_from_abbr("", $offset, date('I'));
    if(!$timezoneName) die('ERROR: Unknown timezone \''.($offset/3600).'\'');
    $oTZ=new DateTimezone($timezoneName);
    $modified = $original->setTimezone($oTZ);
    return $modified->format('Y-m-d H:i:s');
}
function get_timezone_offset($tz_name=null) {
    if(!$tz_name) return 0; // If we have invalid data then return before we error
    $tz=new DateTimeZone($tz_name);
    $dt=new DateTime("now", $tz);
    return $tz->getOffset($dt);
}
function enumerate_tz($tz_select=null) {
    global $tz_offset;
    $tz_ident=DateTimeZone::listIdentifiers();
    foreach($tz_ident as $val) {
        $tmp_offset=get_timezone_offset($val);
        if($val=='UTC'||$tmp_offset) 
            echo '<option value="'.$val.'" '. ($tmp_offset==$tz_offset?' selected':''). '>'. 
            $val. ' [ '.($tmp_offset/3600).' ]'.  // If you'd like to customize the viewable names for each TZ you may do so here
                    '</option>';
    }
}
if(isset($_POST['tz_input']) && $_POST['tz_input']) {
    $tz_input=htmlentities($_POST['tz_input']);
    $tz_offset=get_timezone_offset($tz_input);
}
echo '<html><title>Timezone Select</title><body>'.
'<p>The current timezone offset is: '. ($tz_offset? ($tz_offset/3600): '0'). '</p>';
echo '<p>The current time is: '. get_offset_time($tz_offset). '</p>';
echo '<form method=post><select name=tz_input>';
enumerate_tz($tz_offset); // You'll notice that this list duplicates many of the timezones so that after selecting one the next 
                                    // time through it'll often select a different one. If you want to fix that you'll need to save the actually offset name instead of an offset.
echo '</select><input type=submit value=Search />'.
    '</form></body>';
?>

编辑:另外需要注意的是PHP的timezone_name_from_abbr()函数不完整。某些时区偏移量不会返回TimeZone名称。你也必须考虑到这一点。例如,即使PHP理解“太平洋/中途”时区,在进行反向查找时也无法找到它。我已经更新了代码,因此不会再导致硬错误。

EDIT2:我可以看到,除非有人告诉你如何照亮粪便,否则你不会高兴。你走了:

function getOptionDX($val, $option_array) {
    if(!isset($option_array)||!is_array($option_array)||!count($option_array)>0||!$val) return null;
    $val=htmlentities($val);
    if(isset($option_array[$val])) return $val;
    $new_val=array_search($val, $option_array);
    return $new_val!==FALSE?$new_val: null;
}

将此添加到您的代码中,并通过调用此代码来替换对htmlentities的调用:

$timezone2 = getOptionDX($_POST['timezone2'], $options);

最后,更改此行:

if($timezone2) $offset = get_timezone_offset($timezone2);

如果用户手动输入TZ并且正确,则跳过page2.php。如果您不想更改任何内容,这可以给出答案。事实上,你的逻辑首先是有缺陷的(这并不意味着刺戳,但确实如此)。

EDIT3:IDK出了什么问题,但这是我的完整代码清单,其中包含您要求的修补程序:

<?php
$offset=0; $timezone2='';
$options = array();
$options["Africa/Addis_Ababa"] = "Addis Ababa";
$options["Europe/London"] = "London";
$options["America/Chicago"] = "The Windy City";

function getOptionDX($val, $option_array) {
    if(!isset($option_array)||!is_array($option_array)||!count($option_array)>0||!$val) return null;
    $val=htmlentities(ucwords(strtolower($val)));
    if(isset($option_array[$val])) return $val;
    $new_val=array_search($val, $option_array);
    return $new_val!==FALSE?$new_val: null;
}
function get_timezone_offset( $remote_tz ) {
    $timezone2=new DateTimeZone($remote_tz);
    $datetime2=new DateTime("now", $timezone2);
    $offset=$timezone2->getOffset($datetime2);
    return $offset;
}
if(isset($_POST['location'])) {
    $addLoc=getOptionDX($_POST['location'], $options);
    if(isset($addLoc)) $options[$addLoc]=$_POST['location'];
    else header('Location: '. $_SERVER['SCRIPT_NAME']);
}
if(isset($_POST['timezone2'])) {
    $timezone2=htmlentities($_POST['timezone2']);
    $offset=get_timezone_offset($timezone2);
}
if(isset($_GET['page2'])) {
?>
<form method=post action=?page2>
<select name=timezone2>
<?php foreach($options as $key=>$value) echo "\t".'<option value="'. $key .'"'.(get_timezone_offset($key)==$offset?' selected':'').'>'.$value.'</option>'."\n"; ?>
</select>
<input type=hidden name=location type="text" value="<?php echo $_POST['location']; ?>"/>
</div>
<input type=submit value=Search>
</form>
<p>Current Offset: <?php echo $offset/3600; ?></p>
<p>Current Time: <?php echo gmdate('Y-m-d H:i:s'); ?> UTC</p>
<p>Current Time: <?php echo gmdate('Y-m-d H:i:s', time()+$offset).' '. $timezone2; ?> </p>
<?php
} else {
?>
<form method=post action=?page2>
<input name=location type=text value=""/>
<button type=submit>Search</button>
</form>

<?php
}
?>

我已经对此进行了测试并知道它有效,如果这还不足以回答你的问题,那么我就放弃了。我开始认为你真的想要一种方法来发明不存在的新时区。那是不可能的。你可以将已存在的那些已经存在,就像我在这里所做的那样,它就像你将要获得的那样接近。从逻辑上讲,时区的范围只能在-12:00到+12:00之间,几乎每个已知的时区都已经计算好了,所以如果这还不够,你别无选择,只能重新考虑你的设计。