My MySQL prepared statement won't work - php

I have a MySQL statement that won't work for me. I've checked several parts of the code but it keeps returning null as the result. I've also tried replacing the WHERE enc_mail = AND enc_public_id=" to "WHERE 1" to check if it was a problem with the variables, but it is not. I did not get errors either.
$connect_db = mysqli_connect("myhost","my username","my password","my db");
$mail_id = crypto(mysqli_real_escape_string($connect_db,htmlspecialchars($_GET['em'])),'e');
$public_id = mysqli_real_escape_string($connect_db,htmlspecialchars($_GET['public']));
$active_true = true;
$check = $connect_db->prepare("SELECT active FROM enc_data WHERE enc_mail=? AND enc_pub_id=?");
$check->bind_param("ss", $mail_id, $public_id);
$active = $check->execute();
if($active[0]=="" ){
//It goes here once the code is run
}

You need to apply bind_result and then fetch
Also there is absolutely no reason to escape_string when using prepared statements as #GrumpyCrouton said
i would recommend you switch to PDO as it is more straightforward

I agree with #Akintunde that you should NOT use escaping and htmlspecialchars on query parameters. Escaping is redundant when you use query parameters. htmlspecialchars is just when you output content to HTML, not for input to SQL.
You don't necessarily have to use bind_result() for a mysqli query. You can get a result object from the prepared statement, and then use fetch methods on the result object to get successive rows.
Here's how I would write your code:
// makes mysqli throw exceptions if errors occur
mysqli_report(MYSQLI_REPORT_STRICT);
$connect_db = new mysqli("myhost", "my username", "my password", "my db");
$mail_id = $_GET['em'];
$public_id = $_GET['public'];
$active_true = true;
$sql = "SELECT active FROM enc_data WHERE enc_mail=? AND enc_pub_id=?";
$stmt = $connect_db->prepare($sql);
$stmt->bind_param("ss", $mail_id, $public_id);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
if($row["active"]=="" ){
//It goes here once the code is run
}
}
But in fact I would prefer to use PDO instead of mysqli, so I guess that's not really how I would write the OP's code. :-)

Related

How to pass variable ammount of variables into prepared statement? [duplicate]

I am some confused because some people write PHP code like this for upload data.
But my instructor used $query and $link always to upload and retrieve data from SQL.
<?php
include 'connection.php';
function reg_in() {
if (isset($_POST['submit'])) {
$name = $_POST['name'];
$email = $_POST['email'];
$mob = $_POST['mobile'];
$check_in = $_POST['in'];
$check_out = $_POST['out'];
$rm = $_POST['room'];
$room_type = $_POST['type'];
// Problem start from here
if (mysql_query("INSERT INTO `book` (`name`,`email`,`mobile_no`,`check_in`,`check_out`,`room`,`room_type`) VALUES ('$name','$email','$mob','$check_in','$check_out','$rm','$room_type')")) {
header('Location: C:/wamp/www/project/payment.html');
} else {
echo mysql_error();
}
}
}
if (isset($_POST['submit'])) {
reg_in();
//echo ' succesfully inserted';
} else {
echo 'Not book';
}
MySQL (by my instructor):-
<?php
$link = mysqli_connect("myserver.com", "test", "sunil7117", "test");
if (mysqli_connect_error()) {
die("please give correct permision");
}
//Is both are same!
//$query="INSERT INTO user(email,password) VALUES ('shivanandcpr25#gmail.com','sunil7117')";
$query = "UPDATE user SET email='test#gmail.com' WHERE email='abc#gmail.com' LIMIT 1";
echo mysqli_query($link, $query);
echo "<br>";
$query = "SELECT * FROM user";
if ($result = mysqli_query($link, $query)) {
echo "welcome to database<br>";
$row = mysqli_fetch_array($result);
echo "my E-mail id is <strong> ".$row[1]. "</strong> and passoword is <strong>".$row[2]."</strong>";
}
Neither!
Your first example uses function which has been removed from PHP years ago. mysql_query() does not exist and should not be used anymore. The reason why it was removed is that you should use prepared statements instead. They are provided by either mysqli or PDO extensions.
Your second example is better, but it is way too messy.
You should not echo mysqli_query. There's nothing useful to be printed out from this function.
Get into a habit of using prepared statements all the time and use placeholders for variable data. As of now your queries are constant, but using prepared statements is still a good practice in case you need to add a parameter later on.
Avoid using functions like mysqli_fetch_array(). Iterating the result option one by one is messy and rarely useful.
Never check the return value of mysqli calls. It's pointless. Enable error reporting instead. See How to get the error message in MySQLi?
Always set the correct charset. It should be utf8mb4 99% of the time.
The SQL query can be saved in a separate variable, but what's the point? You are only going to pass it as an argument to the query function. There's no need to use an intermediate variable.
Don't use mysqli. You should use PDO instead. If you have to use mysqli, then create a simple wrapper function or class for this purpose and execute your generic function instead of messing around with mysqli functions.
Here is an example of how I would do it. First I enable error reporting for mysqli, I open the connection and set the charset. Then I declare a function which takes 3 parameters and returns an array. First parameter is your database connection you have just opened. Second is your SQL query with placeholders if there are any. Third is optional and it is an array of values to be bound to the placeholders as parameters. This function works for all kind of SQL queries. The rest of the code becomes really simple.
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = new mysqli("myserver.com", "test", "sunil7117", "test");
$link->set_charset('utf8mb4'); // always set the charset
/**
* Executes an SQL query on the database.
*
* #param \mysqli $mysqli
* #param string $query e.g. SELECT * FROM users WHERE username=?
* #param array $params An array of parameters to be bound in the given order to the placeholders in SQL
* #return array
*/
function prepared_query(\mysqli $mysqli, string $query, array $params = []): array {
$stmt = $mysqli->prepare($query);
if ($params) {
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
if ($result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_BOTH);
}
return null;
}
prepared_query($link, "UPDATE user SET email='test#gmail.com' WHERE email='abc#gmail.com' LIMIT 1");
echo "<br>";
$result = prepared_query($link, "SELECT * FROM user");
echo "welcome to database<br>";
if ($result) {
$row = $result[0];
echo "my E-mail id is <strong> ".$row[1]. "</strong> and passoword is <strong>".$row[2]."</strong>";
}

Converting regular mysql into prepared statements

Im new to database and i have written a LOT of PHP code that accesses a database using MySQL.
I didnt take into account SQL injection attacks so i have to re-write all that PHP code to use mysql prepared statements.
After looking at videos on how to used prepared SQL statements, to perform just ONE SQL command requires a whole lot of "prepared" statements. My existing code has lots of different SQL statements all over the place, it would be a nightmare to change all that code to pack and unpack all the required preparation for each "prepared" statement command.
Is there some kind of wrapper i can use to prevent turning one line of regular SQL into 6 or 7 lines of prepared statements?
For example use to do this line line of SQL
SELECT * from users where userid=10
needs many more lines of prepared SQL statements, especially if there are lots of other SQL statements too it now becomes very complex.
Is there was some sort of one line wrapper that i can call that accepts the template SQL string, plus the parameters, which also executes the command and returns the result in just one line of wrapper for different types of MYSQL statements it would be great and the code would be much less confusing looking and error prone.
For example
$users=WrapAndExecute($db,"SELECT * from users where userid=?","s",$userid);
$data=WrapAndExecute($db,"UPDATE table SET username=?,city=?","ss",$name,$city);
$result=WrapAndExecute($db,"DELETE from table where id=?","s",$userid);
$result=WrapAndExecute($db,"INSERT into ? (name,address) VALUES(?,?)","ss","users",$name,$address);
Each of those lines above would create a prepared statement template, do the bind, execute it and return the result that a regular MYSQL statement would. This would create minimal impact on existing code.
Anybody knows how to do this or if some easy php library or class already exists to do this, that i can just import and start using it?
Thanks
You don't need to change a query to a prepared statement if it has no PHP variables in it. If it has just constant expressions, it's safe from SQL injection.
$sql = "SELECT * from users where userid=10"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
You don't need to change a query that contains PHP variables, as long as the value of that variable is a constant specified in your code. If it doesn't take its value from any external source, it's safe.
$uid = 10;
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
You don't need to change a query that contains PHP variables, as long as you can filter the value to guarantee that it won't risk an SQL injection. A quick and easy way to do this is to cast it to an integer (if it's supposed to be an integer).
$uid = (int) $_GET['uid'];
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
That leaves cases where you are using "untrusted" values, which may have originated from user input, or reading a file, or even reading from the database. In those cases, parameters are the most reliable way to protect yourself. It's pretty easy:
$sql = "SELECT * from users where userid=?"; // Safe!
// two lines instead of the one line query()
$stmt = $pdo->prepare($sql);
$stmt->execute([$_GET['uid']]);
$data = $stmt->fetchAll();
In a subset of cases, you need one additional line of code than you would normally use.
So quit your whining! ;-)
Re your comment about doing prepared statements in mysqli.
The way they bind variables is harder to use than PDO. I don't like the examples given in http://php.net/manual/en/mysqli.prepare.php
Here's an easier way with mysqli:
$sql = "SELECT * from users where userid=?"; // Safe!
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $_GET['uid']);
$stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_all();
I don't like the stuff they do in their examples with bind_result(), that's confusing and unnecessary. Just use get_result(). So with mysqli, you need two more lines of code than you would with PDO.
I've written query wrappers for mysqli that emulate the convenience of PDO's execute() function. It's a PITA to get an array mapped to the variable-arguments style of bind_param().
See the solution in my answers to https://stackoverflow.com/a/15933696/20860 or https://stackoverflow.com/a/7383439/20860
I were in the same boat, and I wrote such a wrapper that works exactly the way you want, save for it's being a class, not a function.
$user = $sdb->getRow("SELECT * from users where userid=?s", $userid);
$sdb->query("UPDATE table SET username=?s, city=?s", $name, $city);
$sdb->query("DELETE from table where id=?s", $userid);
$sdb->query("INSERT into ?n (name,address) VALUES(?s,?s)","users", $name, $address);
The above is a working code, as long as you have somewhere in your bootstrap file
$db = mysqli_connect(...);
...
require 'safemysql.class.php';
$sdb = new SafeMySQL('mysqli' => $db);
Note that none of the other suggestions could do anything like that.
Also note that if I were writing it today, I would have used PDO, as this class is duplicating a lot of functionality already exists in PDO.
Take a look at the PDO extension in PHP - http://php.net/manual/en/intro.pdo.php: it it secure against injections thanks to prepared statements; also, it allows you to connect to many different databases (e.g. MySQL, MSSQL, etc.).
You can then build your own wrapper as you wish to keep it clean; for example your own wrapper could be as follows:
(following example will return user rows as objects)
// connect to DB
$GLOBALS['default_db'] = new DB('localhost','db_name','username','password') ;
// Get users and output results
$query = new DBQuery('SELECT * FROM users WHERE userid = ?',array(10)) ;
var_dump($query -> results()) ;
var_dump($query -> num_rows()) ;
// DB connection
class DB {
public $connection;
public function __construct($host , $dbname , $username , $password) {
$this->connection = new \PDO('mysql:host=' . $host . ';dbname=' . $dbname , $username , $password);
}
}
// Wrapper
class DBQuery {
private $num_rows = 0;
private $results = array();
public function __construct($query , $params = null , $class_name = null , DB $db = null) {
if ( is_null($db) ) {
$db = $GLOBALS['default_db'];
}
$statement = $db->connection->prepare($query);
$statement->execute($params);
$errors = $statement->errorInfo();
if ( $errors[2] ) {
throw new \Exception($errors[2]);
}
$fetch_style = ($class_name ? \PDO::FETCH_CLASS : \PDO::FETCH_OBJ);
$this->results = $class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style);
$this->num_rows += $statement->rowCount();
while ( $statement->nextrowset() ) {
$this->results = array_merge($this->results,$class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style));
$this->num_rows += $statement->rowCount();
}
}
public function num_rows() {
return $this->num_rows;
}
public function results() {
return $this->results;
}
}
Since a key requirement seems to be that you can implement this with minimal impact on your current codebase, it would have been helpful if you had told us what interface you currently use for running your queries.
While you could use PDO:
that means an awful lot of work if you are not already using PDO
PDO exceptions are horrible
Assuming you are using procedural mysqli (and have a good reason not to use mysqli_prepare()) its not that hard to write something (not tested!):
function wrapAndExecute()
{
$args=func_get_args();
$db=array_shift($args);
$stmt=array_shift($args);
$stmt_parts=explode('?', $stmt);
if (count($args)+1!=count($stmt_parts)) {
trigger_error("Argument count does not match placeholder count");
return false;
}
$real_statement=array_shift($stmt_parts);
foreach ($args as $k=>$val) {
if (isnull($val)) {
$val='NULL';
} else if (!is_numeric($val)) {
$val="'" . mysqli_real_escape_string($db, $val) . "'";
}
$real_statement.=$val . array_shift($stmt_parts);
}
return mysqli_query($db, $real_statement);
}
Note that this does not handle IS [NOT] NULL nicely nor a literal '?' in the statement nor booleans (but these are trivial to fix).

Why mysql_real_escape_string() did not prevent hack?

I've a website that hacked today. Server logs returned something like this as hacker's tries:
www.site.com/notifications.php?PID=7&id=999999.9%20union%20all%20select%20%28select%20distinct%20concat%280x7e%2C0x27%2Cunhex%28Hex%28cast%28schema_name%20as%20char%29%29%29%2C0x27%2C0x7e%29%20from%20%60information_schema%60.schemata%20limit%201%2C1%29%2C0x31303235343830303536%2C0x31303235343830303536%2C0x31303235343830303536--
But I've used mysql_real_escape_string() in my code:
if (isset($_GET['id']) && $_GET['id'] != '') {
$id = mysql_real_escape_string($_GET['id']);
} else {
$id = '';
}
if ($id == '') {
$stmt = "SELECT * FROM tbln13 ORDER BY id DESC";
} else {
$stmt = "SELECT * FROM tbln13 WHERE id = $id";
}
$NewsResult = mysql_query($stmt) or die (mysql_error());
Why my website could not prevent this attack?
Because escape_string add slashes and such to quotes. You didn't have any quotes in your query, or the string they submitted.
Your query doesn't have a STRING in it, it appears to expect an int. If you expected an integer, you should have verified it was an int, or forced it to an int, before using it in a query. Escaping a value as a string, then using it as an int, won't work.
Switch to prepared statements in MySQLi or PDO.
The sql injected query looks like this
SELECT * FROM tbln13 WHERE id = 999999.9
union all select
(select distinct concat(0x7e,0x27,unhex(Hex(cast(schema_name as char))),0x27,0x7e)
from `information_schema`.schemata
limit 1,1),
0x31303235343830303536, 0x31303235343830303536, 0x31303235343830303536--
as you see, you were injected because you have just allowed this!
You expected a number but you didn't check for it! So you got the number and something more.
You should have checked the $id variable for what you expected, which is the number. This is what I would use:
if (!preg_match('/^\d+$/', $id))
die("ERROR: invalid id"); // error, don't continue
Use prepared statements, that will, in most cases, prevent SQL injections.
A simple and comprehensible guide to prepared statements can be found in this website:
Bobby Tables
More over you should stop using MYSQL, it's outdated and will be removed in future implementations. Use MySQLi or PDO instead.
Because your escaped variable is not a string therefore it is not inside quotes in your query. If you want a quick fix you can change your query to:
$stmt = "SELECT * FROM tbln13 WHERE id = '$id'";
It is not standard use for numeric comparison but should work.
As mentioned by others, you should ditch deprecated mysql_* functions and instead used prepared statements via mysqli or PDO.
Even then you should also be validating your input, because just using prepared statements will not help you identify whether you have input values that are valid. You would ideally make sure all your input is valid before even attempting a prepared statement. In this case, this validation could be as simple as this:
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (false === $id) {
// you do not have a valid integer value passed. Do something.
} else {
// continue with your prepared statement
}

My code should each the value of the $age variable, but instead it echoes the word "age"?

This is the code I'm using:
<?php
// Set the MySQL Configuration
$db_host = "";
$db_user = "";
$db_password = "";
$db_name = "";
$db_table = "";
// Start Connection
$db_connect = mysql_connect ($db_host, $db_user, $db_password);
// Select Database
$db_select = mysql_select_db ($db_name, $db_connect);
// Update Values in Database
$query = "UPDATE $db_table SET
age = age + 1,
land = '".$_POST['data3']."'
WHERE name = '".$_POST['data1']."'
";
// Execution MySQL query
$result = mysql_query($query) or die(mysql_error($db_connect));
//Close MySQL connection
mysql_close($db_connect);
//HTTP Response
echo " your age: age";
?>
I want to echo the value of the $age variable, but instead I always get the word "age." For example, the code should echo your age: 5 but instead it outputs your age: age
First, you'll need to run a SELECT query to retrieve the updated value of age. The query should look something like this:
"SELECT age FROM db_table_name WHERE name = ?"
Once you've obtained the result of that query, with say PDO::fetch (see my note below about PDO) and set it to the variable $age, you can output it with an echo statement:
echo "Your age: $age";
Also, please don't use mysql_* functions for new code. They are no longer maintained and the community has begun the deprecation process (see the red box). Instead, you should learn about prepared statements and use either PDO or MySQLi. If you can't decide which, this article will help you. If you care to learn, this is a good PDO tutorial.
The reason I'm not giving you the exact code for this is because it shouldn't be done with the mysql_* functions at all. Creating an SQL query with data directly from $_POST like this is extremely dangerous code to use and an incredibly bad idea all around. Never do this. You open yourself up to numerous SQL injection attacks. Even using mysql_real_escape_string is not enough. You should be using prepared statements.
UPDATE: Here is a simple example that's close to what you're asking, but using PDO and prepared statements. This is by no means a comprehensive example, since there are several ways to alter it that will still work (e.g. prepared statements allow you to execute multiple statements on the server in one statement), and I don't have a working server at the moment to test to make sure it's exactly what you need, but I hope it gets the point of across.
<?php
// Create the database connection
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 'username', 'password');
// Set PDO/MySQL to use real prepared statements instead of emulating them
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// The UPDATE query we're going to use
$update_query = "UPDATE `db_table_name` SET age = age + 1, land = :land WHERE name = :name";
// Prepare the query
$stmt = $db->prepare($update_query);
// Bind variables to the named parameters in the query with their values from $_POST
$land = $_POST['data3'];
$name = $_POST['data1']
$stmt->bindParam(':land', $land);
$stmt->bindParam(':name', $name);
// Execute the statement on the server
$stmt->execute();
// The SELECT query we're going to use
$select_query = "SELECT age FROM `db_table_name` WHERE name = :name";
// Again, prepare the query
$stmt_select = $db->prepare($select_query);
// Bind the paramters (in this case only one) to the new statement
// $name is already set from before, so there is no need to set it again
$stmt_select->bindParam(":name", $name);
$stmt_select->execute();
/*
* With no arguments, PDO::fetchColumn() returns the first column
* in the current row of the result set. Otherwise, fetchColumn()
* takes a 0-indexed number of the column you wish to retrieve
* from the row.
*/
$age = $stmt_select->fetchColumn();
echo("Your age: $age");
?>
All of this information came directly from the PHP documentation on prepared statements and PDO::fetchColumn().

PHP/PostgreSQL: check if a prepared statement already exists

I create my prepared statement as:
pg_prepare('stm_name', 'SELECT ...');
Today, I had a problem (calling twice a function for mistake) when declaring a prepared statement with the same name twice:
Warning: pg_prepare() [function.pg-prepare]: Query failed: ERROR: prepared statement "insert_av" already exists in xxx on line 221
So, as the question title, there is a way to check if a prepare statement with the same label already exists, and in case, overwrite it?
I know this error is from my mistake and will be solved by simply declaring the prepared statements at the begin of my code, but I'm wondering if there is a solution to have more control over them.
EDIT:
After the Milen answer, is quite simply to check if the prepared statement is already in use, simply querying the db for the table pg_prepared_statements:
try{
$qrParamExist = pg_query_params("SELECT name FROM pg_prepared_statements WHERE name = $1", array($prepared_statement_name));
if($qrParamExist){
if(pg_num_rows($qrParamExist) != 0){
echo 'parametized statement already created';
}else{
echo 'parametized statement not present';
}
}else{
throw new Exception('Unable to query the database.');
}
}catch(Exception $e){
echo $e->getMessage();
}
But, I don't think this is a good solution, because i have to query the database every time.
Ok, usually the prepared statements are declared in the begin of the script and then just reused, but, I have a class nicely wired and I don't like to declare 10 prepared statements when I'll use just 3 of them.
So, I think I'll use a simple PHP array to keep track the statements I create, and then with isset() function check if it exists or needs to be created:
try{
$prepare = pg_prepare('my_stmt_name', "SELECT ...");
if($prepare){
$this->rayPrepared['my_stmt_name'] = true;
}else{
throw new Exception('Prepared statement failed.');
}
}catch(Exception $e){
echo $e->getMessage();
}
One way (I hope someone will point out a simpler one):
<?
$prepared_statement_name = 'activity1';
$mydbname = '...';
$conn = pg_connect("host=... port=... dbname=... user=... password=...");
$result = pg_query_params($conn, 'SELECT name FROM pg_prepared_statements WHERE name = $1', array($prepared_statement_name));
if (pg_num_rows($result) == 0) {
$result = pg_prepare($conn, $prepared_statement_name, 'SELECT * FROM pg_stat_activity WHERE datname = $1');
}
$result = pg_execute($conn, $prepared_statement_name, array($mydbname));
while($row = pg_fetch_row($result)) {
var_dump($row);
}
Haven't tried this in php but if this is feasible in your application (if you need the statement only in one place and don't have to "fetch" it again by name) you could try to prepare an unnamed statement.
http://www.postgresql.org/docs/8.4/interactive/libpq-exec.html says:PQprepare
...stmtName may be "" to create an unnamed statement, in which case any pre-existing unnamed statement is automatically replaced; otherwise it is an error if the statement name is already defined in the current session.php_pg uses PQprepare, so this might work for you.
Why are you using prepared statements at all ? They only offer a performance advantage if you use the same statement many times over.

Categories