I need some help. I have some nested SELECT statements that get the user's ID then use that ID to search another table in MySQL. I have a foreach() loop that uses the user_id from the first query to create a folder for the user if there isn't one in the filesystem. Then I used bindParam() to assign it a variable and use it in another query to get the user's name. However, it throws and exception saying 'Call to a member function bindParam() on null in C:\foo\bar\foobarscript.php on line 29'. Here's my code up until the break...
try {
$con = new PDO("mysql:host=$dbname;dbname=$db", $user, $pass);
//Set the PDO error mode to exception
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->beginTransaction();
$stmt = $con->prepare("SELECT user_id
FROM users");
$stmt->execute();
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
$res = $stmt->fetchAll();
foreach($res as $row) {
$uid = $row['user_id'];
$filename = './reports/'.$uid.'';
if(!file_exists($filename)) {
if(!mkdir('./reports/'.$uid)) {
die('Failed to create folders..');
}
}
$stmt2->bindParam(':uid', $uid); //<--- Code breaks here
$stmt2 = $con->prepare("SELECT CONCAT(fname,' ',lname) as fullname FROM users WHERE user_id = :uid");
$stmt2->execute();
$fullName = $stmt2->fetchAll();
$userArray[] = array_fill_keys($uid, $fullName);
$stmt2->closeCursor();
}
I have searched up and down and tried rewriting it, debugging piece by piece. Everything works fine until I put it all back together and I get this error again. I really appreciate any help!
Edit: I have even tried removing the assigned variable and binding like:
$stmt2->bindParam(':uid', $row['user_id']);
Related
<?php
try
{
global $db;
$user = 'postgres';
$password = '*****'; //For security
$db = new PDO('pgsql:host=localhost;dbname=dnd', $user, $password);
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch (PDOException $ex)
{
echo 'ERROR!!: ' . $ex->getMessage();
die();
}
$table = htmlspecialchars($_REQUEST['table']);
$idNum = htmlspecialchars($_REQUEST['id']);
try {
//$query = "SELECT * FROM $table WHERE id = $idNum"; This works
//$query = "SELECT * FROM $table WHERE id = :number"; This works
$query = "SELECT * FROM :tableName WHERE id = :number";
$statement = $db->prepare($query);
$statement->bindValue(":tableName", $table, PDO::PARAM_STR);
$statement->bindValue(":number", $idNum, PDO::PARAM_INT);
$statement->execute();
$info = $statement->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $excep) {
echo "Opps: " . $excep->getMessage();
die();
}
Okay I'm going crazy here trying to get this to work.
I have a database set up that I need to query from. I receive the query from an AJAX request with the name of the table I want and the id for the item. When I try to query with both variables, the binding does not occur in the prepared statement and instead I get this error code
Opps: SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "$1" LINE 1: SELECT * FROM $1 WHERE id = 1 ^
When I have just the straight PHP variables it works fine so I know it can work, but when I want to bind multiple it seems to fail and give a variable number as above.
I can also get it to work if I simply have one of the variables bound, such as the second commented out query in the code - this only works tho if I have the variable I want at the end and not if I wanted to lookup the table spot. (I.E.
$query = "SELECT * FROM :tableName WHERE id = $idNum"; does not work)
I need to cleanse the variables to prevent SQL injection, but I can't do that without binding the variables in a prepared statement. Any help would be appreciated!
According to the PHP manual you can't bind a tablename. As you mentioned it, you can replace it by a variable, but you can't replace it with a placeholder.
So the only solution that will work for you is the query you have above:
$query = "SELECT * FROM $table WHERE id = :number"
This will be what you're looking for. If you want to make it safe for injection, you have to find another way. (Regex for example).
Ref: http://us3.php.net/manual/en/book.pdo.php#69304
Im having problems getting an update function to work. The function marks badges as seen so that they are hidden from a notification window.
The function is called when the user clicks a button to mark them as seen.
I have two triggers on the table its trying to update which I think may be causing the problem.
The problem is : Can't update table 'users' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Triggers:
Function:
function markAsSeen() {
require "connect.php";
$seen = mysqli_query($connection,"Update userbadges
INNER JOIN users ON users.id = userbadges.user_id
SET seen='1'
WHERE studentid = '".$_SESSION["studentid"]."' && seen=0") or die(mysqli_error($connection));
while ($data = mysqli_fetch_array($seen)) {
echo 'Done';
}
}
Is there any way around this?
Your issue is that the update_users_trigger trigger makes changes to the contents of the table users, while the query that is triggering the execution of this trigger also uses the table users.
You will need to adjust your query so that this deadlock doesn't occur. It isn't clear which fields are from each table, but I suspect that in your initial query you need to join on users so that you can query on studentid.
You could create a different function to get the userID that you need something like the following:
require_once "connect.php";
function getUserIDFromStudentID($student_id, mysqli $connection)
{
$query = 'SELECT id FROM users WHERE studentid = ? LIMIT 1';
$stmt = $connection->prepare($query);
// Replace the below s to an i if it's supposed to be an integer
$stmt->bind_param("s", $student_id);
$stmt->execute();
$result = $stmt->get_result();
$record = $result->fetch_object();
$result->free();
if ($record) {
return $record->id;
}
}
function markAsSeen(mysqli $connection) {
$user_id = getUserIDFromStudentID($_SESSION["studentid"], $connection);
if (! $user_id) {
throw new Exception('Unable to get user id');
}
$seen_query = 'UPDATE userbadges SET seen = 1 WHERE user_id = ? and seen = 0';
$stmt = $connection->prepare($seen_query);
// Replace the below s to an i if it's supposed to be an integer
$stmt->bind_param("s", $user_id);
$result = $stmt->execute();
if (! $result) {
die(mysqli_error($connection));
}
echo 'Done';
}
Passing the connection object around rather than requiring a global file to be required every time will allow for more flexibility.
I am making a game for class and I have added a commenting system to go with it. I am now wanting to add the ability to report the comment.
I have added a column in the comments table called report_active and my idea was to set this to 1 when it is active (meaning it has been reported) and 0 when it isn't. Then just list in the adminCP all of the comments with an active report on them.
I have made a file called report_comment.php which I intend to only be used to run the queries then redirect back to another page.
This is my report_comment.phppage:
<?php
require_once('db_connect.php');
require_once('security.php');
if (isset($_GET['id'])) {
$report_active = 1;
$id = $_GET['id'];
$select = $db->query("SELECT * FROM comments WHERE id = ?");
$select->bind_param('i', $id);
if ($select->execute()) {
if ($select->num_rows) {
// Run the update query
$update = $db->query("UPDATE comments SET report_active = ? WHERE id = ?");
$update->bind_param('ii', $report_active, $id);
if ($update->execute()) {
header('Location: comments.php');
die();
}
}
}
}
?>
What am I doing wrong? As this is the error I am returned with:
Fatal error: Call to a member function bind_param() on a non-object
$select = $db->query("SELECT * FROM comments WHERE id = ?");
^^^^^---execute the query immediately
You want
$stmt = $db->prepare("SELECT * FROM comment WHERE id = ?");
^^^^^^^---note the diff
instead. Plus, you should be checking for failure, e.g.
if ($stmt === false) {
die("Prepare failed with error: " . $db->errorInfo);
}
or similar for your particular DB library.
In a class, I have some PDO:
$userFName = 'userFName';
include('dbconnect.php'); // Normally I'd store the db connect script outside of webroot
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name;", $db_user, $db_password);
$stmt = $pdo->prepare('SELECT userFName FROM Users WHERE username = :uname AND password = :pword AND roleID = 1');
$stmt->bindParam(':uname', $this->user->username);
$stmt->bindParam(':pword', $this->user->password);
$stmt->bindColumn(4, $userFName, PDO::PARAM_STR);
$stmt->execute();
$familiar = $stmt->fetch(PDO::FETCH_BOUND);
$this->user->firstName = $familiar;
It's returning the ID in the first column instead of the VARCHAR contents in the 4th column. Any idea why?
When using PDO::FETCH_BOUND with fetch(), the method will not return a result record. Instead the value of the column should be available in the variable you have bound using $stmt->bindColumn() earlier.
So change your code to:
$stmt->bindColumn(1, $userFName, PDO::PARAM_STR);
$stmt->execute();
$stmt->fetch(PDO::FETCH_BOUND);
$this->user->firstName = $userFName; // <-- use the bound variable
However you won't need that bindColumn() call. You could simplify the code as this:
$stmt->execute();
$row = $stmt->fetch(); // uses PDO::FETCH_ASSOC by default
$this->user->firstName = $row['FName'];
There is too much code in your class. And one fault. To send a distinct query to get just one property from database, creating a distinct connection for this is a dead overkill.
Connection have to be moved away unconditionally and you must think of getting ALL user data with one query.
Proper code
function __construct($pdo) {
$this->pdo = $pdo;
// Normally you should include somewhere in a bootstrap file
// not in the application class
// and instantiate PDO in that bootstrap as well
// and only PASS already created instance to the class
}
function getUserFName() {
$sql = 'SELECT * FROM Users WHERE username = ? AND password = ? AND roleID = 1';
$stmt = $pdo->prepare($sql);
$stmt->execute(array($this->user->username,$this->user->password));
return $stmt->fetchColumn();
}
Apologies in advance because I'm really unsure how to ask this question so if you need to know anything then please comment rather than downvote and I will edit.
I have teaser links on my main page which when clicked open up a window with the full article. I'm currently converting my MySQL code over to PDO and have gotten a little stuck.
In MySQL I used to be doing the following (Here, $foo_query is the query from the first page):
$id = $_GET['id'];
$sql = "SELECT id, postdate, title, body FROM FooBarTable WHERE id = $id";
if ($foo_query = mysql_query($sql)) {
$r = mysql_fetch_assoc($foo_query);
$title = $r["title"];
$body = $r["body"];
}
Which is simple to understand to me. I've been trying to convert this using what I know, and it turns out I don't know very much. So far I have the following:
$id = $_GET['id'];
$sql = $DBH->prepare("SELECT id, postdate, title, body FROM FooBarTable WHERE id = :id OR id = $id");
$sql->bindParam(':id', $_REQUEST['id'], PDO::PARAM_INT);
if ($foo_query = $DBH->query($sql)) {
$r->setFetchMode(PDO::FETCH_ASSOC);
$r = $foo_query->fetch();
$title = $r["title"];
$body = $r["body"];
}
$sql->execute();
This brings up an error of 'PDO::query() expects parameter 1 to be string'. This is for the 'if' line.
Have I even written any of that PDO correctly? What would I need to do from here? A friend has recently taught me MySQL, but he doesn't know PDO at all which means I can't ask his advice (not all that helpful...)
This is the correct way, with comments:
try {
//Connect to the database, store the connection as a PDO object into $db.
$db = new PDO("mysql:host=localhost;dbname=database", "user", "password");
//PDO will throw PDOExceptions on errors, this means you don't need to explicitely check for errors.
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//PDO will not emulate prepared statements. This solves some edge cases, and relives work from the PDO object.
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//Prepare the statement.
$statement = $db->prepare("SELECT id, postdate, title, body FROM FooBarTable WHERE id = :id");
//Bind the Value, binding parameters should be used when the same query is run repeatedly with different parameters.
$statement->bindValue(":id", $_GET['id'], PDO::PARAM_INT);
//Execute the query
$statement->execute();
//Fetch all of the results.
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
//$result now contains the entire resultset from the query.
}
//In the case an error occurs, a PDOException will be thrown. We catch it here.
catch (PDOException $e) {
echo "An error has occurred: " . $e->getMessage();
}
You need to use PDOStatement::execute instead of PDO::query:
$foo_query = $sql->execute();
You may also bind all your params at once when calling execute:
$foo_query = $sql->execute(array(
':id' => $id
));
You should change it to:
$sql->execute();
if($r = $sql->fetch()) {
$title = $r["title"];
$body = $r["body"];
Try this:
$sql = $DBH->prepare("SELECT id, postdate, title, body
FROM FooBarTable WHERE id = :id OR id = $id");
$sql->bindParam (':id', $_REQUEST['id'],PDO::PARAM_INT);
$sql->execute();
while($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$title = $row["title"];
$body = $row["body"];
}