I have built a PDO connection and query, now I need it to be safe from SQL Injection
Here is my code
User Input
<?php $search=$_GET["Search"];?>
SQL that querys DB
<?php
// Issue the query
$Recordset1 = $dbh->query("SELECT * FROM catelogue
WHERE catelogue.TITLE LIKE '$search'");
$Recordset1->setFetchMode(PDO::FETCH_ASSOC);
?>
Fetch The rows
<?php $row_Recordset1 = $Recordset1-> fetch(); ?>
After this there is a table with a do-while loop to display everything that was returned
How do I make a prepared statement for my query?
Thanks
EDIT:
Ok That last bit of code that DavdRew posted helped to get my search working again. Now I have 2 new problems.
Problem 1: After doing a few querys I get this message
mysql_pconnect() [function.mysql-pconnect]: MySQL server has gone away
It still shows the rest of my page with what I searched for. How is this fixed?
Then Problem 2:
With every search the first record returned is empty, a blank record. It never did this before, Why is it doing it now?
Many Thanks DavdRew
EDIT: ADDED MORE CODE
THIS IS THE ENTIRE PDO CODE
<?php
$hostname_EchosPDO = "localhost";
$username_EchosPDO = "echos";
$password_EchosPDO = "echos";
$database_EchosPDO = "full catelogue";
$connStr = 'mysql:host=localhost;dbname=full catelogue';
try {
$dbh = new PDO($connStr, $username_EchosPDO, $password_EchosPDO);
/*** echo a message saying we have connected ***/
echo 'Connected to database';
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
<?php
$q = $dbh->prepare("SELECT * FROM catelogue WHERE catelogue.TITLE LIKE ?"); // prepare statement
if ($q->execute(array('sharpay%'))) // execute wirh passed params array($search)
{
$row_Recordset1 = $q->fetchAll(PDO::FETCH_ASSOC); // store fetched result into $rows;
}
else
{
$error = $dbh->errorInfo();
throw new Exception("SQLSTATE: {$error[0]}. {$error[1]} {$error[2]}");
}
?>
<?php /* $row_Recordset1 = $Recordset1-> fetch(); */ ?>
<?php do { ?>
<table width="800" border="0">
<tr>
<form action="/Echos Online/Detail.php" method="get"><input value='<?php echo $row_Recordset1['CAT NO.']; ?>' name="detail" type="hidden"/><td width='100' rowspan='4'><input type="image" img src="<?php echo $row_Recordset1['IMAGE PATH']; ?>" width="<?php if ($row_Recordset1['FORMAT']=='DVD') {echo "70";} else if ($row_Recordset1['FORMAT']=='DVD+CD') {echo "70";} else if($row_Recordset1['FORMAT']=='BLURAY+CD') {echo "81";}else if($row_Recordset1['FORMAT']=='BLURAY+DVD') {echo "81";} else if($row_Recordset1['FORMAT']=='BLURAY') {echo "81";} else {echo "100";} ?>" height="100"></td></form>
<td width="100">Artist:</td>
<td><?php echo $row_Recordset1['ARTIST']; ?></td>
</tr>
<tr>
<td width="100">Title</td>
<td><?php echo $row_Recordset1['TITLE']; ?></td>
</tr>
<tr>
<td width="100">Format</td>
<td><?php echo $row_Recordset1['FORMAT']; ?></td>
</tr>
<tr>
<td width="100">Cat. No.</td>
<td><?php echo $row_Recordset1['CAT NO.']; ?></td>
</tr>
<hr background-color="#e4a566" color="#e4a566"; width="100%"/>
<?php } while ($row_Recordset1 = $q-> fetch()); ?>
</table>
Honestly now I'm at the piont of going back to preg_replace and mysql_real_escape_string
Thanks for the help
Like this:
$q = $this->pdo->prepare($query);
$data = array();
if ($q->execute($params)) // params is the array of values for each '?' in your prepared statement.
$data = $q->fetchAll($fetch);
else
{
$error = $this->pdo->errorInfo();
throw new \Exception("SQLSTATE: {$error[0]}. {$error[1]} {$error[2]}");
}
return $data;
Keep in mind that WHERE IN works bad, you need to put as much ? into you imploded by , and wrapped with IN ( from left and ) right.
Example:
$statement = $pdo->prepare('SELECT * FROM my_table AS m WHERE m.id = ?');
if ($statement->execute(array(24))) // here you can pass values too.
$data = $q->fetchAll(\PDO::FETCH_ASSOC);
else
exit('Shit happens');
This search for record with id = 24;
For your code, that would be:
$q = $dbh->prepare("SELECT * FROM catelogue WHERE catelogue.TITLE LIKE ?"); // prepare statement
if ($q->execute(array($search))) // execute wirh passed params array($search)
{
$rows = $q->fetchAll(PDO::FETCH_ASSOC); // store fetched result into $rows;
}
else
{
$error = $dbh->errorInfo();
throw new Exception("SQLSTATE: {$error[0]}. {$error[1]} {$error[2]}");
}
Output:
<table width="800" border="0">
<?php foreach ($rows as $row): ?>
<tr>
<form action="/Echos Online/Detail.php" method="get"><input value='<?php echo $row['CAT NO.']; ?>' name="detail" type="hidden"/><td width='100' rowspan='4'><input type="image" img src="<?php echo $row['IMAGE PATH']; ?>" width="<?php if ($row['FORMAT']=='DVD') {echo "70";} else if ($row['FORMAT']=='DVD+CD') {echo "70";} else if($row['FORMAT']=='BLURAY+CD') {echo "81";}else if($row['FORMAT']=='BLURAY+DVD') {echo "81";} else if($row['FORMAT']=='BLURAY') {echo "81";} else {echo "100";} ?>" height="100"></td></form>
<td width="100">Artist:</td>
<td><?php echo $row['ARTIST']; ?></td>
</tr>
<tr>
<td width="100">Title</td>
<td><?php echo $row['TITLE']; ?></td>
</tr>
<tr>
<td width="100">Format</td>
<td><?php echo $row['FORMAT']; ?></td>
</tr>
<tr>
<td width="100">Cat. No.</td>
<td><?php echo $row['CAT NO.']; ?></td>
</tr>
<hr background-color="#e4a566" color="#e4a566"; width="100%"/>
<?php endforeach; ?>
</table>
$pdo = new PDO('mysql:host=localhost;dbname=mydb', $username, $password);
$stmt = $pdo->prepare('SELECT * FROM catelogue WHERE catelogue.TITLE LIKE :search');
$stmt->bindValue('search', $search);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
OR
$stmt = $pdo->prepare('SELECT * FROM catelogue WHERE catelogue.TITLE LIKE :search');
$stmt->execute(array('search' => $search);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
note that you probably want to have your $search string wrapped with wildcard characters, like
$stmt->bindValue('search', '%'.$search.'%');
also note that searching using like wont use index if you have wildcard on left side of like criteria
$stmt->bindValue('search', '%'.$search.'%'); //will not use index
$stmt->bindValue('search', $search.'%'); //will use index
Related
I need to add a form input to search for a second column in a table.
I have tried adding a form. Tried manually putting what I am looking for in the SELECT line and it finds the data. Just need to be able to find it with form input.
<?php
/**
* Mark as Paid
*/
require "../config.php";
require "../common.php";
$success = null;
if (isset($_POST["submit"])) {
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'])) die();
try {
$connection = new PDO($dsn, $username, $password, $options);
$itemnumber = $_POST["submit"];
$sql = "UPDATE consignsold SET paid='y' WHERE paid='n' AND sold='y' AND itemnumber = $itemnumber";
$statement = $connection->prepare($sql);
$statement->bindValue(':itemnumber', $itemnumber);
$statement->bindValue(':paid', $paid);
$statement->bindValue(':sold', $sold);
$statement->execute();
$success = "Item successfully updated";
} catch(PDOException $error) {
echo $sql . "<br>" . $error->getMessage();
}
}
try {
$connection = new PDO($dsn, $username, $password, $options);
$sql = "SELECT * FROM consignsold WHERE paid='n'";
$statement = $connection->prepare($sql);
$statement->execute();
$result = $statement->fetchAll();
} catch(PDOException $error) {
echo $sql . "<br>" . $error->getMessage();
}
?>
<?php require "templates/header.php"; ?>
<h2>Mark Items as Paid</h2>
<?php if ($success) echo $success; ?>
<style>
table, th, td {
border: 1px solid black;
}
</style>
<form method="post">
<input name="csrf" type="hidden" value="<?php echo escape($_SESSION['csrf']); ?>">
<table>
<thead>
<tr>
<th>Sale Number</th>
<th>Item Number</th>
<th>Lot Number</th>
<th>Category</th>
<th>Item Description</th>
<th>Reserve</th>
<th>Seller Number</th>
<th>Amount</th>
<th>Buyer Number</th>
<th>Sold</th>
<th>Paid</th>
<th>Mark</th>
</tr>
</thead>
<tbody>
<?php foreach ($result as $row) : ?>
<tr>
<td><?php echo escape($row["salenumber"]); ?></td>
<td><?php echo escape($row["itemnumber"]); ?></td>
<td><?php echo escape($row["lotnumber"]); ?></td>
<td><?php echo escape($row["category"]); ?></td>
<td><?php echo escape($row["itemdescription"]); ?></td>
<td><?php echo escape($row["reserve"]); ?></td>
<td><?php echo escape($row["sellernumber"]); ?></td>
<td><?php echo escape($row["amount"]); ?></td>
<td><?php echo escape($row["buyernumber"]); ?></td>
<td><?php echo escape($row["sold"]); ?></td>
<td><?php echo escape($row["paid"]); ?></td>
<td><button type="submit" name="submit" value="<?php echo escape($row["itemnumber"]); ?>">Mark as Paid</button></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</form>
<br>
<?php require "templates/footer.php"; ?>
If I try to add a form, I get a blank page. I expect a form with a place to input Buyer Number. As-is, the page works but displays all items and the operator has to manually find each item by buyer number and click the Mark as Paid button. What I need it to do is have an input where it asks for buyer number and only list those items with the mark button at the end. It is a closed-circuit operation so not worried about injections at this time.
The line: $sql = "SELECT * FROM consignsold WHERE paid='n'";
would be changed to something like: $sql = "SELECT * FROM consignsold WHERE paid='n' AND buyernumber = <from form input>";
Some have asked to clarify. . . I thought it was pretty clear to start with but. . .
REVISION: What I need on that page is a form input that asks the operator for a buyernumber and then uses the input from that form in the SELECT line to look for buyernumber and sold = 'y'. "buyernumber" is a column and "sold" is a column in the table: consignsold.
Thanks again to all who try to help!
I am not entirely sure, I understand your question, but let me answer what I see is wrong.
First of all you should not catch the exceptions. This is considered a bad practice.
You also do not need 3 binds, you can just pass $itemnumber in the execute(). For this however you need to put a placeholder in the query. ? is simpler than a named placeholder.
$connection = new PDO($dsn, $username, $password, $options);
$itemnumber = $_POST["submit"];
$sql = "UPDATE consignsold SET paid='y' WHERE paid='n' AND sold='y' AND itemnumber=?";
$statement = $connection->prepare($sql);
$statement->execute([$itemnumber]);
$success = "Item successfully updated";
I am using the following code to search in the site..I wish to display the message "no result found" when the query returns no result.What changings should i do in the code
My Code:
<?php
error_reporting(E_ALL ^ E_DEPRECATED);
if(isset($_REQUEST["submit"]))
{
$user = $_REQUEST["user"];
mysql_connect("localhost","root","");
mysql_select_db("iata");
$query=mysql_query("SELECT * FROM code WHERE airportcode LIKE '$user'");
$rowcount=mysql_num_rows($query);
?>
<table border="1" align="center">
<tr>
<td>City Name</td>
<td>3 Letter City Code</td>
<td>Airport Name</td>
<td>3 Letter Airport Code</td>
</tr>
<?php
for($i=1;$i<=$rowcount;$i++)
{
$row = mysql_fetch_array($query);
?>
<tr>
<td><?php echo $row["cityname"] ?></td>
<td><?php echo $row["citycode"] ?></td>
<td><?php echo $row["airportname"] ?></td>
<td><?php echo $row["airportcode"] ?></td>
</tr>
<?php
}
}
?>
</table>
<form method="POST">
<input type="text" name="user">
<input type="submit" name="submit" value="Submit">
</form>
You already uses the rowcount. Just check if the count is equal to 0 and you'll know if you have results or not.
More importantly, you are using mysql_* functions. It's advised to use mysqli_* functions instead for almost a decade, they are deprecated since PHP5.5 and have been removed since PHP7.0.
You should use mysqli_* function, or even better PDO :
try {
$db = new PDO('mysql:host=localhost;dbname=iata', 'root, '');
$stmt = $db->prepare("SELECT * FROM code WHERE airportcode LIKE ?");
$stmt->execute(array($user));
while ($row = $stmt->fetch()) {
// Your code here
}
$db = null;
} catch (PDOException $e) {
print "Error !: " . $e->getMessage() . "<br/>";
die();
}
Don't touch code with mysql_* functions in it, don't write it, don't copy it, don't give it to anyone, don't even poke it with a stick ! These functions are vulnerable and would render as vulnerable any application that relies on them !
Do this
if ($rowcount == 0) {
$message = "No Result";
}
Now you can echo $message anywhere on the page to display the message.
Add the following to your code where you want the message to appear:
if ($rowcount == 0) {
echo 'result set is = 0';
}
I have pagination for a table to display data from the database in the table. This was working fine and I tried to add in a button which only admin's can see. If the user is not an admin they will not see this button. This feature works but once I did it, the pagination only shows one row of data compared to the maximum of 10 per page.
This is my code:
public function dataview($query)
{
$stmt = $this->db->prepare($query);
$stmt->execute();
if($stmt->rowCount()>0) // display records if there are records to display
{
while($row=$stmt->fetch(PDO::FETCH_ASSOC))
{
$poll_id = $row['poll_id'];
$question = $row['question'];
?>
<tr>
<td><?php echo $row['poll_id']; ?></td>
<td><?php echo $row['question']; ?></td>
<td>Open Poll</td>
<td>Results</td>
<?php
$stmt = $this->db->prepare("SELECT * FROM users WHERE user_id=:user_id");
$stmt->execute(array(':user_id'=>$_SESSION['user_session']));
$userRow=$stmt->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() > 0){
$admin = $userRow['admin'];
if($admin == 1){
?>
<td>Delete Poll</td>
<?php
?>
</tr>
<?php
}
}
}
}
else
{
?>
<tr>
<td>Nothing here...</td>
</tr>
<?php
}
}
and this is the code on the html page which uses the pagination
<table align="center" border="1" width="100%" height="100%" id="data">
<?php
$query = "SELECT * FROM polls";
$records_per_page=10;
$newquery = $paginate->paging($query,$records_per_page);
$paginate->dataview($newquery);
$paginate->paginglink($query,$records_per_page);
?>
</table>
You are reusing variables like $stmt inside the loop that uses it. So do this:
$stmt = $this->db->prepare($query);
$stmt->execute();
if($stmt->rowCount()>0) // display records if there are records to display
{
while($row=$stmt->fetch(PDO::FETCH_ASSOC))
{
$poll_id = $row['poll_id'];
$question = $row['question'];
?>
<tr>
<td><?php echo $row['poll_id']; ?></td>
<td><?php echo $row['question']; ?></td>
<td>Open Poll</td>
<td>Results</td>
<?php
$stmt2 = $this->db->prepare("SELECT * FROM users WHERE user_id=:user_id");
$stmt2->execute(array(':user_id'=>$_SESSION['user_session']));
$userRow=$stmt2->fetch(PDO::FETCH_ASSOC);
if($stmt2->rowCount() > 0){
$admin = $userRow['admin'];
if($admin == 1){
?>
<td>Delete Poll</td>
<?php
?>
</tr>
<?php
}
}
}
}
else
{
?>
<tr>
<td>Nothing here...</td>
</tr>
<?php
}
I have replace the $stmt inside the loop by $stmt2.
I am attempting to create a discussion board, and am trying to display the number of topics and number of total posts in each forum. I believe the issue lies somewhere in my WHERE clause, as that was causing me issues before on a previous issue.
I know that rowCount() shouldn't be relied on, and in my case doesn't work anyway, mainly due to the fact that it doesn't work with SELECT statements.
I have looked into both SELECT count(*) statements as well as doing $row = $stmt->fetchAll(); $numrows = count($row) However, I didn't get either of them to work.
<?php
/* CATEGORIES */
/* SELECTS ALL OF THE CATEGORIES OF THE BOARD */
$query = "SELECT * FROM bkg_categories";
try {
$stmt = $db->prepare($query);
$result = $stmt->execute();
} catch(PDOException $e) {
$error[] = "An error has occured. Please try again later.";
}
$categories = $stmt->fetchAll();
/* FORUMS */
/* SELECT ALL OF THE FORUMS IN EACH CATEGORY FOR THE BOARD */
foreach($categories as $category) {
$catid = $category['category_id'];
$query = "SELECT * FROM bkg_forums WHERE category_id = :catid";
$query_params = array(':catid' => $catid);
try {
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
} catch(PDOException $e) {
$error[] = "An error has occured. Please try again later.";
}
$forums[$catid] = $stmt->fetchAll();
foreach($forums[$category['category_id']] as $forum) {
$query = "SELECT * FROM bkg_topics where forum_id = :forumid";
$query_params = array(':forumid' => $forum['forum_id']);
try {
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
} catch(PDOException $e) {
$error[] = "An error has occured. Please try again later.";
}
$rows3['forumid'] = $stmt->fetchAll();
$rowCount = count($rows3['forumid']);
echo $rowCount;
var_dump($rowCount);
}
}
/* END QUERIES */
?>
These are all of my select queries that I am using. In that last foreach loop in my PHP select queries, you can see what I was playing around with, the var_dump() and the echo works, when it's not inside any foreach loop except for the inital parent one, but once I move it down into my table, it doesn't seem to work.
<?php foreach($categories as $category): ?>
<table class="forumtable">
<tr>
<td colspan="2"><strong><?php echo $category['category_name']; ?></strong></td>
<td><strong>Lastest Post</strong></td>
<td><strong>Topics</strong></td>
<td><strong>Posts</strong></td>
</tr>
<?php foreach($forums[$category['category_id']] as $forum): ?>
<tr>
<td width="5%" class="forum"></td>
<td class="forum no-padding">
<?php echo $forum['forum_name']; ?>
<div class="description"><?php echo $forum['forum_desc']; ?></div>
</td>
<td width="15%" class="forum content">
<?php if($forum['forum_last_post_topic_id'] == 0): ?>
<div>No posts...</div>
<?php else: ?>
<?php if($forum['forum_last_post_id'] == 0): ?>
<?php echo substr($forum['forum_last_post_title'], 0, 10); ?>
<?php else: ?>
<?php echo substr($forum['forum_last_post_title'], 0, 10); ?>
<?php endif; ?>
<?php endif; ?>
</td>
<td width="5%" class="forum content">
<?php
echo $forum['forum_topics']; ?></td>
<td width="5%" class="forum content"><?php
echo $forum['forum_posts']; ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php endforeach; ?>
I was able to finally get the select(*) to work.
$db->query('SELECT COUNT(*) FROM users')->fetchColumn(); was what I used to get what I needed to work.
I am trying to set up a PHP MySQL search script which will let me print the content of my membership MySQL database table and then filter the results using different criteria.
The following fields are used in my MySQL table:
committee_id
rank
last_name
first_name
sex
address
email
phone_number
active_status
I want 2 ways to filter the data:
1) using using a drop down with all the available rank i can filter the results by rank of member.
2) using a drop down with all the available active_status you can filter the results by active status only.
I have set up my search form successfully, and printed all MySQL Table contents, Only the search by position part is filtering my result, but not the active_status, the filter part is a challenge. here is my html table and search script:
<?php include("./includes/connnect.php");?>
<!DOCTYPE HTML>
<html>
<body>
<table>
<thead>
<tr>
<td>ID</td>
<td>position</td>
<td>Last Name</td>
<td>First Name</td>
<td>Sex</td>
<td>Address</td>
<td><strong>Email</td>
<td><strong>Phone Number</td>
<td>Status</td>
</tr>
</thead>
<tbody>
<?php
if ($_REQUEST["position"]<>'') {
$search_position = " AND position='".mysql_real_escape_string($_REQUEST["position"])."'";
}
if ($_REQUEST["status"]<>'') {
$search_status = " AND status='".mysql_real_escape_string($_REQUEST["status"])."'";
}
else {
$sql = "SELECT * FROM ".$SETTINGS["data_table"]." WHERE committee_id>0".$search_position.$search_status;
}
$sql_result = mysql_query ($sql, $connection ) or die ('request "Could not execute SQL query" '.$sql);
if (mysql_num_rows($sql_result)>0) {
while ($row = mysql_fetch_assoc($sql_result)) {
?>
<tr>
<td><?php echo $row["committee_id"]; ?></td>
<td><?php echo $row["rank"]; ?></td>
<td><?php echo $row["last_name"]; ?></td>
<td><?php echo $row["first_name"]; ?></td>
<td><?php echo $row["sex"]; ?></td>
<td><?php echo $row["address"]; ?></td>
<td><?php echo $row["email"]; ?></td>
<td><?php echo $row["phone_number"]; ?></td>
<td><?php echo $row["active_status"]; ?></td>
</tr>
<?php
}
} else {
?>
<tr><td colspan="5">No results found.</td>
<?php
}
?>
</tbody>
</table>
</body>
</html>
I would appreciate any suggestions to get this going.
Thanks.
That is because when there is $_REQUEST["status"] the variable SQL is not setted as you put it on the else statement
if ($_REQUEST["status"]<>'') {
$search_status = " AND status='" .
mysql_real_escape_string($_REQUEST["status"])."'";
}
else { /// this is your problem
$sql = "SELECT * FROM ".$SETTINGS["data_table"]."
WHERE committee_id>0".$search_position . $search_status;
}
Put the $sql out of the else and take the else out.
Thank you Jorge your solution worked. But I got the same result with these elseif statements:
if ($_REQUEST["position"]<>'') {
$search_position = " AND position='".mysql_real_escape_string($_REQUEST["position"])."'";
}
if ($_REQUEST["status"]<>'') {
$search_status = " AND status='".mysql_real_escape_string($_REQUEST["status"])."'";
}
if ($_REQUEST["position"]<>'' and $_REQUEST["status"]<>'') {
$sql = "SELECT * FROM ".$SETTINGS["data_table"]."
WHERE position = '".mysql_real_escape_string($_REQUEST["position"])."'
AND status = '".mysql_real_escape_string($_REQUEST["status"])."'";
}else if ($_REQUEST["position"]<>'') {
$sql = "SELECT * FROM ".$SETTINGS["data_table"]." WHERE position = '".mysql_real_escape_string($_REQUEST["position"])."'".$search_city;
}else if ($_REQUEST["status"]<>'') {
$sql = "SELECT * FROM ".$SETTINGS["data_table"]." WHERE status = '".mysql_real_escape_string($_REQUEST["status"])."'".$search_position;
}else {
$sql = "SELECT * FROM ".$SETTINGS["data_table"]." WHERE committee_id>0".$search_position.$search_status;
}
I shall have to convert these to mysqli or pdo as advised.