Lets say I have this code:
$array = array('one' => $one, 'two' => $two);
$sql->sql_insert('table_name', $array);
I have the class object $sql and the function sql_insert but how would I use the mysqli prepared statements to bind the values and insert it into the db? And lets say the mysqli connection is $this->connection
Any advice would be great thanks.
edited:
function sql_insert_bind($table, $insert){
$count = count($insert);
$bind_val = '';
for($i = 0; $i <= $count; $i++){
$bind_val .= '?, ';
}
$query = $this->connection->prepare('INSERT INTO `'.$table.'` VALUES ('.substr($bind_val, 0, -2).')');
foreach($insert as $key => $value){
$query->bind_param($key, $value);
}
$query->execute();
}
I get the error message: Fatal error: Call to a member function bind_param() on a non-object but $this->connection is the mysqli object
Ok, here's how I would approach this with PDO (since OP asked)
I'll assume you've instantiated or injected a PDO object into your class as the $connection property, eg
class SQLClass {
/**
* #var PDO
*/
private $connection;
public function __construct(PDO $pdo) {
$this->connection = $pdo;
}
// etc
}
$pdo = new PDO('mysql:host=localhost;dbname=db_name;charset=utf8', 'username', 'password', array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC));
$sql = new SQLClass($pdo);
Then, in your sql_insert_bind method
$keys = array_keys($insert);
$cols = array_map(function($key) {
return sprintf('`%s`', $key);
}, $keys);
$placeholders = array_map(function($key) {
return sprintf(':%s', $key);
}, $keys);
$params = array_combine($placeholders, $insert);
$query = sprintf('INSERT INTO `%s` (%s) VALUES (%s)',
$table, implode(',', $cols), implode(',', $placeholders));
$stmt = $this->connection->prepare($query);
$stmt->execute($params);
You should bind each variable seperately, bind_param will accept many variables to bind:
$array = array('one' => $one, 'two' => $two);
$query = $sql->prepare("INSERT INTO `table` VALUES (?, ?)");
$query->bind_param('ss', $array['one'], $array['two']);
$query->execute();
// inserted
Related
Good day everyone:
I'd like to parametrize my queries, creating a function that receive my query, connection and array with parameters expressed as "?".
My function is:
receiveQuery($query, $mysqli1, $array1)
I have read about sql injection I would like to know that if this is a proper way to avoid these.
I am planning to use this this function for INSERT, DELETE, UPDATE and SELECT.
Also I would like you to guide me how could I create some better handling for more than 1 parameter, because currently I am using a switch.
But every time I require more parameters, I am increasing the switch and I would like to create it dinamically.
SWITCH ($array1Length)
Any comments is helpful, regards.
Felipe
<?php
$mysqli1 = openConn();
$query = "INSERT INTO tblTest (field1 , field2 ) VALUES (?,?)";
$array1 = array($value1, $value2);
$result = receiveQuery($query, $mysqli1, $array1);
if($stmt->affected_rows == 1)
{
$success = "Success.";
}
if($stmt->affected_rows == -1)
{
$error = "Error.";
}
closeConn($stmt);
closeConn($mysqli1);
function openConn()
{
$mysqli1 = new mysqli('localhost', 'userTest', '123', 'dbTest');
if ($mysqli1->connect_error) {
die('Connect Error (' . $mysqli1->connect_errno . ') '
. $mysqli1->connect_error);
}
return $mysqli1;
}
function receiveQuery($query, $mysqli1, $array1)
{
global $stmt;
$stmt = $mysqli1->prepare($query);
if (false===$stmt)
{
echo $mysqli1->error;
die('Error');
}
$array1Length = count($array1);
SWITCH ($array1Length)
{
CASE 0: break;
CASE 1: $stmt->bind_param("s" , $array1[0]) ;break;
CASE 2: $stmt->bind_param("ss" , $array1[0],$array1[1]) ;break;
CASE 3: $stmt->bind_param("sss" , $array1[0],$array1[1],$array1[2]) ;break;
CASE 4: $stmt->bind_param("ssss", $array1[0],$array1[1],$array1[2],$array1[3]);break;
DEFAULT : echo "Error";
}
$stmt->execute();
$result = $stmt->get_result();
return $result;
}
function closeConn($mysqli1)
{
$mysqli1->close();
}
?>
You should be able to use the splat operator on your array.
$s = '';
for ($x = 0; $x < count($params); $x ++) {
$s .= 's';
}
$stmt->bind_param($s, ...$params);
https://secure.php.net/manual/en/migration56.new-features.php
I'd like to parametrize my queries, creating a function that receive
my query, connection and array with parameters expressed as "?"
My suggestion is that you rather use PDO than, the current mysqli that you using at the moment. PDO is easier to learn and can work easy with your current requirements.
Here's how you would do this with PDO.
page.php
<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'dbTest');
define('DB_USER', 'userTest');
define('DB_PASS', '123');
define('DB_CHAR', 'utf8');
class conn
{
protected static $instance = null;
protected function __construct() {}
protected function __clone() {}
public static function instance()
{
if (self::$instance === null)
{
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => FALSE,
);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
}
return self::$instance;
}
public static function __callStatic($method, $args)
{
return call_user_func_array(array(self::instance(), $method), $args);
}
public static function receiveQuery($sql, $args = [])
{
if (!$args)
{
return self::instance()->query($sql);
}
$stmt = self::instance()->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
anotherpage.php
<?php
require 'page.php';
$params = array($value1, $value2);
$sql = "INSERT INTO tblTest (field1 , field2 ) VALUES (?,?)";
$stmt = conn::receiveQuery($sql, $params);
if($stmt->rowCount() > 0){
$success = "Success.";
}else{
$error = "Error.";
}
?>
To learn more about PDO you can follow this site : https://phpdelusions.net/pdo
I have a prepared statement function for INSERT, I got this function in this forum. but I don't know how to pass variables/array to this function. I am new at this, some help would be really useful.
I want somehing like this:
$obj->insert_data($parameter)
I have listed the function below..
function insert_datas($array) {
$placeholders = array_fill(0, count($array), '?');
$keys = $values = array();
foreach($array as $k => $v) {
$keys[] = $k;
$values[] = !empty($v) ? $v : null;
}
$stmt = self::$mysqli->stmt_init();
$query = 'INSERT INTO `'.DB_TABLE_PAGES.'` '.
'('.implode(',', $keys).') VALUES '.
'('.implode(',', $placeholders).')';
$stmt->prepare($query);
call_user_func_array(
array($stmt, 'bind_param'),
array_merge(
array(str_repeat('s', count($values))),
$values
)
);
$stmt->execute();
}
Try this, hope this helps!
define('DB_HOST', 'database_host');
define('DB_NAME', 'database_name');
define('DB_USER', 'database_user');
define('DB_PASS', 'database_password');
$dbc = new PDO('mysql:host='. DB_HOST .';dbname='. DB_NAME, DB_USER, DB_PASS);
function insert_datas($array) {
foreach($array as $a) {
$insert_table = "INSERT INTO table (column) VALUES (:column)";
$stmt = $dbc->prepare($insert_table);
$stmt->bindValue(':column', $a['key'], PDO::PARAM_STR);
$stmt->execute();
}
}
I am trying to create a function to iteratively bind variables. This is what I have so far:
function prepareQuery($db, $query, $args) {
// Returns a prepared statement
$stmt = $db->prepare($query);
foreach ($args as $arg => $value) {
$stmt->bindParam($arg, $value);
}
return $stmt;
}
This is how I'm using it:
$stmt = prepareQuery($db, "SELECT * FROM `Licenses` WHERE `verCode`=:verCode", Array(":verCode" => $verCode));
$verCode = "some_string";
$stmt->execute();
while ($info = $stmt->fetch()) {
print_r($info);
}
Though it doesn't print anything. I know the database entry exists, and the same query works from PHPMyAdmin. So, I think it's just a problem in how my function tries to create the bindings. How can I fix this? Thanks!
Do not create a function to iteratively bind variables. PDO can do it already
function prepareQuery($db, $query, $args) {
$stmt = $db->prepare($query);
$stmt->execute($args);
return $stmt;
}
If it doesn't print anything, then it didn't find anything. As simple as that.
You don't even need this prepare query function actually. Just amend PDO very little like this
class myPDOStatement extends PDOStatement
{
function execute($data = array())
{
parent::execute($data);
return $this;
}
}
$user = 'root';
$pass = '';
$dsn = 'mysql:charset=utf8;dbname=test;host=localhost';
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => TRUE,
PDO::ATTR_STATEMENT_CLASS => array('myPDOStatement'),
);
$pdo = new PDO($dsn, $user, $pass, $opt);
and you'll be able to write such a neat chain:
$sql = "SELECT * FROM `Licenses` WHERE `verCode`=:verCode";
$code = "some_string";
$data = $pdo->prepare($sql)->execute([$code])->fetchAll();
foreach ($data as $info) {
print_r($info);
}
I stupidly built my web application with mysqli. Now, I'm trying to convert my data abstraction layer to pdo, but for some reason the insert query is giving me trouble. my shortcut insert function is called from the controller, and I was hoping to keep it in the name format with the table name and column/values array as the parameters.
I commented where I think the problem is below. Please help.
function insert($table, array $columns_values) {
// connect to db
$dbh = $this->db_connect();
$i = 0;
$columns = array();
$values = array();
$params = array();
foreach($columns_values as $column => $value) {
$i++;
$param = array($i => $value);
array_push($params, $param);
array_push($columns, $column);
array_push($values, '?');
}
// turn arrays into comma separated list
$columns = implode(",", $columns);
$values = implode(",", $values);
$stmt = $dbh->prepare("INSERT INTO $table ($columns) VALUES ($values)");
foreach ($params as $param_stmt) {
// i think this is where the problem is
foreach ($param_stmt as $placeholder => $value) {
$stmt->bindParam($placeholder, $value);
}
}
$stmt->execute();
return $stmt;
} // end insert()
I wouldn't do it your way. After a few minutes, I came up with this:
/**
* Function to insert a list of values to the database.
*
* #param PDO $pdo
* #param string $table
* #param array $columns_values
*
* #throws \Exception
* #throws \PDOException
*/
function insert_to_db(PDO $pdo, $table, array $columns_values) {
//Some data validation.
if (empty($columns_values)) {
throw new \Exception("Insert at least one value.");
}
if (empty($table)) {
throw new \Exception("Table may not be empty.");
}
//Implode all of column names. Will become the columns part of the query.
$str_columns = implode(", ", array_keys($columns_values));
//Implode all column names after adding a : at the beginning.
//They will become the placeholders on the values part.
$prepared_column_names = array_map(function ($el) {
return ":$el";
}, array_keys($columns_values));
$prepared_str_columns = implode(", ", $prepared_column_names);
//The query itself. Will look like "INSERT INTO `$table` (col1, col2, col3) VALUES (:col1, :col2, :col3);"
$query = "INSERT INTO `$table` ($str_columns) VALUES ($prepared_str_columns);";
//Prepare the query
$stmt = $pdo->prepare($query);
//Iterate over the columns and values, and bind the value to the placeholder
foreach ($columns_values as $column => $value) {
$stmt->bindValue(":$column", $value);
}
//Execute the query
$stmt->execute();
}
Things I changed
I don't instantiate the PDO object inside of the function. The function needs one in order to work, so it should be one of the arguments!
I throw Exceptions in case of an error. It's a better way of handling errors.
I use named placeholders instead of unnamed ones (:name vs ?). Produces more readable, easier to follow queries, should you ever need to debug.
Added comments to code. Again, you understand what you wrote now, but will you 6 months from now?
I made use of array_keys() to automatically generate an array full of keys (i.e. the columns), instead of looping and manually adding one.
Some tips
When you instantiate a PDO object, make sure it throws PDOExceptions on error! Like so:
new PDO($dsn, $user, $pass, array(PDO::PARAM_ERRMODE => PDO::ERRMODE_EXCEPTION));
or
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::PARAM_ERRMODE, PDO::ERRMODE_EXCEPTION);
That way, you don't need to explicitly check for errors each time, you use a single try catch block for the whole thing, and you're good:
try {
insert_to_db($pdo, $table, $array_of_columns_and_values);
}
catch (\Exception $e) { //Will catch all kinds of exceptions, including PDOExceptions
echo $e->getMessage();
}
You haven't checked that your prepare() actually succeeded:
$sql = "INSERT ....";
$stmt = $dbh->prepare($sql);
if (!$stmt) {
die($sql . $dbh->errorInfo());
}
Never assume a query succeeded, especially when you're building one totally dynamically as you are.
Without seeing what your original $columns_values array looks like.
Hope it helps
<?php
function insert($table, $values){
$dbh = $this->db_connect();
$fieldnames = array_keys($values[0]);
$sql = "INSERT INTO $table";
/*** set the field names ***/
$fields = '( ' . implode(' ,', $fieldnames) . ' )';
/*** set the placeholders ***/
$bound = '(:' . implode(', :', $fieldnames) . ' )';
/*** put the query together ***/
$sql .= $fields.' VALUES '.$bound;
//INSERT INTO testtable( id ,col1 ,col2 ) VALUES (:id, :col1, :col2 )
/*** prepare and execute ***/
$query = $dbh->prepare($sql);
foreach($values as $vals){
$query->execute($vals);
/* Array
(
[id] =
[col1] = someval1
[col2] = Someval21
)*/
}
}
//Multi Insert
$insert = array(array('id'=>'','col1'=>'someval1','col2'=>'Someval21'),
array('id'=>'','col1'=>'someval2','col2'=>'Someval22'),
array('id'=>'','col1'=>'someval3','col2'=>'Someval23'),
array('id'=>'','col1'=>'someval4','col2'=>'Someval24')
);
insert('testtable',$insert);
?>
I would like to know what query is executed using PHP PDO. I have:
<?php
try {
$DBH = new PDO("mysql:host=localhost;dbname=mytable", 'myuser', 'mypass');
}
catch(PDOException $e) {
echo $e->getMessage();
}
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$STH = $DBH->("INSERT INTO mytable (column1, column2, column3 /* etc...*/) value (:column1, :column2, :column3 /* etc...*/)");
$STH->bindParam(':column1', $column1);
$STH->bindParam(':column2', $column2);
$STH->bindParam(':column3', $column3);
/* etc...*/
$STH->execute();
// what is my query?
I would like to get something like:
INSERT INTO mytable (column1, column2, column3) value ('my first column', 32, 'some text')
Is it possible? Thanks
<?php
class MyPDOStatement extends PDOStatement
{
protected $_debugValues = null;
protected function __construct()
{
// need this empty construct()!
}
public function execute($values=array())
{
$this->_debugValues = $values;
try {
$t = parent::execute($values);
// maybe do some logging here?
} catch (PDOException $e) {
// maybe do some logging here?
throw $e;
}
return $t;
}
public function _debugQuery($replaced=true)
{
$q = $this->queryString;
if (!$replaced) {
return $q;
}
return preg_replace_callback('/:([0-9a-z_]+)/i', array($this, '_debugReplace'), $q);
}
protected function _debugReplace($m)
{
$v = $this->_debugValues[$m[1]];
if ($v === null) {
return "NULL";
}
if (!is_numeric($v)) {
$v = str_replace("'", "''", $v);
}
return "'". $v ."'";
}
}
// have a look at http://www.php.net/manual/en/pdo.constants.php
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_STATEMENT_CLASS => array('MyPDOStatement', array()),
);
// create PDO with custom PDOStatement class
$pdo = new PDO($dsn, $username, $password, $options);
// prepare a query
$query = $pdo->prepare("INSERT INTO mytable (column1, column2, column3)
VALUES (:col1, :col2, :col3)");
// execute the prepared statement
$query->execute(array(
'col1' => "hello world",
'col2' => 47.11,
'col3' => null,
));
// output the query and the query with values inserted
var_dump( $query->queryString, $query->_debugQuery() );
Most people create a wrapper class around the PDO object to record the queries as they are sent to the database. Hardly anyone uses a direct PDO object since you can add extra helper methods by wrapping, or extending PDO.
/**
* Run a SQL query and return the statement object
*
* #param string $sql query to run
* #param array $params the prepared query params
* #return PDOStatement
*/
public function query($sql, array $params = NULL)
{
$statement = $this->pdo->prepare($sql);
$statement->execute($params);
// Save query results by database type
self::$queries[] = $sql;
return $statement;
}