I'm trying to add data to a database using SQLite3 in PHP. I got it working without prepared statements but now I'm trying to make it safer. I'm not using PDO.
So far the following code doesn't work. It just inserts the words ":name" and ":email" into the database, instead of what their bound values should be:
$smt = $db->prepare("insert into names (name, email) values (':name', ':email')");
$smt->bindValue(':name', $var_name);
$smt->bindValue(':email', $var_email);
$var_name = ($_POST[post_name]);
$var_email = ($_POST[post_email]);
$smt->execute();
So I thought at first that this was because I have single quotes around :name and :email in the prepared statement. So I took those out. Now when I post the form, it just puts blank entries into the database, it doesn't insert the values of $var_name and $var_email
The statement is executing, it's just not binding the variables properly I don't think. What have I done wrong?
You managed to confuse binding functions.
It is bindParam have to be used if you don't have your variable assigned yet.
While bindValue have to be used with existing value only.
Also, you should turn error reporting ON
You don't need intermediate variables, you must do this:
$smt = $db->prepare("insert into names (name, email) values (':name', ':email')");
$smt->bindValue(':name', $_POST['post_name'], SQLITE3_TEXT);
$smt->bindValue(':email', $_POST['post_email'], SQLITE3_TEXT);
$smt->execute();
As documented in SQLite3Stmt::bindValue() value is binded instantly, not as SQLite3Stmt::bindParam() that gets the value of the variable at execute() time. So the problem is that that variables are empty when the statement is executed.
Remember:
You don't need to add parentheses on variable assignment: $a = ($b); -> $a = $b;
You MUST quote variable key name. Otherwise PHP will try to look for a constant with this name and will throw a warning if it doesn't exists... but will assign a erroneous key value if it exists!! $_POST[post_name] -> $_POST['post_name']
Related
I'm getting the error: Column count doesn't match value count at row 1
I think, normally this error occurs if the count of the columns and the values aren't equal, but in my code they are...(3).
This is my php code:
$tempsongtitel = $_POST['songtitle'];
$tempinterpret = $_POST['interpret'];
$templink = $_POST['link'];
$query = mysql_query("insert into tMusic (Songtitel, Interpret, Link) values ('$tempsongtitel, $tempinterpret, $templink')") or die(mysql_error());
You missed some quotes. Should be:
$query = mysql_query("insert into tMusic (Songtitel, Interpret, Link) values ('$tempsongtitel', '$tempinterpret', '$templink')") or die(mysql_error());
Otherwise, you were trying to insert all three POST values into the first field.
Moreover, the mysql_ extension has been deprecated and is on the way out and is highly discouraged, especially if you are creating new software.
AND I'll presume you are first sanitizing your data? You're not really taking user input and placing it directly into the database, are you? Even if you don't do any data validation, you should escape your data in the query... easiest and most foolproof way to do that is by using parameterized queries.
The root cause is that your values are all in one set of quotes instead of quoted individually. I think this is a pretty common error, and in my experience it is an easy mistake to make, but not immediately obvious when scanning over your code. You can fix it like this (quick fix, still using deprecated mysql, but with post values escaped):
$tempsongtitel = mysql_escape_string($_POST['songtitle']);
$tempinterpret = mysql_escape_string($_POST['interpret']);
$templink = mysql_escape_string($_POST['link']);
$query = mysql_query("insert into tMusic (Songtitel, Interpret, Link)
values ('$tempsongtitel', '$tempinterpret', '$templink')") or die(mysql_error());
If you can, it would be much better to update your code to use PDO. You could use a prepared statement like this:
$stmt = $pdo->prepare("INSERT INTO tMusic (Songtitel, Interpret, Link) VALUES (?, ?, ?)");
$stmt->bindValue(1, $tempsongtitel);
$stmt->bindValue(2, $tempinterpret);
$stmt->bindValue(3, $templink);
$stmt->execute();
Among the many benefits of using this database extension rather than the old mysql functions it should not be possible to make an error like this in your code. In the prepared statement, there are no quotes around the parameter markers, so if you have VALUES ('?, ?, ?'), or even VALUES ('?', '?', '?') You would get bind errors when trying to bind the values, and the problem would become apparent pretty quickly.
I've found that, even though it's not 100% necessary and it's more time consuming, properly quoting and backticking EVERYTHING helps prevent this from happening.
$myQuery = "INSERT INTO `tMusic` (
`Songtitel`,
`Interpret`,
`Link`
) VALUES (
'$tempsongtitel',
'$tempinterpret',
'$templink'
);";
$runQuery = mysqi_query($DBi, $myQuery) or die(mysqli_error($DBi));
The formatting you use is up to you but this helps me make sure I have a one to one relationship and that I've quoted everything.
Of course that's using mysqli_* in place of the deprecated mysql_* functions AND that's assuming you've set $tempsongtitel, $tempinterpret and $templink properly.
I'm using this Code, to insert the data which is sent with POST into my database.
mysql_query("INSERT INTO pending
(name, alter, mail, kd, steam, spiele)
VALUES
('$_POST["name"]', '$_POST["alter"]', '$_POST["mail"]', '$_POST["kd"]', '$_POST["steam"]', '$_POST["spiele"]')");
but PHP keeps throwing the following error:
PHP Parse error: syntax error, unexpected '"', expecting identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING) in /var/www/bewerben.php on line 34
I cant see the problem there, because i think the '"' is needed there?
You have a bad quote ordering. You can use curly bracers, to escape the variables:
mysql_query("INSERT INTO pending
(name, alter, mail, kd, steam, spiele)
VALUES
('{$_POST['name']}', '{$_POST['alter']}', '{$_POST['mail']}', '{$_POST['kd']}', '{$_POST['steam']}', '{$_POST['spiele']}')");
From the docs:
Complex (curly) syntax
This isn't called complex because the syntax is complex, but because
it allows for the use of complex expressions.
Any scalar variable, array element or object property with a string
representation can be included via this syntax. Simply write the
expression the same way as it would appear outside the string, and
then wrap it in { and }.
To further explain, we have two variables:
$fruit = 'Orange';
$sentence = "$fruits are my favorite fruit";
What I'm trying to get is: Oranges are my favorite fruit. However, this won't work. PHP will instead be looking for a variable called $fruits, and when it doesn't find it, it'll show an error.
So to complete the task properly, we have to wrap the variable in curly braces { }:
$fruit = 'Orange';
$sentence = "{$fruit}s are my favorite fruit";
Great! Now PHP will know where the variable name ends and the string starts.
P.S. I recommend using mysqli.
I'm not quite sure I have the rights to write this here, but I looked at your code & I noticed a problem:
You are using mysql_* which is deprecated since PHP 5.5.0.
This extension is deprecated as of PHP 5.5.0, and will be removed in
the future.
Instead of mysql_* you can use PDO or MySQLi.
Here is a simple example of using MySQLi:
$mysqli = mysqli_init();
$mysqli->real_connect($db_host, $db_user, $db_pass, $db_name);
Then you can prepare your query:
$stmt = $mysqli->prepare("insert into table values(?, ?)");
Bind the params:
$stmt->bind_param("is", $param1, $param2);
We say that the first variable $param1 is an integer and $param2 is a string.
The last thing we need to do is to assign to those variables some values and execute the statement.
$param1 = 1;
$param2 = "somestring";
$stmt->execute();
You should wrap you $_POST variables in {} or escape double quotes in its' keys with \:
mysql_query("INSERT INTO pending
(name, alter, mail, kd, steam, spiele)
VALUES
('{$_POST["name"]}', '{$_POST["alter"]}', '{$_POST["mail"]}', '{$_POST["kd"]}', '{$_POST["steam"]}', '{$_POST["spiele"]}')");
or you can try this :
mysql_query("INSERT INTO pending
(name, alter, mail, kd, steam, spiele)
VALUES
('".$_POST["name"]."', '".$_POST["alter"]."', '".$_POST["mail"]."', '".$_POST["kd"]', '".$_POST["steam"]."', '".$_POST["spiele"]."')");
Try this
INSERT INTO pending
(name, alter, mail, kd, steam, spiele)
VALUES
($_POST["name"], $_POST["alter"], $_POST["mail"], $_POST["kd"], $_POST["steam"], $_POST["spiele"])
NEVER INSERT POSTED VALUES WITHOUT VALIDATION / SANITIZING INTO THE DB
Read about SQL injection : http://www.php.net/manual/en/security.database.sql-injection.php
Why don't you create a function so your code is more reusable?. It's always good to make a single place for reoccurring processes, like adding quotes to strings.
$sql = "INSERT INTO pending SET
name = ".quote($_POST['name']).",
alter = ".quote($_POST['alter']).",
mail = ".quote($_POST['mail']).",
kd = ".quote($_POST['kd']).",
steam = ".quote($_POST['steam']).",
spiele = ".quote($_POST['spiele']);
mysql_query($sql);
function quote($val) {
return "'".$val."'";
}
Also, I prefer using the SET colname = value method for sql, it makes for much more readable code.
I am new to PDO and prepared statements and I am having trouble binding multiple values to my query. I have no problem if it is just one while making a SELECT, for example:
SELECT foo FROM table WHERE id=:something // no problem
But multiple, and trying to INSERT I am getting stuck:
Insert INTO mytable (field1, field2) VALUES (:value1, :value2) // No bueno
Have tried a few different ways and read other posts on here but no luck. Below is an example of what I am having trouble with:
$insertSQL = $db->prepare("INSERT INTO voting_poll (ipaddress, choice)
VALUES (':ipaddress', :value)");
$insertSQL->bindParam(':ipaddress', getenv('REMOTE_ADDR'), PDO::PARAM_STR);
$insertSQL->bindParam(':value', $_POST['radio'], PDO::PARAM_STR);
$insertSQL->execute();
I am getting the following error: Invalid parameter number: number of bound variables does not match number of tokens
You don't put quotes around params. Remove the quotes around :ipaddress in your query.
bindParam() must be used with a variable as it binds the parameter to the variable reference. If you want to use a value (for example, the return value from a function like getenv()), use bindValue() instead.
I'm learning PDO, and finding it tricky to make sure my statements work correctly. I have a PHP function which is updating my database by simply adding the number 1 to the total.
function add_rating($place_id,$rating_id) {
//make $db accessible inside the function
global $db;
// query v1
$sql = "UPDATE places_ratings SET ? +1 WHERE place_id=?";
$q = $db->prepare($sql);
$q->execute(array($rating_id,$place_id));
}
I tried variations of this, none of which I could get to work. I don't know if I was using question marks wrong. I was following this guide and also a previous SO question. In the end I tried a different method which worked first time, so I am tempted to re-use it as it also seems a lot simpler.
function add_rating($place_id,$rating_id) {
//make $db accessible inside the function
global $db;
// query v2
$query = "UPDATE places_ratings SET $rating_id = ($rating_id +1) WHERE place_id = $place_id";
$update = $db->query($query);
}
My question is: which statement is better/safer? And secondly, what am I doing wrong with the first version with question marks? Thanks...
In general prepared statements as in your first example are safer because they are immune to SQL injection.
Your example doesn't work because you can't specify field names using a ? parameter in a prepared statement. Even if you could your SQL still would be wrong, this would expand to
UPDATE places_ratings SET whatever +1 WHERE place_id=?
which is not valid.
If your $rating_id is generated in code and not taken from user input you could combine both approaches.
Prepared statements are not simply like copy'n'pasting variables into a piece of text. Prepared statements separate between the query logic and the values the query should work on. They're there so you're able to tell your database "You're supposed to do this", let the database understand it, then give it the values it's supposed to do that something with. The logic itself cannot be variable, it needs to be complete the first time.
Therefore, you can only use placeholders for values. Your query needs to read UPDATE ... SET FIELD = VALUE WHERE FIELD = VALUE. The FIELD parts need to be in the statement, the VALUE parts you can use placeholders for. It looks like your $rating_id variable is a variable field name. First of all, that's a bad idea. You should not make field names variable if possible. But if you have to, you cannot use prepared statement placeholders for them. Instead, you'll have to do it like this:
$rating_id = 'field_name';
$query = "UPDATE places_ratings SET `$rating_id` = `$rating_id` + 1 WHERE `place_id` = ?";
$stmt = $db->prepare($query);
$stmt->execute(array($place_id));
It's up to you to make sure $rating_id is safe and contains known, whitelisted values. Don't let the user supply the value for it in any way.
Please, go an learn what prepared statements are. And you could also use a tutorial, that does not promote bad practices and vulnerable code.
A correctly created and used prepared statement will always be more secure then concatenated query string, because prepared statements send query logic and data separately.
Also , if you are using PDO, then quite often the use of bindParam() method should be preferred over passing the values directly in the execute() method as an array. This is because, when passing values in execute(), the values are bound as PDO::PARAM_STR, even if DB column expects and integer.
P.S. Stop using global in your code !!
what is oci_bind_by_name for? I read the php manual and cannot understand anything. Please someone explain it to me
look at this example :
$name = "O'Reilly";
$stid = oci_parse($mycon, 'INSERT INTO CUSTOMERS (NAME) VALUES (:nm)');
oci_bind_by_name($stid, ':nm', $name, -1);
oci_execute($stid);
what is -1 for?
It binds values to named parameters:
$name = "O'Reilly";
$stid = oci_parse($mycon, 'INSERT INTO CUSTOMERS (NAME) VALUES (:nm)');
oci_bind_by_name($stid, ':nm', $name, -1);
oci_execute($stid);
So when you run that query :nm will be O'Reilly. The -1 means, the bound value should be as long as the variable. It's the default value. You don't have to set it. As long as you are only binding existing variables, you don't need to bother.
You want to use this method because
Binding allows the database to reuse the statement context and caches from previous executions of the statement, even if another user or process originally executed it. Binding reduces SQL Injection concerns because the data associated with a bind variable is never treated as part of the SQL statement. It does not need quoting or escaping.
which means it is more secure and has better performance.
oci_bind_by_name method is specifying that the value for :nm is "O'Reilly"
-1 is default value ... so need to bother. if you are specifying other value that will tell the method to have the length of the value in :nm.