I have three text files containing the same set of error messages in three languages: English, French and German.
I need to extend the exception class so that when something goes wrong, the own exception object will be thrown, such as "throw new My-Exception("English", 4) - then 4th message in English file will be shown.
This is what I made so far:
<?php
class My_Exception extends Exception {
function __construct($lang, $errcode) {
$this->lang = $lang;
$this->errcode = $errcode;
}
function getMessageMap() {
$errors = file('errfiles/'.$this->lang.'.txt');
foreach($errors as $error) {
list($key,$value) = implode(',', $errors);
$errorArray[$key] = $value;
}
return $errorArray[$this->errcode];
}
}
try { throw new My_Exception('english', 3); }
catch (My_Exception $e) { echo $e->getMessageMap(); }
?>
This doesn't work properly. I will appreciate any help.
Instead of throwing specific exception messages for each language, I would stick to one normal exception. Then, in your application when you catch those errors, you can show an error page for specific languages. In other words, don't overhaul your application architecture (even in this minor way) for what is ultimately a font-end problem.
You mention that the error message looks like this:
file(errfiles/English.txt): failed to open stream
So try using the full path of the error file...
$errors = file('C:/xampp/htdocs/HW4/errfiles/'.$this->lang.'.txt');
Also can you confirm that the file really does start with a capital "E"?
The second error:
Invalid argument supplied for foreach() in
C:\xampp\htdocs\HW4\index.php on line 13
Is because of the first one. Fix that and all is well.
I think you have implode() and explode() mixed up. Assuming your errors.txt file looks like:
1,I am error one
2,I am error two
You want each $errors as $error to thusly explode(',', '1,I am error one'); as:
array("1", "I am error 1")
And yes, the "1" is a string until you specifically cast it as an int using either (int)$errno or intval($errno).
PHP is 'loosely typed' and usually does this in the background so you don't have to worry about it, but you should worry about it. Otherwise you'll run into the occasional situations where your code does very strange things.
Related
I need some function that will accept a function as the parameter and will run it in try {} catch (Exception $e) {}. If it runs successfully, do nothing, otherwise, throw new Exception. That's something like function-checker, which checks functions if they ran successfully. Anybody can help me or give advice?
Thanks for any replies.
The function should work like that:
function itwillfail () {
echo 10 / 0;
}
check("itwillfail");
Output: Caught exception: Custom exception text here, because it has been thrown as custom.
("check" is that function I need)
What I tried:
function check($func) {
try {
call_user_func($func);
} catch (Exception $e) {
throw new Exception("Custom text here.");
}
}
EDIT: More explained: I need to create function, which do the same as "try" and a lot of different "catch"es for different types of exceptions.
Summarizing your question:
You want a way to call a custom function from a string variable (which you have already figured out that would be via call_user_func($var);.
You then want that function to throw a custom exception error
Confused
What is not clear is the reason you would opt to not define your error handler using the set_error_handler function which would effectively do what your asking and set a switch statement to output different messages based on the error generated.
Example
The following example is not using a call_user_func but it effectively allows you to write how the error will be handled
<?php
function myerror($error_no, $error_msg) {
echo "Error: [$error_no] $error_msg ";
echo "\n Now Script will end";
die();
}
// Setting set_error_handler
set_error_handler("myerror");
$a = 10;
$b = 0;
// Force the error
echo($a / $b);
?>
Not every function throws an exception when they fail. Many functions, especially ones that have been around for a long time, simply trigger PHP errors rather than exceptions.
To handle those, you would use a custom error handler:
https://www.php.net/manual/en/function.set-error-handler.php
So you could set up a custom error handler that would intercept those kinds of failures and throw them as exceptions. The whole point of that function is to do what you're trying to do - handle errors in a custom way.
I'd like to able to catch an exception and continue with the execution of other subsequent functions (and possibly log an error in the catch section). In the code sample below, there are instances where $html->find doesn't find the element and returns error exception undefined offset. In such cases, the entire script fails. I don't want to specifically test for this error but rather any error that may occur within the code block in the try section.
public function parsePage1($provider)
{
$path = $this->getFile($provider);
$link = $this->links[$provider];
if (file_exists($path)) {
$string = file_get_contents($path);
$html = \HTMLDomParser::str_get_html($string);
$wrapper = $html->find('.classToLookFor')[0];
unset($string);
}
}
try {
$this->parsePage1('nameOfProvider');
} catch(Exception $e) {
// continue...
}
try {
$this->parsePage2('nameOfProvider');
} catch(Exception $e) {
// continue...
}
No, there is no way to make the code within the try block continue past an exception. An exception terminates the function just like a return would; there is no way to restore the state of the function afterwards.
Instead, avoid triggering the error in the first place:
$wrappers = $html->find('.classToLookFor'); # <-- no [0]!
if (count($wrappers)) {
$wrapper = $wrappers[0];
...
}
Just to be clear, the 'error' in this case was a notice. If your errorlevel does not include notices, which is typically the case in production, your code will continue past that point.
With that said, Notices and warnings are intended for developers to add checks for expected input, as in duskwuff's example.
Unfortunatley, duskwuff's answer is problematic with the most recent versions of php at 7.2+. This is because count() expects either an array or an object that implements countable.
With the newest version you will get a Warning:
Warning: count(): Parameter must be an array or an object that implements Countable in
You will be back where you were before using count() only. A simple fix for that is to add a check for is_array.
$wrappers = $html->find('.classToLookFor'); # <-- no [0]!
if (is_array($wrappers) && count($wrappers)) {
$wrapper = $wrappers[0];
...
}
I also want to point out, that per my original comment, the whole purpose of exception catching is to protect against program termination errors.
This was not a good example of the types of errors where you should apply try-catch, but to be clear, your original code does continue... just not within the try section of the code, but after the catch()
This simulation of your original problem illustrates that:
<?php
function findit($foo) {
return $foo[0];
}
try {
findit('');
} catch(Exception $e) {
var_dump($e);
}
echo 'Hey look we continued';
Output will be something like:
Notice: Uninitialized string offset: 0 in ... on line 4
Hey look we continued
I feel this needs to be added as a response because people in the future are going to probably find this question, which really has nothing much to do with try-catch handling, and really has to do with code that expects to work with an array, but might not get one.
I've run into this issue before, but I can't remember how to solve it. I have created a bare bones (can't get any simpler) controller, and am just trying to echo something to the browser, and I am getting this message:
Fatal error: Uncaught exception 'Zend_Session_Exception' with message 'Session must be started before any output has been sent to the browser ...
Here's my entire controller. It's displaying 'success', but it also displays the error message. How can I silence that error message so I can simply echo something to the browser?
<?php
class CacheController extends Zend_Controller_Action
{
public function clearAction()
{
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();
try {
$result = Model_Cache::emptyCache(array('foobar'=>1));
if ($result['status'] == true) {
echo 'Success';
} else {
echo 'Error: ' . $result['message'];
}
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
}
}
}
From memory, this error is usually due to non-PHP code starting the output before intended (and session initialisation). Usually it's due to whitespace or carriage returns after unnecessary ?> tags. This is the first thing I'd check for.
What the error sounds like it is saying is that you are not starting the Zend_Session before data is being sent to the browser. Typically I have something like I pasted below in my bootstrap to start the Zend_Session.
protected function _initSessions()
{
Zend_Session::start();
}
That should get you going in the Zend Framework. If you are using this tool outside the framework just use that inner line of code near the top of your PHP scripts before you echo or print anything.
Hope that helps!
I found a similar post on this problem:
PHPUnit output causing Zend_Session exceptions
I had the same problem but the solution that was proposed on the previous link did not worked for me, so after some testing I found that there is a variable on the class Zend_Session
/**
* Whether or not Zend_Session is being used with unit tests
*
* #internal
* #var bool
*/
public static $_unitTestEnabled = false;
If you set this variable to "true" the phpunit execution works without any problem. At least that is what happened in my case.
Hope this help
I encountered same problem and my issue was that I was echoing a STRICT warning that was being put to the screen.
A good way to debug this is issue is the use ob_start() and ob_get_contents();
Hope it helps
For some reason, I was trying to set some session variable in my index.php file after the application had finished bootstrapping. Not sure why this didn't cause a problem before, but when I removed this from my index.php, it worked.
$userSession = new Zend_Session_Namespace('Auth');
$userSession->forcePasswordChange = false;
Possible the session is started through your application.ini or php.ini (session autostart) ? If you use an ide try to search for "spaces".
Sometimes searching for " " (with spaces) helps.
I had the same error message. But only for one action. Problem has been caused by these two lines in controller's action:
$customersModel = new Default_Model_DbTable_Customers();
$this->view->customers = $customersModel->fetchAll();
In my database were more than 6000 customers. So it is not good to push a lot of records to view.
I have been dealing with PHP since 2000, but not very actively, and my knowledge of PHP5 is quite horrible. Recently I got my interest for webdevelopment back after a 5 year long break, and I started working on a project. I wrote a class for that project that became fairly large, but so far without any specific error handling.
The purpose of the class is to parse HTML files with a specific layout and handle its data, and it was more or less a training exercise for me to get back into the game. I started to rewrite the class now, and I decided it was time to be a little more professional about error handling than simply using die(), which I have been using a lot so far. I think we can all agree that is a terrible direction to take. I want the class to be quite project independent, so that I can distribute it to whoever wants to use it.
The HTML files I want to parse contain tables with specific bordercolors, trs with specific bgcolors, but the number of elements are dynamic. To validate that the HTML files actually have this specific pattern, I have the following sample (pseudo)code
public function Validate() {
$tables = getall('table', $this->data);
foreach ($tables as $table) {
if ($table->bordercolor != 'navy' && $table->cellspacing != 0) {
// Error
}
foreach ($tables->tr as $tr) {
if ($tr->bgcolor != '#fff') {
// Error
}
}
}
return true;
}
Where it says // Error, the HTML layout doesn't check out and my class should not attempt to parse it. Traditionally I would do this:
if ($table->bgcolor != '#fff') {
$this->error = 'Invalid HTML layout';
return false;
}
And from where I call the method I would use
if ($class->Validate() === false) {
exit_with_error($class->GetError()); // Simple return of $this->error
}
I've always thought it's a decent approach because of it's simplicity. However that's also a disadvantage as it doesn't really provide any in-depth information of the error apart from the text itself. I can't see where the error was triggered, what methods were called, etc.
Since I resumed my PHP hobby I have discovered exceptions. My problem with them is simply that I don't understand how to properly use them. And if I should use them at all. I would like my class to be portable; can I use exceptions to handle errors at all? And if yes, how can I communicate the errors (i.e. translate my traditional error handling)? Or perhaps there is an even better approach to take, which I don't know about.
Any help appreciated :)
You are certainly thinking along the right path. Typically, I like to separatte class design from error handling logic. In other words I don't want to have a bunch of $this->error = 'something' logic in the class, as why would you want to add extra code to every class to store/handle/report errors.
Now you get into exceptions vs. errors and when to use each. This is likely a subject for debate, but my personal preference has largely been to throw Exceptions in cases where you get to a point in your code that you cannot recover from or do not have the logic to handle. A great example of this, that I typically use, is throwing Exceptions right at the beginning of any class method that requires parameters of a certain sort or value. Like this example:
public method set_attribute($value) {
if (empty($value)) {
throw new Exception('You must send me something');
} else if (!is_string($value)) {
throw new Exception("You sent me something but it wasn't the string I was expecting.");
}
// method logic here
}
Here if the caller didn't give us a non-empty string, we throw an Exception, as we were not expecting this and we can't guarantee successful completion of the method without a proper value. There is not reason to continue with the method at all. We send the caller the exception with a message about the problem. Hopefully they invoked this method in a try-catch block and can gracefully handle the exception and pass it along up the call stack. If not, your code just stopped execution with fatal error from an uncaught exception (something really easy to catch in testing).
Triggering errors, I honestly use a lot less, and typically use them more for debug, warning purposes. An example of this might be a deprecated method that you still want to work, but you want to give the user an error on
public function old_method() {
trigger_error('This method had been deprecated. You should consider not using it anymore.'. E_USER_WARNING);
// method logic
}
Of course you can trigger whatever level of E_USER class warning here yourself.
Like I said, I tend to work a lot more with Exceptions, as they are also easily extensible for easy use with logging and such. I almost always would have a custom Exception class extending from PHP's base Exception class that also provides logging, etc.
The other thing to consider is global error handling and Exceptoin handling. I strongly recommend using these and having these be some of the very first lines of code in any new project. Again, it will give you much better control over how you log errors/exceptions than what you can get by default.
I don't see a problem with how you are doing it, but If you want to dive into Exceptions, learn how to use try/catch statements. Usually it would be something like this:
try {
//some code that may cause an error here
} catch (Exception e) {
//if a error is found, or an exception is thrown in the try statement, whatever here will execute
//you can get the error message by using e->getMessage()
}
you can read more about it here: http://php.net/manual/en/language.exceptions.php
I'm familiar with some of the basics, but what I would like to know more about is when and why error handling (including throwing exceptions) should be used in PHP, especially on a live site or web app. Is it something that can be overused and if so, what does overuse look like? Are there cases where it shouldn't be used? Also, what are some of the common security concerns in regard to error handling?
One thing to add to what was said already is that it's paramount that you record any errors in your web application into a log. This way, as Jeff "Coding Horror" Atwood suggests, you'll know when your users are experiencing trouble with your app (instead of "asking them what's wrong").
To do this, I recommend the following type of infrastructure:
Create a "crash" table in your database and a set of wrapper classes for reporting errors. I'd recommend setting categories for the crashes ("blocking", "security", "PHP error/warning" (vs exception), etc).
In all of your error handling code, make sure to record the error. Doing this consistently depends on how well you built the API (above step) - it should be trivial to record crashes if done right.
Extra credit: sometimes, your crashes will be database-level crashes: i.e. DB server down, etc. If that's the case, your error logging infrastructure (above) will fail (you can't log the crash to the DB because the log tries to write to the DB). In that case, I would write failover logic in your Crash wrapper class to either
send an email to the admin, AND/OR
record the details of the crash to a plain text file
All of this sounds like an overkill, but believe me, this makes a difference in whether your application is accepted as a "stable" or "flaky". That difference comes from the fact that all apps start as flaky/crashing all the time, but those developers that know about all issues with their app have a chance to actually fix it.
Roughly speaking, errors are a legacy in PHP, while exceptions are the modern way to treat errors. The simplest thing then, is to set up an error-handler, that throws an exception. That way all errors are converted to exceptions, and then you can simply deal with one error-handling scheme. The following code will convert errors to exceptions for you:
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
set_error_handler('exceptions_error_handler');
error_reporting(E_ALL ^ E_STRICT);
There are a few cases though, where code is specifically designed to work with errors. For example, the schemaValidate method of DomDocument raises warnings, when validating a document. If you convert errors to exceptions, it will stop validating after the first failure. Some times this is what you want, but when validating a document, you might actually want all failures. In this case, you can temporarily install an error-handler, that collects the errors. Here's a small snippet, I've used for that purpose:
class errorhandler_LoggingCaller {
protected $errors = array();
function call($callback, $arguments = array()) {
set_error_handler(array($this, "onError"));
$orig_error_reporting = error_reporting(E_ALL);
try {
$result = call_user_func_array($callback, $arguments);
} catch (Exception $ex) {
restore_error_handler();
error_reporting($orig_error_reporting);
throw $ex;
}
restore_error_handler();
error_reporting($orig_error_reporting);
return $result;
}
function onError($severity, $message, $file = null, $line = null) {
$this->errors[] = $message;
}
function getErrors() {
return $this->errors;
}
function hasErrors() {
return count($this->errors) > 0;
}
}
And a use case:
$doc = new DomDocument();
$doc->load($xml_filename);
$validation = new errorhandler_LoggingCaller();
$validation->call(
array($doc, 'schemaValidate'),
array($xsd_filename));
if ($validation->hasErrors()) {
var_dump($validation->getErrors());
}
The best practice IMHO is to use the following approach:
1. create an error/exception handler
2. start it upon the app start up
3. handle all your errors from inside there
<?php
class Debug {
public static setAsErrorHandler() {
set_error_handler(array(__CLASS__, '__error_handler'));
}
public static function __error_handler($errcode, $errmsg, $errfile, $errline) {
if (IN DEV) {
print on screen
}
else if (IN PRO) {
log and mail
}
}
}
Debug::setAsErrorHandler();
?>
Unhanded errors stop the script, that alone is a pretty good reason to handle them.
Generally you can use a Try-Catch block to deal with errors
try
{
// Code that may error
}
catch (Exception $e)
{
// Do other stuff if there's an error
}
If you want to stop the error or warning message appearing on the page then you can prefix the call with an # sign like so.
#mysql_query($query);
With queries however it's generally a good idea to do something like this so you have a better idea of what's going on.
#mysql_query($query)
or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />');
You should use Error Handling in cases where you don't have explicit control over the data your script is working on. I tend to use it frequently for example in places like form validation. Knowing how to spot error prone places in code takes some practice: Some common ones are after function calls that return a value, or when dealing with results from a database query. You should never assume the return from a function will be what your expecting, and you should be sure to code in anticipation. You don't have to use try/catch blocks, though they are useful. A lot of times you can get by with a simple if/else check.
Error handling goes hand in hand with secure coding practices, as there are a lot of "errors" that don't cause your script to simply crash. while not being strictly about error handling per se, addedbytes has a good 4 article series on some of the basics of secure PHP programming which you can find HERE. There are a lot of other questions here on stackoverflow on topics such as mysql_real_escape_string and Regular Expressions which can be very powerful in confirming the content of user entered data.
Rather than outputing the mysql_error you might store it in a log. that way you can track the error (and you don't depend on users to report it) and you can go in and remove the problem.
The best error handling is the kind that is transparent to the user, let your code sort out the problem, no need to involve that user fellow.
besides handling errors right away in your code you can also make use of
http://us.php.net/manual/en/function.set-exception-handler.php
and
http://us.php.net/manual/en/function.set-error-handler.php
I find setting your own exception handler particularly useful. When an exception occurs you can perform different operations depending on what type of exception it is.
ex: when a mysql_connet call returns FALSE I throw a new DBConnectionException(mysql_error()) and handle it a "special" way: log the error, the DB connection info (host, username, password) etc and maybe even email the dev team notifying them that something may be really wrong with the DB
I use this to compliment standard error handling. i wouldnt recommend overusing this approach
Error suppression with # is very slow.
You can also use Google Forms to catch and analyse exceptions, without having to maintain a database or publicly accessible server. There is a tutorial here that explains the process.
public $error=array();
public function Errors($Err)
{
------ how to use -------
$Err = array("func" => "constr", "ref" => "constrac","context" =>
"2222222ت","state" => 3,);
$ResultErr=$this->Errors($Err);
$context=(array_filter(explode(',', $ResultErr['context'])));
$func=(array_filter(explode(',', $ResultErr['func'])));
$ref=(array_filter(explode(',', $ResultErr['ref'])));
$state=($ResultErr['state']);
$errors=array_merge(["context"=>$context], ["func"=>$func],
["ref"=>$ref], ["state"=>$state]);
var_dump($errors);
---------------begine ------------------------
global $error;
if (!is_array($Err)) {
return $error;
} else {
if (!(isset($error['state']))) {
$error['state']="";
}
if (!(isset($error['func']))) {
$error['func']="";
}
if (!(isset($error['ref']))) {
$error['ref']="";
}
if (!(isset($error['context']))) {
$error['context']="";
}
$error['state']=$error['state'];
$error['func']=$error['func'].= $Err["func"].",";
$error['ref']=$error['ref'].= $Err["ref"].",";
$error['context']=$error['context'].= $Err["context"].",";
$error["state"]=$Err["state"];
return $error;
}
}