I have the following normal User class statement that I'm trying to convert to a prepared statement.
public function didReceiveRequest($user_from) {
$user_to = $this->user['username'];
$check_request_query = mysqli_query($this->con, "SELECT * FROM friend_requests WHERE user_to='$user_to' AND user_from='$user_from'");
if (mysqli_num_rows($check_request_query) > 0) {
return true;
}
else {
return false;
}
}
I'm new to prepared statements and have been doing pretty well throughout the User class, but am still having trouble with a few. Being new, I don't follow the logic as well, so please go easy. Here is what I have so far:
public function didReceiveRequest($user_from){
$user_to = $this->user['username'];
$check_request = $this->con->stmt_init();
$check_request->prepare('SELECT * FROM friend_requests WHERE user_to=? AND user_from=?');
$check_request->bind_param('ss', $user_to, $user_from);
$check_request->execute();
$result = check_request->get_result();
$data = $result->fetch_assoc();
$check_request->free_result();
$check_request->close();
if($data > 0){
return true;
}else{
return false;}
}
So a couple things abt this: 1)I know there is probably a better and more efficient way to do this. And 2) Will what I have return the same result as what was there (with normal statement) previously. I don't want to mix up calls from my dependent pages.
Here is how you would use MySqli prepared statements for your case example.
public function didReceiveRequest($user_from) {
$query = "SELECT *
FROM friend_requests
WHERE user_to = ? AND user_from = ?";
$user_to = $this->user['username'];
$stmt = $this->con->prepare($query);
$stmt->bind_param(ss, $user_to, $user_from); //set your bindings
$stmt->execute();
//$results = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);//Use if you want to see results.
if($stmt->num_rows !== 0) {
return TRUE;
}else{
return FALSE;
}
}
Here is a really good link to read that teaches you how to use prepared statements with MySqli. I would bookmark this link and refer to it often. MySqli prepared statements
Using prepared statements does not affect how you receive the results from you query.
The difference I see in what was provided as an answer is $result = $stmt->get_result(); Again being new to prepared statements I'm not 100% that this is the reason above code throws an error, but this code works.
public function didReceiveRequest($user_from) {
$user_to = $this->user['username'];
$stmt = $this->con->stmt_init();
$stmt->prepare('SELECT * FROM friend_requests WHERE user_to=? AND user_from=?');
$stmt->bind_param('ss', $user_to, $user_from);
$stmt->execute();
$result = $stmt->get_result();
$qty = $result->num_rows;
$stmt->free_result();
$stmt->close();
if($qty > 0) {
return true;
}else{
return false;
}
}
Related
Ok, so I am having a lot of trouble with Prepared statements. I've done hours of research and still can't seem to fully understand everything...
I really feel like I need to understand Prepared statements because I was just about to release a few new free APIs on my website (which require API Key to execute API) but I recently realized how insecure everything is.... I can simply use SQL injection to bypass API Key check, e.g. 'OR'1'='1
Here is how I validate API Key:
$apikey = $_GET['key'];
$sql = "SELECT * FROM `table` WHERE `key` = '$apikey'";
$query = mysqli_query($con, $sql);
if($query)
{
$fetchrow = mysqli_fetch_row($query);
if(isset($fetchrow[0]))
{
echo "API Key is valid!";
}
else
{
echo "API KEY is invalid";
}
}
And like mentioned above this can easily be bypassed by executing my API like this
http://website.com/api.php?key='OR'1'='1
This really scared me at first, but then I did some research and learned a good way to prevent any form of SQL injection is to use prepared statement, so I did a lot of research and it just seems quite complicated to me :/
So I guess my question is, how can I take my above code, and make it function the same way using prepared statements?
Probably everything you need:
class Database {
private static $mysqli;
Connect to the DB:
public static function connect(){
if (isset(self::$mysqli)){
return self::$mysqli;
}
self::$mysqli = new mysqli("DB_HOST", "DB_USER", "DB_PASS", "DB_NAME");
if (mysqli_connect_errno()) {
/*Log error here, return 500 code (db connection error) or something... Details in $mysqli->error*/
}
self::$mysqli->query("SET NAMES utf8");
return self::$mysqli;
}
Execute statement and get results:
public static function execute($stmt){
$stmt->execute();
if ($mysqli->error) {
/*Log it or throw 500 code (sql error)*/
}
return self::getResults($stmt);
}
Bind results to the pure array:
private static function getResults($stmt){
$stmt->store_result();
$meta = $stmt->result_metadata();
if (is_object($meta)){
$variables = array();
$data = array();
while($field = $meta->fetch_field()) {
$variables[] = &$data[$field->name];
}
call_user_func_array(array($stmt, "bind_result"), $variables);
$i = 0;
while($stmt->fetch()) {
$array[$i] = array();
foreach($data as $k=>$v)
$array[$i][$k] = $v;
$i++;
}
$stmt->close();
return $array;
} else {
return $meta;
}
}
Class end :)
}
Example of usage:
public function getSomething($something, $somethingOther){
$mysqli = Database::connect();
$stmt = $mysqli->prepare("SELECT * FROM table WHERE something = ? AND somethingOther = ?");
$stmt->bind_param("si", $something, $somethingOther); // s means string, i means number
$resultsArray = Database::execute($stmt);
$someData = $resultsArray[0]["someColumn"];
}
Resolving your problem:
public function isKeyValid($key){
$mysqli = Database::connect();
$stmt = $mysqli->prepare("SELECT * FROM table WHERE key = ? LIMIT 1");
$stmt->bind_param("s", $key);
$results = Database::execute($stmt);
return count($results > 0);
}
PHP automatically closes DB connection so no worries about it.
$sql = "SELECT * FROM `table` WHERE `key` = ?";
if(stmt = $mysqli->prepare($sql)) {
$stmt->bind_param("i", $apikey);
$stmt->execute();
$stmt->bind_result($res);
$stmt->fetch();
$stmt->close();
}
See more - http://php.net/manual/en/mysqli.prepare.php
is this the correct way to avoid SQL Injection in this SELECT?
// --[ Method ]---------------------------------------------------------------
//
// - Purpose : Check if provided $email (taken from user input) exists in the DB
//
// -----------------------------------------------------------------------------
function DB_EmailExists($email)
{
//
if(DB_Connect() == false)
{
echo mysqli_error();
return false;
}
//
$stmt = $GLOBALS['global_db_link']->prepare("SELECT * FROM ".$GLOBALS['global_db_table_users']." WHERE Email=?");
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
$numrows = $stmt->num_rows;
$stmt->close();
//
if ($numrows==0)
{
DB_Disconnect();
return false;
}
//
DB_Disconnect();
return true;
}
Yes, that works. But no need to SELECT *, just use SELECT email
When preparing a mySQLi statement do I need to bind parameters?
public function query($sql){
$sql = mysqli_prepare($this-> connect, $sql);
$array= array();
$query=mysqli_query($this->connect, $sql);
if ($query > 0){
$c=mysqli_num_rows ($query);
if($c > 1){
while($fetch = mysqli_fetch_row($query)){
array_push($array, $fetch);
}
}
return $array;
}else ...
exit();
}
the ... is just some more conditions to follow through. It just shows what my question is. The way I prepare is that ok or should I do this better. I've never used the prepare method and i am new to this. Also is it best practice to exit the query at the end?
Basically I'm converting all my statements in my class file to prepared statements. After reading over the php.net manual, I still cannot see where or what my error is.
In this particular function I am getting the profile of a user by the users ID.
Any help fellas?
I was able to answer my own question. Using SELECT * doesn't work very well with object oriented prepared statements.
Rather, select all the fields in the table needed and then bind them accordingly.
This particular function is getting all the details of a user by their ID.
Enjoy.
public function getProfile($id){
if($result = $this->link->prepare("SELECT id,first,last,full_name,email,photo FROM dl_users WHERE id=?")){
$result->bind_param('i',$id);
$result->execute();
$result->store_result();
$result->bind_result($id,$first,$last,$full_name,$email,$bio,$hometown,$position,$skills,$photo);
if($result->num_rows == 1){
$user = array();
$result->fetch();
$user['id'] = $id;
$user['first'] = $first;
$user['last'] = $last;
$user['full_name'] = $full_name;
$user['email'] = $email;
$user['photo'] = $photo;
return $user;
}
$result->close();
}
}
MySQLi's prepared statements work with variable references. $result->fetch() doesn't return the fields, it returns a boolean.
What you are can do is this:
public function getProfile($id){
if($result = $this->link->prepare("SELECT * FROM users WHERE id =?")){
$result->bind_param("s", $id);
$result->execute();
$result = $stmt->get_result();
if($row = $result->fetch_assoc()){
return $row;
}else{
return array("error"=>"Profile-Not-Found");
}
$result->close();
}
}
Note: This requires mysqlnd be installed.
If your id field is an integer, you must bind the param in this way:
$result->bind_param("i", $id);
More info here: http://www.php.net/manual/en/mysqli-stmt.bind-param.php
I was able to answer my own question. Using SELECT * doesn't work very well with object oriented prepared statements.
Rather, select all the fields in the table needed and then bind them accordingly.
This particular function is getting all the details of a user by their ID.
Enjoy.
public function getProfile($id){
if($result = $this->link->prepare("SELECT id,first,last,full_name,email,photo FROM dl_users WHERE id=?")){
$result->bind_param('i',$id);
$result->execute();
$result->store_result();
$result->bind_result($id,$first,$last,$full_name,$email,$bio,$hometown,$position,$skills,$photo);
if($result->num_rows == 1){
$user = array();
$result->fetch();
$user['id'] = $id;
$user['first'] = $first;
$user['last'] = $last;
$user['full_name'] = $full_name;
$user['email'] = $email;
$user['photo'] = $photo;
return $user;
}
$result->close();
}
}
I am having some trouble with prepared statements. Basically, this query is returning no rows, even though I know for a fact that this query should return multiple rows. I thought this was just a problem due to SQL injections, but maybe I'm doing something else wrong here, I don't know. If I take out the check for how many rows there are, I get an error:
PHP Fatal error: Call to a member function fetch_array()
Any help would be appreciated!
$stmt = $mysqli->prepare("SELECT sid from SDS WHERE uid=? AND dst=?");
$stmt->bind_param('ss',$username,$structureType);
$stmt->execute();
$stmt->bind_result($results);
$stmt->fetch();
if ($results) {
if($results->num_rows == 0) {
print("No results here.");
return 0;
}
$recordnames = array();
while ($next_row = $results->fetch_array()) {
$recordnames[] = $next_row['sid'];
}
return $recordnames;
}
When you use $stmt->bind_result($result); you are binding the sid from the database to the variable $results. So you cannot perform operations like :
if($results->num_rows == 0) { //... }
or
$results->fetch_array();
This is how I would do it :
<?php
$stmt = $mysqli->prepare("SELECT sid from SDS WHERE uid=? AND dst=?");
$stmt->bind_param('ss', $username, $structureType);
$stmt->execute();
$stmt->bind_result($sid);
$stmt->store_result();
if ($stmt->num_rows == 0)
{
print("No results here.");
$stmt->close();
return 0;
}
else
{
$recordnames = array();
while($stmt->fetch())
{
$recordnames[] = $sid;
}
return $recordnames;
}
?>
This way uses a different logic, check if the row count is 0, if so display "No results here", if not put results into the array.