Checking Users HTML form input with PHP - php

I am creating a web application that takes in a user input (Scientific Paper DOI) and queries a database to display a graph. I've been trying to limit the connections made to the database since its on a remote server (private DMZ with web server) by checking the user input if it matches a correct DOI.. if it doesn't then no connection to the database will be made, I hope this will help speed up the application if there are many users at once making queries.
Pseudo: All paper DOIs start with "10.1103/" because they are all physics papers. This part I have implemented correctly using substr. Next I want to check every character in the input to make sure it only consists of only these characters:
Letter
Number
"/"
"."
Example DOIs:
10.1103/RevModPhys.9.1
10.1103/RevModPhys.76.1015
10.1103/PhysRevLett.95.208304
Here is my code:
function checkDOI($doi) {
if (substr($doi, 0, 8) != "10.1103/") {
echo "Invalid DOI";
return false;
}
for ($n = 0; $n < strlen($doi)+1; $n++) {
if ( !ctype_alnum($doi[n]) && $doi[n] != "." && $doi[n] != "/") {
echo "Invalid DOI";
return false;
}
}
echo "Valid DOI";
return true;
}
if(isset($_POST['submit'])) {
$doi_input = $_POST['doi_input'];
checkDOI($doi_input);
}
I am working with PHP and javascript for the very first time, the pseudo is fairly simple but for some reason, there is something wrong with the 2nd if statement. Not sure if I can really do that. The Echos are just for tests.
Do you think doing this check for every input will slow down the application significantly? Is it worth it to limit the amount of connections to mysql?
The bottom of the code will be modified once I have this working to only query the database if checked returns true.
Thanks for the help!

to check every character in the input to make sure it only consists of only these characters
I suggest you to use preg_match.Try this:
$value="10.1103/RevModPhys.9.1";
if(preg_match("/^[a-zA-Z0-9\/.]+$/", $value)){
echo "match found";
}else{
echo "no match found";
}
Check here: Demo
For more info: preg_match

Your error is $doi[n], it is not an array and should it be the index is invalid.
So use a function like
$chars_doi = str_split($doi);
Before the loop to get an array of characters then use in your loop
$chars_doi[$n]
So you should have something like:
$chars_doi = str_split($doi);
$size = sizeof($chars_doi) - 1;
for ($n = 0; $n < $size; $n++) {
if (!ctype_alnum($chars_doi[$n]) && $chars_doi[$n] != "." && $chars_doi[$n] != "/") {
echo "Invalid DOI";
return false;
}
}
Little tip, avoid use functions such as strlen / sizeof as a loop argument or it will get called at each iteration. It is better for performance to store the value in a variable beforehand.

I would just do:
if (! preg_match ('#^10\.1103/[\p{L}\p{N}.-_]+$#', $doi)) {
... // bad
return;
}
// good
Reference:
http://www.php.net/manual/en/reference.pcre.pattern.syntax.php
http://php.net/manual/en/regexp.reference.unicode.php

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.

Return true/false if word in URL matches specific word

I currently use:
if(strpos($command->href,§current_view) !== false){
echo '<pre>true</pre>';
} else {
echo '<pre>false</pre>';
}
$command->href will output something like this: /path/index.php?option=com_component&view=orders Whereas
§current_view is outputting orders. These outputs are dynamically generated, but the scheme will always be the same.
What I need to do is return true/false if the words from $current_view match the view=orders in the URLs from $command->href. The issue with my code is, that it doesnt match anything.
What is the correct way to do this?
Please note that the $command->href and the whole code is inside a while function, that pass multiple URLs and this only needs to match the same ones.
Breaking it down to a simple example, using your code and variable values.
$current_view = 'orders';
$command = '/path/index.php?option=com_component&view=orders';
if(strpos($command,$current_view) !== false){
echo '<pre>true</pre>';
}
else {
echo '<pre>false</pre>';
}
The oputput is "true".
Now, go and debug the REAL values of $command->href and $current_view...
I'm pretty confident that the values are not what you think they are.
Does something like:
if(substr($command->href, strrpos($command->href, '&') + 6) == $current_view)
accomplish what you are after?
To explain, strpos get the last instance of a character in a string (& for you, since you said it always follows the scheme). Then we move over 6 characters to take "&view=" out of the string.
You should now be left with "orders" == "orders".
Or do you sometimes include some arguments after the view?
Try parsing url, extracting your view query string value and compare it to $current_view
$query= [];
parse_str(parse_url($command->href)['query'], $query);
if($current_view === $query["view"])
echo '<pre>true</pre>';
} else {
echo '<pre>false</pre>';
}

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

check preg_match results against other values?

I need some help with my PHP script.
So, here is the deal.
I have a preg_match which checks for the following text in a .txt file that changes every 30minutes or so: LYBE_TWR,LYBE_APP,LYBA_CTR,LYPG_TWR,LYPG_APP,LYTV_TWR,LYNI_APP)
It runs perfectly and gets the above strings if they are present.
But I need to do even further and check which of the seven combinations have been found because not all are present at all times.
Example:
The current text file contains LYBE_TWR, LYBE_APP, LYPG_TWR. The preg_match does its thing and I can echo the 3 values but I need this.
LYBE_TWR : PRESENT/NOT PRESENT
LYBE_APP: PRESENT/NOT PRESENT
LYBA_CTR PRESENT/NOT PRESENT
LYPG_TWR PRESENT/NOT RESENT
etc.
So if it is found in the text file it echos present, if not it echoes not present.
The correct results would be:
LYBE_TWR : PRESENT
LYBE_APP: PRESENT
LYBA_CTR NOT PRESENT
LYPG_TWR PRESENT
If I do for example if ($string == "LYBE_TWR") { echo 'present'; } else { echo 'not present'} it will echo the correct value for the LYBE_TWR but it will say not present for the later as they are not actually the one I if-ed for.
I hope you understand as I myself am not sure anymore (rofl)
edit: here is the current code..bare in mind it is still WIP so not finished and there will be some errors http://pastebin.com/z1r4A78E
Thanks.
This is the code working on the assumption that you're interested if the string appeared in your file, not in the line. I split the strings into prefixes and suffixes, and I'm ignoring any numerical values. I didn't copy all your code, for readability's sake
$prefixes = array("LYBA", "LYBE", "LYPG", "LYNI", "LYTV");
$suffixes = array("TWR", "APP", "CTR");
foreach($prefixes as $prefix)
{
foreach($suffixes as $suffix)
{
$results[$prefix."_".$suffix] = 0;
}
}
if(preg_match('/^('.implode("|",$prefixes).'|)_[A-Z0-9]*_*('.implode("|",$suffixes).')/', $line, $matches))
{
(... your code ...)
$match_string = $matches[1]."_".$matches[2];
$results[$match_string]++;
}
foreach($results as $key => $value)
{
echo $key;
if($value > 0)
{
echo " PRESENT";
}
else
{
echo " NOT PRESENT";
}
echo "<br/>";
}

How to map (large) integer on (small in size( alphanumeric string with PHP? (Cantor?)

I can't figure out how to optimally do the following in PHP:
In a database, I have messages with a unique ID, like 19041985. Now, I want to refer to these messages in a short-url service but not using generated hashes but by simply 'calculate' the original ID.
In other words, for example: http://short.url/sYsn7 should let me calculate the message ID the visitor would like to request.
To make it more obvious, I wrote the following in PHP to generate these 'alphanumeric ID versions' and of course, the other way around will let me calculate the original message ID.
The question is: Is this the optimal way of doing this? I hardly think so, but can't think of anything else.
$alphanumString = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_';
for($i=0;$i < strlen($alphanumString);$i++)
{
$alphanumArray[$i] = substr($alphanumString,$i,1);
}
$id = 19041985;
$out = '';
for($i=0;$i < strlen($id);$i++) {
if(isset($alphanumString["".substr($id,$i,2).""]) && strlen($alphanumString["".substr($id,$i,2).""]) > 0) {
$out.=$alphanumString["".substr($id,$i,2).""];
} else {
$out.=$alphanumString["".substr($id,$i,1).""];
$out.=$alphanumString["".substr($id,($i+1),1).""];
}
$i++;
}
print $out;
echo trim(base64_encode(pack("L", 19041987)), "=");
print_r(unpack("L", base64_decode("w44iAQ")));
Pack changes the number into four bytes, which is very short but unreadable.
Base64_encode changes the four bytes into some more human-readable characters.
It appends some = characters, which are not needed.
If you do base64_encode(19041987), you get the encoding for the string "19041987", which is not shorter.
You should never use a function inside a for statement since it's played during every loop.
For instance your
for($i=0;$i < strlen($alphanumString);$i++)
{
$alphanumArray[$i] = substr($alphanumString,$i,1);
}
should be
var $alphaLength = strlen($alphanumString);
for($i=0;$i < $alphaLength;$i++)
{
$alphanumArray[$i] = substr($alphanumString,$i,1);
}

Categories