I don't know what's going on with my PHP. I'm using a bunch of classes and a semi-MVC framework that I developed myself (as an experiment). So the PHP file is including a lot of class files.
My PHP line numbers for error messages are completely off and therefore useless and making it impossible for me to debug. For example, right now I'm getting an error message that says:
`Parse error: syntax error, unexpected ')' in /view.php on line 209
The only problem is: there is no ')' anywhere near line 209. Even worse, if I put die() on line 200 or so, it still gives me an error message, now pushed down to line 210. So clearly the line of code is being taken into account, yet for some reason it's not dying.
Another thing is, it's including a header.php file prior to this line. The header file basically just outputs some HTML, and works fine on other pages. Yet on this page, it doesn't even output the header; it's just dying with a blank page and that error message.
Is there anything I can do to use more reliable debugging? If I could have an accurate line number, I'm sure I'd find the bug easily.
Edit: I found the bug. The point of this question is not to solve the unexpected ')' bug. The point is: why are the line numbers inaccurate? The actual error message was on line 218, not 209 or 210.
It's your line endings. Open up a program where you can change the line endings and change it to that of the server and the line number will be correct. I don't know about windows, but on mac you can change line endings using TextWrangler (or BBEdit) and on linux using gedit.
Try adding a Logging function with a simple stacktrace.
Use it:
<?php
require_once("Log.class.php");
$myLog = new Log();
$log->write("Tag here", "Details here");
?>
Log.class.php:
<?php
$debugFolder = "/";
class ExpectedParamaterUndefinedException extends Exception {}
class Log {
private $logs = array();
function __contruct(){
}
function write($type, $message){
$trace=debug_backtrace();
$caller=array_shift($trace);
$fileParts = explode("/", $caller['file']);
$filePieces = explode(".", $fileParts[count($fileParts) -1]);
$this->logs[ $filePieces [count($filePieces ) - 2] ] .= " [ ".date(DATE_RFC822)." ] [ $type ] [Line : ".$caller['line']."] ::: $message \n ";
}
function __destruct(){
foreach($this->logs as $caller => $log){
$fp=fopen($debugFolder . "debug/" . $caller.".log", "a");
fwrite($fp, $log);
fclose($fp);
}
}
}
?>
You will end up with a .log file for each class that you log.
Happy hunting!
Related
I am trying to implement Google+ login on my website and am running into an issue. Here is my code (after creating a Google_Client object):
try {
$client->authenticate($_GET['code']);
$plus = new \Google_Service_Plus($client);
$person = $plus->people->get('me');
$firstName = $person->modelData->name->givenName;
} catch (Google_Auth_Exception $e) {
$response = array(
'error' => 'Error: Authentication exception.'
);
} catch (Exception $e) {
$response = array(
'error' => 'Error: Uncaught exception.'
);
}
$client->authenticate() throws a Google_Auth_Exception if the code passed to it is invalid
If authentication failed, then reading properties from the $person object causes fatal errors
$responseis echo'd out as a JSON-encoded object
The problem is that the try/catch code does not seem to be working properly. When authentication fails due to the code in $_GET['code'] being invalid, the following response is returned from the script:
{"error":"Error: Authentication exception."}
So far so good -- the code in the first catch block was executed.
However, the code in the try block continues to execute in a weird fashion. I say "weird" because in the above form, a bunch of errors (culminating in a fatal error) occur, meaning this line:
$firstName = $person->modelData->name->givenName;
Is still executed! It should not be executed since an exception was thrown on a previous line. If I comment out the above line, the errors are not thrown (again indicating this line is executed, which it shouldn't be).
Here are the errors outputted due to the above line executing after the exception has been thrown:
Notice: Undefined index: modelData in [...]\google-api-php-client-master\src\Google\Model.php on line 78
Notice: Trying to get property of non-object in [...]\ajax_handler.php on line 720 [note: this is the line shown above, where the property is being accessed]
Notice: Trying to get property of non-object in [...]\ajax_handler.php on line 720
Another reason I said "weird" is that if I add this line:
die('dying before reading property');
Right before the above line (where I read a property), no errors occur, BUT the "dying before reading property" text is not output onto the page! This is weird because the script is clearly still executing code in the try block after the error is thrown (since without this die() line, the line reading the property is executed and results in lots of errors being output). As with before, the code in the catch block is still executed and the JSON is output onto the page.
What on earth is going on?
PHP is a compiled language. See this question and this answer for an explanation.
Basically, the code is parsed, assembled, and compiled into bytecode before it's executed; what's happening with your script is that the code is invalid. The syntax is correct, so PHP doesn't just outright fail. The issue arises after the object $person is constructed, when you try to access a dynamic property (modelData) that doesn't exist or is inaccessible due to its scope. So the errors you are seeing are because PHP can't find it.
The reason the code doesn't output 'dying before reading property' is because the code isn't actually being executed, so it can't "stop" execution; it's already stopped.
Change
$firstName = $person->modelData->name->givenName;
to
$firstName = $person->name->givenName;
and you should be good to go.
This question and its selected answer keep bothering me. It seems so unlikely that PHP would have executed/parsed/whatever, while an exception was already thrown.
I would rather suggest the code is being run twice. The first time giving the Exception message, and the second time producing the notices.
I suggest you try this:
put $testVar = uniqid(); just before try {
put echo $testVar; just after try {
When you run the code now you should see a unique ID just before the Exception message, and (my theory) another/different unique ID just before your notices. This would prove the code is being run twice.
About the die("..."); not appearing, I would ask if you really checked this looking in your HTML source, because it could be hidden for some reasong. (eg invisible div)
I use this to compile my java file
$command_compile = "javac $target_path_file 2>&1";
exec($command_compile, $compile_result, $return_compile);
And When my java file has syntax error. It always has error
Error: Could not find or load main class Myclass
How to get error such as Syntax Error. need ) On line 5
Thanks you
$res = exec($command_compile, $compile_result, $return_compile);
inside $res you get the last line of output of the executed command
If javac returns more lines (either error or informative messages) you may want to parse the $compile_result array that contains every output line.
foreach($compile_result as $compile_result_line) {
// do what you need with $compile_result_line
}
Anyway see http://php.net/function.exec for a detailed explanation of exec
The error you get is not from PHP code but is a "java" issue when you call javac. It seem you're trying to compile a file that reference an undefined class.
I get a notice from my php-script:
Undefined offset: 32 in C:\xampp\htdocs\WWW\myfilexyz.php on line 74
I want to detect where the error occurs as the procedure which produces the error is called many times.
I added the following line of code:
error_log("you made a mistake", 3, "errorfile.log");
Looking into errorfile.log, the message appears 3 times, but the procedure is called more than 100 times. How can I find the 3 lines where the error is produced?
I would like to see sometime like:
"you made a mistake, called from line 234 from start.php"
The easiest is to use a proper error handler which provides a stacktrace for each error. You can install xdebug, which outputs a lot more details about an error when activated. While you're at it, look into using xdebug to hook up a debugger (read xdebug's documentation).
Alternatively write your own error handler which uses debug_backtrace to give you a decent stacktrace.
$err = error_get_last();
error_log($err['message'] . ' in ' . $err['file'] . ' on line' . $err['line'], 3, "errorfile.log");
I'll give you the gist.
I'm trying to scrape certain URL's using a third party HTML tag stripper because I don't think the default strip_tags() does the job well. (I don't think you need to check that scraper)
Now sometimes, the HTML source code of some sites contains some weird code that is causing my HTML tag stripper to fail.
One such example is this site that contains the following piece of code :
<li>Photo Galleries</li>
that causes the above mentioned tag stripper to throw this error :
Parse error: syntax error, unexpected
T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or
T_NUM_STRING in /var/www/GET
Tweets/htdocs/tmhOAuth-master/examples/class.html2text.inc(429) :
regexp code on line 1 Fatal error:
preg_replace() [<a
href='function.preg-replace'>function.preg-replace</a>]:
Failed evaluating code:
$this->_build_link_list("<//?=$cnf[\'website\']?>girls/models-photo-gallery/?sType=6#top_menu",
"Photo Galleries") in /var/www/GET
Tweets/htdocs/tmhOAuth-master/examples/class.html2text.inc on line
429
Now what happens is, there is an array of many URLs and some throw the abovementioned error. I do some processing on each URL.
If some URL in the array throws an error like this, I want the execution to proceed ahead with processing of next URL without it disturbing anything. My code is something like this:
foreach ($results as $result)
{
$url=$result->Url;
$worddict2=myfunc($url,$worddict2,$history,$n_gram);
}
Here myfunc does the processing and uses the 3rd party HTML stripper I mentioned before.
I tried modifying the code to this:
foreach ($results as $result)
{
$url=$result->Url;
$worddicttemp=array();
try
{
$worddicttemp=myfunc($url,$worddict2,$history,$n_gram); //returns the string represenation of what matters, hopefully
//The below line will be executed only when the above function doesn't throw a fatal error
$worddict2=$worddicttemp;
}
catch(Exception $e)
{
continue;
}
}
But I'm still getting the same error.
What is wrong? Why is the code inside myfunc() now transferring control to the catch blocks as soon as it encounters that fatal error?
I propose you to use some beautifier script like Tidy before parsing. And your problem can be solved by adding
$html_content = htmlspecialchars($html_content)
You can't catch Parse Errors (or any Fatal Errors for that matter, but Parse Errors are even worse since they'll be generated as soon as the code is loaded). The best way I know of to isolate them is to run completely independent PHP processes for whatever you want to recover from and expect to generate Fatal Errors.
See also How do I catch a PHP Fatal Error
Greetings,
I am writing some code inside a framework for PHP 5.3, and I am trying to catch all errors in a way that will allow me to gracefully crash on client side and add some log entry at the same time. To be sure to also catch parse errors, I am using register_shutdown_function to specifically catch parse errors.
Here is the function that I register
static function shutdown()
{
if(is_null($e = error_get_last()) === FALSE)
if($e["type"] == E_PARSE)
self::error($e["type"], $e["message"], $e["file"], $e["line"], array(self::$url));
}
The error method does two things :
It adds an error entry to a log file using fopen in append.
It execute an error display: it explicitely sets the HTTP code to 500, and display a custom format 500 error page. Some include (which I do within a wapper class, but is only an include for now) are required from there
For some reason, I can fopen my log file and append, but cannot do a simple include; it just silently dies from there.
Here is what the log outputs if I add a Log entry for each includes
static public function file($file)
{
if(class_exists("Logs"))
Logs::append("errors.log", $file . ":" . ((include $file) ? 1 : 0));
else
include $file;
}
// Inside the Logs class...
static public function append($file, $message)
{
if(!is_scalar($message))
$message = print_r($message, true);
$fh = fopen(Config::getPath("LOGS") . "/" . $file, 'a');
fwrite($fh, $message."\r\n");
fclose($fh);
}
Here what the log file gives me:
/Users/mt/Documents/workspace/core/language.php:1
...
/Users/mt/Documents/workspace/index.php:1
/Users/mt/Documents/workspace/core/view.php:1
[2010-01-31 08:16:31] Parsing Error (Code 4) ~ syntax error, unexpected T_VARIABLE {/Users/mt/Documents/workspace/controllers/controller1.php:13}
After the parse error is hitted, it does run the registered function, but as soon as it hits a new include file, it dies of a silent death... is there a way to circumvent this? Why would I be able to open a file for read/write, but not for inclusion?
Try to use Lagger
It would seem that it is related with either something in the config, either with some build specifics.
I ran the code initially on MacOSX, which would not run and fail as described, but it runs on a compiled version of PHP under Ubuntu.
Which is kinda fine for me, but pretty much makes me wonder why it still fails under OSX (XAMPP to be more precise).