Delete database row after a set expiry time (e.g. 5 minutes) - php

Background: I am designing an online virtual classroom management system... it works by generating a random session key (md5(time)) when a teacher creates a classroom and storing it in a database.
To gain access to the classroom the student visits the unique classroom url and the code compares the session key in the url (using GET) to the session key in the database. If there is a match then the classroom displays.
URLs typically look like this: /classroom.php?instance=a529501db8373609f2d47a7843a461ea
Coding help needed: I want my teachers to also be able to set a session 'length', so the classroom is accessible for either 15 minutes, 25 minutes or 50 minutes.
When the time since the classroom was created exceeds for example 25 minutes then the session key is deleted from the database and the classroom can't be accessed any more.
What I have so far:
When a teacher clicks the button to create a classroo the PHP below stores the session key ($instance) and the session length ($duration) in the database...
<?php
session_start();
if (isset($_SESSION['id'])) {
if (isset($_POST['hidden'])) {
// Connects to the database
include_once("$_SERVER[DOCUMENT_ROOT]/classes/includes/dbconnect.php");
mysql_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Sets the session duration
$currentTime = time();
$duration = $currentTime + $_POST['duration'];
// Session variables
$uid = $_SESSION['id'];
$usname = $_SESSION['username'];
// To generate the random hash from the current time
$time = time(); // time to hash
$instance = md5($time); // hash stored in variable
// Stores the session hash (instance) and duration in the instance database
$query = ("INSERT INTO `my-db-name-foo`.`instances` (`instance`, `expiry`) VALUES (`$instance`, $duration`);");
mysql_query($query) or die(mysql_error());
// Closes the database connection
mysql_close();
// Redirects the teacher header('Location:classroom.php?instance='.$instance);
}
} else {
echo 'Please login';
die();
}
?>
Then on the actual classroom.php page a snippet of code checks to see if the session is expired... if it is it deletes it from the database.
<?php
$currentTime = time();
if ($currentTime > $duration){
// Connect to database and delete the row
} else {
// show the classroom
}
?>
Any help or suggestions would be greatly appreciated!
UPDATE ----
Thanks for all the great answers, here is how it all is working at the moment...
On the createclassroom.php page I am storing the instance as well as the NOW() date and time AND the duration as NOW() + $_POST['duration'];...
<?php
session_start();
if (isset($_SESSION['id'])) {
if (isset($_POST['duration']) && !EMPTY($_POST['duration'])) {
// Connects to the database
include_once("$_SERVER[DOCUMENT_ROOT]/classes/includes/dbconnect.php");
// Session variables
$uid = $_SESSION['id'];
$usname = $_SESSION['username'];
// To generate the random hash from the current time
$time = time(); // time to hash
$instance = md5($time); // hash stored in variable
// $duration = $_POST['duration'];
$duration = $_POST['duration'];
// Stores the hash (instance) in the instance database
$sql = ("INSERT INTO `xxx_xxxx`.`instances` (`id`, `teacher`, `instance`, `startdate`, `expiredate`) VALUES ('$uid', '$usname', '$instance', NOW(), NOW() + $duration);");
$query = mysqli_query($dbConnect, $sql)or die(mysql_error());
// Redirects the teacher
header('Location:classroom.php?instance='.$instance);
} else if (isset($_POST['hidden'])) {
echo 'Please select a duration';
}
} else {
echo 'Please login';
die();
}
?>
On the actual classroom.php page I am only checking session instances that are not expired.
<?php
session_start();
// Connects to the database
include_once("$_SERVER[DOCUMENT_ROOT]/classes/includes/dbconnect.php");
$instance = $_GET['instance']; // GETs instance from URL
$usname = $_SESSION['username']; // Gets teacher name
// script to retrieve all the Instances in the database and store them in a variable '$dbInstance'
$sql = "SELECT instance, expiredate FROM instances WHERE instance = '$instance' AND instances.expiredate > NOW()";
$query = mysqli_query($dbConnect, $sql);
$row = mysqli_fetch_row($query);
$dbInstance = $row[0];
if ($dbInstance == $instance){
echo $dbInstance.'<br>';
echo $instance;
} else {
echo $dbInstance.'<br>';
echo $instance.'<br>';
die('Instance not initiated');
}
?>
Now I just need to decide how I want to clear the database every so often. Really, I want to thank you guys for the help, just what I needed!

This sort of row expiration is usually handled as follows:
put the expiration DATETIME in each row. INSERT INTO tbl (id, expiration) VALUES (whatever, NOW() + INTERVAL 5 MINUTE)
when looking up rows, use something like AND tbl.expiration > NOW() in the query. That will make the expired rows appear to be gone.
When convenient, perhaps on an overnight job or an hourly EVENT, get rid of the expired rows: DELETE FROM tbl WHERE tbl.expiration <= NOW()
This is much easier and far more time-precise than trying to actually DELETE expired rows right at the moment they expire. It's also resilient against failures of the immediate DELETE operations, and it scales up nicely.

Add expiry DATETIME to the classroom table, and when you create it set the time when it'll expire.
In the classroom page just compare expiry with the current time.
Bonus: your DB might get big if people don't try to access the classrooms after expiry. You can make a cronjob that deleted expired classrooms once in a while: DELETE FROM classroom WHERE expiry < NOW()

So say your table looked something like this:
CREATE TABLE IF NOT EXISTS sessions (
classroom_id int(10) unsigned NOT NULL AUTO_INCREMENT,
session_key varchar(60) NOT NULL,
duration tinyint(3) unsigned NOT NULL,
created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (classroom_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
and your duration was always in seconds, you could achieve what you want with a query like this:
SELECT classroom_id
FROM sessions
WHERE session_key = :key
AND (UNIX_TIMESTAMP(created) + (duration * 60)) > UNIX_TIMESTAMP(NOW());

Related

Change Login Status on Database after browser force closed or session expired

I have a user login data in MySQL, in condition user only can login 1 times in session. If using logout button, code are running well but if the user close the browser
// user_table in MySQL
user_id user_username user_password is_login
1 xyzabc xxxxx 0 // 0 is not
2 abcdef xxxxx 1 // 1 is login
3 efghij xxxxx 1
I used is_login for blocking access from 2nd login user. So, each account only can login once and is_login we used to kick user from logged in session on set is_login to 0.
// Inside my login function
public function login()
{
... some validation login code ...
// User ID accepted & login = TRUE
$this->session->set_userdata('id', $data->user_id);
// this query is in model, I just copy it to here
$this->db->query('UPDATE user_table SET is_login = "1" WHERE user_id = ".$id."');
$this->session->sess_expiration = 7200;
$this->session->sess_expire_on_close = TRUE;
}
// Logout function in controller
public function logout() {
$id = $this->session->userdata('id');
// this query is in model, I just copy it to here
$this->db->query('UPDATE user_table SET is_login = "0" WHERE user_id = ".$id."');
$this->session->sess_destroy();
}
If the user are logged out using logout function, the code are running well.
The is_login column will be set on 0 again. But if the browser force closed is_login status is still 1. Any solution ?
As indicated by #Tpojka change the is_login column to INT(11)
Add another column to your user table to shows the last user activity
Add a cronjob to SET is_login = 0 if the current system time and the last user activity is greater than expiration time
Whenever a user logs in, store time() value from php into DB
Store the same value of login time() into user session. so everytime that the user refresh a page you make check the value that you have in session with DB to understand that the user is the same or not. if not, logout the user and destroy the same. it might mean that the user is logged in from another device so he/she should be logged out from the current browser
every time that the user send a request and the is_login value matches the value that you have in DB, you may add and update another value in the user session. for example dte_last_activity then you can understand that if the session is expired or not for the user. don't rely on the session expiration time of the server as you might need a different expiration time.
Okay, let say that we have a user table like below:
CREATE TABLE IF NOT EXISTS `system_users` (
`id` smallint(5) unsigned NOT NULL,
`fullname` varchar(90) COLLATE utf8_persian_ci NOT NULL,
`username` varchar(40) COLLATE utf8_persian_ci NOT NULL,
`password` varchar(32) COLLATE utf8_persian_ci DEFAULT NULL,
`dte_login` int(11) unsigned NOT NULL DEFAULT '0',
`dte_activity` int(11) unsigned NOT NULL DEFAULT '0',
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci;
dte_login is timestamp value that we set into the database whenever a user log in
dte_activity is timestamp value for the last time that the user requested something from your server and off course he was log in
Note that dte_activity is only needed if you need to check that a user is still active or not.
function login($username, $password) {
$result = false;
// Check from DB that the username and password is valid or not
// IF user is valid, retrieve user_id from DB
If (USER_IS_VALID) {
$_SESSION['user_id'] = $user_id;
$_SESSION['dte_activity'] = time();
$_SESSION['dte_login'] = time();
$result = true;
}
return $result;
}
Okay now whenever the user ask to access a page you call a sample function like below:
function checkLogin() {
$result = false;
if (!empty($_SESSION['user_id'])) {
// This means that somebody is already logged in
$user_id = $_SESSION['user_id'];
$dte_login = $_SESION['dte_login'];
// We need to check if the user which is login is the same as the last user that used our website so we compare the dte_login value that we stored in session with what we have in DB
$db_connection->query("SELECT `id` FROM `system_users` WHERE `id`={$user_id} AND `dte_login`={$dte_login};");
// If the above query return no result, it means that someone else logged in meanwhile and we have to log out the current user
if ($db_connection->num_rows>0) {
// Now we need to check if his/her session is still valid or not
$EXPIERY = 300; // in seconds (in this case, 5 minutes)
$now = time();
if ($now-$_SESSION['dte_activity']<$EXPIERY) {
// The user session is still valid and we need to update database
$db_connection->query("UPDATE `system_users` SET `dte_activity`={$now} WHERE id={$user_id};");
$_SESSION['dte_activity'] = $now;
$result = true; // Means that someone is active
} else {
session_destroy();
}
} else {
session_destroy();
}
}
return $result;
}

How do I delete rows of data from mysql table automatically with 24 hours after data into table?

For example, i have a data input program And I want to delete my data automatically after 1 day of this data I input. how I do that?
Someone can explain in code?
Create.php these values are sent to the server
<form action="" method="post" enctype="multipart/form-data">
<input type="text" name="name_portofolio">
<textarea name="info_portofolio"></textarea>
<input type="file" accept="image/*" name="picture_portofolio">
<button type="submit" name="submit">Save</button>
</form>
function-add.php
<?php
function create_data($name_portofolio, $info_portofolio,
$picture_portofolio)
{
global $connect;
$name_portofolio = mysqli_real_escape_string($connect, $name_portofolio);
$info_portofolio = mysqli_real_escape_string($connect, $info_portofolio);
$filePath = "picture/".basename($picture_portofolio["name"]);
move_uploaded_file($picture_portofolio["tmp_name"], $filePath);
$query = "INSERT INTO portofolio
(name_portofolio, info_portofolio, picture_portofolio)
VALUES ('$name_portofolio', '$info_portofolio', '$filePath')";
if(mysqli_query($connect, $query))
{
return true;
}else{
return false;
}
} // create_data
db.php
<?php
$host = "127.0.0.1";
$user = "root";
$password = "";
$db = "wherco";
// create connection
$connect = new mysqli($host, $user, $password, $db);
// check connection
if($connect->connect_error) {
die("connection failed : " . $connect->connect_error);
} else {
// echo "Successfully Connected";
}
?>
thanks .
Try to use regular events. To get started, enable the Event Scheduler using
SET GLOBAL event_scheduler = ON;
After that you could crate event that will check rows creation time. For example
CREATE EVENT recycling ON SCHEDULE EVERY 1 HOUR ENABLE
DO
DELETE FROM MyTable WHERE `timestamp_column` < CURRENT_TIMESTAMP - INTERVAL 24 HOUR;
If there is no column with timestamp of a row creation in your table, then you can create trigger that will insert current timestamp and inserted row identificator to auxiliary table.
CREATE TRIGGER logCreator AFTER INSERT ON MainTable
FOR EACH ROW
INSERT INTO LogTable (MainID, Created) VALUES(NEW.id, CURRENT_TIMESTAMP);
Then you can use this log to get keys of main table that was created before specific time.
delimiter |
CREATE EVENT cleaner ON SCHEDULE EVERY 1 HOUR ENABLE
DO
BEGIN
DECLARE MaxTime TIMESTAMP;
SET MaxTime = CURRENT_TIMESTAMP - INTERVAL 24 HOUR;
DELETE FROM MainTable
WHERE id IN (SELECT MainID FROM LogTable WHERE Created < MaxTime);
DELETE FROM LogTable WHERE LogTable.Created < MaxTime;
END |
delimiter ;
In your table "portofolio" add column created_at(datetime).
Then in Cron Job, check the current datetime exceeds created_at(datetime) with 24hours and delete the records by mysql query like
DELETE FROM portofolio WHERE created_at<=DATE_SUB(NOW(), INTERVAL 1 DAY)
And run the cron job file every minute

Auto Creating a Table in SQL

I wonder if someone can help?
I am new to PHP and have started creating a membership based website as a project to try and learn some new PHP and I was wondering what the correct syntax would be to auto-create a table?
Here is my current code, I am looking to create an individual table for each user however upon trying and trying I can't seem to get it to work!
Any suggestions/corrections?
<?php
require("dbconnection.php");
if(empty($_SESSION['username'])) {
header("Location: index.php");
die("Redirecting to index.php");
}
$user = $_SESSION['username'];
$sql = "CREATE TABLE $user (id int(5) NOT NULL)";
$result = mysql_query($sql);
if(!$result) {
echo "FAILED";
}
echo "CREATED";
?>
The dbconnection.php file is working correctly as all my other pages call it in order to carry out other tasks.
DO NOT DO THAT !
Why not inserting a new row in a single table that hold all data of all the users ?
$sql = "INSERT INTO users (username) VALUES ('".$sql."')";
Based on my experience, It's highly not recommendable to create each table for each user because it's very expensive in terms of space and resources. If Facebook were doing the same thing, they would be having 1.1 billion tables on their database! Instead of that they have 1 table for all these members. Use one table, then keep a Primary Key column e.g. Id to be used to identify the person. e.g.
$sql = "CREATE TABLE IF NOT EXISTS users (
id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
names VARCHAR(100),
email VARCHAR(100),
password VARCHAR(200)
)";
mysql_query($sql) or die(mysql_error());
Then as user signs up, the id column auto increments, thus he/she will have a unique Id that you can use to trace him/her, like this;
$res = mysql_query("SELECT * FROM users WHERE id ='".$id."'") or die(mysql_error());
$data = mysql_fetch_assoc($res);
echo $data['names']." ".$data['email']; /* names, email, password ... etc */
This is much better. Rather than creating 1 million tables, you can just have 1 table for all the 1 million people.
Regards!

How to store Profile Views to show each user who's viewed their profile?

If we wanted to show each user which users of the opposite sex have viewed their profile, what would be the best way to keep track of all those views in MySQL?
Each user has a unique userid from the main Users table, which also stores their sex.
We would want to show each user the users that viewed them in order of most recent view to oldest view.
We would obviously not want to show the user themselves if they happened to view their own profile.
We would want to show guys only the girls that viewed them, and the girls only the guys that viewed them.
How would we setup the table of ProfileViews to do that?
What indexes would we use?
What would be the query we would need to show each user who has viewed them?
This is a simple example that I will make for you, hope this helps.
SQL:
CREATE TABLE user
(
user_id BIGINT NOT NULL AUTO_INCREMENT,
sex VARCHAR(10) NOT NULL,
CONSTRAINT PK_USER PRIMARY KEY (user_id)
) ENGINE=INNODB;
CREATE TABLE profileview
(
profileview_id BIGINT NOT NULL AUTO_INCREMENT,
user_id BIGINT NOT NULL,
visitor_user_id BIGINT NOT NULL,
date_time DATETIME NOT NULL,
CONSTRAINT PK_PROFILEVIEW PRIMARY KEY (profileview_id)
) ENGINE=INNODB;
ALTER TABLE profileview
ADD FOREIGN KEY FK_PROFILEVIEW_USER(user_id)
REFERENCES user (user_id);
ALTER TABLE profileview
ADD FOREIGN KEY FK_PROFILEVIEW_VISITOR(visitor_user_id)
REFERENCES user (user_id);
PHP:
This is a simple example of the user profile page - www.domain.com/profile.php?id=xxx.
At this point you need to define two variables in session when the user logs into the site:
$_SESSION['user_id'] (int) / $_SESSION['user_logged'] (boolean)
<?php
if ($_GET && isset($_GET['id']){
if(isset($_SESSION['user_id']){
$profile_user_id = $_GET['id'];
// the user that visits the profile has a session with his/her id on it.
session_start();
$visitor_user_id = $_SESSION['user_id'];
} else {
// if visitor specified an id but there is no session, redirect to login.
header("location: login.php");
}
} else {
// if no id passed redirect to index
header("location: index.php");
}
?>
<html>
<head>
<title>Your title</title>
</head>
<script src="scripts/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
//here you will store the visit with jquery.
$(document).ready(function(){
// store the values from php.
var profile_user_id = <?php echo $profile_user_id ?>;
var visitor_user_id = <?php echo $visitor_user_id ?>;
// here, the user information goes to the visit.php file.
$.post('visit.php' { profile_user_id:profile_user_id, visitor_user_id:visitor_user_id } );
});
</script>
<body>
Here print user information from a SQL select or something of the id passed in the GET.
</body>
</html>
Now, the visit.php file to store data:
<?php
if ($_POST && isset($_POST['profile_user_id']) && isset($_POST['visitor_user_id'])) {
session_start();
// this will end the execution of the script if there is no session from user logged
if ($_SESSION['user_logged'] != true) {
exit();
}
// everything is ok, do the process:
// functions.php contains your SQL connection, I suppose you know how to do it.
include('../cgi-bin/functions.php');
$link = dbconn();
$profile_user_id = mysql_real_escape_string($_POST['profile_user_id']);
$visitor_user_id = mysql_real_escape_string($_POST['visitor_user_id']);
// this will store the data in profileview including date and time if id's are not equal.
if($profile_user_id != $visitor_user_id){
$sql = "INSERT INTO profileview (user_id, visitor_user_id, date_time) VALUES ($profile_user_id, $visitor_user_id, NOW())";
mysql_query($sql, $link);
}
}
?>
EXTRA: if you don't know what functions.php do, here it is:
<?php
function dbconn() {
if(!include_once('db.php')) {
die('Error include file.');
}
if (!$link = mysql_connect($db['hostname'],$db['username'],$db['password'])) {
die('Error connecting.');
}
if (!mysql_select_db($db['database'])) {
die('Error selecting.');
}
return $link;
}
?>
The above file will need this file too: setup here your connection parameters to your db.
db.php
<?php
$db = array(
'hostname' => 'localhost',
'username' => 'root',
'password' => 'mysql',
'database' => 'mydb'
);
?>
I suggest you to put this in the cgi-bin folder of your hosting for better practices as you can see in visit.php file code.
Now, create another file called visitors.php?id=xxx and do a select * from of your profile views according to the user_id. At this point you will be able to:
Get the user_id information and if it is men (for example)...
Select visitors by sex and do a rule to list only female visitors.
List visitors according to the time stored in profileview table.
profileviews:
profile
userwhoviewed
timestamp
Index the profile column.
So when your user views the page, check if it's the profile owner, get the sex of the profile owner, check the sex of the viewer, if different, update the table with the viewer and the timestamp.
When querying the results, just select all rows matching the target profile, ordered by timestamp desc, and iterate to build your links back to those profiles.
I normally use INT data types in these fields (keeps the rows smaller and speeds up the lookups), then have a user table that generates those UID's as an auto_increment primary key. That will hold your gender and preference fields, too, as well as any other ancillary user data, and makes it easier to change login names, if desired.
But you're leaving out your gay users. Better to just log them all and let the user filter based on their preferences. :)
UsersTable
UserID Sex
1 Boy
2 Girl
3 Girl
UsersViewsTable
UserID View Unixtimestamp
1 2 342143243432
1 3 142143243432
2 3 242143243432
3 1 442143243432
When you visite the user profile, you'll use this :
IF CurrentUserSex != UserProfileSex
INSERT INTO UsersViewsTable (UserID, View, Unixtimestamp) VALUES (CurrentUser, CurrentProfileUserID, time)
Now, you want to fetch this on a page to see last seen from opposite sex ?
SELECT * FROM UsersViewsTable LEFT JOIN UsersTable USING (UserID) WHERE Sex != CurrentUserSex GROUP BY View ORDER BY Unixtimestamp DESC
EDIT :
IF CurrentUserSex != UserProfileSex {
$Res = SELECT CurrentProfileUserID FROM UsersViewsTable WHERE UserID = CurrentUserID AND View = UserProfileID LIMIT 1
if($Res['Count'] == 1){
// Exist
UPDATE UsersViewsTable SET Unixtimestamp = time WHERE UserID = CurrentUserID AND View = UserProfileID LIMIT 1
} elseĀ {
// Doesnt exist
INSERT INTO UsersViewsTable (UserID, View, Unixtimestamp) VALUES (CurrentUser, CurrentProfileUserID, time)
}
}
Just check n compare for each user profile page with the visitor id and profile id. If two are different store in a visit table with date and time and your required info. Before inserting just check the table row
if prof id, vistor id already exists then update the time else just insert the data.
Thanks.

Protect counter views In order not to be manipulated

I have this code :
$id = $_GET['id'];
mysql_query("UPDATE threads SET views = views + 1 WHERE id = '$id'");
but when I click refresh over and over the counter increases with each refresh.
How can I protect this counter from this with sessions or any other way?
You could set a session variable with (hasBeenCounted) and if that is set, you do not increment.
if(!isset($_SESSION['hasBeenCounted'])
{
$id = $_GET['id'];
mysql_query("UPDATE threads SET views = views + 1 WHERE id = '$id'");
$_SESSION['hasBeenCounted'] = "counted";
}
EDIT:
session_start():
will need to be at the very top of any page that you intend to use sessions on.
One way to do this is to use sessions. However, in the end, that's not really scalable. As a user moves through your site, you could potentially have a massive session file. Additionally, every time a user creates a new session, you will record that view anyway.
If you only want to record a single view for a single user, you need to store that that user viewed the thread. Depending on whether your site only allows logged in users to view threads, or if your site is open to the public, you'll have to store something unique about each user in a separate table, structured something like this (your mileage will vary on field types):
CREATE TABLE `thread_views` (
`id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`thread_id` INT( 10 ) UNSIGNED NOT NULL ,
`user_id` INT( 10 ) UNSIGNED NOT NULL ,
`ts` TIMESTAMP NOT NULL
)
Every time a user views the thread, you'll need to check this table. If there's no record in thread_views, insert one, and the increment the views column in your threads table. If there is a row in thread_views, then you know the user has already viewed the thread.
I think sessions with cookies are your best shot. You would probably want to set the cookie after the first visit, and then if the cookie is already set you don't update your view counter.
The syntax will be similar to this:
$expire=time()+2592000; //This is set to expire in 1 month (in seconds)
setcookie("visitor", "Already Visited", $expire);
This is how I would implement it:
if !(isset($_COOKIE["visitor"]))
{
$expire=time()+2592000; //This is set to expire in 1 month (in seconds)
setcookie("visitor", "Already Visited", $expire);
$id = $_GET['id'];
mysql_query("UPDATE threads SET views = views + 1 WHERE id = '$id'");
}
$id = $_GET['id'];
if(!isset($_SESSION['hasBeenCounted']) || $_SESSION['hasBeenCounted'] != $id)
{
mysql_query("UPDATE threads SET views = views + 1 WHERE id = '$id'");
$_SESSION['hasBeenCounted'] = $id;
}
I've modified the code and it works now.

Categories