PHP database connection class bind_param - php

I would like to write a database connection class and I dont understand how I have to write the select method with bind_param-s. Here is the full code. And here the part of the code where I need the help:
public function select($sql){
$db = $this->connect(); //This methos connect to the DB
$stmt = $db->prepare($sql);
if($stmt === false){ //If the prepare faild
trigger_error("Wrong SQL", E_USER_ERROR);
}
$error = $stmt->bind_param("i", $id);
if($error){
return "Error: ".$stmt->error, $stmt->errno;
}
$err = $stmt->execute();
if($error){
return "Error: ".$stmt->error, $stmt->errno;
}
$result = $stmt->bind_result($id);
$stmt->close();
$dbConnection->closeConnection($db);
return $result;
}
I need to got it parameters or how can I slove it?

You need to pass your values into this function too. And eventually bind them into prepared statement.
Optionally you can pass string with types, but by default all "s" will do.
Also remember that you should connect only ONCE per script execution. and then use one single connection all the way throughout your code.
And get rid of all these error checks. Set mysqli in exception mode instead.
public function q($sql, $values = array(), $types = NULL)
{
$stm = $this->mysql->prepare($sql);
if (!$types)
{
$types = str_repeat("s", count($values));
}
if (strnatcmp(phpversion(),'5.3') >= 0)
{
$bind = array();
foreach($values as $key => $val)
{
$bind[$key] = &$values[$key];
}
} else {
$bind = $values;
}
array_unshift($bind, $types);
call_user_func_array(array($stm, 'bind_param'), $bind);
$stm->execute();
return $stm->get_result();
}
so it can be used like this
$res = $db->q("SELECT name FROM users WHERE id=?", [$id]);
or
$res = $db->q("SELECT name FROM users WHERE id=?", [$id], "i");
your other functions have to be changed as well.
class DB{
public $con;
function __construct()
{
$this->con = new mysqli("localhost", "root", "", "proba_fferenc");
}
public function select(...)
{
// as shown above
}
}

Related

Number of bound variables does not match number of tokens when using a custom PDO function

I tried the questions with similar titles, but they are all regular queries that are not in functions.
I am trying to create an update function in a Database class so I don't have to write out the entire process over and over. However, I am getting the error:
Invalid parameter number: number of bound variables does not match number of tokens
Here is my function.
public function updateRow($query, $params) {
try {
$stmt = $this->master_db_data->prepare($query);
foreach($params as $key => $val) {
$stmt->bindValue($key+1, $val);
$stmt->execute();
return true;
}
} catch(PDOException $e) {
die("Error: " . $e->getMessage());
}
}
And its usage:
$query = "UPDATE records SET content=?, ttl=?, prio=?, change_date=? WHERE id=?";
$params = array($SOA_content, $fields['SOA_TTL'], '1', $DATE_TIME, $id);
if($db->updateRow($query, $params)) {
echo "Success";
}
else {
echo "Fail";
}
Doing it without a function works:
$pdo = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
$query = "UPDATE records SET content=:content, ttl=:ttl, prio=:prio, change_date=:change_date WHERE id=:id";
$stmt = $pdo->prepare($query);
$stmt->bindValue(":content", $SOA_content);
$stmt->bindValue(":ttl", $fields['SOA_TTL']);
$stmt->bindValue(":prio", 1);
$stmt->bindValue(":change_date", $DATE_TIME);
$stmt->bindValue(":id", $id);
$stmt->execute();
Am I wrong with my bindValue in the function? If so, how?
Always make sure your execute calls happen after all binding has been performed. In this situation, move the execute out of the binding loop.

MySQL Prepared statement confusion

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

Passing arguments in function pdo php

I created a function to grab data from my database. I want this function to be reusable just by placing correct arguments for different tables. Here's what I've done :
public function selectdata($table, $arguments='*', $where = null){
if($this->isconnect){
//check whether users put column names in the select clause
if(is_array($arguments)){
$new_args = implode(',', $arguments);
$sql = 'SELECT '.$new_args.' FROM '.$table;
} else {
$sql = 'SELECT '.$arguments.' FROM '.$table;
}
//check whether users use the where clause
if($where != null && is_array($where)){
$where = implode(' ', $where);
$sql .= ' WHERE '.$where ;
}
$query = $this->db->query($sql);
$query -> SetFetchMode(PDO::FETCH_NUM);
while($row = $query->fetch()){
print_r($row);
}
} else {
echo 'failed, moron';
}
}
And this is the way to run the function :
$columnname = array('bookname');
$where = array('bookid','=','2');
echo $database-> selectdata('buku', $columnname, $where);
The code worked quite decently so far, but I'm wondering how I want to use $where but without $columnname in the function. How do I pass the arguments in the function?
And could you point to me the better way to create a function to grab data using PDO?
Just use a PDO class which can look like this:
<?php
class DB_Connect{
var $dbh;
function __construct(){
$host = "xxx";
$db = "xxx";
$user = "xxx";
$password = "xxx";
$this -> dbh = $this -> db_connect($host, $db, $user, $password);
}
public function getDBConnection(){
return $this -> dbh;
}
protected function db_connect($host, $db, $user, $password){
//var_dump($host, $db, $user, $password);exit();
try {
$dbh = new PDO("mysql:host=$host;dbname=$db", $user, $password);
}
catch(PDOException $err) {
echo "Error: ".$err->getMessage()."<br/>";
die();
}
return $dbh;
}
public function query($statement){
$keyword = substr(strtoupper($statement), 0, strpos($statement, " "));
$dbh = $this->getDBConnection();
if($dbh){
try{
$sql = $dbh->prepare($statement);
$exe = $sql->execute();
}
catch(PDOException $err){
return $err->getMessage();
}
switch($keyword){
case "SELECT":
$result = array();
while($row = $sql->fetch(PDO::FETCH_ASSOC)){
$result[] = $row;
}
return $result;
break;
default:
return $exe;
break;
}
}
else{
return false;
}
}
}
?>
Now you can include that class and create an object with $dbh = new DB_Connect; and call every statement you want just with the reference on $dbh->query($statement)
This is my prefered way to do this.
EDIT: If you want to use a statement on another Database, just use the __construct($db) method to pass your database name on object creation

How to use prepared statements (named parameters) on a php Class

I want to know how to use named parameters in a prepared statement with pdo class, so the call to pdo look something like following.
$query = $bdd->prepare('SELECT * FROM table WHERE login = :login AND pww = :pww');
$query->execute(array('login' => $login, 'pww' => $pww));
And I want to integrate this on a class regardless of the number of parameters.
Currently, I have this code
require_once 'constants.php';
class Mysql extends PDO {
private $con;
public function __construct() {
try {
$this->con = parent::__construct(DB_DSN, DB_USER, DB_PASS);
if ($this->getAttribute(PDO::ATTR_DRIVER_NAME) == DB_TYPE)
$this->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, TRUE);
return $this->con;
} catch (PDOException $e) {
die('Error:' . $e->getMessage());
}
}
public function select($reqSelect) {
try {
$this->con = parent::beginTransaction();
$result = parent::prepare($reqSelect);
$result->execute();
//$this->con = parent::commit();
$this->con = parent::rollBack();
return $result;
$result->closeCursor();
} catch (Exception $e) {
die('Error:' . $e->getMessage());
}
}
public function selectAll($reqSelect) {
$result = parent::prepare($reqSelect);
$result->execute();
$resultat = $result->fetchAll();
return $resultat;
$result->closeCursor();
}
}
And for parameters, I use somethings like ( which is wrong and vulnerable to injection )
require_once 'classes/Mysql.class.php';
$mysql = new Mysql();
$sql = 'SELECT * FROM articles WHERE id = '.$_GET['id'].' LIMIT 1';
$data = $mysql->select($sql);
Thanks.
So it's seems that I have figured it out, the trick was adding an optional parameter to the function, you use it whenever you need to work with prepared statements (named parameters).
So the function is something like
public function selectAll($reqSelect, $param = null) {
$result = parent::prepare($reqSelect);
//Check whether the parameter was passed or not
if (is_null($param)) {
$result->execute();
$resultat = $result->fetchAll();
return $resultat;
} else {
//Binding the parameters
$result->execute($param);
$resultat = $result->fetchAll();
return $resultat;
}
$result->closeCursor();
}
And for applying it, it goes like
//First param, the SQL. Here we have named parameters, so we need them to get bind
$sql = 'SELECT * FROM articles WHERE publish = :number';
//Second param, the parameters that will get bind with the named ones
$param = array(':number' => 1);
$query = $mysql->selectAll($sql, $param);
foreach ($query as $row) {
extract($row);
echo $title . '<br />';
}
I don't know if this, is considered the best practice, secured or even correct. if I'm mistaken feel free to correct me.

What is the correct and easiest way to do prepared statements with PHP's mysqli?

I have been using the old mysql api in PHP for a long time and want to start using mysqli for both speed and security with a new project I'm working on. I've looked through the manual and read several tutorials, but I'm finding a lot of conflicting and somewhat confusing information on how to do prepared statements in mysql.
Is there anything in this code that doesn't need to be there, and is there anything that is missing? Also, is this the easiest way to do something simple like this (seems somewhat involved for such a simple task)?
Procedural:
// build prepared statement
$query = mysqli_prepare($link, "SELECT email FROM users WHERE id = ?");
// bind parameters to statement
mysqli_stmt_bind_param($query, 's', $_GET['id']);
// execute statement
mysqli_stmt_execute($query);
// bind the variables to the result
mysqli_stmt_bind_result($query, $email);
// print the results
while (mysqli_stmt_fetch($query)) {
echo $email;
}
// close the statement
mysqli_stmt_close($query);
// close connection
mysqli_close($link);
Object-Oriented:
// build prepared statement
$query = $link->prepare("SELECT email FROM users WHERE id = ?");
// bind parameters to statement
$query->bind_param('s', $_GET['id']);
// execute statement
$query->execute();
// bind the variables to the result
$query->bind_result($email);
// print the results
while ($query->fetch()) {
echo $email;
}
// close the statement
$query->close();
// close connection
$link->close();
Here's the guts of a semi-self-explanatory class that encapsulates mysqli, including prepared statements, which are quite tricky. It's pretty well tested - I've been using it for a year now without change.
It only implements prepared statements to Execute SQL commands because they change data and often require nasty encoding tricks otherwise. If you want SELECTs, it's left as an exercise for the reader - it's easier. :)
<?php
class Db
{
var $_mysqli;
var $_result;
var $_error_msg;
public function __construct($server, $user, $password, $name)
{
$this->_mysqli = new mysqli("p:".$server, $user,
$password, $name);
if($this->_mysqli->connect_errno)
{
$this->_error_msg = $this->_mysqli->connect_error;
}
}
public function __destruct()
{
}
private function sql_select($sql)
{
$this->_mysqli->query("SET NAMES 'utf8'"); // a little help for UTF8 io
$this->_result = $this->_mysqli->query($sql);
}
private function sql_close()
{
$this->_mysqli->close();
}
public function ErrorMessage()
{
return $this->_error_msg;
}
public function SqlRows($sql)
{
$rows = array();
$result = $this->sql_select($sql);
if($this->IsError())
{
return $rows;
}
while($row = $result->fetch_array())
{
$rows[] = $row;
}
$result->free();
return $rows;
}
public function SqlObjects($sql)
{
$objects = array();
$result = $this->sql_select($sql);
while($object = $this->_result->fetch_object())
{
$objects[] = $object;
}
$result->free();
return $objects;
}
public function SqlOneObject($sql)
{
$result = $this->sql_select($sql);
$obj = $result->fetch_object();
$result->free();
return $obj;
}
public function SqlOneRow($sql)
{
$result = $this->sql_select($sql);
if(! is_object($result))
return null;
if($result->num_rows > 0)
$row = $result->fetch_array();
else
$row = null;
$result->free();
return $row;
}
public function SqlOneValue($sql)
{
$result = $this->sql_select($sql);
if(!empty($result))
{
$row = $result->fetch_array();
}
$result->free();
return empty($row) ? null : $row[0] ;
}
// returns number of affected rows
public function SqlExecute($sql)
{
$this->_result = $this->_mysqli->query($sql);
return $this->affected_rows();
}
private function affected_rows()
{
return $this->_mysqli->affected_rows;
}
private function IsError()
{
if(empty($this->_mysqli))
return false;
return !empty($this->_mysqli->error);
}
// arguments are sql and an array of
// argument references (not values).
public function SqlExecutePS($sql, $args)
{
$stmt = $this->_mysqli->prepare($sql);
// make the type-string
$typestr = make_typestring($args);
$params = array($typestr);
$params = array_merge($params, $args);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$ret = $this->affected_rows();
$stmt->close();
return $ret;
}
public function SqlExists($sql)
{
$result = $this->SqlOneRow($sql);
return !empty($result[0]);
}
function make_typestring($args)
{
assert(is_array($args));
$ret = "";
foreach($args as $arg)
{
switch(gettype($arg))
{
case "boolean":
case "integer":
$ret .= "i";
break;
case "double":
$ret .= "d";
break;
case "string":
$ret .= "s";
break;
case "array":
case "object":
case "resource":
case "NULL":
default:
// call it a blob and hope
// you know what you're doing.
$ret .= "b";
break;
}
}
return $ret;
}
}
?>

Categories