“Notice: Undefined variable”, “Notice: Undefined index”, and “Notice: Undefined offset” using PHP
我正在运行一个PHP脚本,并继续收到以下错误:
Notice: Undefined variable: my_variable_name in C:\wamp\www\mypath\index.php on line 10
Notice: Undefined index: my_index C:\wamp\www\mypath\index.php on line 11
第10行和第11行如下:
1 2 | echo"My variable value is:" . $my_variable_name; echo"My index value is:" . $my_array["my_index"]; |
这些错误消息的含义是什么?
为什么它们突然出现?我使用这个脚本已经很多年了,我从来没有遇到过任何问题。
我怎么修理它们?
This is a General Reference question for people to link to as duplicate, instead of having to explain the issue over and over again. I feel this is necessary because most real-world answers on this issue are very specific.
Related Meta discussion:
- What can be done about repetitive questions?
- Do"reference questions" make sense?
注意:未定义的变量
从PHP手册的广博智慧来看:
Relying on the default value of an uninitialized variable is problematic in the case of including one file into another which uses the same variable name. It is also a major security risk with register_globals turned on. E_NOTICE level error is issued in case of working with uninitialized variables, however not in the case of appending elements to the uninitialized array. isset() language construct can be used to detect if a variable has been already initialized. Additionally and more ideal is the solution of empty() since it does not generate a warning or error message if the variable is not initialized.
从PHP文档:
No warning is generated if the variable does not exist. That means
empty() is essentially the concise equivalent to !isset($var) || $var
== false.
这意味着您只能使用
例子:
1 2 3 4 5 6 7 8 | $o = []; @$var = ["",0,null,1,2,3,$foo,$o['myIndex']]; array_walk($var, function($v) { echo (!isset($v) || $v == false) ? 'true ' : 'false'; echo ' ' . (empty($v) ? 'true' : 'false'); echo" "; }); |
在3v4l.org在线PHP编辑器中测试上述代码段
尽管php不需要变量声明,但它确实建议这样做,以避免某些安全漏洞或错误,因为人们会忘记为脚本中稍后将使用的变量提供值。php在未声明变量的情况下所做的是发出一个非常低级别的错误,
处理问题的方法:
建议:声明变量,例如,当您试图向未定义的变量附加字符串时。或者使用
1 2 3 4 5 6 7 8 |
与php 7.0相比,这变得更干净了,现在您可以使用空的coalesce操作符:
1 2 | // Null coalesce operator - No need to explicitly initialize the variable. $value = $_POST['value'] ?? ''; |
为e_notice设置自定义错误处理程序,并将消息重定向到远离标准输出的位置(可能是指向日志文件):
1 |
禁止电子通知报告。一种快速排除
1 |
使用@运算符取消错误。
注意:强烈建议只执行第1点。
注意:未定义的索引/未定义的偏移量当您(或PHP)尝试访问数组的未定义索引时,会出现此通知。
处理问题的方法:
在访问索引之前检查它是否存在。为此,您可以使用
1 2 3 4 | //isset() $value = isset($array['my_index']) ? $array['my_index'] : ''; //array_key_exists() $value = array_key_exists('my_index', $array) ? $array['my_index'] : ''; |
当语言构造
两个变量用于访问两个数组元素,但是只有一个数组元素index
Notice: Undefined offset: 1
上述通知通常在与
还要注意,所有3个变量都是超全局变量,并且都是大写的。
相关:
- 注意:未定义的变量
- 注意:未定义的索引
试试这些
Q1: this notice means $varname is not
defined at current scope of the
script.Q2: Use of isset(), empty() conditions before using any suspicious variable works well.
1 2 3 4 5 6 7 8 | // recommended solution for recent PHP versions $user_name = $_SESSION['user_name'] ?? ''; // pre-7 PHP versions $user_name = ''; if (!empty($_SESSION['user_name'])) { $user_name = $_SESSION['user_name']; } |
或者,作为一种快速而肮脏的解决方案:
1 2 3 | // not the best solution, but works // in your php setting use, it helps hiding site wide notices error_reporting(E_ALL ^ E_NOTICE); |
关于会话的说明:
使用会话时,需要将
session_start(); 放在所有使用会话的文件中。http://php.net/manual/en/features.sessions.php
错误显示
对于不需要的和多余的通知,可以使用专用的
1 | $var = @($_GET["optional_param"]); |
- 这通常是不鼓励的。新来的人往往过度使用它。
- 对于应用程序逻辑中的深层代码(忽略不应声明的变量),例如函数参数或循环中的代码,这是非常不合适的。
- 不过,与
isset?: 或?? 超级抑制相比,还有一个优势。通知仍然可以被记录。可以用:set_error_handler("var_dump"); 恢复@ 隐藏的告示。- 另外,您不应该习惯性地在初始代码中使用/推荐
if (isset($_POST["shubmit"])) 。 - 新来者不会发现这样的打字错误。它只是剥夺了你对这些案件的PHP通知。只有在验证功能后才添加
@ 或isset 。 -
Fix the cause first. Not the notices.
- 另外,您不应该习惯性地在初始代码中使用/推荐
@ 主要用于$_GET /$_POST 输入参数,特别是在可选的情况下。
既然这涵盖了大多数这样的问题,那么让我们进一步讨论最常见的原因:
当遇到未定义的索引/偏移量时,首先要检查是否有错别字:
$count = $_GET["whatnow?"]; - 这是一个预期的键名,并出现在每个页面请求中吗?
- 在PHP中,变量名和数组指示符区分大小写。
其次,如果通知没有明显原因,则使用
var_dump 或print_r 验证所有输入数组的当前内容:两者都将显示您的脚本是使用正确的参数还是使用任何参数调用的。
交替或另外使用浏览器开发工具(F12)并检查"网络"选项卡中的请求和参数:
post参数和get输入将分别显示。
对于
$_GET 参数,您还可以在中查看QUERY_STRING 。1PHP有一些规则可以将非标准参数名合并为超全局参数。Apache也可以进行一些重写。您还可以通过这种方式查看提供的原始
$_COOKIES 和其他HTTP请求头。更明显的是,查看浏览器地址栏以获取参数:
OCx1〔21〕
? 问号后面的name=value 对是您的查询(get)参数。因此,该URL只能生成$_GET["id"] 和$_GET["sort"] 。最后检查您的
和
声明,如果您希望参数,但没有收到参数。 - 确保每个必需的输入都有一个
。 id= 或title= 属性不足够。method=POST 表格应填写$_POST 。- 而一个
method=GET (或不加)将产生$_GET 变量。 - 表单还可以通过$GET提供
action=script.php?get=param ,旁边还有$POST中的其余method=POST 字段。 - 在现代PHP配置中(≥5.6),再次使用
$_REQUEST['vars'] 已经变得可行(不流行),它混合了get和post参数。
- 确保每个必需的输入都有一个
如果您使用的是mod-rewrite,那么您应该检查
access.log ,并使RewriteLog 能够找出不存在的参数。
- 同样的健全性检查也适用于文件上传和
$_FILES["formname"] 。 - 另外检查
enctype=multipart/form-data 。 - 以及你的
声明中的
method=POST 。 - 另请参见:php未定义索引错误$u文件?
$_COOKIE 数组永远不会在setcookie() 之后填充,但只能在任何后续HTTP请求上填充。- 此外,它们的有效性超时,它们可能是子域或单个路径的约束,用户和浏览器可以拒绝或删除它们。
一般是因为"编程不好",而且可能会出现现在或以后的错误。
这意味着您正在测试、评估或打印尚未分配任何内容的变量。这意味着您要么输入错误,要么需要先检查变量是否已初始化为某个值。检查您的逻辑路径,它可以在一个路径中设置,但不能在另一个路径中设置。
我不想禁用通知,因为它很有用,但我想避免输入太多内容。
我的解决方案是这个函数:
1 2 3 4 |
因此,如果我想引用$name和echo(如果存在),我只需写下:
1 | <?=ifexists('name')?> |
对于数组元素:
1 2 3 4 |
在第页中,如果我想引用"$U REQUEST[‘name’]":
1 | <?=ifexistsidx($_REQUEST,'name')?> |
获取输入字符串的最佳方法是:
1 |
这一衬垫几乎等同于:
1 2 3 4 5 6 7 |
如果您绝对想要字符串值,就像:
1 |
回答"为什么它们突然出现?我使用这个脚本已经很多年了,我从来没有遇到过任何问题。"
对于大多数站点来说,在"显示所有错误,但不显示‘通知’和‘不推荐’的‘默认’错误报告"下操作是很常见的。这将在php.ini中设置,并应用于服务器上的所有站点。这意味着示例中使用的那些"通知"将被抑制(隐藏),而其他被认为更重要的错误将被显示/记录。
另一个关键设置是可以隐藏错误(即
在这种情况下会发生的情况是,要么
他们为什么变了?
显而易见/最简单的答案是,有人在php.ini中调整了这些设置,或者升级后的php版本现在使用的是与以前不同的php.ini。那是第一个看的地方。
但是,也可以在
- .htconf(Web服务器配置,包括vhosts和子配置)*
- HTAccess
- 在PHP代码中
其中任何一个也可能被改变。
还有一个额外的复杂性,即Web服务器配置可以启用/禁用.htaccess指令,因此如果在.htaccess中有突然启动/停止工作的指令,则需要检查它。
(.htconf/.htaccess假定您以apache身份运行。如果运行命令行,则不适用;如果运行IIS或其他Web服务器,则需要相应地检查这些配置)
总结
- 检查php.ini中的
error_reporting 和display_errors php指令没有更改,或者您没有使用与以前不同的php.ini。 - 检查.htconf(或vhosts等)中的
error_reporting 和display_errors php指令是否未更改。 - 检查.htaccess中的
error_reporting 和display_errors php指令没有更改。 - 如果在.htaccess中有指令,请检查.htconf文件中是否仍允许使用这些指令。
- 最后检查您的代码;可能是一个不相关的库;看看是否在那里设置了
error_reporting 和display_errors php指令。
因为变量"$user_location"未被定义。如果您使用的是任何if循环,其中声明了"$user_location"变量,那么您还必须有一个else循环并定义相同的变量。例如:
1 2 3 | $a=10; if($a==5) { $user_location='Paris';} else { } echo $user_location; |
上述代码将创建错误,因为if循环不满足,并且在else循环中未定义"$user_location"。仍然要求PHP回送变量。因此,要修改代码,必须执行以下操作:
1 2 3 | $a=10; if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; } echo $user_location; |
快速修复方法是在代码顶部将变量赋给空值。
1 | $user_location = null; |
我曾经诅咒过这个错误,但是提醒你避开用户输入是很有帮助的。
例如,如果您认为这是一个聪明的速记代码:
1 2 | // Echo whatever the hell this is <?=$_POST['something']?> |
…再想想!更好的解决方案是:
1 2 | // If this is set, echo a filtered version <?=isset($_POST['something']) ? html($_POST['something']) : ''?> |
(我使用自定义的
我一直使用自己有用的函数exst(),它自动声明变量。
你的代码是-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | $greeting ="Hello,".exst($user_name, 'Visitor')." from".exst($user_location); /** * Function exst() - Checks if the variable has been set * (copy/paste it in any place of your code) * * If the variable is set and not empty returns the variable (no transformation) * If the variable is not set or empty, returns the $default value * * @param mixed $var * @param mixed $default * * @return mixed */ function exst( & $var, $default ="") { $t =""; if ( !isset($var) || !$var ) { if (isset($default) && $default !="") $t = $default; } else { $t = $var; } if (is_string($t)) $t = trim($t); return $t; } |
用一种非常简单的语言。
错误是你使用的是一个变量
或
这是一个很常见的错误,所以不用担心,只要声明变量并享受编码。
在php 7.0中,现在可以使用空合并运算符:
1 | echo"My index value is:" . ($my_array["my_index"] ?? ''); |
等于:
1 |
PHP手册PHP 7.0
为什么会这样?
随着时间的推移,PHP已经成为一种更加注重安全性的语言。以前默认情况下关闭的设置现在默认情况下打开。一个很好的例子是
此外,根据php文档,默认情况下,php.ini中禁用
1 2 3 4 5 6 7 8 9 10 | ; Common Values: ; E_ALL (Show all errors, warnings and notices including coding standards.) ; E_ALL & ~E_NOTICE (Show all errors, except for notices) ; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) ; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) ; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED ; Development Value: E_ALL ; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT ; http://php.net/error-reporting error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT |
注意,
但是,要回答您的问题,此错误在以前未出现时会立即出现,因为:好的。
您安装的PHP和新的默认设置的文档记录比较差,但不排除
我该怎么办?
通过复制"默认值"
在文件或文件夹级别上关闭
重写代码以使其更干净。如果您在移动到生产环境时需要这样做,或者不希望有人看到您的错误,请确保您禁用了任何错误显示,并且只记录错误(请参阅php.ini中的
扩展选项3:这是理想的。如果你能走这条路,你应该走。如果您最初不走这条路,请考虑最终通过在开发环境中测试代码来移动这条路。当你这样做的时候,去掉
1 2 3 4 5 6 7 8 9 10 | function foo() { $my_variable_name = ''; //.... if ($my_variable_name) { // perform some logic } } |
1 2 3 4 5 6 7 8 | // verbose way - generally better if (isset($my_array['my_index'])) { echo"My index value is:" . $my_array['my_index']; } // non-verbose ternary example - I use this sometimes for small rules. $my_index_val = isset($my_array['my_index'])?$my_array['my_index']:'(undefined)'; echo"My index value is:" . $my_index_val; |
另一个选项是在函数顶部声明一个空数组。这并不总是可能的。好的。
1 2 3 4 5 6 7 |
(附加提示)
- 当我遇到这些和其他问题时,我使用了NetBeansIDE(免费),它给了我很多警告和通知。其中一些提供了非常有用的提示。这不是一个需求,除了大型项目之外,我不再使用IDES。我现在更像是一个江户人。
好啊。
为什么不保持简单呢?
1 2 3 4 5 6 7 8 9 10 11 | <?php error_reporting(E_ALL); // making sure all notices are on function idxVal(&$var, $default = null) { return empty($var) ? $var = $default : $var; } echo idxVal($arr['test']); // returns null without any notice echo idxVal($arr['hey ho'], 'yo'); // returns yo and assigns it to array index, nice ?> |
例如,未定义的索引表示在您为不可用的数组索引请求的数组中
1 2 3 4 5 6 |
未定义的变量意味着您使用了完全不存在的变量,或者未使用该名称定义或初始化的变量,例如
1 |
未定义的偏移量意味着在数组中您请求了不存在的键。以及解决方法是使用前检查
1 |
关于这部分问题:
Why do they appear all of a sudden? I used to use this script for years and I've never had any problem.
没有明确的答案,但这里有一些可能的解释为什么设置可以"突然"改变:
您已经将php升级到一个更新的版本,该版本可以具有其他错误报告、显示错误或其他相关设置的默认值。
您删除或引入了一些代码(可能是依赖项),这些代码使用
您更改了Web服务器配置(假设这里是Apache):
通常通知不会显示/报告(请参阅PHP手册)因此,在设置服务器时,可能由于某种原因(文件权限)无法加载php.ini文件。?)您使用的是默认设置。稍后,"bug"已被解决(意外),现在它可以加载正确的php.ini文件,并将错误报告设置为显示通知。
如果使用类,则需要确保使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Person { protected $firstName; protected $lastName; public function setFullName($first, $last) { // Correct $this->firstName = $first; // Incorrect $lastName = $last; // Incorrect $this->$lastName = $last; } } |
引发未定义索引通知的另一个原因是数据库查询中省略了列。
即。:
1 | $query ="SELECT col1 FROM table WHERE col_x = ?"; |
然后尝试访问循环中的更多列/行。
即。:
或在
1 2 3 4 5 6 7 8 9 | while( $row = fetching_function($query) ) { echo $row['col1']; echo""; echo $row['col2']; // undefined index thrown echo""; echo $row['col3']; // undefined index thrown } |
需要注意的是,在*nix OS和mac OS X上,情况区分大小写。
请参阅堆栈上的以下问答:
mysql中的表名是否区分大小写?
查询中的MySQL区分大小写表名
mysql-不同服务器中表的区分大小写问题
使用三元是简单、易读和干净的:
PHP前7将变量赋给另一个变量的值(如果已设置),否则赋给
1 |
PHP 7 +除使用空合并运算符外,其他方法相同。不再需要调用
1 | $newVariable = $thePotentialData ?? null; |
这两种方法都将阻止操作问题中的通知,并且两者完全等同于:
1 2 3 4 5 |
nbsp;如果不需要设置新变量,则可以直接使用三元的返回值,如与
艾可:
1 |
功能:
1 2 3 4 5 6 7 8 | $foreName = getForeName(isset($userId) ? $userId : null); function getForeName($userId) { if ($userId === null) { // Etc } } |
上面对数组(包括会话等)的作用是相同的,将被检查的变量替换为,例如:
nbsp;
抑制:
使用
您真的应该检查这个问题并适当地处理它,或者提供一个不同的消息,或者甚至只是返回一个空值来标识精确的状态。
如果您只关心通知不在错误日志中,那么作为一个选项,您可以忽略错误日志。
每当我们使用未设置的变量时,就会发生这些错误。
处理这些问题的最佳方法是在开发过程中设置错误报告。
要设置错误报告,请执行以下操作:
1 2 3 |
在生产服务器上,错误报告是关闭的,因此,我们不会得到这些错误。
但是,在开发服务器上,我们可以在上设置错误报告。
为了消除此错误,我们看到以下示例:
1 2 3 4 | if ($my == 9) { $test = 'yes'; // Will produce error as $my is not 9. } echo $test; |
我们可以在分配或使用变量值之前将变量初始化为
因此,我们可以将代码修改为:
1 2 3 4 5 | $test = NULL; if ($my == 9) { $test = 'yes'; // Will produce error as $my is not 9. } echo $test; |
即使
所以,基本上,为开发设置错误报告总是更好的。
修复所有错误。
在生产中,错误报告应设置为关闭。
可能你以前使用的是旧的PHP版本,现在升级了PHP,这就是为什么从现在开始它一直在工作而没有任何错误的原因。在php4之前,如果您使用变量而不定义它,则不会出现错误,但是在php5之后,它会为问题中提到的代码抛出错误。
处理文件时,需要一个适当的enctype和post方法,如果表单中没有包含这两个方法之一,则会触发一个未定义的索引通知。
本手册规定了以下基本语法:
HTML
1 2 3 4 5 6 7 8 | <!-- The data encoding type, enctype, MUST be specified as below --> <form enctype="multipart/form-data" action="__URL__" method="POST"> <!-- MAX_FILE_SIZE must precede the file input field --> <input type="hidden" name="MAX_FILE_SIZE" value="30000" /> <!-- Name of input element determines name in $_FILES array --> Send this file: <input name="userfile" type="file" /> <input type="submit" value="Send File" /> </form> |
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php // In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used instead // of $_FILES. $uploaddir = '/var/www/uploads/'; $uploadfile = $uploaddir . basename($_FILES['userfile']['name']); echo '[cc lang="php"]'; if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { echo"File is valid, and was successfully uploaded. "; } else { echo"Possible file upload attack! "; } echo 'Here is some more debugging info:'; print_r($_FILES); print" |
;?>< /代码>
参考文献:
- http://php.net/manual/en/features.file-upload.post-method.php
提交HTML表单后变量不存在的一个常见原因是表单元素不包含在