I'm trying to create a function that will grab all posts within a table. I also wanted to add a optional LIMIT parameter. Here is an example:
function get_all_posts($conn, $limit = 0) {
if ($limit > 0) {
$stmt = $conn->prepare("SELECT * FROM posts LIMIT :limit");
$stmt->execute(array(
':limit' => $limit
));
$results = $stmt->fetchAll();
return $results ? $results : false ;
} else {
$stmt = $conn->prepare("SELECT * FROM posts");
$stmt->execute();
$results = $stmt->fetchAll();
return $results ? $results : false ;
}
}
If I call the function without using the limit parameter it works and displays all the posts. But if I call the function like this: get_all_posts($conn, "1"); Then I get this error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 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 ''1'' at line 1' in /Applications/MAMP/htdocs/sandbox/blog2/functions.php:19 Stack trace: #0 /Applications/MAMP/htdocs/sandbox/blog2/functions.php(19): PDOStatement->execute(Array) #1 /Applications/MAMP/htdocs/sandbox/blog2/index.php(12): get_all_posts(Object(PDO), '1') #2 {main} thrown in /Applications/MAMP/htdocs/sandbox/blog2/functions.php on line 19
Can anyone show me where I've gone wrong?
1 is not a string, so don't put quotes around it here: get_all_posts($conn, 1);
By default PDO execute() treats parameters as a string. As such it is quoting "1". You will need to use bindParam().
Although MySQL may handle this, you should bind this parameter accordingly (as an INT). See this related question for more detail.
Like Sammitch said, its because its a string, not an integer. Use this to fix:
if (is_numeric($limit)) {
$limit = (int)$limit;
...
to clear any variable type issues
In the LIMIT clause you need an integer parameter.
In your code you pass the :limit' parameter's value viaexecute` which are all strings.
A string is not an integer. This mismatch creates your issue.
Instead bin the parameter as integer and you are fine.
$stmt = $conn->prepare("SELECT * FROM posts LIMIT :limit");
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$success = $stmt->execute();
$results = $stmt->fetchAll();
As you accept the $limit variable via a function parameter, you should sanitize it's value as well:
$limit = (int) $limit;
That will ensure you are using a variable of type integer when binding it as an integer parameter.
Related
I'm getting a weird error that I don't understand, I tried everything but nothing worked, here is my request:
public function displayFirstEvents_indexed($start, $limit)
{
$query = $this->connect()->prepare(
"SELECT *
FROM t_event join t_type_event using(tte_id)
WHERE eve_active = :active AND tte_lib = :lib
ORDER BY eve_date DESC
LIMIT :start, :limit;"
);
$query->bindParam(':start', $start, PDO::PARAM_INT);
$query->bindParam(':limit', $limit, PDO::PARAM_INT);
$query->execute([':active' => 'yes', ':lib' => 'first']);
return $query;
}
here is the error
<br />
<b>Fatal error</b>: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in C:\xampp\htdocs\UFTAM WEBSITE API\classes\event.c.php:105
Stack trace:
#0 C:\xampp\htdocs\UFTAM WEBSITE API\classes\event.c.php(105): PDOStatement->execute(Array)
#1 C:\xampp\htdocs\UFTAM WEBSITE API\handers\events\displayFirstEvents_indexed.php(7): Event->displayFirstEvents_indexed('1', '4')
#2 {main}
thrown in <b>C:\xampp\htdocs\UFTAM WEBSITE API\classes\event.c.php</b> on line <b>105</b><br />
I tried replacing ':active' and ':lib' with '?' but it gave me the same error, does anyone know a solution for this ?
I suspect the problem here is in the Where close I think I cant use 'where' with 'limit' I've been looking into it and I haven't found any example with 'where' and 'limit' together, does anyone think that this is true?
A note I found on php.net from 10 years ago:
Note that you must
EITHER pass all values to bind in an array to PDOStatement::execute()
OR bind every value before with PDOStatement::bindValue(), then call PDOStatement::execute() with no parameter (not even "array()"!).
Passing an array (empty or not) to execute() will "erase" and replace any previous bindings (and can lead to, e.g. with MySQL, "SQLSTATE[HY000]: General error: 2031" (CR_PARAMS_NOT_BOUND) if you passed an empty array).
https://www.php.net/manual/en/pdostatement.execute.php
As frustrating as this may be (because why not!?), you cannot mix 'bind' and 'execute' when using PDO. Two of your parameters are being deleted. Either pass the tokens in the execute, or bind them all first. (I'd probably bind them first and in order.)
$query->bindValue(':active', 'yes', PDO::PARAM_STR);
$query->bindValue(':lib', $colour, PDO::PARAM_STR);
$query->bindValue(':start', $start, PDO::PARAM_INT);
$query->bindValue(':limit', 'first', PDO::PARAM_INT);
$query->execute();
If binding doesn't work, try putting them into the execute (). If you do this though, be mindful of PHP PDO apparent issue with limit.
https://phpdelusions.net/pdo#limit
The order of the mysql command are wrong, ORDER BY is behind the WHERE Clause
$query = $this->connect()->prepare(
"SELECT *
FROM t_event join t_type_event using(tte_id)
WHERE eve_active = :active AND tte_lib = :lib
ORDER BY eve_date DESC
LIMIT :start,:limit;"
);
$sth->bindValue(':active', 'yes', PDO::PARAM_STR);
$sth->bindValue(':lib', 'first', PDO::PARAM_STR);
$sth->bindValue(':limit', $limit, PDO::PARAM_INT);
$sth->bindValue(':start', $start, PDO::PARAM_INT);
$query->execute();
And bind all 4 variables before executing.
I'm trying to bind a search term and a limit value to a PDO execute query, but I get error messages no matter which way I do it
public static function searchUsersByName($searchTerm, $results = null) {
//getDBConnection
if($results == null) {
$results = 5;
}
$searchTerm = '%'.$searchTerm.'%';
$query = $database->prepare("SELECT user_id, user_firstname, user_lastname
FROM users_details
WHERE user_firstname LIKE :searchTerm
OR user_lastname LIKE :searchTerm
LIMIT :results");
$query->bindParam(':searchTerm', $searchTerm, PDO::PARAM_STR);
$query->bindParam(':results', $results, PDO::PARAM_INT);
$query->execute();
$search_results = array();
foreach ($query->fetchAll() as $user) {
$search_results[$user->user_id] = new stdClass();
$search_results[$user->user_id]->user_id = $user->user_id;
$search_results[$user->user_id]->user_firstname = $user->user_firstname;
$search_results[$user->user_id]->user_lastname = $user->user_lastname;
}
return $search_results;
}
This is the error I get from this:
PDOStatement::execute(): SQLSTATE[42000]: Syntax error or access violation: 1064 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 "5"
It works fine if I take out the bind for LIMIT and just hardcode 5 into the SQL query, but I want to be able to change it if possible
$query->execute(array(':searchTerm' => '%'.$searchTerm.'%', ':results' => $results));
I've tried doing it this way, but of course PDO automatically puts quotes around the values its inserting via this method, and as far as I know you can't put a PDO::PARAM_INT in while using this method.
What am I doing wrong?
Could it be that $results is not an integer? The error seems like your PHP code is posting a string into the query, which would explain the error.
I am guessing this is the issue because of the following piece of code
if($results == null) {
$results = 5;
}
How is $results set in the first place? Via GET/POST? Then it might have been converted to a string.
I've tried your piece of code myself and casting it to an int fixed it for me.
$query->bindParam(':results', intval($results), PDO::PARAM_INT);
I've built a function which will prepare SQL statement and execute it with given parameters. So here how it looks like:
function go($statement) {
$q = self::$connection->prepare($statement, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
for($i = 1; $i < func_num_args(); $i++) {
$arg_to_pass = func_get_arg($i);
$q->bindParam($i, $arg_to_pass, PDO::PARAM_INT);
}
$q->execute();
}
But when I call it, it gives me the following error:
Fatal error: Uncaught exception 'PDOException' with message
'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an
error in your SQL syntax;
However, this two variants are working perfectly:
function go($statement) {
$q = self::$connection->prepare($statement, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
for($i = 1; $i < func_num_args(); $i++) {
$q->bindValue($i, func_get_arg($i), PDO::PARAM_INT);
}
$q->execute();
}
(This one is stupid, but just for test)
function go($statement) {
$q = self::$connection->prepare($statement, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$arg_to_pass = func_get_arg(1);
$q->bindParam(1, $arg_to_pass, PDO::PARAM_INT);
$arg_to_pass2 = func_get_arg(2);
$q->bindParam(2, $arg_to_pass2, PDO::PARAM_INT);
$q->execute();
}
So why bindParam doesn't work inside a loop?
I'm guessing it's because you're breaking the binding - you fetch an argument into $arg_to_pass, and then bind it. On the next iteration, you fetch another arg into the same variable (which is now bound as parameter #1) and try to rebind it as parameter #2. The other versions all use unique argument names (the direct return value from func_get_args, different var names, etc...).
I'm not sure why you're getting that message, but I'd say the problem is you're trying to use PDOStatement::bindParam(), which binds as a reference and only gets the value of the variable when you call PDOStatement::execute(), however by that time the original variable has been overwritten with a new value.
Either use PDOStatement::bindValue(), so the value is copied within the loop, or use unique variable references with bindParam.
I think it might be a flaw in my pdo fetching data method,
public function fetch_all($query, $params = array())
{
try
{
# prepare the query
$stmt = $this->connection->prepare($query);
# if $params is not an array, let's make it array with one value of former $params
if (!is_array($params)) $params = array($params);
# execute the query
$stmt->execute($params);
# return the result
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
catch (PDOException $e)
{
# call the get_error function
$this->get_error($e);
}
}
All the parameters that have been passed into this method will become strings, but I need integers for sql LIMIT query, such as below
$sql = "
SELECT *
FROM root_pages
ORDER BY root_pages.pg_created DESC
LIMIT ?,?";
items = $connection->fetch_all($sql,array('0','6'));
It returns this error,
2SQLSTATE[42000]: Syntax error or
access violation: 1064 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 ''0','6'' at line 32
How can I fix it?
EDIT:
As suggested, I changed the code in my method to this below,
# fetch a multiple rows of result as a nested array ( = multi-dimensional array)
public function fetch_all($query, $params = array())
{
try
{
# prepare the query
$stmt = $this->connection->prepare($query);
# if $params is not an array, let's make it array with one value of former $params
//if (!is_array($params)) $params = array($params);
foreach($params as $k=>$p){
if(is_numeric($p)){
$stmt->bindParam($k+1, $p, PDO::PARAM_INT);
}
else{
$stmt->bindParam($k+1, $p, PDO::PARAM_STR);
}
}
$stmt->execute();
# execute the query
//$stmt->execute($params);
# return the result
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
catch (PDOException $e)
{
# call the get_error function
$this->get_error($e);
}
}
$items = $connection->fetch_all($sql,array(0,6));
then I get a different error,
2SQLSTATE[42000]: Syntax error or
access violation: 1064 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 ''6'' at line 32
EDIT:
I just changed it to,
if(is_int($p)){..}
but still getting the same error... sigh...
you should pass your parameter with type PDO::PARAM_INT, like:
$sth->bindParam(':limit', $limit, PDO::PARAM_INT);
You can't do this via placeholders.
PDO always quotes params that aren't null, even when they're integers. Normally this isn't such a bad thing, but LIMIT clauses can not handle quoted integers.
You're going to need to fall back to good old fashioned concatenation. Because you know that these are going to be integers, you can treat them safely in your code by calling intval or casting them prior to concatenation.
$limit = intval($thing_that_provides_limit);
$offset = intval($thing_that_provides_offset);
$sql = "
SELECT *
FROM root_pages
ORDER BY root_pages.pg_created DESC
LIMIT {$offset}, {$limit}";
Try removing the quotes around the 0 and the 6:
$connection->fetch_all($sql,array(0,6));
This should make the query:
LIMIT 0,6
With quotes on the 0 and the 6, the query is:
LIMIT '0','6'
EDIT: Call bindParam before you call execute.
foreach($params as $k=>$p){
if(is_int($p)){
$stmt->bindParam($k+1, $p, PDO::PARAM_INT);
}
else{
$stmt->bindParam($k+1, $p, PDO::PARAM_STR);
}
}
$stmt->execute();
And then call fetch_all like so:
$connection->fetch_all($sql,array(0,6));
Try:
$items = $connection->fetch_all($sql,array(0,6));
Note the lack of quotes around the 0 and 6 - this makes PHP treat them as the integers they are, and not the strings you had.
I am working with PHP-PDO and Oracle 11g. I am working with Oracle packages which have many functions and stored procedures. Now when I make a call to one of the functions from sql*plus or sql developer IDE, I run this command to get the result set.
select package_name.function_name(param1,param2) from dual
It works fine and returns my result set. Now when I do the same, I am getting errors from the PDO Exception handling. The code with on PHP end looks like this,
$stmt = "select package_name.function_name (?,?) from dual";
$res = $this->ConnOBJ->prepare($stmt);
$param1 = '1';
$param2 = null;
$result->bindParam(1,$param1);
$result->bindParam(2,$param2);
$result->execute();
And I get back an exception which is being logged into my log file.
Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 904 OCIStmtExecute: ORA-00904: "PACKAGE_NAME"."FUNCTION_NAME"": invalid identifier (/var/www/php-5.3.3/ext/pdo_oci/oci_statement.c:146)' in /opt/web/dir/ora_class.php:209 Stack trace: #0 /opt/web/dir/ora_class.php(209): PDOStatement->execute() #1 /opt/web/dir/ora_class.php(298): dbPDO->execPackage() #2 {main} thrown in /opt/web/dir/ora_class.php on line 209
Am I passing the query in a wrong way? Or am I binding the parameters in a wrong way?
Update
I have now got the data going through to Oracle, and have found how to pass null values. My code now is
$stmt = "select package_name.function_name(?,?) from dual";
$res = $this->ConnOBJ->prepare($stmt);
$param1 = 1;
$param2 = null;
$res->bindParam(1,$param1,PDO::PARAM_INT);
$res->bindParam(2,$param2,PDO::PARAM_NULL);
$res->execute();
var_dump($res->fetchAll());
And now when I pass data, I get back the error
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 932 OCIStmtFetch: ORA-00932: inconsistent datatypes: expected CHAR got DTYCWD (/var/www/php-5.3.3/ext/pdo_oci/oci_statement.c:467)' in /opt/web/dir/ora_class.php:216 Stack trace: #0 /opt/web/dir/ora_class.php(216): PDOStatement->fetchAll() #1 /opt/web/dir/ora_class.php(305): dbPDO->execPackage() #2 {main} thrown in /opt/web/dir/ora_class.php on line 216
I am making sure all the types are right, but I still am getting back the same error. I even removed the null value and passed in a string, and changed the pdo type to PDO::PARAM_STR, but it still gives me the error.
Does the function take one parameter or two? In SQL*Plus, you're passing two parameters. In PHP, you're passing only one. If the function requires two parameters and there is no overloaded method that takes only one parameter, you'd get this error.
I am not using PDO anymore, I would be using OCI drivers. Thank you for all the help.
Here is a link to an answer for a similar question [LINK] : https://stackoverflow.com/a/57558306/7897970
or best
//Your connection details
$conn = oci_connect($username, $password, '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE)))' );
/* Your query string; you can use oci_bind_by_name to bind parameters or just pass the variable in it*/
$query = "begin :cur := functionName('".$param1."','".$param2."','".$param3."'); end;";
$stid = oci_parse($conn, $query);
$OUTPUT_CUR = oci_new_cursor($conn);
oci_bind_by_name($stid, ':cur', $OUTPUT_CUR, -1, OCI_B_CURSOR);
oci_execute($stid);
oci_execute($OUTPUT_CUR);
oci_fetch_all($OUTPUT_CUR, $res);
// To get your result
var_dump($res);