I am trying to prevent a user from cancelling a booking if the booking is less than 2 days away. I tried doing this by getting the current date and the date of the booking, converting them both to strtotime and then checking if one value was greater than the other. However when I run my code though all it does is redirect to page which only displays the value of $diff
Here is my code
<?php
$customerRef = $_SESSION['customerRef'];
$messageCancelError;
$messageSuccess;
if (isset($_POST['Cancel']))
{
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$cancelAppointment = $_POST['cancel'];
//echo $cancelAppointment;
$sql4 = "SELECT dateOfBooking FROM booking WHERE bookingRef=? AND customerRef=?";
// initalise the prepared statement
$stmt4 = mysqli_stmt_init($conn);
// prepare the prepared statement
if (mysqli_stmt_prepare($stmt4, $sql4))
{
// bind values to the prepared statement
mysqli_stmt_bind_param($stmt4, "ss", $cancelAppointment, $customerRef);
// execute the prepared statement
mysqli_stmt_execute($stmt4);
// store the results of the prepared statement
mysqli_stmt_store_result($stmt4);
// bind the results of the prepared statement to variables
mysqli_stmt_bind_result($stmt4, $appointmentDate);
mysqli_stmt_fetch($stmt4);
//echo mysqli_stmt_error($stmt4);
//gets the current date in y-m-d format
$date = date('Y-m-d'); //gets the difference in todays date and the date of an appointment in seconds
$diff = abs(strtotime($date) - strtotime($appointmentDate)); echo $diff;
}
$stmt4->close();
}
$stmt4->close();
//172800 seconds in 2 days
if ($diff > 172800)
{
// checking for customer ref as well to prevent a user cancelling another users booking
$sql3 = "DELETE FROM booking WHERE bookingRef =? AND customerRef =?";
$stmt3 = mysqli_stmt_init($conn);
if (mysqli_stmt_prepare($stmt3, $sql3))
{
mysqli_stmt_bind_param($stmt3, "si", $cancelAppointment, $customerRef);
mysqli_stmt_execute($stmt3);
mysqli_stmt_store_result($stmt3);
// echo mysqli_stmt_error($stmt3);
}
if (mysqli_stmt_affected_rows($stmt3) === 1)
{
$messageSuccess = "Booking Cancelled";
}
else
{
$messageCancelError = "Couldn't cancel your booking, check your booking ref against existing ones ";
}
}
// Close statement
$stmt3->close();
// Close connection
// $conn->close();
}
I have tried changing it to this but the error is still happening
if ($diff > 172800) {
// checking for customer ref as well to prevent a user cancelling another users booking
$sql3 = "DELETE FROM booking WHERE bookingRef =? AND customerRef =?";
$stmt3 = mysqli_stmt_init($conn);
if (mysqli_stmt_prepare($stmt3, $sql3)) {
mysqli_stmt_bind_param($stmt3, "si", $cancelAppointment, $customerRef);
mysqli_stmt_execute($stmt3);
mysqli_stmt_store_result($stmt3);
// echo mysqli_stmt_error($stmt3);
if (mysqli_stmt_affected_rows($stmt3) === 1) {
$messageSuccess = "Booking Cancelled";
}//affected rows
}//stmt_prepare
}//$diff
else {
$messageCancelError = "Couldn't cancel your booking, check your booking ref against existing ones ";
}
Your if block needs to change.
Change:
//172800 seconds in 2 days
if ($diff > 172800)
{
...
if (mysqli_stmt_affected_rows($stmt3) === 1)
{
$messageSuccess = "Booking Cancelled";
}
else
{
$messageCancelError = "Couldn't cancel your booking, check your booking ref against existing ones ";
}
}
// Close statement
To:
//172800 seconds in 2 days
if ($diff > 172800)
{
...
if (mysqli_stmt_affected_rows($stmt3) === 1)
{
$messageSuccess = "Booking Cancelled";
}
}
else
{
$messageCancelError = "Couldn't cancel your booking, check your booking ref against existing ones ";
}
// Close statement
Related
I have a scheduling system
I have a query to create a error if the date and time has already been scheduled
my problem is i have multiple room and if i create a schedule in one room if it is the same with the other room it wont add
function save_schedule(){
extract($_POST);
$data = "";
foreach($_POST as $k=> $v){
if($k != 'id'){
if(!empty($data)) $data.=", ";
$data.=" {$k} = '{$v}'";
}
}
if(strtotime($datetime_end) < strtotime($datetime_start)){
$resp['status'] = 'failed';
$resp['err_msg'] = "Date and Time Schedule is Invalid.";
}else{
$d_start = strtotime($datetime_start);
$d_end = strtotime($datetime_end);
$chk = $this->conn->query("SELECT * FROM `schedule_list` where (('{$d_start}'
Between unix_timestamp(datetime_start) and unix_timestamp(datetime_end)) or ('{$d_end}'
Between unix_timestamp(datetime_start) and unix_timestamp(datetime_end))) ".(($id > 0) ? "
and id !='{$id}' " : ""))->num_rows;
if($chk > 0){
$resp['status'] = 'failed';
$resp['err_msg'] = "The schedule is conflict with other schedules.";
}else{
if(empty($id)){
$sql = "INSERT INTO `schedule_list` set {$data}";
}else{
$sql = "UPDATE `schedule_list` set {$data} where id = '{$id}'";
}
$save = $this->conn->query($sql);
if($save){
$resp['status'] = 'success';
$this->settings->set_flashdata('success', " Schedule successfully saved.");
}else{
$resp['status'] = 'failed';
$resp['sql'] = $sql;
$resp['qry_error'] = $this->conn->error;
$resp['err_msg'] = "There's an error while submitting the data.";
}
}
}
return json_encode($resp);
}
can anyone help me in this query
$chk = $this->conn->query("SELECT * FROM `schedule_list` where (('{$d_start}'
Between unix_timestamp(datetime_start) and unix_timestamp(datetime_end)) or ('{$d_end}'
Between unix_timestamp(datetime_start) and unix_timestamp(datetime_end))) ".(($id > 0) ? "
and id !='{$id}' " : ""))->num_rows;
assembly_hall table
schedule_list table
Aside from the SQL injection problems, I see a couple of issues:
Your query should be only looking for conflicts for the assembly_hall_id it will be inserting; as is, it looks for conflicting schedules for any assembly hall.
Your conflict check is incorrect; if a hall is reserved for 1pm-2pm and someone tries to reserve it for 12pm-3pm, you don't detect it, because neither the new start nor end is in the reserved range. Correct conflict checking is done with:
least(datetime_end, new end value) > greatest(datetime_start, new start value)
I am just wondering if we need to have the !isset function for email activation because we are not really filling out a form to check if the user has submitted the form or not but a link instead. I read somewhere that email activation can fail and one should also allow the user to activate their account manually but the following code should work but sometimes I do get the missing link error. However, all the variables are shown in my url though:
<?php
include_once __DIR__.'/header2.php';
if($_SESSION['u_uid']) {
echo "<meta http-equiv='refresh' content='0;url=../index.php?activatelevel2promo=mustloggedoutfirst'>";
exit();
} else {
if (!isset($_GET['email']) || !isset($_GET['activatetoken']) || !isset($_GET['duration'])) {
echo "<meta http-equiv='refresh' content='0;url=../index.php?activatelevel2promo=missinglink'>";
exit();
} else {
include_once __DIR__.'/dbh.php';
// retrieve the email and token from url
$activate = 0;
$email = strip_tags($_GET['email']);
$token = strip_tags($_GET['activatetoken']);
$duration = strip_tags($_GET['duration']);
$sql = "SELECT * FROM memberships WHERE user_email = ? AND token2 = ? AND activate2 = ?;";
$stmt = mysqli_stmt_init($conn);
//Prepare the prepared stement
if (!mysqli_stmt_prepare($stmt, $sql)) {
echo "SQL statement failed";
} else {
//Bind parameters to the placeholder
mysqli_stmt_bind_param($stmt, "ssi", $email, $token, $activate);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$resultCheck = mysqli_num_rows($result);
if ($resultCheck > 0) {
$subscriptionplandate = date("Y-m-d H:i:s");
$level2promo_activate = 1;
if($duration == '1week') {
$expirydate = date('Y-m-d H:i:s', strtotime("+1 week"));
}
if($duration == '2weeks') {
$expirydate = date('Y-m-d H:i:s', strtotime("+2 week"));
}
if($duration == '3weeks') {
$expirydate = date('Y-m-d H:i:s', strtotime("+3 week"));
}
if($duration == '4weeks') {
$expirydate = date('Y-m-d H:i:s', strtotime("+1 month"));
}
$token = null;
$sql2 = "UPDATE memberships
SET subscriptionplandate2 = ?, expirydate2 = ?, token2 = ?, level2promo_activate = ?
WHERE user_email = ?;
";
$stmt = mysqli_stmt_init($conn);
//Prepare the prepared stement
if (!mysqli_stmt_prepare($stmt, $sql2)) {
echo "SQL statement failed";
} else {
//Bind parameters to the placeholder
mysqli_stmt_bind_param($stmt, "sssis", $subscriptionplandate, $expirydate, $token, $level2promo_activate, $email);
mysqli_stmt_execute($stmt);
echo "<meta http-equiv='refresh' content='0;url=../index.php?activatelevel2promo=success'>";
exit();
}
}
}
}
}
This is what is been shown in the url:
https://www.pianocourse101.com/includes/activatelevel2promo.php?email=pianoforte0011#gmail.com&activatetoken=%5E#%rG%5EGTq#&duration=2weeks
because we are not really filling out a form to check if the user has submitted the form or not but a link instead
That doesn’t matter. Same as I could not fill out or remove a form field named foo, I could also remove a parameter ?bar=... from any URL before I call it - the result would be the same, a parameter your script is expecting, resp. needs to be able to properly perform its task, isn’t there. So yes, checking whether you got all the data you need, makes sense in both cases.
but the following code should work but sometimes I do get the missing link error. However, all the variables are shown in my url though
Yeah, well …
…?email=pianoforte0011#gmail.com&activatetoken=%5E#%rG%5EGTq#&duration=2weeks
What you have here, is one parameter with the name email and the value pianoforte0011#gmail.com, and one parameter named activatetoken with the value %5E, or ^ after URL decoding … and that’s it.
The rest of that URL is just the fragment identifier or “hash” - and that does not even get send to the server in the first place.
You neglected to properly URL-encode your parameter values here. The # is not supposed to have its special meaning here, so it needs to be encoded (%23)
You should either apply urlencode to all parameter values individually; or collect all your parameters and values in an array first, and then use http_build_query - that will do the complete job of creating the whole query string for you, and it takes care of the necessary encoding automatically while doing so.
http://php.net/manual/en/function.urlencode.php
http://php.net/manual/en/function.http-build-query.php
I'm making a simple timeclock system that allows employees to log their working hours.
I have a table that stores the timestamps and weather it was a clock-in or clock-out action. Depending on the last action for a given user, the opposite options are presented. For example, if the last action was clock-out then the presented action should be clock-in.
In a scenario where the user has not used the system before they should be presented with an option to clock-in.
$sql_status = "SELECT * FROM timeclock WHERE employeeid = $employee_number ORDER BY id DESC LIMIT 1";
if ($result=$mysqli->query($sql_status)) {
while ($row = $result->fetch_row()){
$timeclock_action = $row[2];
$timeclock_timestamp = $row[3];
if($timeclock_action=="out") {
$forward_action = "clockin";
$forward_action_label = "Clock in";
$timeclock_status_label = "Last clock out: ";
} elseif($timeclock_action=="in") {
$forward_action = "clockout";
$forward_action_label = "Clock out";
$timeclock_status_label = "Clocked in: ";
}
}
} elseif(mysql_num_rows($result)==0) {
$forward_action = "clockin";
$forward_action_label = "Clock in";
$timeclock_status_label = "You've never clocked in before";
} else {
echo "Error: " . $sql . "<br>" . $mysqli->error;
}
My thought process is that elseif mysql query returns 0 rows, the variables would be set accordingly, but they don't get set at all.
Where am I wrong in my thinking? Thanks!
Your current logic is that if the query failed - that is when the query returned false (not that it didn't return any results, but that the execution altogether failed), you check if the number of rows returned was zero.
Instead, you should execute the query first, then check if there were any rows returned. You also don't need to loop for multiple rows, as you only expect one row with LIMIT 1 in the query.
You should also look into using a prepared statement instead of injecting variables directly in the query, and doing some other error-handling; as errors should never be displayed directly to the user (log the errors, and display a generic "Something went wrong" message).
// The query to be executed
$sql_status = "SELECT * FROM timeclock WHERE employeeid = $employee_number ORDER BY id DESC LIMIT 1";
// See if the query was successful or not
if ($result = $mysqli->query($sql_status)) {
// If there are any rows returned
if ($result->num_rows) {
// Fetch rows - no need for a loop since you only expect one record (LIMIT 1 in the query)
$row = $result->fetch_row();
$timeclock_action = $row[2];
$timeclock_timestamp = $row[3];
if ($timeclock_action=="out") {
$forward_action = "clockin";
$forward_action_label = "Clock in";
$timeclock_status_label = "Last clock out: ";
} elseif ($timeclock_action=="in") {
$forward_action = "clockout";
$forward_action_label = "Clock out";
$timeclock_status_label = "Clocked in: ";
}
} else {
$forward_action = "clockin";
$forward_action_label = "Clock in";
$timeclock_status_label = "You've never clocked in before";
}
} else {
// The query failed
echo "Error: " . $sql . "<br>" . $mysqli->error;
}
I am using a simple script at the top of every page that will update a LastActive column in the database:
$username = $_SESSION['username'];
$userID = $_SESSION['user_id'];
if(isset($username, $userID)) {
if ($insert_stmt = $mysqli->prepare("UPDATE Users SET lastActive = DATE_ADD(Now(), interval 6 hour) WHERE username = ?")) {
$insert_stmt->bind_param('s', $username);
// Execute the prepared query.
if (! $insert_stmt->execute()) {
$insert_stmt->close();
header('Location: ../headers/error.php?err=Failed Upload');
}
}
$insert_stmt->close();
}
I always want to keep performance and security in mind. Would this lead to poor performance in the future with 000's of connections?
How does using cookies (not that I know how) differ from a simple script like this?
Thanks
edit:
$username = $_SESSION['username'];
$userID = $_SESSION['user_id'];
$loginTime = $_SESSION['timestamp'];
date_default_timezone_set("Europe/London");
$now = new DateTime();
$diff=$now->diff($loginTime);
$minutes = $diff->format(%i);
if(isset($username, $userID) && $minutes> 30) {
$_SESSION['timestamp'] = $now;
$online = true;
}
Couple of suggestions:
You could do this via AJAX, so that the LastVisited is updated asynchronously after the user's page loads. That way, there won't be any impact to the page load time for the user.
If, for any reason, your SQL query fails, you should fail silently. Since recording Last Visited is not business critical, you should not redirect the user to an error page. Maybe just log an error, and set up an alert so if there are multiple failures, you get alerted and can take a look at it.
All that you made with cookies will be data supplied by your users, then you cannot trust it.
In other hand, if you work with cookies, all of them will travel in each request header.
You should do it in server side and yes, a database is not performant.
You can try to persist this information with something like Redis, a in-memory data structure store, used as database, cache and message broker.
I thought I'd post the way I got around this for any one else looking for a User Online type method. Of course this might have been done much better but works in my situation.
I am using both database entries and session to test if a user is online.
On user login I update a column in my users table with a Now() timestamp and add this to their session data.
At the top of each page I am running a script to check if the user is logged in and get their timestamp from session data. if this data is 45 minutes old, the script will update the table setting the lastActive column of my users table to Now();
<?php
include_once 'functions.php';
if(isset($_SESSION['username'], $_SESSION['user_id'], $_SESSION['lastActive'])) {
date_default_timezone_set("Europe/London");
$now = new DateTime();
$lastActive = $_SESSION['lastActive'];
$diff=$now->diff($lastActive);
$hours = $diff->format('%h');
$mins = $diff->format('%i');
$day = $diff->format('%d');
$month = $diff->format('%m');
$year = $diff->format('%y');
if($mins > 45 || $hours >= 1 || $day >= 1 || $month >= 1 || $year >= 1) {
$_SESSION['lastActive'] = $now;
set_last_active($mysqli, $_SESSION['username']);
}
}
set_latst_action is simply just:
function set_last_active($mysqli, $username) {
if ($stmt = $mysqli->prepare("UPDATE Users SET lastActive = Now() WHERE username = ?")) {
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->close();
}
}
then when I want to see if a user is online for example on a profile page I call isOnline();
function isOnline($mysqli, $username) {
if ($stmt = $mysqli->prepare("SELECT lastActive FROM Users WHERE username = ? LIMIT 1")) {
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
$stmt->bind_result($return);
$stmt->fetch();
$lastActive = $return;
} else {
// user does not exist
$lastActive = "";
return $lastActive;
$stmt->close();
}
} else {
// SELECT failed
$lastActive = "";
return $lastActive;
$stmt->close();
}
if (!empty($lastActive)) {
date_default_timezone_set("Europe/London");
$dateNow = new DateTime;
$lastActiveDate = new DateTime($lastActive);
$diff=$dateNow->diff($lastActiveDate);
$hours = $diff->format('%h');
$mins = $diff->format('%i');
$day = $diff->format('%d');
$month = $diff->format('%m');
$year = $diff->format('%y');
if ($mins > 45 || $hours >= 1 || $days >= 1 || $month >= 1 || $year >= 1) {
$return = "Offline";
return $return;
}
else {
$return = "Online";
return $return;
}
}
else {
$return = "Offline";
return $return;
}
}
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
$serv_id = $_POST['serv_id'];
$time = $_POST["time"];
$date = $_POST["date"];
if (!isset($_SESSION['id']))
{
echo "sorry you're not logged in.";
exit();
}
if(date('w', strtotime($date)) == 6 || date('w', strtotime($date)) == 0)
{
echo 'Event is on a weekend and cannot be booked.';
}
else
{
echo 'Thank for you booking with Claires hair and beauty';
$time = $time. ":00:00";
$result = mysqli_query($con, "SELECT time FROM tbl_booking WHERE time = '$time' AND date = '$date'") or trigger_error("Query Failed! SQL: $result - Error: ".mysqli_error($con), E_USER_ERROR);
}
if(mysqli_num_rows($result) == 0)
{
$sql = "INSERT INTO tbl_booking (tbl_mem_id, serv_id, date, time) VALUES ('{$_SESSION['id']}','$serv_id','$date','$time')";
mysqli_query($con, $sql) or die('Error: ' . mysqli_error($con));
location: 'dashboard.php';
}
else
{
echo("this time is already booked");
}
}
Essentially I'm trying to make it check if they're logged in by checking a session variable, then check if the date they have entered is a weekend and then if the date/time being entered is already taken as if it is it just needs to echo this time is already booked.
But what is happening is when the slot is already taken? It echos
Thank for you booking with Claires hair and beautythis time is already booked
Try This Code:
if(date('w', strtotime($date)) == 6 || date('w', strtotime($date)) == 0)
{
echo 'Event is on a weekend and cannot be booked.';
}
else
{
$time = $time. ":00:00";
$result = mysqli_query($con, "SELECT time FROM tbl_booking WHERE time = '$time' AND date = '$date'") or trigger_error("Query Failed! SQL: $result - Error: ".mysqli_error($con), E_USER_ERROR);
}
if(mysqli_num_rows($result) == 0)
{
$sql = "INSERT INTO tbl_booking (tbl_mem_id, serv_id, date, time) VALUES ('{$_SESSION['id']}','$serv_id','$date','$time')";
mysqli_query($con, $sql) or die('Error: ' . mysqli_error($con));
echo 'Thank for you booking with Claires hair and beauty';//this is right place
location: 'dashboard.php';// Don't know what you trying to do here
}
else
{
echo("this time is already booked");
}
If you want to redirect to another page in php use this:
header('Location: yourpage.php');
PHP Header Function