PHP MySQLi prepared statement bind errors on certain characters? - php

First time posting to StackOverflow, but I've been a long time reader of the comments here.
I ran across a programming bug that I could not figure out after several hours, and couldn't find anything in the questions and responses that seemed to apply, so here goes my first post!
I'm using PHP and a MySQLi prepared statement to insert data that originates from a file into a database and stores each record from the file into an array ($dbData[]) that is passed to a function that performs the database storage. I have checked the array values for all four indices for each record and data exists in all record fields, although there is a lot of slashes (forward and backwards), apostrophes, quotes (single and double) and html tags in some of the string content.
The $dbData array correlates to the columns in the table for the insert.
The table is called "content" and it has a constraint on the second column that it cannot be null. It is named 'CText'.
The code that operates on the data array is in a function that is called within a loop for all of the file data. I am providing the contents of the function below without the function interface. For simplification purposes I have included code that connects to the database, but the code that actually creates the database connection resides outside the function.
$mysqli = new mysqli("example.com", "user", "password", "database");
...
$queryText = "insert into content values (?, ?, ?, ?)";
$query = mysqli->prepare($queryText);
$query->bind_param('dsds',$dbData[0],$dbData[1],$dbData[2],$dbData[3]);
if (!$query->execute()) {
echo '<br>Execute failed: (' . $query->errno . ') . $query->error;
echo '<br>dbData[1]: ' . $dbData[1];
}
The insert works for most of the $dbData record data, but I get this error on a few of the records:
Execute failed: (1048) Column 'CText' cannot be null
CText: {data printed here that is truncated after what appears to be a line return in the string content}
My question is whether the bind may have issues with certain characters, like a line feed/carriage return or some other combination. I have not set a character encoding in the code so the default encoding is in use.

whether the bind may have issues with certain characters, like a line feed/carriage return or some other combination.
No. There are no issues with bind. The only reason for such error message is when data IS null.
Here goes simple checklist for solving all the problems of the kind.
Trust your eyes. You are not a sole user of mysqli prepared statements. There are millions of them, and noone experienced such a problem yet. Means if database is reporting that value cannot be null, then value IS null.
Anyway, if you still thinks that there is a bug - create an isolated, reprobuceable code example. Means not just create unworkable sketch to show to the readers, but a complete working example that anyone can reproduce. Such as
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("CREATE TABLE content ...");
$queryText = "insert into content values (?, ?, ?, ?)";
$query = $mysqli->prepare($queryText);
$dbData[0] = 0;
$dbData[1] = 'some text that yo think is causing the error';
$dbData[2] = 0;
$dbData[3] = 'some another text';
$query->bind_param('dsds',$dbData[0],$dbData[1],$dbData[2],$dbData[3]);
if (!$query->execute()) {
echo '<br>Execute failed: (' . $query->errno . ') . $query->error;
echo '<br>dbData[1]: ' . $dbData[1];
}
without loops. without any code that is not shown - but a complete, working example that produces the noted error.
After failing with such an example, start debugging your code, to find a logical error either with program flow or the way you debug it.
You have to realize that this kind of questions ("I have a bug in PHP out of the clear sky") cannot have another receive without a reproduceable example.

Related

User inputs, clean and sanitize before sending to db

I've searched a lot of the questions here and I found that they either very old or suggesting using prepared statements PDO which I am not using. So I need your help please.
I have a small discussion/chat box where a user submit a message using a <textarea>
What I need is sanitize and filter the user input so it only accepts plain texts (e.g. no tags, no html tags, no scripts no links, etc). Also, it is important to allow line breaks.
Based on my reading I am doing the following in the following order:
trim()
htmlentities($comment, ENT_NOQUOTES)
mysqli_real_escape_string()
nl2br()
Is what I am doing is right? or I am missing something?
Also is there anything I have to do when echoing the data from the db?
really, appreciate your help and kindness
First, keep the text logical and clean:
trim() -- OK
htmlentities($comment, ENT_NOQUOTES) -- No; do later
mysqli_real_escape_string() -- Yes; required by API
nl2br() -- No; see below
The logic behind those recommendations: The data in the database should be just plain data. Not htmlentities, not br-tags. But, you must do the escape_string in order to pass data from PHP to MySQL; the escapes will not be stored.
But... That is only the middle step. Where did the data come from? Older versions of PHP try to "protect" you be adding escapes and other junk that works OK for HTML, but screws up MySQL. Turn off such magic escaping, and get the raw data.
Where does the data go to? Probably HTML? After SELECTing the data back out of the table, then first do htmlentities() and (optionally) nl2br();
Note, if you are expecting to preserve things like <I> (for italic), you are asking for trouble -- big trouble. All a hacker needs to do is <script> ... to inject all sorts of nastiness into your web page and possibly your entire system.
You also have another option. You can use prepared statements with mysqli
They aren't very difficult to learn and work a bit better than mysqli_real_escape_string() in that you don't need to worry about escaping every single variable that will be in your query. They are by nature "prepared" before they go into the database. There are other advantages to this as well, in that:
you do not need to addslashes() to be able to handle characters with
apostrophes etc.
for large databases, they will considerably speed
up your queries (much like PDO).
Here's how to do it:
You connect to the database by creating a new mysqli object like this:
$conn = new mysqli($host, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $dbc->connect_error);
}
Next you want to convert your variables from your form.
Say you have a form field like this:
<input type="text" name="var1">
you can use htmlentities and trim together like so, and create your $var1 variable:
$var1 = htmlentities(trim($_POST['var1']));
Then you can create your transaction like this:
$stmt= $conn->prepare("insert into tablename (key1, key2) values (?,?)");
$stmt->bind_param("is",$var1, $var2);
$stmt->execute();
$stmt->close();
That's basically it. You do a query just like you normally would, but instead use the ? placeholders, assigning the datatype (above is i for integer, and s for string) and then bind them to your placeholders in the query.
That's basically it.
if you want to do it with a select with a variable, you use the normal select syntax and the same way with a ? with the variable, and then bind it. You can then bind your results into variables easily like so (assuming var3 is an integer):
$stmt= $conn->prepare("select var1, var2 from tablename where var3 = ?");
$stmt = bind_param("i", $var3);
$stmt->bind_result($var1, $var2);
$stmt->execute();
$stmt->close()
and then you can fetch your variables using this
$stmt->fetch();
or if your query brings back multiple rows
while ($stmt->fetch() {
echo $var1 . $var2;
}
nl2br() is used for output, you don't need to worry about input; it can be stored in the database as \n, and when you need it spits it out as breaks. If one of these variables needs the new lines turned into <br/> tags, you can, as you suggest use nl2br() on the variables (note this adds no security, but as you said you needed it), like so
echo nl2br($var1, false);
you can also use trim() and htmlentities() on this if it is being echoed into, say, a form input field and you don't want your form to break if there are html characters in the output.
Your question can lead me to build a full project with many features ;) lol
Before we start with out steps, we need a dummy (test) database for this scenario. We call out database chatbox with table called chat. You can simply create it by executing the following sql statement in your MySQL test environment:
CREATE TABLE `chat` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`msg` VARCHAR(200) NOT NULL DEFAULT '0',
`user_id` INT(11) NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
;
Now you can go a head and follow the steps here:
Step 1: Create project folder in your web server.
Build database connection based on PDO and call it dbConnect.inc.php:
<?php
// check if PDO driver not available
if (!defined('PDO::ATTR_DRIVER_NAME'))
echo 'PDO driver unavailable <br />';
// database configuration
$dbHost = "localhost";
$dbPort = "3306";
$dbName = "chatbox";
$dbUser = "root";
$dbPass = "";
$strDSN = "mysql:host=$dbHost:$dbPort;dbname=$dbName";
// database connection
try
{
$dbConn = new PDO($strDSN, $dbUser, $dbPass);
//Activate following line to view all error messages
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e)
{
die("Could not connect to the database $dbName, error info: <br />"
. $e->getMessage());
exit();
}
I will test this works before go to next step. Btw the prepared method does not require mysqli_real_escape_string().
I have used PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION in stead of if statements, this method will give you useful error details while development the project. You will find out which method is more practical for getting error message while your development process of the project.
Step2: Create a file call filter.inc.php:
<?php
// filter for input
function filterInput($content)
{
$content = trim($content);
$content = stripslashes($content);
return $content;
}
//filter for viewing data
function filterOutput($content)
{
$content = htmlentities($content, ENT_NOQUOTES);
$content = nl2br($content, false);
return $content;
}
This file contain a function to filterInput to sanitize or filter your input content for comments or other inputs. And filterOutput that effect your data view.
All depending on your strategy and what you need, like if you need to allow people post url's or email address, should url and email become active link or only viewed as text etc. that way you can define which filter should be use for your content input and which filter should be used for you content output.
You can add or delete extra features to functions. There are many features for text input and output, you can test those individually and evaluate it, and even extend the filter function or create your own function.
Final step 3: Now we put the puzzles together in our index.php file:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Chat box</title>
</head>
<body>
<?php include './dbConnect.inc.php'; ?>
<?php include './filter.inc.php'; ?>
<h1>Chat box</h1>
<p>
<?php
// this is dummy user id, but use the id over user id when login or the way you want
// this is only example
$user_id = 1;
if (isset($_POST["msg"]))
{
$msg = filterInput($_POST["msg"]);
$sql = "INSERT INTO chat "
. "(msg, user_id) "
. "VALUES "
. "(:msg, :user_id)";
$stmt = $dbConn->prepare($sql);
$fieldsArr = [':msg' => $msg, ':user_id' => $user_id];
$stmt->execute($fieldsArr)
// refresh page after insert
header("Location: " . $_SERVER['REQUEST_URI']);
}
?>
<form action="index.php" method="post">
<textarea name="msg" id="msg" required></textarea>
<input name="submit" type="submit">
</form>
</p>
<p>Comments</p>
<p>
<?php
$sql = "SELECT * FROM chat WHERE user_id = (:user_id);";
$stmt = $dbConn->prepare($sql);
$fieldsArr = [':user_id' => $user_id];
$stmt->execute($fieldsArr)
while ($result = $stmt->fetch())
echo "<h3>" . filterOutput($result['msg']) . "</h3>";
$dbConn = null;
?>
</p>
</body>
</html>
This is to demonstrate how things works. You have insert, select statement as example and filter functions. You can make tests, extend it the way you like or further develop your own project.
Here is screen shot of the chatbox example I made:
filter_input could be another one you are looking for. It can save you hours from writing sanitizing and validation code. Of course, it does not cover every single case, but there is enough so that you can focus more on specific filtering/validating code.
Though it is strongly recommended to use prepared statements with
PDO/mysqli. But sometimes it is not so easy to convert the whole
project in the tail end of the project. You should learn PDO/mysqli for
your next project.
$comment = filter_input(INPUT_POST, 'comment', FILTER_SANITIZE_STRING);
There are different Types of filters for you. You can select depending on your needs. You can also use filter_has_var to check for variable set.
Your code looks fine, if you don't want to prepare statements then escaping is the next best thing. And when you echo it should be straightforward, it's only plain text.

Retrieving Data From One Table To Another Table With Different Columns

Trying to retrieve information from the database t_awhole and input it into a_whole. I've read up on a lot of these, but cannot find anything specific to my question.
The code stops where I have placed the comment //>>>>Stops here<<<<<. I used an echo statement to find that it does not pass this point.
This is a email confirmation function, so t_awhole's table structure is different than a_whole. Everything is the same but in t_awhole the first column is a confirmation code associated to to that user. Once they click the link in their email, the row with that confirmation code should transfer all the data from that t_awhole into a_whole. However, it should not transfer the confirmation code, but should add a new column for the number of the row (first column) as an increment, and whether the user is an admin or not (last column). Everything else will stay as it was (fN, lN, aI, eml, pss) in between that first and last row. Please tell me how to do this. Someone attempted below, but his answer was difficult to understand (although he tried and I thank him for that).
Finally, I am using PDO as the structure. It was originally written in mysql. I notice a colon : is used instead of a money sign $. How do I switch this to be from sql to PDO?
<?php
include('db.php');
// passkey that got from link
$pk=$_GET['pk'];
$t_awhole_conf="t_awhole";
// Retrieve data from table where row that match this passkey
$sql_conf1="SELECT * FROM $t_awhole_conf WHERE confirm_code ='$pk'";
$result_conf=mysql_query($sql_conf1) or die ('Error updating database: '.mysql_error());
// If successfully queried
if($result_conf){
// Count how many row has this passkey
$count=mysql_num_rows($result_conf);
// if found this passkey in our database, retrieve data from table "t_awhole"
if($count==1){
$rows=mysql_fetch_array($result_conf);
$fN = $rows['fN']; // capitalizes the first letter (6-26-14)
$lN = $rows['lN']; // capitalizes the first letter (6-26-14)
$aI = $rows['aI'];
$eml = $rows['eml'];
$pss = $rows['pss'];
$pss2 = $rows['pss2'];
$a_whole_conf="a_whole";
// Insert data that retrieves from "t_awhole" into table "a_whole"
$sql_conf2= $conn->prepare("INSERT INTO $a_whole_conf(fN, lN, aI, eml, pss, admin)
VALUES ($fN, $lN, $aI, $eml, $pss, $admin)");
//>>>>Stops here<<<<<
$result_conf2=$sql_conf2->execute() or die ('Error updating database: '.mysql_error());
}
// if not found passkey, display message "Wrong Confirmation code"
else {
echo "Wrong Confirmation code";
}
// if successfully moved data from table"t_awhole" to table "a_whole" displays message "Your account has been activated" and don't forget to delete confirmation code from table "t_awhole"
if($result_conf2){
echo "Your account has been activated";
// Delete information of this user from table "t_awholeb" that has this passkey
$sql_conf3="DELETE FROM $t_awhole_conf WHERE confirm_code = '$pk'";
$result_conf3=mysql_query($sql_conf3);
}
}
?>
TO ANSWER THE QUESTION YOU ASKED
The colon (:) is used in SQL text to identify a placeholder for a named bind parameter within a prepared statement. That colon gets included in the SQL text, and value for that placeholder is provided when the SQL statement is executed.
The "money sign" identifies a PHP variable; in the string context, the variable is evaluated, and the value of the variable gets incorporated into the SQL text.
The following is not an answer to the question you asked. But I think this will answer several other questions you should be asking...
The inclusion of "unsafe" values in PHP variables is where the "SQL Injection" vulnerability comes in, if we don't have any guarantee that the value of the variables don't contain some characters that will be interpreted as SQL. And that's exactly why the mysql interface includes the mysql_real_escape_string function. This is a "wrapper" that inspects values, and properly escapes values so that they will be seen as values, and not be interpreted as SQL syntax.
Q: 1. The code stops where I have placed the comment //>>>>Stops here<<<<<.
A: Cool. It's not clear how you know the code "Stops here", if you're getting some sort of error or what.
We don't see any declaration or assignment for the reference to the $admin variable. We do see that we expected column pss2 to be retrieved by the SELECT. But we don't see anything be done with that, except to assign that to a PHP variable named $pss2, and that doesn't appear to be referenced anywhere else. Curious.
Q: 2. This is a email confirmation function, so t_awhole's table structure is different than a_whole. Everything is the same but in t_awhole the first column is a confirmation code associated to to that user. Once they click the link in their email, the row with that confirmation code should transfer all the data from that t_awhole into a_whole. However, it should not transfer the confirmation code, but should add a new column for the number of the row (first column) as an increment, and whether the user is an admin or not (last column). Everything else will stay as it was (fN, lN, aI, eml, pss) in between that first and last row.
A: Seems like an awkward design. It's not clear why you need to loop through all the individual rows returned by a SELECT (and your code is subject to SQL injection. Hopefully, "Little Bobby Tables" doesn't register... http://xkcd.com/327/)
I'm not sure why you don't just run a single INSERT .. SELECT statement to "copy" the rows from one table to the other in one fell swoop, for example:
$sql = "INSERT INTO a_whole
( fN , lN, aI, eml, pss, admin)
SELECT t.fN, t.lN, t.aI, t.eml, t.pss, '' AS admin
FROM t_awhole t
WHERE t.confirm_code = '" . mysql_real_escape_string($pk) "'";
(I don't see any declaration or assignment to $admin in the original code, so I replaced that reference with a literal string (zero length) in the example above.)
If you were going to do this with PDO, you could use a prepared statement with a bind placeholder. All of the SQL is the same, with the exception that we replace a reference to the value of the PHP $pk variable with a bind placeholder in the SQL text:
$sql = "INSERT INTO a_whole
( fN , lN, aI, eml, pss, admin)
SELECT t.fN, t.lN, t.aI, t.eml, t.pss, '' AS admin
FROM t_awhole t
WHERE t.confirm_code = :pk";
Now the SQL text is a constant string, and is not subject to SQL injection.
With PDO, you'd first call the prepare(), and then call bind_param() and execute(), e.g.
$sth = $dbh->prepare($sql);
$sth->bindParam(':pk', $pk, PDO::PARAM_INT);
$sth->execute();
BUT... to do that, you need to have a PDO connection (referenced as $dbh above); you can't use a mysql connection with PDO.
(If you don't check the result from each call, you'd want to set the error handling on the connection to throw an error, and use a try/catch block to catch any PDOException.)
UPDATE: actually, I see that your code only copies the first row returned from the SELECT, we don't see a normal while (fetch) loop we usually see. That was my oversight there, seeing something I expected but that wasn't there. That's my bad. Still, there's no need to retrieve the values into PHP variables, if all we are going to do with them is insert them into another table. Let the database do that, without mucking up the code with a bunch of variables we don't need.
Q: 3. Finally, I am using PDO as the structure. It was originally written in mysql. I notice a colon : is used instead of a money sign $. Why is this and where would I switch the : for the $ in my code?
A: The code modified in the edit, is now calling functions both from the deprecated mysql interface; and PDO (per the references to PDO functions.)
It's not valid to mix mysql interface functions and PDO interface functions. You can't use PDO functions on a connection obtained using the mysql interface, etc.
This is likely why your code "stops here".
(I was a little confused earlier; I didn't see the PDO functions, all I saw was mysql functions. We're not used to seeing mysql and PDO functions mixed like this, mostly because we never see this because it's not valid.)
TO ANSWER THE QUESTION YOU ASKED
The colon (:) is used in SQL text to identify a placeholder for a named bind parameter within a prepared statement. That colon gets included in the SQL text, and value for that placeholder is provided when the SQL statement is executed.
The "money sign" identifies a PHP variable; in the string context, the variable is evaluated, and the value of the variable gets incorporated into the SQL text. (This is where the "SQL Injection vulnerability comes in... we don't have any guarantee that the value of that variable doesn't contain text that will be interpreted as SQL.
And that's exactly why the mysql interface includes the mysql_real_escape_string function.

Error: Query was empty

$nam=$_POST['name'];
$fname=$_POST['family'];
$dat=$_POST['date'];
$bal=$_POST['balance'];
$curr=$_POST['currency'];
$con=mysql_connect('localhost', 'xxxx', 'xxxx', 'xxxx');
$db=mysql_select_db('users',$con);
$ins=mysql_query("INSERT INTO users (Name, FamilyName, Date, Balance, Currency) VALUES ('$nam', '$fname', '$dat', '$bal', '$curr'))",$con);
if (!mysql_query($ins,$con))
{
die('Error: ' . mysql_error($con));
}
So guys, I got this code and I am trying to do something like a registration form. I have tripple checked the names of the variables and the query itself is working when executed in SQL database. The thing is when I include it in my php script it returns that the Query was empty. I've looked around but all errors on the Web are around not assigning to a variable or having several insert statements and so on. So my question is why am i getting this when I am actually inputting data from a web form? Error: Query was empty
P.S.
Ok so what I mde of this: I removed the check that you said was for a second time that is the if (!mysql_query($ins,$con)) { die('Error: ' . mysql_error($con)); } part now i get execution but it does not really add the entry to the database and i cannot call it. That is the new name.
You're basically trying to use mysql_query() twice:
$ins=mysql_query("INSERT INTO users (Name, FamilyName, Date, Balance,
Currency) VALUES ('$nam', '$fname', '$dat', '$bal', '$curr'))",$con);
if (!mysql_query($ins,$con))
{
$ins will contain a valid MySQL resource if the query was executed correctly, but you're attempting to use it again in the if condition.
Just remove the mysql_query() part from the condition, like so:
if(!$ins) {
# code ...
}
That should fix this particular issue. But note that your code is vulernable to SQL injection. Also, mysql_* functions are deprecated and are soon to be removed. I recommend you switch to MySQLi or PDO and start using parameterized queries to be safe.
this is incorrect
if (!mysql_query($ins,$con))
why are you performing a query of a query ??
just use if (!$ins||!$con)) if you are trying to check if the query and connection has been successful

How do I load data when tables names are stored in variables?

I want to load data from several CSV documents in a database.
The problem is that there is a table for a file, thus the table name has to be stored in a variable progressively updated by the loop. The tables are created, but after that the script fails; Nothing happens, my tables and their fields always have 0 lines.
I think that my idea is feasible, because some topics describe some tips in this way, but nothing works in my case.
This is my code that fails:
$query = "INSERT INTO". $name_of_the_file." (id, content) values (". $arrayGenre[0].",'".trim($arrayGenre[1])."')";
where $name_of_the_file refers to the table created in the loop, referring ultimately to the file targeted by the loop.
Following your recommendations, I added a space and print the query by:
echo ("<br>". $query);
Here is an example for the first line. No offense for the xxx substitutions: these are nominative data.
INSERT INTO names.csv (id, url, content) values (1,'xxx_some_adressxxx,'agency: xxx')
I do not know enough PHP to say that it is the expected result, but that seems a good SQL request and the values are fine.
Here are the next lines of my script:
$mysqli->query($query);
and at the beginning of my script, the definition of $mysqli:
$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
New edit :
Well it was in fact SQL code which was badly written...
Try adding a space:
$query = "INSERT INTO ". $name_of_the_file ...
It's always worth outputting your SQL via echo to make sure it looks like what you expect it to look like.
Edit:
INSERT INTO names.csv (id, url, content) values (1,'xxx_some_adressxxx,'agency: xxx')
You need to add an apostrophe at the end of the second field:
INSERT INTO names.csv (id, url, content) values (1,'xxx_some_adressxxx','agency: xxx')
I'd also recommend that you look into things like PDO, to make your code more robust and more secure.
You can also try pasting your SQL directly into the database, to see if it gives you an error.

Can I use htmlentities() in an SQL query?

Much thanks for the discussion my original question generated. I took Jay's suggestion to use bind_param(), but there is something I don't understand about it that may be giving me the Server Error: "The website encountered an error while retrieving...". I don't know what the parameter 'sssd' that came with the example means.
Any suggestions as to what is generating the Server Error are much appreciated.
<?php
$mysqli = new mysqli('my-database-address', 'my-username', 'my-password', 'my-database-name');
f (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit(); }
$stmt = $mysqli->prepare("INSERT INTO volunteers VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param('sssd', $first_name, $last_name, $street_address, $apt_unit, $city, $zip,
$email, $phone, $planning, $signatures, $canvassing, $phone_bank, $media, $press_releases,
$volunteer_coordinator, $speaker, $house_parties, $web_page, $other, $skills, $organizations);
$first_name = '$_POST[first_name]'; $last_name = '$_POST[last_name]'; $street_address = '$_POST[street_address]';
$apt_unit = '$_POST[apt_unit]'; $city = '$_POST[city]'; $zip = '$_POST[zip]'; $email = '$_POST[email]';
$phone = '$_POST[phone]'; $planning = '$_POST[planning]'; $signatures = '$_POST[signatures]';
$canvassing = '$_POST[canvassing]'; $phone_bank = '$_POST[phone_bank]'; $media = '$_POST[media]';
$press_releases = '$_POST[press_releases]'; $volunteer_coordinator = '$_POST[volunteer_coordinator]';
$speaker = '$_POST[speaker]'; $house_parties = '$_POST[house_parties]'; $web_page = '$_POST[web_page]';
$other = '$_POST[other]'; $skills = '$_POST[skills]'; $organizations = '$_POST[organizations]';
$stmt->execute();
$stmt->close();
echo "<br /><br />";
echo "<div class='center-col-wrap'>";
echo "Your information has been received.";
echo "<br /><br />";
echo "Thank you for volunteering!"; echo "<br />";
echo "Your help in this effort to bring greater democracy to Oakland"; echo "<br />";
echo "will go a long way to create a healthy and informed community."; echo "<br />";
echo "<br /><br />";
echo "<a href='http://communitydemocracyproject.org/'>Return to CDP Home Page.</a>";
echo "</div>";
$mysqli->close();
?>
MY ORIGINAL QUESTION IS BELOW:
I didn't know if this would work or not. It does not So how can I use htmlentities() here?
Any help is much appreciated.
$sql="INSERT INTO volunteers (first_name, last_name, street_address, apt_unit, city, zip, email, phone,
planning, signatures, canvassing, phone_bank, media, press_releases, volunteer_coordinator, speaker,
house_parties, web_page, other, skills, organizations)
VALUES
('htmlentities($_POST[first_name])','htmlentities($_POST[last_name])','htmlentities($_POST[street_address])',
'htmlentities($_POST[apt_unit])','htmlentities($_POST[city])','htmlentities($_POST[zip])',
'htmlentities($_POST[email])','htmlentities($_POST[phone])','$_POST[planning]','$_POST[signatures]','$_POST[canvassing]','$_POST[phone_bank]',
'$_POST[media]','$_POST[press_releases]','$_POST[volunteer_coordinator]','$_POST[speaker]',
'$_POST[house_parties]','$_POST[web_page]','$_POST[other]','htmlentities($_POST[skills])','htmlentities($_POST[organizations])')";
You never want to use htmlentities() on data that's going to be inserted into the database!
NEVER!
Only use it when you are outputting data to a web page.
Otherwise, if you ever want to do anything with that data, ever, that's not directly to a web browser (think, sending emails, or counting words, or outputting to CSV, what have you), you'll quickly realize your error.
As Theodore said, never use htmlentities() for "escaping" something you want to put in your DB.
I strongly recommend to use prepared statements when anything that (could) come from outside (the user) is stored in a database.
Prepared statements are really easy to use.
If you use PDO to access you database help can be found here.
As you can see the bindParam() method is used to assign any value to a placeholder in the query.
If you use mysqli you can find the docs here.
The syntax of bind_param() is slightly different since the placeholders don't have names (order matters) and first argument is a string that determines what type the arguments have ("s" for string, "i" for integer and so on).
Using prepared statements has several positive effects. First of all it automatically masks the data that is provided in the bindParam()/bind_param() method and is the best way to close the SQL injection attack vector and it even optimizes the performance of your queries by storing the execution plan in the database (this has a little overhead but if you execute a query twice it pays off double).
PS: htmlentities() should only be used if you want to display some HTML as raw text to your users (code listings for instance).
PPS: Don't use real_escape_string() to prevent SQL injection since it's not safe (supeskt.org)
Update
First of all, for a follow up you should ask a new question. People don't read questions that are already marked as answered and by opening new questions you give kind people an opportunity to get some reward. :)
Nevertheless, the first argument "sssd" tells the database provider that you are passing four arguments, three of type string and a fourth of type double (in the example in the docs three strings and one double are bound ("DEU", "Bavarian", "F" and 11.2)). This is obviously not the case here, you are actually passing (binding) 21 values.
Depending of the type that the columns in your volunteers table have you need to pass a string of 21 characters as the first argument.
There are four possible chars that can be used to determine the type:
i for integer
d for double (floating point numbers)
s for string
b for boolean
All you have to do is to check what types you DB columns have. You will see that the types in the database have different names (like varchar, float etc.). If you google for this names you will find out that they are similar to string, integer, double and boolean. So you have to choose the best matching type depending on the column type (string ≆ varchar, double ≆ float, string ≆ tinytext, string ≆ date/datetime etc. pp.) and you should ensure that the values (your $_POST variables) actually match the type you defined.
Assuming that all your columns are of an text like type like varchar, the first argument would look like 'sssssssssssssssssssss' (21 times s) or 'ssssssssssssssissssss' if the column that takes the volunteer_cordinator is of type int (just for instance).
After you have done this you should double check if f (mysqli_connect_errno()) is a copy&paste related mistake or if you have actually missed the i in your code (should be if (mysqli_connect_errno())).
If you have checked that you should consider to write $_POST['xyz'] instead of '$_POST[xyz]', it will help you, really (' marks the start/end of a string and xyz is in fact the string here).
If you still encounter errors enable more detailed error information by adding error_reporting(E_ALL); at the top of your file (you should remove this for security reasons when your site goes live) and ask a new question.
Update 2
Double check your MySQL connection string (the arguments you pass in the mysql() method). Are you sure that your password starts with an # and ends with a full stop? By the way, you shouldn't post passwords etc. in the public.
Ensure that you server supports the mysqli methods by running a script containing only
<?php
// Show all information, defaults to INFO_ALL
phpinfo();
?>
and check the output for something like this:
To answer your question exactly as you wanted, you'll need to exit out of your string:
$sql="INSERT INTO volunteers (...) VALUES
('".htmlentities($_POST['first_name'])."','".htmlentities($_POST['last_name'])'." ...
(But please, as Theodore clearly says, don't do this. It's bad. Really, don't do it. Please!)
I think you're trying to escape your input/output. The best way to do is is firstly to stop SQL injection, use your favourite DB escaping method. I'm just using this as an example, you might have a better setup than this short example code:
$sql="INSERT INTO volunteers (...) VALUES
('".$mysqli->real_escape_string($_POST['first_name'])."','".$mysqli->real_escape_string($_POST['last_name'])'." ...
And then when you output, escape using htmlentities:
echo htmlentities($output->first_name);

Categories