PDO acts different on two -very- similar queries - php

The following block of code works fine (no errors)
$query = "select * from users where username = ?";
$statement = $sql->prepare($query);
echo gettype($statement); // -- This returns 'object'
$statement->bindParam(1, $username);
The following gives:
Fatal error: Call to a member function bindParam() on a non-object in /file.php on line 39
$email = 'fake#email.com';
$query = "select * from users where email = ?";
$statement = $sql->prepare($query);
echo gettype($statement); // -- this returns 'boolean'
$statement->bindParam(1, $email); // -- this is line 39.
Now this is strange.
At my local machine, and my remote host, this was never a problem.
This errors only shows up on this new hosting company I am trying out for the month. Could it be a config param when they compiled php?
--------edit--------
While still trying to figure out what's wrong,I found this out.
$query = "select userID, username from users";
$statement = $sql->prepare($query);
$statement->execute();
$r = $statement->fetchAll(PDO::FETCH_ASSOC);
// display # of rows
echo "Rows returned: " . $statement->rowCount();
// display results array
echo '<pre>'; print_r($r); echo '</pre>';
On a server, I get
Rows returned: 4
Array
(
[0] => Array
(
[userID] => 1
[username] => lyrae
)
[1] => Array
(
[userID] => 2
[username] => jproffer
)
[2] => Array
(
[userID] => 3
[username] => king
)
[3] => Array
(
[userID] => 4
[username] => gergy
)
)
Which is correct. Says 4 rows returned and displays the result array. On another server however, I get
Rows returned: 0
Array
(
[0] => Array
(
[userID] => 1
[username] => lyrae
)
[1] => Array
(
[userID] => 2
[username] => jproffer
)
[2] => Array
(
[userID] => 3
[username] => king
)
[3] => Array
(
[userID] => 4
[username] => gergy
)
)
Thus, it seems also that PDOStatement::rowCount() does not work on a sever but works on another.

Read this: $statement->closeCursor()
PDOStatement::closeCursor() frees up the connection to the server so that other SQL statements may be issued
Are you using the same database on the server where you say you don't have this issue?

Found a solution to the problem.
This is the entire block of code..
// check if username exists
$query = "select * from users where username = ?";
$statement = $sql->prepare($query);
$statement->bindParam(1, $username);
$statement->execute();
// check if email exists
$sql2 = new PDO('mysql:host=localhost; dbname=db', 'username', 'pw');
$query = "select * from users";
$statement = $sql2->prepare($query);
echo gettype($statement);
#$statement->bindParam(1, $email);
So for some reason, I have to create a new instance of PDO. what's strange is that on 2 other servers, I don't have to do this.
And upon further looking, i found that PDO::Prepare raises an PDOExeption.
Here it is:
SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
Array
(
[0] => HY000
[1] => 2014
[2] => Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
)
Maybe it'll help someone in the future :)

Is $email undefined? You could try a var_dump($email) too see what it says. Good luck.

Have you tried putting the $email= line below the bindParam (but before you do the execute)? bindParam passes the parameter by reference so you can execute as query, change the value of the variable and execute again.
I think though that it's probably a PHP set up error. I've heard people saying PDO had a lot of bugs before PHP 5.3, so maybe see if you can get PHP up to the latest version?
Have you also tried swapping the two queries around? Maybe something breaks after you run one query.

I'd better recommend using this:
$email = 'fake#email.com';
$query = "select * from users where email = ?";
$statement = $sql->prepare($query);
$statement->execute(array($email));
No BindParam use is needed here.

I had same problem with
echo "Rows returned: " . $statement->rowCount();
I got -1 rows, lol. My database is INFORMIX and searching web i found
that rowCount(); returns only affected rows in a DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
With a SELECT statement you need to use function
$statement->fetchColumn();
read it here: http://www.phpbuilder.com/manual/en/function.pdostatement-rowcount.php

Related

SELECT data as one array rather than while loop results together & prevention of injection

So I have two questions.
Question 1:
My select statement returns 2 items. However, I have to while loop through the items it returns to append the results into a single array called $results. Is there a function which already returns the data as one single array (same/similar to how the output is right now, but minus the while loop).
select-statement-code.php
$stid = oci_parse($conn, "SELECT *
FROM test_table");
oci_execute($stid);
while($row=oci_fetch_array($stid)) {
$results[] = $row;
}
print_r($results);
The output is:
Array
(
[0] => Array
(
[0] => 1
[MY_ID] => 1
[1] => John
[F_NAME] => John
)
[1] => Array
(
[0] => 2
[MY_ID] => 2
[1] => Mike
[F_NAME] => Mike
)
)
Question 2:
I've been reading over stackoverflow answers and there are multiple different answer which are conflicting each other. There is a clear cut answer for mysqli, but for oracle, it seems people argue about it. Is the way I am doing it below, the proper way to eliminate SQL injection? Also I used the oci_bind_by_name function 2 times, to bind the my_id and f_name. Is there a way to call the bind function once and bind both variables?
insert-statement.php
$my_id = 3; // Pretend this is an input from a random user, using my website
$name = "Bobby"; // Pretend this is an input from a random user, using my website
$sql = "INSERT INTO test_table (my_id, f_name)
VALUES (:id, :f_name)";
$stid = oci_parse($conn, $sql);
oci_bind_by_name($stid, ":id", $my_id);
oci_bind_by_name($stid, ":f_name", $name);
oci_execute($stid);
Q1. use oci_fetch_all:
$num_rows = oci_fetch_all($stid, $results);
Q2.
a. Yes, that's the correct way to prevent injection. See this Q&A for more details.
b. No, you have to call oci_bind_by_name once for each variable.

How can I retrieve query results as array in PDO?

Im working on a small PHP project and im changing from MySQLi to PDO , im also using prepared statements now.
I have managed to connect to the database and execute a query but I want to know how I can retrieve the results as an array?
I use the fetch_assoc() function in MySQLi to do this but now im using PDO and Prepared statements , i dont know how to accomplish this.
My code so far...
$res = $connection -> prepare("SELECT * FROM ad WHERE id = :id");
$res -> bindValue(':id',$id);
$res -> execute();
I have heard of using this code but it doesnt work?
$z= $res -> fetchAll(PDO::FETCH_ASSOC);
$productname = $z['productname'];
$z is now a multi-dimensional array, and as such, if you want to access the first row, you could just explicitly access index zero:
echo $z[0]['productname'];
It should look something like this:
Array
(
[0] => Array // index zero
(
[id] => 1
[productname] => productname 1 // sub index
)
// $z[0]['productname']
[1] => Array
(
[id] => 2
[productname] => productname 2
)
// $z[1]['productname']
[2] => Array
(
[id] => 3
[productname] => productname 3
)
// $z[2]['productname']
)
If you want to access all the row sets, just use the good ol' foreach:
foreach($z as $row) {
echo $row['productname'];
}

PHP PDO execute() returning duplicate results

For this code:
$title = '0';
$subTitle = '1';
$tableName = 'someString';
$stmt = $dbh->prepare("SELECT `".$title."`, `".$subTitle."` FROM `".$tableName."_data` WHERE `id` = :key");
$stmt->bindValue(':key', '127');
$stmt->execute();
$result = $stmt->fetchAll();
print_r($result);
I get $result as this:
Array
(
[0] => Array
(
[0] => 91651
[1] => 91651 - DESCRIPTION
[2] => 91651 - DESCRIPTION
)
)
When the expected result should be this:
Array
(
[0] => Array
(
[0] => 91651
[1] => 91651 - DESCRIPTION
)
)
When I run the same query in mySQL, it returns the expected result. When it is executed via PHP PDO, it adds a duplicate.
Thanks!
Use fetchAll(PDO::FETCH_ASSOC) instead of fetchAll().
Solved by checking with someone better at databases than myself...
I foolishly named the columns as integer values.
So, what appeared as "duplicate values" was just the fact that the column number and the column name were the same!
In conclusion, I am bad at database structure.
Try to check the fetch_style and fetch_argument and set it to a value you need.
see sample #3:
http://www.php.net/manual/en/pdostatement.fetchall.php
sometimes dep. on your php version/pdo version there is a bug when using bindvalue.
try to avoid that and use sample #3 instead.
You could change to using fetch() instead of fetchAll(), that will return one row. But I'd just ensure in the database that id is unique.

Doctrine DBAL 2: fetchAll() unnecessary array dimensions

In doctrine DBAL2 when I execute a query like this:
<?php
$connection = $this->getDatabaseConnection();
$sql = "SELECT page_url
FROM cms_user_page
WHERE site_id = :siteid
AND active = '1'
";
$stmt = $connection->prepare($sql);
$stmt->bindValue("siteid", $id);
$stmt->execute();
return $stmt->fetchAll();
?>
I get a result like this:
Array
(
[0] => Array
(
[page_url] => index.php?action=login
)
[1] => Array
(
[page_url] => index.php?action=shoppingcart
)
[2] => Array
(
[page_url] => index.php?action=products
)
)
My question is, is there a fetch mode that produces an result like this:
Array
(
[0] => index.php?action=login
[1] => index.php?action=shoppingcart
[2] => index.php?action=products
)
I could not find any info about fetch modes in the documentation. and i could do an array map. But thats overhead in my opinion..
You can pass a fetch mode parameter to fetchAll().
$stmt->fetchAll(\PDO::FETCH_COLUMN)
This answer has been edited because this answer is correct.
You can use the FETCH_COLUMN fetch mode in fetchAll():
$stmt->fetchAll(\PDO::FETCH_COLUMN)
As another user points out in the comments, fetchAll() can return data formatted in a multitude of interesting formats.
Or you can iterate with fetchColumn():
while($page_url = $stmt->fetchColumn()) {
echo $page_url . PHP_EOL;
}
As of PHP5.5 you could use aray_column to achieve required result like so:
<?php
$connection = $this->getDatabaseConnection();
$sql = "SELECT page_url
FROM cms_user_page
WHERE site_id = :siteid
AND active = '1'
";
$stmt = $connection->prepare($sql);
$stmt->bindValue("siteid", $id);
$stmt->execute();
$data = array_column($stmt->fetchAll(), 'page_url');
return $data;
If you have more than one case where you need that form of result, although i dont really understand the sense too, you could implement AbstractHydrator interface to create your own ArrayHydrator that returns the structure as you need it.
Hydration Classes reside in NS:
Doctrine\ORM\Internal\Hydration
It looks like fetchAll was made deprecated in a recent version of DBAL. However I found another method called fetchFirstColumn which appears to do the same thing as fetchAll(\PDO::FETCH_COLUMN). I am currently on version 2.11.1 Doctrine DBAL.
I am using it like this in Symfony:
$statement = $connection->prepare('SELECT foo FROM bar WHERE baz = :baz');
$statement->execute([':baz' => 1]);
$result = $statement->fetchFirstColumn();
The value of $result will be a numerically indexed array starting at 0 like this:
[
0 => 'foo1',
1 => 'foo2'
];
As soon as you're requesting multiple rows in a database it does not make sense.
RDBMS stores rows and columns so the result is represented as rows and columns.
In the programming world it is called a matrix, in the PHP world it is an array.
________________
| id | name |
|______|_________|
| 1 | foo |
|______|_________|
| 2 | bar |
|______|_________|
will results in
array(
0 => array(
'id' => 1,
'name' => 'foo',
),
1 => array(
'id' => 2,
'name' => 'foo',
)
);
So no, you can't do that, you'd rather to process the result to fit your needs.

PHP class array question

For some reason my array I am returning is not what I expect. Could someone explain to me why I am getting the current results, and what I can do to fix it? Here is the code in question:
public static function getProduct($_row, $_value)
{
$stmt = _DB::init()->prepare("SELECT pid, name, quantity, price, cost
FROM products
WHERE $_row = ?"
);
if($stmt->execute(array($_value)))
{
while ($row = $stmt->fetch())
return $row;
}
}
$product = Class::getProduct('pid',1);
print_r($product);
When I print the following array I am getting two results per row like so:
Array ( [pid] => 1 [0] => 1 [name] => Boondoggle [1] => Boondoggle [quantity] => 12 [2] => 12 [price] => 9.9900 [3] => 9.9900 [cost] => 12.9900 [4] => 12.9900 ) Boondoggle
I was only wanting to show the associative results. What is wrong with my function?
From the looks of it you are using PDO to communicate with your DBMS. The PDOStatement::fetch() method's first argument is a parameter to tell it what to return. By default it returns each column in both name format and numbered index format to allow iterating through columns easier. To just get the column names as indexes, you can pass it PDO::FETCH_ASSOC to your call. So the fetch statement would look like this:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)
See here for more details:
http://www.php.net/manual/en/pdostatement.fetch.php
Pass PDO::FETCH_ASSOC to your fetch call:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
edit: I'm just assuming you're using PDO, of course

Categories