So, I'm getting the following error using PHP's PDO:
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
Now, as far as I understand, this error only occurs when a parameter is used in a query, but then never properly bound. Typos, for example, make this a common error.
The problem is... I can't seem to find the issue! I've gone through each parameter several times, and can't find any disparities. Could something else be causing this issue? Am I just scrolling over an obvious typo that requires a second set of eyes to see? Any help would be hugely appreciated! Note that the error is occurring on the execute(), if that matters to you.
$sth = $dbh->prepare("
INSERT INTO administrators
(
org_id,
admin_email,
passwd,
passwd_salt,
announcements,
logo,
design,
content,
layout,
services,
contributions_edit,
contributions_report,
contributions_enable,
pledges,
calendar,
event,
survey,
email,
caller,
bulletin,
prayer,
email_newsletter,
member_add,
member_edit,
passwd_reset,
spotlight,
profile_status,
groups,
attendance,
sermons,
church_info,
mail_merge,
file_upload,
admin_name,
administrators,
newsletter,
outreach,
charts,
streaming
)
VALUES
(
:org_id,
:admin_email,
:passwd,
:passwd_salt,
:announcements,
:logo,
:design,
:content,
:layout,
:services,
:contributions_edit,
:contributions_report,
:contributions_enable,
:pledges,
:calendar,
:event,
:survey,
:email,
:caller,
:bulletin,
:prayer,
:email_newsletter,
:member_add,
:member_edit,
:passwd_reset,
:spotlight,
:profile_status,
:groups,
:attendance,
:sermons,
:church_info,
:mail_merge,
:file_upload,
:admin_name,
:administrators,
:newsletter,
:outreach,
:charts,
:streaming
)
");
$sth->bindParam(':org_id,', $org_id);
$sth->bindParam(':admin_email', $admin_email);
$sth->bindParam(':passwd', $passwd);
$sth->bindParam(':passwd_salt', $passwd_salt);
$sth->bindParam(':announcements', $announcements);
$sth->bindParam(':logo', $logo);
$sth->bindParam(':design', $design);
$sth->bindParam(':content', $content);
$sth->bindParam(':layout', $layout);
$sth->bindParam(':services', $services);
$sth->bindParam(':contributions_edit', $contributions_edit);
$sth->bindParam(':contributions_report', $contributions_report);
$sth->bindParam(':contributions_enable', $contributions_enable);
$sth->bindParam(':pledges', $pledges);
$sth->bindParam(':calendar', $calendar);
$sth->bindParam(':event', $event);
$sth->bindParam(':survey', $survey);
$sth->bindParam(':email', $email);
$sth->bindParam(':caller', $caller);
$sth->bindParam(':bulletin', $bulletin);
$sth->bindParam(':prayer', $prayer);
$sth->bindParam(':email_newsletter', $email_newsletter);
$sth->bindParam(':member_add', $member_add);
$sth->bindParam(':member_edit', $member_edit);
$sth->bindParam(':passwd_reset', $passwd_reset);
$sth->bindParam(':spotlight', $spotlight);
$sth->bindParam(':profile_status', $profile_status);
$sth->bindParam(':groups', $groups);
$sth->bindParam(':attendance', $attendance);
$sth->bindParam(':sermons', $sermons);
$sth->bindParam(':church_info', $church_info);
$sth->bindParam(':mail_merge', $mail_merge);
$sth->bindParam(':file_upload', $file_upload);
$sth->bindParam(':admin_name', $admin_name);
$sth->bindParam(':administrators', $administrators);
$sth->bindParam(':newsletter', $newsletter);
$sth->bindParam(':outreach', $outreach);
$sth->bindParam(':charts', $charts);
$sth->bindParam(':streaming', $streaming);
$sth->execute();
Thanks so much!
$sth->bindParam(':org_id,', $org_id);
^
|
|_____________ This , is intentional? i guess not.
$sth->bindParam(':admin_email', $admin_email);
$sth->bindParam(':passwd', $passwd);
$sth->bindParam(':passwd_salt', $passwd_salt);
$sth->bindParam(':announcements', $announcements);
$sth->bindParam(':logo', $logo);
$sth->bindParam(':design', $design);
$sth->bindParam(':content', $content);
$sth->bindParam(':layout', $layout);
$sth->bindParam(':services', $services);
$sth->bindParam(':contributions_edit', $contributions_edit);
$sth->bindParam(':contributions_report', $contributions_report);
$sth->bindParam(':contributions_enable', $contributions_enable);
$sth->bindParam(':pledges', $pledges);
$sth->bindParam(':calendar', $calendar);
$sth->bindParam(':event', $event);
$sth->bindParam(':survey', $survey);
$sth->bindParam(':email', $email);
$sth->bindParam(':caller', $caller);
$sth->bindParam(':bulletin', $bulletin);
$sth->bindParam(':prayer', $prayer);
$sth->bindParam(':email_newsletter', $email_newsletter);
$sth->bindParam(':member_add', $member_add);
$sth->bindParam(':member_edit', $member_edit);
$sth->bindParam(':passwd_reset', $passwd_reset);
$sth->bindParam(':spotlight', $spotlight);
$sth->bindParam(':profile_status', $profile_status);
$sth->bindParam(':groups', $groups);
$sth->bindParam(':attendance', $attendance);
$sth->bindParam(':sermons', $sermons);
$sth->bindParam(':church_info', $church_info);
$sth->bindParam(':mail_merge', $mail_merge);
$sth->bindParam(':file_upload', $file_upload);
$sth->bindParam(':admin_name', $admin_name);
$sth->bindParam(':administrators', $administrators);
$sth->bindParam(':newsletter', $newsletter);
$sth->bindParam(':outreach', $outreach);
$sth->bindParam(':charts', $charts);
$sth->bindParam(':streaming', $streaming);
$sth->execute();
Related
Im working with a lot of sql queries. While I have not mastered PDO yet I was hoping to come here for a bit of help since my previous searches didn't deliver much in terms of help. I did come across this link on SO but it seems a bit out of scope to what I am doing
Consider The following code, which works 100%;
public function composeMsg($userID, $toUser, $subject, $msg, $sentOn ){
$db = DB::getInstance();
$sql = "INSERT INTO messages (userID, fromID, subject, body, senton) values (:userID, :toUser, :subject, :msg, :sentOn )";
$stmnt = $db->prepare($sql);
//NOT EFFICIENT
$stmnt->bindValue(':userID', $userID);
$stmnt->bindValue(':toUser', $toUser);
$stmnt->bindValue(':subject', $subject);
$stmnt->bindValue(':msg', $msg);
$stmnt->bindValue(':sentOn', $sentOn);
$stmnt->execute();
if($stmnt->rowCount() > 0){
return true;
}
else{
return false;
}
}//FUNCTION
Im finding myself to continuously type $stmnt->bindValue(':value', $value) multiple times as can be seen from the code above. Im looking for a build in PDO function or something similar which I can make use of to avoid all the repetition.
Any advise welcomed
Binding them all as part of the execute...
$stmnt->execute([':userID'=> $userID,
':toUser'=> $toUser,
':subject' => $subject,
':msg' => $msg,
':sentOn' => $sentOn]);
I have two inserts on a processing page. The first works without a hitch. The second will not even activate. I even tried putting a PDO query to see if it would work but still nothing.
$cpinsert = $db->prepare('insert into Chatposts values (0, :chatid, :name, :url, :text, now(), :ipaddress, 0)');
$cpinsert -> bindParam(':chatid', $chatroomid, PDO::PARAM_INT);
$cpinsert -> bindParam(':name', $name, PDO::PARAM_STR);
$cpinsert -> bindParam(':url', $url, PDO::PARAM_STR);
$cpinsert -> bindParam(':text', $text, PDO::PARAM_STR);
$cpinsert -> bindParam(':ipaddress', $ipaddress, PDO::PARAM_STR);
$cpinsert -> execute();
// Needs an error checker
$cpid = $cpinsert ->lastInsertID();
$cpinsert->closeCursor();
^ That works fine, though I don't know about the lastinsertid since I cannot test it.
\V/ Nothing in there will execute no matter what I try. Something is preventing anything there from executing or I didn't close the above's connection properly.
// Targets Insert
//if (isset($target)):
$query = "insert into Targets values (9,'rommel')";
$db->query($query);
$targetinsert = $db->prepare('insert into Targets values (:cpid,:tname)');
foreach ($target as $tname):
$targetinsert -> bindParam(':cpid', $cpid, PDO::PARAM_INT);
$targetinsert -> bindParam(':tname', $tname, PDO::PARAM_STR);
endforeach;
$targetinsert -> execute();
//endif;
I have tried everything I know of and no luck. It is quite possible I did a minor mistake since I am new to PDO. Closecursor didn't seem to do anything either when I added it in.
You said you need to do execute many inserts, but for some reason you are executing your query only once.
Also, please remove these try..catch things from your code - they are the reason why you have no idea what's going wrong
I had to recreate a half functional model of my page but I found the problem, it was lastinsertid(). I was applying a PDOstatement class on a PDO class.
Before:
$cpid = $cpinsert->lastInsertID();
After:
$cpid = $db->lastInsertID();
I just had to call the Database instead of the prepare with that line of code.
I am trying to start getting to grips with PHP and also PDO. As I am starting now, I hear that PDO is more beneficial, that is why I am not using the more popular mysqli.
I am having trouble getting data inserted into my db using PDO. I wanted to try and use prepared statements to minimize sql injection. I have tried many ways and keep hitting a brick wall.
I could do with some pointers please.
here is the error message.
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in C:\wamp\www\test-search\insert_property.php on line 61
This is the relevant php code.
// Insert Property
// Include db
include 'db_connect_pdo.php';
include 'defines.php';
try {
// create SQL
$sql = "INSERT INTO property (pid, title, intro_en, description_en, bedrooms,
bathrooms, address, city, country, stype, ptype, price)
VALUES(:pid, :title, :intro_en, :description_en, :bedrooms, :bathrooms, :address,
:city, :country, :stype, :ptype, :price)";
// prepare the statement
$stmt = $conn->prepare($sql);
// bind the parameters and execute the statement
$stmt->bindValue(':pid', $pid);
$stmt->bindValue(':title', $title);
$stmt->bindValue(':intro_en', $intro_en);
$stmt->bindValue(':description_', $description_en);
$stmt->bindValue(':bedrooms', $bedrooms);
$stmt->bindValue(':bathrooms', $bathrooms);
$stmt->bindValue(':address', $address);
$stmt->bindValue(':city', $city);
$stmt->bindValue(':country', $country);
$stmt->bindValue(':stype', $stype);
$stmt->bindValue(':ptype', $ptype);
$stmt->bindValue(':price', $price);
// execute the statement
$stmt->execute();
}
catch (Exception $e)
{
echo $e->getMessage();
}
$conn = null;
?>
</blockquote></code>
Not sure where it is going wrong, any advice will be greatly appreciated.
Your error is this line:
$stmt->bindValue(':description_', $description_en);
Should be:
$stmt->bindValue(':description_en', $description_en);
I'm having a slight problem with the PHP PDO library and prepared statements. As far as I can see the prepared statement below should work but it doesn't, instead I get: "PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens".
My PHP code for this section looks like:
$sql = 'INSERT INTO '.POLYGON_TABLE.' (user_id, polygon, polygon_type) VALUES (:userId, PolygonFromText(\'POLYGON((:polygonArea))\'), :polygonType)';
$sth = $this->pdo->prepare($sql);
$sth->bindValue(':userId', $polygon->getUserId(), \PDO::PARAM_INT);
$sth->bindValue(':polygonArea', $polygon->getPolygonAsText(), \PDO::PARAM_STR);
$sth->bindValue(':polygonType', $polygon->getPolygonType(), \PDO::PARAM_STR);
if($sth->execute()) {
return true;
} else {
return false;
}
I have done a var_dump of $polygon->getUserId(), $polygon->getPolygonAsText() and $polygon->getPolygonType() and get the following:
string(1) "1"
string(226) "53.897910476098765 -1.739655277929728, 53.865530797116 -2.080231449804728, 53.67235280490181 -2.006073734960978, 53.68862047002787 -1.621552250585978, 53.89305512284903 -1.539154789648478, 53.897910476098765 -1.739655277929728"
string(7) "commute"
The issue is with $polygon->getPolygonAsText() as commenting out this particular bindValue call and the PolygonFromText(\'POLYGON((:polygonArea))\') from the SQL statement causes the query to work.
I'm now completely at a loss. Anyone know what's wrong here? I can't see anything wrong with the text contained within $polygon->getPolygonAsText(). I have searched high and low for a solution to this and spent several hours this evening tinkering with the code but to no avail.
I have even tried the suggestions in these 2 stack overflow topics but they didn't work either:
Invalid parameter number on PDO Prepared Statement
PHP PDO prepared statements
Any help would be much appreciated...
Did you try passing in the entire expression as the bind value?
$sql = 'INSERT INTO '.POLYGON_TABLE.' (user_id, polygon, polygon_type) VALUES (:userId, PolygonFromText(:polygonArea), :polygonType)';
$sth = $this->pdo->prepare($sql);
$area = sprintf("POLYGON((%s))", $polygon->getPolygonAsText());
$sth->bindValue(':userId', $polygon->getUserId(), \PDO::PARAM_INT);
$sth->bindValue(':polygonArea', $area, \PDO::PARAM_STR);
$sth->bindValue(':polygonType', $polygon->getPolygonType(), \PDO::PARAM_STR);
It appears that you're trying to use a named parameter inside a string:
PolygonFromText(\'POLYGON((:polygonArea))\')
This would be akin to doing something like this:
UPDATE foo SET bar = 'blah blah :wontwork blah blah'
What you should try instead is binding the whole string in the query:
PolygonFromText(:polygonArea)
And then including the rest of the string in the bound value:
$sth->bindValue(':polygonArea', 'POLYGON((' . $polygon->getPolygonAsText() . '))', \PDO::PARAM_STR);
Last resort you could do this:
$sql = "INSERT INTO ".POLYGON_TABLE." (user_id, polygon, polygon_type) "
."VALUES (:userId, PolygonFromText('POLYGON(". $polygon->$getPolygonAsText
.")'),:polygonType)";
But I think you should try the ? params first and see how that goes.
$sql = "INSERT INTO ".POLYGON_TABLE." (user_id, polygon, polygon_type) "
."VALUES (?, PolygonFromText('POLYGON(?)'), ?);";
$data = array($polygon->getUserId(), $polygon->getPolygonAsText(), $polygon->getPolygonType());
$query->execute($data);
Btw, I also think those single quotes around the POLYGON(?) function are dodgy... usually you don't quote a method call do you?
Is there a way I can put these bindParam statements into one statement?
$q = $dbc -> prepare("INSERT INTO accounts (username, email, password) VALUES (:username, :email, :password)");
$q -> bindParam(':username', $_POST['username']);
$q -> bindParam(':email', $_POST['email']);
$q -> bindParam(':password', $_POST['password']);
$q -> execute();
I was using mysqli prepared before where it was possible, I switched to PDO for assoc_array support. On the php.net website for PDO it shows them on seperate lines, and in all examples I have seen it is on seperate lines.
Is it possible?
Example 2 on the execute page is what you want:
$sth->execute(array(':calories' => $calories, ':colour' => $colour));
You may want to look at the other examples too. With question mark parameters, it would be:
$q = $dbc -> prepare("INSERT INTO accounts (username, email, password) VALUES (?, ?, ?)");
$q->execute(array($_POST['username'], $_POST['email'], $_POST['password']));
If those are the only columns, you can just write:
$q = $dbc -> prepare("INSERT INTO accounts VALUES (?, ?, ?)");
$q->execute(array($_POST['username'], $_POST['email'], $_POST['password']));
helper function is a function that makes you help to avoid writing bunch of repetitive code every time you want to run a query.
This is called "programming" and there is almost none of it on this site, at least under "PHP" tag.
While many peiople thinks that programming stands for copy/pasting chunks of code from manual examples, it's somewhat different.
Although it's hard to learn but really worth it, especially if you're devoting yourself to web-developing.
As you can see, no accepted answer did no real help for you, as you still have to write something like
$sth->execute(array(':username' => $_POST['username'],
':email' => $_POST['email']
':password' => $_POST['password']);
as many times as many fields in your table, which makes not much difference from your initial approach, still makes you write each field name FOUR times.
But being a programmer, you can use powers of programming. A loop, for example - one of cornerstone programming operators.
Every time you see repetitions, you know there should be a loop.
for example, you can set up a list of fields, naming them only once.
And let a program do the rest.
Say, such a function like this one
function pdoSet($fields, &$values, $source = array()) {
$set = '';
$values = array();
if (!$source) $source = &$_POST;
foreach ($fields as $field) {
if (isset($source[$field])) {
$set.="`$field`=:$field, ";
$values[$field] = $source[$field];
}
}
return substr($set, 0, -2);
}
being given an array of field names, it can produce both insert statement and data array for you. Programmatically. So, your code become no more than these 3 short lines:
$fields = array('username', 'email', 'password');
$stmt = $dbh->prepare("INSERT INTO accounts SET ".pdoSet($fields,$values));
$stmt->execute($values);
Your Common Sense is totally right that the aim of coding is to save typing... but his solution doesn't help with the BindParams bit. I couldn't find anything else about this online, so here's something I finally just persuaded to work - I hope it's useful for someone!
//First, a function to add the colon for each field value.
function PrepareString($array){
//takes array (title,author);
//and returns the middle bit of pdo update query :title,:author etc
foreach($array as $k =>$v){
$array[$k]=':'.$v;
}
return implode(', ', $array);
}
Then...
function PdoInsert($table_name,$array){
$db = new PDO(); //however you create your own pdo
//get $fields and $vals for statement
$fields_vals=array_keys($array);
$fields=implode(',',$fields_vals);
$vals=PrepareString($fields_vals);
$sql = "INSERT INTO $table_name($fields) VALUES ($vals)";
$qwe=$db->prepare($sql);
foreach ($array as $k =>$v ){
//add the colon to the key
$y=':'.$k;
//god knows why it doesn't like $qwe->bindParam($y,$v,PDO::PARAM_STR);
// but it really doesn't! So we refer back to $array.
//add checks for different binding types here
(see PDO::PARAM_INT is important in bindParam?)
$qwe->bindParam($y,$array[$k],PDO::PARAM_STR);
}
if ($qwe->execute()==true){
return $db->lastInsertId();
}
else {
return $db->errorCode();
}
}
Then you can insert anything by doing
PdoInsert('MyTableName',array('field1'=>$value1,'field2'=>$value2...));
Having previously sanitized your values of course.
+1 to Matthew Flaschen for the accepted answer, but I'll show you another tip. If you use SQL parameters with names the same as the entries in $_POST, you could take advantage of the fact that $_POST is already an array:
$q->execute($_POST);
The SQL parameter names are prefixed with a colon (:) but the keys in the $_POST array are not. But modern versions of PDO account for this - you no longer need to use colon prefixes in the keys in the array you pass to execute().
But you should be careful that anyone can add extra parameters to any web request, and you should get only the subset of $_POST params that match parameters in your query.
$q = $dbc -> prepare("INSERT INTO accounts (username, email, password)
VALUES (:username, :email, :password)");
$params = array_intersect_key($_POST, array("username"=>1,"email"=>1,"password"=>1));
$q->execute($params);
Personally, I prefer to use a wrapper function for all of pdo, which simplifies the code necessary substantially.
For example, to run bound queries (well, all my queries), I do this:
$iterable_resultset = query("INSERT INTO accounts (username, email, password) VALUES (:username, :email, :password)", array(':username'=>'bob', ':email'=>'bob#example.com', ':password'=>'bobpassword'));
Note that not only is the sql simply a string, but it's actually a reusable string, as you can simply pass the sql as a string and change the array of variables to pass in if you want to perform a similar insert right after that one (not applicable to this situation, but applicable to other sql use cases).
The code that I use to create this wrapper function is as below:
/**
* Run bound queries on the database.
*
* Use: query('select all from players limit :count', array('count'=>10));
* Or: query('select all from players limit :count', array('count'=>array(10, PDO::PARAM_INT)));
*
* Note that it returns foreachable resultset object unless an array is specifically requested.
**/
function query($sql, $bindings=array(), $return_resultset=true) {
DatabaseConnection::getInstance(); // Gets a singleton database connection
$statement = DatabaseConnection::$pdo->prepare($sql); // Get your pdo instance, in this case I use a static singleton instance. You may want to do something simpler.
foreach ($bindings as $binding => $value) {
if (is_array($value)) {
$first = reset($value);
$last = end($value);
// Cast the bindings when something to cast to was sent in.
$statement->bindParam($binding, $first, $last);
} else {
$statement->bindValue($binding, $value);
}
}
$statement->execute();
if ($return_resultset) {
return $statement; // Returns a foreachable resultset
} else {
// Otherwise returns all the data an associative array.
return $statement->fetchAll(PDO::FETCH_ASSOC);
}
}
// Wrapper to explicitly & simply get a multi-dimensional array.
function query_array($sql_query, $bindings=array()) {
return query($sql_query, $bindings, false); // Set return_resultset to false to return the array.
}
As noted in the comments, you'd want to use your own method for setting up a database connection and getting an initialized pdo, but in general it allows your bound sql to be cut down to just a single line.