I have a file called functions.php.
This file consists includes to all the other function files, for example:
include_once("user_functions.php");
include_once("foo_functions.php");
I would like to catch errors where when I screw a code in one of those files, It wouldn't give the error to the entire system.
For example, if there is a parser error in foo_functions.php it will just not include it in functions.php.
Is that possible?
As of PHP 7, most eval/include errors, such as ParseError can be catched:
try {
include_once(__DIR__ . '/test.php');
} catch (\Throwable $e) {
var_dump($e);
}
Parser errors are fatal errors, so you can't catch them. See this question and answer for more details.
What you can do if you can run exec() is call php -l thefilename.php and check the result. See the manual for information on how this works. There are a few problems here, however:
This is extremely dangerous, because you are passing information to the command line. You absolutely must filter any user input very carefully, or you would be giving the user very broad access to your system.
exec() is often disabled, as it should be, because of the extremely high security risks of using it incorrectly.
There's really no good reason to include a file that you haven't already validated for syntax errors. If this is for plugins or something, then I understand your reasoning. If it is code you have control over, however, you should validate before putting it into production.
This code can check if file is exist or not, if file exist than include it.
<?
if(!is_file('user_functions.php')){
//There is no file user_functions.php . You may use file_put_contents('user_functions.php','<? //content ?>');
}else{
//ther is file user_functions.php, so include it.
include 'user_functions.php';
}
?>
And this one help you get syntax errors (PHP 7+ only)
<?
try {
include('user_functions.php');
}catch (ParseError $e) {
echo 'Error: '.$e->getMessage();
//syntax error, unexpected end of file, expecting ',' or ';'
}
?>
so if you use PHP 7+ you may use:
<?
if(!is_file('user_functions.php')){
echo 'Error: file is not exist';
}else{
//check errors
try {
include('user_functions.php');
}catch (ParseError $e) {
echo 'Error: '.$e->getMessage();
//syntax error, unexpected end of file, expecting ',' or ';'
}
}
?>
What if you put
error_reporting(E_ALL);
ini_set("display_errors", 1);
at the beginning of foo_functions.php ?
include() and include_once() return false if they fail. You can use this to check if the included files were successful.
if (!include('user_functions.php'))
echo 'user functions failed to include';
if (!include('foo_functions.php'))
echo 'foo_functions failed to include';
By changing the echos to handle your error logic, you should be able to do what you are asking.
The solution that I am using feels like a band-aid solution, but it will give you control back.
The idea is to use "eval()" to first check for errors. Also, ignore errors with the # in the beginning. Of course you will need to be careful with eval, so don't ever let users feed anything to it.
// first "eval" the file to see if it contains errors
$txt = file_get_contents($template_filename);
// eval starts out in php-mode. get out of it.
$txt = '?' . '>' . $txt;
ob_start();
$evalResult = #eval($txt);
ob_end_clean();
// if there are no errors
if($evalResult !== FALSE) {
require($template_filename);
} else {
error_log(print_r(error_get_last(), TRUE));
}
Please note that I think "file_get_contents + eval" = "require", or very close to it, so you may be able to just skip the require-part.
Related
Now that we can catch fatal errors in PHP7 (set_error_handler cannot), would it be a good idea to use it to catch errors on a whole project? Mine is always going through index.php, so I was planning to do this:
try {
//All the code and includes, etc.
} catch(Error $ignored) {
//save the error in log and/or send a notification to admin.
}
I tried first to be sure:
set_error_handler(function(int $number, string $message) {
echo "Error $number: '$message'" . PHP_EOL ;
});
$var = $undeclared_var //The error is sent to the error_handler.
function_dont_exist(); //The error isn't sent to the error_handler.
try {
function_dont_exist();
}
catch(Error $E){
echo "Error"; //That works.
}
Is it a good idea / good practice to envelope the whole code with a try/catch/error to deal with them? It sounds good, but I wonder why I don't see it much. I tried and I believe it works, but it sounds too easy.
Thank you for your help!
Sometimes we have functions which aren't intended to print (ie. output) anything. However, if some code within them throws an error, this will sometimes be output. That'll mean that this error shows up in our final HTML at whatever point the function was run. To avoid this, it occurs to me that it might be a good idea to put ob_start(); at the start of the function, and ob_end(); at the end (or before the return statement).
Is this a bad idea? Is it good practice? Are there pitfalls? Should I use ob_end_clean() instead?
How nested output buffering works seems relevant, but I don't understand this. It just occurs to me that my function might be called when another function has run ob_start(); but not yet run ob_end();.
An example might be in WordPress or Drupal.
There are certainly pitfalls. As you stated yourself the whole thing breaks down once an unexpected exception is thrown and not caught. Same goes for fatal errors that may occur. Output buffering should only be used where you want to ... well ... buffer the output.
Whether or not an error is shown or not should be totally independent of that and you should properly set your error_reporting() and display_errors for that (i.e. don't display anything on production environments).
it seems that you need to use exception. It allows doing what you want if your code does some unexpected happened.
In the example below, you can see how it could work
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
Exceptions See the documentation for more
Well, I have run into a bit of a pickle here. I am needing to check some PHP for syntax errors. I noticed this bit that needs to run from the commandline:
php -l somefile.php
However, is there a way to run this from within a PHP file itself? I've been looking and have think that I can use parse_str function somehow to accomplish this by entering it into a $_GET, but can't quite understand how this works.
Someone else told me to use token_get_all() php function to determine this.
But I can't figure out how to do this with any approach? Can anyone here give me some sample code to get started perhaps?? I don't think using eval() is the way to go, although I had an eval($code) working, but don't think I should run the script if there are PHP syntax errors.
Any help on this is greatly appreciated, as always!
You could simply do shell_exec() like this:
$output = shell_exec('php -l /path/to/filename.php');
This gives you the output of the command line operation in the string $output.
It is safer to check the return status of php -l
$fileName = '/path/to/file.php';
exec("php -l {$fileName}", $output, $return);
if ($return === 0) {
// Correct syntax
} else {
// Syntax errors
}
See this fiddle to see it in action
I use token_get_all for this. I have some PHP code in the db. Before saving, I do
function is_valid_php_code_or_throw( $code ) {
$old = ini_set('display_errors', 1);
try {
token_get_all("<?php\n$code", TOKEN_PARSE);
}
catch ( Throwable $ex ) {
$error = $ex->getMessage();
$line = $ex->getLine() - 1;
throw new InvalidInputException("PARSE ERROR on line $line:\n\n$error");
}
finally {
ini_set('display_errors', $old);
}
}
Works like a charm. Syntax only. No missing variables, type incompayibility etc.
InvalidInputException is my own. You can make it anything, or return a bool, or handle the exception yourself.
I'm not sure if display_errors is necessary. It was at some point.
I would do it like this:
$php_file = 'The path to your file';
if(substr(`php -l $php_file`, 0, 16) == 'No syntax errors') {
// Correct syntax
} else {
// Error
}
php_check_syntax should do the trick. If you're running PHP >= 5.05, see the first comment in the comments section for the implementation.
You can use exec to check for syntax errors.
$tempFile = path/of/file
$syntaxParseError = strpos(exec('php -l '.$tempFile), 'No syntax errors detected') === false;`
Unfortunately, this will not give you the line number or tell you anything about the error. For that you will either need to install static analyzer on your server Is there a static code analyzer [like Lint] for PHP files? or write your own parser.
NB. token_get_all() will not determine anything on its own, but it useful function for making a parser.
Why use the shell at all?
function syntax_is_valid($code)
{
try
{
#eval($code);
}
catch (ParseError $e)
{
return false;
}
return true;
}
Alternatively use $e->getMessage() for more info.
Well, I have run into a bit of a pickle here. I am needing to check some PHP for syntax errors. I noticed this bit that needs to run from the commandline:
php -l somefile.php
However, is there a way to run this from within a PHP file itself? I've been looking and have think that I can use parse_str function somehow to accomplish this by entering it into a $_GET, but can't quite understand how this works.
Someone else told me to use token_get_all() php function to determine this.
But I can't figure out how to do this with any approach? Can anyone here give me some sample code to get started perhaps?? I don't think using eval() is the way to go, although I had an eval($code) working, but don't think I should run the script if there are PHP syntax errors.
Any help on this is greatly appreciated, as always!
You could simply do shell_exec() like this:
$output = shell_exec('php -l /path/to/filename.php');
This gives you the output of the command line operation in the string $output.
It is safer to check the return status of php -l
$fileName = '/path/to/file.php';
exec("php -l {$fileName}", $output, $return);
if ($return === 0) {
// Correct syntax
} else {
// Syntax errors
}
See this fiddle to see it in action
I use token_get_all for this. I have some PHP code in the db. Before saving, I do
function is_valid_php_code_or_throw( $code ) {
$old = ini_set('display_errors', 1);
try {
token_get_all("<?php\n$code", TOKEN_PARSE);
}
catch ( Throwable $ex ) {
$error = $ex->getMessage();
$line = $ex->getLine() - 1;
throw new InvalidInputException("PARSE ERROR on line $line:\n\n$error");
}
finally {
ini_set('display_errors', $old);
}
}
Works like a charm. Syntax only. No missing variables, type incompayibility etc.
InvalidInputException is my own. You can make it anything, or return a bool, or handle the exception yourself.
I'm not sure if display_errors is necessary. It was at some point.
I would do it like this:
$php_file = 'The path to your file';
if(substr(`php -l $php_file`, 0, 16) == 'No syntax errors') {
// Correct syntax
} else {
// Error
}
php_check_syntax should do the trick. If you're running PHP >= 5.05, see the first comment in the comments section for the implementation.
You can use exec to check for syntax errors.
$tempFile = path/of/file
$syntaxParseError = strpos(exec('php -l '.$tempFile), 'No syntax errors detected') === false;`
Unfortunately, this will not give you the line number or tell you anything about the error. For that you will either need to install static analyzer on your server Is there a static code analyzer [like Lint] for PHP files? or write your own parser.
NB. token_get_all() will not determine anything on its own, but it useful function for making a parser.
Why use the shell at all?
function syntax_is_valid($code)
{
try
{
#eval($code);
}
catch (ParseError $e)
{
return false;
}
return true;
}
Alternatively use $e->getMessage() for more info.
How to print custom error when trying to include/require a php file ?
This was my idea:
<?php
try{
include "template/".$_GET['view'].".php";
}
catch (Exception $e){
echo 'some error code';
};
?>
But, still I'm getting default error if required file don't exist.
Decided the comment was worth changing to answer:
Use file_exists() to see if file exists.
If it does, include, else echo your custom error message.
Use file_exists() to check if the file is there before including. That way you can handle the error.
<?php
if(file_exists('asd.php')){
include "asd.php";
}else{
echo "Oh no! The file doesn't exist!";
}
?>
The include errors are not going to be caught by your try/catch, however, I believe that errors inside the included script would be caught correctly. A better solution would be to use the file-exists function, see this post for an example: Optional include in PHP
Once you perform your own verification for the existence for the file you can wrap the executing code in a try catch to ensure errors in that code are caught.
I would not recommend using just file_exist. You don't want your visitor to have access to any file on your file-system so I would recommend a white-list; if the file-name is in the white-list, only then display / include it.
if ((include "template/".$_GET['view'].".php") != 'OK') {
echo "My custom error message";
}
If you want your own error Message you can do it like this:
<?php
$file = "template/".$_GET['view'].".php";
if ( error_reporting() == 0 ){
( #include_once($file) ) OR die("<tt><p><b>ERROR</b> $file file not found!</p>");
}else{
require_once($file);
}
?>
So if there is no error reporting (as most time in productiv enviroment) you can print your own Error Message. If you are in Development Mode (ans error_reporting is on) the you get PHP Error Message!
HINT Never use $_GET Input from user direct for an Include - this is a Black XSS Hole :-D