使用$_POST时出现未定义的索引问题

49

我正在努力重新学习一些PHP基础知识,以便制作一个简单的登录脚本。然而,我遇到了一个之前没有遇到过的错误(我在一年多前做过同样的脚本,从未遇到这种错误)。我尽可能地简化了代码,以测试哪个区域有问题,这里是问题所在:

<?php
$user = $_POST["username"];
if($user != null)
{
    echo $user;
    echo " is your username";
}
else
{
    echo "no username supplied";
}
?>

现在当我向脚本发送一个变量时,这段代码可以正常工作,但当没有提供变量时,它会抛出错误。理论上这是可以接受的,因为如果没有提供用户名/密码,则应该会出现错误。在将代码发送到脚本之前,我将检查以确保这一点,但我担心空字符串可能会泄漏并导致一些未知的错误。下面是我得到的错误:

( ! ) Notice: Undefined index: username in C:\wamp\www\verify_login.php on line 2

Call Stack

    Time    Memory  Function    Location
1   0.0003  668576  {main}( )   ..\verify_login.php:0

未提供用户名

如您所见,该代码注册了未提供变量,但是它发出错误,我认为这意味着在期望找到一个变量时没有找到一个变量或类似的情况。请问有人可以为我澄清一下吗?


请发布表单的代码。看起来_POST [username]未设置。 - Paul Dessert
因为如果你做的都是正确的,你只是在HTML页面方法中命名为“get”,并且你正在使用“$_POST”捕获参数。你需要将其重命名为$_GET。就这样。 - CodeToLife
10个回答

75
在PHP中,一个从未被设置过的变量或数组元素与其值为null的不同;试图访问这样的未设置值是一个运行时错误。
这就是你遇到的问题:数组$_POST在键"username"上没有任何元素,所以解释器在到达nullity测试之前就终止了你的程序。
幸运的是,你可以测试变量或数组元素是否存在,而不必实际尝试访问它;这就是特殊的isset操作符所做的事情。
if (isset($_POST["username"]))
{
  $user = $_POST["username"];
  echo $user;
  echo " is your username";
} 
else 
{
  $user = null;
  echo "no username supplied";
}

您的代码看起来会以完全相同的方式崩溃,因为PHP尝试获取$_POST ["username"]的值作为传递给函数isset()的参数。然而,isset()实际上并不是一个真正的函数,而是在评估阶段之前识别的特殊语法,因此PHP解释器检查该值的存在性,而不会尝试检索它。

值得一提的是,在运行时错误方面,缺少数组元素被认为是较小的错误(分配了E_NOTICE级别)。如果更改error_reporting级别以忽略通知,则您的原始代码实际上将按原样工作,并且尝试访问数组将返回null。但这被认为是不良做法,特别是对于生产代码。

顺便说一句:PHP进行字符串插值,因此if块中的echo语句可以合并为一个:

echo "$user is your username";

6
谢谢。非常详细但简单易懂的回答了我为什么会出现这个错误以及如何解决它。我不仅想要一个“如何修复/消除此错误”的答案,我还想理解它,而您正是为我做到了这一点,谢谢。 - Xander Luciano
@ViperCode,你的$_POST["username"]变量没有被设置。 - Bender

7

使用:

if (isset($_POST['user'])) {
   //do something
}

但是你可能应该使用一些更合适的验证。尝试使用简单的正则表达式或来自Zend Framework或Symfony的坚实实现。

http://framework.zend.com/manual/en/zend.validate.introduction.html

http://symfony.com/doc/current/book/validation.html

或者甚至使用内置的过滤器扩展:

http://php.net/manual/en/function.filter-var.php

永远不要相信用户输入,要聪明地处理。不要相信任何东西。始终确保你接收到的是你预期的内容。如果应该是一个数字,请确保它确实是一个数字。

改进后的代码:

$user = filter_var($_POST['user'], FILTER_SANITIZE_STRING);
$isValid = filter_var($user, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => "/^[a-zA-Z0-9]+$/")));

if ($isValid) {
    // do something
}

清理和验证。


1
或者,您可以使用 array_key_exists($_POST,'user') - mpen
我喜欢你关于确保的说法。这基本上将是一个登录脚本,我计划使用mysql_real_escape(); 我相信这就是它的名称。用户名将是任何组合,密码应该只使用MD5,在发送到脚本之前在程序中进行哈希处理。另外,我应该注意这是游戏验证,而不是网站验证。 - Xander Luciano
1
永远不要使用mysql_real_escape()。了解预处理语句并开始使用PDO。http://php.net/manual/pdo.prepared-statements.php - vinnylinux
array_key_exists('user', $_POST) - Luke Pring

5
在 PHP 5.2.0 及以上版本之前,您应该使用 filter_input() 来获取特定的外部用户输入,如 get、post 或 cookie 变量,并可选择过滤它以避免您的网站受到任何 XSS/注入攻击。例如:
$user = filter_input(INPUT_POST, 'username');

你可以使用 INPUT_GET、INPUT_POST、INPUT_COOKIE、INPUT_SERVER 或 INPUT_ENV 中的一个。
通过使用可选的第三个参数,你可以使用各种过滤器(用于验证清理过滤其他),例如 FILTER_SANITIZE_SPECIAL_CHARSFILTER_SANITIZE_ENCODED 等等。
例如:
<?php
$search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
$search_url = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_ENCODED);
echo "You have searched for $search_html.\n";
echo "<a href='?search=$search_url'>Search again.</a>";
?>

语法如下:

mixed filter_input ( int $type , string $variable_name [, int $filter = FILTER_DEFAULT [, mixed $options ]] )

(PHP 5 >= 5.2.0, PHP 7)

另请参阅:为什么最好使用filter_input()?


5

你可以使用比 isset() 更短的方式来禁止错误输出,就是 @$_POST['field']。如果该字段未设置,则页面上不会显示任何错误。


3

你的代码假定了某个东西的存在:

$user = $_POST["username"];

PHP 提示您在 $_POST 数组中找不到“用户名”。在这种情况下,在尝试访问之前,最好使用 isset() 检查该值:

if ( isset( $_POST["username"] ) ) {
    /* ... proceed ... */
}

相反,您可以劫持||运算符来分配默认值:

$user = $_POST["username"] || "visitor" ;

只要用户的名称不是 falsy 值,你就可以认为这个方法非常可靠。更安全的默认赋值方法是使用三元运算符:
$user = isset( $_POST["username"] ) ? $_POST["username"] : "visitor" ;

2

试试这个:

我在任何需要 $_POST 请求的地方都使用它。

$username=isset($_POST['username']) ? $_POST['username'] : "";

这只是一个简写布尔值,如果isset,则将其设置为$ _POST ['username'],否则将其设置为空字符串。

用法示例:

if($username===""){ echo "Field is blank" } else { echo "Success" };

2
我知道这是一篇旧帖子,但希望有人能提供帮助:
function POST($index, $default=NULL){
        if(isset($_POST[$index]))
        {
            if(!empty(trim($_POST[$index])))    
                return $_POST[$index];
        }
        return $default;
    }

这是我常用的基础POST函数。您可以在此处添加过滤器、正则表达式等。这种方法更快速和干净。我的高级POST函数更为复杂,可以接受和检查数组、字符串类型、默认值等。在这里让您的想象力发挥吧。

您可以像这样轻松检查用户名:

$username = POST("username");
if($username!==null){
    echo "{$username} is in the house.";
}

还有,我添加了$default字符串,如果POST不活动或内容不存在,您可以定义一些默认值。

echo "<h1>".POST("title", "Stack Overflow")."</h1>";

试着使用它。


1

当你说:

$user = $_POST["username"];

您正在要求PHP解释器将$user赋值为具有键(或索引)为username$_POST数组的值。如果不存在,PHP会抛出异常。

使用isset($_POST['user'])来检查该变量是否存在:

if (isset($_POST['user'])) {
  $user = $_POST["username"];
  ...

谢谢,就像马克·里德解释的那样。 - Xander Luciano

0

尝试

if(isset($_POST['username']))
    echo $_POST['username']." is your username";
else
    echo "no username supplied";

1
谢谢。我以前没有遇到过这个错误,现在我明白了。 - Xander Luciano

-2

这在很多方面都是错误的… - vinnylinux
下投票者和@vinnylinux:为什么是错误的? - flowfree
可能是因为它没有产生OP想要的输出[username]是您的用户名(如果有影响的话,我不是那个点踩的人,所以原因可能不同)? - tigrang
@tigrang 什么?错了因为没有产生相同的字符串吗?顺便说一下,OP实际上是在问如何避免PHP注意事项,如果键不存在,而不是“如何输出此字符串”。 - flowfree
我告诉过你,我不知道 - 我不是其中一个downvoters。在阅读OP的问题后,他想要检查它是否设置,而不是真正的输出,OP想要检查它是否设置,因此也许需要修改您的答案为if (_arr($_POST, 'username', false)) { // do something }。您可能需要等待并查看downvote的真正原因。 - tigrang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接