"Notice: Undefined variable", "Notice: Undefined index", and "Notice: Undefined offset" using PHP
I’m running a PHP script and continue to receive errors like:
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
Line 10 and 11 looks like this:
echo "My variable value is: " . $my_variable_name; echo "My index value is: " . $my_array["my_index"];
What is the meaning of these error messages?
Why do they appear all of a sudden? I used to use this script for years and I’ve never had any problem.
How do I fix them?
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:
Notice: Undefined variable
From the vast wisdom of the PHP Manual:
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.
From PHP documentation:
No warning is generated if the variable does not exist. That means empty() is essentially the concise equivalent to !isset($var) || $var == false.
This means that you could use only empty()
to determine if the variable is set, and in addition it checks the variable against the following, 0
, 0.0
, ""
, "0"
, null
, false
or []
.
Example:
$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 "\n"; });
Test the above snippet in the 3v4l.org online PHP editor
Although PHP does not require a variable declaration, it does recommend it in order to avoid some security vulnerabilities or bugs where one would forget to give a value to a variable that will be used later in the script. What PHP does in the case of undeclared variables is issue a very low level error, E_NOTICE
, one that is not even reported by default, but the Manual advises to allow during development.
Ways to deal with the issue:
-
Recommended: Declare your variables, for example when you try to append a string to an undefined variable. Or use
isset()
/!empty()
to check if they are declared before referencing them, as in://Initializing variable $value = ""; //Initialization value; Examples //"" When you want to append stuff later //0 When you want to add numbers later //isset() $value = isset($_POST['value']) ? $_POST['value'] : ''; //empty() $value = !empty($_POST['value']) ? $_POST['value'] : '';
This has become much cleaner as of PHP 7.0, now you can use the null coalesce operator:
// Null coalesce operator - No need to explicitly initialize the variable. $value = $_POST['value'] ?? '';
-
Set a custom error handler for E_NOTICE and redirect the messages away from the standard output (maybe to a log file):
set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
-
Disable E_NOTICE from reporting. A quick way to exclude just
E_NOTICE
is:error_reporting( error_reporting() & ~E_NOTICE )
-
Suppress the error with the @ operator.
Note: It’s strongly recommended to implement just point 1.
Notice: Undefined index / Undefined offset
This notice appears when you (or PHP) try to access an undefined index of an array.
Ways to deal with the issue:
-
Check if the index exists before you access it. For this you can use
isset()
orarray_key_exists()
://isset() $value = isset($array['my_index']) ? $array['my_index'] : ''; //array_key_exists() $value = array_key_exists('my_index', $array) ? $array['my_index'] : '';
-
The language construct
list()
may generate this when it attempts to access an array index that does not exist:list($a, $b) = array(0 => 'a'); //or list($one, $two) = explode(',', 'test string');
Two variables are used to access two array elements, however there is only one array element, index 0
, so this will generate:
Notice: Undefined offset: 1
$_POST
/ $_GET
/ $_SESSION
variable
The notices above appear often when working with $_POST
, $_GET
or $_SESSION
. For $_POST
and $_GET
you just have to check if the index exists or not before you use them. For $_SESSION
you have to make sure you have the session started with session_start()
and that the index also exists.
Also note that all 3 variables are superglobals and are uppercase.
Related:
Try these
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.
// 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']; }
Or, as a quick and dirty solution:
// not the best solution, but works // in your php setting use, it helps hiding site wide notices error_reporting(E_ALL ^ E_NOTICE);
Note about sessions:
-
When using sessions,
session_start();
is required to be placed inside all files using sessions.
Error display @
operator
For undesired and redundant notices, one could use the dedicated @
operator to »hide« undefined variable/index messages.
$var = @($_GET["optional_param"]);
- This is usually discouraged. Newcomers tend to way overuse it.
- It’s very inappropriate for code deep within the application logic (ignoring undeclared variables where you shouldn’t), e.g. for function parameters, or in loops.
- There’s one upside over the
isset?:
or??
super-supression however. Notices still can get logged. And one may resurrect@
-hidden notices with:set_error_handler("var_dump");
- Additonally you shouldn’t habitually use/recommend
if (isset($_POST["shubmit"]))
in your initial code. - Newcomers won’t spot such typos. It just deprives you of PHPs Notices for those very cases. Add
@
orisset
only after verifying functionality. -
Fix the cause first. Not the notices.
- Additonally you shouldn’t habitually use/recommend
@
is mainly acceptable for$_GET
/$_POST
input parameters, specifically if they’re optional.
And since this covers the majority of such questions, let’s expand on the most common causes:
$_GET
/ $_POST
/ $_REQUEST
undefined input
-
First thing you do when encountering an undefined index/offset, is check for typos:
$count = $_GET["whatnow?"];
- Is this an expected key name and present on each page request?
- Variable names and array indicies are case-sensitive in PHP.
-
Secondly, if the notice doesn’t have an obvious cause, use
var_dump
orprint_r
to verify all input arrays for their curent content:var_dump($_GET); var_dump($_POST); //print_r($_REQUEST);
Both will reveal if your script was invoked with the right or any parameters at all.
-
Alternativey or additionally use your browser devtools (F12) and inspect the network tab for requests and parameters:
POST parameters and GET input will be be shown separately.
-
For
$_GET
parameters you can also peek at theQUERY_STRING
inprint_r($_SERVER);
PHP has some rules to coalesce non-standard parameter names into the superglobals. Apache might do some rewriting as well. You can also look at supplied raw
$_COOKIES
and other HTTP request headers that way. -
More obviously look at your browser address bar for GET parameters:
http://example.org/script.php?id=5&sort=desc
The
name=value
pairs after the?
question mark are your query (GET) parameters. Thus this URL could only possibly yield$_GET["id"]
and$_GET["sort"]
. -
Finally check your
<form>
and<input>
declarations, if you expect a parameter but receive none.- Ensure each required input has an
<input name=FOO>
- The
id=
ortitle=
attribute does not suffice. - A
method=POST
form ought to populate$_POST
. - Whereas a
method=GET
(or leaving it out) would yield$_GET
variables. - It’s also possible for a form to supply
action=script.php?get=param
via $_GET and the remainingmethod=POST
fields in $_POST alongside. - With modern PHP configurations (≥ 5.6) it has become feasible (not fashionable) to use
$_REQUEST['vars']
again, which mashes GET and POST params.
- Ensure each required input has an
-
If you are employing mod_rewrite, then you should check both the
access.log
as well as enable theRewriteLog
to figure out absent parameters.
$_FILES
- The same sanity checks apply to file uploads and
$_FILES["formname"]
. - Moreover check for
enctype=multipart/form-data
- As well as
method=POST
in your<form>
declaration. - See also: PHP Undefined index error $_FILES?
$_COOKIE
- The
$_COOKIE
array is never populated right aftersetcookie()
, but only on any followup HTTP request. - Additionally their validity times out, they could be constraint to subdomains or individual paths, and user and browser can just reject or delete them.
Generally because of “bad programming”, and a possibility for mistakes now or later.
- If it’s a mistake, make a proper assignment to the variable first: $varname=0;
- If it really is only defined sometimes, test for it:
if (isset($varname))
, before using it - If it’s because you spelled it wrong, just correct that
- Maybe even turn of the warnings in you PHP-settings
It means you are testing, evaluating, or printing a variable that you have not yet assigned anything to. It means you either have a typo, or you need to check that the variable was initialized to something first. Check your logic paths, it may be set in one path but not in another.
I didn’t want to disable notice because it’s helpful, but wanted to avoid too much typing.
My solution was this function:
function ifexists($varname) { return(isset($$varname)?$varname:null); }
So if I want to reference to $name and echo if exists, I simply write:
<?=ifexists('name')?>
For array elements:
function ifexistsidx($var,$index) { return(isset($var[$index])?$var[$index]:null); }
In page if I want to refer to $_REQUEST[‘name’]:
<?=ifexistsidx($_REQUEST,'name')?>
The best way for getting input string is:
$value = filter_input(INPUT_POST, 'value');
This one-liner is almost equivalent to:
if (!isset($_POST['value'])) { $value = null; } elseif (is_array($_POST['value'])) { $value = false; } else { $value = $_POST['value']; }
If you absolutely want string value, just like:
$value = (string)filter_input(INPUT_POST, 'value');
Its because the variable ‘$user_location’ is not getting defined. If you are using any if loop inside which you are declaring the ‘$user_location’ variable then you must also have an else loop and define the same. For example:
$a=10; if($a==5) { $user_location='Paris';} else { } echo $user_location;
The above code will create error as The if loop is not satisfied and in the else loop ‘$user_location’ was not defined. Still PHP was asked to echo out the variable. So to modify the code you must do the following:
$a=10; if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; } echo $user_location;
In reply to “”Why do they appear all of a sudden? I used to use this script for years and I’ve never had any problem.”
It is very common for most sites to operate under the “default” error reporting of “Show all errors, but not ‘notices’ and ‘deprecated'”. This will be set in php.ini and apply to all sites on the server. This means that those “notices” used in the examples will be suppressed (hidden) while other errors, considered more critical, will be shown/recorded.
The other critical setting is the errors can be hidden (i.e. display_errors
set to “off” or “syslog”).
What will have happened in this case is that either the error_reporting
was changed to also show notices (as per examples) and/or that the settings were changed to display_errors
on screen (as opposed to suppressing them/logging them).
Why have they changed?
The obvious/simplest answer is that someone adjusted either of these settings in php.ini, or an upgraded version of PHP is now using a different php.ini from before. That’s the first place to look.
However it is also possible to override these settings in
- .htconf (webserver configuration, including vhosts and sub-configurations)*
- .htaccess
- in php code itself
and any of these could also have been changed.
There is also the added complication that the web server configuration can enable/disable .htaccess directives, so if you have directives in .htaccess that suddenly start/stop working then you need to check for that.
(.htconf / .htaccess assume you’re running as apache. If running command line this won’t apply; if running IIS or other webserver then you’ll need to check those configs accordingly)
Summary
- Check
error_reporting
anddisplay_errors
php directives in php.ini has not changed, or that you’re not using a different php.ini from before. - Check
error_reporting
anddisplay_errors
php directives in .htconf (or vhosts etc) have not changed - Check
error_reporting
anddisplay_errors
php directives in .htaccess have not changed - If you have directive in .htaccess, check if they are still permitted in the .htconf file
- Finally check your code; possibly an unrelated library; to see if
error_reporting
anddisplay_errors
php directives have been set there.
the quick fix is to assign your variable to null at the top of your code
$user_location = null;