I'm at the early stages of incorporating a search facility on a website, but I've hit a stumbling block. At the moment, I'm just doing some testing, using jQuery AJAX, but the problem definitely lies in my php:
...
$searchq = $_POST['searchq'];
$output = '';
$db = new PDO($dsn, $mysqluser, $mysqlpass, array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
function getData($db){
// Prepare resource query statement
$stmt = $db->query("SELECT * FROM mod_site_content WHERE alias = ':searchq'");
// Bind paremeters
$stmt->bindParam(':searchq', $searchq, PDO::PARAM_STR);
// Execute query
$stmt->execute();
// Grab result
$output = $stmt->fetchAll();
// Return output
done($output);
};
try {
getData($db);
} catch(PDOException $e){
echo $e->getMessage();
}
function done($out){
echo $out;
}
At the moment I'm just passing the results to console.log() in my AJAX .done() method. The above outputs "Array" with nothing in it, regardless of whether I search for something that should be there or not.
If I change the above slightly to:
function getData($db){
...
$output = $stmt->fetchAll();
$result = implode($output,"--");
// Reture output
done($result);
};
I get nothing back whatsoever.
mod_site_content looks like this:
id | type | alias
-------------------------
1 | document | home
2 | document | projects
...
Thanks.
Your issue is here:
$stmt = $db->query("SELECT * FROM mod_site_content WHERE alias = ':searchq'");
replace it by this:
$stmt = $db->prepare("SELECT * FROM mod_site_content WHERE alias = :searchq");
PDO variable i.e. :searchq shouldn't be surrounded by ' or else PDO will consider them as strings, your code should be giving an error when you try to bind searchq
Additionally notice that I used the prepare() not query(), you need to prepare the query first, then bind params then execute
third issue, you should pass $searchq to your getData function
I copied and pasted your code here, and edited, just to clear my head, can you please test it and tell me if it works?
$searchq = $_POST['searchq'];
$output = '';
$db = new PDO($dsn, $mysqluser, $mysqlpass, array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
function getData($db, $searchq){
// Prepare resource query statement
$stmt = $db->prepare("SELECT * FROM mod_site_content WHERE alias = :searchq");
// Bind paremeters
$stmt->bindParam(':searchq', $searchq, PDO::PARAM_STR);
// Execute query
$stmt->execute();
// Grab result
$output = $stmt->fetchAll();
// Return output
done($output);
};
try {
getData($db, $searchq);
} catch(PDOException $e){
echo $e->getMessage();
}
function done($out){
if(is_array($out)){
print_r($out);
} else {
echo $out;
}
}
echo json_encode($out) and make sure you are expecting a json object on the browser.
No idea offhand why imploding the return value and echoing it out failed to return anything, unless ->fetchAll doesn't return an actual array according to implode, in which case it should be kicking out an error somewhere...
Related
<?php
require_once('dbconfig.php');
global $con;
$query = $con->prepare("SELECT * FROM userinfo order by id DESC");
$query->execute();
mysqli_stmt_bind_result($query, $id, $name, $username, $password);
You should use ->bindColumn Manual
See also This answer.
Best Practise: Do not use SELECT * instead define each column you need to grab from the table.
Do not globalise your connection variable. This is a security risk as well as adding bloat and should be unneeded on your code.
Because it is a static statement you can use ->query rather than prepare, as nothing needs to be prepared.
Solution:
$query = $con->query("SELECT id,name,username,password FROM userinfo ORDER BY id DESC");
try {
$query->execute();
$query->bindColumn(1, $id);
$query->bindColumn(2, $name);
$query->bindColumn(3, $username);
$query->bindColumn(4, $password);
}
catch (PDOException $ex) {
error_log(print_r($ex,true);
}
Alternatively:
A nice feature of PDO::query() is that it enables you to iterate over the rowset returned by a successfully executed SELECT statement. From the manual
foreach ($conn->query('SELECT id,name,username,password FROM userinfo ORDER BY id DESC') as $row) {
print $row['id'] . " is the ID\n";
print $row['name'] . " is the Name\n";
print $row['username'] . " is the Username\n";
}
See Also:
Mzea Has some good hints on their answer, you should use their $options settings as well as using their suggested utf8mb4 connection character set.
And their suggestion for using ->fetchAll is also completely valid too.
Try this
$dsn = "mysql:host=localhost;dbname=myDatabase;charset=utf8mb4";
$options = [
PDO::ATTR_EMULATE_PREPARES => false, // turn off emulation mode for "real" prepared statements
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //turn on errors in the form of exceptions
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //make the default fetch be an associative array
];
try {
$pdo = new PDO($dsn, "username", "password", $options);
} catch (Exception $e) {
error_log($e->getMessage());
exit('Something weird happened'); //something a user can understand
}
$arr = $pdo->query("SELECT * FROM myTable")->fetchAll(PDO::FETCH_ASSOC);
I'm having problems with a PHP script that returns some info based on a supplied array of identifiers (MAC addresses).
It gives me a 500 unspecified error.
if (!isset($_POST['macs'])) {
echo 'Please enter mac addresses!';
die;
}
$mysqli = new mysqli("x", "x", "x", "x");
/* check connection */
if ($mysqli->connect_error)
die("$mysqli->connect_errno: $mysqli->connect_error");
$stmt = $mysqli->stmt_init();
/* create a prepared statement */
$query = "SELECT username, mac FROM user WHERE mac IN (" . str_repeat("?,", count($_POST['macs']));
$query = rtrim($query, ",");
$query = $query . ')';
if ($mysqli->prepare($query)) {
call_user_func_array(array($stmt, "bind_param"), array_merge(array('s'), $_POST['macs']));
/* execute query */
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo $row['username'];
}
/* close statement */
mysqli_stmt_close($stmt);
}
mysqli_close($link);
This is what I'm posting via the Postman Chrome app:
macs[0] = 'F0:72:8C:F3:B5:66'
macs[1] = 'FA:72:8C:F3:B5:66'
Can anyone at least hint me at what's causing the problem. I'm guessing it's the call_user_func_array call but, I'm unsure of what's the actual problem.
// If you bind array-elements to a prepared statement, the array has to be declared first with the used keys:
Coming to the problem calling mysqli::bind_param() with a dynamic number of arguments via call_user_func_array() with PHP Version 5.3+, there's another workaround besides using an extra function to build the references for the array-elements.
You can use Reflection to call mysqli::bind_param().
Example:
<?php
$db = new mysqli("localhost","root","","tests");
$res = $db->prepare("INSERT INTO test SET foo=?,bar=?");
$refArr = array("si","hello",42);
$ref = new ReflectionClass('mysqli_stmt');
$method = $ref->getMethod("bind_param");
$method->invokeArgs($res,$refArr);
$res->execute();
for more
http://php.net/manual/en/mysqli-stmt.bind-param.php#104073
Can't seam to find the answer to this.
I have a mysqli loop statement. And in that loop I want to run another query. I cant write these two sql together. Is that possible?
I thought since I use stmt and set that to prepare statement. So i add another variable stmt2. Running them seperate works, but run it like I wrote it gives me "mysqli Fatal error: Call to a member function bind_param() on a non-object"
Pseudocode :
loop_sql_Statement {
loop_another_sql_statement(variable_from_firsT_select) {
echo "$first_statement_variables $second_statemenet_variables";
}
}
$sql = "select dyr_id, dyr_navn, type_navn, dyr_rase_id, dyr_fodt_aar, dyr_kommentar, dyr_opprettet, dyr_endret
from dyr_opphald, dyr, dyr_typer
where dyropphald_dyr_id = dyr_id
and dyr_type_id = type_id
and dyropphald_opphald_id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("i",
$p_opphald_id);
$stmt->execute();
$stmt->bind_result($dyr_id, $dyr_navn, $type_navn, $dyr_rase_id, $dyr_fodt_aar, $dyr_kommentar, $dyr_opprettet, $dyr_endret);
echo "<table>";
while($stmt->fetch()) {
echo "<tr><td>$dyr_navn</td><td>$type_navn</td><td>$dyr_rase_id</td><td>$dyr_fodt_aar</td><td>";
$sql2 = "select ekstra_ledetekst, ekstradyr_ekstra_verdi from dyr_ekstrainfo, ekstrainfo where ekstradyr_ekstra_id = ekstra_id and ekstradyr_dyr_id = ?";
try {
$stmt2 = $mysqli->prepare($sql2);
$stmt2->bind_param("i",
$dyr_id);
$stmt2->execute();
$stmt2->bind_result($ekstra_ledetekst, $ekstra_ledetekst);
echo "<td>";
while($stmt2->fetch()) {
echo "$ekstra_ledetekst => $ekstra_ledetekst<br>";
}
}catch (Exception $e) {}
echo "</td></tr>";
}
echo "</table>";
The answer:
Silly me, I didnt know I had to have two mysqli connection. So the solution was to declare another mysqli connection.
$mysqli = new mysqli($start, $name, $pwd, $selected_db);
$mysqli2 = new mysqli($start, $name, $pwd, $selected_db);
You should be able to do that, although you make have to start a second connection.
I'm using PDO to grab records from a mysql table. The data will be encoded with json_encode() and printed through the Slim framework for the API:
$app->get('/get/profile/:id_user', function ($id_user) use ($app) {
$sql = 'SELECT * FROM user WHERE id_user = :id_user';
try {
$stmt = cnn()->prepare($sql);
$stmt->bindParam(':id_user', $id_user, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC); // THIS!!!
if($stmt->rowCount()) {
$app->etag(md5(serialize($data)));
echo json_encode($data,JSON_PRETTY_PRINT);
} else {
$app->notfound();
}
} catch(PDOException $e) {
echo $e->getMessage();
}
});
Should I use
$data = $stmt->fetch(PDO::FETCH_ASSOC);
or
$data = $stmt->fetchObject();
? Any direct benefits on fetching the data as an object? I've read some examples but they never explain why. The only usage for the resulting data will be to print it in JSON format. Thanks!
It doesn't matter. Though I'd cut an object out with Occam's razor.
Also your code is slightly wrong and redundant. Here is a proper version
$sql = 'SELECT * FROM user WHERE id_user = :id_user';
$stmt = cnn()->prepare($sql);
$stmt->bindParam(':id_user', $id_user, PDO::PARAM_INT);
$stmt->execute();
if ($data = $stmt->fetch()) {
$app->etag(md5(serialize($data)));
echo json_encode($data,JSON_PRETTY_PRINT);
} else {
$app->notfound();
}
there is no point in setting fetch mode for the every query when you can set it globally.
numrows() call is also useless.
and of course catching an exception is redundant, insecure and unreliable.
I am trying to set up my first transaction in MySQL using PHP/PDO...
I just have a quick question, what is the best way to determine if the previous query was successful or not? Here is what I have right now, but I would rather find a way to test the query with an if statement.
This is pretty much mock up code to try to get a working model.. I know $results isn't effectively testing if anything was good or bad.. i have it there more as a place holder for the real deal when the time comes..
if ($_POST['groupID'] && is_numeric($_POST['groupID'])) {
$sql = "SET AUTOCOMMIT=0";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$sql = "START TRANSACTION";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$sql = "DELETE FROM users_priveleges WHERE GroupID=:groupID";
$dbs = $dbo->prepare($sql);
$dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$dbs->execute();
try {
$sql = "DELETE FROM groups WHERE GroupID=:groupID LIMIT 1";
$dbs = $dbo->prepare($sql);
$dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$dbs->execute();
$results["error"] = null;
$results["success"] = true;
try {
$sql = "DELETE FROM users WHERE Group=:groupID";
$dbs = $dbo->prepare($sql);
$dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$dbs->execute();
$results["error"] = null;
$results["success"] = true;
$sql = "COMMIT";
$dbs = $dbo->prepare($sql);
$dbs->execute();
}
catch (PDOException $e) {
$sql = "ROLLBACK";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$results["error"] = "Could not delete associated users! $e";
$results["success"] = false;
}
}
catch (PDOException $e)
{
$sql = "ROLLBACK";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$results["error"] = "COULD NOT REMOVE GROUP! $e";
$results["success"] = false;
}
}
Some general notes:
Don't use bindParam() unless you use a procedure that modifies the parameter's value
Therefore, use bindValue(). bindParam() accepts argument value as a referenced variable. That means you can't do $stmt->bindParam(':num', 1, PDO::PARAM_INT); - it raises an error.
Also, PDO has its own functions for controlling transactions, you don't need to execute queries manually.
I rewrote your code slightly to shed some light on how PDO can be used:
if($_POST['groupID'] && is_numeric($_POST['groupID']))
{
// List the SQL strings that you want to use
$sql['privileges'] = "DELETE FROM users_priveleges WHERE GroupID=:groupID";
$sql['groups'] = "DELETE FROM groups WHERE GroupID=:groupID"; // You don't need LIMIT 1, GroupID should be unique (primary) so it's controlled by the DB
$sql['users'] = "DELETE FROM users WHERE Group=:groupID";
// Start the transaction. PDO turns autocommit mode off depending on the driver, you don't need to implicitly say you want it off
$pdo->beginTransaction();
try
{
// Prepare the statements
foreach($sql as $stmt_name => &$sql_command)
{
$stmt[$stmt_name] = $pdo->prepare($sql_command);
}
// Delete the privileges
$stmt['privileges']->bindValue(':groupID', $_POST['groupID'], PDO::PARAM_INT);
$stmt['privileges']->execute();
// Delete the group
$stmt['groups']->bindValue(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$stmt['groups']->execute();
// Delete the user
$stmt['users']->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$stmt['users']->execute();
$pdo->commit();
}
catch(PDOException $e)
{
$pdo->rollBack();
// Report errors
}
}
I wouldn't prepare & execute the transaction statements. I'd use PDO::beginTransaction() , PDO::commit(), and PDO::rollback().
PDO::prepare() and PDO::execute() return FALSE if there's an error, or else they throw PDOException if you setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION).
In your exception handler, you should check PDO::errorInfo() and report the nature of the error. Best practice is to log the raw error info, but give the user a more friendly message.
Don't echo the literal error message in the UI -- this can give the user inappropriate knowledge about your SQL query and schema.
PDO Statement's execute() returns TRUE on success and FALSE on failure, so you can test the return value of the previous execute() in your if statement.
$pdo_result = $dbs->execute();
if ($pdo_result) {
// handle success
} else {
// handle failure
// you can get error info with $dbs->errorInfo();
}
That said, as #Bill Kerwin correctly points out (in his answer that I'm totally upvoting because it's exactly correct), it would be preferable to use PDO::beginTransaction(), PDO::commit(), and PDO::rollback().