PHP fgets returns an empty string - php

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

Related

PHP - Append only if match found in txt-file

complete newbie to php here.
I have a simple application where I register different accesscodes. I've already written a function that checks the txt-file for duplicates, so that only new unique values are appended. This function works fine, see below.
function checkAccesscode($code)
{
$file=fopen ("files/codes.txt", 'r');
while ($string=fgets ($file))
{
if ($string!="")
{
$part=explode (";",$string);
$input=trim($part[0]);
if (stripos($input,$code)!==false)
{
return true;
}
}
else
{
return false;
}
}
}
Now, what I need is a similar, separate function which also checks for matches in a different txt-file (call it "codereg.txt"). Meaning that the code not only has to be unique, but it also has to be pre-registered in a different application/txt-file before it can be appended to its file.
Can anyone point me in the right direction?
Regards,
MadBer
Here's a function that reads the entire files into arrays and searches those with preg_grep().
<?php
define("UNIQ", "uniqueCodes.txt");
define("PREREQ", "preregCodes.txt");
function checkCodes(string $code):bool {
// Quote the search string to deal with regular expression special characters
$code = preg_quote($code,'/');
// Read the unique file. search with preg_grep(), return false if we get back a non-empty array
$uniq = file(UNIQ, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (preg_grep("/^{$code}/i", $uniq)) {
return false;
};
// Read the preregistered file and search with preg_grep(). Cast the result
// to a boolean and return. An empty array casts to FALSE, otherwise TRUE
$preq = file(PREREQ, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
return (bool)(preg_grep("/^{$code}/i", $preq));
}
$checks = ['abc123', 'abc124', 'abc126', 'abc200'];
foreach($checks as $check) {
echo "Checking code $check:".(checkCodes($check)?"pass":"fail")."<br>";
}
Unique Codes:
abc123;first code
abc124;second code
abc125; third code
Preregistered codes:
abc123: a
abc124: b
abc125: c
abc200: d
abc201: e
Results:
Checking code abc123:fail // non-unique code
Checking code abc124:fail // non-unique code
Checking code abc126:fail // unique, not pregistered
Checking code abc200:pass // unique, pre-registered

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.

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

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

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

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