Safe way to fetch data with mysql/php - php

i wrote this code before i was aware of the use of prepared statements and what it does to SQL injections. Now i'm also aware of how messy it is to fetch arrays with prepared statements. So i was wondering if this piece of code is safe to use since it doesn't use any user submitted information to fetch the rows.
What it does is to identify the row in the db table by using a session id, session is ensured by a login_check function etc..:
$username = $_SESSION['username'];
$select = mysqli_query($link, " SELECT product_id, product_title, product_value
FROM product
WHERE user_id='$username'");
while ($row = mysqli_fetch_assoc($select))
{
$product[] = array(
'product_id' => $row['product_id'],
'product_title' => $row['product_title'],
'product_value' => $row['product_value']);
}
Some information regarding this issue would really be appreciated since things were going so well until i got to know of the prepared statements..
Edit
So, i kinda went in another direction and skipped the array part completely for this query. Instead i went with the prepared statement and did something like this..:
$select_stmt = $db->prepare("SELECT etc...)
$select_stmt->bind_param("CODE")
$select_stmt->execute();
And so on..
But the thing is that my bind_result got pretty big (?) with 14 variables. Perhaps this is a stupid question but will that slow down my site compared to the old way with using a single array (if 14 even is considered "big")? This is a common query that hopefully many users will use simultaniously and often. Prepared statements are new for me so..
Thanks sofar for the help people.

You should look into prepared statements. This is one of the many benefits of mysqli. It allows you to insert variables without having to worry about SQL injection. mysqli_real_escape_string will work most times, but prepared statements are the only truly secure method for avoiding attacks.
Example from the manual:
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$city = "Amersfoort";
/* create a prepared statement */
if ($stmt = $mysqli->prepare("SELECT District FROM City WHERE Name=?")) {
/* bind parameters for markers */
$stmt->bind_param("s", $city);
/* execute query */
$stmt->execute();
/* bind result variables */
$stmt->bind_result($district);
/* fetch value */
$stmt->fetch();
printf("%s is in district %s\n", $city, $district);
/* close statement */
$stmt->close();
}

If the username is e.g. Jean D'arc the string reaching the mysql server would be
SELECT
product_id, product_title, product_value
FROM
product
WHERE
user_id='Jean D'arc'
and that would result in a parse error.
Properly encoding/escaping the parameters within an sql statement is not only necessary for preventing malicious input from users but for every parameter where you can't (with absolute certainty) be sure it doesn't contain characters that may break the statement. In case of (any tiny) doubt encode/escape the parameter, or simply use prepared statements.

Related

PHP SQL Injection bind dynamic variables in statement for UPDATE

I am trying to be safe from Sql Injection by doing prepared statements + binding on all Database save/update/query actions.
But I got stuck in the moment in which the table name + user_id are variables. code:
// ALL USUAL $dbc MySqli DATABASE CONNECTION - then code statement prepare:
$stmt = $dbc->prepare("UPDATE ".$tablex." SET logo=?, last_mod=? WHERE ".$table_id."=?");
// or: $stmt = $dbc->prepare("UPDATE $tablex SET logo=?, last_mod=? WHERE $table_id=?"); same thing
$stmt->bind_param('ssi', $log_logo, $last_mod, $user_id);
// execute and do some checking
$status_save = $stmt->execute();
if ($status_save === false) {trigger_error($stmt->error, E_USER_ERROR);}
It has worked fine so far as long as $tablex and $table_id were known. Now they can have different names, and using a variable sets things wrong. What am I doing wrong here? Tx.

How can I use array values in WHERE clauses?

I'm trying to figure out how to use a array variable with a where clause.
when I echo $deader, I get 23,25,43,56,31,24,64,34,ect.. these are id numbers i want Updated
$sql = mysql_query("UPDATE users SET dead='DEAD' WHERE userID ='(".$deader.")' ");
The Array$deader has multiple values of id numbers, it only works and updates the first id# in the $deader Array.
I'm reading that Implode is what I need, but don't know how to get it into a functional format.
Use WHERE ... IN
$sql = mysql_query("UPDATE users SET dead='DEAD' WHERE userID IN (".$deader.")");
Where $deader is in comma separated format. (for example: $deader = '143, 554, 32')
If it is an array you can use $deader = implode(',', $deader); to make it comma separated.
Note:
Please stop using mysql_* functions for new code. The functions aren't maintained anymore and the community has begun the deprecation process. See here for more info about converting this to PDO: How do I convert a dynamically constructed ext/mysql query to a PDO prepared statement? (thanks to PeeHaa)
If $deader is some sort of string of values, you will need to use MySQL IN() condition. Like this
UPDATE users SET dead = 'DEAD" WHERE userID IN ('?', '?', '?')
Where ? are your values. If userID as an INTEGER field, you can omit the single quotes around the values, if it is a string field, they would be required.
I think what you're looking for is the IN keyword in SQL.
UPDATE users set dead='DEAD' where userID in (100,101,102)
Using MySQLi instead of mysql_*
require_once('.dbase'); //contains db constants DB_NAME, DB_USER etc
//using PHP built in connection class mysqli
$mysqli = new mysqli(DB_HOST,DB_UNAME,DB_UPWORD,DB_NAME);
if ($mysqli->connect_errno){
$err = urlencode("Failed to open database connection: ".$mysqli->connect_error);
header("Location: error.php?err=$err");
exit();
}
$deader=implode(',',$deader); //assumes array, sting "143,554,32"
if ($stmt = $mysqli->prepare("UPDATE users SET dead='DEAD' WHERE userID IN (?)"){
//bind variable to statement object
$stmt->bind_param('s',$deader) //var type[string],var to bind
//execute query
$stmt->execute();
//feedback
$rowsAffected = $stmt->affected_rows(); //update doesn't return a result set.
//close statement object
$stmt->close();
}
$mysqli->close();
You guys are hammering on Rickos for using mysql_* but not explaining how to do it otherwise, my point was simply showing how to use mysqli. A prepared statement isn't necessary, but since you marked my comment down (peehaa) for not showing it as a prepared statement, here it is edited as a prepared statement. And it does answer his questions.

Replacing \r\n with preg_replace, since nl2br() doesn't work after real_escape [duplicate]

So in this program I'm writing, I actually grab a SQL query from the user using a form. I then go on to run that query on my database.
I know not to "trust" user input, so I want to do sanitization on the input. I'm trying to use mysql_real_escape_string but have been unsuccessful in getting it to work.
Here's what I'm trying, given the input:
select * from Actor;
//"query" is the input string:
$clean_string = mysql_real_escape_string($query, $db_connection);
$rs = mysql_query($clean_string, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
This is ALWAYS giving me the
"Invalid input!"
error.
When I take out the clean_string part and just run mysql_query on query, the
"invalid
input"
message is not output. Rather, when I do this:
$rs = mysql_query($query, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
It does NOT output
"invalid input".
However, I need to use the mysql_real_escape_string function. What am I doing wrong?
Update:
Given
select * from Actor; as an input, I've found the following.
Using echo statements I've
found that before sanitizing, the string holds the value:
select * from Actor;
which is correct. However, after sanitizing it holds the incorrect
value of select *\r\nfrom Actor;, hence the error message. Why is
mysql_real_escape_string doing this?
use it on the actual values in your query, not the whole query string itself.
example:
$username = mysql_real_escape_string($_POST['username']);
$query = "update table set username='$username' ...";
$rs = mysql_query($query);
Rather than using the outdated mysql extension, switch to PDO. Prepared statement parameters aren't vulnerable to injection because they keep values separate from statements. Prepared statements and PDO have other advantages, including performance, ease of use and additional features. If you need a tutorial, try "Writing MySQL Scripts with PHP and PDO".
mysql_real_escape_string() is the string escaping function. It does not make any input safe, just string values, not for use with LIKE clauses, and integers need to be handled differently still.
An easier and more universal example might be:
$post = array_map("mysql_real_escape_string", $_POST);
// cleans all input variables at once
mysql_query("SELECT * FROM tbl WHERE id='$post[id]'
OR name='$post[name]' OR mtime<'$post[mtime]' ");
// uses escaped $post rather than the raw $_POST variables
Note how each variable must still be enclosed by ' single quotes for SQL strings. (Otherwise the escaping would be pointless.)
You should use mysql_real_escape_string to escape the parameters to the query, not the entire query itself.
For example, let's say you have two variables you received from a form. Then, your code would look like this:
$Query = sprintf(
'INSERT INTO SomeTable VALUES("%s", "%s")',
mysql_real_escape_string($_POST['a'], $DBConnection),
mysql_real_escape_string($_POST['b'], $DBConnection)
);
$Result = mysql_query($Query, $DBConnection);
manual mysql_real_escape_string()
Escapes special characters in a string
for use in an SQL statement
So you can't escape entire query, just data... because it will escape all unsafe characters like quotes (valid parts of query).
If you try something like that (to escape entire query)
echo mysql_real_escape_string("INSERT INTO some_table VALUES ('xyz', 'abc', '123');");
Output is
INSERT INTO some_table VALUES (\'xyz\',
\'abc\', \'123\');
and that is not valid query any more.
This worked for me. dwolf (wtec.co)
<?php
// add data to db
require_once('../admin/connect.php');
$mysqli = new mysqli($servername, $username, $password, $dbname);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$post = $mysqli->real_escape_string($_POST['name']);
$title = $mysqli->real_escape_string($_POST['message']);
/* this query with escaped $post,$title will work */
if ($mysqli->query("INSERT into press (title, post) VALUES ('$post', '$title')")) {
printf("%d Row inserted.\n", $mysqli->affected_rows);
}
$mysqli->close();
//header("location:../admin");
?>

How to optimize a query with MySQL multi-query?

I need to optimize a script for high performance so the question is how can I add MySQL multi-query to this code?
foreach($multiContent as $htmlContent) {
$email = urldecode($email['1']);
$user = $user['1'];
//store in db
$db->query("UPDATE eba_users
SET mail = '$email'
WHERE username = '$user'");
//echo "email is $email and user is $user\n";
}
//close if ($array_counter % 200
unset($array_counter);
unset($data);
}
If you're using mysqli or PDO already, you should be using prepared statements for your queries since they are supported. This will also have a slight increase in performance since the entire query doesn't need to be sent again to the DB server. However the biggest advantage is the increased security that prepared statements provide.
Other than this, try adding an index on username to speed this query up if you haven't already.
Edit:
If you want to do it all in one query, as you seem to suggest, you could also use ON DUPLICATE KEY UPDATE as mentioned as an answer to this question:
INSERT INTO eba_users (`username`, `mail`)
VALUES
('username1','$email1'),
('username2','$email2'),
('username3','$email3'),
('username4','$email4'),
....
('usernameN','$emailN'),
ON DUPLICATE KEY UPDATE `mail`=VALUES(mail);
However this may not be as fast as using prepared statements with a regular UPDATE.
Edit2: As requested, here is probably a close approximation of what you should be doing to bind the parameters in mysqli:
if ($stmt = $mysqli->prepare("UPDATE eba_users SET mail= ? WHERE username= ?")) {
/* loop through array of users */
foreach ($array as $username => $newemail) {
/* bind parameters for markers */
$stmt->bind_param("ss", $newemail, $username);
/* execute query */
$stmt->execute();
}
}
Of course this doesn't provide any sort of error messages in case this fails. For that, you can look into mysqli::error

How to use mysql_real_escape_string function in PHP

So in this program I'm writing, I actually grab a SQL query from the user using a form. I then go on to run that query on my database.
I know not to "trust" user input, so I want to do sanitization on the input. I'm trying to use mysql_real_escape_string but have been unsuccessful in getting it to work.
Here's what I'm trying, given the input:
select * from Actor;
//"query" is the input string:
$clean_string = mysql_real_escape_string($query, $db_connection);
$rs = mysql_query($clean_string, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
This is ALWAYS giving me the
"Invalid input!"
error.
When I take out the clean_string part and just run mysql_query on query, the
"invalid
input"
message is not output. Rather, when I do this:
$rs = mysql_query($query, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
It does NOT output
"invalid input".
However, I need to use the mysql_real_escape_string function. What am I doing wrong?
Update:
Given
select * from Actor; as an input, I've found the following.
Using echo statements I've
found that before sanitizing, the string holds the value:
select * from Actor;
which is correct. However, after sanitizing it holds the incorrect
value of select *\r\nfrom Actor;, hence the error message. Why is
mysql_real_escape_string doing this?
use it on the actual values in your query, not the whole query string itself.
example:
$username = mysql_real_escape_string($_POST['username']);
$query = "update table set username='$username' ...";
$rs = mysql_query($query);
Rather than using the outdated mysql extension, switch to PDO. Prepared statement parameters aren't vulnerable to injection because they keep values separate from statements. Prepared statements and PDO have other advantages, including performance, ease of use and additional features. If you need a tutorial, try "Writing MySQL Scripts with PHP and PDO".
mysql_real_escape_string() is the string escaping function. It does not make any input safe, just string values, not for use with LIKE clauses, and integers need to be handled differently still.
An easier and more universal example might be:
$post = array_map("mysql_real_escape_string", $_POST);
// cleans all input variables at once
mysql_query("SELECT * FROM tbl WHERE id='$post[id]'
OR name='$post[name]' OR mtime<'$post[mtime]' ");
// uses escaped $post rather than the raw $_POST variables
Note how each variable must still be enclosed by ' single quotes for SQL strings. (Otherwise the escaping would be pointless.)
You should use mysql_real_escape_string to escape the parameters to the query, not the entire query itself.
For example, let's say you have two variables you received from a form. Then, your code would look like this:
$Query = sprintf(
'INSERT INTO SomeTable VALUES("%s", "%s")',
mysql_real_escape_string($_POST['a'], $DBConnection),
mysql_real_escape_string($_POST['b'], $DBConnection)
);
$Result = mysql_query($Query, $DBConnection);
manual mysql_real_escape_string()
Escapes special characters in a string
for use in an SQL statement
So you can't escape entire query, just data... because it will escape all unsafe characters like quotes (valid parts of query).
If you try something like that (to escape entire query)
echo mysql_real_escape_string("INSERT INTO some_table VALUES ('xyz', 'abc', '123');");
Output is
INSERT INTO some_table VALUES (\'xyz\',
\'abc\', \'123\');
and that is not valid query any more.
This worked for me. dwolf (wtec.co)
<?php
// add data to db
require_once('../admin/connect.php');
$mysqli = new mysqli($servername, $username, $password, $dbname);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$post = $mysqli->real_escape_string($_POST['name']);
$title = $mysqli->real_escape_string($_POST['message']);
/* this query with escaped $post,$title will work */
if ($mysqli->query("INSERT into press (title, post) VALUES ('$post', '$title')")) {
printf("%d Row inserted.\n", $mysqli->affected_rows);
}
$mysqli->close();
//header("location:../admin");
?>

Categories