$_REQUEST not created when using variable variables? - php

Consider the following snippets of code:
Exhibit A:
$_REQUEST = json_decode(stripslashes(json_encode($_REQUEST, JSON_HEX_APOS)), true);
Exhibit B:
${'_REQUEST'} = json_decode(stripslashes(json_encode(${'_REQUEST'}, JSON_HEX_APOS)), true);
Exhibit C:
${'_' . 'REQUEST'} = json_decode(stripslashes(json_encode(${'_' . 'REQUEST'}, JSON_HEX_APOS)), true);
Both exhibit A and B work perfectly fine, exhibit C however displays a very strange error message:
Notice: Undefined variable: _REQUEST
What makes it even more weird is that this only happens with the $_REQUEST superglobal, if I try it with $_GET, $_POST or $_COOKIE all experiments work fine without raising error notices.
I'm guessing this is a PHP bug? I'm running on PHP 5.3.0.

(I tested with PHP 5.3.1)
One funny thing is that this portion of code :
<?php
var_dump(${'_' . 'REQUEST'});
Gets the notice Undefined variable: _REQUEST
But this one :
<?php
var_dump($_REQUEST);
var_dump(${'_' . 'REQUEST'});
Doesn't give any notice, and shows two empty arrays.
For a while, I though this could be related to auto_globals_jit, but $_REQUEST doesn't seem to the concerned by that directive... But there is one interested thing said, here :
Usage of SERVER and ENV variables is
checked during the compile time so
using them through e.g. variable
variables will not cause their
initialization.
Maybe, after all, even if it's not said in the manual, auto_globals_jit has an impact on $_REQUEST...
And, to be sure, I turned Off auto_globals_jit in my php.ini file :
; When enabled, the SERVER and ENV variables are created when they're first
; used (Just In Time) instead of when the script starts. If these variables
; are not used within a script, having this directive on will result in a
; performance gain. The PHP directives register_globals, register_long_arrays,
; and register_argc_argv must be disabled for this directive to have any affect.
; http://www.php.net/manual/en/ini.core.php#ini.auto-globals-jit
auto_globals_jit = Off
And tried this code again :
<?php
var_dump(${'_' . 'REQUEST'});
And I now get an empty array, and not a notice anymore.
So it seems auto_globals_jit does indeed have an impact on $_REQUEST -- even if it's not mentionned in the manual.

Please note that variable variables cannot be used with PHP's Superglobal arrays within functions or class methods. The variable $this is also a special variable that cannot be referenced dynamically.
http://www.php.net/manual/en/language.variables.variable.php
This is most likely related to:
Usage of SERVER and ENV variables is checked during the compile time so using them through e.g. variable variables will not cause their initialization.
From Pascal's Answer.
Which can all be related back to the auto_globals_jit option.

I'm going with the bug since $_GET etc do work
It's not been mentioned at the php bugtrack: http://bugs.php.net/
Maybe you should report it.
I did some quick debugging in Zend Studio:
<?php
var_dump( ${'_' . 'REQUEST'});
var_dump( ${'_REQUEST'});
var_dump( $_REQUEST);
And it seemed to work with the included PHP 5.2.10. Maybe you could use this as a workaround:
$foo = '_' . 'REQUEST'
$$foo //<-- is the same as $_REQUEST
EDIT: Woops, this wouldn't work with Superglobals, sorry -- thanks Cacha102

Found this "bug" report. According to tony2001#php it's not a bug:
Variable variables: Superglobals
cannot be used as variable variables
inside functions or class methods.
This page says the same thing, but what is weird is that this only happens with $_REQUEST, other GPC superglobals don't raise the error notice, can anyone double-check this?

Related

HTTP_POST_ARRAYS long variables not working in php5.4

I have some legacy code to modify in PHP5.4, the script was originally written in PHP4.0.
The problem arises when we try to login.
HTTP_POST_VARS is not recognized and these post and get variables need changing to $_POST and $_GET in the entire script which is worth 30-40 script files.
Could someone share any ideas on how to change all the long variables to short $_POST kind.
I tried to turn on register_long_arrays in php.ini file, but it is already on and not sure what else to be done.
The register_long_arrays directive does no longer exist:
This directive became available in PHP 5.0.0. [...] This feature has
been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0.
Any decent editor out there should provide a "Replace in files" menu item (which is normally under "Edit", "Search" or a similar location). With that, it should be a 2 minute task because HTTP_POST_VARS is a long name that won't cause much ambiguity.
You appear to be using phpDesigner. You can find a screen-shot in their site (scroll down to "Advanced search and replace").
Edit: You seem to have panic to text editors so another alternative is to create the missing variables yourself:
$HTTP_GET_VARS = &$_GET;
$HTTP_POST_VARS = &$_POST;
$HTTP_POST_FILES = &$_FILES;
$HTTP_SERVER_VARS = &$_SERVER;
$HTTP_SESSION_VARS = &$_SESSION;
$HTTP_ENV_VARS = &$_ENV;
$HTTP_COOKIE_VARS = &$_COOKIE;
You can place this code on top of your application's main settings file, which you hopefully have (otherwise, and considering that search & replace is apparently not an option, you'd need to put the stuff in a new *.php file and get it magically loaded with the auto_prepend_file PHP directive).
Please note we're using & to assign references so paired variables remain in sync (that's specially important to make $HTTP_SESSION_VARS actually work).
Of course, $HTTP_... variables were not superglobals. If you don't really understand the code, you can get faced to subtle bugs.
`$HTTP_GET_VARS = &$_GET;
$HTTP_POST_VARS = &$_POST;
$HTTP_POST_FILES = &$_FILES;
$HTTP_SERVER_VARS = &$_SERVER;
$HTTP_SESSION_VARS = &$_SESSION;
$HTTP_COOKIE_VARS = &$_COOKIE;`
put them all in config(settings) file before database valid functions start and its applicable to all the scripts belonging to the folder.

Defining constants with $GLOBALS

I want to use a global variable setup where they are all declared, initialized and use friendly syntax in PHP so I came up with this idea:
<?
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
$GLOBALS['debugger'] = 1; // set $GLOBALS['debugger'] to 1
DEFINE('DEBUGGER','$GLOBALS["debugger"]'); // friendly access to it globally
echo "1:" . DEBUGGER . ":<br>";
echo "2:" . ${DEBUGGER}. ":<br>";
echo "3:" . $GLOBALS['debugger'] . ":<br>";
if (DEBUGGER==1) {echo "DEBUG SET";}
?>
generates the following:
1:$GLOBALS["debugger"]:
Notice: Undefined variable: $GLOBALS["debugger"] in /home/tra50118/public_html/php/test.php on line 8
2::
3:1:
How can there be an error with 2: when clearly $GLOBALS["debugger"] IS defined? And then not generate a similar notice with the test at line 10?
I think what I am trying to do is to force PHP to interpret a string ($GLOBALS["debugger"]) as a variable at run time i.e. a constant variable variable
Disclaimer: I agree with the comments, globals are generally a bad idea.
That said, there's a few questions here that are worth answering, and the concept of indirection is useful, so here goes.
${'$GLOBALS["debugger"]'} is undefined. You don't include the leading '$' when using indirection. So, the correct version would be define('DEBUGGER', 'GLOBALS["debugger"]').
But, this doesn't work either. You can only access one level down via indirection. So you can access the array $GLOBALS, but you can't access keys in that array. Hence, you might use :
define('DEBUGGER', 'debugger');
${DEBUGGER};
This isn't useful, practically. You may as well just use $debugger directly, as it's been defined as a global and will be available everywhere. You may need to define global $debugger; at the start of functions however.
The reason your if statement is not causing notices is because you defined DEBUGGER to be a string. Since you aren't trying to use indirection in that line at all, it ends up reading as:
if ("$GLOBALS['debugger']"==1) {echo "DEBUG SET";}
This is clearly never true, though it is entirely valid PHP code.
I think you may have your constants crossed a bit.
DEFINE('DEBUGGER','$GLOBALS["debugger"]'); sets the constant DEBUGGER to the string $GLOBALS["debugger"].
Note that this is neither the value nor the reference, just a string.
Which causes these results:
1: Output the string $GLOBALS["debugger"]
2: Output the value of the variable named $GLOBALS["debugger"]. Note that this is the variable named "$GLOBALS["debugger"]", not the value of the key "debugger" in the array $GLOBALS. Thus a warning occurs, since that variable is undefined.
3: Output the actual value of $GLOBALS["debugger"]
Hopefully that all makes sense.
OK, thanks to all who answered. I think I get it now, I am new to PHP having come form a C++ background and was treating the define like the C++ #define and assuming it just did a string replace in the precompile/run phase.
In precis, I just wanted to use something like
DEBUGGER = 1;
instead of
$GLOBALS['debugger'] = 1;
for a whole lot of legitimate reasons; not the least of which is preventing simple typos stuffing you up. Alas, it appears this is not doable in PHP.
Thanks for the help, appreciated.
You can not use "variable variables" with any of the superglobal arrays, of which $GLOBALS is one, if you intend to do so inside an array or method. To get the behavior you would have to use $$, but this will not work as I mentioned.
Constants in php are already global, so I don't know what this would buy you from your example, or what you are going for.
Your last comparison "works" because you are setting the constant to a string, and it is possible with PHP's typecasting to compare a string to an integer. Of course it evaluates to false, which might be surprising to you, since you expected it to actually work.

PHP extracting without extract()

I have something like:
if(isset($_POST['submit']))
{
$linktitle=strtolower(str_replace(" ","-",$title));
etc.
$linktitle and $title are actually variables from $_POST - ie $_POST['linktitle'] and $_POST['title'].
Somehow, even though (as far as I can see!) I haven't extract()ed $_POST at this stage in the code, it is still working - PHP is understanding that $title is referring to $_POST['title']. Could anyone please explain why this might be?
Thanks!
ps. Sorry, but I really can't get this inline code quote formatting thing to work...!
register_globals is enabled in your PHP instance. See here for more info.
This is behaviour that should be relied upon as it's use is now deprecated. You will find that you can still use $_POST['keyname'] as well as $keyname, and that is what you should refer to in your code.
Your php.ini file must have register_globals enabled, so GPC variables are being added to the symbol table. This is why you see this behaviour. See the security risks of such a feature here
You have register globals activated in your webserver (php.ini), so PHP replace the unknoe variables with the corresponding GET or POST value. This option is deprecated and dangerous! Disable it if you can!

Another Undefined Index (this one's defined though)

Alright, PHP is throwing this error (in the log) and it's quite detrimental to the application.
PHP Notice: Undefined index: sessid in methods.php on line 7
Yes, I'm aware of what this error means, what I cannot figure out is why it's obviously defined and saying it's undefined. Here is the relevant code in methods.php
$sessid = mysql_real_escape_string($_REQUEST['sessid']);
Now before you go off and say that "NO IT'S UNDEFINED!!!", here is the POST request to the methods.php (and yes, I'm also aware that $_REQUEST "can't be trusted").
method=r&room=general&sessid=d0sma94yw4r4cdckv2ufhb&qid=1276957562382
As you can see, the sessid is obviously defined and is being sent off to the methods.php. I just thought I'd throw in the relevant query here too.
mysql_query('UPDATE active SET time=\''.$timestamp.'\' WHERE sessid=\''.$sessid.'\'');
Yes, time is also defined as:
$time = time();
So, what is the issue here?
Barring typos etc, if you have a version >= 5.3.0, you might want to check what request_order (or variables_order if request_order is empty) ini-setting is set to. If in none of those two the 'P' is set, the $_POST array will not be in $_REQUEST (and not even set it the 'P' is not in variables_order afaik). See: http://www.php.net/manual/en/ini.core.php#ini.request-order
If those 2 are allright, I'd say you have a logical error somewhere else, var_dump() the $_POST and $_REQUEST superglobals to check.

PHP 5.3 support for strange '${}' code?

I've just upgraded to PHP 5.3 and started supporting an old website for a new client. It seems to use rather odd PHP code which I've not come across before.
Whilst trying to access $_GET or $_REQUEST variables, the developer has used the following: ${"variable_name"}
I get notices generated due to undefined variables (presumably because PHP is not parsing the ${"variable_name"} style code).
Changing this to $_REQUEST['variable_name'] works as expected, but I can't go through all their code and change it as the site is massive and uses proprietry layout methods.
Does anyone know if it's possible to switch on support for these tags / codeblocks? I've taken a look in PHP.ini and there is a mention of ASP style tags and short tags but enabling these has no effect (they look totally different anyway, I just thought it was worth a shot).
I don't think there is anything new with that syntax :
$a = 10;
var_dump(${"a"});
Works just fine ;-)
You problem is probably due to the fact that, before, register_globals was enabled (by default, if PHP <= 4.something), and is now disabled -- and that is good for security !
With register_globals set to On, any variable in $_REQUEST is automatically injected as a vartiable in your application -- well, actually, this depends on the variables_order configuration option, but this one almost always includes Get, Post, and Cookie, at least.
For instance, if there is a variable like $_GET['my_var'], you will also have a $my_var variable... And this one can also be accessed with the syntax ${'my_var'}
Considering register_globals is Off by default since something like PHP 4.2, and should disappear in PHP 6 (if I remember correctly), I would advise against re-activating it... at least, if you have the time required to correct / test the code...
Curly brace syntax for variables is an embedded part of PHP, and has been around for quite awhile. The reason it exists is to resolve ambiguities with arrays and object syntaxes when using variable variables.
From the manual:
In order to use variable variables
with arrays, you have to resolve an
ambiguity problem. That is, if you
write $$a1 then the parser needs to
know if you meant to use $a1 as a
variable, or if you wanted $$a as the
variable and then the 1 index from
that variable. The syntax for
resolving this ambiguity is: ${$a1}
for the first case and ${$a}1 for
the second.
It's a very handy syntax in several situations, such as using array or object variables while outputting something using heredoc syntax.
I won't reiterate the advice by others about using register_globals, I just wanted to expound on this unusual syntax.
The ${"variable_name"} syntax is practically the same as $variable_name, except that the contents of the curly braces are evaluated first. It is supported by all recent versions of PHP, even the beta versions. What is not supported by recent versions of PHP though is the support of registering $_REQUEST (and other) variables as global variables. There's a setting for enabling it:
register_globals = on
It is NOT recommended for production use because of security issues though. It may be easier to run you source through some 'sed'-like tool and replace the usages with regular expression.
The old server probably has REGISTER_GLOBALS on. So the weird brackets aren't the problem.
REGISTER_GLOBALS puts all the variables in $_REQUEST as regular variables in the global scope, meaning you can access $_REQUEST['test'] can be accessed like $test or ${"test"}
The bracket syntax is on by default, and I don't believe you can turn it on/off.
register_globals was likely switched on. {$variable_name} syntax is always on, but register_globals turns things like $_REQUEST['variable_name'] into $variable_name.
Avoid switching it on if at all possible, though - there's a reason it's been long advised against, and it's going away entirely in PHP6.
register_globals is deprecated as of php 5.3 and will be removed as of php 6.0. What you want to do is use the Refactoring feature found in most PHP IDE's (zendo studio 6+) to rename the variable to something more appropriate, ie $_GET['variable_name'].

Categories