PDO statement not retrieving any data [duplicate] - php

I am trying to do a search through php's PDO class (mysql driver). I have the following query working with the MySQL client (table names changed to protect the innocent):
SELECT hs.hs_pk,
hs.hs_text,
hs.hs_did,
hd.hd_did,
hd.hd_text,
hv.hv_text,
hc.hc_text
FROM hs
LEFT JOIN hd
ON hs.hs_did = hd.hd_did
LEFT JOIN hd
ON hd.hd_vid = hv.hv_id
LEFT JOIN hc
ON hd.hd_pclass = hc.hc_id
WHERE hs.hs_text LIKE "%searchTerm%"
LIMIT 25;
This works like a charm regardless of the search term that I use. However, when I move to php, I can't get it to return anything. I have tried several different syntaxes that seem logical to work, but nothing I have tried works. here's my existing code:
$handle = fopen('/foo/bar/test.log', 'w+');
fwrite($handle, "doSearch, with search term: $searchTerm\n");
$sql =
'SELECT hs.hs_pk,
hs.hs_text,
hs.hs_did,
hd.hd_did,
hd.hd_text,
hv.hv_text,
hc.hc_text
FROM hs
LEFT JOIN hd
ON hs.hs_did = hd.hd_did
LEFT JOIN hd
ON hd.hd_vid = hv.hv_id
LEFT JOIN hc
ON hd.hd_pclass = hc.hc_id
WHERE hs.hs_text LIKE :searchTerm
LIMIT 25';
try {
$dbh = new PDO('mysql:host=localhost;dbname=awdb', "user", "password");
fwrite($handle, "connected to DB\n");
$prep = $dbh->prepare($sql);
$ret = $prep->execute(array(':searchTerm' => '"%'.$searchTerm.'%"'));
while ($row = $prep->fetch(PDO::FETCH_ASSOC)) {
$i++;
$result[$i]['subText'] = $row['hs_pk'];
$result[$i]['subText'] = $row['hs_text'];
$result[$i]['subDid'] = $row['hs_did'];
$result[$i]['devDid'] = $row['hd_did'];
$result[$i]['devText'] = $row['hd_text'];
$result[$i]['vendorText'] = $row['hv_text'];
$result[$i]['classText'] = $row['hc_text'];
}
$dbh = null;
}
catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
I've tried the following as well (SQL WHERE clause & prep->execute lines are all that change):
WHERE hs.hs_text LIKE CONCAT(\'%\', ?, \'%\')
$ret = $prep->execute(array($searchTerm));
WHERE hs.hs_text LIKE "%:searchTerm%"
$ret = $prep->execute(array(':searchTerm' => $searchTerm));
WHERE hs.hs_text LIKE ":searchTerm"
$ret = $prep->execute(array(':searchTerm' => '%'.$searchTerm.'%'));
etc...

$ret = $prep->execute(array(':searchTerm' => '"%'.$searchTerm.'%"'));
This is wrong. You don't need the double quotes.
WHERE hs.hs_text LIKE ":searchTerm"
$ret = $prep->execute(array(':searchTerm' => '%'.$searchTerm.'%'));
This is also wrong.
Try with:
$prep = $dbh->prepare($sql);
$ret = $prep->execute(array(':searchTerm' => '%'.$searchTerm.'%'));
Explanation: Prepared statements don't simply do a string-replace. They transport the data completely separate from the query. Quotes are only needed when embedding values into a query.

$prep = $dbh->prepare($sql);
$ret = $prep->execute(array('searchTerm' => $searchTerm));

Well, I solved this one. And quite frankly, I'm an idiot... Thank you all for seeing this and giving good feedback. The problem was a typo in a table name (which I changed, so nobody here would be able to see my issue to begin with...). The suggestions did lead me to find the issue, though, so thank you adam, jkndrkn and troelskn.
For the record, the following combination works well:
WHERE aw_hcl_subdevices.hs_text LIKE CONCAT(\'%\', ?, \'%\')
$ret = $prep->execute(array($searchTerm));

Related

PDO returns empty array as result

I have a simple search form, which I use to send a POST request to my php script using AJAX. I want the script to search my database for the keyword in the title column, and return the rows where it finds it. The posted data looks like this "searchword=test1", where test1 in the content of my text input.
I have 2 rows in my database, one has a title of test1, and another of test2. If I do SELECT * FROM articles I can see the results fine. If I type SELECT * FROM articles WHERE title LIKE 'test1'; into console, I get the correct result, but my php script returns an empty array.
No idea what I'm doing wrong here, any help is appreciated.
my php:
try {
$hostname = "localhost";
$username = "root";
$password = "";
$db = new PDO("mysql:host=$hostname;dbname=topdecka_PTC",$username, $password);
if (!empty($_POST["searchword"])) {
$searchword = $_POST["searchword"];
$query = $db->prepare("SELECT * FROM articles WHERE title LIKE %:seachword%");
$query->execute(array(':searchword' => $searchword));
$result = $query->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($result);
die();
}
else {
$query = $db->prepare('SELECT * FROM articles');
$query->execute();
$result = $query->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($result);
die();
}
} catch (PDOException $e) {
echo "Error!: " . $e->getMessage() . "<br/>";
die();
}
Firstly, you forgot the $ sign for %:seachword% as per your assignment:
Sidenote: There's a typo that I just noticed in seachword which should read as searchword as per ':searchword' => $searchword
$searchword = $_POST["searchword"];
However, I'd do something like this instead:
LIKE :seachword
then
$query->execute(array(":searchword" => "%" . $searchword . "%"));
Example syntax:
$sqlprep = $conn->prepare("SELECT `column` FROM `table` WHERE `column` LIKE :word");
$sqlprep->bindValue(':word', '%value%');
Also make sure that your form does have a POST method and that your element is indeed named and no typos.
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// rest of your code
Sidenote: Error reporting should only be done in staging, and never production.
Add $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); right after the connection is opened, to catch potential errors, if any.
The reason it isn't working is because the value for :searchname is being escaped. As a result,
SELECT * FROM articles WHERE title LIKE %:seachword%
is being interpreted as this:
SELECT * FROM articles WHERE title LIKE %"test1"%
which is an invalid query. You need to quote the entire string or use concat() to add the % in.
Your two options are:
$query = $db->prepare("SELECT * FROM articles WHERE title LIKE :seachword");
$query->execute(array(':searchword' => "%" . $searchword . "%"));
or:
$query = $db->prepare("SELECT * FROM articles WHERE title LIKE CONCAT('%', :seachword, '%')");
$query->execute(array(':searchword' => $searchword));
Personally, I prefer the option with CONCAT as it separates responsibilities better, in my opinion.

Fatal error: Call to a member function fetch() on a non-object in, but I can't see any issues at all with the query

I know this you get this question a lot, but I haven't been able to get this to work with all of the answers on previous questions about the same problem. I've tried testing the query, and it works fine. I've copied and pasted the exact same query on PHPMyAdmin and it worked fine and I get no errors when I execute the query.
Here's my code:
try {
$selectProfilesQuery = 'SELECT profile_id, user_id, profile_name, profile_picture_50, profile_tile_cover FROM profile WHERE user_id = :user_id';
$prepSelectProfiles = $conn->prepare($selectProfilesQuery);
$prepSelectProfiles->bindParam(':user_id', $uid, PDO::PARAM_INT);
$prepSelectProfiles->execute();
$profilesResult = $prepSelectProfiles->fetchAll();
}
catch(PDOException $e) {
$conn = null;
header('Location: ../errors/error_101.html');
}
while ($profiles = $profilesResult->fetch(PDO::FETCH_ASSOC)) {
$profileId = $profiles['profile_id'];
$profileTileBg = $profiles['profile_tile_cover'];
$profileImage = $profiles['profile_picture_50'];
$profileName = $profiles['profile_name'];
}
I've tried to find any other error that maybe had anything to do with my query, but whatever I do it keeps giving me two results (which is the desired effect, but should happen inside the application and not in my DB management system).
Who knows what the problem is here? Becuase I'm staring at this code for 30 minutes now and it makes me go nuts.
The error says the problem is on the line with:
while ($profiles = $profilesResult->fetch(PDO::FETCH_ASSOC)) {
Remove the $profilesResult = $prepSelectProfiles->fetchAll(); and use $prepSelectProfiles->fetch() in while loop.
Or
Do a foreach on the result:
foreach($profilesResult as $profiles) {
//...
}
The fetch() should be on PDO Object
So take out
$profilesResult = $prepSelectProfiles->fetchAll();
and change
while ($profiles = $profilesResult->fetch(PDO::FETCH_ASSOC)) {
with
while ($profiles = $prepSelectProfiles->fetch(PDO::FETCH_ASSOC)) {
$profilesResult is an array after u did $profilesResult = $prepSelectProfiles->fetchAll(); and u are calling fetch() using $profilesResult
which is is why its failing
Yes, it is different from other questions.
Here you need only understand what are you doing. In this line you are getting an array
$profilesResult = $prepSelectProfiles->fetchAll();
of simple arrays, none of which being an instance of PDO statement
To make this code little saner and less wordy
$sql = 'SELECT profile_id, user_id, profile_name, profile_picture_50, profile_tile_cover '
. 'FROM profile WHERE user_id = :user_id';
$stmt = $conn->prepare($sql);
$stmt->execute([$uid]);
$profiles = $stmt->fetchAll();
while (foreach $profiles as $row) {
extract($row);
}

How do I reuse a PDOStatement prepare?

I made a search but I couldn't find anything fulfilling
Imagine the following:
<?php
$connection = new \PDO($dsn, $user, $pass);
$stmt1 = $connection->prepare("
SELECT
*
FROM
table
WHERE
a = :a
AND b = :b
AND c = :c
AND d = :d
AND search LIKE :search
");
$stmt1->bindValue(":a", $a);
$stmt1->bindValue(":b", $b);
$stmt1->bindValue(":c", $c);
$stmt1->bindValue(":d", $d);
$stmt2 = clone $stmt1;
$stmt1->bindValue(":search", "a%");
$stmt2->bindValue(":search", "b%");
$stmt1->execute();
$stmt2->execute();
while(($r1 = $stmt1->fetchObject()) && ($r2 = $stmt2->fetchObject()))
echo $r1->foo . " " . $r2->foo . "\n";
}
Am I allowed to do something like this? How can I clone/reuse a PDOStatement instance and use it at the same time of its original instance?
Don't say "use UNION", that's not the point of my question :P
Thank you in advance.
This is not what prepared statement re-use is for. The idea of reusing a prepared statements is consecutive, not concurrent.
So you can do this:
$connection = new \PDO($dsn, $user, $pass);
$stmt = $connection->prepare("
SELECT *
FROM table
WHERE a = :a
AND b = :b
AND c = :c
AND d = :d
AND search LIKE :search
");
$stmt->bindValue(":a", $a);
$stmt->bindValue(":b", $b);
$stmt->bindValue(":c", $c);
$stmt->bindValue(":d", $d);
foreach (["a%", "b%"] as $search) {
$stmt->bindValue(":search", $search);
$stmt->execute();
while($r = $stmt->fetchObject()) {
echo $r->foo . "\n";
}
$stmt->closeCursor();
}
If you want to handle multiple result sets concurrently (at least with MySQL), you will need to do one of the following:
Use an appropriate set of UNION/JOIN to create a single result set.
Buffer the result sets in memory and iterate them again when you have all the data available.
Create multiple connections - you cannot have more than one open statement cursor per connection, but you can have multiple open connections.
If you want to use multiple connections, your code becomes:
$query = "
SELECT *
FROM table
WHERE a = :a
AND b = :b
AND c = :c
AND d = :d
AND search LIKE :search
";
$connection1 = new \PDO($dsn, $user, $pass);
$connection2 = new \PDO($dsn, $user, $pass);
$stmt1 = $connection1->prepare($query);
$stmt1->bindValue(":a", $a);
$stmt1->bindValue(":b", $b);
$stmt1->bindValue(":c", $c);
$stmt1->bindValue(":d", $d);
$stmt1->bindValue(":search", "a%");
$stmt2 = $connection2->prepare($query);
$stmt2->bindValue(":a", $a);
$stmt2->bindValue(":b", $b);
$stmt2->bindValue(":c", $c);
$stmt2->bindValue(":d", $d);
$stmt2->bindValue(":search", "b%");
$stmt1->execute();
$stmt2->execute();
while(($r1 = $stmt1->fetchObject()) && ($r2 = $stmt2->fetchObject()))
echo $r1->foo . " " . $r2->foo . "\n";
}
$stmt1->closeCursor();
$stmt2->closeCursor();
Sounds like you're looking for an abstraction of a prepared statement that is able to carry it's own parameters with it.
As you actually consume each result by traversing it, adding an Iterator that knows how to traverse such a parametrized prepared statement looks fitting then.
However this suggestion is not part of PDO, so you would need to write it your own (however this might also prevent to repeat yourself with PDO code and you perhaps can even deffer the actual creation and execution of the statement so this might also create some benefit for lazy loading data).

Updating multiple MySQL table columns using arrays with PDO

I'm trying to switch all my MySQL connections from the old mysql_query to PDOs. I'm trying to update multiple rows and columns of a MySQL table using different arrays and I'm receiving the following error:
[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 '(accnt, car, radio, misc) values ('admin', '300.00', '400.00', '10.00') WHERE ID' at line 1
From the following code:
$account = $_POST['account'];
$car_lease = $_POST['car_lease'];
$radio_lease = $_POST['radio_lease'];
$misc_lease = $_POST['misc_lease'];
$lease_ID = $_POST['lease_ID'];
//$data = array_map(null,$account,$car_lease,$radio_lease,$misc_lease);
$A = count($lease_ID);
try {
$DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$STH = $DBH->prepare('UPDATE lease (accnt, car, radio, misc) values (:account, :car_lease, :radio_lease, :misc_lease) WHERE ID = :lease_ID');
$i = 0;
while($i < $A) {
$STH->bindParam(':account', $account[$i]);
$STH->bindParam(':car_lease', $car_lease[$i]);
$STH->bindParam(':radio_lease', $radio_lease[$i]);
$STH->bindParam(':misc_lease', $misc_lease[$i]);
$STH->bindParam(':lease_ID', $lease_ID[$i]);
$STH->execute();
$i++;
}
}
catch(PDOException $e) {
echo "I'm sorry, but there was an error updating the database.";
file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
}
I believe this problem is arising from the way I'm calling the statement handle, but I'm not sure what part of my syntax is incorrect. Also, is this the best way of handling such situations? Or is there a better method to update multiple rows in a table?
You have confused the syntax between INSERT and UPDATE statements. Instead of a VALUES() list, you need a SET clause:
$STH = $DBH->prepare('
UPDATE lease
SET
accnt = :account,
car = :car_lease,
radio = :radio_lease,
misc = :misc_lease
WHERE ID = :lease_ID
');
Review the MySQL UPDATE syntax reference for the full specification to use with UPDATE statements.
I think this would be the simplest and easiest solution, if you can trust your keys and values:
$update = 'SET ';
$fields = array_keys($_POST);
$values = array_values($_POST);
foreach ($fields as $field) {
$update .= $field . '=?,';
}
$update = substr($update, 0, -1);
$db->query("update sub_projects ${update} where id=${_GET['id']}");
$db->execute($values);
Simple way to update multiple fields .but very important that inputs on your editing page must be in same order with your data base table.
hope its help
if (isset($_POST['pageSubmit'])) {
echo '<pre>';
print_r($_POST['page']);
echo '</pre>';
$fields = array('id','name','title','content','metaKey','metaDescr','metaTitle');//fields array
$fields = array_map(function($field){
return "`$field`";
},$fields);
$queryArray = array_combine($fields,$_POST['page']);//createng array for query
$countFields = count($queryArray);//getting count fields
$id = array_splice($queryArray , 0,-($countFields-1));//getting id of page
$insertArray = $queryArray;//getting new fields array without first key and value
function updatePage($db, array $fields, array $id){
$where = array_shift($id);
$sql = array();
foreach ($fields as $key => $value) {
$sql[] = "\n".$key."" ." = "."'".$value."'";
}
$sql = implode(",",$sql);
try {
$query = $db->prepare("UPDATE `pages` SET $sql WHERE `id` = $where ");
$query->execute();
} catch (Exception $e) {
echo $e->getMessage();
}
}
updatePage($db, $insertArray, $id);
}
better way is CASE, it is 3-4 time faster than preapared stmt

pdo select statement returning no rows

I am making a simple select from mySQL using PHP. I am doing something wrong that I can't seem to track down.
Here's my statement:
$storyTitle = $_GET['title'];
$storyDate = urldecode($_GET['date']);
$SQL = "SELECT
*
FROM
tblContent
WHERE
REPLACE(contentTitle,' ' , '-') = :storyTitle
AND
date(publishDate) = date(:storyDate)";
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);
$q = $conn->prepare($SQL);
$q->execute(array(':storyTitle' => $storyTitle, ':storyDate' => $storyDate));
while($r = $q->fetch()){
echo $SQL;
};
This throws no errors and gives no rows.
If I replace the identifiers :storyTitle and :storyDate with a hard coded SQL statement, I get the correct results. I've stepped through and looked at the variables, and they seem right... I've already wasted so much time hunting, but I lack the expertise to pick out what I'm doing wrong.
Dump the contents of your variables. I'm suspicious of:
$storyDate = urldecode($_GET['date']);
$_GET parameters automatically are url-decoded.
you have to ask PDO to throw an error explicitly
try {
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$q = $conn->prepare($SQL);
$q->execute(array(':storyTitle' => $storyTitle, ':storyDate' => $storyDate));
} catch (PDOException $e) {
echo $e->getMessage();
}

Categories