Optimal way to handle "return"? - php

I need an advice how to handle function with lots of different return's better.
I have this simple log in function in my class:
public function login($email, $password){
$record = // Go to database and find what we need.
if($record){
// Check pass, $user_match = TRUE;
} else {
return 1; //No such user. Please register!
}
$active = (1 == $record['is_active']) ? TRUE : FALSE;
$verified = (1 == $record['is_verified']) ? TRUE : FALSE;
//User email and password matched:
if($user_match == true){
if($verified === true){
// Start session and insert to db table "online_users"
// Check that user was inserted to table: $confirm = $stmt->rowCount();
if($confirm !== 1){
return 2; //Unexpected technical error. Please try again in a moment.
}
return 0; //0 means that all clear, we good to go.
} else {
return 3; //not verified
}
} else {
return 4; // no match with email and pass, reject!
}
}
The problem is, that now all the time I need to check all return's, something like that:
$log = $user->login($_POST['email'], $_POST['pass']);
if($log === 0) {
//Log in & edirect
} elseif ($log === 1) {
//No such user. Tell to register
} elseif($log === 2){
//technical error, try again
} elseif($log === 3){
//Not verified
} elseif($log === 4){
//wrong password
It's really annoying right now, and imagine if I would need to check like 20 return's? Is there any better way? How to do it more efficient and faster?
Thanks in advance.

You should rethink the purpose of this function and structure the return types accordingly. If the purpose is to log the user in, there can only be one answer: it either worked or it didn't. So the primary return type of the function should be a boolean. How to differentiate between different causes for failure is a different topic.
Option 1: throw exceptions:
try {
if (!$foo->login()) {
echo 'Invalid credentials';
}
} catch (UserNotActiveException $e) {
...
} catch (UserNotValidatedException $e) {
...
}
Not necessarily the most elegant option, since a failed login isn't really an exceptional circumstance.
Option 2: save the error state in the login provider:
if (!$foo->login()) {
echo "You're not logged in because ", $foo->loginError();
}
Whether this is good or not depends on how the class is used otherwise, you may not want to make it too stateful.
Option 3: separate the problem of login from what is the user's state entirely:
if (!$foo->login($user)) {
switch ($foo->currentStatus($user)) {
case $foo::ALL_OK :
echo 'Login credentials invalid';
break;
case $foo::ACCOUNT_INACTIVE :
...
}
}
Option 4: return a status object:
$result = $foo->login();
switch ($result->status) {
case $result::ALL_OK :
...
}
That's essentially what you're doing now, just without the magic numbers.

Using exceptions would be one way to provide clear handling of error code, depending on how this fits into the rest of your application.
As was pointed out by Nanne, you shouldn't use exceptions for flow control: they should only indicate exceptional circumstances. The technical error is clearly an exceptional circumstance and using exceptions for this would be clear and appropriate.
Using exceptions for the rest of it is less clear, but still an option. You could simply throw an exception with different error messages for each failure condition, or different exception classes that have appropriate handlers for the failure conditions.
This is starting to break the semantics of exceptions, depending on how this code fits in with the rest. Being able to call the login function elsewhere without having to worry about it throwing inappropriate exceptions might be useful or necessary, for example.
In the end, there's probably no getting around the need to have explicit checks for each of those failing conditions and returning them inside the function. Again, depending on how flexible this needs to be, you could just return true on a successful login, or an error message on failure (using === to verify that the result is true, not just truthy). Or you could return an object with a success property and an error condition, which at least makes your error handling code a matter of checking the success and handling the error code.
If you need significantly different error handling mechanisms for each failure condition, then returning a constant for each failure case could at least make it clear what's going on in the code. You can then return LOGIN_PASSWORDS_DO_NOT_MATCH instead of a cryptic number, which could then be checked in your error code.

Better use switch statement if you need many if-else statements:
$log = $user->login($_POST['email'], $_POST['pass']);
switch ($log) {
case 1:
break;
case 2:
break;
//etc....
}
To clarify error codes use named constants or static array of name=>code pairs instead of "magic numbers"
static $ERROR_CODES = array(
"WRONG_PASSWORD"=>1,
"WRONG_EMAIL"=>2
);
switch ($log) {
case LoginClass::$ERROR_CODES["WRONG_PASSWORD"]:
break;
case LoginClass::$ERROR_CODES["WRONG_EMAIL"]:
break;
//etc....
}

You can use INI Files
write your bugs in an ini file:
1 = "Error"
2 = " Technical"
3 = "Network"
...
And save it into and ini file. Then use this code:
<?php
$array = parse_ini("er.ini");
echo $array[$log];
?>

Related

Check result of PHP include

I've got my login and session validity functions all set up and running.
What I would like to do is include this file at the beginning of every page and based on the output of this file it would either present the desired information or, if the user is not logged in simply show the login form (which is an include).
How would I go about doing this? I wouldn't mind using an IF statement to test the output of the include but I've no idea how to go about getting this input.
Currently the login/session functions return true or false based on what happens.
Thanks.
EDIT: This is some of the code used in my login/session check but I would like my main file to basically know if the included file (the code below) has returned true of false.
if ($req_method == "POST"){
$uName = mysql_real_escape_string($_POST['uName']);
$pWD = mysql_real_escape_string($_POST['pWD']);
if (login($uName, $pWD, $db) == true){
echo "true"; //Login Sucessful
return true;
} else {
echo "false";
return false;
}
} else {
if (session_check($db) == true){
return true;
} else {
return false;
}
}
You could mean
if (include 'session_check.php') { echo "yeah it included ok"; }
or
logincheck.php'
if (some condition) $session_check=true;
else $session_check=false;
someotherpage.php
include 'session_check.php';
if ($session_check) { echo "yes it's true"; }
OR you could be expecting logincheck.php to run and echo "true" in which case you're doing it wrong.
EDIT:
Yes it was the latter. You can't return something from an included file, it's procedure not a function. Do this instead and see above
if (session_check($db) == true){
$session_check=true;
} else {
$session_check=false;
}
Actually..
$session_check=session_check($db);
is enough
Depending on where you want to check this, you may need to declare global $session_check; or you could set a constant instead.
you could have an included file which sets a variable:
<?php
$allOk = true;
and check for it in you main file:
<?php
include "included.php";
if ($allOk) {
echo "go on";
} else {
echo "There's an issue";
}
Your question seems to display some confusion about how php includes work, so I'm going to explain them a little and I think that'll solve your problem.
When you include something in PHP, it is exactly like running the code on that page without an include, just like if you copied and pasted. So you can do this:
includeme.php
$hello = 'world';
main.php
include 'includeme.php';
print $hello;
and that will print 'world'.
Unlike other languages, there is also no restriction about where an include file is placed in PHP. So you can do this too:
if ($whatever = true) {
include 'includeme.php';
}
Now both of these are considered 'bad code'. The first because you are using the global scope to pass information around and the second because you are running globally scoped stuff in an include on purpose.
For 'good' code, all included files should be classes and you should create a new instance of that class and do stuff, but that is a different discussion.

LDAP Strong(er) authentication required

I want to add the value to the attribute. This is my code below.
function set_attribute($attribute, $uid, $service)
{
$entries = $this->get_account($uid);
if ($entries != false && count($entries) == 1) {
$entry = $entries[0];
$result = $entry->add(array($attribute => $service));
if (PEAR::isError($result))
return false;
else {
$result = $entry->update();
if (PEAR::isError($result))
return false;
}
return true;
} else
return false;
}
I failed to add new value to the attribute. This is the error when I dump this code $result->getMessage()
string(121) "Could not add new values to attribute serviceType: Strong(er) authentication required: LDAP_STRONG_AUTH_REQUIRED"
What's wrong with it. I find no solution at all even I have authenticated.
This does not look like confidentiality required error, when you need SSL/TLS enabled to secure the channel rather than a clear text connection. Though you never know, since you do not clarify if your connection is secure or not.
I wonder if this is meant as a permission issue? Or perhaps this is a case where, the system is allowing a clear text bind, but will not allow certain operations without secure comms on the connection.

PHP classes - Should status messages be inside or outside of the class?

I have a class that does something, and when it's done it returns true, but if any of the various things go wrong it will return false. Now my question is, should status messages for such events be kept inside a class (Example1) or outside the class (Example2) where class maybe only provides error code to help distinguishing what happened.
class Example1 {
private $var;
private $status;
public function doSomething($var) {
$this->var = $var;
if (!is_numeric($this->var)) {
$this->status = 'Please provide a number';
return false;
}
if (empty($this->var)) {
$this->status = 'Please fill the field';
return false;
}
$this->status = 'Ok, you submitted a number, cool.';
return true;
}
function getStatus() {
return $this->status;
}
}
example 2:
class Example2 {
private $var;
public function doSomething($var) {
$this->var = $var;
if (!is_numeric($this->var)) {
return false;
}
if (empty($this->var)) {
return false;
}
return true;
}
}
Example 1 seems to me more convenient to use, code reads like a poem, but at the same time seems less reusable, depending on what you use class for, you might want success/error messages to have different syntax.
So basically my question would be what's the usual practice?
First example: you hard code error messages which is... bad. And you can't see the error message if you don't check $object->status later.
Second example: if something goes wrong, you know it but you don't know why.
I suggest avoiding both these ways and throwing exceptions for a more object oriented approach (I guess that's what you want, since you're using classes :).
It's completely up to you. If error messages are easier for you to understand and help you debug your code, then by all means go for it. Coming up with error codes for different errors will probably just slow down the development process, unless you want to hide the true errors from users (but in that case you have several options, one of which is to not print errors to screen at all if users might see them).
It's not what you are asking, but it's generally considered bad practice to have multiple return statements in one function. The problem is that it makes it harder to know where you exit the function, which makes it not clear what is executed. In your example, if the first test succeeds, the rest of the code is not executed. What would happen if you set some attributes afterwards ? Sometimes they will be set, sometimes they won't. To get rid of this problem, it's better to have only one return statement. More code will be executed, and you'll have to change the way you are coding a bit in order to get used to it.
Here is an example of what I mean, with the code you provide :
public function doSomething($var) {
$this->var = $var;
$result = false;
if (!is_numeric($this->var)) {
$this->status = 'Please provide a number';
}
else if (empty($this->var)) {
$this->status = 'Please fill the field';
}
else{
$this->status = 'Ok, you submitted a number, cool.';
$result = true;
}
return $result;
}

What is the standard way to return errors to the user from a function?

What is the standard way to return errors to the user from a function? (email invalid, max characters exeeded, etc.)
function register($name, $email) {
if(!$name) {
$registration_errors = 'name empty,';
}
if(!email) {
$registration_errors = $errors . 'email empty,';
}
if($registration_errors) {
return $registration_errors;
}
else {
register stuff........
return true;
}
}
now the problem is that it always returns true so you cant do something like:
if(register()) {blah blah blah} else { put errors under inputs}
So what would be the standard method of doing this?
use something like this
function register
{
..
else
{
return array('error' => $errorwhichyoufound);
}
....
}
$result = register();
if((array_key_exists('error', $result)))
{
}
else
{
}
This way you can even check for individual errors.
<?php
// in your register function:
$registration_errors = array();
if (!$name) {
$registration_errors['name'] = 'Name is required.';
}
// etc.
?>
<!-- in your phtml: -->
<?php if (array_key_exists('name', $registration_errors) echo $registration_errors['name'];?>
<label for="name">Name</label>
<input id="name" name="name" type="text" value="<?php echo $name; ?>" />
There are all sorts of ways to do this, and you might even consider some of them "standard". You could return an array containing the error code (as the answers above), you could store the error as an object property (requiring you to call "register" as an object method), you could store the error in a global variable, or put the error in a registered location. You could pass in a variable reference and set the variable value to the error. You could reverse the return logic, so a string would be false and a zero would be a true value. You could raise an error. You could throw an exception.
The real problem here is that the "register" function is supposed to perform some function and you are asking it to sanitize the input just in case something funny is going on. So if you really need to sanitize $name and $email, why not do that validation before the call to register? You are going to need some kind of error path regardless, and perhaps several different error messages depending on the situation. When you are finally ready to call register, it should succeed or fail for its own reasons, and not because the business rules require a non-empty email address.

PHP: testing session

Why is the construction brittle? I tried "!empty ( get_original_passhash() )" as a condition, but it ignites the error that you cannot use the return value.
if ( get_original_passhash () != '' )
{
set_login_session ( get_original_passhash() );
}else
print("Please, log in.");
I would be inclined to assign the variable before you test it, and probably also clean up your formatting a little too:
$original_hash = get_original_passhash();
if ($original_hash != ""){
set_login_session(get_original_passhash());
} else {
print("Please Log In");
}
You should also ensure that get_original_passhash() is returning the right type of variable - interger, string, boolean, etc.
Edit:
function get_original_passhash(){
$dbconn = pg_connect("host=localhost port=5432 dbname=heoa user=heoa password=123");
if(!empty($passhash_session)){
return $passhash_session;
} else {
return $passhash_post;
}
}
What is this code supposed to do? It connects to a database, and then tests a variable that just appears out of nowhere? Your code isn't working because, from the example's you've provided us, nothing is even being set. Is this the full source code for this function?
You may want to split up your logic:
if (is_logged_in()) {
set_login_session(get_original_passhash());
} else {
print("Please Log In");
}
Since, in the conditional, you don't want the pass hash. You want to know if they're logged in or not.

Categories