Although the item is successfully added to the database, I'm not sure that I'm executing the mysql_real_escape_string() function correctly and, thus, getting the error. Any help is appreciated.
Success!
Warning: array_map() [function.array-map]: Argument #2 should be an array in /home/site4/public_html/lab/mailing_list_dev_1-0/mailing_list_add.php on line 32
Thanks for signing up!
Here's the code in question...
<?php
// connects the database access information this file
include("mailing_list_include.php");
// the following code relates to mailing list signups only
if (($_POST) && ($_POST["action"] == "sub")) {
if ($_POST["email"] == "") {
header("Location: mailing_list_add.php");
exit;
} else {
// connect to database
doDB();
// filtering out anything that isn't an email address
if ( filter_var(($_POST["email"]), FILTER_VALIDATE_EMAIL) == TRUE) {
echo 'Success!';
} else {
echo 'Invalid Email Address';
exit;
}
// check that the email is in the database
emailChecker($_POST["email"]);
// get number of results and do action
if (mysqli_num_rows($check_res) < 1) {
// free result
mysqli_free_result($check_res);
// cleans all input variables at once
$email = array_map("mysqli_real_escape_string", ($_POST["email"]));
// add record
$add_sql = "INSERT INTO subscribers (email)
VALUES('".$_POST["email"]."')";
$add_res = mysqli_query($mysqli, $add_sql)
or die(mysqli_error($mysqli));
$display_block = "<p>Thanks for signing up!</p>";
// close connection to mysql
mysqli_close($mysqli);
} else {
// print failure message
$display_block = "You're email address, ".$_POST["email"].", is already subscribed.";
}
}
}
?>
<html>
<?php echo "$display_block";?>
</html>
You're treating $_POST['email'] as an array, which it probably ins't.
If you only intended to escape email, do
$email = mysqli_real_escape_string($dbConn, $_POST['email']);
Then in your INSERT statement, use the escaped $email instead of $_POST['email']
$add_sql = "INSERT INTO subscribers (email) VALUES('$email')";
array_map() is meant for arrays. If all you have is a single value then just call the function directly.
There is at least one bug, here:
// Does not work because $_POST["email"] is a string, not an array
$email = array_map("mysqli_real_escape_string", ($_POST["email"]));
This looks like something you adapted from code that was working, but right now it's broken. You probably wanted something like this:
$post = array_map("mysqli_real_escape_string", $_POST["email"]);
after which you can use $post["email"] safely, as it has been escaped.
Of course escaping everything inside $_POST is possibly not the best way to go about this. There's still the mundane but spot-on way to consider:
$email = mysqli_real_escape_string($_POST['email']);
This is apparently not mysqli_real_escape_string problem but array_map() problem. Or rather misuse of the latter one.
However, you will face mysqli_real_escape_string() problem as soon as you solves this one.
To solve this latter your doDB() function have to return connection id, which you have to use with every mysqli_* function.
$conn = doDB();
$email = mysqli_real_escape_string($conn,$_POST["email"]);
thus you will have all your [listed] problems solved but I believe that emailChecker will may cause the same kind of problem of inexistent $check_res variable. Instea d of which such a function apparently have to return just a boolean and used like
if (!emailChecker($_POST["email"])) {
Related
I have a problem with either registration and login shows (undefined offset) and look at registration is there some problem with my code?it is the registration form the problem it sometimes saves the existing email in spite of the fact that I wrote a function for not submitting the existing email which is inside my data.txt. shortly the functions do not work properly
<?php
if(isset($_POST['submit_reg'])){
$var=file("data.txt");
$userData = $_POST['email'] . " " . $_POST['password'] . "\r\n";
$lines=0;
$db = fopen("data.txt", "a+");
foreach($var as $key=>$value){
$user = (explode(' ', $value));
if ($_POST["password"] === $_POST["confirm_password"]) {
//print_r($value);
if (trim($user[0]) == $_POST['email']) {
$lines++;
}
break;
}
}
if($lines){
echo "The email is already exists ";
}else{
fwrite($db,$userData."\r\n");
fclose($db);
echo "you are registered successfully ";
}
}
?>
and it is my login form the problem with login is it gives an error undefined offset 12
<?php
if (isset($_POST['submit_log'])) {
$email =isset($_POST['email']);
$password =isset($_POST['password']);
$file = explode( PHP_EOL, file_get_contents( "data.txt" ));
$auth = false;
foreach( $file as $line ) {
list($email, $password) = explode(" ", $line);
if ($_POST['email'] == $email && $_POST['password'] == $password) {
$auth =true;
break;
}
}
if($auth) {
echo "Login successfull!";
} else {
echo "Invalid username or password";
}
}
?>
Let me say first off, storing plaintext passwords in a .txt file is probably not the best way of building a longin system. (that's the disclaimer anyway).
Undefined offset (just a guess)
That said I see a few places to improve your code. My guess without more specifics about the error, is you may be pulling a empty array at the end of the file, it's typical to leave a hanging line return at the end (a new line with nothing else for the last line). Which may turn into something like this once you explode it for the second time on the space ['']. And then you try to access it using list which gives you undefined offsets.
You could use array_filter and maybe trim but instead of doing this:
$file = explode( PHP_EOL, file_get_contents( "data.txt" ));
You could try (which you should know as you use this function already)
$file = file( "data.txt", FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES ));
The file function, takes a file and breaks it into an array based on the line returns. So this takes the place of both explode and file_get_contents.
Then it has 2 (bitwise) flags which you could make use of:
array file ( string $filename [, int $flags = 0 [, resource $context ]] )
Reads an entire file into an array.
FILE_IGNORE_NEW_LINES
Omit newline at the end of each array element
FILE_SKIP_EMPTY_LINES
Skip empty lines
http://php.net/manual/en/function.file.php
These take the place of filtering the data for empty lines (something you weren't doing). Granted this is a file you created but you never know when a errant line return could creep in there.
Non-unique entries
if(isset($_POST['submit_reg'])){
$var=file("data.txt");
$userData = $_POST['email'] . " " . $_POST['password'] . "\r\n";
$lines=0;
$db = fopen("data.txt", "a+");
foreach($var as $key=>$value){
$user = (explode(' ', $value));
if ($_POST["password"] === $_POST["confirm_password"]) {
//NOTE: the uniqueness check only happens when the confirm password matches
if (trim($user[0]) == $_POST['email']) {
$lines++;
}
break;
}
}
if($lines){
echo "The email is already exists ";
}else{
//NOTE:yet you save it no matter if that is the case
fwrite($db,$userData."\r\n");
fclose($db);
echo "you are registered successfully ";
}
}
Your uniqueness check only works when the confirm password matches the password, however when it comes time to save the data, there is no check. Instead of just adding that check in around the saving bit, it would be better to wrap the whole thing inside this confirm test, as both pieces of that are known before touching the file:
Here I reworked this a bit for you
if(isset($_POST['submit_reg'])){
if ($_POST["password"] === $_POST["confirm_password"]) {
//VERIFY AND SANITIZE user input, if you put junk in you get junk out
$password = trim($_POST['password']);
//again use something better then die
if(empty($password))die('Password cannot be empty');
//because you split on space, you cannot allow it in inputs
if(preg_match('/\s+/', $password)) die('Password cannot contain spaces');
$email = trim($_POST['email']);
if(empty($email))die('Email cannot be empty');
//you may want to validate using something better
if(preg_match('/\s+/', $email )) die('Email cannot contain spaces');
//Use the flags
$var=file("data.txt", FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES);
//for duplication we only care if there is 1 previous entry
//which is enough to say its a duplicate
$exists=false;
foreach($var as $key=>$value){
$user = explode(' ', $value);
if (trim($user[0]) == $email) {
//we found a match this is enough to call it a duplicate
$exists = true;
break;
}
}
if($exists){
echo "The email is already exists ";
}else{
file_put_contants("data.txt", $email." ".$password.PHP_EOL, FILE_APPEND);
echo "you are registered successfully ";
}
}else{
echo "Confirm password must match password";
}
}
Other stuff
These are also incorrect:
$email =isset($_POST['email']);
$password =isset($_POST['password']);
Isset returns a boolean value, so you are assigning true or false to those two variables. This doesn't matter as you never check them and in your loop you overwrite with the call to list(). But just because someting "doesn't matter" doesn't mean it's correct.
These really should be something like this:
if(!isset($_POST['email']))
die("no email"); //dont use die but do some kind of error message
if(isset($_POST['password']))
die("no password"); //dont use die but do some kind of error message
SUMMERY
Really it's quite a mess. What I mean by this is you used 3 different ways to open and access the file data. You used the PHP line constant in some places but not all. You had code that was somewhat haphazardly thrown around, where you were setting things long before you need them, and in some cases you may not have needed them, so you were wasting resources setting them.
Please don't take the criticism hard, as I am not trying to offend. Simply pointing out places you could improve the flow of the code and simplify things. The big thing is don't get discouraged, in order to program effectively you have to have a no-quite attitude and the drive for continuous self improvement. Even after 9 years of PHP programing I still learn new things all the time, I learned (and wrote a library around it) something new just 2 days ago...
As I said at the beginning and to be honest a database would actually reduce the amount of code you need. It might be intimidating at first to use a database but you'll find that it's easier then doing this. An example is your check for uniqueness, you can set a field to be unique in the Database then you never need to worry about duplicates, only catching the errors for them.
I would suggest looking into PDO and prepared statements, password_hash and password_verify.
A final word of warning is I didn't test any of this so forgive me if there are any typos...
Hope it helps.
I have been trying to get a page working for a number of days now, and there doesn't seem to be much help from the "related" questions on this site.
I have made a signup.php page, which has a form for inputting user credentials to signup up for the site I am building, when the form is filled out and the user presses the 'submit' button, the form uses the action "signupsuccess.php" which has all of the php code for inserting the credentials into the database, and then redirects the user to the "Login.php" page.
My problem:
I have written code to say that if the user has not put in any data for one of the fields in the form, then they are brought back to the signup.php page by using this code:
<?php
if(!isset($_POST['fname'])&&($_POST['lname'])&&($_POST['email'])&&($_POST['pass'])){
header('Location:Signup.php');
exit;
}
else{
$host = "localhost";
$user = "******";
$password = "******";
$conn = mysql_connect($host, $user, $password);
$db = mysql_select_db('*****', $conn);
if(! get_magic_quotes_gpc() )
{
$fname = addslashes ($_POST['fname']);
$lname = addslashes ($_POST['lname']);
$email = addslashes($_POST['email']);
$pass = addslashes($_POST['pass']);
}
else
{
$fname = $_POST['fname'];
$lname = $_POST['lname'];
$email = $_POST['email'];
$pass= $_POST['pass'];
}
$query = mysql_query("select * from users where pass='$pass' AND email='$email'", $conn);
$rows = mysql_num_rows($query);
if ($rows == 1) {
$errors[] = 'That user already exists, try another email';
}else
{
$sql = "INSERT INTO users ".
"(fname,lname, pass, email) ".
"VALUES('$fname','$lname','$pass','$email')";
$retval = mysql_query( $sql, $conn );
if(! $retval )
{
die('Could not enter data: ' . mysql_error());
}
}
}
mysql_close($conn);
?>
But the header() just won't bring the user back when they haven't put anything in to the fields. Is there anything I am doing obviously wrong or can anyone help me sort out the redirection of the user if they haven't entered anything.
Your if statement is incorrect. If you're just trying to check to see if those variables are set you need to call isset() on all of them.
You can do this with individual calls to isset() or all in one call.
if(!isset($_POST['fname'],$_POST['lname'],$_POST['email'],$_POST['pass'])){
header('Location:Signup.php');
exit;
}
FYI, you are wide open to SQL injections. addslashes() does not prevent SQL injections. Also, the mysql_* funcstions are obsolete and you should not be writing new code using them. Look into mysqli or PDO instead.
I don't think you really need a redirection, you probably should overcome this issue from the frontend, maybe a js validation could do the trick and is way simpler.
1.- change the action of submit to run the function "validate()"
2.- create the function that will be something like:
$(document).ready(function(){
function validate(){
if ($.trim($("#inputid").val()) == ""){
$(this).css('border', '2px solid red');
} else if ($.trim($("#inputid2").val()) == "") {
$(this).css('border', '2px solid red');
} else if ($.trim($("#inputid3").val()) == "") {
$(this).css('border', '2px solid red');
} else {
submit();
}
}
});
Where '#input?' is the selector for the input you want to validate and null is the value that you want to avoid, in this case, no value, just empty input. Then if all the inputs are filled it will execute submit() function which you should create to do whatever he has to.
Note: This kind of selectors are for jquery so you must include it in your code as well, put this in your header
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
Note 2: This is the frontend approach. I don't know if this is convenient but at least is an option and helps.
Good luck!
Your if statement was the problem. because the isset was only affecting
$_POST['fname'],
the if statment was being skipped so
header('Location:Signup.php')
was not being reached.
I like to put
echo 'test';
in my code while i am testing it and move it around the code. That way, if it is not echoing 'test', i know that the code isn't even being reached. That could have helped you in this case, showing you that the problem wasn't the header, it was the if statement. Also, consider using PDO for mysql connections. It is more secure against mysql injections.
Your condition (if corrected according to the previous answers) would still always result in the else case. Since you are checking for $_POST fields, those will always be present. isset()returns false if the variable is not set (but it is: it comes from your form) or is NULL (which it is not: it contains an empty value). So, isset() will return true fopr every field. What you need is, for each field: if (empty(trim($_POST['fname']))) || ... )empty() returns false when the variable is not set or empty (i.e NULL, an empty string, 0, 0.0, false, etc, see here: http://php.net/manual/en/function.empty.php)Plus, you need to do something about the deprecated mysql_functions and your vulnerability to attacks.
I'm kinda new to the OOP(? If this IS OOP, I don't know) language, and I'm trying to make a simple login-proccess, with MySQLi. The problem are, that the code doesn't work. I can't login (and It's not showing me any errors) and I can't register an new account (same problem) - It's like the code are dead or something.
I'm not sure I've done it right, but this is my best, so far. 'cause I'm new to OOP(?).
Index.php:
<?php
if(isset($_POST['submit'])) {
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string(md5($_POST['password']));
$userControl = "SELECT * FROM users WHERE username='".$username."' AND password='".$password."'";
$userControlResult = $mysqli->query($userControl);
if($mysqli->num_rows($userControlResult) > 1) {
$userRow = $mysqli->fetch_assoc($userControlResult);
$dbid = $userRow['id'];
$dbuser = $userRow['username'];
$_SESSION['id'] = $dbid;
$_SESSION['username'] = $dbuser;
header("location: me.php");
die();
} else {
echo "<div class='errorField'>Användarnamnet eller lösenordet är fel!</div>";
}
}
?>
I suppose that if I can solve the first error, I can solve the second too.
Thanks!
Many things I would recommend changing about your code:
Don't use mysql_real_escape_string() if you're using mysqli. You can't mix these APIs.
No need to escape a string returned by md5(), because it's guaranteed to contain only hexadecimal digits.
Don't use mysqli_real_escape_string() anyway -- use parameters instead.
Always check if prepare() or execute() return false; if they do, then report the errors and exit.
You can get a mysqli result from a prepared statement using mysqli_stmt_store_result().
Don't SELECT * if you don't need all the columns. In this case, you already have $username so all you really need to fetch is the id column.
No need to check the number of rows returned, just start a loop fetching the rows (if any). Since you exit inside the loop, your "else" error clause will be output only if the loop fetches zero rows.
Consider using a stronger password hashing function than MD5. Also, add a salt to the password before hashing. Read You're Probably Storing Passwords Incorrectly.
Example:
<?php
if(isset($_POST['submit'])) {
$username = $_POST['username'];
$password = md5($_POST['password']);
$userControl = "SELECT id FROM users WHERE username=? AND password=?";
if (($userControlStmt = $mysqli->prepare($userControl)) === false) {
trigger_error($mysqli->error, E_USER_ERROR);
die();
}
$userControlStmt->bind_param("ss", $username, $password);
if ($userControlStmt->execute() === false) {
trigger_error($userControlStmt->error, E_USER_ERROR);
die();
}
$userControlResult = $userControlStmt->store_result();
while($userRow = $userControlResult->fetch_assoc()) {
$_SESSION['userid'] = $userRow["id"];
$_SESSION['username'] = $username;
header("location: me.php");
die();
}
// this line will be reached only if the while loops over zero rows
echo "<div class='errorField'>Användarnamnet eller lösenordet är fel!</div>";
}
?>
A good command to enter at the top of the script (under the
ini_set('display_errors', 1);
This will display any errors on your script without needing to update the php.ini (in many cases). If you try this, and need more help, please post the error message here and I'll be able to help more.
Also, if you are using $_SESSION, you should have
session_start();
at the top of the script under the
Make sure your php is set to show errors in the php.ini file. You'll need to do some research on this on your own, but it's fairly easy to do. That way, you'll be able to see what the error is and go from there.
I understand this has been discussed before but since this post in late 2010 and other discussions around that time when issues were raised - Does FILTER_VALIDATE_EMAIL make a string safe for insertion in database? - I have tried some of the situations described, such as using single quotes and the ` characters in an email form where I am using FILTER_VALIDATE_EMAIL and it has blocked them from being entered into the database.
Have recent releases of PHP fixed earlier issues and is it safe?
I'm tempted to also use mysql_real_escape_string(), presumably the two functions can be used in parallel without any conflict?
Here is the mailing list code that I am using to put addresses into the database
<?php
// connects the database access information this file
include("mailing_list_include.php");
// the following code relates to mailing list signups only
if (($_POST) && ($_POST["action"] == "unsub")) {
// trying to ubsubscribe; validate email addresses
if ($_POST["email"] == "") {
header("Location: mailing_list_remove.php");
exit;
} else {
// connect to database
doDB();
// filtering out anything that isn't an email address
if ( filter_var(($_POST["email"]), FILTER_VALIDATE_EMAIL) == TRUE) {
echo '';
} else {
echo 'Invalid Email Address';
exit;
}
// check that email is in the database
emailChecker($_POST["email"]);
// get number of results and do action
if (mysqli_num_rows($check_res) < 1) {
// free result
mysqli_free_result($check_res);
// print failure message
$display_block = "We couldn't find ".$_POST["email"].". No action has therefore been taken.";
} else {
// get value of ID from result
while ($row = mysqli_fetch_array($check_res)) {
$id = $row["id"];
}
// unsubscribe the address
$del_sql = "DELETE FROM subscribers
WHERE id = '".$id."'";
$del_res = mysqli_query($mysqli, $del_sql)
or die(mysql_error($mysqli));
$display_block = " Your email address, ".$_POST["email"].", is unsubscribed!";
}
mysqli_close($mysqli);
}
}
?>
<html>
<?php echo "$display_block";?>
</html>
The filter_var flag FILTER_VALIDATE_EMAIL will do what it says = Validate value as e-mail, meaning if its not an email it will return false.
You might be looking for FILTER_SANITIZE_EMAIL which will (Remove all characters, except letters, digits and !#$%&'*+-/=?^_`{|}~#.[] )
or
FILTER_SANITIZE_STRING will Strip tags, optionally strip or encode special characters.
Tho I don't recommend w3schools it has a list of filter_var flags http://www.w3schools.com/php/php_ref_filter.asp
Also as others have said, use PDO's prepared query's tobe safe, you can find a great pdo example here: http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html#10 which will explain a few things and there is also a simple pdo CRUD (Create Retrieve Update Delete) class here: http://www.phpro.org/classes/PDO-CRUD.html
good luck...
Kind of an unclear question but I'm trying to check if a username has been taken or not. The code I have now isn't erroring but it's also not working, when echoing the $username variable I get nothing.
$sql="SELECT people_username FROM people WHERE people_username='{$_POST['username']}'";
//Set the result of the query as $username and if the select fails echo an error message
if ($username = !mysql_query($sql,$con)) {
die('Error: ' . mysql_error());
}
else if ($_POST['username'] == $username){
$errors[ ] = 'This username is already in use, please try again...sorry';
}
Is it a syntax error or is my logic wrong?
i would just do
$resource = mysql_query("SELECT people_username FROM people WHERE people_username='".mysql_escape_string($_POST['username'])."'");
if(!$resource) {
die('Error: ' . mysql_error());
} else if(mysql_num_rows($resource) > 0) {
$errors[ ] = 'This username is already in use, please try again...sorry';
} else {
//username is not in use... do whatever else you need to do.
}
If some cheeky user happens to try: '; DROP people; -- as a username, you'd be in big trouble.
You may want to check the following Stack Overflow post for further reading on this topic:
What is SQL injection?
As for the other problem, the other answers already addressed valid solutions. However, make sure to fix the SQL injection vulnerability first. It is never too early for this.
Your code is wrong.
It should be something like this:
$sql="SELECT people_username FROM people WHERE people_username='".mysql_escape_string($_POST['username'])."'";
//If the select fails echo an error message
if (!($result = mysql_query($sql,$con))) {
die('Error: ' . mysql_error());
}
$data = mysql_fetch_assoc($result);
if ($data == null){
$errors[ ] = 'This username is already in use, please try again...sorry';
}
Notice that for security reasons you need to escape the strings you use in SQL queries.
mysql_query($sql,$con) returns a resultset (which may be empty)
you are not testing any condition with if($var = !'value'), you are just assigning a negated resultset to the variable $username (what beast that is, I am not sure)
My suggestion: Simplify the code, do not overload lines of code with multiple tasks.
3. List item