validating a string in php if only substring is true - php

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".

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

Comparing user input with PHP array

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

if statement is not working when looping through file

I am trying to loop through a file of blocked IP address.
I seem to be unable to do this even when they should match.
Here is the code that checks.
$blocked_ips = file("/home/block_list.txt");
for ( $i = 0; $i < count($blocked_ips); $i++) {
if ( $_SERVER["REMOTE_ADDR"] == $blocked_ips[$i] ) {
exit;
}
}
And here is the code I use to add the ip address to the file.
if ( $_SESSION["LogInAttempts"] >= "10" ) {
$block_ip = $_SERVER["REMOTE_ADDR"];
$block_ip = $block_ip . "\r\n";
file_put_contents("/home/block_list.txt", $block_ip, FILE_APPEND);
}
And here is a list of ip addresses in the file. (example only)
169.254.51.183
192.168.0.1
192.168.10.84
I'm not to sure what I am doing wrong.
Make sure to account for whitespace when reading from files or receiving user input. trim() is your friend for such cases, though, as Jack noted in the comments, using FILE_IGNORE_NEW_LINES in file() will solve that for you. As the documentation says:
FILE_IGNORE_NEW_LINES
   Do not add newline at the end of each array element
Furthermore, you might find foreach a little more comfortable than your for loop, but that's a question of personal taste, ultimately. Here's a variant with the additional parameter in file() and with foreach:
$blocked_ips = file("/home/block_list.txt", FILE_IGNORE_NEW_LINES);
foreach($blocked_ips as $ip) {
if ($_SERVER["REMOTE_ADDR"] == $ip) {
exit;
}
}
Note also that you shouldn't have quotes around that 10 in your code below, though with PHP's type juggling feature your code will work, of course. However, it's always a good idea to be as precise as possible. If for nothing else, for clarity: it will make the intention of your code easier to understand – also for you when you'll be looking at your code after a long time.
You can also append a string to REMOTE_ADDR without a problem (again, a question of personal taste). Finally, note that getting the IP address of a user is not as straightforward as simply calling $_SERVER['REMOTE_ADDR'] if we want to be very correct, but for most purposes it will suffice. Nevertheless, there's a very interesting discussion about getting the IP address of a user in PHP on StackOverflow I recommend everyone to read.
if ($_SESSION["LogInAttempts"] >= 10) {
$block_ip = $_SERVER["REMOTE_ADDR"] . "\r\n";
file_put_contents("/home/block_list.txt", $block_ip, FILE_APPEND);
}
You don't need a loop at all. You can do that with in_array().
<?php
// Read in blocked ips list.
$blockedIps = file('/home/block_list.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// Check if ip is blocked.
if(in_array($_SERVER['REMOTE_ADDR'], $blockedIps)) {
exit;
}

php foreach in foreach looping

I want to extrect all usernames and passwords each from his file and output it nicely.
I wrote a code on my appserv 2.5.1 on my computer but only the last loop gave the username output.
Tested the code on other machines and it worked perfectly.
Dont know what is the problem ...
usernames.txt content :
user1
user2
user3
passwords.txt content :
pass1
pass2
pass3
script content :
$usernames = explode("\n", file_get_contents("usernames.txt"));
$passwords = explode("\n", file_get_contents("passwords.txt"));
foreach( $usernames as $username )
{
foreach( $passwords as $password )
{
echo $username.":".$password."\n";
}
}
output :
:pass1
:pass2
:pass3
:pass1
:pass2
:pass3
user3:pass1
user3:pass2
user3:pass3
for ($i=0;$i<count($usernames) && $i<count($password); $i++) {
echo $usernames[$i].':'.$passwords[$i];
}
But $password[x] must be related to $usernames[x]
There's always those that will say you don't need it (and you often don't) but I tend to use regular expressions whenever I'm parsing these kind of flat files - there's always some quirky character, extra line-break or difference that finds it's way into a text file - be it from transferring servers, restoring backups or simply user-interference. You could also make use of array_combine in this situation if you'd prefer to carrying on using a foreach loop - I know some folks prefer it for readability.
preg_match_all('/\w+/m', file_get_contents('usernames.txt'), $usernames);
preg_match_all('/\w+/m', file_get_contents('passwords.txt'), $passwords);
if(count($usernames[0]) !== count($passwords[0]))
die('Computer says: mismatch!'); // some resemblance of error handling...
$result = array_combine($usernames[0], $passwords[0]);
foreach($result as $name => $pass)
echo "{$name}:{$pass}\n";
demo
After debugging with the post author, I guessed that the problem was with the line return character. Using a \r\n fixed the problem:
$usernames = explode("\n\r", file_get_contents("usernames.txt"));
$passwords = explode("\n\r", file_get_contents("passwords.txt"));
For reference, please note that it is very important not to assume your input data is right. If you see that something is wrong and it points obviously to a mistake you made previously (in that case it is clearly not the foreach function that is buggy, but the array), then you need to swallow your pride and debug your own code. I have been programming PHP for 10 years, and I still have to remember that every single day.

Categories