Note: I am using output buffering. It's just wrapped in the head() and foot() functions.
I create pages in my current PHP project by using the following template:
<?php
include 'bootstrap.php';
head();
?>
<!-- Page content here -->
<?php
foot();
?>
Is the following example an appropriate use of die()? Also, what sort of problems might this cause for me, if any?
<?php
include 'bootstrap.php';
head();
try
{
//Simulate throwing an exception from some class
throw new Exception('Something went wrong!');
}
catch(Exception $e)
{
?>
<p>Please fix the following error:</p>
<p><?php echo $e->getMessage(); ?></p>
<?php
foot();
die();
}
//If no exception is thrown above, continue script
doSomething();
doSomeOtherThing();
foot();
?>
Basically, I have a script with multiple tasks on it and I am trying to set up a graceful way to notify the user of input errors while preventing the remaining portion of the script from executing.
Thanks!
I'd do this:
head();
try {
somethingPossiblyWithError();
somethingElse();
} catch (Exception $e) {
handleError();
}
foot();
No deaths necessary. If an error is raised in somethingPossiblyWithError, then somethingElse will get skipped. foot will get executed in both cases.
UPDATE: I upvoted Col. Shrapnel's answer, since I guess you did not think about that, and that is a valuable piece of knowledge. In PHP, you can get an equivalent functionality by output buffering, without explicitly passing values around, but it's not as pretty - however, it works if you are calling functions which will print things and not return them as values, so sometimes it's useful to know.
The whole page structure is wrong.
Though it's most widespread newbie mistake.
One should never output a thing before having all data ready.
Your script may send some HTTP headers, may set up some variables for use in the header() or anything.
Therefore, template use is necessary.
You have to divide your script into 2 parts - getting data part and displaying data part.
So, you have to move header() function much lower.
And based on the Amadan's answer it could be
<?php
include 'bootstrap.php';
try {
getData();
} catch (Exception $e) {
handleError();
}
head();
body();
foot();
?>
handleError() function may set appropriate HTTP error code (404 or 500) and substitute body template with error message text.
Your approach is not recommended for many reasons. You should:
separate the presentation and the logic (take a look at MVC pattern)
avoid procedural code, write object oriented PHP
separate user and admin experience (handle errors gently)
Example, implementing above:
<? $page->debug = true; ?>
<?= $page->getHead(); ?>
<?= $page->getBody(); ?>
<?= $page->getFoot(); ?>
class page {
public debug;
public function getBody() {
try {
//
} catch (Exception $e) {
$this->_errorhandler('message');
}
}
protected function _errorhandler($message) {
if ($this->debug) {
// display error message
} else {
// display nothing, log the error
// or throw concrete exception
// or redirect
}
}
...
}
This is not recommended too (there are many separate classes needed for each task), but you see the point: separating, not mixing everything.
Related
1) I have a view (a neseted one) that triggers a notice-level error
2) I have set up a custom error handler, which is called. Code goes below
3) I want visitor seeing only the "error happened" string in his browser, instead, he sees the half-baked page with this error message appended
4) messing with php's native ob_end_clean only made me clear the contents of the deepest view involved, yet the higher-level views are still half-shown
5) the contents of final_output var of CI_Ouput class is empty string at the moment of error. That's strange is CI is said to pre-buffer everything befoew outputting to the client.
essentially, what I need seems to be discarding any content having been collected so far and replacing it with error message only.
how can I do it?
the code of the handler:
function _error_handler($errno, $errstr) {
echo "error happened";
die();
}
Try to use a Try Catch system?
Try{
//Do something
} catch(Exception $e){
echo "Error has occured!";
}
as suggested in the discussion this had to be related to php's native output buffering wich we can control with ob_* family of functions. Buffering in php can be nested, and CI seems to use it, opening a buffer for each view being loaded.
If we load a view from inside a view, the nesting gets deeper, and generally, when an error occures in the view we don't know how deep we are.
So that's what seems to solve the problem (the code of error handler):
function _error_handler($errno, $errstr) {
$currentLevel=ob_get_level();
for($i=0; $i<$currentLevel-1; $i++) {
ob_end_clean();
}
print "errorrrr!";
die();
}
so it detects how deep it is and cleans as many buffers as needed. After all, we end up with "errorrrr" message being the only thing on the page.
Looking at the following structure:
groups.php
<?php
session_start();
include('header.php');
if($_SESSION['admin'])
{ include('groups_admin.php'); }
... html ...
?>
groups_admin.php
<?php
if(!$_SESSION['admin'])
{ die(); }
... html ...
?>
inside of groups_admin.php - performing the die(); causes the rest of the page (including groups.php) to stop loading.
without wrapping all of groups_admin.php is a big if statement and reversing it; is there anyway to tell PHP to just stop loading that specific PHP file while inside of that file?
Just do a return in the include eg:
<?php
if(empty($_SESSION['admin']))
{ return false; }
... html ...
?>
A lot of people don't know you can return a value from an included file.
Just for completion of this answer. You have a couple of other, less elegant (and not recommended) options.
You throw an exception and catch it outside of the include
Wrap it in an if block
Although this is suboptimal compared to the return solution, I just can't help it.
Guess what: php supports goto!
<?php
if(!$_SESSION['admin'])
{ goto endoffile; }
... html ...
endoffile:
?>
I just found out myself and it zapped me back in time, to my GWBASIC years... (sigh!)
Does anybody have any ideas why the below page isn't redirecting?
My php file that I want to redirecting is:
<?php require_once("../includes/db_connection.php"); ?>
<?php require_once("../includes/functions.php"); ?>
<?php
if (isset($_POST['submit'])) {
} else {
redirect_to("new_subject.php");
}
?>
The functions file is:
<?php
function redirect_url($new_location)
{
header("location:".$new_location);
exit;
}
?>
I have removed the db_connection.php file to see if that makes any difference but it doesn't.
Besides the fact that the function you call and the function name you have are different ("redirect_to" vs. "redirect_url"), you also have white space before you make a header call. The space between the requires and the next PHP block is white space and will disallow setting of headers after the white space has been sent to browser.
I would highly suggest you turn on error logging in PHP and reference the error logs when investigating a problem. You would see both the function call error and the header error in your logs.
Also, it is generally pretty poor coding form to open and close PHP tags unnecessarily. You could clean this up to look like this:
<?php
require_once("../includes/db_connection.php");
require_once("../includes/functions.php");
if (!isset($_POST['submit'])) {
redirect_url("new_subject.php");
}
?>
Note here that you can keep a separation between the requires and the code to aid in readability, but since you never exit the PHP block, you don't have a white space problem.
Function name is redirect_url()
So code should be
else {
redirect_url("new_subject.php");
}
Your function call should be
redirect_url("new_subject.php");
instead of
redirect_to("new_subject.php");
You can try this,
<?php
if (isset($_POST['submit'])) {
//some thing do here
} else {
redirect_url("new_subject.php");
}
function redirect_url($new_location)
{
header("location:".$new_location);
exit;
}
?>
So I asked a similar question earlier and I'm only more confused now, so I'll ask it in a different way...
What I'm trying to do is abstract my php and put the bits of html, used in my validator as error messages, into functions that return the html to the spot where they are needed in the page.
What I have right now is:
<section>
<?php
if($errMsg)
{
errMsg();
}
?>
</section>
<?php
function errMsg()
{
?>
<section>
<p>O crap! There was an error</p>
</section>
<?php
}
?>
But in my previously mentioned question, I was told doing it this way is a 'dirty hack' and its better to use return in situations like this. But to use return I'd need to assign all of the returning html to a var and to do that I would need to put the html in a string. I'd rather avoid putting more than two lines of html in a string because of the pain in the butt number of quotes needed to do so.
So I'm thinking I either use the heredoc syntax or ob_start/ob_get_clean functions. What I'd like to know is.
1 Do I even need to bother with abstracting my code like this?
2 If so, which way is the best practices way to do it? And/Or
3 Should I just give up on web development and go back to pizza delivery? :-\
1: You don't need to, but you can if it's done properly.
2: To do this, i recommend you to use the EOF in your PHP error func, it looks like this :
function errMsg()
{
$error = <<<EOF
<section>
<p>O crap! There was an error</p>
</section>
EOF;
}
I wouldn't return any HTML. Simply return the error message from the function and then build the html in a more appropriate place. For example the inside the template.
Yes definitely, you have no flexibility with the way you are doing it.
You should separate all of your HTML from your PHP ideally, at least functions - the only place it is remotely acceptable is within a view which uses PHP just to display the output of the functions.
Pizza! Just kidding, but there can never be enough pizza!?
Take a look at the Zend framework http://framework.zend.com/manual/en/zend.application.quick-start.html they forward error messages which aren't caught to an error handler, which then uses its own view to render the error.
Or w/o a framework:
try{
//do work here and throw exception on error
}
catch (Exception $e)
{
//do error logging/display error
//or preferably load another class which handles your error and produces output
}
You could just do this:
<?php if($errMgs){ ?>
<section>
<p><?php echo errMsg(); ?></p>
</section>
<?php } ?>
Generally, I try my best not to echo out HTML via PHP. Why? Because if a designer needs to work on my code, I don't want him/her worrying about what HTML my functions are spitting out.
Move the html code into a separate file, error.php. After that you just capture the output:
function errMsg()
{
ob_start();
include '/path/to/error.php';
return ob_get_clean();
}
// ...
echo errMsg();
First off, I agree with the posts above. Don't format, just have the function return the bare error message and if you need to format it appropriately where you want to display it.
Secondly, I always find that it is useful to be able to turn error and testing messages on and off quickly. As the majority of my code is object orientated and I might only want to have messages popping from an object at a time, I normally have something like this in my classes:
class userObject
{
public $history;// = historyObject;
public $userName;
public $userRelation;
public $userCode;
private $mySQLAccessData;
private $isDebug=false;
public function makeHistoryObject($KPI, $KPIType)
{
if($this->isDebug){echo "Having a go at creating ".$this->userName.".<br>";}
$this->history = new historyObject($this->userCode, $KPI, $KPIType);
}
}
I slip a private element in which I leave as false by default. If I need to debug or make changes, I set it to true and all my error/logging messages are neatly displayed on screen. I know that this isn't directly answering your question, but I do find that it is so handy it might be worth it for you when you start. It certainly beats commenting out and then uncommenting potentially dozens of messages. You can leave these outputs in the object without worrying and have them displaying all the detail you need.
If you may at some point have number of errors, then do like this
<?php
$errors = array();
if (!$item = getItem($id)) {
addError("No item $id");
}
if (!updateUser($user, $id)) {
addError("Can not update user");
}
if (!updateItemPicture($id, $picture)) {
addError("Can not add picture to $id");
}
function addError($error) {
global $errors; $errors []= $error;
}
function hasErrors() {
global $errors; return count($errors);
}
function printErrors() {
if (!hasErrors()) return;
print "<ul class='errors'><li>" . join("</li><li>", $errors) . "</li></ul";
}
printErrors();
?>
This is in case you are not using object oriented way. And assuming that all errors are not fatal and caught in try {} catch () {} blocks.
Let's say I have some code like this:
<html>
<head><title>Title</title></head>
<body>
<?php
if (!$someCondition){
die();
}
else{
#Do something
}
?>
</body>
<html>
I hope the purpose of this code is straightforward. If a certain condition is met (ie can't connect to database), then the program should die, but otherwise it should execute. My problem arises when the die() function is executed. It stops right there, and sends only the first three lines to the browser, but not the last two lines.
Is there a funciton that I can use instead of die() so that the php chunks will stop executing, but the static HTML text is still sent through?
Decouple your program logic from presentation. Read about MVC, templates.
In simplest form it goes like that:
<?php
function logic() {
if (!$someCondition) {
return 'display_empty_page';
} else {
return 'display_other_stuff';
}
}
presentation(logic());
For other cases, where die() or such is unavoidable (e.g. fatal error or 3rd party code dying), there's hack involving output handler:
ob_start('myhandler');
function myhandler($page) {return $page.' extra markup';}
die();
Although I recommend using that only for diagnostic/debugging purposes.
You should be separating out your header and footer into an separate files and functions. This makes the UI much easier to maintain and keeps things consistent for rendering the view. Couple that with using Exception handling and you're golden.
<?php
printHeader(); // outputs the html header
try
{
if (some condition)
{
throw new Exception("It Died...");
}
// More processing here that should not execute if the above condition is true
// ...
}
catch (Exception e)
{
echo $e->getMessage();
}
printFooter(); // outputs the html footer
?>
Pass the die a parameter of the static text.
For example change this:
<html>
<head><title>Title</title></head>
<body>
<?php
if (!$someCondition){
die();
}
else{
#Do something
}
?>
</body>
<html>
To this:
<html>
<head><title>Title</title></head>
<body>
<?php
if (!$someCondition){
die("OMG RED ALERT!!!!</body></html>");
}
else{
#Do something
}
?>
</body>
<html>
I would probably use exceptions. Wrap everything in a try / catch block, then throw a new exception on an error condition like a database failure. You could do nothing in the catch block (like an empty die() method), but it would be better to present an error message to the user here.
Here's a pretty good guide on exception handling in PHP5 in case you're not familiar with them or you need to brush up on what's changed since PHP4.
Have you looked into using register_shutdown_function (php.net) to finish loading the page? It should be able to handle die() and exit().
If you look at the PHP Documentation you'll see that "Equivalent to exit()" - ie calling it terminates your program and doesn't really give you much of a chance to do anything. Even outside of ZF, there's not a whole lot you can do when an application die()s. The solution is to use Exceptions.
An uncaught exception is essentially the same thing as a die() (other than the stack trace that gets generated). What an exception gives you is the ability to put it in a try/catch block, giving you the opportunity to correct the error and continue on with the program (or display a friendly error message and generate a log). Assuming you're using Zend_Controller_Front, you can check out the Zend Framework Quickstart to see how they make a default error handler that will catch uncaught exceptions and display an appropriate error message.
One method, which works but is not exactly what I'm looking for, would be to replace die() with die("</body></html>"). If the text to return were more complicated than that, it could, say, be stored in a variable. Is there anything better than this?
die() might not exactly be what you want here. Why not replace
if (!$someCondition) {
die();
} else {
/* do stuff */
}
with
if ($someCondition) {
/* do stuff */
} else {
/* output error message/redirect/output nothing/whatever */
}
or throw/catch an exception?
If you're working with PHP4, or just don't want to bother with exceptions, then you could use this technique:
<html>
<head><title>Title</title></head>
<body>
<?php
do {
if (!$someCondition){
break;
} else {
#Do something
}
} while (0);
?>
</body>
<html>
.. though some people seem quite opposed to using this style, appropriately commented, I don't see any issues with it. I'd say it's much better than duplicating your "footer" code in each of your die() statements.
<html>
<head><title>Title</title></head>
<body>
<?php
if (!$someCondition){
header ("location:error_page.php?erro_message='This error occured'");
die();
}
else{
#Do something
}
?>
</body>
<html>
error_page.php
header
echo $_GET[$error_message];
footer