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.
Related
I'm trying for the last few days but I just can't get this figured out. I have a filter page where the user can select the start_date, end_date, client and paying_status. Client and paying_status are referencing to the main service table.
I even echo all the $_POST and get the right inputs but my SQL query isn't producing any results. When I run the same query on my database, I get the right results. I don't see any errors or I'm getting blind over my own mistakes after all these days.
<?php
include "../controller/session.php";
include "../controller/pdo.php";
$submit = isset($_POST["filter-submit"]) ? $_POST["filter-submit"] : "";
$date_start = isset($_POST["date_start"]) ? $_POST["date_start"] : "";
$date_end = isset($_POST["date_end"]) ? $_POST["date_end"] : "";
$client = isset($_POST["client"]) ? $_POST["client"] : "";
$payed = isset($_POST["payed"]) ? $_POST["payed"] : "";
echo $date_start . "<br>" . $date_end . "<br>" . $client . "<br>" . $payed . "<br>";
if ($submit == "Filter") {
$query = $db->prepare("SELECT * from service where(date BETWEEN ':date_start'AND ':date_end') AND clientId=:client AND paying_status=:payed;");
$query->bindParam(':date_start', $date_start);
$query->bindParam(':date_end', $date_end);
$query->bindParam(':client', $client);
$query->bindParam(':payed', $payed);
$results = $query->fetchAll(PDO::FETCH_OBJ);
var_dump($results);
}
2019-01-01
2019-07-03
1
1
array(0) {}
Above are the $_POST inputs and the empty array. I don't know where to watch anymore.
EDIT:
SELECT * from service where(date BETWEEN '2019-01-01'AND '2019-07-03') AND clientId=1 AND paying_status=1;
This works fine on my database.
EDIT 2: Updated code. Still doesn't work.
if ($submit == "Filter") {
$query = $db->prepare("SELECT * from service where(date BETWEEN ':date_start'AND ':date_end') AND clientId=:client AND paying_status=:payed;");
$query->bindParam(':date_start', $date_start);
$query->bindParam(':date_end', $date_end);
$query->bindParam(':client', $client, PDO::PARAM_INT);
$query->bindParam(':payed', $payed, PDO::PARAM_INT);
$query->execute();
$results = $query->fetchAll(PDO::FETCH_OBJ);
var_dump($results);
}
EDIT 3:
if ($submit == "Filter") {
$query = $db->prepare("SELECT * from service where(date BETWEEN :date_start AND :date_end) AND clientId=:client AND paying_status=:payed;");
$query->bindParam(':date_start', $date_start);
$query->bindParam(':date_end', $date_end);
$query->bindParam(':client', $client, PDO::PARAM_INT);
$query->bindParam(':payed', $payed, PDO::PARAM_INT);
$query->execute();
$results = $query->fetchAll(PDO::FETCH_OBJ);
var_dump($results);
}
This works! Can someone explain why i sometimes need to execute the query and sometimes I just can fetch the data with fetchAll or just fetch? When do i need to execute and when can I just fetch? Thanks
You are getting the '..number of bound variables ...' error because as #Xatenev says you don't need to quotes around your place markers. What you are asking PDO to prepare is the string '...BETWEEN :date_start AND ... i.e. it looks for a date with STRING VALUE OF ':date_start' which presumably doesn't exist, rather than looking for a date value with the value of :date_start.
If should look like this:
from service where(date BETWEEN :date_start .....
just to expand slightly, the actual error then occurs because you try to bind the values for each of the quoted placeholders, but PDO cannot see these placeholders at all, as all it can interpret are some strings you have added and two placemarkers
If you remove your quotes then it no longer sees this as a string and will view it as the place marker as intended
UPDATE -
Re OPs comments about not quite understanding, imagine you have a variable $values
$values[] contains 'jam','bread', or 'peanut butter' depending on the input.
So you want to insert into a table called sandwich_parts and you create a query based on the input (or selection, or loop for whatever)
foreach($values as $value){
$q1->prepare("INSERT INTO sandwich_parts (part) values (':value'));
$q2->prepare("INSERT INTO sandwich_parts (part) values (:value));
$q->bindValue(':value',$value,PDO::PARAM_STR);
}
this would be sent to mysql on execute() as
INSERT INTO sandwich_parts (part) values (':value')
INSERT INTO sandwich_parts (part) values ('jam')
INSERT INTO sandwich_parts (part) values (':value')
INSERT INTO sandwich_parts (part) values ('bread')
INSERT INTO sandwich_parts (part) values (':value')
INSERT INTO sandwich_parts (part) values ('peanut butter')
because the first insert always reads the string ':value' whereas the second sees the place marker and binds the parameter, as such you would get errors for the first query each time because it cannot see a placeholder to bind the value to
I hope that helps your understanding a little, basically, you don't need to quote placeholders that is what the binding process is for
I have data that should be escaped inside a JSON formatted string, so I'm using PDO's named parameters and PDO::Prepare to bind them.
Because JSON with it's apostrophes causes errors in the MySQL query, i have to use single quotes around it - although this causes the PDO::Prepare to ignore the named parameters inside the JSON, so it fails with SQLSTATE[HY093]: Invalid parameter number: parameter was not defined.
Any ideas how to work around this?
function send($_data) {
global $_SESSION;
global $dbApi;
#These are temporary debug variables:
$_SESSION['room_id'] = 1;
$id = 124;
$json = '"' . $id . '": {"user_id": ":email","data": ":data"}';
$query = "UPDATE `room_index` " .
"SET `data` = JSON_ARRAY_INSERT(`data`, '$[0]', '" . $json . "') " .
"WHERE `id` = :room_id";
$dbApi->query($query, array(':email' => $_SESSION['email'],
':data' => $_data,
':room_id' => $_SESSION['room_id']));
}
To explain the code a bit, :email ($_SESSION['email']) doesn't have to be a parameter, but it's cleaner this way. The main issue is :data ($_data) - that is user input straight from a textarea via JS.
$dbApi is a class with a proper query function, that looks like this:
function query($_query, $_params = array()) {
global $_DB; # <- Database connection object
$query = $_DB->prepare($_query);
if (! $query)
echo $_DB->errorInfo();
try {
$query->execute($_params);
} catch (PDOException $e) {
die( $e->getMessage() );
}
return $query;
}
There are 2 issues with the code.
1. JSON_INSERT is more appropriate.
As I'm inserting a named object into another object (the top level document), the JSON_INSERT offers such a syntax straight away
2. Using JSON_OBJECT instead of manually writing the JSON syntax
As my main issue was, that PDO doesn't replace single, or double quoted parameters, the solution was using JSON_OBJECT, which doesn't require double quotes as they are automatically generated later (my assumption) - but after PDO replaces the variables and also places single quotes around them.
New, tested code outputting valid JSON:
#Temporary, to avoid other unrelated issues
$_SESSION['room_id'] = 1;
$_SESSION['email'] = 'email#email.com';
$id = 123;
$json = 'JSON_OBJECT("user_id", :email, "data", :data)';
$query = "UPDATE `room_index` " .
"SET `data` = JSON_INSERT(`data`, :id, $json) " .
"WHERE `id` = :room_id";
$dbApi->query($query, [':id' => "$." . $id,
':email' => $_SESSION['email'],
':data' => $_data,
':room_id' => $_SESSION['room_id']]);
The code below makes a query and then loops through those results. I am having a hard time understanding what "?" is in that query and how to make "?" dynamic.
It assume that name = "?". I have changed ? to a variable I added in the function $ad_id and that still does not work. I basically need to query the DB only WHERE name = a variable. But this simple solution does not work. The commented line is what I replaced.
Any help will be greatly appreciated. Incase you are wondering this is the code I am trying to make dynamic and not just pulling all images in the table:
https://github.com/blueimp/jQuery-File-Upload/wiki/PHP-MySQL-database-integration
protected function set_additional_file_properties($file) {
parent::set_additional_file_properties($file);
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$ad_id = '1';
//$sql = 'SELECT `id`, `type`, `title`, `description` FROM `'
//.$this->options['db_table'].'` WHERE `name`=?';
$sql = 'SELECT id, type, title, description FROM '.$this->options['db_table'].' WHERE name = '.'$ad-id'.';
$query = $this->db->prepare($sql);
$query->bind_param('s', $file->name);
$query->execute();
$query->bind_result(
$id,
$type,
$title,
$description
);
while ($query->fetch()) {
if ($description == $ad_id){
$file->id = $id;
$file->type = $type;
$file->title = $title;
$file->description = $description;
};
}
}
}
In this example, the SQL query is using bound parameters. This means that you create the string for the SQL query, and put a placeholder in for each variable - the placeholder is the '?' character you mentioned. Then the following two lines:
$query = $this->db->prepare($sql);
$query->bind_param('s', $file->name);
The first line sends the query to the database, and the second line sends the parameters that need to be bound into the placeholder sites (where those question marks were in the query string). So if you want to change the variable that is inserted into the query, you should change the bind_param call.
Check out the documentation for bind_param, but basically the 's' specifies a string parameter, and the second argument is the variable itself.
Hopefully that gives you enough insight into what is going on here to change the code to do exactly what you want.
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);
I have this code (which worked):
if (isset($_POST['plant_name']) && $_POST['plant_name']) {
$where .= "AND (common_name) LIKE '".strtolower($_POST['plant_name']) . "' OR (latin_name) LIKE '".strtolower($_POST['plant_name'])."%' ";
}
But I wanted to change it to prepared statements and my attempt is below but I am getting errors:
$plant_name = $_POST['plant_name'];
if (isset($_POST['plant_name']) && $_POST['plant_name']) {
$stmt = $conn2->prepare . $where .= "AND (common_name) LIKE '".'?'. "' OR (latin_name) LIKE '".'?'."%' ";
}
$stmt->bind_param('s', $plant_name);
$stmt->execute();
Could somebody please help me out please
My errors are:
Notice: Undefined property: mysqli::$prepare
Fatal error: Call to a member function bind_param() on a non-object
EDIT: You're using mysqli not PDO my fault. Unfortunately mysqli doesn't support named parameters.
In your original example, you're treating $conn2->prepare like it's a property, but it's a function.
Try this:
// Presumably by this point you have a $sql and a $where that you're appending to.
if (isset($_POST['plant_name']) && $_POST['plant_name']) {
$where .= "AND (common_name) LIKE ? OR (latin_name) LIKE ?";
}
$stmt = $conn2->prepare($sql . $where);
if (isset($_POST['plant_name']) && $_POST['plant_name']) {
$stmt->bind_param('s', strtolower($_POST['plant_name']));
$stmt->bind_param('s', strtolower($_POST['plant_name'])."%");
}
Here's the PDO way (I think it's a lot cleaner, but it's probably not worth changing from mysqli to PDO at this point for you):
$statement = $conn2->prepare(
"UPDATE tablename SET
field1 = :value1,
field2 = :value2
WHERE common_name LIKE :plant_name
OR latin_name LIKE :plant_name
");
$statement->bindValue('value1', $_POST['field1']);
$statement->bindValue('value2', $_POST['field2']);
$statement->bindValue('plant_name', strtolower($_POST['plant_name']));
Note a few things about this:
I switched you from using ? (numerically indexed placeholders) to :name (name-based placeholders). Since you're using the same value for searching both fields, this gets you a very small performance gain, and makes the SQL a lot more readable.
You don't want to put quote marks around the bound parameter. One of the advantages of bound parameters is that they don't need to be quote-escaped. The SQL is sent on a separate channel from the parameter values. So there's no chance of SQL injection. The database notices the bound parameter and reads the right value all on its own by looking it up in the bound parameters data.