I have this function that should just look in the database for a name similars to an user input. However I can't use Like with the param :uname.
Everyone I look in the web they suggest me to do something like this
$username = "$%username%";
However the query doesn't return any result.
I know the database is properly made because if I ask this, it returns the proper answer
SELECT * FROM $schema.pessoa WHERE nome LIKE %Mike%
However in my code $username contains "Mike" and yet it doesn't return anything, I assumed %username hadn't be properly made however if I make an echo of it, it indeed contains the string I want- "Mike".
So the problem seems to be in the way I am questioning it with the parameter but I have no idea
function SearchUser($username) {
global $dbh, $schema;
try {
$username = "$%username%";
$stmt = $dbh->prepare("SELECT * FROM $schema.pessoa WHERE nome LIKE :uname");
$stmt->bindParam(':uname', $username);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if(empty($result))
{echo 'empty';}
return $result;
}
catch(PDOException $e) {
$_SESSION["s_errors"]["generic"][] = "ERRO[32]: ".$e->getMessage();
header("Location: list.php");
die;
}
It does look right to me,
I could only suggest you try it this way and see if that makes any difference
$username = 'Mike';
$stmt->bindValue(":uname", "%".$username."%");
Edit.
Looking at it again, this doesn't look right to me..
$username = '$%username%';
Shouldn't it be
$username = '%'.$username.'%';
Related
I'm having problems in understanding a part of the meaning of binding certain variable types in PDO and mysqli if the type given, in my case, seems to be meaningless. In the following code, the type bound (like i or s) gets ignored. The table row "wert_sortierung" in the database is INT(11). Regardingless if $val_int is really integer or not and if I bind it via i,s / PDO::PARAM_INT or _STR, the query always works, no break, no error or warning, that the types in the binding and database or variable itself don't fit.
<?
class PDOTest {
protected $pdo;
function __construct(){
$usr="usr";
$pwd="pwd";
$host="localhost";
$db="db";
$val_int="I'm a string";
$val_str="OP";
$querystring="SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = ? AND wert_CD = ?";
try {
$db_info = "mysql:host=$host;dbname=$db"; // usually provided via require_once and during construction
$this->pdo = new PDO($db_info, $usr, $pwd);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $this->pdo->prepare($querystring);
$stmt->bindValue(1,$val_int,PDO::PARAM_INT);
$stmt->bindValue(2,$val_str,PDO::PARAM_STR);
$stmt->execute();
$row_return = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->varprint($row_return);
$this->pdo = NULL;
}
catch (PDOException $ex) {
printf ('Es spricht:');
$this->printerror("Fehla! (" . $ex->getMessage() . ")");
$this->pdo = NULL;
exit();
}
printf("<br />-------<br />");
//Added for comparison
$mysqli = new mysqli($host, $usr, $pwd, $db);
$m_stmt = $mysqli->prepare($querystring);
$m_stmt->bind_param('is',$val_int, $val_str);
$m_stmt->execute();
$m_stmt->bind_result($row_return);
$m_stmt->fetch();
$this->varprint($row_return);
$m_stmt->close();
$mysqli->close();
}
private function printerror($txt) {
printf("<p><font color=\"#ff0000\">%s</font></p>\n",
htmlentities($txt));
}
private function varprint($var) {
echo "<br />";
echo "<pre>";
echo var_dump($var);
echo "</pre>";
}
}
new PDOTest();
?>
Please can anyone point out my error in reasoning.
It is actually Mysql's loose-typing that that deceived you.
As a matter of fact, regular Mysql queries can accept strings for the numberic values all right:
SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = '1' AND wert_CD = '1';
while prepared statement just following this behavior.
However, a contrary situation is not that harmless. Addressing a string value with a number
SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = 1;
will cause infinite number of warnings in case of wert_sortierung being of string type and some unexpected behavior, like matching for ALL the rows.
So, as a general advise I would suggest to always use 's' by default. The only drawback is PDO's emulated prepares and it can be easily worked around.
So, to answer your question explicitly - prepared statements just allow the same behavior as regular queries, adding nothing to it. Everything that possible with a regular query, is possible with prepared statement as well. And no, binding do not validate your data (however it should. Imn my class I test integer placeholders and throw an exception if no numeric value given)
After a lot of recommendation from others I have decided to make the switch from mysql_ to PDO. I started looking at PDO literally around 15 minutes ago and I'm stuck trying to convert this line of code into PDO format.
function verify_user($username, $recover_password) {
return (mysql_result(mysql_query("SELECT COUNT(`user_id`) FROM `users` WHERE `username` = '$username' AND `password_recovery` = '$recover_password'"), 0) == 1) ? true : false;
}
I have looked at a couple of tutorials and as far as I can work out I can do the actual query with this code:
$verify_user = "SELECT COUNT(`user_id`) FROM `users` WHERE `username` = '$username' AND `password_recovery` = '$recover_password'";
$result = $con->prepare($verify_user);
$result->execute();
The problem I am having is the second part of the line of code - the mysql_result. Now that the query has run I have no idea how to return true or false using PDO. I'd appreciate any help. Thanks!
Updated:
$result = $con->prepare("SELECT COUNT(`user_id`) FROM `users` WHERE `username` = :username AND `password_recovery` = :recover_password");
$result->bindParam(':username', $username, PDO::PARAM_STR);
$result->bindParam(':password_recovery', $recover_password, PDO::PARAM_STR);
$result->execute();
From reading that page you provided it would be:
$result = $con->prepare("SELECT COUNT(`user_id`) FROM `users` WHERE `username` = :username AND `password_recovery` = :recover_password");
$result->bindParam(':username', $username, PDO::PARAM_STR);
$result->bindParam(':password_recovery', $recover_password, PDO::PARAM_STR);
$result->execute();
return ($con->fetch($result) == 1) ? true : false;
I'm probably miles out but I appreciate the help you've given me :) I'll do a couple more searches.
I would write the function this way:
function verify_user($username, $recover_password) {
$sql = "SELECT COUNT(`user_id`) AS count FROM `users`
WHERE `username` = ? AND `password_recovery` = ?";
$stmt = $con->prepare($sql);
$stmt->execute(array($username, $recover_password));
while ($row = $stmt->fetch()) { } /* should be exactly one row anyway */
return $row["count"] == 1;
}
There's no need to use bind_param(), since you can just pass values in an array argument to execute(). And there's no need to specify the parameter type (that's actually ignored, at least in the MySQL PDO driver).
Also be careful to do error-checking. The prepare() and execute() functions return false on error. Many things can cause an error. You could misspell a column name. Your database connection may lack the right database privileges. Someone could drop the table.
FWIW, proper error-checking is important when using the mysql_* and mysqli_* API's too, but it seems that few people do it right.
In the above code, I don't show checking the return values because I've made an assumption that we've enabled exceptions when we created the PDO connection.
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
That relieves us of having to write code to check the return values every time, but it means that an error will cause our application to go "white-screen". It's best practice to handle the exceptions in the caller function, and display some friendly error screen.
Hi It seems that both bindParam or bindValue methods will not work.
Please advise. I tried to bind the $dbname to dbtest. It does not seem to work!
bindParam
$dbname = "test1";
$stmt=$dbh->prepare('use :dbtest');
$stmt->bindParam(':dbtest', $dbname, PDO::PARAM_STR);
$firephp->fb($stmt);
try
{ $stmt->execute();
$stmt=$dbh->prepare('select database()');
$stmt->execute();
$count = $stmt->fetch(PDO::FETCH_ASSOC);
$firephp->warn("Attempting to use selected database is successful.");
}
bindValue
$dbname = "test1";
$stmt=$dbh->prepare('use :dbtest');
$stmt->bindValue(':dbtest', $dbname, PDO::PARAM_STR);
$firephp->fb($stmt);
try
{ $stmt->execute();
$stmt=$dbh->prepare('select database()');
$stmt->execute();
$count = $stmt->fetch(PDO::FETCH_ASSOC);
$firephp->warn("Attempting to use selected database is successful.");
$firephp->fb($count);
}
What could be the problem?
First, native prepared statements won't work for identifiers
Second, there is no point in having dynamically bound databases. They are supposed to be constant.
So, select your database in DSN and then use bindValue to bind values in the query.
I changed this login script to PDO. Now it passes the username but get's stuck fetchAll line. I need help please. thanks
<?php
session_start();
include_once"includes/config.php";
if (isset($_POST['admin_login'])) {
$admin_user = trim($_POST['admin_user']);
$admin_pw = trim($_POST['admin_pw']);
if ($admin_user == NULL OR $admin_pw == NULL) {
$final_report.="Please complete all the fields below..";
} else {
$check_user_data = $db->prepare("SELECT * FROM `admin`
WHERE `admin_user`='$admin_user'");
$check_user_data->execute();
if ($check_user_data->fetchColumn() == 0) {
$final_report.="This admin username does not exist..";
} else {
$get_user_data = $check_user_data->fetchAll($check_user_data);
if ($get_user_data['admin_pw'] == $admin_pw) {
$start_idsess = $_SESSION['admin_user'] = "".$get_user_data['admin_user']."";
$start_passsess = $_SESSION['admin_pw'] = "".$get_user_data['admin_pw']."";
$final_report.="You are about to be logged in, please wait a few moments...";
header('Location: admin.php');
}
}
}
}
?>
Not checking return value prepare() or execute() for false. You need to check for SQL errors and handle them, stopping the code instead of continuing on blithely.
Not using query parameters in the prepared statement, still interpolating $_POST content into the query unsafely. You're missing the benefit of switching to PDO, and leaving yourself vulnerable to SQL injection attack.
You're storing passwords in plaintext, which is unsafe. See You're Probably Storing Passwords Incorrectly.
Do you really need to SELECT * if you only use the admin_pw column? Hint: no.
PDOStatement::fetchAll() returns an array of arrays, not just one array for a row. Read the examples in the documentation for fetchAll().
I want to optimize some of the SQL and just need an opinion on whether I should do it or leave it as is and why I should do it. SQL queries are executed via PHP & Java, I will show an example in PHP which will give an idea of what Im doing.
Main concerns are:
-Maintainability.
-Ease of altering tables without messing with all the legacy code
-Speed of SQL (is it a concern???)
-Readability
Example of what I have right now:
I take a LONG array from a customer (cant make it smaller unfortunately) and update the existing values with the new values provided by a customer in the following way:
$i = 0;
foreach($values as $value)
{
$sql = "UPDATE $someTable SET someItem$i = '$value' WHERE username='$username'";
mysql_query($sql, $con);
$i+=1;
}
Its easy to see from the above example that if the array of values is long, than I execute a lot of SQL statements.
Should I instead do something like:
$i = 0;
$j = count($values);
$sql = "UPDATE $someTable SET ";
foreach($values as $value)
{
if($i < $j) //append values to the sql string up to the last item
{
$sql .= "someItem$i = '$value', ";
}
$i+=1;
}
$sql .= "someItem$i = '$value' WHERE username='$username'"; //add the last item and finish the statement
mysql_query($sql, $con); //execute query once
OR which way should it be done / should I bother making these changes? (there a lot of the type and they all have 100+ items)
Thanks in advance.
The only way you'll get a definitive answer is to run both of these methods and profile it to see how long they take. With that said, I'm confident that running one UPDATE statement with a hundred name value pairs will be faster than running 100 UPDATE statements.
Don't run 100 seperate UPDATE statements!
Use a MySQL wrapper class which, when given an array of name => value pairs will return an SQL UPDATE statement. Its really simple. I'm just looking for the one we use now...
We use something like this (registration required) but adapted a little more to suit our needs. Really basic but very very handy.
For instance, the Update method is just this
/**
* Generate SQL Update Query
* #param string $table Target table name
* #param array $data SQL Data (ColumnName => ColumnValue)
* #param string $cond SQL Condition
* #return string
**/
function update($table,$data,$cond='')
{
$sql = "UPDATE $table SET ";
if (is_string($data)) {
$sql .= $data;
} else {
foreach ($data as $k => $v) {
$sql .= "`" . $k . "`" . " = " . SQL::quote($v) . ",";
}
$sql = SQL::trim($sql , ',');
}
if ($cond != '') $sql .= " WHERE $cond";
$sql .= ";";
return $sql;
}
If you can't change the code, make sure it is enclosed in transaction (if the storage engine is InnoDB) so no non-unique indexes will be updated before commiting transaction (this will speed up the write) and the new row won't be flushed to disk.
If this is MyISAM table, use UPDATE LOW_PRIORTY or lock table before the loop and unlock after read.
Of course, I'm sure you have index on the username column, but just to mention it - you need such index.