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
Related
I'm using the following code to return true or false if a string contains a substring in PHP 8.0.
<?php
$username = "mothertrucker"; // This username should NOT be allowed
$banlistFile = file_get_contents("banlist.txt"); //Contains the word "trucker" in it
$banlist = explode("\n", $banlistFile); // Splits $banlistFile into an array, split by line
if (contains($username, $banlist)) {
echo "Username is not allowed!";
} else {
echo "Username is allowed";
}
function contains($str, array $arr)
{
foreach($arr as $a) { // For each word in the banlist
if (stripos($str, $a) !== false) { // If I change $a to 'trucker', it works. "trucker" does not
return true;
}
}
return false;
}
?>
This is to detect if an inappropriate word is used when creating a username. So for example, if someone enters the username "mothertrucker", and "trucker" is included in the ban list, I want it to deny it.
Right now with this code, If I just type in the word "trucker" as a username, it is found and blocks it. Cool. However if there's more to the string than just "trucker", it doesn't detect it. So the username "mothertrucker" is allowed.
I discovered that if I explicitly type in 'trucker' instead of $a in the stripos function, it works perfectly. However, if I explicitly type in "trucker" (with double quotes), it stop working, and only blocks if that's the only thing the user entered.
So what I'm seeing, is it looks like the string $a that I'm passing it is being interpreted by PHP as a double quoted string, when in order for this to detect it properly, it needs to be a single quoted string. But as far as I can tell, I have no control over how php passes passing the variable.
Can I somehow convert it to a single quoted string? Perhaps the explode command I'm using in line 2 is causing it? Is there another way I can pull the data from a txt document and have it be interpreted as a single quote string? Hopefully I'm made sense with my explanation, but you can copy and paste the code and see it for yourself
Thanks for any help!
One potential problem would be any whitespace (which includes things like \r) could stop the word matching, so just trimming the word to compare with can tidy that up...
stripos($str, $a)
to
stripos($str, trim($a))
I do not know what your file actually contains so i dont know what the result of explode is.
Anyways my suggestion is (depending on the speed you want to perform this and also the length of the banlist file also your level of banning) to not explode the file and just look into it as a whole.
<?php
$username = "allow"; // This username should be allowed
$banlist = "trucker\nmotherfucker\n donot\ngoodword";
var_dump(contains($username, $banlist));
function contains($str, $arr)
{
if (stripos($arr, $str) !== false) return true;
else return false;
}
?>
Otherwise if you are going to allow say good which is an allowed word but since it is in the file with goodword it will not (using my example), you should not use stripos but instead use your example and use strcasecmp
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;
}
I have a piece of Javascript code that generates a dynamic XML string. This XML string is then passed to a PHP file where I need to check to make sure the string doesn't contain any bad words that could allow for SQL injection.
I figured I would just create a blacklist and if any word was found, we just don't send the XML to the database.
My snippet of code however isn't returning true when I pass in one or more of the blacklist words.
// Create a blacklist array
$blacklist = Array('create', 'alter', 'update', 'delete', 'drop', 'insert', 'into', 'from', 'where');
// Define our vars
$xml = '<blah>alert table drop something create</blah>';
$actor = $_COOKIE['QID'];
$sp = $_POST['sp'];
// Lets check the XML string to see if it contains any database altering words
function contains($str, array $arr)
{
foreach($arr as $a) {
if (stripos($a,$str) !== false) return true;
}
return false;
}
// Check our XML string
if(contains($xml, $blacklist))
{
echo 'Contains';
}
else
{
echo 'Does not contain';
}
Is there a better way to handle this type of check? I wasn't sure what to search for so figured the blacklist of words would be sufficient.
You have the parameters in the wrong order when calling stripos. Instead of stripos($a,$str), you want stripos($str,$a). The first version is search for the entire XML string within an individual "bad" word. The second searches for the word within the XML string.
recently im trying to work with JSON data via php for my higher education project. But I hanged-up while managing/updating this into the JSON file.
Let me introduce you the whole scenario:
Its a entry based project, where all entries must be save in the JSON file (.json), format is :
[{"Name":"xyz","UID":"1234","RDate":"11122014","ReLogin":"true","LTime":"1e3","Passive":"false"},{"Name":"abc","UID":"5678","RDate":"01102014","ReLogin":"true","LTime":"1e3","Passive":"false"},......]
Now, what I have to do is that: when a new entry sended to the PHP, than firstly find the match entry based on some paremater, like name, uid, rdate.
IF MATCH FOUND, than replace/update the whole entry into the file,
IF MATCH NOT FOUND, than add/write the new entry into the file.
To do this, currently I'm trying to use these bunch of codes:
1) `function chkEntry($uid,$entry)
$file='file.json';
$s[]=$entry;$match=0;
global $RESP;
if(0==filesize($file)){
return true;
}else{
$data=json_decode(file_get_contents($file),true);
foreach($data as $keyD=>$valD){
foreach($s as $keyS=>$valS){
if($valD["Name"]!=$valS["Name"]||$valD["UID"]!=$valS["UID"]||$valD["RDate"]!=$valS["RDate"]){ // here `RDate` is always unique, so I can use it for the matching process
$match=0;
}else{
$match=1;
}
}
}
if($match==1){return false;}else{return true;}
}
This chkEntry always return false :(
And also I don't know that how to replace the while entry int the file, if match found.
UPDATED chkEntry function: matching criteria is limited to a single parameter only [uid]. If match found, than delete the whole entry and return true to the addEntry function, so that addEntry add the new entry.But unfortunately this function is also not working as expected.
function chkEntry($uid,$entry){
$file='file.json';
$data=json_decode(file_get_contents($file),true);
foreach($data as $keyD=>$valD){
if($valD["uid"]==$entry["uid"]){
unset($data[$keyD]); //delete the entry, if matched
file_put_contents($file,json_encode($data));
return true;
}
}
return true;
}
2) `function addEntry($uid,$entry)
global $RESP;
$ready=false;
$file='file.json';
if(addFile($uid)){ //`function addFile`, if file not exists, than create an blank file
$data=json_decode('file.json',true);
unset($file);
if(chkEntry($uid,$entry)){ //`function chkEntry`, match the entry
$data[]=$entry;
file_put_contents('file.json',json_encode($data));
unset($data);
}else{
$RESP["entry"]="This entry is already exists into Database";
}
$ready=true;
}else{
$RESP["err"]="We are unable to add the entry right now. Please try after some time!";
}
if($ready){
if(!isset($RESP["entry"])){$RESP["entry"]="for evaluatuion";}
return true;
}else{
$RESP["err"]="Something went wrong! Please try to add this later.";
return false;
}
3)
$entry=array("Name"=>$_POST["name"],"UID"=>$_POST["uid"],"RDate"=>$_POST["rdate"],"ReLogin"=>$_POST["relogin"],"LTime"=>$_POST["ltime"],"Passive"=>$_POST["passive"]);
addServer($uid,$entry);
So, my question is :
How the finding/matching function should be managed, so that its return true if match found otherwise return false and IF MATCH FOUND, than how to replace/update the whole entry into the file.
for example: if the new entry is
{"Name":"try","UID":"1111","RDate":"12122014","ReLogin":"`true","LTime":"1e3","Passive":"false"}
than first match it to the existing entries and than ad it to the file.
IF the new entry is : (based on name, uid, rdate)
{"Name":"xyz","UID":"2222","RDate":"15122014","ReLogin":"true","LTime":"1e3","Passive":"false"} //match found, based on `name`
OR
{"Name":"nws","UID":"1234","RDate":"19122014","ReLogin":"true","LTime":"1e3","Passive":"false"} //match found, based on `uid`
OR
{"Name":"nws","UID":"2222","RDate":"11122014","ReLogin":"true","LTime":"1e3","Passive":"false"} //match found, based on `rdate`
than update/replace the old entry {"Name":"xyz","UID":"1234","RDate":"11122014","ReLogin":"true","LTime":"1e3","Passive":"false"} with it.
help me plz.....
Thanks & Regards
Here's how I would go about doing it (minus the error messages) simplifying everything down to one function.
define('JSON_FILE', 'file.json');
function addEntry($newEntry)
{
// flag to indicate whether an update was made or not;
// flag is by default set to false to assume no update was made
$update = false;
// retrieve list of current entries
if (file_exists(JSON_FILE)) {
$entries = json_decode(file_get_contents(JSON_FILE), true);
}
// if there are entries, look for a match
if (!empty($entries)) {
foreach ($entries as $i => $entry) {
// if match IS found...
if ($entry["Name"] == $newEntry["Name"] ||
$entry["UID"] == $newEntry["UID"] ||
$entry["RDate"] == $newEntry["RDate"]){
// update/replace existing entry with new entry
$entries[$i] = $newEntry;
// turn on flag to indicate that an update was made
$update = true;
// no need to keep searching any further, so quit loop
break;
}
}
// otherwise if there no entries, create an empty list
} else {
$entries = array();
}
// if no update was made i.e. no match was found, then it means a new entry needs to be added
if (!$update) {
// add new entry
$entries[] = $newEntry;
}
// save list of entries
file_put_contents(JSON_FILE, json_encode($entries));
}
$entry = array(
"Name" => $_POST["name"],
"UID" => $_POST["uid"],
"RDate" => $_POST["rdate"],
"ReLogin" => $_POST["relogin"],
"LTime" => $_POST["ltime"],
"Passive" => $_POST["passive"]
);
addEntry($entry);
chkEntry is probably failing because json_decode() errors out. Json_decode returns null on error, and in php $x = null; $x[1] === NULL is always true; all subscripted values on a null $x will be null and thus equal to each other.
Basically the problem I am having is I need to write this function that can take a URL like www.stackoverflow.com and just return the "com". But I need to be able to return the same value even if the URL has a period at the end like "www.stackoverflow.com."
This is what I have so far. The if statement is my attempt to return the point in the array before the period but I dont think I am using the if statement correctly. Otherwise the rest of the code does exactly what is supposed to do.
<?php
function getTLD($domain)
{
$domainArray = explode("." , $domain);
$topDomain = end($domainArray);
if ($topDomain == " ")
$changedDomain = prev(end($domainArray));
return $changedDomain;
return $topDomain;
}
?>
Don't use a regex for simple cases like that, it is cpu costly and unreadable. Just remove the final dot if it exists:
function getTLD($domain) {
$domain = rtrim($domain, '.');
return end(explode('.', $domain));
}
The end function is returning an empty string "" (without any spaces). You are comparing $topDomain to single space character so the if is not evaluating to true.
Also prev function requires array input and end($domainArray) is returning a string, so, $changedDomain = prev(end($domainArray)) should throw an E_WARNING.
Since end updates the internal pointer of the array $domainArray, which is already updated when you called $topDomain = end($domainArray), you do not need to call end on $domainArray inside the if block.
Try:
if ($topDomain == "") {
$changedDomain = prev($domainArray);
return $changedDomain; // Will output com
}
Here is the phpfiddle for it.
Use regular expressions for something like this. Try this:
function getTLD($domain) {
return preg_replace("/.*\.([a-z]+)\.?$/i", "$1", $domain );
}
A live example: http://codepad.org/km0vCkLz
Read more about regular expressions and about how to use them: http://www.regular-expressions.info/