how to debug properly in php - php

I have some 2000 lines of code in php... some place i have some echo here and there to know that this or that is done properly... but i what more tracing and echo on each and every task done... i what echo in function enter and before function return... but all these echo polluate the code and the screen, and it's a nigtmare to remove or comment it out when ready for production...
the question, how to say, echo this and that, but when i say debug off, stop echo..how do you that in your code... what i tought was
global $debug_echo;
$debug_echo = true;
if ($debug_echo) {echo "function xyz - start";}
if ($debug_echo) {echo "function xyz - end";}
...
...
so with this, i can turn debug everywhere with one change... does it make sense ?

Best thing to do for debugging, would be to use a constant. So at the top of your file, or wherever you want to declare debug mode on or off you do this
define('DEBUG', true);
Then to check you just want to do
if(DEBUG === true) { echo 'something here'; }
You only have to declare the constant once, and then it's available throughout the entire scope of the code, providing it's declared somewhere.

In a core file, such as config.php (which is usually included in all sub files in a web app), have something similar to this:
$debug = true;
if($debug){
ini_set('display_errors', 1);
error_reporting(E_ALL);
}else{
error_reporting(0);
}
then just change true to false to disable debugging.
If you want to dump errors in the middle of scripts, such as MySQL queries, then that's a whole different kettle of fish.
Check out this slideshow: http://www.slideshare.net/asgrim1/errors-exceptions-logging-php-hants-oct-13

Here is something you can do:
function is_dev() {
return isset($_SERVER['APP_ENV'] AND $_SERVER['APP_ENV'] === 'DEV')
}
..In your apache virtual host configuration / .htaccess
SetEnv APP_ENV DEV
If you are using a framework or creating your SQL queries dynamically, you can output them if is_dev() returns true.
if(is_dev()) {
echo $sql;
}

Related

Can PHP constants' values be changed per HTTP request?

I'd like to know from a design POV whether changing the value of a constant per HTTP request is discouraged or perfectly ok.
I have a few constants that are defined at the start of a PHP script and they're used to figure out a particular context (what is the user trying to do at the time). The constants are never changed throughout the lifecycle of the script so they conform with the rules of constants and they work well. However, the values of these constants depends on what the user's doing. I'm wondering whether this is discouraged or perfectly acceptable in PHP.
<?php
// This function is only run once per HTTP request at the start
function new_paper() {
define('NEW_PAPER', 1);
define('NEW_VERSION', 0);
}
// This function is also only run once per HTTP request at the start
function new_paper_version() {
define('NEW_PAPER', 0);
define('NEW_VERSION', 1);
}
// This function is subsequently called by both functions above
function a_handler_of_sorts() {
if (NEW_PAPER) {
// Do something if it's a new paper
}
elseif (NEW_VERSION) {
// Do something if it's a new version
}
else {
}
}
In no circumstances are both new_paper() and new_paper_version() run in the same HTTP request.
A typical use case would be something like:
define('DEBUG', !empty($_GET['debug']));
if (DEBUG) echo 'some debugging statement';
Obviously don't do this only based on a query parameter, especially not in production, but you get the idea.
So, yes, setting constant values based on the request is fine. Whether this is the best thing to do in your particular case is questionable and I don't know. I'd really reserve it for "meta" values like debug flags, not for values which are essentially function parameters, inputs for your business logic. Do this sparingly.
"Constant values" which influence how every script works independently of the request would be something like config files or environment variables, e.g. containing database access credentials and such.
Constants should not change during the request but as you said yours don't so I think you're OK there.
They represent fixed things such as how many DB connections are allowed, the name of the application etc. If you're trying to use them to store the state of your application then you could consider doing something like:
<?php
define('STATE_PAPER', 0);
define('STATE_VERSION', 1);
define('STATE_INVALID', 2);
$applicationState = null;
if (someCheckForPaper() === true) {
$applicationState = NEW_PAPER;
} else if (someCheckForVersion() === true) {
$applicationState = NEW_VERSION;
} else {
$applicationState = STATE_INVALID;
}
// Save $applicationState somewhere... maybe session?
// Somewhere else
if ($applicationState === STATE_PAPER) {
...
}

Removing debugging messages in PHP

I have couple of mysql queries in PHP and at the end of each query I did this
mysql_query(STRING) or die(mysql_error());
This is fine as far as I am in DEV environment but I dont want production users to see these errors. Any good Idea to remove this messages by just setting ON OFF.
Apart from the fact that you shouldn't use mysql_ as they're deprecated, you can simply make another function:
define('DEV', true);
function mysql_query_custom() {
$result = call_user_func_array('mysql_query', func_get_args());
if ($result === false) {
if (DEV) {
die(mysql_error());
}
}
return $result;
}
mysql_query_custom(STRING);
Lots of ways to do it. The most terse and most like you're doing now:
// do this once
$PRODUCTION = true;
// now use
mysql_query() or ($PRODUCTION ?: die(mysql_error()));
I caution though this is not a maintainable way to debug in the long term. There's a lot of good alternatives in this thread.
Whatever you do, develop a comprehensive error detection, logging, and response mechanism in your code. If you're using a framework, leverage its facilities.
Even easier you could just replace all die( with error_handle( or something else, and include this function:
function error_handle($err) {
die($err); // Comment this line out if you don't want the error to be displayed.
}
This is also great because you could extend the code to log errors etc in production. You could in addition define a $debug-variable somewhere in your global code if you are using Git or other version-control-systems.
Edit: I suggest replace all die( and not just die to avoid replaces where you don't want it, if you e.g use die in a sentence or something.
Then set a configuration variable called $DEBUG and just wrap your logic in a conditional if/else?
$DEBUG = true;
if ($DEBUG) {
mysql_query(STRING) or die(mysql_error());
}
else {
mysql_query(STRING);
}
const DEBUG = true;
function fail($message) { die (DEBUG ? $message : ''); }
...
use_mysql_query_even_though_it_sucks() or fail(mysql_error());
// seriously. Use mysqli.
Better still, use something like this:
if($_SERVER['SERVER_NAME'] != "dev.mydomain.com"){
ini_set("display_errors",0);
ini_set("log_errors", 1);
}
It saves you having to remember to disable the errors when you upload it to the production server.

Control parts of code through external on off config file?

I want to have a config file that basically says something like (Account: on/off), where an admin can choose on or off. And then, in my main script, i want a bunch of if else statements that says if its on, do this, if off, do this.
Any suggestions?
config.php:
<?php
$account = 'off';
main_script.php:
<?php
include('config.php');
if ($account == 'on') {
//do this
} else {
//do something else
}
Config files usually define global constants available everywhere in your code and often seen in the variable $GLOBALS['config']. Config files are normal PHP files that get included using include() or better include_once() at the very top of your applications main file.
include_once('config.php');
if ($GLOBALS['config']['admin']) doThis();
else doThat();
http://php.net/manual/de/reserved.variables.globals.php

include() it does not work

I have problem that on server include() function does not want to work and I have no idea why?
I have:
if (file_exists('/home/p002/htdocs/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php')) {
echo "1 works";
} else {
echo "The file 1 does not exist";
}
if(include "$_SERVER[DOCUMENT_ROOT]/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php" == 'OK')
{
echo 'INCLUDE 1 works';
}
else
{
echo 'Step 1 fail';
}
if(include '/home/p002/htdocs/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php' == 'OK')
{
echo 'INCLUDE 2 works';
}
else
{
echo 'Step 2 fail';
}
It returns: 1 works Step 1 fail Step 2 fail
I have no idea how to force it to work. HELP
I use zend framework and this file is in the library (parallel to zend -libraries - directory but it does not want to work too without the include directory :/
It is really strange for me as when I add:
include ("/home/p002/htdocs/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php");
And it is correct path I have only blank page! But when I add:
include ("/homedddd/p002/htdocs/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php");
And it is wrong path the page is not blank, it looks like working OK. It mean something is wrong with this IntelliSMS library it does not work with my server but I do not know why? Probably server blocking sending sms or something? Do you have any idea? This library is from http://intellisms.co.uk/sms-gateway/php-sdk/ Maybe there is problem that it needs the OpenSSL extension module? What should I do it to start works?
In the first block of code you found out, that /home/p002/htdocs/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php exists. When you try to include this file, you never use the exact same string. If you do, it should work.
Edit:
You tried that and it failed. In that case it looks like a permission issue. If you do not have read permissions on that file, the first test will work, but including the file will fail.
You've changed your slashes around. This may be a problem.
You should never use the \ backslash in path names. Use the forward slash / which works on both Windows and Un*x servers.
Also the base directory name is unlikely to be identical on both servers. Make it relocatable and replace /home/p003/htdocs with DOCUMENT_ROOT like so:
include "$_SERVER[DOCUMENT_ROOT]/Project2/library/IntelliSMS/SendScripts/IntelliSMS.php";
Notice the double quotes.
I would further recommend to avoid mixed-case filenames if possible.
Here's what you're doing wrong, you were actually trying to include FALSE in every single attempt. Doing something like this
include '/path/to/file.php' == "OK";
equals that
include FALSE;
This is probably what you wanted to do
if((include '/path/to/file.php') == "OK") { echo("works"); }
Other SO users overlooked this fact because your path is so long, the comparison gets hidden in your code block.

What's a organized or standarized way of testing PHP code using var_dump and print_r?

I usually, test code with PHP code, special PHP variables with var_dump and print_r
But I always end up placing them everywhere and messing up the code.
Is it common to include them or place them in an organised way?
No, it's not! You shouldn't rely on var_dump and print_r for testing and debugging. Instead start writing unit tests and start using a debugger!
What you need, in order to write quality PHP code, is an IDE like PhpStorm, Aptana, Eclipse, Zend Studio or NetBeans which provide you with an easy way to integrated debugging and unit testing.
There are two good debuggers for PHP, Zend Debugger and Xdebug.
There is one de facto standard for writing unit tests for PHP, phpUnit.
Use var_dump and print_r only occasionally and never leave them in the code! I strongly disagree with Sam Starlings method. I think it inhibits the development of best practices.
I would also advice using some sort of 'ENVIRONMENT' constant for defining the environment instead of the localhost/IP approach.
Why not wrap every var_dump or print_r in this way:
if($debug) {
var_dump($foo);
}
Then you can set $debug = true at the top of every file - or even better, in a file that is included by every other file, so that you can globally turn debugging on or off. You can also programatically set the debug flag like this:
if($_SERVER['SERVER_NAME'] == "localhost") {
$debug = true;
} else {
$debug = false;
}
Sam's solution is useful, and probably sufficient for many very small projects, but it does involve adding a lot of superfluous code to application logic. In a similar case I would define something like
function aray_out($arr, $continue = NULL) {
echo '<pre>';
(is_array($arr)) ? print_r($arr) : var_dump($arr);
echo '</pre>';
if(!$continue)
exit();
}
When something isn't working as expected, we can just bash out array_out($_SESSION) (or whatever), save and retry, removing the line once we're confident our variables are holding the right stuff. Wrapping the output in <pre> tags makes it a lot more readable.
We could also require_once 'debug.php' in our malfunctioning scripts, using that file to dump our environment.
# debug.php
$your_ip = '192.168.0.1';
if($_SERVER['REMOTE_ADDR'] == $your_ip || $_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
array_out($_SERVER, 1);
array_out($_SESSION, 1);
array_out($_POST, 1);
# etc.
}
This has the added benefit of giving us information, as we have set the IP address we are accessing the server from, but leaving output for other users the same.
Of course, more serious use cases need more serious tools.

Categories