Search keys inside multiple arrays - php

I am just working with username-to-password validation scripting, and I don't want to mess with database connections just yet. So I'm just putting certain test emails and passwords into some arrays, then working at validating against those arrays.
I'm getting stuck on the best way to do this, because I actually want to put more pertinent data into each "user" array.
Here's what I've started so far, and you'll see what I'm shooting for:
<?php
$email = $_POST['email'];
// test emails
$logins = array('john#smith.com'=>'123456','jane#smith.com'=>'123456');
if (!array_key_exists($email, $logins)) {
echo "that email does not exist, stop here.";
}else{
echo "email exists, continue...";
}
?>
And this works fine, since it's simple, but as I needed to add more options into the array, the method changed to this:
<?php
// tester accounts
$user1 = array('email'=>'john#smith.com','password'=>'123456','fullname'=>'john smith','handle'=>'johnny');
$user2 = array('email'=>'jane#smith.com','password'=>'123456','fullname'=>'Jane Smith','handle'=>'janeyS');
// credentials passed from a form
$email = $_POST['email'];
$pass = $_POST['pass'];
/* not quite sure how to validate the $user arrays */
?>
And the user arrays probably will grow with more things related to that user, obviously.
But I'm used to working with database connections, and not straight from PHP arrays.
Can someone throw me a little advice on a simple email/pass validation from multiple php arrays like what I just did above? Or perhaps there's a better method?

Turn your users into a $users array.
$success = (bool) array_filter($users, function($user) use ($email, $pass) {
return $user['email'] == $email AND $user['password'] == $pass;
});
This code will loop through all the users in the $users array and return the subset which matched for username and password (should be either 0 or 1).
Because an empty array is falsy in PHP, casting it to Boolean should give the correct result. You could skip this if you wanted, dependent on the context of using it.

Related

Using function inside $_REQUEST

So I'm trying to check if an user exist before deleting it (if user exists, it will compare the passwords and then the user will be deleted), but I'm stuck in the comprobation of the user existing.
At beggining, I was making the user existing and password matching inside the isset($_REQUEST), but I thought making functions for these things will be cleaner and clearer for me (I was having problems making everything inside $_REQUEST). So I decided to make a function to check if an user exists in the database and I want it to be called inside my $_REQUEST(botonBaja) button.
What am I doing wrong?
I have this line at beggining, so $conexion is not out of scope:
<?php
include 'conexionBBDD.php';
function checkUserExist($nif){
$selectPass = "SELECT PASSWORD FROM votante WHERE NIF='".$nif."';";
$resultado= $conexion->query($selectPass);
if (mysqli_num_rows($resultado) == 0) {
return false;
}else return true;
}
The previous code is called by this isset($_REQUEST), which is a button (the button is working well). $nif and $password are being collected well, trust me, I've debugged it, it and it stops when it reaches the function.
if (isset($_REQUEST['botonBaja'])) { //DELETE USERS
$nif = $_REQUEST['nif'];
$password = $_REQUEST['password'];
if (checkUserExist($nif)){
echo "The user already exist";
}else echo "The user doesn't exist";
}
(Both codes are in the same php file)

problem with registration and login php,will you check my code?if there is an error

I have a problem with either registration and login shows (undefined offset) and look at registration is there some problem with my code?it is the registration form the problem it sometimes saves the existing email in spite of the fact that I wrote a function for not submitting the existing email which is inside my data.txt. shortly the functions do not work properly
<?php
if(isset($_POST['submit_reg'])){
$var=file("data.txt");
$userData = $_POST['email'] . " " . $_POST['password'] . "\r\n";
$lines=0;
$db = fopen("data.txt", "a+");
foreach($var as $key=>$value){
$user = (explode(' ', $value));
if ($_POST["password"] === $_POST["confirm_password"]) {
//print_r($value);
if (trim($user[0]) == $_POST['email']) {
$lines++;
}
break;
}
}
if($lines){
echo "The email is already exists ";
}else{
fwrite($db,$userData."\r\n");
fclose($db);
echo "you are registered successfully ";
}
}
?>
and it is my login form the problem with login is it gives an error undefined offset 12
<?php
if (isset($_POST['submit_log'])) {
$email =isset($_POST['email']);
$password =isset($_POST['password']);
$file = explode( PHP_EOL, file_get_contents( "data.txt" ));
$auth = false;
foreach( $file as $line ) {
list($email, $password) = explode(" ", $line);
if ($_POST['email'] == $email && $_POST['password'] == $password) {
$auth =true;
break;
}
}
if($auth) {
echo "Login successfull!";
} else {
echo "Invalid username or password";
}
}
?>
Let me say first off, storing plaintext passwords in a .txt file is probably not the best way of building a longin system. (that's the disclaimer anyway).
Undefined offset (just a guess)
That said I see a few places to improve your code. My guess without more specifics about the error, is you may be pulling a empty array at the end of the file, it's typical to leave a hanging line return at the end (a new line with nothing else for the last line). Which may turn into something like this once you explode it for the second time on the space ['']. And then you try to access it using list which gives you undefined offsets.
You could use array_filter and maybe trim but instead of doing this:
$file = explode( PHP_EOL, file_get_contents( "data.txt" ));
You could try (which you should know as you use this function already)
$file = file( "data.txt", FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES ));
The file function, takes a file and breaks it into an array based on the line returns. So this takes the place of both explode and file_get_contents.
Then it has 2 (bitwise) flags which you could make use of:
array file ( string $filename [, int $flags = 0 [, resource $context ]] )
Reads an entire file into an array.
FILE_IGNORE_NEW_LINES
Omit newline at the end of each array element
FILE_SKIP_EMPTY_LINES
Skip empty lines
http://php.net/manual/en/function.file.php
These take the place of filtering the data for empty lines (something you weren't doing). Granted this is a file you created but you never know when a errant line return could creep in there.
Non-unique entries
if(isset($_POST['submit_reg'])){
$var=file("data.txt");
$userData = $_POST['email'] . " " . $_POST['password'] . "\r\n";
$lines=0;
$db = fopen("data.txt", "a+");
foreach($var as $key=>$value){
$user = (explode(' ', $value));
if ($_POST["password"] === $_POST["confirm_password"]) {
//NOTE: the uniqueness check only happens when the confirm password matches
if (trim($user[0]) == $_POST['email']) {
$lines++;
}
break;
}
}
if($lines){
echo "The email is already exists ";
}else{
//NOTE:yet you save it no matter if that is the case
fwrite($db,$userData."\r\n");
fclose($db);
echo "you are registered successfully ";
}
}
Your uniqueness check only works when the confirm password matches the password, however when it comes time to save the data, there is no check. Instead of just adding that check in around the saving bit, it would be better to wrap the whole thing inside this confirm test, as both pieces of that are known before touching the file:
Here I reworked this a bit for you
if(isset($_POST['submit_reg'])){
if ($_POST["password"] === $_POST["confirm_password"]) {
//VERIFY AND SANITIZE user input, if you put junk in you get junk out
$password = trim($_POST['password']);
//again use something better then die
if(empty($password))die('Password cannot be empty');
//because you split on space, you cannot allow it in inputs
if(preg_match('/\s+/', $password)) die('Password cannot contain spaces');
$email = trim($_POST['email']);
if(empty($email))die('Email cannot be empty');
//you may want to validate using something better
if(preg_match('/\s+/', $email )) die('Email cannot contain spaces');
//Use the flags
$var=file("data.txt", FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES);
//for duplication we only care if there is 1 previous entry
//which is enough to say its a duplicate
$exists=false;
foreach($var as $key=>$value){
$user = explode(' ', $value);
if (trim($user[0]) == $email) {
//we found a match this is enough to call it a duplicate
$exists = true;
break;
}
}
if($exists){
echo "The email is already exists ";
}else{
file_put_contants("data.txt", $email." ".$password.PHP_EOL, FILE_APPEND);
echo "you are registered successfully ";
}
}else{
echo "Confirm password must match password";
}
}
Other stuff
These are also incorrect:
$email =isset($_POST['email']);
$password =isset($_POST['password']);
Isset returns a boolean value, so you are assigning true or false to those two variables. This doesn't matter as you never check them and in your loop you overwrite with the call to list(). But just because someting "doesn't matter" doesn't mean it's correct.
These really should be something like this:
if(!isset($_POST['email']))
die("no email"); //dont use die but do some kind of error message
if(isset($_POST['password']))
die("no password"); //dont use die but do some kind of error message
SUMMERY
Really it's quite a mess. What I mean by this is you used 3 different ways to open and access the file data. You used the PHP line constant in some places but not all. You had code that was somewhat haphazardly thrown around, where you were setting things long before you need them, and in some cases you may not have needed them, so you were wasting resources setting them.
Please don't take the criticism hard, as I am not trying to offend. Simply pointing out places you could improve the flow of the code and simplify things. The big thing is don't get discouraged, in order to program effectively you have to have a no-quite attitude and the drive for continuous self improvement. Even after 9 years of PHP programing I still learn new things all the time, I learned (and wrote a library around it) something new just 2 days ago...
As I said at the beginning and to be honest a database would actually reduce the amount of code you need. It might be intimidating at first to use a database but you'll find that it's easier then doing this. An example is your check for uniqueness, you can set a field to be unique in the Database then you never need to worry about duplicates, only catching the errors for them.
I would suggest looking into PDO and prepared statements, password_hash and password_verify.
A final word of warning is I didn't test any of this so forgive me if there are any typos...
Hope it helps.

PHP password_verify PDO returns false every time

I have this PHP code. The variable $password has the right password static assigned (no user input to validate).
$data['password'] returns the right hash too, when printing it out with echo.
But somehow the password_verify function doesnt work in this function. When I'm using it manually with the same inputs it workes fine.
Maybe there is something wrong with the PDO query, but I have no idea what.
$this->mysql->query("SELECT * FROM user WHERE username = :username LIMIT 1");
$this->mysql->bind(':username', $username);
$data = $this->mysql->single();
if($this->mysql->rowCount() == 1)
{
echo $data['password'];
if(password_verify($password, $data['password']))
{
echo "yees!";
}else{
$this->user_error = true;
}
}else{
$this->user_error = true;
}
So I figured it out.
There where some whitespaces in the array, but I haven't got any idea where they came from.
So I jused the trim() function to remove these whitespaces and now everything works properly.
Thanks for quick help!

PHP what is the easiest way to create users?

I want to create a very simple website with just 10 users for my school project. I am trying to use simplest code as possible. So I figured it would be best to hard code username/password combinations to a php file.
Like,
$users = array ('Shannon'=>array('password1')
I just want to create 10 variables that contains passwords. So I figured an array would be best option.
Can anybody explain to me how to create a two dimensional array then later on retrieve the array information to authenticate logging in ?
PS I have a good background in C++.
Simple as hell.
$users = array();
$users['Shannon'] = array('Password' => 'Banana');
$users['April'] = array('Password' => 'Qwerty');
$name = 'April'; // Entered in login form name
$password = 'Apple'; // Entered in login form password
if($users[$name]['password'] == $password) {
// login
} else {
// dont login
}
$users = array('user1'=> array('username' => 'Shannon, 'password' => herPassword'),
'user2' => array('username' => 'Shannon, 'password' => herPassword'))
foreach($users as $user) {
if ($user['username'] == 'USERINPUT' AND $user['password'] == 'USERINPUTPASSWORD) {
// log the user in
}
}
This would be the solution, for a PRIVATE website only! Normally you are working with a database, where you store each account in. Then you would escape the user input aswell, to make sure that nobody stores invalid things into your database, and to prevent your database from SQL Injection.
If you want filling details manually you can do something like.
$users=array();
$user['Shannon']="password";
$user['user2']="password2";
and so on
and check for password like
$username=$_POST['username'];
if(isset($user[$username])&&$user[$username]===$_POST['password'])
//Login sucessfull
Note: This is very bad idea for doing registration like this and storing passwords in plain text.

Cannot register the new user if the table is empty

$query = "SELECT username, email
FROM members
WHERE username = :username OR email = :email";
$stmt = $sql->prepare($query);
$stmt->execute(array(
':username' => $_POST['username'],
':email' => $email
));
$existing = $stmt->fetchObject();
if ($existing)
{
if ($existing->username == $_POST['username'])
{
$errors['username'] = "Username already in use !";
}
if ($existing->email == $email)
{
$errors['email'] = "Mail already in use !";
}
}
This is the part of register.php file. Not sure that just this part is responsible for the problem, but I suppose.
So, if table members is empty, and form is submitted - Firefox shows it's busy-gif about a half minute, but ends without registering new user, and without showing any error. Just keep freezing.
Then i press F5 - a window to approve resend information appears - click Resend - and the new user is registered.
If the tablemembersis not empty - everything works normally.
It seems - problem is because the code above is busy to find non-existing data.
If so, how to tell something like - if the table is empty - stop trying - just register the new user.
I'm pretty sure $existing = $stmt->fetchObject(); is fetching you an empty object, but one that does not implicitly evaluate to false. After that there's nothing in your code that would trigger, leading to your blank output.
Try a var_dump($existing) to see what your code is actually operating on.
edit
$existing = $stmt->fetchObject(); //this might be returning an empty object
if ($existing) { //empty objects evaluate to true
if ($existing->username == $_POST['username']) {
$errors['username'] = "Username already in use !";
} else if ($existing->email == $email) {
$errors['email'] = "Mail already in use !";
} else {
//this will trigger if something ELSE is wrong other than what you're explicitly checking for.
$errors['other'] = "Something else is wrong.\n" . var_export($existing, TRUE);
}
}
It should be noted that it is generally a bad idea from a security standpoint to confirm to a would-be attacker that a username or email address exists in your system. This presumably would give them half of the information needed to execute a dictionary attack on your login.
I would make the the username and email fields in your table have unique indexes, and just go straight to the insert. If the insert fails because one of the uniqueness constraints doesn't allow it, just give the user a generic message about not being able to register.
This will also happen to save you a lot of unnecessary queries against the database.
Should $email be $_POST['email']? And what is the full code - you don't have a closing if brace here. In that case, everything after would only execute if $existing is true. So the first time, nothing would be displayed. Also, it's better to use database constraints to ensure no duplicates like MySQL - Meaning of "PRIMARY KEY", "UNIQUE KEY" and "KEY" when used together while creating a table

Categories