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


Fatal error: Uncaught PHP exception in DateTimeZone::__construct()?

这将有点难以解释,但我会尽我所能解释清楚。

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

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中实际存在时区London时,如果我直接在select表单中输入/搜索London,它将回显该时区的当前时间,但如果在page1.php的输入文本字段中输入时区名称并将其传递到page2.php的select表单,则不会!

这是我在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
?>

这是第2.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>

有人能给我指正确的方向吗?

由于以下几个原因,您会出错。首先,可能的时区列表是有限的,所以去掉文本字段,只使用下拉列表。

其次,您可以删除/重命名下拉列表中的项目,但请记住,由于您保存的是偏移量,而不是tz名称,因此永远无法返回(如果您使用它,我的示例将向您展示确切的原因)。通常,最好存储名称而不是偏移量,这样您就可以正确管理夏令时。你会注意到,为了让这个系统正常工作,我需要调用日期("I")来确定它是否是夏令时,这真的很糟糕(仅仅因为它在我的服务器TZ中是夏令时并不意味着它在用户TZ中)。如果你保存了TZ名称,你可以将该逻辑推迟到PHP,只使用当前的偏移量。在这个简单的例子中,这似乎并不重要,但如果你试图存储偏移量或使用它计算未来''过去的时间,你肯定会遇到麻烦。

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

我已经重写了你的代码,使其更好一点,并在你使用它时实际工作,但我遗漏了一些细节(比如混淆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>';
?>

EDIT:还有一点需要注意,PHP的timezone_name_from_abbr()函数并不完整。某些时区偏移不会返回时区名称。你也必须对此作出解释。例如,尽管PHP了解"太平洋/中途岛"时区,但在进行反向查找时却找不到它。我已经更新了代码,这样就不会再出现硬错误了。

第二版:我看得出来,除非有人教你如何发光,否则你不会快乐。给你:

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。如果你不想更改任何内容,这几乎是一个答案。事实是,你的逻辑一开始就有缺陷(这不是一个刺拳,但这是真的)。

第三版: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之间,而且几乎所有已知的时区都已经被考虑在内,所以如果这还不够,你真的别无选择,只能重新考虑你的设计。