My SQL looks something like this:
$sql = "select * from user where id in (:userId) and status = :status";
$em = $this->getEntityManager();
$stmt = $em->getConnection()->prepare($sql);
$stmt->bindValue(':userId', $accounts, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
$stmt->bindValue(':status', 'declined');
$stmt->execute();
$result = $stmt->fetchAll();
But it returns:
An exception occurred while executing (...)
with params
[[1,2,3,4,5,6,7,8,11,12,13,14], "declined"]
Notice: Array to string conversion
I cannot user queryBuilder because my real SQL is more complicated (ex. contains joined select, unions and so on)
You can't use prepared statements with arrays simply because sql itself does not support arrays. Which is a real shame. Somewhere along the line you actually need to determine if your data contains say three items and emit a IN (?,?,?). The Doctrine ORM entity manager does this for you automatically.
Fortunately, the DBAL has you covered. You just don't use bind or prepare. The manual has an example: https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion
In your case it would look something like:
$sql = "select * from user where id in (?) and status = ?";
$values = [$accounts,'declined'];
$types = [Connection::PARAM_INT_ARRAY, \PDO::PARAM_STR];
$stmt = $conn->executeQuery($sql,$values,$types);
$result = $stmt->fetchAll();
The above code is untested but you should get the idea. (Make sure you use Doctrine\DBAL\Connection; for Connection::PARAM_INT_ARRAY)
Note for people using named parameters:
If you are using named parameters (:param instead of ?), you should respect the parameter names when providing types. For example:
$sql = "select * from user where id in (:accounts) and status = :status";
$values = ['accounts' => $accounts, 'status' => 'declined'];
$types = ['accounts' => Connection::PARAM_INT_ARRAY, 'status' => \PDO::PARAM_STR];
If you want to stick to the :param syntax where order does not matter, you have to do a bit of extra work, but I'll show you an easier way to bind the parameters:
// store all your parameters in one array
$params = array(
':status' => 'declined'
);
// then, using your arbitrary array of id's ...
$array_of_ids = array(5, 6, 12, 14);
// ... we're going to build an array of corresponding parameter names
$id_params = array();
foreach ($array_of_ids as $i => $id) {
// generate a unique name for this parameter
$name = ":id_$i"; // ":id_0", ":id_1", etc.
// set the value
$params[$name] = $id;
// and keep track of the name
$id_params[] = $name;
}
// next prepare the parameter names for placement in the query string
$id_params = implode(',', $id_params); // ":id_0,:id_1,..."
$sql = "select * from user where id in ($id_params) and status = :status";
In this case we end up with:
"select * from user where id in (:id_0,:id_1,:id_2,:id_3) and status = :status"
// now prepare your statement like before...
$stmt = $em->getConnection()->prepare($sql);
// ...bind all the params in one go...
$stmt->execute($params);
// ...and get your results!
$result = $stmt->fetchAll();
This approach will also work with an array of strings.
You need to wrap them in an array
$stmt->bindValue(':userId', array($accounts), array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY));
http://doctrine-dbal.readthedocs.io/en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion
edit
I should have elaborated more. You cannot bind an array like that, dont prepare the sql execute directly as the example in the docs.
$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
array(array(1, 2, 3, 4, 5, 6)),
array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY));
You cannot bind an array of values into a single prepared statement parameter
Related
Currently Im trying to create a PDO class where I will have a method to run a query like INSERT, UPDATE, or DELETE.
For examaple this is my method for a SELECT
public function getPreparedQuery($sql){
$stmt = $this->dbc->prepare($sql);
$stmt->execute([5]);
$arr = $stmt->fetchAll(PDO::FETCH_ASSOC);
if(!$arr) exit('No rows');
$stmt = null;
return $arr;
}
And i Simply call it like this:
$stmt = $database->getPreparedQuery($sql2);
var_export($stmt);
And so far I know that a runQuery should work something similar to this:
Insert Example without using a method:
$idRol = "6";
$nomRol = "test6";
$stmt = $database->dbc->prepare("insert into roles (idRol, NomRol) values (?, ?)");
$stmt->execute(array($idRol,$nomRol));
$stmt = null;
But I want to make it into an universal method where i simply can pass the sql sentence, something like this:
$database->runQuery($query);
but the query can happen to be
$query = "INSERT INTO roles (idRol, NomRol) VALUES ('4','test')";
or
$query = "INSERT INTO movies (movName, movLength, movArg) VALUES ('name1','15','movie about...')";
So how do I slice the arg $query so I can get all the variables that are being used in order to make an universal runQuery?
Because I can imagine that my method should be something like this
runQuery([$var1 , $var2, $var3....(there can be more)] , [$var1value, $var2value, $var3value...(there can be more)]){
$stmt = $database->dbc->prepare("insert into movies($var1 , $var2, $var3....(there can be more)) values (?, ? , ? (those are the values and there ca be more than 3)"); //how do i get those "?" value and amount of them, and the name of the table fields [movName, movLength, movArg can be variable depending of the sentence]?
$stmt->execute(array($var1,$var2, $var3, ...)); //this is wrong , i dont know how to execute it
$stmt = null;
}
You need to add a second parameter to your function. Simply an array where all those variables would go. An array by definition can have an arbitrary number of elements, which solves your problem exactly:
public function runQuery($sql, $parameters = []) {
$stmt = $this->dbc->prepare($sql);
$stmt->execute($parameters);
return $stmt;
}
this simple function will run ANY query. You can see the usage example in my article dedicated to PDO helper functions:
// getting the number of rows in the table
$count = $db->runQuery("SELECT count(*) FROM users")->fetchColumn();
// the user data based on email
$user = $db->runQuery("SELECT * FROM users WHERE email=?", [$email])->fetch();
// getting many rows from the table
$data = $db->runQuery("SELECT * FROM users WHERE salary > ?", [$salary])->fetchAll();
// getting the number of affected rows from DELETE/UPDATE/INSERT
$deleted = $db->runQuery("DELETE FROM users WHERE id=?", [$id])->rowCount();
// insert
$db->runQuery("INSERT INTO users VALUES (null, ?,?,?)", [$name, $email, $password]);
// named placeholders are also welcome though I find them a bit too verbose
$db->runQuery("UPDATE users SET name=:name WHERE id=:id", ['id'=>$id, 'name'=>$name]);
// using a sophisticated fetch mode, indexing the returned array by id
$indexed = $db->runQuery("SELECT id, name FROM users")->fetchAll(PDO::FETCH_KEY_PAIR);
As you can see, now your function can be used with any query with any number of parameters
This question already has an answer here:
PDO pagination with LIKE
(1 answer)
Closed 2 years ago.
I have one doubt about PDO.
I have a method in the class that returns data from the database for sent filters.
I want to get a number of rows for that query, but there are LIMIT and STAR in the query.
So because of that, I am using two queries to get a number of rows and data but to work, I need to bind the same value two times. Is there any more elegant way to achieve not have repeated code?
The method that I use is below.
$db = $this->openConnection();
$sql = " SELECT * FROM contacts";
// Filter data by main search input
if(!empty($search_query)){
$sql .= " WHERE ( location LIKE :search_query_location OR address LIKE :search_query_address ) ";
}
$sql .=" ORDER BY ".$order;
$stmt = $db->prepare($sql);
if(!empty($search_query)){
$stmt->bindValue(':search_query_location', (string) $search_query.'%');
$stmt->bindValue(':search_query_address', (string) $search_query.'%');
}
// Get number of rows after filter
$stmt->execute();
$total = $stmt->rowCount();
$sql .=" LIMIT :start, :limit_num";
$stmt = $db->prepare($sql);
if(!empty($search_query)){
$stmt->bindValue(':search_query_location', (string) $search_query.'%');
$stmt->bindValue(':search_query_address', (string) $search_query.'%');
}
// Bind start and limit value
$stmt->bindValue(':start', (int) $start, PDO::PARAM_INT);
$stmt->bindValue(':limit_num', (int) $limit, PDO::PARAM_INT);
// Get filtered data
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
return array($total,$data);
WHY I NEED TO REPEAT BINDING FOR TWO SAME QUERIES ONE WITHOUT LIMITS TO WORK IS THERE ANY ELEGANT SOLUTION
Problem
The reason that you have to bind twice is that $pdo->prepare($sql) returns a PDOStatement which isn't editable after it's been set. So when you update it you have to overwrite it and start again... Obviously the new statement doesn't retain the old bound parameters.
If you think of it as an array that you add some data to and then overwrite with a new, blank, array... You then can't read the information from the original array because it doesn't exist in the new one:
$array = [];
$array[] = 1;
$array[] = 2;
$array[] = 3;
var_dump($array);
/*
Output...
Array
(
[0] => 1
[1] => 2
[2] => 3
)
*/
$array = [];
print_r($array);
/*
Output...
Array
(
)
*/
The difference is that PDOStatement is an object not an array. But it's functionally the same thing!
N.B.
While $pdo->rowCount() may return the number of results from a SELECT query it isn't guaranteed so usually it's best practice not to use it.
I wouldn't overwrite the variable with a new query anyway... Better to use a different variable name e.g. $countQuery and $dataQuery
Solutions
So, if the only reason is that you're trying to reduce the amount of code then there are a bunch of solutions that you could use. However, this doesn't appear to be code golf, so why does it matter?
Solution 1
Assuming you don't have an unreasonable amount of unneeded results returned by the query then you could just return the array from the first query and use array_slice to take the place of the second query...
$pdo = $this->openConnection();
$sql = "SELECT * FROM contacts";
if($search_query){
$sql .= " WHERE ( location LIKE :search_query_location OR address LIKE :search_query_address ) ";
}
$sql .= " ORDER BY :order";
$query = $pdo->prepare($sql);
if($search_query){
$query->bindValue(':search_query_location', $search_query.'%');
$query->bindValue(':search_query_address', $search_query.'%');
}
$query->bindValue(':order', $order);
$query->execute();
$result = $query->fetchAll(PDO::FETCH_ASSOC);
$count = count($result);
return [$count, array_slice($result, $start, $limit)];
Solution 2
If you're worried about readability and code maintenance then you should remember that: it's usual for a method/function to have a reasonably specific function, for example...
Return the number of rows which match a query
Return the data which matches a query
Implementing this would mean you have each of your queries in separate functions:
function countContacts(...)
{
$sql = 'SELECT count(*) FROM contacts WHERE ...';
$query = $pdo->prepare($sql);
$query->bindValue(...);
$query->execute();
return $query->fetchColumn();
}
function getContacts(...)
{
$sql = 'SELECT * FROM contacts WHERE ... ORDER BY ... LIMIT ...';
$query = $pdo->prepare($sql);
$query->bindValue(...);
$query->execute();
return $result->fetchAll(PDO::FETCH_ASSOC);
}
Solution 3
I wouldn't use this, but it technically solves the issue
You could use a union and run two queries in one, then you could use emulated prepared statements (as per #Straberry's answer) to bind once...
Although, again, emulated prepared statements are not something that anyone on here is likely to suggest you should use without good reason. Of course you could use normal prepares and use different bind parameter names.
Either way, this isn't a great solution. I wouldn't use it.
$sql = "
SELECT COUNT(*) as col1, null as col2, null as col3, null as col4, null as col5 FROM contacts WHERE ...
UNTION
SELECT col1, col2, col3, col4, col5 FROM contacts WHERE ... ORDER BY ... LIMIT ...
";
$query = $pdo->prepare($sql);
$query->bindValue(...);
$query->execute();
$result = $query->fetchAll(PDO::FETCH_ASSOC);
return [$result[0]["col1"], array_slice($result, 1)];
Currently Im trying to create a PDO class where I will have a method to run a query like INSERT, UPDATE, or DELETE.
For examaple this is my method for a SELECT
public function getPreparedQuery($sql){
$stmt = $this->dbc->prepare($sql);
$stmt->execute([5]);
$arr = $stmt->fetchAll(PDO::FETCH_ASSOC);
if(!$arr) exit('No rows');
$stmt = null;
return $arr;
}
And i Simply call it like this:
$stmt = $database->getPreparedQuery($sql2);
var_export($stmt);
And so far I know that a runQuery should work something similar to this:
Insert Example without using a method:
$idRol = "6";
$nomRol = "test6";
$stmt = $database->dbc->prepare("insert into roles (idRol, NomRol) values (?, ?)");
$stmt->execute(array($idRol,$nomRol));
$stmt = null;
But I want to make it into an universal method where i simply can pass the sql sentence, something like this:
$database->runQuery($query);
but the query can happen to be
$query = "INSERT INTO roles (idRol, NomRol) VALUES ('4','test')";
or
$query = "INSERT INTO movies (movName, movLength, movArg) VALUES ('name1','15','movie about...')";
So how do I slice the arg $query so I can get all the variables that are being used in order to make an universal runQuery?
Because I can imagine that my method should be something like this
runQuery([$var1 , $var2, $var3....(there can be more)] , [$var1value, $var2value, $var3value...(there can be more)]){
$stmt = $database->dbc->prepare("insert into movies($var1 , $var2, $var3....(there can be more)) values (?, ? , ? (those are the values and there ca be more than 3)"); //how do i get those "?" value and amount of them, and the name of the table fields [movName, movLength, movArg can be variable depending of the sentence]?
$stmt->execute(array($var1,$var2, $var3, ...)); //this is wrong , i dont know how to execute it
$stmt = null;
}
You need to add a second parameter to your function. Simply an array where all those variables would go. An array by definition can have an arbitrary number of elements, which solves your problem exactly:
public function runQuery($sql, $parameters = []) {
$stmt = $this->dbc->prepare($sql);
$stmt->execute($parameters);
return $stmt;
}
this simple function will run ANY query. You can see the usage example in my article dedicated to PDO helper functions:
// getting the number of rows in the table
$count = $db->runQuery("SELECT count(*) FROM users")->fetchColumn();
// the user data based on email
$user = $db->runQuery("SELECT * FROM users WHERE email=?", [$email])->fetch();
// getting many rows from the table
$data = $db->runQuery("SELECT * FROM users WHERE salary > ?", [$salary])->fetchAll();
// getting the number of affected rows from DELETE/UPDATE/INSERT
$deleted = $db->runQuery("DELETE FROM users WHERE id=?", [$id])->rowCount();
// insert
$db->runQuery("INSERT INTO users VALUES (null, ?,?,?)", [$name, $email, $password]);
// named placeholders are also welcome though I find them a bit too verbose
$db->runQuery("UPDATE users SET name=:name WHERE id=:id", ['id'=>$id, 'name'=>$name]);
// using a sophisticated fetch mode, indexing the returned array by id
$indexed = $db->runQuery("SELECT id, name FROM users")->fetchAll(PDO::FETCH_KEY_PAIR);
As you can see, now your function can be used with any query with any number of parameters
following query returns all wanted results if entered in phpmyadmin:
SELECT postid, voting
FROM postvotes
WHERE userid = 1
AND postid IN
(1007,1011,1012,1013,1014,
1015,1016,1017,1018,1019,1020,1021,1023,1025,1026,
1027,1028,1029,1030,1031)
But PDO fails to fetchAll(). It just returns the first match like fetch().
What's wrong?
PHP Code:
private function userPostVotings( $postIDs ) {
// $postIDs contains a string like 1,2,3,4,5,6,7...
// generated through implode(',', idArray)
try {
$userPostVote = $this->_db->prepare('SELECT postid, voting
FROM postvotes
WHERE userid = ?
AND postid IN ( ? )');
$userPostVote->setFetchMode(\PDO::FETCH_ASSOC);
$userPostVote->execute( array( $this->_requester['id'], $postIDs ) );
while ( $res = $userPostVote->fetch() ) {
var_dump( $res );
}
} catch (\PDOException $p) {}
}
If I echo out the query used in this method and fire it through phpmyadmin I get the correct number of results. However PDO gives just the first. No matter if a loop with fetch() or fetchAll().
You cannot bind array in prepared statements in PDO.
Reference:
Can I bind an array to an IN() condition?
it is not PDO's fetchAll() of course, but your query.
Which is not
IN (1007,1011,1012,1013,1014)
but
IN ('1007,1011,1012,1013,1014')
and of course it will find only first value as this string will be cast to the first number
One have to create a query with placeholders representing every array member, and then bind this array values for execution:
$ids = array(1,2,3);
$stm = $pdo->prepare("SELECT * FROM t WHERE id IN (?,?,?)");
$stm->execute($ids);
To make this query more flexible, it's better to create a string with ?s dynamically:
$ids = array(1,2,3);
$in = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT * FROM table WHERE column IN ($in)";
$stm = $db->prepare($sql);
$stm->execute($ids);
$data = $stm->fetchAll();
My site is rather extensive, and I just recently made the switch to PHP5 (call me a late bloomer).
All of my MySQL query's before were built as such:
"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'";
This made it very easy, simple and friendly.
I am now trying to make the switch to mysqli for obvious security reasons, and I am having a hard time figuring out how to implement the same SELECT * FROM queries when the bind_param requires specific arguments.
Is this statement a thing of the past?
If it is, how do I handle a query with tons of columns involved? Do I really need to type them all out every time?
I could be wrong, but for your question I get the feeling that bind_param() isn't really the problem here. You always need to define some conditions, be it directly in the query string itself, of using bind_param() to set the ? placeholders. That's not really an issue.
The problem I had using MySQLi SELECT * queries is the bind_result() part. That's where it gets interesting. I came across this post from Jeffrey Way: http://jeff-way.com/2009/05/27/tricky-prepared-statements/(This link is no longer active). The script basically loops through the results and returns them as an array — no need to know how many columns there are, and you can still use prepared statements.
In this case it would look something like this:
$stmt = $mysqli->prepare(
'SELECT * FROM tablename WHERE field1 = ? AND field2 = ?');
$stmt->bind_param('ss', $value, $value2);
$stmt->execute();
Then use the snippet from the site:
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$parameters[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $parameters);
while ($stmt->fetch()) {
foreach($row as $key => $val) {
$x[$key] = $val;
}
$results[] = $x;
}
And $results now contains all the info from SELECT *. So far I found this to be an ideal solution.
"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'";
becomes
"SELECT * FROM tablename WHERE field1 = ? && field2 = ?";
which is passed to the $mysqli::prepare:
$stmt = $mysqli->prepare(
"SELECT * FROM tablename WHERE field1 = ? && field2 = ?");
$stmt->bind_param( "ss", $value, $value2);
// "ss' is a format string, each "s" means string
$stmt->execute();
$stmt->bind_result($col1, $col2);
// then fetch and close the statement
OP comments:
so if i have 5 parameters, i could potentially have "sssis" or something (depending on the types of inputs?)
Right, one type specifier per ? parameter in the prepared statement, all of them positional (first specifier applies to first ? which is replaced by first actual parameter (which is the second parameter to bind_param)).
While you are switching, switch to PDO instead of mysqli, It helps you write database agnositc code and have better features for prepared statements.
http://www.php.net/pdo
Bindparam for PDO:
http://se.php.net/manual/en/pdostatement.bindparam.php
$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2");
$sth->bindParam(':value1', 'foo');
$sth->bindParam(':value2', 'bar');
$sth->execute();
or:
$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = ? && field2 = ?");
$sth->bindParam(1, 'foo');
$sth->bindParam(2, 'bar');
$sth->execute();
or execute with the parameters as an array:
$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2");
$sth->execute(array(':value1' => 'foo' , ':value2' => 'bar'));
It will be easier for you if you would like your application to be able to run on different databases in the future.
I also think you should invest some time in using some of the classes from Zend Framwework whilst working with PDO. Check out their Zend_Db and more specifically [Zend_Db_Factory][2]. You do not have to use all of the framework or convert your application to the MVC pattern, but using the framework and reading up on it is time well spent.
Is this statement a thing of the past?
Yes. Don't use SELECT *; it's a maintenance nightmare. There are tons of other threads on SO about why this construct is bad, and how avoiding it will help you write better queries.
See also:
What is the reason not to use select *?
Performance issue in using SELECT *?
Why is using '*' to build a view bad?
You can still use it (mysqli is just another way of communicating with the server, the SQL language itself is expanded, not changed). Prepared statements are safer, though - since you don't need to go through the trouble of properly escaping your values each time. You can leave them as they were, if you want to but the risk of sql piggybacking is reduced if you switch.
you can use get_result() on the statement.
http://php.net/manual/en/mysqli-stmt.get-result.php
I was looking for a nice and complete example of how to bind multiple query parameters dynamically to any SELECT, INSERT, UPDATE and DELETE query. Alec mentions in his answer a way of how to bind result, for me the get_result() after execute() function for SELECT queries works just fine, and am able to retrieve all the selected results into an array of associative arrays.
Anyway, I ended up creating a function where I am able to dynamically bind any amount of parameters to a parametrized query ( using call_user_func_array function) and obtain a result of the query execution. Below is the function with its documentation (please read before it before using - especially the $paremetersTypes - Type specification chars parameter is important to understand)
/**
* Prepares and executes a parametrized QUERY (SELECT, INSERT, UPDATE, DELETE)
*
* #param[in] $dbConnection mysqli database connection to be used for query execution
* #param[in] $dbQuery parametrized query to be bind parameters for and then execute
* #param[in] $isDMQ boolean value, should be set to TRUE for (DELETE, INSERT, UPDATE - Data manipulaiton queries), FALSE for SELECT queries
* #param[in] $paremetersTypes String representation for input parametrs' types as per http://php.net/manual/en/mysqli-stmt.bind-param.php
* #param[in] $errorOut A variable to be passed by reference where a string representation of an error will be present if a FAUILURE occurs
* #param[in] $arrayOfParemetersToBind Parameters to be bind to the parametrized query, parameters need to be specified in an array in the correct order
* #return array of feched records associative arrays for SELECT query on SUCCESS, TRUE for INSERT, UPDATE, DELETE queries on SUCCESS, on FAIL sets the error and returns NULL
*/
function ExecuteMySQLParametrizedQuery($dbConnection, $dbQuery, $isDMQ, $paremetersTypes, &$errorOut, $arrayOfParemetersToBind)
{
$stmt = $dbConnection->prepare($dbQuery);
$outValue = NULL;
if ($stmt === FALSE)
$errorOut = 'Failed to prepare statement for query: ' . $dbQuery;
else if ( call_user_func_array(array($stmt, "bind_param"), array_merge(array($paremetersTypes), $arrayOfParemetersToBind)) === FALSE)
$errorOut = 'Failed to bind required parameters to query: ' . $dbQuery . ' , parameters :' . json_encode($arrayOfParemetersToBind);
else if (!$stmt->execute())
$errorOut = "Failed to execute query [$dbQuery] , erorr:" . $stmt->error;
else
{
if ($isDMQ)
$outValue = TRUE;
else
{
$result = $stmt->get_result();
if ($result === FALSE)
$errorOut = 'Failed to obtain result from statement for query ' . $dbQuery;
else
$outValue = $result->fetch_all(MYSQLI_ASSOC);
}
}
$stmt->close();
return $outValue;
}
usage:
$param1 = "128989";
$param2 = "some passcode";
$insertQuery = "INSERT INTO Cards (Serial, UserPin) VALUES (?, ?)";
$rowsInserted = ExecuteMySQLParametrizedQuery($dbConnection, $insertQuery, TRUE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference
if ($rowsInserted === NULL)
echo 'error ' . $errorOut;
else
echo "successfully inserted row";
$selectQuery = "SELECT CardID FROM Cards WHERE Serial like ? AND UserPin like ?";
$arrayOfCardIDs = ExecuteMySQLParametrizedQuery($dbConnection, $selectQuery, FALSE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference
if ($arrayOfCardIDs === NULL)
echo 'error ' . $errorOut;
else
{
echo 'obtained result array of ' . count($arrayOfCardIDs) . 'selected rows';
if (count($arrayOfCardIDs) > 0)
echo 'obtained card id = ' . $arrayOfCardIDs[0]['CardID'];
}