Here's the relevant piece of my PHP code:
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//get values from AJAX
$whereCategory = isset($_GET['cat_code'])? "{$_GET['cat_code']}" : '';
$sortvalue = isset($_GET['sortvalue'])? "{$_GET['sortvalue']}" : '';
$sortorder = isset($_GET['sortorder'])? "{$_GET['sortorder']}" : '';
$sql = "select * from {$table} where cat_code = ':cat_code' order by ':sortvalue' ':sortorder';";
$stmt2 = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY) );
$stmt2->execute(array(':cat_code' => $whereCategory,':sortvalue' => $sortvalue, ':sortorder' => $sortorder));
$result = $dbh->query($sql)->fetchAll(PDO::FETCH_ASSOC);
header('Content-type: application/json');
echo json_encode($result);
If I var_dump the variables $where_category,$sortorder, and $sortvalue, they are all what I expect and the correct data that would need to be passed in the query. I've tried the query directly without PDO just substituting in the correct variables and I get back what I want, but apparently I'm not sending the variables correctly with my PDO methods (such as they are).
I'm getting no errors back, but no data returned either.
Any suggestions?
First off, named placeholders doesn't need to be quoted, so ditch those.
Secondly, you cannot bind identifiers (table/columns/DESC/ASC) You could only whitelist those.
Third, don't mix ->query() and ->execute(). Use ->execute() alone:
header('Content-type: application/json');
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//get values from AJAX
if(isset($_GET['cat_code'], $_GET['sortvalue'], $_GET['sortorder'])) {
$whereCategory = $_GET['cat_code'];
$sortvalue = $_GET['sortvalue'];
$sortorder = $_GET['sortorder'];
// super simple filtering
$default_tables = array('table1', 'table2', 'table3');
$default_columns = array('column1', 'column2', 'column3');
in_array(needle, haystack)
if(
in_array($table, $default_tables) &&
in_array($sortvalue, $default_columns) &&
in_array($sortorder, array('ASC', 'DESC'))
) {
// good to go
$sql = "SELECT * FROM $table where cat_code = :cat_code ORDER BY $sortvalue $sortorder";
$stmt2 = $dbh->prepare($sql);
$stmt2->execute(array(':cat_code' => $whereCategory));
echo json_encode($stmt2->fetchAll(PDO::FETCH_ASSOC));
} else {
// did not satisfy condition
}
}
Sidenote: Those default tables and columns are just examples, you'll need to populate and correspond it into yours. You could create your own method/function which creates a map with tables with their corresponding columns if you really want to be sure of it.
Change this -
$result = $dbh->query($sql)->fetchAll(PDO::FETCH_ASSOC);
to this -
$result = $stmt2->fetchAll(PDO::FETCH_ASSOC);
You're trying to run the query again when all you need to do is grab the results.
The query you are running is against a prepared statement which is incorrect, removing the query and assigning the result from the execute statement will work. There's also quite a few other problems in your php. Also using the input directly from the user such as the table (which appears to be undefined in this code snippet), sort order and sort value leaves you open to sql injection.
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//get values from AJAX
$whereCategory = isset($_GET['cat_code'])? $_GET['cat_code'] : '';
$sortvalue = isset($_GET['sortvalue'])? $_GET['sortvalue'] : '';
$sortorder = isset($_GET['sortorder'])? $_GET['sortorder'] : '';
/** you cannot use prepared statements for doing the order by */
$sql = "select * from $table where cat_code = :cat_code order by $sortvalue $sortorder;";
$stmt2 = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY) );
$query = $stmt2->execute(['cat_code' => $whereCategory]);
/** below line isn't needed because above on deals with it */
//$dbh->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$result = $query->fetchAll();
header('Content-type: application/json');
echo json_encode($result);
try without quotes:
$sql = "select * from {$table} where cat_code = :cat_code order by :sortvalue :sortorder;";
Use Like this
$result = $stmt2->fetchAll(PDO::FETCH_ASSOC);
Related
I'm using an internal switch to determine the sort order of my results and have just discovered that you can't use PDO to bind certain params (like selecting a table or specifying a sort order) in this way.
So I'm now trying to return my results without binding using ->query like this (ignoring the sort part for now) :
$results = $db->query("SELECT * from tracks WHERE online = 1", PDO::FETCH_ASSOC);
But when I print_r($results) I'm just getting the PDO object statement back :
PDOStatement Object
(
[queryString] => SELECT * from tracks WHERE online = 1
)
What am I doing wrong here?
Here is my PDO connection :
protected static function getDB()
{
static $db = null;
if ($db === null) {
$dbhost = getenv('DB_HOST');
$dbuser = getenv('DB_USER');
$dbpass = getenv('DB_PASS');
$dbname = getenv('DB_NAME');
try {
$db = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=utf8mb4",
$dbuser, $dbpass);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
return $db;
}
the statement needs to be executed ...
$stmt = $db->query("SELECT * from tracks WHERE online = 1");
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
passing it as second argument should also work:
$stmt = $db->query("SELECT * from tracks WHERE online = 1", PDO::FETCH_ASSOC);
$data = $stmt->fetchAll();
or as one-liner:
$data = $db->query("SELECT * from tracks WHERE online = 1")->fetchAll(PDO::FETCH_ASSOC);
there's also:
$stmt->setFetchMode(PDO::FETCH_ASSOC);
PDO::query manual shows you how to work with results, returned by query method:
$results = $db->query("SELECT * from tracks WHERE online = 1", PDO::FETCH_ASSOC);
foreach ($results as $row) {
print $row;
}
I'm trying to select data where by acc_id
What I get in my localhost: []
However, when I set a specific acc_id i get the correct row is there something in my syntax?
<?php
header('Access-Control-Allow-Origin: *');
// Define database connection parameters
$hn = 'localhost';
$un = 'root';
$pwd = '';
$db = 'ringabell';
$cs = 'utf8';
// Set up the PDO parameters
$dsn = "mysql:host=" . $hn . ";port=3306;dbname=" . $db . ";charset=" . $cs;
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
PDO::ATTR_EMULATE_PREPARES => false,
);
// Create a PDO instance (connect to the database)
$pdo = new PDO($dsn, $un, $pwd, $opt);
$data = array();
// Attempt to query database table and retrieve data
try {
$acc_id = $pdo->prepare('SELECT acc_id FROM account_info');
$stmt = $pdo->prepare('SELECT p_fname, p_lname, p_condition FROM patient_info WHERE acc_id = "$acc_id"');
$stmt->execute([$acc_id]);
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// Assign each row of data to associative array
$data[] = $row;
}
// Return data as JSON
echo json_encode($data);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
It seems like you want to use the prepared statement but instead executing your query instantly. If you want to bind the value to your query use something like this:
$acc_id = // get the $acc_id value from somewhere you want
$stmt = $pdo->prepare('SELECT p_fname, p_lname, p_condition FROM patient_info WHERE acc_id = ?');
$stmt->execute([$acc_id]);
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// Assign each row of data to associative array
$data[] = $row;
}
Example with using a placeholder
Instead of executing your statement with the array of params, you could also use the bindValue() or the bindParam() method:
$stmt = $pdo->prepare('SELECT p_fname, p_lname, p_condition FROM patient_info WHERE acc_id = :acc_id');
$stmt->bindValue(':acc_id', $acc_id);
$stmt->execute();
// everything else works as previous
The difference between these two methods is written in docs:
bindValue():
Binds a value to a corresponding named or question mark placeholder in the SQL statement that was used to prepare the statement.
bindParam():
Binds a PHP variable to a corresponding named or question mark placeholder in the SQL statement that was used to prepare the statement. Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
Why is this not working:
function listOrderComments ($factnr){
global $connection;
//$factnr = 123; //or $factnr = "123"; (Both work)
$query = "SELECT * FROM orderstatus WHERE factuurnummer = '$factnr'";
$result = mysqli_query($connection, $query);
When I echo $factnr I get "123" back.
When I uncommented //$factnr = 123; my function is working.
Looked everywhere for a solution. check the type $factnr is (string).
Well if you're using a variable in your query you're opening yourself up to an injection attack for one.
If you're going to be using that variable I would recommend you use bind_param for your query
Read the PHP manual link below and you will be able to figure out the issue
http://php.net/manual/en/mysqli-stmt.bind-param.php
If you're passing in a variable to your function it should already be set so I don't understand why you're setting it to 123 anyway. So execute the sql statement and bind the parameter following the first example on the PHP docs page.
public function listOrderComments ($factnr)
{
global $connection;
$query = "SELECT * FROM orderstatus WHERE factuurnummer = ?";
$sql->prepare($query);
$sql->bind_param("s", $factnr);
$sql->execute();
$result = $sql->get_result();
$data = mysqli_fetch_all($result, MYSQLI_ASSOC);
foreach ($data as $row) {
print_r($row);
}
}
Then do what you want with the result
You can go with:
$query = "SELECT * FROM orderstatus WHERE factuurnummer = ". $factnr;
Concatenating your code is not good practise. Your best solution is to use PDO statements. It means that your code is easier to look at and this prevents SQL injection from occuring if malice code slipped through your validation.
Here is an example of the code you would use.
<?php
// START ESTABLISHING CONNECTION...
$dsn = 'mysql:host=host_name_here;dbname=db_name_here';
//DB username
$uname = 'username_here';
//DB password
$pass = 'password_here';
try
{
$db = new PDO($dsn, $uname, $pass);
$db->setAttribute(PDO::ERRMODE_SILENT, PDO::ATTR_EMULATE_PREPARES);
error_reporting(0);
} catch (PDOException $ex)
{
echo "Database error:" . $ex->getMessage();
}
// END ESTABLISHING CONNECTION - CONNECTION IS MADE.
$factnr = "123" // or where-ever you get your input from.
$query = "SELECT * FROM orderstatus WHERE factuurnummer = :factnr";
$statement = $db->prepare($query);
// The values you wish to put in.
$statementInputs = array("factnr" => $factnr);
$statement->execute($statementInputs);
//Returns results as an associative array.
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
$statement->closeCursor();
//Shows array of results.
print_r($result);
?>
Use it correctly over "doted" concat. Following will just work fine:
$factnr = 123;
$query = "SELECT * FROM orderstatus WHERE factuurnummer = " . $factnr;
UPDATE:
here is $factnr is passing as argument that supposed to be integer. Safe code way is DO NOT use havvy functions even going over more complicated PDO, but just verify, is this variable integer or not before any operation with it, and return some error code by function if not integer. Here is no danger of code injection into SQL query then.
function listOrderComments ($factnr){
global $connection;
if (!is_int($factnr)) return -1
//$factnr = 123; //or $factnr = "123"; (Both work)
$query = "SELECT * FROM orderstatus WHERE factuurnummer = " . $factnr;
$result = mysqli_query($connection, $query);
I have the following PHP code:
$comp1 = $_POST['cohort_id1'];
$comp2 = $_POST['cohort_id2'];
$comp3 = $_POST['cohort_id1'];
$comp4 = $_POST['cohort_id2'];
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT cat_code, value, :comp1 , :comp2, round(:comp3/:comp4 * 100) as index_number FROM {$table}";
$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY) );
$stmt->execute(array(':comp1' => $comp1, ':comp2' => $comp2, ':comp3' => $comp3, ':comp4' => $comp4 ));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
header('Content-type: application/json');
echo json_encode($result);
Here is how one of the objects is returned:
?: "national_percent"
cat_code: "edu"
index_number: null
value: "Some College"
What I can't understand is why the first line returns with a "?", but more importantly, why the index_number is null. I suspect it is because those values are being converted into strings, but I'm not sure how to handle that.
To prevent SQL injection of user input that contains column names, check the input against an array of valid column names:
$valid_columns = array('col1', 'col2', 'col3');
if (in_array($user_input_col, $valid_columns))
{
$sql = "SELECT {$user_input_col} from table...";
...
}
else
{
die('Invalid column name');
}
I'm a rookie in PDO and I've done some search about the issue I'm facing and I wasn't able to find any answers about it. As you can see below, I have this function:
function deleteInfo($id){
$pdo = connPDO();
$deleteInfo = $pdo -> prepare("DELETE FROM game_locais_zumbis WHERE id_zumbi IN (:id)");
$deleteInfo -> bindValue(":id", $id, PDO::PARAM_STR);
$deleteInfo -> execute();
$pdo = null;
}
After that, I have the following code:
while($row = $listInfo -> fetch(PDO::FETCH_ASSOC)){
$ids[] = $row['ids'];
}
$ids = implode(',', $ids);
deleteInfo($ids);
When I echo my $ids, I get:
1,2,3,4,5
But the DELETE function is not deleting all those five rows in my db but only the first one, like "1". When I run that exactly same DELETE function in my db, replacing the ":id" with "1,2,3,4,5", it does work! Does anybody know what's my mistake here? I appreciate any help.
I would do this:
$query = "DELETE FROM game_locais_zumbis WHERE id_zumbi in (".str_repeat("?,", count($ids) - 1)."?)";
$stmt = $conn->prepare($query);
$stmt->execute($ids);
Unfortunately you can't bind an array of elements with prepared statements. You will have to build them in the query directly.
function deleteInfo($ids)
{
$pdo = connPDO();
if (!is_array($ids))
$ids = array($ids); // if it is just one id not in an array, put it in an array so the rest of the code work for all cases
$ids = array_map([$pdo, 'quote'], $ids); // filter elements for SQL injection
$pdo->exec('DELETE FROM game_locais_zumbis WHERE id_zumbi IN (' . implode(', ', $ids) . ')');
}
Remember to pass the array to deleteInfo() instead of imploding it into a string.
This is how i have done it and it worked. I created an array and looped through it.
<?php
// set a database connection
$host = "localhost";
$user ="root";
$password = "";
$db = "pdopost";
//Set a DSN
$dsn = 'mysql:host ='.$host . ';dbname='.$db;
// Create a PDO instance
$pdo = new PDO ($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$ids=['6', '7'];
foreach($ids as $id){
$sql = "DELETE FROM posts WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id]);
}
echo 'Deleted in the database';
?>