This question already has answers here:
Use bound parameter multiple times
(5 answers)
Closed 3 years ago.
I'm having an issue with the PDO statements for ODBC.
I'm using SQL SERVER 7 in Windows Server 2003 and PHP 5.4.x
For eg:
I have the query:
(this is not the actual query but it serves right for the example)
$query = SELECT * FROM table WHERE number = :number OR number = :number
in my php i have:
$conn = new PDO($connectionString);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$statement = $conn->prepare($query);
$statement->bindParam(':number', $someNumber);
$statement->execute();
This throws error
COUNT field incorrect or syntax error
The thing is, bindParam is only binding the FIRST occurrence of :number ... AND trying to bind it again doesn't work either.
Is there a way to bind multiple named params with the same name?
I'm trying not to use positional params using the ? instead
Theoretical you could turn on emulation of prepared statements.
You must include a unique parameter marker for each value you wish to
pass in to the statement when you call PDOStatement::execute(). You
cannot use a named parameter marker of the same name more than once in
a prepared statement, unless emulation mode is on.
http://www.php.net/manual/en/pdo.prepare.php
I don't know too much about MsSQL to be honest, but I am quite sure there is some equivalent to User Defined Variables in MySQL. You could use those instead of parameters like I described in this answer:
https://stackoverflow.com/a/31068865/3391783
Just turn emulation on, changing this setting from false to true:
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
Related
This question already has answers here:
Use bound parameter multiple times
(5 answers)
Closed 3 years ago.
I'm having an issue with the PDO statements for ODBC.
I'm using SQL SERVER 7 in Windows Server 2003 and PHP 5.4.x
For eg:
I have the query:
(this is not the actual query but it serves right for the example)
$query = SELECT * FROM table WHERE number = :number OR number = :number
in my php i have:
$conn = new PDO($connectionString);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$statement = $conn->prepare($query);
$statement->bindParam(':number', $someNumber);
$statement->execute();
This throws error
COUNT field incorrect or syntax error
The thing is, bindParam is only binding the FIRST occurrence of :number ... AND trying to bind it again doesn't work either.
Is there a way to bind multiple named params with the same name?
I'm trying not to use positional params using the ? instead
Theoretical you could turn on emulation of prepared statements.
You must include a unique parameter marker for each value you wish to
pass in to the statement when you call PDOStatement::execute(). You
cannot use a named parameter marker of the same name more than once in
a prepared statement, unless emulation mode is on.
http://www.php.net/manual/en/pdo.prepare.php
I don't know too much about MsSQL to be honest, but I am quite sure there is some equivalent to User Defined Variables in MySQL. You could use those instead of parameters like I described in this answer:
https://stackoverflow.com/a/31068865/3391783
Just turn emulation on, changing this setting from false to true:
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
Can't PDO bind a value to multiple occurrences of a param in a query with a single bindParam()?
I'm surprised, I thought it was possible, but I didn't find any info on php's docs on this, neither on the web. Any clarification / alternative is welcome!
Note : I'm using php 5.3.6 / 5.3.8 (dev/prod)
Example :
Consider this prepared statement :
INSERT INTO table VALUES (:param1, 0), (:param1, 1);
Now, if I bind values to my query:
bindParam(":param1",$my_param1);
I have a PDO error :
SQLSTATE[HY093]: Invalid parameter number
See PDO::prepare
You cannot use a named parameter marker of the same name twice in a prepared statement
I have this function in PHP. I am trying to insert (if it's necessary) and then get the app_id from the table.
private function addApp($bundle_identifier,$os_id) {
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ALL;
//Insert or update app details
if ($stmt = $this->db->prepare("INSERT IGNORE INTO app (app_identifier,os_id) VALUES (?,?); SELECT app_id FROM app WHERE app_identifier = ? AND os_id = ?")){
$stmt->bind_param("ssss", $bundle_identifier,$os_id,$bundle_identifier,$os_id);
$stmt->execute();
$stmt->bind_result($app_id);
if (!isset($app_id)) {
echo "is set";
$app_id=$stmt->insert_id;
}
}
if($this->db->commit()){
return $app_id;
}
return 0;
}
The issue here is that stmt is always false with the error:
Uncaught exception 'mysqli_sql_exception' with message '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 'SELECT app_id
FROM app WHERE app_identifier = ? AND os_id = ?' at line 1'
The weird thing is that this query works fine in my SQL.
Is that a limitation of mysqli?
According to http://php.net/manual/en/mysqli.prepare.php :
The query must consist of a single SQL statement.
Which basically answers your question. You have to use two db calls for two queries. Or use something like http://php.net/manual/en/mysqli.multi-query.php
The below is kept for information only as it refers PDO, while the question is about mysqli. It's generally useful though.
I think the reason for this working in mysql, but not in mysqli is that the latter supports prepared statements natively, while the former uses emulation. As your expression contains two queries, all bound parameters are given by driver to the first query (out of which is uses two and discards the other two). The second query then gets no parameters and therefore question marks are syntax errors. With prepared statements emulation PHP actually substitutes question marks with the properly escaped values and so forms two valid queries.
You can enable emulation using $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true), however, this may slightly affect performance.
See also http://www.php.net/manual/en/pdo.setattribute.php
This question already has answers here:
Can PHP PDO Statements accept the table or column name as parameter?
(8 answers)
Closed 8 years ago.
So I am having this strange issue with PDO, in that queries with bound variables are not executing properly for some reason. Let me show some code:
$conn = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pwd);
$sth=$conn->prepare("select count(*) from article");
$sth->execute();
var_dump($sth->fetchColumn());
This will print out the correct number of entries in the table "article".
However, if we change it slightly, by making the table a named parameter instead of a constant:
$conn = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pwd);
$sth=$conn->prepare("select count(*) from :article");
$sth->execute(array(":article"=>"article"));
var_dump($sth->fetchColumn());
This will print a boolean false. Both statements should return the same result, but I have no idea why the second one is not working. I suspect I have a typo somewhere, but I checked several times, and I don't see any issue. Anyone have any idea?
Not possible. You're trying to use a placeholder for a tablename. This is not permitted. placeholders can only replace values.
SELECT count(*) FROM :table WHERE field=:article
^^^^^^--illegal ^^^^^^^^--legal
For this, you'll have to use old-fashion string building:
$table = "article";
$sth=$conn->prepare("select count(*) from $table");
which then re-opens the SQL injection attack vulnerability, because you're now directly inserting external data into an SQL string.
PHP's PDO allows multiple querys to be executed at once, either via the query() method or as a prepared statement. Both of the following examples work:
// Two SQL queries
$query = "SELECT * FROM table; DROP table;"
// Execute via query()
$pdo->query($query);
// Execute via prepared statement
$stmt = $pdo->prepare($query);
$stmt->execute();
Is there any way to limit PDO to a single query at a time, much like the mysql_query() function is?
This is a more up-to-date answer to this question.
The old way of preventing multi query execution was to disable emulated prepares, however this was only applicable to the PDO::prepare() method. In newer versions of PHP (>= 5.5.21 and >= 5.6.5), a new constant has been introduced to disable this multi query execution in both PDO::prepare() and PDO::query(). (Constants aren't usually added in patch versions, but this was done due to the severity of a Drupal SQL injection attack brought about by this capability).
The new constant is PDO::MYSQL_ATTR_MULTI_STATEMENTS and must be set on object creation (as the fourth argument to the PDO constructor) - setting it on a pre-existing object with PDO::setAttribute() will not work.
$pdo = new PDO('mysql:host=_;dbname=_', '', '', [PDO::MYSQL_ATTR_MULTI_STATEMENTS => false]);
Mmm, there's a way of achieving this by disabling the emulation of prepared statements in PDO to make it use the native mysql API instead (multi-querying is not supported in server-side prepared statements):
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
However, one of the drawbacks of this option is that the query cache is lost.