how can I secure my search query with the prepare method?
DB Connection
// connect to database
$con = new mysqli("localhost", "root", "", "chat");
// Check connection
if ($con->connect_error) {
die("Connection failed: " . $con->connect_error);
}
MySQL Query
if (isset($_POST['query'])) {
$search_string = trim($_POST['query']);
$query = mysqli_real_escape_string($con, $search_string);
//MySQL order by best match
$sql = "SELECT reply FROM question_answer WHERE question
LIKE '%$query%'
ORDER BY CASE
WHEN question = '$query' THEN 0
WHEN question LIKE '$query%' THEN 1
WHEN question LIKE '%$query%' THEN 2
WHEN question LIKE '%$query' THEN 3
ELSE 4
END, question ASC";
$res = mysqli_query($con, $sql);
if (mysqli_num_rows($res) > 0) {
$row = mysqli_fetch_assoc($res);
$html = $row['reply'];
} else {
$html = "Sorry not be able to understand you";
$added_on = date('Y-m-d h:i:s');
mysqli_query($con, "INSERT INTO unknown_question(question,added_on,type) VALUES('$query','$added_on','user')");
}
echo $html;
die();
}
An example of using prepared queries with mysqli in your code could be like this:
if (isset($_POST['query'])) {
$sql = "SELECT reply FROM question_answer WHERE question LIKE ?
ORDER BY CASE
WHEN question = ? THEN 0
WHEN question LIKE ? THEN 1
WHEN question LIKE ? THEN 3
ELSE 2
END, question ASC";
$query = trim($_POST['query']);
$params = [
'%' . $query . '%',
$query,
$query . '%',
'%' . $query
];
$stmt = $con->prepare($sql);
$stmt->bind_param(str_repeat('s', count($params)), ...$params);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if (!empty($row)) {
$html = $row['reply'];
} else {
$html = "Sorry not be able to understand you";
$added_on = date('Y-m-d h:i:s');
$sql = "INSERT INTO unknown_question(question,added_on,type) VALUES(?,?,'user')";
$stmt = $con->prepare($sql);
$stmt->bind_param('ss', $query, $added_on);
$stmt->execute();
}
echo $html;
}
Related
I want to use prepared statements inside DataTables for the code stated below. It has two queries (query and query1).
Query has two "where conditions" which variables are $classid and $searchfield.
Query1 is a "Limit" statement and also has two variables $start and $end.
The results of both queries should be stored in the $data array. At the moment I don't get any results. How do I bind the paramteres correctly in this case and store the results in the array so DataTables gets a working json?
My try:
$connect = mysqli_connect("localhost", "xxxx", "xxx", "xxx");
$columns = array('itemOverview.id', 'itemOverview.Display_lang');
// Variables to bind
$classid = 4;
$searchfield = $_POST["is_searchfield"];
$start = $_POST['start'];
$end = $_POST['length'];
$query = "SELECT * FROM itemOverview INNER JOIN item ON item.id = itemOverview.id";
$query.= " WHERE item.ClassID = ? AND ";
if(!empty($searchfield)) {
$query .= "itemOverview.Display_lang = ? AND ";
}
$query1 = '';
if($_POST["length"] != -1) {
$query1 = 'LIMIT ?, ?';
}
$stmt = mysqli_stmt_init($connect);
if (!mysqli_stmt_prepare($stmt, $query. $query1)) {
echo "SQL Failed";
} else {
// bind paramaters to the placeholder
mysqli_stmt_bind_param($stmt, "ssss", $classid, $searchfield, $start, $end);
// run parameters inside database
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$data = array();
while($row = mysqli_fetch_array($result))
{
$sub_array = array();
$sub_array[] = $row["id"];
$sub_array[] = $row["Display_lang"];
$data[] = $sub_array;
}
}
$output = array(
"draw" => intval($_POST["draw"]),
"data" => $data
);
echo json_encode($output);
This question already has an answer here:
Writing a PDO search query from a PHP array
(1 answer)
Closed 2 years ago.
I am playing with the PDO option of PHP, and I am finding it strange it does not work. I think it is because of the binding of parameters, but I am not sure. Can anyone help me please.
if(isset($_POST['submit']))
{
$query = "SELECT * FROM occasions WHERE naam IS NOT NULL";
$stmt = $pdo->prepare($query);
if (isset($_POST['merk'])) {
$query .= " AND merk = :merk";
$merk = $_POST['merk'];
$stmt->bindParam(':merk', $merk);
}
if($stmt->execute())
{
echo "query is executed";
print_r($query);
}
else
{
echo "query is niet executed";
}
while($result = $stmt->fetch())
{
echo "<br>";
echo $result['naam'];
}
}
Here is a better way to frame your code. Try this. I believe this will work.
$merk = (!empty($_POST['merk']))?$_POST['merk']:null;
$brandstof = (!empty($_POST['brandstof']))?$_POST['brandstof']:null;
if(isset($_POST['submit'])){
$query = "SELECT * FROM occassions WHERE naam IS NOT NULL";
if($merk != null){
$query .= " AND merk = :merk";
}
if($brandstof != null){
$query .= " AND brandstof = :brandstof";
}
$stmt = $pdo->prepare($query);
if($merk != null){
$stmt-> bindValue(':merk', $merk);
}
if($brandstoff != null){
$stmt-> bindValue(':brandstof', $brandstof);
}
$stmt-> execute();
while($result = $stmt->fetch()){
echo "<br>";
echo $result['naam'];
}
}
I have this code for a multiple insert query (I have to transfer data from db to another and makes some update, so I wanna use a code that could do all this automatically)
$query = "select * from pubblicate order by idPubblicate asc";
$dbh = newPdo2();
$dbh->exec("set names utf8");
$sth = $dbh->prepare($query);
$sth->execute();
$count = 0;
$query2 = "insert into published_offer
(codice_onshop,nome,inbreve,anteprima,
galleria1,galleria2,galleria3,galleria4,prezzo,
tp_prezzo,bonus_usabile,proposta,condizioni,
prenotare,categoria,description,keywords,
valido_da,valido_a) ";
while($offerta = $sth->fetch(PDO::FETCH_ASSOC)) {
$array[$count]['id'] = $offerta['idPubblicate'];
$array[$count]['co'] = $offerta['codiceOfferta'];
$array[$count]['no'] = $offerta['nomeOfferta'];
$array[$count]['ib'] = $offerta['inBreve'];
$array[$count]['ke'] = $offerta['keywords'];
$array[$count]['de'] = $offerta['description'];
$array[$count]['pr'] = $pfferta['prezzo'];
$array[$count]['pe'] = $offerta['persona'];
$array[$count]['da'] = $offerta['daTimer'];
$array[$count]['a'] = $offerta['aTimer'];
$array[$count]['an'] = $offerta['anteprima'];
$array[$count]['g1'] = $offerta['galleria1'];
$array[$count]['g2'] = $offerta['galleria2'];
$array[$count]['g3'] = $offerta['galleria3'];
$array[$count]['g4'] = $offerta['galleria4'];
$array[$count]['pro'] = $offerta['proposta'];
$array[$count]['con'] = $offerta['condizioni'];
$array[$count]['pre'] = $offerta['prenotare'];
$array[$count]['bo'] = 999;
if($offerta['italia']=="Sì") $array[$count]['ca'] = "ita";
else if($offerta['europa']=="Sì") $array[$count]['ca'] = "eur";
else if($offerta['mondo']=="Sì") $array[$count]['ca'] = "mon";
$count++;
}
$query2 .= "values (:co,:no,:ib,:an,:g1,:g2,
:g3,:g4,:pr,:pe,:bo,:pro,:con,
:pre,:ca,:de,:ke,:da,:a)";
$dbh = newPdo();
$dbh->exec("set names utf8");
$sth = $dbh->prepare($query2);
$i=0;
echo $array[0]['no'] . " " . count($array) . " " . $array[125]['no'] . "<br>" . $query2 . "<br>";
while($i<count($array)) {
$sth->bindParam(":co", $array[$i]['co']);
$sth->bindParam(":no", $array[$i]['no']);
$sth->bindParam(":ib", $array[$i]['ib']);
$sth->bindParam(":an", $array[$i]['an']);
$sth->bindParam(":g1", $array[$i]['g1']);
$sth->bindParam(":g2", $array[$i]['g2']);
$sth->bindParam(":g3", $array[$i]['g3']);
$sth->bindParam(":g4", $array[$i]['g4']);
$sth->bindParam(":pr", $array[$i]['pr']);
$sth->bindParam(":pe", $array[$i]['pe']);
$sth->bindParam(":bo", $array[$i]['bo']);
$sth->bindParam(":pro",$array[$i]['pro']);
$sth->bindParam(":con",$array[$i]['con']);
$sth->bindParam(":pre",$array[$i]['pre']);
$sth->bindParam(":ca", $array[$i]['ca']);
$sth->bindParam(":de", $array[$i]['de']);
$sth->bindParam(":ke", $array[$i]['ke']);
$sth->bindParam(":da", $array[$i]['da']);
$sth->bindParam(":a", $array[$i]['a'] );
$sth->execute();
$i++;
}
But this code doesn't work. I've also tried to use try-catch(PDOException) for $sth->execute() but it doesn't show me anything.
Why?
Who says "this question is a duplicated" doesn't read really the question. Infact the error was a wrong character: $array[$count]['pr'] = $pfferta['prezzo'] would be been $array[$count]['pr'] = $offerta['prezzo']so I couldn't find an answer in another question.
Try adding some simple checks that things actually worked like this
$res = $sth->execute();
if ( ! $res ) {
echo sprintf('ERROR: %d - %s', $sth->errorCode(), $sth->errorInfo() );
}
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
i had a sql injection in my code, i checked it with havji.
so i was thinking of a fix, and i set the type of my values to integers or strings
like this. would this do the trick ? like no more injections ??? NOTHING TO WORRY ABOUT ?
my code IS below,
sorry for my bad english!
function get_page_by_id($page_id) {
settype($page_id, "integer");
global $connection;
$query = "SELECT * ";
$query .= "FROM pages ";
$query .= "WHERE id=" . $page_id ." ";
$query .= "LIMIT 1";
$result_set = mysql_query($query, $connection);
confirm_query($result_set);
// REMEMBER:
// if no rows are returned, fetch_array will return false
if ($page = mysql_fetch_array($result_set)) {
return $page;
} else {
return NULL;
}
}
CODE BEFORE FIX
function get_page_by_id($page_id) {
global $connection;
$query = "SELECT * ";
$query .= "FROM pages ";
$query .= "WHERE id=" . $page_id ." ";
$query .= "LIMIT 1";
$result_set = mysql_query($query, $connection);
confirm_query($result_set);
// REMEMBER:
// if no rows are returned, fetch_array will return false
if ($page = mysql_fetch_array($result_set)) {
return $page;
} else {
return NULL;
}
}
What you normally want to do is use a prepared statement instead. For php you can read about one option here.
Here is the example from that page
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
// insert another row with different values
$name = 'two';
$value = 2;
$stmt->execute();
?>
Try the following code:
$page_id = mysql_real_escape_string(stripslashes($page_id));
I have been trying to convert a php page to mysqli, and have encoutnered some problems. Given the code below, and the way which I have ordered things to work, I would like to know what the better way is using mysqli methods.
Is there an mysqli alternative to mysql_num_rows or is a different method of calculating the number of rows required?
How would I do the following using mysqli?:
$data = mysql_query($countQuery) or die(mysql_error());
$rowcount = mysql_num_rows($data);
What is an alternative for mysql_fetch_assoc? I feel that I should not be using the current rows method I am using, even if there is a replacement function, so what would be the correct approach?
I apologize for these questions, but I have not been able to determine the answers myself so far.
<?php
$con = mysqli_connect("localhost", "user", "", "ebay");
if (!$con) {
echo "Can't connect to MySQL Server. Errorcode: %s\n". mysqli_connect_error();
exit;
}
$con->query("SET NAMES 'utf8'");
$cmd = "word";
//normally retrieved from GET
if($cmd=="deleterec") {
$deleteQuery = "DELETE FROM AUCTIONS1 WHERE ARTICLE_NO = ?";
if ($delRecord = $con->prepare($deleteQuery)) {
$delRecord->bind_param("s", $pk);
$delRecord->execute();
}
}
$table = 'AUCTIONS';
$brand = "test";
$countQuery = "SELECT ARTICLE_NO FROM ? WHERE upper(ARTICLE_NAME) LIKE '% ? %'";
if ($numRecords = $con->prepare($countQuery)) {
$numRecords->bind_param("ss", $table, $brand);
$numRecords->execute();
$data = $con->query($countQuery) or die(print_r($con->error));
$rowcount = mysql_num_rows($data);
$rows = getRowsByArticleSearch($query, $table, $max);
$last = ceil($rowcount/$page_rows);
}
$self = htmlspecialchars($_SERVER['PHP_SELF'],ENT_QUOTES,'utf-8');
foreach ($rows as $row) // print table rows {
echo '<tr>' . "\n";
echo '<td>'.$row['USERNAME'].'</td>' . "\n";
// repeated for each column
}
function getRowsByArticleSearch($searchString, $table, $max) {
global $con;
$recordsQuery = "SELECT ARTICLE_NO, USERNAME, ACCESSSTARTS, ARTICLE_NAME, date_format(str_to_date(ACCESSSTARTS, '%d/%m/%Y %k:%i:%s'), '%d %m %Y' ) AS shortDate FROM ? WHERE upper(ARTICLE_NAME) LIKE '%?%' ORDER BY str_to_date(ACCESSSTARTS, '%d/%m/%Y %k:%i:%s')" . $max;
if ($getRecords = $con->prepare($recordsQuery)) {
$getRecords->bind_param("ss", $searchString, $table);
$getRecords->execute();
$getRecords->bind_result($ARTICLE_NO, $USERNAME, $ACCESSSTARTS, $ARTICLE_NAME, $shortDate);
while ($getRecords->fetch()) {
$result = $con->query($recordsQuery);
$rows = array();
while($row = mysql_fetch_assoc($result)) {
$rows[] = $row;
}
return $rows;
}
}
}
I usually use this directly after my execute:
$query->execute();
// store the result first
$query->store_result();
$rows = $query->num_rows;
Actually, to answer the first question:
$data = mysql_query($countQuery) or die(mysql_error());
$rowcount = mysql_num_rows($data);
If you want to do this using mysqli, mysqli_num_rows works just fine. The only difference is, remember to put the connection parameter in the query.
$data = mysqli_query($dbc,$countQuery) or die(mysql_error());
I've rewritten your code sample with the correct property / function calls to fix the two issues that you mention in the question:
<?php
$con = mysqli::connect("localhost", "user", "", "ebay");
if (!$con) {
echo "Can't connect to MySQL Server. Errorcode: %s\n". mysqli_connect_error();
exit;
}
$con->query("SET NAMES 'utf8'");
$cmd = "word";
//normally retrieved from GET
if($cmd=="deleterec") {
$deleteQuery = "DELETE FROM AUCTIONS1 WHERE ARTICLE_NO = ?";
if ($delRecord = $con->prepare($deleteQuery)) {
$delRecord->bind_param("s", $pk);
$delRecord->execute();
}
}
$table = 'AUCTIONS';
$brand = "test";
$countQuery = "SELECT ARTICLE_NO FROM ? WHERE upper(ARTICLE_NAME) LIKE '% ? %'";
if ($numRecords = $con->prepare($countQuery)) {
$numRecords->bind_param("ss", $table, $brand);
$numRecords->execute();
$data = $con->query($countQuery) or die(print_r($con->error));
// Here is the property that you can reference to determine the affected rows from the previous query. -- gabriel
$rowcount = $data->num_rows;
$rows = getRowsByArticleSearch($query, $table, $max);
$last = ceil($rowcount/$page_rows);
}
$self = htmlspecialchars($_SERVER['PHP_SELF'],ENT_QUOTES,'utf-8');
foreach ($rows as $row) // print table rows {
echo '<tr>' . "\n";
echo '<td>'.$row['USERNAME'].'</td>' . "\n";
// repeated for each column
}
function getRowsByArticleSearch($searchString, $table, $max) {
//global $con; Globals are BAD!! Please don't use.
$con = mysqli::connet("localhost", "user", "", "ebay");
$recordsQuery = "SELECT ARTICLE_NO, USERNAME, ACCESSSTARTS, ARTICLE_NAME, date_format(str_to_date(ACCESSSTARTS, '%d/%m/%Y %k:%i:%s'), '%d %m %Y' ) AS shortDate FROM ? WHERE upper(ARTICLE_NAME) LIKE '%?%' ORDER BY str_to_date(ACCESSSTARTS, '%d/%m/%Y %k:%i:%s')" . $max;
if ($getRecords = $con->prepare($recordsQuery)) {
$getRecords->bind_param("ss", $searchString, $table);
$getRecords->execute();
$getRecords->bind_result($ARTICLE_NO, $USERNAME, $ACCESSSTARTS, $ARTICLE_NAME, $shortDate);
while ($getRecords->fetch()) {
$result = $con->query($recordsQuery);
$rows = array();
// Notice the adjusted function call to retrieve the associate array for each record within the result set. -- gabriel
while($row = $result->fetch_assoc()) {
$rows[] = $row;
}
return $rows;
}
}
}
However, I would like to add that dusoft was correct in the assessment that MySQLi is buggy and is known to create issues. It is for this reason that we had to switch from MySQLi to PDO (which is native to PHP as of at least 5.1) and we haven't had any problems since. I would strongly recommend that you look at PDO or perhaps one of the Pear libraries to actually provide your database connection interface.
You can use:
$data->num_rows();
$data->fetch_assoc();
You can check out the docs for more info num_rows and fetch_assoc.