PHP - Wondering about efficiency of nested IF statements for user registration - php

I am working on a little project of designing a website for my friends and myself.
I am currently building the user registration system and am wondering if the way I am checking user's entries is the best it could be.
Um, ignore the api stuff, it is for eve and likely irrelevant.
I have plans for the elses.
Essentially, I would like to know if this is acceptable in terms of... everything.
And if not, what could I do to improve this.
I am newer to PHP, please be kind :)
So, this is what I am currently using:
if (!empty($_POST['username'])
&& !empty($_POST['password1'])
&& !empty($_POST['password2'])
&& !empty($_POST['email1'])
&& !empty($_POST['email2'])
&& !empty($_POST['keyID'])
&& !empty($_POST['vCode'])
){
$api = new EVEAPI();
if ($api->getCharacterID($_POST['username']) != 0){
//The username is valid.
if ($_POST['password1'] == $_POST['password2']){
//Passwords match.
if ($_POST['email1'] == $_POST['email2']
&& filter_var($_POST['email1'], FILTER_VALIDATE_EMAIL)
){
//Emails match and are in valid format.
if ($api->isValidAPI($_POST['keyID'], $_POST['vCode'])){
//If the API returns something that is not an error, continue.
$xml = $api->getAPIKeyInfo($_POST['keyID'], $_POST['vCode']);
if ($xml->result->key->attributes()->type == 'Account'){
//If the 'type' of the returned API info is 'Account', continue.
foreach ($xml->result->key->rowset->row as $apiRow){
$charID = (int) $apiRow->attributes()->characterID;
if ($charID == $api->getCharacterID($_POST['username'])){
//DO SOMETHING WITH INFO
}
else{
}
}
}
else{
}
}
else{
}
}
else{
}
}
else{
}
}
else{
}

Efficiency wise this isn't going to matter all that much, but for maintainability's sake it will.
Instead of nesting so many ifs like that, try early failure with your ifs. Something like this:
if ($api->getCharacterID($_POST['username']) == 0) {
// Fail early. Throw an exception, die, or whatever
}
// Continue along as normal, not in an else.
if ($_POST['email1'] != $_POST['email2']) {
// Fail early. Throw an exception, die, or whatever
}
// Etc.
That sort of strategy will generally serve you well unless there's a very good reason to not use it.

It is hard to read and not very clean. The way I do it is use negative if statements. By that I mean the following:
if ($api->getCharacterID($_POST['username']) == 0){
// Username is not valid, so stop execution
}
if ($_POST['password1'] != $_POST['password2']) {
// Send error to user and stop execution
}
// ...etc.
Now how do you stop execution? Well you have few options
Throw an exception
Use die statement
have a parameter that you change everytime you enter an if block, then check if you should continue.
some other solution
But the point is, this approache makes your code cleaner.
Cheers.

These days mostly programmer use jquery / Javascript for forms validations, but if you are using pure PHP the try below code, hope it will be good and secure obviously :)
$username = mysql_real_escape_string($_POST['username']);
if($username == "")
{
$username_required = '<div>Please enter your username</div>';
} else {
$username_ok = true;
}

Typically in most validation patterns out there they have this errors array where you check for all the conditions and add error messages into the array if the array is empty at the end it only means that there are no errors..
For me i wouldn't want my code to look too nested like this i would use variables to dictate each step.
From there you can decide whether to display just the first error. It doesnt hurt to validate through everything at once because the processing should not be that extensive unless you have like 5000 form fields. I think it's ok.
When you code you must remember because code is written for humans and you will want to be kind to your eyes or for those who read your code.. Basically nested is ok. it saves some further processing and it also depends on the logic you need.
Yes its good to save time but at times you do things too nicely to minimize processing you have to weigh the needs if you do it so nice but in the end the time you save is so substantial then it makes no point.. The compiler is not going to pat your back and say good job anyways..
$errors = array();
$usernameValid = $api->getCharacterID($_POST['username']) != 0;
if (!$usernameValid) $errors[] = 'Username is not valid';
//If you want to store which attribute caused the error you can use the attribute name as array key
//if (!$usernameValid) $errors['username'] = 'Username is not valid';
$passwordMatches = $_POST['password1'] == $_POST['password2'];
if (!$passwordMatches) $errors[] = 'Password does not match';
if ($usernameValid && $passwordMatches)
{
//What to do if user name and password passes validation. wooo hoo~
}
//Etc etc..

Related

PHP fgets returns an empty string

So I'm making a webshop, well, trying to atleast for a course project using WAMP. But when trying to register new users and in the process checking their password against a list of common ones the use of fgets() returns an empty string.
if(empty(trim($_POST["password"]))){
...
} elseif (!checkPassword($_POST["password"])) {
$password_err = "Password to common.";
echo "<script>alert('Password to common.'); location.href='index.php';</script>";
}
The checkPassword() is where the fault lies.
function checkPassword($passwordtocheck) {
$passwordtocheck = strtolower($passwordtocheck);
$common_passwords = fopen("commonpasswords.txt", "r");
while(!feof($common_passwords)) {
$check_against = fgets($common_passwords);
echo "<script>alert('Checking $passwordtocheck against $check_against.'); location.href='index.php';</script>";
if($check_against == $passwordtocheck) {
fclose($common_passwords);
return false;
}
}
fclose($common_passwords);
return true;
}
Lets say that I input the password 12345678 when registering, then the scripted alert will say "Checking 12345678 against ." and send me back to index.php. So it looks like it doesn't succeed in reading the file at all. The commonpasswords.txt is in the same folder as the rest of the files and with a single password on each row.
And there is no problem opening the file to begin with either, if I do this instead:
$common_passwords = fopen("commonpasswords.txt", "a");
fwrite($common_passwords, "test");
'test' will appear at the bottom of the file under the existing words on its own row without a hitch. And this is where I'm at, would appreciate whatever input people can give!
EDIT; I do understand that this probably breaks a ton of good-practice 'rules' in general and regarding security. But the website is not really supposed to function or look good, it just need to barely work so that we can later try and use different methods of attacking it and the connected database.
If you insist on doing this yourself – which I do not recommend – you can simplify things a lot by using the file() function. This returns an array of every line in the file. Then use array_filter(); it runs a callback on each element of the array where you can check if there's a match with your password. If the callback returns false, the element is removed from the array. After that, if you have any elements left you know there was a match.
function checkPassword($pwd) {
$pwd = strtolower($pwd);
$common = file("commonpasswords.txt", FILE_IGNORE_NEW_LINES);
$results = array_filter($common, function($i) use ($pwd) {return $i == $pwd;});
return count($results) === 0;
}
But really, there are dozens of libraries out there to check password strength. Use one of them.
Or, as pointed out in the comment, even simpler array_search:
function checkPassword($pwd) {
$pwd = strtolower($pwd);
$common = file("commonpasswords.txt", FILE_IGNORE_NEW_LINES);
return array_search($pwd, $common) === false;
}

Simple password validation in PHP

I'm a beginner to PHP trying to learn the basics of validating form data. I want to check if the password has been set, and if it has then to further check if it is the right length and has the right characters etc.
//check if set
if (empty($_POST['password']) {
//further validate - check length, characters etc
if (myFunction(($_POST['password'])) {
//success
$password = $_POST['password'];
}
else {
$error = "Password must be at least 8 characters and contain at least one number";
}
}
else {
$error = "Password is required";
}
The problem I'm having is if the user enters "0" as a password, the empty() function treats this as empty, and they're given the "Password is required" error, rather than the "Password must have..." etc error.
Using the isset() function instead wouldn't work either because an empty field would return an empty string, which would be considered to be set.
At the moment I have a workaround where I have a further conditional to check if the password is set to "0", but there must be a more elegant way.
Apologies if this has been covered in another question, I couldn't find anything. Thanks
Use isset() (and possibly strlen(trim()), not empty(). Although the way this code is shown, it will process only an empty password, and give an error to anyone who puts in a password.
if(isset($_POST['password']) && strlen(trim($_POST['password']))){
//process
}else{
//error
}
If you are just learning the basics, then use the function below. However, do remember in a live environment you will want to be hashing passwords properly. Read this link for more info: http://php.net/manual/en/faq.passwords.php
function PasswordCheck($password_string)
{
$password_string = trim($password_string);
if($password_string == '')
{
die("Password not entered");
}
elseif(strlen($password_string) < 8)
{
die("Password must be more than 8 characters in length");
}
elseif(!(preg_match('#[0-9]#', $password_string)))
{
die("Password must contain at least one number");
}
else
{
//Success, now process password
}
}
$password = $_POST['password'];
PasswordCheck($password);
You can use is_null() function or:
if ($_POST['password']==NULL)
please don't forget to use htmlspecialchars once before you use $_POST to make sure no XSS scripting attacK.
Isset function is better than empty in your case.
Additonally if you want user to get at least 8 characters and contain one number, use regular expression it is much better.
0 is considered to be empty in php. (source: http://php.net/empty )
You could get around this by checking if it is empty or if there is nothing in the string, or if it is exactly null, like so:
if ((empty($_POST['password']) || ($_POST['password']=='') ||
($_POST['password']===null) ) {
...
}
This should cover all your bases, however it is easy to check that something is there than checking a negative (I find it cognitively easier), such as making sure the password is entered, instead of checking to see whether it is not entered
The 'PHP Type Comparison Table' is your friend.
http://php.net/manual/en/types.comparisons.php
To check if the password has been set.
// Check if it has been set and contains characters.
if (isset($_POST['password']) && strlen($_POST['password']) > 0)
{
// Passed, now check for the right length, characters, etc.
if (myFunction(($_POST['password']))
{
// Success.
$password = $_POST['password'];
} else {
// Error.
$error = "Password must be at least 8 characters and contain at least one number";
}
} else {
// Failed.
$error = "Password is required";
}
If you require help with your 'myFunction()' function to check length, characters, etc then you will need to post that code as well.
Hope this helps.

Checking Users HTML form input with PHP

I am creating a web application that takes in a user input (Scientific Paper DOI) and queries a database to display a graph. I've been trying to limit the connections made to the database since its on a remote server (private DMZ with web server) by checking the user input if it matches a correct DOI.. if it doesn't then no connection to the database will be made, I hope this will help speed up the application if there are many users at once making queries.
Pseudo: All paper DOIs start with "10.1103/" because they are all physics papers. This part I have implemented correctly using substr. Next I want to check every character in the input to make sure it only consists of only these characters:
Letter
Number
"/"
"."
Example DOIs:
10.1103/RevModPhys.9.1
10.1103/RevModPhys.76.1015
10.1103/PhysRevLett.95.208304
Here is my code:
function checkDOI($doi) {
if (substr($doi, 0, 8) != "10.1103/") {
echo "Invalid DOI";
return false;
}
for ($n = 0; $n < strlen($doi)+1; $n++) {
if ( !ctype_alnum($doi[n]) && $doi[n] != "." && $doi[n] != "/") {
echo "Invalid DOI";
return false;
}
}
echo "Valid DOI";
return true;
}
if(isset($_POST['submit'])) {
$doi_input = $_POST['doi_input'];
checkDOI($doi_input);
}
I am working with PHP and javascript for the very first time, the pseudo is fairly simple but for some reason, there is something wrong with the 2nd if statement. Not sure if I can really do that. The Echos are just for tests.
Do you think doing this check for every input will slow down the application significantly? Is it worth it to limit the amount of connections to mysql?
The bottom of the code will be modified once I have this working to only query the database if checked returns true.
Thanks for the help!
to check every character in the input to make sure it only consists of only these characters
I suggest you to use preg_match.Try this:
$value="10.1103/RevModPhys.9.1";
if(preg_match("/^[a-zA-Z0-9\/.]+$/", $value)){
echo "match found";
}else{
echo "no match found";
}
Check here: Demo
For more info: preg_match
Your error is $doi[n], it is not an array and should it be the index is invalid.
So use a function like
$chars_doi = str_split($doi);
Before the loop to get an array of characters then use in your loop
$chars_doi[$n]
So you should have something like:
$chars_doi = str_split($doi);
$size = sizeof($chars_doi) - 1;
for ($n = 0; $n < $size; $n++) {
if (!ctype_alnum($chars_doi[$n]) && $chars_doi[$n] != "." && $chars_doi[$n] != "/") {
echo "Invalid DOI";
return false;
}
}
Little tip, avoid use functions such as strlen / sizeof as a loop argument or it will get called at each iteration. It is better for performance to store the value in a variable beforehand.
I would just do:
if (! preg_match ('#^10\.1103/[\p{L}\p{N}.-_]+$#', $doi)) {
... // bad
return;
}
// good
Reference:
http://www.php.net/manual/en/reference.pcre.pattern.syntax.php
http://php.net/manual/en/regexp.reference.unicode.php

Creating a PHP function triggered when shady DROP like queries are performed

I'm trying to code "If (the query contains any common attack terms, over 80 characters etc) { execute function }"
I know preg_replace allows characters but is there a function to disallow set strings or how to build something like:
if(isset( contains['DROP, OR, 1-1, etc]) ) {
$message = $_SERVER["REMOTE_ADDR"];
$message = $_SERVER[""];
mail('admins#website.com', 'Shady Query Going on', $message);
}
I know various plugins send warnings of multiple login attempts and lockouts etc. I'm looking to do the same with SQLi attempts
UPDATE: Turns out that this is in fact a useful plugin - Better WP Security emails you when bad logins and other shady business goes on. No one answered my question either, seems like a bunch of elitist rants...
Thanks to #Rook and #Thawab tho!
I would recommend using http://phpids.org/ in your script since it can detect more attacks.
If you properly protect your site against SQL injection you absolutely don't need this. However, to implement it...
function checkForBlacklistedTerms($string)
{
$blacklisted = array('DROP', '--', 'KILL', 'BLAH', 'BLIH');
foreach($blacklisted as $bl) {
if( strpos($string, $bl) !== FALSE ) {
return true;
}
}
return false;
}
if( checkForBlacklistedTerms($searchquery) || strlen($searchquery) > 80 )
{
// warning code goes here
}

How should I validate form input data using PHP? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
Hi im still learning PHP so dont be too harsh if my code seems stupid. Anyways, I'm trying to make a contact page and add validation to it. I'm using an if statement but I don't think it is right, any way how should the below code look?
<?php
if($name_blank == false){
echo"you left name blank";
}
else if($email_blank == false){
echo"Email blank";
}
else if($email_fake == false){
echo"Fake email";
}
else if($number_blank == false){
echo"Number blank";
}
else if($number_low == false){
echo"Number incorrect";
}
else if($number_fake == false){
echo"Fake number";
}
else if($comment_blank == false){
echo"Commant blank";
}else{
hasError = false;
}
?>
thanks.
There are plenty of libraries/frameworks that will take care of most of the work involved in forms (and other annoying bits in PHP) for you. I like Symfony but you might want to find something a bit less complicated if all you want is a contact form.
Both IF/ELSEIF/ELSE and SWITCH/CASE aren't great structures for something like this. In both cases, the code will stop at the first condition that evaluates to true. If someone has more than one invalid input in your form, you will only output an error message for the first issue you find.
I would use something like:
$hasError = false;
if($name_blank == false){
echo"you left name blank";
$hasError = true;
}
if($email_blank == false){
echo"Email blank";
$hasError = true;
}
if($email_fake == false){
echo"Fake email";
$hasError = true;
}
if($number_blank == false){
echo"Number blank";
$hasError = true;
}
if($number_low == false){
echo"Number incorrect";
$hasError = true;
}
if($number_fake == false){
echo"Fake number";
$hasError = true;
}
if($comment_blank == false){
echo"Commant blank";
$hasError = true;
}
Of course, there is a lot more to properly using forms, but to get the basic functionality your looking for, this will do the job.
Considering usage of else if it seems all right.
In PHP, you can write both elseif or 'else if' (in two words) and the behavior would be identical to the one of 'elseif' (in a single word). The syntactic meaning is slightly different but the bottom line is that both would result in exactly the same behavior.
some short stuff:
instead of writing ($a == false), you can always write (!$a)
if name_blank indicates that the name is blank, one would think that an error message is in order if it true, not false, so maybe your variable naming is a bit strange
no reason not to give out all the errors, not only the first one (ie only if (){} if (){} etc.) you might want to add them to an error message string, that will also allow you to find out if hasError or not
Please look into these functions:
empty() - helps to check whether the user submitted data into a field
strip_tags() - prevents XSS*
isset() - check whether a variable is set or not
And when you'll start learning databases:
mysqli_real_escape_string() - prevents SQL injection*
What you did there is not enough, nor correct.
If the name is NOT blank then you skip every other field, because of else if's, but those skipped fields could be empty, too!
So I recommend you understand the execution flow first, in this case having only ifs it would be ok, plus the functions I mentioned above!
* of course there is more you can do, but for now it's enough
Do all the user friendly validation on client side and ignore requests coming with an invalid form data on the server side for security.
Somebody who passes through your client side validation doesn't deserve any user friendliness anyway.
Validation is too expensive in terms of programmer time. Don't spend too much time on validating input.
in this case, use ifs and not else ifs, learn what if and else does.
My personal preference is
switch(true){
case blabla>number: break;
case blabla=="": break;
case strlen(blabla)==5: break;
}

Categories