How to break on variable change in PHP? - php

Is there any way to break on variable getting changed?
E.g. Variable $abc is used and modified in many different functions and files, when I debug a large project, I want to know when it get changed exactly.
Setting breakpoints can only tell me what the value is at that point, but I want to know the whole life of this variable.

Please search for 'php debugger'.
But I don't use one. It's relatively easy to search your source base for that variable and then use var_dump()'s to display when a variable is it's getting changed. Do you know how to use the Search all files feature in Notepad++?
Then once you've found your problem, use the undo to restore the files, and take the var_dumps() back out.
I also often put a die in places to stop so I can know for sure where a particular var_dump is executing.
I keep a Debug variable in my ini file and have a way to easily turn it on and off, and then can watch certain variables with if($ini['Debug']) var_dump($myvar);
There are some advantages to doing things this way rather than with a debugger. First your code runs faster, and this can matter depending on the complexity of your code. Second, it always works, no matter how strange your code, whereas there are sometimes things that can fool a debugger.

Related

Get a list of names of all global variables in PHP

I'm working with Moodle and theres a lot of global variables and it seems that there's no proper documentation. First I thought like "yeah just see what echo "<pre>",print_r($GLOBALS,1),"</pre>"; will yield". But when I try it, my browser becomes unresponsive while rendering and the rendered result is a mess. Unfortunately I don't have the possibility to use an debugger since the xdebug package is not available for the distro I'm using. (Turnkey Moodle appliance)
So my question is: Is there a way to see just the names of all global variables so that I can inspect them individually?
Easiest answer - open up lib/setup.php, scroll down to approx line 418 and they are all defined there.
Whilst you're at it, Moosh can also generate a file that allows autocompletion of all the $CFG-> variables in your Moodle site (not directly answering the question, but closely related).
maybe array_keys($GLOBALS)&
As you pointed out, $GLOBALS is in fact the way to see all global variables.
The reason your script is dying is because you have a large number of variables, and each of them likely have many child objects (possibly even recursively).
If you just want a list of the names of the variables, just do var_dump(array_keys($GLOBALS)).
Use get_defined_vars() to get all variables in that scope, that could be in all script or in a specific function.
echo '<pre>';
print_r(get_defined_vars());

PHP 4 to PHP 5 - isset checks on boolean if statements

Scenario:
We are in the process of converting an application from PHP 4 to PHP 5. The application needs to be able to work on PHP 4 for a little while, which means no PHP 5 specific elements can be used, yet. We are simply trying to make sure the application works on both platforms.
There are a lot of conditionals that look like this in the application:
if ($variable) { // do something }
Some of these variables end up not being defined at all and we are trying to reduce the number of errors (there's a lot of them).
To solve these errors, we are adding checks in various areas like this:
if (!isset($variable)) $variable = "";
or
if (!empty($variable)) { // do something }
Question:
Does anyone know of a simpler approach to fixing these errors. The problem is that these variables are being used across files (via includes) and defining the variable may change the logical flow in that file if its doing a check like (if (!isset($variable)) { // do something }).
The point of this question is to reduce errors and time consumption of tracking each individual use of these variables. Currently, we are having to either examine thoroughly what the variable is doing (which may take a good chunk of time), or we are doing a "fire and forget" / hope-its-fixed method of correcting.
-- Edit --
Does anyone know of a program like cppcheck for php that could somehow reference these variables or create some kind of chaining that could find errors and link possible references? (I hope that makes sense.)
AFAIK there is a code-checker that looks for uninitialized variables which works OK. You can work through it's messages, it's called PHP Mess Detector and one of it's rule covers uninitialized variables. However this can never be perfect.
Another method is to track the error messages and use them to locate the places within in the code. I've done that in the past and it worked very well, just do it in iterations and keep log of the warnings.
You can also work with a whitelist and import whitelisted variables when the request starts. Non-whitelisted submissions need to cause an access violation error to have this properly working, so this way is more work than tracking warnings albeit it might make your application more secure.
Please see as well:
PHP Syntax checking pre-source control
E_NOTICE ?== E_DEBUG, avoiding isset() and # with more sophisticated error_handler
isset() and empty() make code ugly

Is there any good way to see where a variable is coming from?

I'm tracing back a variable, I can print out the value of that variable, but I don't know where(which page) this value has been passed to the variable. Is there any good way to print out where actually this value is coming from?
A good starting point would be the debug_print_backtrace() function. It won't trace where a variable has been passed per se, but it will show you all the functions and included/required files with line numbers.
Why don't you check $_POST /$_GET variables in the pages which you are backtracing. Are you sure if you are not able to find the variable using grep/search utility?
Recap of debugging and some gotchas.
There is no programmatic way to determine where a variable "spawned" into existence in PHP.
Good debugging skills are your friend. Do check out the other answers posted. Recapped here:
debug_print_backtrace() - to let you know what files are included.
Use grep -rn 'variable_name' . from the top level of your site to see where it exists.
Add var_dump($variable) in a bunch of places one at a time can help as well to track down what the variable was in different states.
Also:
Using a good debugger can help out quite a bit. One widely used debugger extension is Xdebug.
Two potential gotchas to look for are: eval() and extract()
Both of these can "magically" cause variables to exist that didn't before.
Of course, the best way to fix this problem is to not have global variables. Or at least have as few as possible. You can have a well defined flow to your code, whether it's MVC or something else. Then you'll know the order your code is executed in and where variables are instantiated and/or passed around.
If you're in linux, you can type:
grep -rn "variable_name" .
to view the files (and the line numbers on those files) that the variable is referenced.
I always like to test my assumptions too. So if you suspect that the variable might be changed on a page, you can type:
var_dump( $variable_name );
To see the value. By moving that around, you'll be able to zero in on it and find the source of the variable being set.
I hope that helps...

PHP odd variable Question. Pertaining to "Root"

Ok I get a script from: http://abeautifulsite.net/blog/2008/03/jquery-file-tree/
Its a directory listing script. I am having troubles with it. It works out of the box no problems per say other than the put fact that it goes way back into the system structure then I am allowed to even see some how.
The person that made the script has this one line that throws me off and I can't make heads of tales of it per say.
file_exists($root . $_POST['dir'])
I've never seen $root in that context before. Nor is it defined anywhere in the script from what I can tell. So is that a valid thing? If not can anyone tell me how I can use this script beneficially to just displaying directories starting at a specific directory. The document I point to with the above link shows an example, but it doesn't seem to mean anything to the scripts workings.
On the other hand if someone knows of a canned script thats very similar in nature I'd be happy to give that a look too. But I'd really like to edit this one to work the way I want it to work so any help would be appreciated.
an example of how far its going back can be found at http://domainsvault.com/tree/
I say its going far back because I don't even have access to those directories through my ftp.. its a shared system.. hostgator..
*EDIT* Thanks Everyone for the input, this essentially what I was afraid of hearing. It was hopped that we could skip reinventing the wheel by using this concept. But its appearing more so than not that its basically a bricked concept and far from worth using and attempting to tamper with. It'd likely be a lot more easy for me to build something from scratch than have to deal with this. This was just one of those canned scripts you find it looks ascetically pleasing to the eye, and you hope for the best. Didn't turn out to be the case, thanks again all.
file_exists($root . $_POST['dir'])
Run away.
This connector script does no checking on what paths you pass to it, so it's perfectly possible to escape the root (which, yes, you're supposed to set manually) and browse any files on your server that the web user has access to.
Also, it fails to do URL-escaping, and mangles Unicode through inadvisable use of htmlentities. This will make files with various punctuation or non-ASCII characters in fail.
This is a shonky and insecure script. Do not deploy it.
$root is a user-defined variable. It should be defined somewhere in the script - it may be a global. The script can still work if the variable doesn't exist (it might have been deleted in a previous code refactor), in that case you should just delete the variable from the line you copied here.
I think $root means $_SERVER[ 'DOCUMENT_ROOT']
you can defined as
$root=$_SERVER[ 'DOCUMENT_ROOT']
at the beginning

Convert big php project from register_globals to _GET["param"]

I have a rather big php site, which was written for php4 and register_globals enabled. It is old custom CMS. Now I want to run it on the php5 hosting without register_globals. Is it possible to change parameters parsing from $id to $_GET["id"] automatically, with some script?
I can get parameters names from wget -r on this site.
It have dozens of php scripts, and it is not very easy to do this change manually.
PS: UPDATE: I want to convert only GET variables. The additional line is $var_name = $_GET["var_name"] for each parameter. This line should be inserted very high in the script, e.g. by adding a new <? ?> section at very top.
Running such tool would introduce great risk of introducing errors in code.
I'd suggest running extract() on superglobals, so that you force register_globals and aplication will work properly.
http://php.net/manual/pl/function.extract.php
Next, when everything will be ok, write an OO wrapper for input parameters, pack it into nice DI Container and start manually transitioning whole script to the new style.
I don't know of any tools that help you in the conversion, but you have several options:
Simulate register globals by doing the same thing that register_globals did: At the beginning of the script, put all variables from GET and POST into the global variable namespace (i.e. via extract). While this is fastest and the most easy solution, it will lead to the security problems that register_globals was known for, and it doesn't help with the performance of your application
Determine the variables that are used and load them only via the init script into $GLOBALS only. Still not nice
Determine the variables that are used and replace the GLOBALS usage with REQUEST
Walk through it manually. This way, you can be sure everything is correct and will have the least trouble afterwards.
From your description, solution 1 or 2 might be the best for you since the cms doesn't seem to be updated anyway (which is a shame).
Although the actual finding/replacing might take more time, doing this manually will most likely result in less bugs / weird behaviour.
If are not the original author of the application, then this manual finding/replacing is also an opportunity for you to become much more familiar with the codebase than some automatic method.
Automatic: fast, almost definitely will result in some horrible bugs
Manual: slower (likely), almost definitely will result in better understanding, less bugs - and any bugs that are introduced will be easier to fix because of your better understanding.

Categories