我正在运行一个PHP脚本,并继续收到错误,如:

注意:未定义变量my_variable_name在C:\wamp\www\mypath\index.php第10行 注意:第11行未定义索引:my_index C:\wamp\www\mypath\index.php 警告:在C:\wamp\www\mypath\index.php第11行未定义数组键“my_index”

第10和11行是这样的:

echo "My variable value is: " . $my_variable_name;
echo "My index value is: " . $my_array["my_index"];

这些错误消息的含义是什么?

为什么他们会突然出现?我曾经使用这个脚本多年,从来没有任何问题。

我该如何修复它们?


这是一个一般参考问题,供人们链接作为副本,而不是需要一遍又一遍地解释这个问题。我觉得这很有必要,因为现实世界中关于这个问题的答案都非常具体。 相关元讨论: 如何应对重复的问题? “参考问题”有意义吗?


当前回答

错误显示@操作符

对于不需要的和多余的通知,可以使用专用的@操作符来»隐藏«未定义的变量/索引消息。

$var = @($_GET["optional_param"]);

这通常是不鼓励的。新人往往会过度使用它。 对于应用程序逻辑深处的代码(忽略不应该声明的未声明变量)是非常不合适的,例如函数参数或循环中。 isset有一个好处?:或??然而super-supression。通知仍然可以被记录。可以使用set_error_handler("var_dump")来恢复@-hidden通知; 另外,你不应该在初始代码中习惯性地使用/recommend if (isset($_POST["shubmit"]))。 新人不会发现这样的错别字。它只是剥夺了这些情况下的php注意。仅在验证功能后添加@或isset。 首先解决原因。不是通知。 @主要用于$_GET/$_POST输入参数,特别是在它们是可选的情况下。

既然这涵盖了大多数这样的问题,让我们扩展一下最常见的原因:

$_GET / $_POST / $_REQUEST未定义输入

当遇到未定义的索引/偏移量时,你要做的第一件事是检查错字: $count = $_GET["whatnow?"]; 这是每个页面请求中所期望的键名吗? 变量名和数组索引在PHP中是区分大小写的。 其次,如果通知没有明显的原因,使用var_dump或print_r来验证所有输入数组的当前内容: var_dump ($ _GET); var_dump ($ _POST); / / print_r ($ _REQUEST); 两者都将揭示您的脚本是否使用了正确的参数或任何参数调用。 或者使用你的浏览器devtools (F12)检查network选项卡中的请求和参数: POST参数和GET输入将分别显示。 对于$_GET参数,还可以查看中的QUERY_STRING _SERVER print_r (); PHP有一些规则来将非标准参数名称合并到超全局参数中。Apache也可能会进行一些重写。 您还可以以这种方式查看提供的原始$_COOKIES和其他HTTP请求标头。 更明显的是查看浏览器地址栏的GET参数: http://example.org/script.php?id=5&sort=desc name=value在?问号是查询(GET)参数。因此,这个URL可能只会产生$_GET["id"]和$_GET["sort"]。 最后检查你的<form>和<input>声明,如果你期望一个参数但没有收到。 确保每个必需的输入都有一个<input name=FOO> id=或title=属性是不够的。 method=POST表单应该填充$_POST。 而method=GET(或省略它)将产生$_GET变量。 表单也可以提供action=script.php?get=param通过$_GET和剩余的方法=POST字段在$_POST旁边。 对于现代PHP配置(≥5.6),再次使用$_REQUEST['vars']已经变得可行(不流行),它将GET和POST参数混在一起。 如果你正在使用mod_rewrite,那么你应该检查access.log以及启用RewriteLog来找出缺失的参数。

带有_file美元

同样的健全检查适用于文件上传和$_FILES["formname"]。 此外,检查enctype=multipart/form-data 以及<form>声明中的method=POST。 参见:PHP未定义索引错误$_FILES?

$ _COOKIE

$_COOKIE数组永远不会在setcookie()之后填充,而只在后续的HTTP请求中填充。 此外,它们的有效性会超时,它们可以被限制在子域或单个路径上,用户和浏览器可以拒绝或删除它们。

其他回答

抛出未定义索引通知的另一个原因是数据库查询中遗漏了一列。

例如:

$query = "SELECT col1 FROM table WHERE col_x = ?";

然后尝试访问循环中的更多列/行。

例如:

print_r($row['col1']);
print_r($row['col2']); // undefined index thrown

或者在while循环中:

while( $row = fetching_function($query) ) {

    echo $row['col1'];
    echo "<br>";
    echo $row['col2']; // undefined index thrown
    echo "<br>";
    echo $row['col3']; // undefined index thrown

}

另外需要注意的是,在*NIX操作系统和Mac OS X上,事情是区分大小写的。

参考Stack上的以下问答:

MySQL中的表名是否区分大小写? Mysql查询中区分大小写的表名 MySql -表在不同服务器中的大小写敏感问题

错误显示@操作符

对于不需要的和多余的通知,可以使用专用的@操作符来»隐藏«未定义的变量/索引消息。

$var = @($_GET["optional_param"]);

这通常是不鼓励的。新人往往会过度使用它。 对于应用程序逻辑深处的代码(忽略不应该声明的未声明变量)是非常不合适的,例如函数参数或循环中。 isset有一个好处?:或??然而super-supression。通知仍然可以被记录。可以使用set_error_handler("var_dump")来恢复@-hidden通知; 另外,你不应该在初始代码中习惯性地使用/recommend if (isset($_POST["shubmit"]))。 新人不会发现这样的错别字。它只是剥夺了这些情况下的php注意。仅在验证功能后添加@或isset。 首先解决原因。不是通知。 @主要用于$_GET/$_POST输入参数,特别是在它们是可选的情况下。

既然这涵盖了大多数这样的问题,让我们扩展一下最常见的原因:

$_GET / $_POST / $_REQUEST未定义输入

当遇到未定义的索引/偏移量时,你要做的第一件事是检查错字: $count = $_GET["whatnow?"]; 这是每个页面请求中所期望的键名吗? 变量名和数组索引在PHP中是区分大小写的。 其次,如果通知没有明显的原因,使用var_dump或print_r来验证所有输入数组的当前内容: var_dump ($ _GET); var_dump ($ _POST); / / print_r ($ _REQUEST); 两者都将揭示您的脚本是否使用了正确的参数或任何参数调用。 或者使用你的浏览器devtools (F12)检查network选项卡中的请求和参数: POST参数和GET输入将分别显示。 对于$_GET参数,还可以查看中的QUERY_STRING _SERVER print_r (); PHP有一些规则来将非标准参数名称合并到超全局参数中。Apache也可能会进行一些重写。 您还可以以这种方式查看提供的原始$_COOKIES和其他HTTP请求标头。 更明显的是查看浏览器地址栏的GET参数: http://example.org/script.php?id=5&sort=desc name=value在?问号是查询(GET)参数。因此,这个URL可能只会产生$_GET["id"]和$_GET["sort"]。 最后检查你的<form>和<input>声明,如果你期望一个参数但没有收到。 确保每个必需的输入都有一个<input name=FOO> id=或title=属性是不够的。 method=POST表单应该填充$_POST。 而method=GET(或省略它)将产生$_GET变量。 表单也可以提供action=script.php?get=param通过$_GET和剩余的方法=POST字段在$_POST旁边。 对于现代PHP配置(≥5.6),再次使用$_REQUEST['vars']已经变得可行(不流行),它将GET和POST参数混在一起。 如果你正在使用mod_rewrite,那么你应该检查access.log以及启用RewriteLog来找出缺失的参数。

带有_file美元

同样的健全检查适用于文件上传和$_FILES["formname"]。 此外,检查enctype=multipart/form-data 以及<form>声明中的method=POST。 参见:PHP未定义索引错误$_FILES?

$ _COOKIE

$_COOKIE数组永远不会在setcookie()之后填充,而只在后续的HTTP请求中填充。 此外,它们的有效性会超时,它们可以被限制在子域或单个路径上,用户和浏览器可以拒绝或删除它们。

关于这部分问题:

为什么他们会突然出现?我曾经使用这个脚本多年,从来没有任何问题。

没有明确的答案,但这里有一些可能的解释,为什么设置可以“突然”改变:

您已经将PHP升级到一个新的版本,该版本可以为error_reporting、display_errors或其他相关设置设置其他默认值。 您已经删除或引入了一些在运行时使用ini_set()或error_reporting()设置相关设置的代码(可能是在依赖项中)(在代码中搜索这些代码) 你改变了web服务器配置(假设这里是apache): .htaccess文件和vhost配置也可以操作php设置。 通常通知不会被显示/报告(参见PHP手册) 因此,在设置服务器时,php.ini文件可能因为某些原因(文件权限??)而无法加载,而您使用的是默认设置。稍后,“错误”已经解决(意外),现在它可以加载正确的php.ini文件与error_reporting设置显示通知。

在回答“为什么他们突然出现?”我使用这个脚本很多年了,从来没有遇到过任何问题。”

对于大多数网站来说,在“默认”错误报告下操作是很常见的,“显示所有错误,但不显示‘通知’和‘已弃用’”。这将在php.ini中设置,并应用于服务器上的所有站点。这意味着示例中使用的那些“通知”将被抑制(隐藏),而其他被认为更严重的错误将被显示/记录。

另一个关键设置是可以隐藏错误(即display_errors设置为“off”或“syslog”)。

在这种情况下发生的情况是,error_reporting被更改为也显示通知(如示例所示)和/或设置被更改为屏幕上的display_errors(而不是抑制它们/记录它们)。

他们为什么改变了?

最明显/最简单的答案是有人在PHP .ini中调整了这些设置之一,或者PHP的升级版本现在使用与以前不同的PHP .ini。这是首先要看的地方。

但是,也可以覆盖这些设置

.htconf (webserver配置,包括vhosts和子配置 . htaccess 在PHP代码中

这些都可以被改变。

还有一个额外的复杂性,web服务器配置可以启用/禁用。htaccess指令,所以如果你的。htaccess指令突然启动/停止工作,那么你需要检查它。

(.Htconf / .htaccess假设你以apache运行。如果运行命令行,这将不适用;如果运行IIS或其他web服务器,则需要相应地检查这些配置)

总结

检查php.ini中的error_reporting和display_errors php指令是否更改,或者您使用的php.ini与以前不同。 检查error_reporting和display_errors php指令在.htconf(或vhosts等)没有改变 检查error_reporting和display_errors php指令在.htaccess中没有改变 如果你在.htaccess中有指令,检查它们在.htconf文件中是否仍然被允许 最后检查你的代码;可能是一个不相关的库;查看error_reporting和display_errors PHP指令是否已经设置在那里。

HTML表单提交后变量不存在的一个常见原因是表单元素没有包含在<form>标记中:

示例:<表单>中不包含的元素

<form action="example.php" method="post">
    <p>
        <input type="text" name="name" />
        <input type="submit" value="Submit" />
    </p>
</form>

<select name="choice">
    <option value="choice1">choice 1</option>
    <option value="choice2">choice 2</option>
    <option value="choice3">choice 3</option>
    <option value="choice4">choice 4</option>
</select>

示例:元素现在包含在<表单>中

<form action="example.php" method="post">
    <select name="choice">
        <option value="choice1">choice 1</option>
        <option value="choice2">choice 2</option>
        <option value="choice3">choice 3</option>
        <option value="choice4">choice 4</option>
    </select>
    <p>
        <input type="text" name="name" />
        <input type="submit" value="Submit" />
    </p>
</form>