I am using Cakephp but this is a MVC/php doubt
letting the view display the message
vs
echo 'Invalid Data'; exit;
I would like to know is there any pitfalls in the second case like memory leak etc.. Which one is better
EDIT
In case of a ajax call is exit good. and what about memory leak and other issues . Are all variables deallocated
You should use a custom ExceptionHandler (set_error_handler / set_exception_handler) and throw an Exception if you encounter any errors (CakePHP should already provide an ExceptionHandler). Make some space in your view and if the ExceptionHandler/ErrorHandler has a message, show it there to let the user know.
Your second code will just produce a blank page containing the little text. Every user will appreciate if you show the message inside your usual page layout instead of producing a blank page (which looks broken to most people).
The Cake tools to signal errors to the user are session messages and error views.
For "passive" actions like view actions, you should throw a 404 or similar, possibly more specialized error, e.g. if the requested model does not exist:
function view($id) {
$data = $this->Model->read(null, $id);
if (!$data) {
$this->cakeError('error404');
}
...
}
See Error Handling with CakePHP.
For any POST action, you should return the user to the view and display an error message using $this->Session->setFlash('Error!') and appropriate error messages for each invalid form field. That's the default behavior of baked views and controllers.
Terminating the whole script with exit makes for a miserable user experience.
In general, you should avoid exit. Exit is an abnormal termination, and programs should not terminate abnormally. Even if an error occurs, there are still many things that needs to be done - cleanup, logging, notifying the user etc. After all, your operating system doesn't reboot every time it cannot open a file.
performance-wise (AJAX cals)
Use exit().
user experience-wise (standard site nav)
Show the error in a proper formated page keeping the user within your site.
Related
while using Codacy to analyze my PHP code I found a number of errors caused by the exit(); function. here's one function,
public function saveCssForm(){
$data = $_POST;
if(!$data){
// is a direct acess
$this->index();exit();
}
// update the data
$this->csssettingmodel->updateCSS($data);
// save the notifications
$this->notify_update($data['site_id'],$data['lang_key']);
// set the success message
$this->session->set_flashdata('edit_item', 'edited');
// redirect to the view page
$baseUrl = $this->config->item('base_url');
redirect($baseUrl.'index.php/cssSettings/view/'.$this->session->userdata("languageabbr"));
}
public function index()
{
// Denay Direct Access
echo "<hr><h1><center>NO DIRECT ACCESS</h1> </center>";
echo "<center>You are not permitted to access this page </center>";
}
and the codacy result shows this...
any alternatives or suggestions to avoid this would be helpful.
Codacy is not displaying errors, in the sense of problems you need to fix; it is analysing the quality of your code, and suggesting that the exit appearing in this position is not a good practice, so you might want to fix it.
Firstly, application frameworks are often designed to have a single point of entry, process some logic, and then return a result to the entry point which will output and clean up. Exiting from different points in the code makes it harder to predict the flow, because whole sections of the code may look reachable but actually come after the program has exited.
Secondly, such code might be used for debugging, to interrupt the flow of execution at a particular point to display some intermediate data or simulate a particular failure. In this case, it appearing in the analysed code would suggest that you had left the debugging code in accidentally.
I have found that one common reason for the error is an exception being thrown from within an exception handler. I'm quite sure this doesn't happen in the application I'm trying to debug... But I've put all the initialization processing lines at the top of index.php in a try/catch.*
It can apparently also happen because some things cannot be serialized to be stored in a session. At most this application stores arrays into the session (quite a bit), but I'm confident that it doesn't store anything too out of the ordinary in it.
Someone commented that it happened to them because their primary key needed to be CHAR(32) instead of INT(11). The PK's in this app are all INTs.
Other suggestions are that it could be a problem with PHP 5.3.3 fixed in 5.3.6, full disk, and a need to typecast a SimpleXML value. We do happen to be running PHP 5.3.3, but upgrading would have to be a last resort in this case. It hasn't always been doing this.
UPDATE/NOTE: I actually can't reproduce the error myself, only see it happening in the logs, see below paragraph for where I believe the error is happening...
* From the error logs, it seems likely that at least one place it is happening is index.php. I am deducing this only because it is indicated in some entries by a referring URL. The try/catch code is currently only around the "top" initialization portion of the script, below that is mostly the HTML output. There is some PHP code in the output (pretty straightforward stuff though), so I may need to test that. Here is the catch part, which is not producing any output in the logs:
} catch (Exception $e) {
error_log(get_class($e)." thrown. Message: ".$e->getMessage(). " in " . $e->getFile() . " on line ".$e->getLine());
error_log('Exception trace stack: ' . print_r($e->getTrace(),1));
}
Would really appreciate any tips on this!
EDIT: PHP is running as an Apache module (Server API: Apache 2.0 Handler). I don't think there are any PHP accelerators in use, but it could just be that I don't know how to tell. None of the ones listed on Wikipedia are in phpinfo().
As far as I can tell the MPM is prefork. This is the first I'd ever looked into the MPM:
# ./httpd -l
Compiled in modules:
core.c
prefork.c
http_core.c
mod_so.c
The problem
In short you have a exception thrown somewhere, you have no idea where and up until now you could not reproduce the error: It only happens for some people, but not for you. You know that it happens for other people, because you see that in the error logs.
Reproduce the problem
Since you have already eliminated the common reasons you will need to reproduce the error. If you know which parameter will cause the error it should be easy to locate the error.
Most likely it is enough if you know all the POST/GET parameters.
If you can't reproduce with just these, you need to know additional request headers. Such as user agent, accept-encoding,...
If you still can't reproduce, then it becomes very difficult: The error may depend on a state (a session), the current time, the source ip address or the like.
The custom log method
Let's start simple: To get all parameters you can write in the very beginning of the affected php file something like:
file_put_contents("/path/to/some/custom_error_log", date()."\n".print_r(get_defined_vars(), true), FILE_APPEND | LOCK_EX);
Don't forget that the custom_error_log file must be writable to your php application. Then, when the error occurs in the error log, find the corresponding lines in your custom_error_log file. Hopefully there are not to many requests per second so that you can still identify the request. Maybe some additional parameters in the error log like source ip can help you identify the request (if your error log shows that).
From that data, reconstruct a request with the same POST/GET parameters.
The tcpdump method
The next option that is very simple as well, but requires you to have root-access on your target machine is to install tcpflow. Then create a folder, cd into that folder and simply execute (as root) tcpflow "port 80". The option (port 80) is a pcap filter expression. To see all you can do with that, see man pcap-filter. There is a lot what these filter expressions can do.
Now tcpflow will record all tcp connections on port 80, reconstruct the full data exchange by combining the packages belonging to one connection and dump this data to a file, creating two new files per connection, one for incoming data and one for outgoing data. Now find the files for a connection that caused an error, again based on the timestamp in your error log and by the last modified timestamp of the files. Then you get the full http request headers. You can now reconstruct the HTTP request completely, including setting the same accept-encoding, user-agent, etc. You can even pipe the request directly into netcat, replaying the exact request. Beware though that some arguments like a sessionid might be in your way. If php discovers that a session is expired you may just get a redirect to a login or something else that is unexpected. You may need to exchange things like the session id.
Mocking more things
If none of this helps and you can't reproduce the error on your machine, then you can try to mock everything that is hard to mock. For example the source ip adress. This might make some stunts necessary, but it is possible: You can connect to your server using ssh with the "-w" option, creating a tunnel interface. Then assign the offending ip adress to your own machine and set routes (route add host ) rules to use the tunnel for the specific ip. If you can cable the two computers directly together then you can even do it without the tunnel.
Don't foget to mock the session which should be esiest. You can read all session variables using the method with print_r(get_defined_vars()). Then you need to create a session with exactly the same variables.
Ask the user
Another option would be actually ask the user what he was doing. Maybe you can follow the same steps as he and can reproduce.
If none of this helps
If none of that helps... well... Then it gets seriously difficult. The IP-thing is already highly unlikely. It could be a GEO-IP library that causes the error on IPs from a specific region, but these are all rather unlikely things. If none of the above helped you to reproduce the problem, then you probably just did not find the correct request in all the data generated by the custom_log_file-call / tcpflow. Try to increase your chances by getting a more accurate timestamp. You can use microtime() in php as a replacement for date(). Check your webserver, if you can get something more accurate than seconds in your error log. Write your own implementation of "tail", that gives you a more accurate timestamp,... Reduce the load on the system, so that you don't have to choose from that much data (try another time of day, load of users to different servers,...)
circle the problem once you can reproduce
Now once you can reproduce it should be a walk in the park to find the actual cause. You can find the parameter that causes the error by trial and error or by comparing it to other requests that caused an error, too, looking for similarities. And then you can see what this parameter does, which libraries access it, etc. You can disable every component one by one that uses the parameter until you can't reproduce anymore. Then you got your component and can dive into the problem deeper.
Tell us what you found. I am curious ;-).
I had such an error, too. Found out that I returned a sql object in my session class (that was used by the session_handler) instead of returning nothing or at least not the sql object. First look into your _write and _read methods, if you too return some incorrect stuff.
Notice: ... Unknown on line 0 - How to find correct line, it's NOT "line 0"
I realize this question has already been answered, but I'll add this since it may help someone:
I managed to (unintentionally) produce errors without a stack frame from a function which used its own error handler to maintain control of execution while calling a potentially "dangerous" function, like this:
// Assume the function my_error_handler() has been defined to convert any
// PHP Errors, Warnings, or Notices into Exceptions.
function foo() {
// maintain control if danger() crashes outright:
set_error_handler('my_error_handler');
try {
// Do some stuff.
$r = danger();
} catch (Exception $e) {
$r = 'Bad Stuff, Man!';
}
restore error_handler();
return $r;
}
The "untraceable failure" would happen at the end of the program execution if the logic in "Do some stuff" returned from foo() directly, bypassing the call to restore_error_handler(). What I took away from the experience is this:
PHP maintains a stack of error handlers which gets deeper/taller with each call to set_error_handler().
Bad Stuff can happen if you push error handlers onto the stack and don't clean up after yourself before the program exits "normally".
This was a tough bug to isolate - I basically narrowed the problem down to the above function and then stared at it until my eyes bled.
So how would I have tracked this down, knowing what I know now? Since I don't know of any way to inspect the PHP error handler "stack" directly, I'm thinking it might make sense to use a Singleton object to encapsulate all set/restore operations for PHP error handlers. At least then it would be possible to inspect the state of the Singleton before exiting the program normally, and if "dangling" error handlers are detected to generate a sensible failure/warning message before PHP freaks out.
Instead of wrapping code in a try/catch block, what happens when you register an exception handler? Clearly your try/catch block is not catching the exception, thus resulting in the errors logged to Apache. By registering a handler, you can be sure any uncaught exception is handled.
Also, if you're using namespaces in your application, make sure you write \Exception in your catch block (or include the Exception class via a use statement).
This may be a little late but one issue I discovered when moving a site from a local to a remote server. I was using Concrete5 cms had developed my site locally(windows 8 in xampp) and then uploaded to a remote server running Cent 0S
Windows mysql by default is case insensitive and created a lower case database. Once this was uploaded to the remote server I received the "Exception thrown without a stack frame in Unknown on line 0?"
I then corrected the database tables case and my site started working again.
For us, this error was due to inadvertently serializing SimpleXML objects.
If you are using SimpleXML objects with 5.3.3, make sure you are are casting the node values to whatever you need (e.g. string) if you are serializing the values in the session.
Before:
$token = $response->Token->Value;
/* token saved in session, results in line 0 error */
After:
$token = (string) $response->Token->Value;
/* token saved in session, no error */
I had completely the same error. A very spacial case: if you connect an unnamed function (closure) hook to an object instance's hook point. After that you try to serialize this object.
I had the same error after filling the Illuminate Eloquent model's Fillable property incorrectly. Note the last 3 elements of the array, one is missing a coma.
protected $fillable = [
'budget',
'routestatus' ,
'userroutenumber'
'totalmovingseconds',
'totalidleseconds'
];
I had the same error, it appeared upgrading server from centos 5 to centos 6 and downgrading PHP from 5.4 to 5.3. Actual issue was PHP apc, not configured properly. Check your APC. I was using Symfony2, so you might find some help at Symfony Unable to allocate memory for pool
one simple way to produce this error is an old server with register_globals = On. then you only need two lines of code:
<?php
$_SESSION["my_var"] = "string";
$my_var = new MyClass(); //could be any class, i guess
?>
as soon as you reload this page once, you'll get the Exception thrown without a stack frame in Unknown on line 0 - error. seems like there is a conflict between the instance of the class and the (session) variable.
at least this is how i got this annoying error which is so hard to debug.
This problem occurred for me when I changed the namespace on a few Symfony bundles. Deleting the files in the the symfony cache directory fixed the issue.
Likely you have a corrupt/inconsistent table in the database. Try dumping the database. If you get a error that's the time. Repair that table and the issue should go away.
It is for this reason why clean install works. The clean install is just that clean.
mysqlcheck should work but if it does not show and issue still do above.
Using CakePHP 2.1 I have the following code
public function getForm($id=null){
$this->loadModel('DynamicFormResponse');
/**
* Check if form exists
*/
$this->form_schema= $this->DynamicForm->isValidForm($id);
if($this->form_schema == false){
$this->flash("Invalid form", $this->referer(
array('controller'=>"pages", 'action' => 'display')
));
}
...
...
the problem I am facing is that, the call to $this->flash() renders the flash page but also continues the execution of the controller.
So Unless I do something like
if($this->form_schema == false){
$this->flash("Invalid form", $this->referer(
array('controller'=>"pages", 'action' => 'display')
));
return;
}
the controller does not terminate .
The main problem arises when a _crsf_error method is called
function _csrf_error() {
$this->flash("csrf Error", $this->referer(
array('controller'=>"pages", 'action' => 'display')
));
}
Since the flash method does not redirect It offers no csrf protection at all.
Using return; after $this->flash() in the _crsf_error method does not work.
PS: Full code available here
Although the answer above is a great explanation of what the flash() method does, to me, it did not fully answer the question but rather give a great alternative.
I personally wanted to use the flash method so I didn't have to use the session component and I found myself stuck on my flash message as well. In the cake 2.x documentation, it says that the second parameter of the flash() method is a CakePHP-relative URL. This means the following should show a message and then redirect to the index action.
$this->flash(__("Some message for the user here..."), array("action" => "index"));
My problem, and what it looks like the original poster's problem, was that it was showing you the flash message but not doing the redirect after.
I tested this thoroughly with my application and the culprit was the debug setting in core.php
Configure::write('debug', 0);
The debug value has to be set to '0' in order for the redirect to take place. I do not know why this is the case but I tested it about 10 times and 10/10 when my debug settings were set to 1 or higher, I just got the flash message. If I set it to 0, everything works perfectly. This wasn't much of a concern to me since production environments should have this setting set to 0 anyway.
If anyone else has some insight as to why the redirect doesn't happen when debugging is on, please enlighten us all.
Hope this helps.
flash() does not redirect, it renders. It is very similar to the render() function, it will continue the execution of the script, unlike the redirect() function.
You just need to organize your logic accordingly, so that no other line is executed after it If you don't want to. Optionally you can use session->setFlash() combined with a redirect.
When dealing with serious errors like an invalid csrf token I'd recommend throwing an exception instead of rendering a nice message to the attacker. You can prettify the exception rendering using the error handler, though.
I was also facing the same problem. And after turning debug mode to 0,i got the solution of my problem.
Configure::write('debug', 0);
And why redirect was not happening with debug mode 2 there is one main cause,
your application is outputting something to the browser before the redirect header was sent. This may be caused by (non visible) white-space before or after any . This will cause a 'headers already sent' warning, and the browser will not redirect. There are many questions regarding this situation here on StackOverflow, for example: Headers already sent by PHP
When using Magentos log facility Mage::log() it sometimes causes a white screen. No error messages are outputted either to the screen or any of the log files (var/log/system.log, var/log/exception.log )
This seems to happen only when I'm trying to log a very large object. for example when I'm trying this
Mage::log(Mage::helper('catalog/category')->getStoreCategories());
inside a block controller it causes a white screen.
the same happens when I'm trying to log the current product in app/design/frontend/enterprise/default/template/catalog/product/view/media.phtml
using
Mage::log($_product);
Usually Mage::log() works fine and writes everything to the system.log file.
I was wondering if this has happened to anybody else or if anybody has an idea about why this is happening?
Mage::log works a lot like print_r, private and protected values are printed too which includes extensive resource details. You can avoid these by using the purpose made Varien_Object::debug method.
Mage::log($_product->debug());
debug is also preferred because it detects recursion which not all versions of PHP do.
I guess it happens to everyone.
Try not to log large objects.
In case you need I would advice you to use die.
for example like this
$object = ...;
die($object);
or
die('pre html tag'.print_r($object,true).'pre html tag');
Why not using array of errors instead of throwing errors and check if it's not empty later in the code.... Exception handling is very confusing to me , I can not understand it's purpose ... can anybody enlighten me !?
they compare it with die() as better not to stop the execution of the code , why would I stop the execution of code if I don't want to !? ofcourse I do
I'm a beginner programmer , it might be confusing to you as well , or because i'm not very experienced in this ugly thing.
Please in the context of PHP only.
One reason you might decide to throw an exception is because you can add a jump in control flow without an explicit piece of syntax. What do I mean by that?
rather than
$returnVal = doSomeDiskFunction();
if($returnVal == $ERROR_CODEA)
{
// do some stuff
}
else if( $returnVal == $ERROR_CODEB)
{
//do some stuff
}
$returnVal = doSomeOtherDiskFunction();
if($returnVal == $ERROR_CODEA)
{
// do some stuff
}
else if( $returnVal == $ERROR_CODEB)
{
//do some stuff
}
you could just have
try{
doSomeDiskFunction();
doSomeOtherDiskFunction();
}
catch(ExceptionTyepA $exceptionA)
{
//do some stuff
}
catch(ExceptionTypeB $exceptionB)
{
//do some stuff
}
Seems a lot cleaner, yes??? It's also a formal way of alerting calling code that it needs to deal with potential error conditions if you choose to have the exception propogate upwards in the call stack.
Also, exceptions should be used for code that you don't expect to happen, like failing to connect to a database, not code that you DO expect to happen, like a user submitting bad data. The other poster made the point that you kind of expect a user to make a lot of errors filling out a form, so you wouldn't throw an exception when you come across some data that is in a bad user-entered format, because you expect user data to be poor quality.
It really depends what type of error you're talking about.
I always die(); for really bad errors, like if the application couldn't connect to the database.
But for anything that takes user input, like a form, it's better to use arrays of errors that the user can see all at once, instead of correcting one field at a time and repeatedly having to press submit.
(If you want to know in more detail, I often use an array of arrays to display errors, since one field could potentially have multiple things wrong with it. For example, if a user tries to register an account with username "1337", I will use a validator to check against multiple conditions and it will return an array with things like "username must be at least 5 characters long", "username must contain at least three letters", "that username has been disallowed by the administrator" and all those messages will be displayed simultaneously above that particular field)
There is a way to code completely without exception handling. For example, if you have a method that returns the length of an object, have it return -1 if there's been an error. This is how most C API's are built.
That said, when you're building complex systems, and you have a ton of "black box" code that might behave wrongly, exceptions help. The way exceptions work is like this: when someone "throws", folks on the call stack start getting notified. One step at a time. One of these methods can "Catch" the exception and handle it.
Why is this useful: you can have a DB layer that has lots of logic inside that throws exceptions. If something goes wrong there, your DB exception handling code can fail gracefully, showing a nice error message to the user; it can also send a text message to the admin, demanding attention.
You can even create a hierarchy of exception handlers: you can re-throw the exception after you've done something with it.
PHP's exceptions sucks hard, but they still have their basics benefits:
Exception provides much more information about "What went wrong?" in much better form (exception is an object)
They make your code clearer
They are the only reasonable way to break execution of the part of code (that doesn't work as it supposes to), fix (if possible) what need to be fixed and continue without complete failure.
Really it depends on the language. C is similar in that respect -- it doesn't force you to handle an error. Most functions return -1 if they had a problem; it's up to you to check 'errno' to see what happened.
Exceptions are generally a good thing though. You rarely want to blindly continue running if an error occurred (Never never NEVER say "On Error Resume Next" in Visual Basic. Please.). It's quite easy to catch the exception and do nothing if you are sure you don't need to do anything.