Function/Trigger already in use? - php

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.

Related

how to call a function multiple times with where clause in php pdo?

I am new to php and trying hard to learn its why you guys and gals need to Forgive me for asking a lot!
Here is my question;
I am trying to call a function with where clause multiple times, I have read allmost all posts and examples still didn't understand how to do it.
I tought that An example will be more useful than any blurb I can write.
Here is the function I am trying to create and use it multiple times :
function getTable($tableName, $clause) {
$stmt = $pdo->prepare("SELECT * FROM ".$tableName." WHERE ".$clause." = :".$clause);
$stmt->bindParam(":$clause", $clause, PDO::PARAM_STR);
$stmt->execute();
if($stmt->rowCount() > 0){
return true;
}else{
return false;
}
return $stmt;
}
I am not sure if my fucntion is safe or its rigth.
AND this is how I am trying to call function, which I dont know how to call table name and where clause and how to turn while loop.
getTable('posts');
If you give an example of creating and caling function, I would be grateful, Thanks
Nope, your function is not safe. Moreover it is just useless. There is no use case where you would use it like this getTable('posts');. And for the everything else it is much better to allow the full SQL syntax, not some limited subset.
The simplest yet most powerful PDO function I can think of is a function that accepts a PDO object, an SQL query, and array with input variables. A PDO statement is returned. I wrote about such function in my article about PDO helper functions. So here is the code:
function pdo($pdo, $sql, $args = NULL)
{
if (!$args)
{
return $pdo->query($sql);
}
$stmt = $pdo->prepare($sql);
$stmt->execute($args);
return $stmt;
}
With this function you will be able to run any query, with any number of WHERE conditions, and get results in many different formats. Here are some examples from the article mentioned above:
// getting the number of rows in the table
$count = pdo($pdo, "SELECT count(*) FROM users")->fetchColumn();
// the user data based on email
$user = pdo($pdo, "SELECT * FROM users WHERE email=?", [$email])->fetch();
// getting many rows from the table
$data = pdo($pdo, "SELECT * FROM users WHERE salary > ?", [$salary])->fetchAll();
// getting the number of affected rows from DELETE/UPDATE/INSERT
$deleted = pdo($pdo, "DELETE FROM users WHERE id=?", [$id])->rowCount();
// insert
pdo($pdo, "INSERT INTO users VALUES (null, ?,?,?)", [$name, $email, $password]);
// named placeholders are also welcome though I find them a bit too verbose
pdo($pdo, "UPDATE users SET name=:name WHERE id=:id", ['id'=>$id, 'name'=>$name]);
// using a sophisticated fetch mode, indexing the returned array by id
$indexed = pdo($pdo, "SELECT id, name FROM users")->fetchAll(PDO::FETCH_KEY_PAIR);
Special for you, here is the while example, though this method is considered clumsy and outdated:
$stmt = pdo($pdo,"SELECT * FROM tableName WHERE field = ?",[$value]);
while ($row = $stmt->fetch()) {
echo $row['name'];
}

How can I delete a like from my database if user_id and post_id are the same?

I want to check if user already liked the post, if so than delete the user from database likes.
I've tried to do an if statement but it wont get to the else and only add likes even when user_id and post_id are the same.
Like.class.php
private function Addlike(){
$conn = db::getInstance();
$query = "insert into likes (post_id, user_id) values
(:post_id, :user_id)";
$statement = $conn->prepare($query);
$statement->bindValue(':post_id',$this->getPostId());
$statement->bindValue(':user_id',$this->getUserId());
$statement->execute();
}
private function Deletelike(){
$conn = db::getInstance();
$query = "DELETE FROM likes WHERE post_id = :post_id
AND user_id =:user_id";
$statement = $conn->prepare($query);
$statement->bindValue(':post_id',$this->getPostId());
$statement->bindValue(':user_id',$this->getUserId());
$statement->execute();
}
public function CheckLike(){
$conn = db::getInstance();
$query = "SELECT COUNT(*) FROM likes WHERE
post_id=:post_id AND user_id=:user_id";
$statement = $conn->prepare($query);
$statement->bindValue(':post_id',$this->getPostId());
$statement->bindValue(':user_id',$this->getUserId());
$statement->execute();
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
if($result["COUNT(*)"] == 0){
$this->Addlike();
}else{
$this->Deletelike();
}
return $result;
}
If you press like for the first time you should like the post and it should be stored in the database, if you press again you unlike the post and it gets deleted from the database. But now it only does the Addlike function...
I think PDO::FETCH_ASSOC returns a multidimensional array when used with PDOStatement::fetchAll, according to https://www.php.net/manual/en/pdostatement.fetchall.php#refsect1-pdostatement.fetchall-examples.
Try changing your code to something like this and see if it works. You could also try dumping the $result variable to see what the structure looks like.
if($result[0]["COUNT(*)"] == 0){
$this->Addlike();
}else{
$this->Deletelike();
}
If an array index doesn't exist, PHP considers it false, which would explain why you're always adding likes, since false == 0 in PHP.
If you want to avoid this equivalency of false and 0, use the identical operator to also compare types:
if ($result["COUNT(*)"] === 0) {
...

Returning a value from an SQL Method

]i'm completely out of idea's as to why the code below does not return the value. I have 2 sql tables that related to one another. Within a class i have the following method, and within the scope of that method all is well. The var dump shows the correct data. The following code is stated in class.php.
public function getId($username, $password) {
if (isset($_SESSION['username'])) {
$sql = "SELECT person_id FROM user WHERE username = ?";
$stmt = $this->dbh->prepare($sql);
$stmt->bindParam(1, $_SESSION['username']);
$stmt->execute();
$id = $stmt->fetch(PDO::FETCH_NUM);
$id = $id[0];
}
ELSE {
echo "Failed to retreive person_id";
}
var_dump($id);
return $id[0];
}
However when i return that value to the showinfo.php which is the main document and state the following:
$user_id = $id[0];
var_dump($user_id);
Then the var dump echoes "NULL". And I need it for the follwing method which is also in class.php.
public function showInfo($user_id) {
$sql = "SELECT * FROM person WHERE person_id = ?";
$stmt = $this->dbh->prepare($sql);
$stmt->bindParam(1, $user_id);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
foreach ($result as $row) {
echo "<pre>".print_r ($row, true)."</pre>";
}
}
Could anybody be so kind as to show me ways to get this done?
Many thanks in advance for your time and effort in helping me.
I'm guessing you are trying to access the field with the index [0] twice.
Maybe try to return just $id and then access [0] on the outer class.
My PHP is a bit rusty and I don't have access to test right now, but don't you need single quotes around the question mark so it goes to SQL quoted?
i.e.
$sql = "SELECT * FROM person WHERE person_id = '?'";
or
$stmt->bindParam(1, "'" + $_SESSION['username'] + "'");
(but not both!)
so that SQL sees
SELECT * FROM person WHERE person_id = 'MyVal'
instead of
SELECT * FROM person WHERE person_id = MyVal
which it would interpret as a column name
You don't show where the method is called.
You tried this in showinfo.php:
$user_id = $id[0];
Shouldn't this be...
$user_id = getId('someusername', 'somepassword')
Or something similar? Sorry this isn't an answer, but I can't comment.

Why do I get Call to a member function bind_param() on a non-object...?

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.

running multiple query's in mysql?

i'm currently running this query to delete messages within a messaging system on my site, when the user hits delete the query runs and updates the table in my database.
deleted_to is updated from '0' to '1'
what i also want to do is capture the user's id and store this in the table under the column 'user_who_deleted'
to do this i am using $_SESSION['user_id'] but am having trouble finding a way to have this inserted into the table.
can someone please show me how to do this. thanks
delete message link code:
<?php $inbox_set = get_inbox();
while ($inbox = mysql_fetch_array($inbox_set)) { ?>
<div class="message_buttons2">Delete Conversation</div>
query that sets deleted_to from 0 to 1 :
function delete_message_to($message, $user) {
global $connection;
global $_SESSION;
$query = "UPDATE ptb_messages
SET deleted_to='1'
WHERE msg_id='1' ";
mysql_query($query, $connection);
}
the delete bit works but i am now trying to insert the users $_SESSION['user_id'] into ptb_messages.user_who_deleted
i want this to run as part of the same query if i can. i've tried something like below but it doesnt do anything
function delete_message_next($message, $user) {
global $connection;
global $_SESSION;
$query = "SELECT user_who_deleted
FROM ptb_messages
SET user_who_deleted =" . $_SESSION['user_id'] . "";
mysql_query($query, $connection);
}
Unless i misunderstand, don't you just want to do this?
$query = '
UPDATE
ptb_messages
SET
deleted_to=1,
user_who_deleted = "'.$_SESSION['user_id'].'"
WHERE
msg_id=1';
Ideally, as mentioned, you want to go to mysqli or PDO, and work with prepared statements:
$query = '
UPDATE
ptb_messages
SET
deleted_to= :setDeleted,
user_who_deleted = :userId
WHERE
msg_id= :msgId';
$stmt = $dbh->prepare($query);
$stmt->bindParam(':setDeleted', 1);
$stmt->bindParam(':userId', $_SESSION['user_id']);
$stmt->bindParam(':msgId', 1);
$stmt->execute();
http://www.php.net/pdo.prepared-statements

Categories