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.
Related
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!
I am a C++ programmer starting with PHP. I find that I lose most of the debugging time (and my selfesteem!) due to undefined variables. From what I know, the only way to deal with them is to watch the output at execution time.
Are other strategies to notice these faults earlier (something like with C++ that a single compile gives you all the clues you need)?
This is a common complaint with PHP. Here are some ideas:
Use a code analysis tool. Many IDEs such as NetBeans will help also.
Just run the code. PHP doesn't have an expensive compilation step like C++ does.
Use unit testing. Common side effects include: better code.
Set error_reporting(-1), or the equivalent in your ini file.
Get xdebug. It's not preventative, but stack traces help with squishing bugs.
isset(), === null (identity operator), and guard clauses are your friends.
Loose and dynamic typing are a feature of the language. Just because PHP isn't strict about typing doesn't mean you can't be. If it really bugs you and you have a choice, you could try Python instead—it's a bit stricter with typing.
Log your E_NOTICE messages to a text file. You can then process logs with automated scripts to indicate files and lines where these are raised.
No. In PHP, you can only know a variable doesn't exist when you try to access it.
Consider:
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
var_dump($line);
You have to restructure your code so that all the code paths leads to the variable defined, e.g.:
$line = "default value";
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
var_dump($line);
If there isn't any default value that makes sense, this is still better than isset because you'll warned if you have a typo in the variable name in the final if:
$line = null;
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
if ($line !== null) { /* ... */ }
Of course, you can use isset1 to check, at a given point, if a variable exists. However, if your code relies on that, it's probably poorly structured. My point is that, contrary to e.g. C/Java, you cannot, at compile time, determine if an access to a variable is valid. This is made worse by the nonexistence of block scope in PHP.
1 Strictly speaking, isset won't tell you whether a variable is set, it tell if it's set and is not null. Otherwise, you'll need get_defined_vars.
From what I know the only way to deal with them is to watch the output at execution time.
Not really: To prevent these notices from popping up, you just need to make sure you initialize variables before accessing them the first time. We (sadly IMO) don't have variable declaration in PHP, but initializing them in the beginning of your code block is just as well:
$my_var = value;
Using phpDocumentor syntax, you can also kind of declare them to be of a certain a type, at least in a way that many IDEs are able to do code lookup with:
/** #desc optional description of what the variable does
#var int */
$my_var = 0;
Also, you can (and sometimes need to) use isset() / empty() / array_key_exists() conditions before trying to access a variable.
I agree this sucks big time sometimes, but it's necessary. There should be no notices in finished production code - they eat up performance even if displaying them is turned off, plus they are very useful to find out typos one may have made when using a variable. (But you already know that.)
Just watch not to do operations that requires the variable value when using it the first time, like the concatenate operator, .=.
If you are a C++ programmer you must be used to declare all variables. Do something similar to this in PHP by zeroing variables or creating empty array if you want to use them.
Pay attention to user input, and be sure you have registered globals off and check inputs from $_GET and $_POST by isset().
You can also try to code classes against structural code, and have every variable created at the beginning of a class declaration with the correct privacy policy.
You can also separate the application logic from the view, by preparing all variables that have to be outputted first, and when it goes to display it, you will be know which variables you prepared.
During development stages use
error_reporting(E_ALL);
which will show every error that has caused, all NOTICE errors, etc.
Keep an eye on your error_log as well. That will show you errors.
Use an error reporting system, example:
http://php.net/manual/en/function.set-error-handler.php
class ErrorReporter
{
public function catch($errno, $errstr, $errfile, $errline)
{
if($errno == E_USER_NOTICE && !defined('DEBUG'))
{
// Catch all output buffer and clear states, redirect or include error page.
}
}
}
set_error_handler(array(new ErrorReporter,'catch'));
A few other tips is always use isset for variables that you may / may not have set because of a if statement let’s say.
Always use if(isset($_POST['key'])) or even better just use if(!empty($_POST['key'])) as this checks if the key exists and if the value is not empty.
Make sure you know your comparison operators as well. Languages like C# use == to check a Boolean state whereas in PHP to check data-types you have to use === and use == to check value states, and single = to assign a value!
Unless I'm missing something, then why is no one suggesting to structure your page properly? I've never really had an ongoing problem with undefined variable errors.
An idea on structuring your page
Define all your variables at the top, assign default values if necessary, and then use those variables from there. That's how I write web pages and I never run into undefined variable problems.
Don't get in the habit of defining variables only when you need them. This quickly creates spaghetti code and can be very difficult to manage.
No one likes spaghetti code
If you show us some of your code we might be able to offer suggestions on how you can better structure it to resolve these sorts of errors. You might be getting confused coming from a C background; the flow may work differently to web pages.
Good practice is to define all variable before use, i.e., set a default value:
$variable = default_value;
This will solve most problems. As suggested before, use Xdebug or built-in debugging tools in editors like NetBeans.
If you want to hide the error of an undefined variable, then use #. Example: #$var
I believe that various of the Code Coverage tools that are available for PHP will highlight this.
Personally, I try and set variables, even if it's with an empty string, array, Boolean, etc. Then I use a function such as isset() before using them. For example:
$page_found = false;
if ($page_found==false) {
// Do page not found stuff here
}
if (isset($_POST['field'])) {
$value = $_POST['field'];
$sql = "UPDATE table SET field = '$value'";
}
And so on. And before some smart-ass says it: I know that query's unsafe. It was just an example of using isset().
I really didn't find a direct answer already here. The actual solution I found to this problem is to use PHP Code Sniffer along with this awesome extension called PHP Code Sniffer Variable Analysis.
Also the regular PHP linter (php -l) is available inside PHP Code Sniffer, so I'm thinking about customizing my configuration for regular PHP linting, detecting unused/uninitialized variables and validating my own code style, all in one step.
My very minimal PHPCS configuration:
<?xml version="1.0"?>
<ruleset name="MyConfig">
<description>Minimal PHP Syntax check</description>
<rule ref="Generic.PHP.Syntax" />
<rule ref="VariableAnalysis" />
</ruleset>
I'm currently working on a very large project, and am under a lot of pressure to finish it soon, and I'm having a serious problem. The programmer who wrote this last defined variables in a very odd way - the config variables aren't all in the same file, they're spread out across the entire project of over 500 files and 100k+ lines of code, and I'm having a hell of a time figuring out where a certain variable is, so I can fix an issue.
Is there a way to track this variable down? I believe he's using SMARTY (Which I can not stand, due to issues like this), and the variable is a template variable. I'm fairly sure that the variable I'm looking for was initially defined as a PHP variable, then that variable is passed into SMARTY, so I'd like to track down the PHP one, however if that's impossible - how can I track down where he defined the variable for SMARTY?
P.S. I'm in Vista, and don't have ssh access to the server, so 'grep' is out of the question.
Brute force way, because sometimes smarty variables are not directly assigned, but their names can be stored in variables, concatenated from many strings or be result of some functions, that makes it impossible to find in files by simply searching / greping.
Firstly, write your own function to print readable backtrace, ie:
function print_backtrace()
{
$backtrace = debug_backtrace(FALSE);
foreach($backtrace as $trace)
echo "{$trace['file']} :: {$trace['line']}<br>";
}
Open main smarty file (Smarty.class.php by default) and around line 580 there is function called assign. Modify it to watch for desired variable name:
function assign($tpl_var, $value = null)
{
if($tpl_var == 'FOOBAR') /* Searching for FOOBAR */
{
print_backtrace();
exit;
}
The same modification may be required for second function - assign_by_ref. Now after running script you should have output like that:
D:\www\test_proj\libs\smarty\Smarty.class.php :: 584
D:\www\test_proj\classes.php :: 11
D:\www\test_proj\classes.php :: 6
D:\www\test_proj\functions.php :: 7
D:\www\test_proj\index.php :: 100
Second line points to the place where variable was first assigned.
This sort of thing is the #1 reason I install Cygwin on all my windows machines.
grep myvariablename `find project_dir -name "*.php"`
I can't imagine programming without a working grep.
There is an interesting further option, ugly like hell but helpful if you are really lost.
If you would like to know where THE_NAME was defined, write lines like these on a place you are sure is run first:
error_reporting(E_ALL);
define('THE_NAME', 'Chuck Norris');
If later PHP will run the definition you are looking for, it will write a notice like this:
Notice: Constant THE_NAME already defined
in /home/there/can-rip-a-page-out-of-facebook.com/SomeConfiguration.php on line 89
Then you know that the definition you are looking for is in the file SomeConfiguration.php on line 89.
To have this working, you must consider
if there are HTTP forwards in the framework on the way to the code you set in
if there are further commands setting the PHP error reporting mode
So sometimes it helps to add some exit('here') in order not to blur the output. Maybe you have to narrow down a bit or you have to set error_reporting earlier, but you'll find it.
It's not a perfect solution, but I find agent ransack useful for searching large directories and files. Might help you narrow things down. The search results will allow you to read the exact line it finds a match on in the result pane.
If you use the netbeans editor just "right click" -> "go to Definition"
Or ctrl + click on the variable.
If the editor can't figure it out, you could fallback to the "Find in files" option.
Just use one of the available PHP IDEs (or a simple text editor like Notepad++ if you're really desperate) and search for the name of the variable in all source files (most PHP IDEs also support finding where functions/vars were defined and allow you to jump to the relevant piece of code). Though it seems weird that you don't know what piece of code calls the template (whether it's Smarty or anything else doesn't really matter). You should be able to drill down in the code starting from the URI (using any IDE which supports debugging), because that way you're bound to see where said variable is defined.
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'].
Ok I cannot remember the details on this but on some servers you can use
$var instead of $_GET['var'] to access a variable in the URL, I know this is BAD but I can't remember why it is bad?
I think you mean Register Globals.
You shouldn’t use them because you cannot distinguish the source of that variable values since they can come from any source of the EGPCS variables (Environment, GET, POST, Cookie, Server).
So if you have a the $var, you cannot say if the value is either from $_ENV['var'], $_GET['var'], $_POST['var'], $_COOKIE['var'] or $_SERVER['var'].
The feature is called Register Globals and it allows people to inject variables into your code. See the documentation for examples; here's one:
<?php
// define $authorized = true only if user is authenticated
if (authenticated_user()) {
$authorized = true;
}
// Because we didn't first initialize $authorized as false, this might be
// defined through register_globals, like from GET auth.php?authorized=1
// So, anyone can be seen as authenticated!
if ($authorized) {
include "/highly/sensitive/data.php";
}
?>
You can use that if your server has register_globals set to 1 (or true) on the php.ini file.
At some point, this started to be off by default, and applications started to break, which is a reason why this is a bad practice.
You can see a list of php.ini variables here.
It's also bad because you can confuse yourself with the way that PHP will scope your variables. You may wind up overwriting data if you aren't careful. Also, using $_GET is much clearer as to what you are attempting to accomplish.
Because letting people inject values into arbitrary variables is a very bad thing. You could be storing anything there and they could overwrite some value that compromises your security. Remember to use isset to check that a value has been set before trying to use it.
It's bad because if you're not careful to initialize every variable before you use it (something that PHP won't force you to do), people can easily cause your code to do Very Bad Things with a request as simple as /myapp/index.php?admin_privileges=1.
The setting is called REGISTER_GLOBALS and it was discussed here:
Why is REGISTER_GLOBALS so bad?
If you can do that, then "register_globals" is turned on. This is bad because you won't know where a variable came from, and it mixes your variables with the ones any user can inject via the URL. Read more here: http://www.php.net/manual/en/security.globals.php
Once you get used to using $_POST, $_GET, etc your code's purpose will be easier to read and much, much easier to maintain.
Register globals would work but it's going to go away in a future version of PHP. Not to mention that it really is wrong to have it enabled.
You can use extract() for a more controlled behavior. It will extract the keys from an array (in this case, $_GET) into the local context as variables. You can give them a common prefix so that they don't collide with your existing variables. And you can filter the array beforehand to make sure you're only getting the expected variables.
int extract( $var_array [, $type = EXTR_OVERWRITE [, $prefix ]] )
Import variables from an array into the current symbol table.