Comparing user input with PHP array - php

For a small project I'm working on I want a user to be able to register an account using a username however I don't want to configure a database i.e I just want to compare the username the user inputs with a PHP array.
<?php
$a=array("user1","user2");
for($a =0; $x<$arrlength; $a++){
if($username == $a){ //i want to say if $username is in array alert this and do nothing
$echo print a new username, already taken;
return false;
else(
array_push($a,username);?>
I'm working with the w3 schools PHP examples and I have something like this (the user inputs a 'username' in a form. I was wondering how you would actually implement this functionality properly.

You could simply use the in_array() function:
<?php
$usernames = array("user1", "user2", "user3", "user4");
if (in_array("username_from_user_input", $usernames)) {
echo "Got Username";
}else{
echo "Username not found"
}
?>

If you want to save the registered accounts across requests, you have to store them in a file or database (or something else..), because the script is run from start on every requests.
Instead of looping over the array, you could also use the in_array function. ( http://php.net/manual/de/function.in-array.php )
To store the usernames, take a look at the file functions. (e.g. http://php.net/manual/en/function.file-put-contents.php to write to a file, and file_get_contents or file(..) to read a file). (For real projects, make sure to lock the file to prevent race conditions.)

Late answer, but because I'm on a ternary mood, here it goes:
echo (in_array("someuser", array("user1","user2"))) ? "Got Username" : "Username not found";

You can use in_array:
if (in_array($username, $a){
...
}

Try the solution of the other users but you could combine with Traits.
You could create a Trait called VerifyUser with the next content:
trait VerifyUser {
public function verifyUser($user){
if (in_array($username, $usersArray)){
echo $username . "is already taken";
}else {
array_push($usersArray, $username);
}
}
}
Don't forget add your custom array to your class if you are working in a OOP environment. Add this trait with the use VerifyUser instruction.
class UsersCollection{
use VerifyUsers
$usersArray= ["user1", "user2"];
$this->verifyUser("user1"); //It echo the custom message you could return a boolean value and then specify a custom behaviour.
}

Related

Creating a PHP Function to Search a .TXT for a Specific Username and Password

So, I am trying to create a login form as an example so there is no encryption or anything too confusing, it has 3 files, a loginform.php, logindisplay.php, and a password.txt. The goal of this question is to tell me why the function below doesn't work and what I can do to fix it.
The function is meant to open up the password.txt file and search for a username and password, which would be on separate lines username over the password, and if the file doesn't have it, it is supposed to tell them to add it using a specific button (which the creation of that data to password.txt already works perfectly in the code) otherwise allow the login to be successful. Any help would be great and please keep in mind I know very little about PHP, so the code may need to be explained a bit depending! Thank you and sorry if this is a bad question!
Also $isLogin is supposed to be a global variable, and is already in the code!
function searchPasswordFile($UserName, $PassWord){
$search = $UserName. "\n" .$PassWord. "\n";
$lines = file('password.txt');
$found = false;
foreach($lines as $line) {
if(strpos($line, $search) !== false) {
$isLogin = true;
echo "Thank you for logging in!";
}
}
if(!$found) {
echo "No login found, please Create a new Login!<br />\n";
}
$islogin = false;
}
You use file() to read your password.txt file but then you want to search for multi-line content. That's will never match because your $lines holds each read line separately. You need to either drop using \n as separator (If your username can't contain say : or | that would be a good candidate) or rework how you read that file.
perhaps it is best to have the user name and password on the same line & separated by a single space (such as password.txt below)
UserName1 PassWord1
UserName2 PassWord2
UserNameN PassWordN
this would simplify comparing the string input with a user name and password
$search = $UserName." ".$PassWord;
to lines of password.txt
So here goes the proposed updated code:
<?php
function searchPasswordFile($UserName, $PassWord){
$search = $UserName." ".$PassWord; # Proposed change here
$lines = file('password.txt');
$found = false;
foreach($lines as $line) {
if(strpos($line, $search) !== false) {
$isLogin = true;
echo "Thank you for logging in!";
}
}
if(!$found) {
echo "No login found, please Create a new Login!<br />\n";
}
$islogin = false;
}
echo searchPasswordFile("UserName2", "PassWord2");
Output:
Thank you for logging in!
'hope this helps.
password.txt
one
two
three
four
five
six
password.php
<?php
// set $isLogin to the return value from searchPasswordFile
$isLogin = searchPasswordFile('three','four');
function searchPasswordFile($UserName, $PassWord){
// read password.txt into $lines as an array
$lines = file('password.txt',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
// get the number of lines in the array
$lineCount = count($lines);
// loop through the array, advancing the index by two each time
for ($i = 0; $i < $lineCount; $i += 2) {
// if there is a match
if($lines[$i] === $UserName && $lines[$i+1] === $PassWord) {
// report success and return
echo "Thank you for logging in!".PHP_EOL;
return true;
}
}
// report failure and return
echo "No login found, please Create a new Login!".PHP_EOL;
return false;
}
When you read the file with file you are getting an array where each element is a separate line. You are searching for two lines, but only across a line at a time.
There are many different(and better) ways to do this, but here is an option based on your existing approach.
$lineCount=count($lines);
for($l=0;$l<$lineCount;$l+=2){
if(rtrim($lines[$l])==$UserName&&rtrim($lines[$l+1])==$PassWord){
//Credentials matched
}
}
Ultimately, there are many issues here. First, never store plaintext passwords. Look into hashing. PHP has built-in functions to help with this. Second, when comparing passwords, you must be mindful of various vulnerabilities(for instance, timing attacks, which are not mitigated in my example). Your original example(had it worked) would also have allowed authenticating using one user's password as the username and the next user's username as the password. There are plenty of standard file formats with built-in support in PHP that would be easier and safer to parse(JSON or XML for instance are supported in core PHP). You should really reconsider this approach if you are building anything remotely serious. Authentication is not a place to take shortcuts.

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;
}

Always get an empty array in foreach loop

There are two columns in the database table "system". I have the systemId and want to get the mobileSystemId. But the variable $mobileSystemIds which I already defined as global is always empty.
EDIT: Now array_map doesn´t work. I always get my Exception output "Arrayfehler ArrayMap"
I have the following code :
$mobileSystemIds=array();
function getMobileSystemId($systemId)
{
global $mysqli;
global $mobileSystemIds;
$query="SELECT mobileSystemId FROM system WHERE systemId ='" .$systemId ."'";
if(!$result=$mysqli->query($query))
{
echo "Datenbankfehler DB-QUery";
exit(0);
}
if (!$mobileSystemId=$result->fetch_assoc())
{
echo "Datenbankfehler DB-Fetch";
exit(0);
}
$mobileSystemId=$mobileSystemId["mobileSystemId"];
echo "mobile System ID: " .$mobileSystemId ."<br />";
return $mobileSystemId;
}
if(!$mobileSystemIds=array_map("getMobileSystemId",$systemList))
{
echo "Arrayfehler ArrayMap";
}
In this case, using a return in your function would be much cleaner.
Nothing to do with your problem, but is your $systemId var trusted ? (To prevent SQL injection).
Update:
if(!$mobileSystemIds=array_map("getMobileSystemId",$systemList))
{
echo "Arrayfehler ArrayMap";
}
ought to read (just checked; it works for me):
$mobileSystemIds = array_map('getMobileSystemId', $systemsList);
if (empty($mobileSystemIds))
{
if (empty($systemsList) || !(is_array($systemsList)))
echo "OK: no mobile IDs, but no systems either";
else
echo "THIS now is strange :-(";
}
else
{
echo "Alles OK";
var_dump($mobileSystemIds);
}
I tried this by returning a dummy value based on input; if it does not work for you, there must be something strange in the database.
(Update: the text below refers to your original code, which did not use array mapping)
Your code ought to be working as it is. You put several $mobileSystemId 's into a single $mobileSystemId.
It works: I tested with a simpler code, removing the DB calls but leaving your code, and spelling, untouched.
So, the error must be elsewhere. I would guess that this code is included into something else, and:
the $mobileSystemIds = array(); declaration gets executed more than once, thereby losing all its data;
the $mobileSystemIds = array(); declaration is itself included in a more local scope and you read it from outside, reading an empty value or a totally different value.
Try replacing the first part of your code with:
GLOBAL $mobileSystemsIds;
if (defined($mobileSystemsIds))
trigger_error("mobileSystemsId defined more than once", E_USER_ERROR);
else
$mobileSystemsIds = array();
and also, in the function body:
if (!defined($mobileSystemsId))
trigger_error("mobileSystemsId should have been defined", E_USER_ERROR);

class design - validating user input

I use the clas below to validate user input. Originally it was just a collection of static functions grouped together.
However, I modifed it to an object style and added in a private memeber to hold the user input array. What is the next step to making this class adaptable, i.e. more generic so that it can be used by others as part of a library?
$message is the text displayed to the user on a validation fail.
Library Code:
class validate
{
private $input;
function __construct($input_arg)
{
$this->input=$input_arg;
}
function empty_user($message)
{
if((int)!in_array('',$this->input,TRUE)) return 1;
echo $message;return 0;
}
function name($message)
{
if(preg_match('/^[a-zA-Z-\.]{1,40}$/',$this->input['name'])) return 1;
echo $message;return 0;
}
function email($message)
{
if(preg_match('/^[a-zA-Z0-9._s-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,4}$/',$this->input['email'])) return 1;
echo $message;return 0;
}
function pass($message)
{
if(preg_match('/^[a-zA-Z0-9!##$%^&*]{6,20}$/',$this->input['pass'])) return 1;
echo $message;return 0;
}
}
Application Code:
function __construct()
{
parent::__construct();
$obj=check_new($this->_protected_arr);
$a='<si_f>Please enter both an email and a password!';
$b='<si_f>Please enter a valid email!';
$c='<si_f>Please enter a valid password!';
if($obj->empty_user($a) && $obj->email($b) && $obj->pass($c) && self::validate())
{
self::activate_session();
echo "<si_p>";
}
}
I'd not write all these function in a generic class. I'd rather have separate functions that perform specific checks, and maybe a specific class that calls these checks on my specific input.
This class now echo's, which is never a good solution for a class like this. Just let it perform the check and raise an exception if something's wrong. If exceptions are too hard, or don't fit in your achitecture, let your function return false, and set a property that can be read afterwards.
About your specific checks:
Your e-mail check is very strict and doesn't allow all e-mail addresses. The domain, for instance, can be an IP address too, and the username (the part before the #) can include many obscure characters, including an #. Yes, really!
Why must a password be 6 characters at least? And why on earth would you limit the password to 20 characters? I use passwords of over 20 characters, and I know many other people that do too. Just let everybody type everything they want. Anything. Let them post 3MB of text if they like. Let them include unicode characters if they want. What is a better protection that having a bunch of chinese characters as a password? And if they want to enter just a, that's their responsibility too.
You should never ever store the password itself anyway, so just hash whatever they input and store the 32 characters that gives you (if you use MD5 hashing). The only password that you may refuse is an empty password. Anything else should go.
Same goes for name. 40 characters? Really. I can imagine people having names that long. Add a little more space. Bytes aren't that expensive, and it's not that you're gonna have 2 billion users.
Maybe it's worth having a look at Zend Validate? Or any other PHP frameworks validate classes. Just then extend them to add the functionality you want.
In answer to your question, is it worth having another variable in the class so you can check the error?
class validate
{
private $input;
public $error = false;
function __construct($input_arg)
{
$this->input=$input_arg;
}
function empty_user($message)
{
if((int)!in_array('',$this->input,TRUE)) return 1;
echo $message;$this->error = "Empty message";
}
... else
}
$validate = new validate($empty_message);
if( !$validate->empty_user('this input is empty') === false)
{
echo "Was not empty";
}

validating a string in php if only substring is true

How to validate a substring is true in PHP for example if user1 is in the string it should be true?
textfile:
user1 : pass1
user2 : pass2
user3 : pass3
if(in_array($_SERVER['user1'] . "\r\n", $textfile)){ //not the way want this to be true
printf("Ok user1 is in this row somewhere");
}
I would advice against this kind of authentication system as is prone to errors or abuse. Use other system like ACL or database user/password hash check.
As those above have said, this is not a good approach as far as user authentication goes. If you want something basic, look at using HTTP Authentication or something at least.
That said, you can do what you have asked using PHP's file function, e.g.
function validUser($file, $user, $pass) {
// Check file exists
if (!is_file($file)) {
return FALSE;
}
// Read file
$lines = file($file);
if ($lines === FALSE) {
return FALSE;
}
// Go over the lines and check each one
foreach ($lines as $line) {
list($fuser, $fpass) = explode(':', trim($line));
if ($user == $fuser && $pass == $fpass) {
return TRUE;
}
}
// No user found
return FALSE;
}
if (validUser('passwords.txt', 'foo', 'bar')) {
echo 'The user was found';
}
Note that this assumes each line is of the form "username:password" with nothing else; you may need to adjust exactly how you match your lines depending on your format. An example file which would be validated by this would have a line such as
foo:bar
If you are using this for authentication; for the sake of your users consider a different (more secure) approach. By the way the reply to the OP is correct that just about nothing in that PHP code would work as appears to be intended.
However, if the idea is to use the value of an array by key $arr['key'] to look up configuration settings that need not be protected (for the world to see, basically) you can use the parse_ini_file() and friends. Again: this is not a good idea for truly sensitive data.
EDIT: Also, it is probably a good idea to use the PHP_EOL constant for end-of-line characters rather than assuming "\r\n".

Categories