I am making a registration system with an e-mail verifier. Your typical "use this code to verify" type of thing.
I want a session variable to be stored, so that when people complete their account registration on the registration page and somehow navigate back to the page on accident, it reminds them that they need to activate their account before use.
What makes this problem so hard to diagnose is that I have used many other session variables in similar ways, but this one is not working at all. Here's my approach:
/* This is placed after the mail script and account creation within the same if
statement. Things get executed after it, so I know it's placed correctly. */
$_SESSION['registrationComplete'] = TRUE;
// I've tried integer 1 and 'Yes' as alternatives.
Now to check for the variable, I placed this at the top of the page.
echo $_SESSION['registrationComplete']; // To see if it's setting. This gives the
// undefined index notice.
if (isset($_SESSION['registrationComplete'])) {
// Alternatively, I have nested another if that simply tests if it's TRUE.
echo $_SESSION['registrationComplete']; // When echo'd here, it displays nothing.
echo '<p>Congratulations, Foo! Go to *link to Bar*.</p>';
}
Now, I used to have the page redirect to a new page, but I took that out to test it. When the page reloads from submit, my message in the if statement above appears and then I get an Notice: Undefined index: registrationComplete blah blah from the echoing of the session var!
Then if I ever go back to the page, it ignores the if statement all together.
I have tested for typos and everything, clearing session variables in case old ones from testing were interfering, but I am having no luck. A lot of Googling just shows people suppressing these errors, but that sounds insane! Not only that, but I am not getting the same persistence of session variables elsewhere on my site. Can someone point out if I'm doing something blatantly wrong? Help! Thanks!
FYI, I read several related questions and I am also a beginner, so I may not know how to utilize certain advice without explanation.
As requested, more code, heavily annotated to keep it brief
var_dump($_SESSION);
// It's here to analyze that index message. I guess it's not important.
echo $_SESSION['registrationComplete'];
if (isset($_SESSION['registrationComplete'])) {
// The golden ticket! This is what I want to appear so badly.
echo 'Congratulations, Foo! Go to *link to Bar*.';
}
// Explanation: I don't want logged in users registering.
// The else statement basically executes the main chunk of code.
if (isset($_SESSION['user_id'])) {
echo 'You are logged in as someone already.';
}
else {
if (isset($_POST['submitRegister'])) {
// Code: Database connection and parsing variables from the form.
if (!empty($email) && !empty($email2) && $email == $email2 && !empty($displayName) && !empty($password) && !empty($password2) && $password == $password2) {
// Code: Query to retrieve data for comparison.
if (mysqli_num_rows($registrationData) == 0) {
// Code: Generates the salt and verification code.
// Code: Password hashing and sending data to verify database.
// E-mail the verification code.
$_SESSION['registrationComplete'] = 'yes';
}
else {
// Some error handling is here.
$registerError = 'The e-mail address you entered is already in use.';
}
}
// the elseif, elseif, and else are more error handling.
elseif ($email != $email2) { $registerError = 'Your e-mails did not match'; }
elseif ($password != $password2) { $registerError = 'Passwords didn\'t match.'; }
else { $registerError = 'Filled out completely?'; }
// If the registration was submitted, but had errors, this will print the form again.
if (!isset($_SESSION['registrationComplete'])) { require_once REF_DIR . REF_REGISTERFORM; }
// IMPORTANT! it turns out my code did not work, I forgot I had the same statement elsewhere.
else { echo 'Congratulations, Foo! Go to *link to Bar*.'; }
}
// Creates form.
else { require_once REF_DIR . REF_REGISTERFORM; }
}
This came down to the basics of debugging/troubleshooting.
Understand as much as you can about the technique/library/function/whatever that you're trying to use.
Inspect the salient bits and make sure that they are what you expect or what they should be. (There's a slight difference between those two, depending on the situation.)
If that doesn't bring you towards a solution, step back and make sure you're understanding the situation. This may mean simplifying things so that you're only dealing with the issue at hand, i.e. create a separate, simpler test case which exposes the same problem. Or, it may simply mean that you stop coding and work through the flow of your code to make sure it is really doing what you think it is doing.
A typical issue with sessions not working is forgetting to use session_start() (near or at the top) of any page which uses sessions.
One of my favorite snippets of PHP code, for debugging:
print '<pre>';
var_dump($some_variable);
print '</pre>';
I try to use print for debugging and echo for regular output. It makes it easier to spot debugging code, once it's goes beyond a few trivial bits of output.
Meanwhile, var_dump will print a bit more info about the variable, like it's type and size. It's important to wrap it in <pre></pre> so that it's easier to read the output.
Try
if (!empty($_SESSION['registrationComplete'])) {
If you get the warning after the message is printed, this cannot come from the variable echoing because according to your code it would be thrown before printing that message. Are you sure you don't use $_SESSION['registrationComplete'] beyond the if statement? Try to add exit or die() before the closing bracket of the if and see if the notice disappears.
Related
I've been using PHP for quite a long time now, and I do enjoy it. However, it has come to my attention that my error handling is not up to scratch and for the new project I am working on, I want to adopt a proper error-handling method.
I'm wondering how to handle user input specifically, but also more generally any errors.
I have a case as below as an example:
function check_email($email){
if(empty($email)){
$error='You must enter an email address';
error_log($error);
header('Location: page.php?error='.$error);
exit();
}
if( *doesn't match regex* ){
$error='Not a valid email format';
error_log($error);
header('Location: page.php?error='.$error);
exit();
}
}
I want to both be able to revert to the user with the error message, and also log it in the error_log document.
The above method works fine, but it is super messy code, or at least it feels messy. Any ideas how I can clean this up? I want to be efficient with it because easy-to-write error catchers mean I will write more of them instead of being lazy
Edit: yes, I could wrap that in a function of it's own
function er($error){
error_log($error);
header ('Location:...);
}
Surely there is a more elegant, native solution though?
I have utilised comments below to come up with two individual functions for soft errors and returning user errors
For user errors:
function return_error($msg){
$_SESSION['error']=$msg;
header("location:javascript://history.go(-1)");
exit;
}
For soft errors / unusual behaviour (make_file() function just makes a file if not exist)
function soft_error($e){
$trace=debug_backtrace(-1);
if(isset($trace,$trace[0],$trace[0]['file'],$trace[0]['line'])){
$file=BASE_DIRECTORY.'logs/soft_error.log';
make_file($file);
$log=fopen($file,'a');
fwrite($log,'['.date('Y-m-d H:i:s').'] File: '.$trace[0]['file'].' - Line: '.$trace[0]['line'].' - Error: '.$e.PHP_EOL);
fclose($log);
}
}
For hard errors, there is error_log() or they will be logged automatically based on server settings, so that is fine
Is it ok to include a break or exit command to prevent further code from executing or is this bad programming?
function index()
{
$error = NULL;
if ($_POST){
// validate form
if ($form_validated) {
echo 'this content only';
exit; // or return IS THIS BAD???
} else {
$error = 'form failed';
}
}
echo 'normal page on initial load';
if ($error) { echo '<br />'.$error; }
}
It is OK to prevent further code from executing using exit.
Having said that, whether this is the best way to do it in this particular example is debatable. It is typical to use exit when issuing redirects:
header('Location: /foo');
exit;
In your case, there doesn't seem to be an immediate need to stop the program execution in mid run. You should rather structure your program flow so it always completes, but with different results. It is hard to follow program logic which may terminate somewhere in the middle, so a more logical flow that returns from functions or branches using if..else is usually preferable.
For the example you give:
function index()
{
...
if ($form_validated) {
echo 'this content only';
exit; // or return IS THIS BAD???
} else {
...
}
This is normally called early exit or early return (return is more common). This can be very okay, some people say that early returns make code hard to understand but I'd say it depends on a lot more if a function can be easily read and understood or not.
So the person who decides here whether it is bad or not is you. You need to find some criteria on your own where you draw the line. For example if a function is long (more than 12 lines of code) and contains many of these early returns or even exits, this will make the code more complicated.
Generally early returns can make a functions code less complex which can heavily reduce the number of bugs.
So probably the complexity is a good criteria here.
Additionally I suggest you use exit very carefully. It does much at once and you should normally not need it within your program flow. Especially if you're writing business logic.
Is it a good or bad practice to authenticate and then just exit() the function or to wrap the whole result of the authentication in an if statement? Example
function foo($uid)
{
$allowed = $auth->checkIfAllowed($uid);
if ($allowed == false) exit();
//continue with senstive code here
}
}
OR
function foo($uid)
{
$allowed = $auth->checkIfAllowed($uid);
if ($allowed == true)
{
// do sensitive stuff
}
}
I would like to take this opportunity to talk about exit; (as others have stated both work, the second is more explicit then the first, and give you the opportunity to send a nice error message to the user). My main beef (I have several with exit;) is that people should stop using it in libraries, i.e. code that can/will be used in other projects... You know how irritating it is to debug those? Throw exceptions, trigger fatal errors, but give me something with a description.
/rant
Your examples are equivalent.
However, it's not usually useful to the end user to just exit the script abruptly. Instead, send your user a useful error message printed in HTML rather than the plain text you would get from a die() call, for example.
function foo($uid)
{
$allowed = $auth->checkIfAllowed($uid);
if ($allowed == false)
{
$errormsg = "You are not allowed to view this page";
}
else
{
//continue with senstive code here
}
}
Later, print the error in HTML, rather than just aborting the script:
<div class='error'><?php echo $errormsg; ?></error>
Either or. I don't think it'll make a difference. It relatively the exact same thing. In programming there are many ways to program things, never on right way in most instances.
They are absolutely the same. The indentation and coding style is the only difference. In both cases the sensitive code won't execute unless the authentication is done successfully.
It's usually better to be expressive in your code though, so I'd recommend the second method.
What I want to do is when an if condition doesn't go as it should, instead of echo'ing the my custom error message in else { }, storing the error message somewhere else and retrieving it from another page.
For example, this is my page with the if condition:
if ($something < 4){
echo 'yes it is less than four';
else { echo 'no it isn\'t less than four';}
I want to for example store these error messages in strings and give them numbers:
if ($something < 4){
$debug11 = 'yes it is less than four';
echo '11';
else { $debug10 = 'no it isn\'t less than four'; echo '10'; }
then let's assume there's a debug.php file with php class that can echo these messages but in order to do so it needs to know what $debug11 is, can it do that without including that php page? is that what public strings are for? or should I just define all of them in debug.php
the point of all this is that jquery will call this file.php and get a message like 11 or 10 which in this case is success or failure then I will be able to know why it failed with debug.php. numbers are easier since I may play with text messages a lot and easier to confirm with numbers than text in if conditions.
You want to store error-messages and read this messages by another script.
It means you need a storage.
As a storage, you can use files, or memcache, or APC, or queues.
Create logger, which will write messages to the storage, and then in debug.php you will read list of messages from the storage.
I recommend to use Memcache, set_error_handler and trigger_error.
I'm not sure what you mean by 'public strings', but if you are looking at accessing a variable between 2 pages, you would need to persist them into a session variable at least.
Also you might be better off using PHP assertions to check for error conditions within your code (I think that's what your trying to achieve here):
Assertions should be used as a debugging feature only. You may use them for sanity-checks that test for conditions that should always be TRUE and that indicate some programming errors if not or to check for the presence of certain features like extension functions or certain system limits and features.
Try logging to file: http://nl3.php.net/manual/en/errorfunc.configuration.php#ini.error-log. You can supply a custom log file in which you can find all your errors.
If you put in a error handler you should be able to create debug messages and store them in another file.
Write own logging mechanism and put log messages in a file.
As above I am not 100% sure what you are trying to do, however instead of using variables for your custom error messages it may be better to use Constants. The benefits of them are that the values can't be rewritten unlike your variable where you can change the value within your script.
Your code would look something like this:
define("ERROR1", "It wont Work!");
define("ERROR2", "It still wont Work!");
define("ERROR3", "It must be broken!");
if ($something < 4){
echo '11';
} else {
echo ERROR1; // Prints "It wont Work!"
}
You can store these Constants in your debug.php file and use them on any page you include the file on.
Hope this helps.
I've been having this problem for around an hour, and have searched the internet for answers. I've checked the PHP documentation, looked around, Googled, nothing.
Anyways, my problem is that after I try to validate something (and it's wrong), if I use exit; it will also stop the HTML after. Here's what I'm talking about:
if ($_POST['exampleEmail'] == "")
{
echo "Please enter an e-mail."; //Now I want only the PHP script to stop, however...
exit; //If I use exit, then the HTML after this script (footer) doesn't show.
}
If anyone can help, please do. I've tried using break, but to no avail, since it's only for loops and switches.
If there is a better/more correct (or simply correct if this is the wrong way), please share. I've had this problem in the past, and I just used exit then.
Thanks.
Just wrap the rest of the script in a new if block:
$execute = true;
// HTML here...
if (empty($_POST['exampleEmail'])) {
echo "Please enter an e-mail.";
$execute = false;
}
// HTML here...
if ($execute) {
// do stuff only if execute is still true.
}
// HTML here...
Now that this is working for you, I advise you to do some research into separating your presentation and your logic. There's a lot of tutorials and blogs on the subject, you just need to start searching.
You should use an if-statement in PHP
if ($_POST['exampleEmail'] == "")
{
echo "Please enter an e-mail.";
$stop_script = true; //stop the script
}
else $stop_script = false; //or continue the script
if($stop_script === false)
{
//php scripts
}
//html
Use break http://php.net/manual/en/control-structures.break.php instead. But you probably have a structural Problem if it comes to this usecase in the first place.