function to dynamic insert to Database using mysqli prepare - php

i need help with my function thet i build , i trying to use MYSQLI prepare but i am not so good .
this is my function :
function insertToDb($table,$rowsarray,$valuequestionmarks,$lenstrings,$valarray){
$this->mysqli->set_charset("utf8");
if ($insert_stmt = $this->mysqli->prepare(
"INSERT INTO $table ($rowsarray)
VALUES
($valuequestionmarks)"
))
{
$insert_stmt->bind_param("$lenstrings",$valarray);
// Execute the prepared query.
if(!$insert_stmt->execute())
{
die("Execute failed: (" . $insert_stmt->errno . ") " . $insert_stmt->error);
}
}
}
And this is how i call :
$img = "something.jpg";
$uip = ulUtils::GetRemoteIP(false);
$table='forgotpassqm';
$rowsarray = 'email,text,img,ip';
$valuequestionmarks ='?,?,?,?';
$lenstrings ='ssss';
$valarray ='$email,$text,$img,$uip';
$func->insertToDb($table,$rowsarray,$valuequestionmarks,$lenstrings,$valarray);
And i keep get this error :
Warning: mysqli_stmt::bind_param(): Number of elements in type definition string doesn't match number of bind variables
And the execute error :
Execute failed: (2031) No data supplied for parameters in prepared statement
i tryed allot of combination none work , i read other question none as my , and none worked or help either.
And i know this is about the ssss , but i using 4 and its seem to be alright so where i wrong here ?
Thanks allot.
EDIT :
$table output : forgotpassqm .
$rowsaray output: email,text,img,ip .
$valuequestionmarks output : ?,?,?,? .
$lenstrings output: ssss.
$valarray output: $email,$text,$img,$uip.
I think the problem is at $valarray.

Judging by the looks of it you are attempting to send a comma-delimited list of variables as an array (not how an array works) and you are using single quotes so variables aren't being interpolated to their values.
bind_param() expects a list of arguments after the type definitions. You aren't sending a list, you are sending the string '$email,$text,$img,$uip'.
Your call to that function should look like this:
$stmt->bind_param("ssss", $email, $text, $img, $uip);

Related

How to call a stored procedure with multiple parameters?

How would I go about calling a stored procedure in PHP with several parameters?
let's say I have a stored procedures like this in mysql:
delimiter //
create procedure createInvoice (inProduct varchar(20), inCost float, inAmount integer)
begin
.....
.....
.....
end//
delimiter ;
Now in PHP I want to call this procedure and set the inProduct, inCost and inAmount variables to values that comes from a form. How would I go about doing this? I've tried setting it up like this but it's not working out.
.....
.....
.....
<?php
if(isset($_POST['invoiceform']) {
$sp = 'call createInvoice("' . $_POST['product'] . ',' . $_POST['cost'] . ',' . $_POST['amount'] . '")';
.....
.....
.....
}
?>
So I just wanna know how to formulate the "call"-code in PHP. The rest I know (forms, what to write after the call etc).
UPDATE:
So I have it like this now:
if(isset($_POST['invoiceform']) {
$sp = 'call createInvoice(?,?,?);
$spParameter([$_POST['product], $_POST['cost'], $_POST['amount'];
$stmt = $pdo->prepare($call);
$stmt->bindParam('inProduct', $_POST['product']);
$stmt->bindParam('inCost', $_POST['cost']);
$stmt->bindParam('inAmount', $_POST['amounnt']);
$stmt->execute();
I get this error:
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in x/x/x/x/x/invoice.php on line x PDOStatement Object ( [queryString] => CALL createInvoice(?,?,?) )
UPDATE 2: SOLVED IT:
if(isset($_POST['invoiceform']) {
$sp = 'call createInvoice(?,?,?);
$spParameter([$_POST['product], $_POST['cost'], $_POST['amount'];
$stmt = $pdo->prepare($call);
$stmt->bindParam('inProduct', $_POST['product']);
$stmt->bindParam('inCost', $_POST['cost']);
$stmt->bindParam('inAmount', $_POST['amounnt']);
$stmt->execute($spParameters);
By what you are currently doing you get a concatenated string like this:
call createInvoice("product, cost, amount")
Which means you are only passing one parameter, namely the first one.
But what you actually want is this to pass all three individually:
call createInvoice("product", "cost", "amount")
So you have to add in the quotes accordingly when doing the string concatenation, like so:
$sp = "call createInvoice(?, ?, ?)";
$spParameter = [$_POST["product"], $_POST["cost"], $_POST["amount"]];
Prepare $sp then execute with parameters in $spParameter.
Side note: you are wide open to SQLinjection.

mysqli prepared statement returns 0 rows, no errors

I created a series of helper functions in php that I have been using because they make prepared mysqli statements a lot quicker and easier to follow for me. They have worked on other projects but for some reason the problem on this particular project is eluding me... It works perfectly offline but when I upload it to my server I get 0 rows returned. I am assuming it must be a setting somewhere but I can't for the life of me figure out what it is. No errors in the Apache log appear when I run this.
In this particular case I am trying to verify that a series of values exists in the database. If they do, return true. If they don't, return false.
Here is the helper function:
function verifyRow($a_verify) {
//Pass $mysqli connection variable
global $mysqli;
//Create a string from the selection criteria
$selection = implode(", ", (array) $a_verify->selection);
//Transfer table contents to table variable just for consistency
$table = $a_verify->table;
//Create a string from the parameter types
$type = implode("", (array) $a_verify->type);
//Push a reference to the string of types to the parameter array
$a_params[] =& $type;
//For each result parameter, push a column = result string into the colvals array and create a reference to the parameter in the parameters array
foreach ($a_verify->columns as $key => $value) {
$a_colvals[] = "{$value} = ?";
$a_params[] =& $a_verify->results->$key;
}
//Create a string from the column = result array
$colvals = implode(" AND ", $a_colvals);
//Generate a query
$query = "SELECT {$selection} FROM {$table} WHERE {$colvals} LIMIT 1";
//Prepare statement and error checking
if (!($stmt = $mysqli->prepare($query))) {
print "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
//Bind parameters and error checking
if (!(call_user_func_array(array($stmt, 'bind_param'), $a_params))) {
print "Binding parameters failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
//Execute statement and error checking
if (!$stmt->execute()) {
print "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}
//Get the result
$result = $stmt->get_result();
//Bind the result to a variable
$row = $result->fetch_assoc();
//If the row exists, return true
if ($row) {
return true;
}
//If the row doesn't exist, return false
else {
return false;
}
}
Here is how I am trying to retrieve the result:
// Confirm there is a user in the db with this user code
$a_verify = (object) array(
"selection" => (object) array(
"*"
),
"table" => "`users`",
"columns" => (object) array(
"`code`"
),
"results" => (object) array(
"'123456'"
),
"type" => (object) array(
"s"
)
);
print verifyRow($a_verify); //Ideally 'true'
Here is how the "users" database is set up:
|-----|---------------|--------|
| id | email | code |
--------------------------------
| 0 | test#test.com | 123456 |
--------------------------------
Any idea what the problem might be? It's driving me crazy.
Helper functions are great and here I am totally with you. But... you call this dazzling skyscraper of code "a lot quicker and easier" than vanilla SQL for real?
For some reason you are constantly moving your code back and forth from one format into another. For example, you are creating an array array("*") then convert it into object (object) and then... convert it back into array (array) $a_verify->selection. Why?
Or you take a simple SQL query, SELECT * FROM users WHERE code = ? and create a multiple-line construction where SQL keywords are substituted with array keys with an addition of a lot of quotes, parentheses and stuff. And then convert it back into SQL.
SQL is an amazing language, it survived for decades thanks to its simplicity and strictness. There is no reason to dismantle it into pieces to add a structure. SQL already has a structure. And it has many features that just aren't supported by your helper. In the end, with so much effort you get a severely limited SQL version with complicated syntax and entangled implementation. You call it a helper function?
Last but not least. Such functions where you are adding column and table names freely are asking for SQL injection. And your other question displays this appalling practice - you are adding the user input directly in your SQL. Why bother with prepared statements if you have an injection anyway? See this answer on how to deal with such situations.
Let me show you a real helper function. It makes your code short and readable and it supports full features of SQL (ordering the results for example):
function prepared_query($mysqli, $sql, $params, $types = "")
{
$types = $types ?: str_repeat("s", count($params));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute();
return $stmt;
}
If you're interesting in how it works you can read the explanation I wrote here.
Now let's rewrite your helper function based on mine
function verifyRow($mysqli, $sql, $parameters) {
$result = prepared_query($mysqli, $sql, $parameters)->get_result();
return (bool)$result->fetch_assoc();
}
Just two lines of code!
And now to verify the actual row:
var_dump(verifyRow($mysqli, "SELECT 1 FROM users WHERE code = ?", ['12345']));
One line instead of a dozen.
Now to the question why it doesn't find anything. There are two possible reasons.
indeed there is some misconfiguration.
a much simpler case: there is no such data in the table you are querying at the moment
To test for the former you must enable PHP error reporting. If your code doesn't work as expected then there must be an error somewhere and all you need is to catch it. Add these two lines to your code
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
ini_set('log_errors',1); // well to be 100% sure it will be logged
in order to make sure that all PHP and mysql errors will present themselves. Then run the code again. If it won't produce any error then likely your system is configured properly.
Now to test your data. Write a different query that would return all rows from the table
$sql = "SELECT code FROM users WHERE 1 = ?";
$result = prepared_query($mysqli, $sql, [1])->get_result();
var_dump($result->fetch_all(MYSQLI_ASSOC));
and see what you really have in your database. Probably there are no rows or a different code value. A hint: there could be non-printable characters that would prevent the matching. to reveal them use a very handy function rawurlencode(): it will leave all basic characters as is but convert everything else into hex codes making them an easy spot

Dynamic number of arguments in bind_param [duplicate]

This question already has an answer here:
Bind multiple parameters into mysqli query
(1 answer)
Closed 5 years ago.
I have been trying to use call_user_func_array()but dont seem to get it right.
$sql_sentence = "SELECT * FROM test_table WHERE Fag = ? AND (" . $sql_subject . ") AND (" . $sql_grade . ") AND (" . $sql_type . ")";
$sql = $conn->prepare($sql_sentence);
$allarrays = array_merge(array('ssss'),array($_POST['Fag']),$_POST['subject'],$_POST['Grade'],$_POST['Type']);
//testing to see if it prints out right values of array.
for ($x = 0; $x < count($allarrays); $x++) {
echo "The number $x is $allarrays[$x] <br>";
}
call_user_func_array(array($sql, "bind_param"),$allarrays);
$sql->execute();
But I get this error Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, and it points it to line call_user_func....
When I print out the SQL sentence it looks like this:
SELECT * FROM test_table WHERE Fag = ? AND (Subject LIKE ?) AND (Grade LIKE ?) AND (Type LIKE ?)
and all array-values are right, and the first array value is 'ssss', and after the first array comes four arrays with different values.
Have I done anything wrong here?
Do you need more code?
EDIT: Can you open this question. I found an answer which was different than the similar question! Think it should be printed here.
call_user_func_array expects its first argument to be a callable not an array:
mixed call_user_func_array ( callable $callback , array $param_arr )
Which function are trying to call, exactly? mysqli_stmt::bind_param()?
If so, it would need to look something like this:
call_user_func_array(array($stmt, 'bind_param'), array('s', $_POST['Fag']) );

Dynamically turning undefined index using isset()

I'm writing a generic function that will take a large number of fields from $_POST and build an SQL insert into a table. In this case, I have a number of Undefined indexes and from reading other posts on SO, I am using a ternary to test if the variable exists. This works perfectly when I use it in interactive php, especially since there are no $_POST variables defined.
But when I use it in my form, I seem to get a extra quote and a few returns but I cannot see where they are coming from. I've beaten about this in different ways but am hoping someone can help me see what I'm not seeing.
function SaveDonation($form) {
try {
$querystr = "INSERT INTO GeneralDonations(donationForm, firstName, startYear)"
. "VALUES(" . "'" . $form . "', "
. ((!isset($_POST['firstName']))
? "'', " : ("'" . mysql_real_escape_string($_POST['firstName'])."', "))
. ((isset($_POST['startDate']))
? ("'" . mysql_real_escape_string($_POST['startDate'])."' ") : "'' ")
.")";
echo "<pre>query = "; var_dump($querystr);die;
$donation = $this->db->insertRow($querystr);
$result = true;
} catch(MysqlException $e) {
$result = false;
$this->errorMsg = $e->getMessage();
}
return $result;
}
The startDate is the undefined index value. This is the browser output using var_dump. It appears that the x-debug output is showing instead of the variable. But all table, no useful data? Please help me see what's different here?
string 'INSERT INTO GeneralDonations(
donationForm, firstName, startYear)VALUES('buy-a-foot', 's',
'<br />\r\n<font size=\'1\'><table class=\'xdebug-error xe-notice\'
dir=\'ltr\' border=\'1\' cellspacing=\'0\' cellpadding=\'1\'>\r\n
<tr><th align=\'left\' bgcolor=\'#f57900\' colspan=' )' (length=284)
Your code has some problems:
Please use prepared statements (see below)!
The error message (which is not entirely shown) would continue with "Undefined index firstName", since there's an ! too much in (!isset($_POST['firstName'])).
The error message is incomplete because your xdebug shortens var_dump output. You can change this behaviour with the settings xdebug.overload_var_dump and xdebug.var_display_max_data. See xdebug documentation.
If you can't use prepared statements, consider using some sprintf() construction to improve readability.
// Prepared statements (untested)
$stmt = $db->prepare("
INSERT INTO GeneralDonations(donationForm, firstName, startYear)
VALUES (?, ?, ?)");
$stmt->execute(array(
$form,
isset($_POST['firstName']) ? $_POST['firstName'] : '',
isset($_POST['startDate']) ? $_POST['startDate'] : ''
));

Trouble binding an imploded array into a mysql prepared statement

I am beating my head over the below syntax error. I am trying to bind an imploded array into a prepared statement, but I am getting the following syntax error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1
Here is my code. Can anyone see where I am going wrong?
<?php
include('config.php');
$selected = $_POST['selected'];
if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN ?")) {
$stmt->bind_param("s", "('" . implode("', '", $selected) . "')" );
$stmt->execute();
$stmt->close();
print "ok";
} else {
print $mysqli->error;
}
$mysqli->close();
?>
As a test, I tried:
print "('" . implode("', '", $selected) . "')";
Which correctly gives me
('me#me.com', 'you#you.com')
Let me save you some trouble and tell you what you're trying to do won't work anyway. You are only binding one parameter to your IN() function call. You think you're passing a comma separated list but you are actually only passing a comma separated string which is treated as one value. This means you will be search for one record with a value of "'me#me.com', 'you#you.com'" instead of records that match "me#me.com" or "you#you.com".
To overcome this you need to:
Dynamically generate your types string
Use call_user_func_array() to bind your parameters
You can generate the types string like this:
$types = str_repeat('s', count($selected));
All this does is create a string of s's that is as many characters as the number of elements in the array.
You would then bind your parameters using call_user_func_array() like this (notice I put the parenthesis back in for the IN() function):
if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN (?)")) {
call_user_func_array(array($stmt, "bind_param"), array_merge($types, $selected));
But if you try this you will get an error about mysqli_stmt::bind_param() expecting parameter two to be passed by reference:
Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, value given
This is kind of annoying but easy enough to work around. To work around that you can use the following function:
function refValues($arr){
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
It just creates an array of values that are references to the values in the $selected array. This is enough to make mysqli_stmt::bind_param() happy:
if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN (?)")) {
call_user_func_array(array($stmt, "bind_param"), array_merge($types, refValues($selected)));
Edit
As of PHP 5.6 you can now use the ... operator to make this even simpler:
$stmt->bind_param($types, ...$selected);

Categories