Alright, so I believe that there is a better way that I can fetch an array from the database, here's the code right now that I have.
$id = 1;
$userquery = mysql_query("SELECT * FROM login WHERE id='$id'");
while($row = mysql_fetch_array($userquery, MYSQL_ASSOC)) {
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
So If I am not wrong, you want a better way to get all the returned rows from mysql in a single statement, instead of using the while loop.
If thats the case, then I must say mysql_ drivers do not provide any such functionality, which means that you have to manually loop through them using foreach or while.
BUT, since mysql_ is already depricated, you are in luck! you can actually switch to a much better and newer mysqli_ or the PDO drivers, both of which DO actually have functions to get all the returned rows.
For mysqli_: mysqli_result::fetch_all
For PDO : PDOStatement::fetchAll
Eg.
mysqli_fetch_all($result,MYSQLI_ASSOC);
// The second argument defines what type of array should be produced
// by the function. `MYSQLI_ASSOC`,`MYSQLI_NUM`,`MYSQLI_BOTH`.
Like the comments already told you: PHP's mysql driver is deprecated. And you should use prepared statements and parameters.
for example in PDO your code would look something like this:
//connection string:
$pdo= new PDO('mysql:host=localhost;dbname=my_db', 'my_user', 'my_password');
//don't emulate prepares, we want "real" ones:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//use exception-mode if you want to use exception-handling:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$id = 1;
//it's always better to strictly use backticks for db-names (db, tables, fields):
$sql = "SELECT * FROM `login` WHERE `id` = :id";
try
{
//create your prepared statement:
$stmt = $pdo->prepare($sql);
//bind a parameter and explicitly use a parameter of the type integer (in this case):
$stmt->bindParam(":id", $id, PDO::PARAM_INT);
//execute the query
$stmt->execute();
}
catch(PDOException $e)
{
exit("PDO Exception caught: " . $e->getMessage());
}
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
here you go: your PHP-MySQL routine is save against SQL-injections now and no longer uses deprecated PHP-functions! it's kinda state of the art ;)
Related
I'm trying to create a secure, SQL-injection proof connection to a database using PDO. I've know certain character sets are vulnerable, but that UTF-8 is not one of them. I also know that I should turn PDO's prepared statement emulation mode off. Below is the code that I've put together for the connection. My question is twofold.
Can someone please take a look at my code below to make sure that I'm doing everything correctly? I've tested it, and it works. But is there something else I could add to make it more secure or am I doing it right?
I'm not 100% positive that my syntax for what's inside the array is correct, though I don't get any errors when I do an insert, so I'm inclined to believe that it is. However, is there a way to test or confirm that those attributes are actually being set? Or can someone tell by looking that the syntax is correct and those attributes are definitely being set?
Thanks for any help in advance. My full code for the database connection and an insert using a prepared statement is below.
function addItem($category, $item, $price) {
$dsn = 'mysql:host=localhost;dbname=myDatabase;charset=utf8';
$username = "myUsername";
$password = "myPassword";
$options = array(
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
$link = new PDO($dsn, $username, $password, $options);
$query = $link->prepare("INSERT INTO items (category, item, price)
VALUES (:category, :item, :price)");
$query->bindParam(':category', $category);
$query->bindParam(':item', $item);
$query->bindParam(':price', $price);
$query->execute();
echo "New item added successfully";
}
catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
$link = null;
}
I just converted some MySQL to mysqli, but realized I do not have access to the mysqlnd driver with my server setup. So, I need to now convert to PDO which I have available.
I am trying to convert the following to PDO, but there is no bind_result available in PDO from what I have read. I need to use a prepared statement for this as there is user input.
$stmt = $mysqli->prepare("SELECT user,pass FROM test_users WHERE user = ?");
// bind params
$stmt->bind_param('s', $_POST['username']);
// execute prepared statement
$stmt->execute();
// Bind result variables
$stmt->bind_result($ruser, $rpass);
// fetch values
$stmt->fetch();
// close statement
$stmt->close();
Can anyone help out quick? Here is what I have, but not sure how to retrieve the resulting values into useable variables...
$stmt = $db->prepare("SELECT user,pass FROM test_users WHERE user = ?");
// bind params
$value = $_POST['username'];
// execute prepared statement
$stmt->execute($value);
// stmt now holds results, but how can I retrieve them into useable values?
// ?
// close statement
$stmt->closeCursor();
You need to make yourself familiar with arrays. They are no less "useable" than regular variables.
And sometimes arrays even more usable, especially in your case.
$stmt = $db->prepare("SELECT user, pass FROM test_users WHERE user = ?");
$stmt->execute([$_POST['username']]);
$row = $stmt->fetch();
Now $row contains the row returned by query. Now you can test if any data returned and then use it.
For the password check you can use it this way
if ($row && $row['pass'] === whatever_hash_used($_POST['password']]))
{
unset($row['pass']);
$_SESSION['user'] = $row;
// etc
}
You can return values from a PDO query with the PDOStatement::fetch method. There are various ways of fetching the data, such as into an array, into an object, and into a lazy-loading object. The simplest of these, and the most appropriate in your circumstance, is an array. In this case, you need to use the PDO::FETCH_ASSOC constant.
$results = $stmt->fetch(PDO::FETCH_ASSOC);
You can then access $results['user'] and $results['pass'].
A nice way of improving this would be to fetch $user and $pass variables rather than an array. This can be done with the list construct:
list($user, $pass) = $stmt->fetch(PDO::FETCH_NUM);
The other problem with your code (as Your Common Sense may or may not be pointing out in the comments: it's a little hard to tell) is that your code to bind the variables isn't quite right. PDOStatement::execute expects an array:
$stmt->execute(array($value));
$stmt->execute([$value]); // from PHP 5.4
In my opinion, the nicer way to do this is with named parameters:
$stmt = $db->prepare('SELECT user, pass FROM test_users WHERE user = :user');
$stmt->bindParam(':user', $_POST['username']);
$stmt->execute();
list($user, $pass) = $stmt->fetch(PDO::FETCH_NUM);
I want to create a dynamic sql statement and run it using PDO. My problem is that i have some parameters and i cannot think of a way to pass the parameters.
Ex :
$query = "Select * from tbl_task where 1=1";
if (!empty($name)) $query .= " AND name = ?";
if (!empty($status)) $query .= " AND status = ?"
$db_stmt = new PDOStatement();
$db_stmt = $this->db->prepare($query);
$db_stmt->bindParam (1,$name);
$db_stmt->bindParam (2,$status);
My parameters does not get binded and i don't know how many parameters i have to bind, unless i write the same if statements but with bindParam instructions.
I tryed with mysql_real_escape_string instead bindParam to PDO but for some reason my parameters are added empty.
Any idea on how can i build a dynamic query and bind parameters to PDO ?
Edit 1 :
$arr = array();
if (!empty($name)){
$query .= " AND `name` like :NAME";
$arr['NAME'] = $name;
}
$db_stmt = new PDOStatement();
$db_stmt = $this->db->prepare($query);
$db_stmt->execute($arr);
How can i write a "like" statement ? I tried
$query .= " AND `name` like :NAME" . "%";
and is not working.
What I usually do is the following:
$query = "Select * from `tbl_task` where 1=1";
$arr = array();
if (!empty($name))
{
$query .= " AND `name` = :NAME";
$arr['NAME'] = $name;
}
if (!empty($status))
{
$query .= " AND `status` = :STATUS";
$arr['STATUS'] = $status;
}
$this->db->beginTransaction();
try
{
$tmp = $this->db->prepare($query);
$tmp->execute($arr);
$this->db->commit();
}
catch(PDOException $ex)
{
$this->db->rollBack();
$this->log->error($ex->getMessage());
}
You can't add SQL code as a parameter; only data will do. You'll have to force these bits into $query. They won't be escaped then so they shouldn't contain user-submitted data.
What I usually do is the following:
$query = "Select * from tbl_task where 1=1";
if (!empty($name)) $query .= $db->parse(" AND name = ?s", $name);
if (!empty($status)) $query .= $db->parse(" AND status = ?s",$status);
$data = $this->db->getAll($query);
the idea is in having a function to parse placeholders in arbitrary query part instead of whole query.
I don't bother with native prepared statements though. They pollute PHP scripts with heaps of useless code with not a single benefit.
To answer updated question
as you've been told, you can't bind arbitrary query part. But a literal only.
So, make your literal looks like foo% and then bind it usual way.
Based on this question How to insert array into mysql using PDO and bindParam?
I'm trying to insert values of an array into mysql via PDO.
I'm having a hard time of it, because I keep getting the following error.
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
for this line $stmt->execute();
I'm guessing the problem has something to do with this line
$stmt->bindParam(':val$count', $val,PDO::PARAM_STR); Specifically 'val$count', but I'm not sure exactly what is going wrong.
QUESTION: What am I doing wrong? How can I fix this?
Anyway here is the code I'm using along with the sample array.
$lastInsertValue=87;
$qid[0][0]=1;
$qid[0][1]=1;
$qid[1][0]=2;
$qid[1][1]="null";
$qid[2][0]=3;
$qid[2][1]=0;
$array_count = count($qid);
if (isset($lastInsertValue))
{
try
{
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$stqid=array();
$a=0;
for ($i=0; $i<$array_count; $i++)
{
$stqid[$a]=$lastInsertValue;
$a++;
$stqid[$a]=$qid[$i][0];
$a++;
$stqid[$a]=$qid[$i][1];
$a++;
}
$sql = "INSERT INTO qresults (instance, qid, result) VALUES ( :val0, :val1, :val2)";
$count = 0;
$stmt = $dbh->prepare($sql);
foreach ($stqid as $val)
{
$stmt->bindParam(':val$count', $val,PDO::PARAM_STR);
$count++;
}
$stmt->execute();
$dbh = null;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
Yikes, so many issues.
Your array building is so verbose. Try this
$stqid = array();
foreach ($qid as $qidArr) {
$stqid[] = $lastInsertValue; // no idea why you repeat this
$stqid[] = $qidArr[0];
$stqid[] = $qidArr[1];
}
Use positional placeholders if you're simply relying on number of arguments
$sql = 'INSERT INTO ... VALUES (?, ?, ?)';
bindParam uses references which you are overwriting with each loop iteration. You would want to use bindValue() instead
Your query only has 3 placeholders but your $stqid array has 9 items. This is the source of your error.
You have single quotes around a variable, which will be treated as the variable name $count (not the value), try concatenating the variable to the string. Give this a try:
$stmt->bindParam(':val' . $count, $val,PDO::PARAM_STR);
for ($i=0; $i<$array_count; $i++)
{
$stqid[$a]=$lastInsertValue;
$a++;
$stqid[$a]=$qid[$i][0];
$a++;
$stqid[$a]=$qid[$i][1];
$a++;
}
so in case $i = 2, it will add $stqid[6], $stqid[7], $stqid[8] so
foreach ($stqid as $val)
{
$stmt->bindParam(':val$count', $val,PDO::PARAM_STR);
$count++;
}
will give you :val0 to :val8
In your query you have only :val0 to :val2.
Also having multiple values in one field in database is bad. Don't do it. Try to redesign your DB differently
EDIT: bad math in the morning... sorry
I'm using PHP to make a very specific sql query. For example sake, I have the user's ID number, but I need their name. So I do a sql query from that table with the ID number in order to return the name.
$result = mysql_query("SELECT name FROM users WHERE userID=$thisuserid",$db);
Now I want to use that. What's the most succinct way to go about making that result into a variable ths I can use?
edit:
I'm hoping that this is not the answer:
$rowCheck = mysql_num_rows($result);
if ($rowCheck > '0') {
while ($row = mysql_fetch_assoc($result)){
foreach ($row as $val){
$username = $val;
}
}
}
I have used something like this to keep it short in the past:
list($name) = mysql_fetch_row(mysql_query("SELECT name FROM users WHERE userID=$thisuserid",$db));
echo $name;
In my opinion, the best way to fetch any SQL result is through mysql_fetch_assoc(). To use it, you would do something like this:
$result = mysql_query("SELECT name FROM users WHERE userID=$thisuserid",$db);
while ($row = mysql_fetch_assoc($result)) {
echo $row['name']; // You get an array with each column returned from your query.
}
Still, MySQL extension has been replaced for MySQLi, which is acknowledged to be faster and more practical. It has both OOP and structural bindings, and takes more into account your server settings.
$result = mysql_query("SELECT name FROM users WHERE userID=$thisuserid",$db);
if (!$result) {
echo 'Could not run query: ' . mysql_error();
exit;
}
$name = mysql_fetch_row($result)[0];
You should use MySQLi as bellow:
$db = new MySQLi($host,$user,$pass,$db);
$query = $db->query('SELECT name FROM users WHERE userID='.$thisuserid);
$result = $query->fetch_object();
echo $result->name;
If you use SELECT * so you also can access via $result->{field_name}