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.
Related
Referring to Is there a static code analyzer [like Lint] for PHP files? -- I am looking at how to assess the content of PHP files before they are committed by developers. Whichever solution(s) are appropriate will be triggered via SVN hooks similar to the answer: Is it possible to check PHP file syntax from PHP?
I came across this Automatic Syntax checking of PHP files when checking into SVN which is the angle I'm going for, however ... php -l isn't quite sufficient.
For example, given the code:
if ($foo == 'bar') {
echo $foo;
}
This results in:
2012/01/15 02:51:14 [error] 694#0: *164 FastCGI sent in stderr: "PHP Notice: Undefined variable: foo
Compared to:
if (isset($foo)) { echo $foo; }
Some of this comes down to educating coders on best practices. Unfortunately, some don't learn as quickly as others, and the only way to ensure that compliance to coding standards is met, is to reduce what is going into SVN that has been untested or isn't compliant.
From the first link in this question, I have tried:
php -l
doesn't notify about the problem with $foo
phplint-pure-c-1.0_20110223 - PHPLint
doesn't notify about the problem with $foo
if ($foo == 'bar') {
\_ HERE
==== /mnt/hgfs/workspace/scratch-pad/phpinfo.php:44: Warning: comparing (unknown) == (string): cannot check the comparison between unknown types
phpcs - PHP Code Sniffer
doesn't notify about the problem with $foo despite PHP Sanity Check indicating it was the right answer
SimpleTest
Is very nice, but requires the developers who are writing the bad code to write good unit tests...
All are interesting in their own way, but none are catching these problems that really are only being found at runtime.
Appreciate input / thoughts on this topic.
EDIT
There was one poster who suggested that PHPLint was the right way to go. I thought, OK! Let's try it again given that there is a new version: phplint-pure-c-1.1_20120202:
<?php
if ($foo == 'bar') {
echo $foo;
}
?>
Simple test .................... and, it works and reports 1 error, 1 warning. However, if the following is added BEFORE the if statement:
<?php
if (isset($foo) && $foo == 'bar') { echo 'man'; }
if ($foo == 'bar') {
echo $foo;
}
?>
it does not work, and reports 0 errors, 2 warnings.
I think this might be a bit hard for an analyser to give warnings about. The code you've given might work with the help register_globals, for example. Also, it might be defined in some other file that is including this file. For those reasons, PHP files should be analyzed with full context of other files for this to be really reliable, and PHP/server configuration should also be either available or defined to the analyzing mechanism.
That said, are you sure phplint doesn't do what you want to?
There is an online validator that you can use to test it. Given the input:
<?php
echo $foo;
the result was:
echo $foo;
\_ HERE
==== 3: ERROR: variable `$foo' has not been assigned
END parsing of test-qBlPWw
==== ?: notice: unused package `dummy.php'
==== ?: notice: unused module `standard'
Overall test results: 1 errors, 0 warnings.
whereas with isset() it didn't find any issues.
EDIT: so for this other test case:
<?php
if ($foo == 'bar') echo $foo;
On Linux Mint 8 the response is:
$ src/phplint test.php
/home/vadmin/phplint/phplint-pure-c-1.0_20110223/test.php:3: ERROR: variable `$foo' has not been assigned
/home/vadmin/phplint/phplint-pure-c-1.0_20110223/test.php:3: Warning: comparing (unknown) == (string): cannot check the comparison between unknown types
Overall test results: 1 errors, 1 warnings.
and with this:
<?php
$foo = '1';
if ($foo == 1) echo $foo;
it is:
$ src/phplint test.php
/home/vadmin/phplint/phplint-pure-c-1.0_20110223/test.php:6: ERROR: comparing (string) == (int)
Overall test results: 1 errors, 0 warnings.
so isn't it working like it should, and reporting the problem properly?
You might want to combine phpcs (to adhere to coding standards) and a new project by Sebastian Bergmann: https://github.com/sebastianbergmann/hphpa This utilizes the static compiler by facebook to check for errors such as your looking for... Might be too much as a pre commit hook, but a hook into your build system might suffice?
All of these smart super power tools that eavesdrop every door and look into every keyhole will never be able to compete withe the stupid and blunt action of RUNNING the code.
What is the value of having compilable, syntactically valid php files in the repo? You can make zounds of such files, commit them on a regular basis to the repo and, rest assured, all of them contribute to the project and add a certain reliable feature, because, well, they went through the pre-commit hook to check their validity?
There is a cr#pload of problems with the code written by humans, syntax and missing vars being only the tip of the iceberg. Unit testing (as noted by #NikiC) helps quite a bit. It's the responsibility of the developer to make reliable, working, documented code and test it before committing. Silly mistakes of using undeclared vars is something that the IDE can point out (Zend Studio does, for instance). Your goal is to create good working software and unit tests are key here. This should be the main concern in my opinion. Valid php files is a very loose requirement...
Could you use a third party compiler that has more compile time options, like phc ( http://www.phpcompiler.org/doc/latest/runningphc.html#compiling-web-applications) ? (or possibly hiphop?)
Then I thought: you need Perl::Critic for php.
Critiquing PHP-code / PerlCritic for PHP?
(also google : perl critic for php )
I wish I could be more concretely helpful, but sometimes it's just an idea that gets you to the solution. That is what I have to offer :)
David
Oh yeah, what you need is PHPUnderControl! It will check your syntax, automatically chack your unit tests, do a C.R.A.P. index, and more good stuff. It's basically the bomb!
Check it out, here is the URL: http://phpundercontrol.org/
while not a command line checker, PHPStorm has to be one of the best IDE's out there.
It has various inspections which can detect the sort of problems that you've mentioned. Also, it automatically re-runs these inspections on the files you're committing to version control, checking for undefined variables, poor quality code and "todos".
However the problem with these inspections is that they can't know everything, so they sometimes err on the side of being 'suggestions' or 'warnings' rather than error.
However, it is quite good at what it does, and it can these sorts of problems while you're editing and, usually it results in fixing the errors well before any commit action anyway.
Let's say that at the beginning of a random function variable $variables['content'] is 1,000 characters long.
This random function is very long, with many nested functions within.
At the end of the function $variables['content'] is only 20 characters long.
How do you find which of nested functions modified this variable?
Not sure how you'd want to return it but you could use the magic constant __LINE__. That returns the line of the current document.
You could create a variable called $variables['line'] and assign __LINE__ as the value, where appropriate.
If it were me, first I'd consider breaking apart the 1000-line beast. There's probably no good reason for it to be so huge. Yes, it'll take longer than just trying to monkey-patch your current bug, but you'll probably find dozens more bugs in that function just trying to break it apart.
Lecture over, I'd do a search/replace for $variables['content'].*=([^;]*); to a method call like this: $variables['content'] = hello(\1, __LINE__);. This will fail if you are assigning strings with semicolons in them or something similar, so make sure you inspect every change carefully. Write a hello() function that takes two parameters: whatever it is you're assigning to $variables['content'] and the line number. In hello(), simply print your line number to the log or standard error or whatever is most convenient, and then return the first argument unchanged.
When you're done fixing it all up, you can either remove all those silly logging functions, or you can see if 'setting the $variables['content'] action' is important enough to have its own function that does something useful. Refactoring can start small. :)
I think this is a problem code tracing can help with.
In my case I had this variable that was being modified across many functions, and I didn't know where.
The problem is that at some point in the program the variable (a string) was around 40,000 characters, then at the end of the program something had cut it to 20 characters.
To find this information I stepped through the code with the Zend debugger. I found the information I wanted (what functions modified the variable), but it took me a while.
Apparently XDebug does tell you what line numbers, in what functions the variables are modified:
Example, tracing documentation, project home, tutorial article.
I have an old application witch pops up an error at a certain location. The error is about an wrong set variable. Only from the error it is not possible to find the location where the variable is set wrong. Now my idea is to use reflections to find the location.
Is it possible to use reflections to find the code position at which a variable gets a certain value?
The idea: I have the name and the value of the variable. Now if both are matching a certain event should be triggered and echo the actual parsed file and line number.
Every ideas that help are appreciated.
Thank you,
-lony
P.S.: Is it possible even if the application is not really object oriented and uses a lot of spaghetti code?
I would be you do a debug_backtrace at the point where the error occurs and try to exploit the stack trace to see where the variable is changed. The debug_backtrace would give you a list of file included after it should be fairly easy to filter a list of line with a global search (i.e. grep)
var_dump(debug_backtrace())
if (variable == value) {
echo "variable equals value, line #whatever"+"<br/>";
}
Just place these at various points in code and see which ones display. Manually enter line numbers.
I found a solution to one of my problems.
The function debug_print_backtrace helped me finally debugging my spaghetti code. I found it by reading this post.
-Cheers
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 stepping through the source code of CodeIgniter with Xdebug in NetBeans and I'm looking for a way to see defined constants as they are defined. If it's not possible, are there any other ways to display all defined constants?
Take a look at the get_defined_constants function. It will return an array of all the defined constants in the code up to the point of the function call. You can then use print_r to print out the array.
This kind of practice I use is quite decent as it shows only custom/user created constants.
print_r(var_export(get_defined_constants(true)['user'], true));
Wrap this within pre tags or just view source and you'll get very nice array of all the stuff You defined.
Note that this is not going to work with php 5.3.* where in 5.4.* it outputs fine.
In earlier versions of php, get_defined_constants() must be assigned to a variable first, before output.
Something like this.
$gdc = get_defined_constants(true);
print_r( var_export($gdc['user'], true) );
You probably want to adapt:
$arr = get_defined_vars();
The best I could find is to press F7 (step into) while in debug mode to have your constant line executed.
define('SOME_CONSTANT','VALUE');
And then double click "SOME_CONSTANT", right click and chose add new watch (shortcut: shift + ctrl + F7), and the add new watch window will appear with the constant prepopulated, select enter and you should see your constant value in the Variables (if you have the blue diamond selected "Show watches inside variables view") & Watches window panel.
Also quite handy to know, you can hover over variables to see their value as opposed to looking in the Debugging > Variables window panel...just need to turn it on as it's off by default...apparently buggy...using the latest xdebug and it's been fine for me so far.
Tools > Options > PHP > General Tab > Debugging Section > Check Watches and Balloon evaluation
Hopefully this will still be useful 2 years later.