I would like the error log to show each error on a new line beginning with a time stamp.
Currently the errors just show up in a connected chunk.
catch(PDOException $e) {
file_put_contents('logs/insert_errors.txt', $e->getMessage(), FILE_APPEND);
}
I'm sure this is fairly simple. Just my first time working with PDO and not sure how to accomplish this.
Preamble: As #Phil mentioned this has nothing to do with PDO.
There are two parts to your question:
a) it is all in one connected line
The reason is quite obvious, you are not adding a new line character at the end. What that character(s) is(are) depend on your OS, but PHP solves that for you with the PHP_EOL constant that you can just append to the end of your string.
b) you want a timestamp at the beginning of each line
Again, the issue is because you didn't put it there. Just adding the output of date('r') before printing out the message should be enough.
The real solution: a real logger
You may want to look at using a complete logging solution for your code. Someting like log4php, for example.
Homebrew solution
Alternatively, if that is too much, you could build your own logger. A good small example one can be found in the comments of the documentation of PHP's error_log function that I adapted for your needs:
Class Log {
const ERROR_DIR = '/home/site/error_log/db_errors.log';
// Log PDO errors
public function error($msg) {
$date = date('r');
$log = sprintf('%s: %s%s', $date, %msg, PHP_EOL);
error_log($log, 3, self::ERROR_DIR);
}
// shortcut for PDO exceptions
public function exception($e) {
$this->error($e->getMessage())
}
}
try {
$log = new log();
$log->error($msg); //use for general messages
} except (Exception $e)
$log->exception($e); //use for exceptions
}
Simply format the string to be inserted, eg
catch (PDOException $e) {
$error = sprintf('%s: %s%s', date('c'), $e->getMessage(), PHP_EOL);
file_put_contents('logs/insert_errors.txt', $error, FILE_APPEND);
// don't forget to re-throw the exception otherwise your program will
// continue execution
throw $e;
}
Related
I am currently developing my PHP SDK to interact with a REST API. Let's say the API can create a 'car' model. To create a car I would write something like this...
$car = $api->create('car', array(
'wheels' => 6,
'color' => 'blue'
));
If another developer downloads my SDK and tries to create a car model incorrectly and forgets to include required arguments. How can I throw an exception via the SDK to notify the developer of missing arguments, other than them seeing a PHP error like Warning: Missing argument 1 for BMW::create() which does not include many details.
function foo($bar, $baz) {
if (!isset($bar, $baz)) {
throw new InvalidArgumentException("Detailed description of what's wrong here");
}
...
}
PHP will trigger a warning, but will still execute your function as usual (which is... oh well, let's not dwell on it). That means you can do your regular argument checking inside your function and throw exceptions or trigger_errors all you want in as much detail as you want.
Please go through this page...
http://php.net/manual/en/language.exceptions.php
And try something like following
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
// Continue execution
echo "Hello World\n";
?>
As of PHP 7.1, invoking user-defined functions with too few arguments will result in an Error exception. You do not need to implement the functionality yourself.
https://www.php.net/manual/en/migration71.incompatible.php
I have a class Person.
I want to add error handling into my script, so that say, the user enters an incorrect email address the script will tell them. Usually not a problem at all, but now I am using OO classes I am in unfamiliar territory.
So. I guess I want to know how to handle multiple exceptions. Or do I need to try each line of code one at a time and catch each line? This seems slightly excessive. Ideally I'd like to do the following:
try {
$people[$new]->set_fullname($_POST['name']);
$people[$new]->set_active(true);
$people[$new]->set_add1(rEsc($_POST['add1']));
$people[$new]->set_add2(rEsc($_POST['add2']));
$people[$new]->set_add3(rEsc($_POST['add3']));
$people[$new]->set_add4(rEsc($_POST['add4']));
$people[$new]->set_postcode(rEsc($_POST['postcode']));
$people[$new]->set_phone(rEsc($_POST['phone']));
$people[$new]->set_email(rEsc($_POST['email']));
} catch {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
But in my error handling, How can I catch multiple errors? I'd like to push all the error messages into an array and display them each nicely in the webpage. As far as I can see on php.net it seems that I can only catch one error message at a time.
Do I really have to try {} catch {} each line of code?
Imho this shouldn't throw exceptions in the first place. Simply loop through the fields and add the possible errors to some $errors array.
Users screwing up fields is not an exceptional case. I don't even think the user object should be able to validate an emailaddress. That seems to be like a responsibility of the Form.
Also am I wondering what that rEsc function is you are using. Not only are you using a global function which makes it virtually impossible to swap it out for some other function in the future (tight coupling), but also the name is chosen badly. Also do I fail to see why you would want to escape stuff in that place (I guess that is what the thing does). Only escape / sanitize data when you are using it. And I'm wondering for what you are escaping your data, because if it is for database input there are far better ways.
try {
$people[$new]->set_fullname($_POST['name']);
$people[$new]->set_active(true);
$people[$new]->set_add1(rEsc($_POST['add1']));
$people[$new]->set_add2(rEsc($_POST['add2']));
$people[$new]->set_add3(rEsc($_POST['add3']));
$people[$new]->set_add4(rEsc($_POST['add4']));
$people[$new]->set_postcode(rEsc($_POST['postcode']));
$people[$new]->set_phone(rEsc($_POST['phone']));
$people[$new]->set_email(rEsc($_POST['email']));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} catch (EmailFormatException $em) {
echo 'Caught exception: '. $e->getMessage();
}
Just continue it like that
Here's how I would design this:
Create a validate() method on the Person class that verifies every property and returns an array of strings that explain the errors to the user. If there are no errors, have the method return null.
Do not use exceptions at all. They are slow; they complicate code maintenance (and you're seeing the symptoms in the approach you've taken so far)
Remove the custom methods for setting properties of the Person object. PHP is not Java. Set the properties directly.
Putting this all together:
class Person {
public $name;
public $address1;
public $address2;
public function validate() { }
}
And then your code:
$obj = new Person();
$obj->name = "Bob";
$obj->address1 = "1 Elm St.";
$validationResult = $obj->validate();
if ( $validationResult != null) { // there were errors
print_r($validationResult);
}
You can make a foreach statement that sets the data that needs validation with try/catch inside the loop in order to populate an array with the errors, like that:
$errors = [];
foreach (['field1', 'field2', ...] as $field) {
try {
$method = "set_{$field}";
$people[$new]->$method(rEsc($_POST[$field]));
} catch (Exception $e) {
$errors[] = $e->getMessage();
}
}
Since a short period of time I'm working with Try Catch in PHP. Now, every time a new error is thrown you get a fatal error on the screen, this isn't really user friendly so I was wondering if there's a way to give the user a nice message like an echo instead of a fatal error.
This is the code I have now:
public static function forceNumber($int){
if(is_numeric($int)){
return $int;
} else {
throw new TypeEnforcerException($int.' must be a number');
}
}
public function setStatus($status) {
try {
$this->status = TypeEnforcer::forceInt($status);
} catch (TypeEnforcerException $e) {
throw new Exception($e->getMessage());
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
This is best solved with a frontend controller that is able to catch all uncatched exceptions:
<?php
require('bootstrap.php');
try {
$controllerService->execute($request);
} catch (Exception $e) {
$controllerService->handleControllerException($e);
}
You can then write code to return the internal server error because an exception signals an exceptional case so it normally is an 500 internal server error. The user must not be interested what went wrong other than it just didn't work out and your program crashed.
If you throw exceptions to give validation notices you need to catch those in a different layer (and you're probably doing it wrong if you use exceptions for that).
Edit: For low-level functions, because PHP is loosely typed, if a function expects and int, cast to intDocs:
public static function forceNumber($int){
$int = (int) $int;
return $int;
}
this will actually force the integer. In case the cast is not possible to do (e.g. $int it totally incompatible) PHP will throw the exception for you.
The example is a bit akward because by the method's name you use it to validate some number and provide an error if not (here wrongly with an exception). Instead you should do some validation. If you expect wrong input, it's not an exceptional case when wrong input is provided, so I would not use exceptions for that.
I'm using try-catch for years, but I never learned how and when to use finally, because I never understood the point of finally (I've read bad books)?
I want to ask you about use of finally in my case.
My code example should explain everything:
$s = "";
$c = MyClassForFileHandling::getInstance();
try
{
$s = $c->get_file_content($path);
}
catch FileNotFoundExeption
{
$c->create_file($path, "text for new file");
}
finally
{
$s = $c->get_file_content($path);
}
Is this correct use of finally?
More precise question:
Shall I use finally (in future PHP versions or other languages) for handling "create something if it not exists" operations?
Finally will always be executed, so in this case, it is not its intended purpose, since normal execution would reopen the file a second time. What you intend to do would be achieved in the same (cleaner) way if you do
$s = "";
$c = MyClassForFileHandling::getInstance();
try
{
$s = $c->get_file_content($path);
}
catch(FileNotFoundExeption $e)
{
$c->create_file($path, "text for new file");
$s = $c->get_file_content($path);
}
Then the manual says:
For the benefit of someone anyone who hasn't come across finally blocks before, the key difference between them and normal code following a try/catch block is that they will be executed even the try/catch block would return control to the calling function.
It might do this if:
code if your try block contains an exception type that you don't catch
you throw another exception in your catch block
your try or catch block calls return
Finally would then be useful in this kind of scenario:
function my_get_file_content($path)
{
try
{
return $c->get_file_content($path);
}
catch(FileNotFoundExeption $e)
{
$c->create_file($path, "text for new file");
return $c->get_file_content($path);
}
finally
{
$c->close_file_handler();
}
}
=> if you need to make sure you close your file handler in this case, or some resource in general.
finally wasn't introduced into PHP until version 5.5 which has not been released yet so that why you haven't seen any examples with it yet. So unless you're running and alpha version of PHP 5.5 you can't use finally yet.
From the manual (exceptions)
In PHP 5.5 and later, a finally block may also be specified after the catch blocks. Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.
Example from the manual of using finally
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
else return 1/$x;
}
try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}
try {
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "Second finally.\n";
}
// Continue execution
echo 'Hello World';
?>
Finally means what do you want to DO Finally.
try
{
$s = $c->get_file_content($path);
}
catch FileNotFoundExeption
{
$c->create_file($path, "text for new file");
}
finally
{
//Create a pdf with my file
//or, Rename my file
//or, store my file into Database
}
No matter what happens(regardless of whether an exception has been thrown) inside try or catch, 'Finally code' will execute.
So, no point of using same code over 'try' and 'finally'.
Does this simply answer your question?
I just want to appoint that if an Exception occurs in the try block, the exception will be correctly raised even if the finally block is present.
The usefulness of the finally block is for clean and free resources.
I think it's best use is when, for example, you upload a file but then an error happens:
$tmp_name = null;
try {
$tmp_name = tempnam(UPLOAD_DIR, 'prefix');
move_uploaded_file($file['tmp_name'], $tmp_name);
ImageManager::resize($tmp_name, $real_path, $width, $height); // this will rise some exception
}
finally {
if($tmp_name)
unlink($tmp_name); // this will ensure the temp file is ALWAYS deleted
}
As you can see, in this way no matter what happen, the temp file will be correctly deleted.
If we would emulate the finally clause in older version of PHP, we should write something like this:
// start finally
catch(Exception $ex) {
}
if($tmp_name)
unlink($tmp_name);
if( isset($ex) )
throw $ex;
// end finally
Note that the exception has been re-thrown in case the catch block caught something. It isn't clear as the finally version, but works the same.
Which would you recommend?
Return an error code, such as E_USER_ERROR from a function, and determine proper message higher up:
function currentScriptFilename()
{
if(!isset($_SERVER['SCRIPT_FILENAME']))
{
//This?
return E_USER_ERROR;
}
else
{
$url = $_SERVER['SCRIPT_FILENAME'];
$exploded = explode('/', $url);
return end($exploded);
}
}
Execute trigger_error() from the function, with a specific error message:
function currentScriptFilename()
{
if(!isset($_SERVER['SCRIPT_FILENAME']))
{
//Or this?
trigger_error('$_SERVER[\'SCRIPT_FILENAME\'] is not set.', E_USER_ERROR);
}
else
{
$url = $_SERVER['SCRIPT_FILENAME'];
$exploded = explode('/', $url);
return end($exploded);
}
}
I am not sure if I will regret having put a bunch of error messages in my functions further down the line, since I would like to use them for other projects.
Or, would you recommend something totally different?
Do not mix the matters.
Error notification and error handling are different tasks.
You have to use both methods simultaneously.
If you think that $_SERVER['SCRIPT_FILENAME'] availability is worth an error message, you can use trigger error. However PHP itself will throw a notice if you won't check it.
If you want to handle this error, just check this function's return value.
But I would not create a special function for this task.
So,
if (!$filename = basename($_SERVER['SCRIPT_FILENAME']) {
// do whatever you want to handle this error.
}
would be enough
Exceptions could be useful to handle errors, to know if we had any errors occurred.
A simple example:
try {
$filename = basename($_SERVER['SCRIPT_FILENAME'])
if (!$filename) throw new Exception("no filename");
$data = get_some_data_from_db() or throw new Exception("no data");
$template = new Template();
//Exception could be thrown inside of Template class as well.
}
catch (Exception $e) {
//if we had any errors
show_error_page();
}
$template->show();
3.Use exceptions.
If this is the route you are going, I'd rather recommend throwing Exceptions rather then returing an E_ERROR (E_USER_ERROR should be used), as this is just an integer, and possibly a totally valid return for your function.
Advantages:
- Throwing of an Exception cannot be interpreted as anything else then an error by mistake.
- You keep the possibility to add a descriptive error message, even though you don't handle the error at that point/
- You keep a backtrace in your Exception.
- You can catch specific exceptions at specific points, making the decision where in your project a specific type of error should be handled a lot easier.
If not using exceptions which you should be, use trigger_error().
If it is an error you'd like to deal with, try returning FALSE like a lot of the in built functions do.
If you do use exceptions, catch them like this
try {
whatever()
} catch (Exception $e) {
// handle however
}