Comparing current DateTime to a value in MySQL - php

I've been trying to add in an expiry for password reset requests.
When the user requests a password request at the moment, it stores an expiration date in the database as NOW() + INTERVAL 2 DAY - so exactly 2 days from now.
When the user comes back to the page by following their reset link, it checks the reset key exists and then runs a series of if statements, one of which I want to test whether the current DateTime is greater than that of which is in the database and if it is then display an error message.
I've tried a raft of ways as most tend to suggest using SQL to evaluate this. The most recent and most popular from what I've found was to do the following:
"SELECT *, DATE(`Expiration`) > DATE(NOW()) AS is_current FROM password_reset WHERE Reset_link='$key'"
This way you could then feed the results in to a variable and test it in the if statement as is_current would either be 0 or 1, i.e:
if ($result_check_row['is_current']){
echo '<div class="warning">Your password reset request has now expired. Please request a new one by completing the form again.''</div>';
}
I haven't had any luck with this, or any of the other things I've tried which include creating a timestamp via PHP to test against this.
Can anyone see where I am going wrong or suggest a good alternative?

try this query, it will produce date difference between current date and expiry date...
SELECT DATEDIFF(DATE(`Expiration`), DATE(NOW())) AS DiffDate FROM password_reset WHERE Reset_link='$key'"

Related

PHP Foreach Loop Query

I've been tinkering with PHP lately (self-taught, no formal training), trying to understand how to grab data from a database and display the data somewhere. So far I have learned quite a bit, but now I am stumped.
I have a list of about 200 users in my local database in a table called site_members. The table has three fields: id, name, birth_date. Via PHP, I want to display all the users on a webpage, and have something like "Birthday soon!" be mentioned right after their name. Something like this:
John Smith (Birthday soon!)
I haven't written the code to do this, because I usually write pseudocode first before actually diving into the coding part. Here's the pseudocode:
Get the current date and time and convert it to Unix timestamp
Start foreach loop and go through list of users
Query the database table, get the birthdate of a user by their id, and store it in a variable named bdate.
Convert bdate to Unix timestamp
Subtract the current date from bdate, convert it into days remaining, and store it in a variable called remaining_days.
If the user's bdate is within 15 days (remaining_days is less than 15)
Display their name, followed by (Birthday soon!)
otherwise
Just display their name only
End if
End foreach loop
Here's my problem: With the above pseudocode once translated into actual code, there would be a database query made every time in that foreach loop. Some of the tutorials I consulted mentioned I should avoid that for efficiency reasons, and it makes sense. I ran Google searches to find something similar, but that didn't do much. I do not want anyone to write any actual code for me. I just want a better solution to the querying.
Thanks in advance!
I think your concept for the pseudo code is right, and you're understanding of doing multiple database queries is also right, you just tangled the two into giving you a wrong idea.
If you construct your select statement properly (that's basically what you'd be using to access the database), you actually pull the information for everyone out of the database and store it once in an array (or some other form of object). You can then start your foreach loop using the array as your value and perform the rest of your checks that way.
$date = date("m.d.y");
$people = ** insert your commands to grab the info from the DB **
foreach($people as $person) {
// do your comparison checks and echo's etc in here
}
Does this make sense?
There can be two solutions to your problem:-
1:
Instead of making query for every user, first get the data for all the users.
Traverse the data using foreach loop php
Do the processing and display the results.
2:
Store the user date_of_birth in proper mysql date datatype
Change your mysql query to use date function to get all the users who match your date difference criteria and just display those users.
It seems you failed to read up properly on the relationship between SQL and PHP. If you actually posted code, then you could have been easily unstumped because there are many ways to do the simple task from legacy tutorials to current PDO or even MVC within in 5mins or less.
I'm not going to write the code but you need to change HOW you think in your "pseudo code".
The problem with your pseudo code is because you believe that the DB is not smart and you are doing it as if it was only for storage.
The correct pattern for PHP is the following:
1) use the Date function to retrieve current day + 15. Get month and
day only.
2) you make a SQL query that retrieve all users who's
birth_date field's month and day are GREATER THAN (or equal) to
TODAY and who are less than or equal to today + 15 (day and month
only)
3) execute the query.
4) with the returned data set (if any)
you can choose two path depending situation and design
a) you can loop it with a simple FETCH which fetch each row retrieve
and display name and extra message.
or
b) iterates through the result set and store the display message
into a variable and then finally display it once the iteration is
done.
(option b is prefered because its more flexible since you can use this technique to out into a file instead of an echo)
THIS pseudo-code ensures that you are only retrieve the correct data set with the aid of the SQL system (or storage system).
In terms of overall process, aashnisshah is absolutely correct. First, you should retrieve all the records you need from your database then loop through each row to do your data comparisons and finally close the loop.
As for finding out if their birthday is close and if you want MySQL to do the hard work, you can build your query like that in PHP:
$query = "SELECT *, DATEDIFF(DATE_FORMAT(dob, '" . date('Y') . "-%m-%d'), CURDATE()) AS days_to_dob FROM Members";
The idea is to fetch an extra column called 'days_to_dob' containing the amount of days until that person's date of birth. Note that it will be negative if that date has passed for this year. With that extra column you can easily evaluate whether their dob is within 15 days.
If you don't want any php code, then here is my pseudocode:
Get date and time -> UTC stamp and store in $time_current
Get all from site_members and store in $data
for each entry in $data, store in $record
get birth_date from $record and convert to utc stamp and store in $birthday
print name from $record
if $birthday is close to $time_current then print "Birthday soon" end if
print new line
end for
That performs only one request to your database.

How to execute a PDO query with a condition based on calculation

I work on a site where visitors can create an account, and to do so, they have to confirm their email adresses in the end of the process.
Before the account is created, the entered values such as email, pass etcetc are kept in a special table temporarily. That means a visitor has an hour to open their email and klick the link, or else that row will be deleted, to prevent "garbage" from bots and evil or simply overlazy people.
My idea was to let the users clean up the mess, and this is how: when a user klick the link sent to them, the row in the table with temporarily stored values is moved to the actual table for members, and another function will clean up rows that are "outdated", that is, who are inserted more than one hour ago.
This is my current code:
$stmt3 = $dbc->prepare('DELETE FROM temp_storage WHERE time() - time > 3600');
$stmt3->execute();
(time is the column with the time when the row was inserted is stored)
However this code is appareantly not working. I know I could do a workaround with SELECT FROM temp_storage and then check if the row is inserted too long ago, but I thought that, why would it be impossible to do it this way?
Now my question is, is it, or am I doing it the wrong way?
TIME() in MySQL does not give you the current time, it strips the "time portion" from a timestamp. You are looking for a different time function, probably UNIX_TIMESTAMP() if that is how you are storing your timestamps in the table.
Review MySQL date and time functions here: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
The function you're using to get the current time is not correct. It's not time() it's now().
If you check what $pdo->errorInfo() returns you'll see an error message.
In light of your comments about echo time() i get what you wanted to do but in order for that to work you should have written the following:
$stmt3 = $dbc->prepare('DELETE FROM temp_storage WHERE '.time().' - time > 3600');
$stmt3->execute();
By doing this you're using the return value of PHP's time() function to build a string which will then be sent to MySQL to be executed as a query.
You have to understand the difference between PHP-realm and SQL-realm code:
PHP only constructs text strings. It patches together various words an letters to compose a string. PHP doesn't even care what that string is for.
PHP can never look into that string and say "hey this is some good SQL queries right here".
What it can do is send the text you composed to an SQL server; the sql server will try and execute the text as if if were a corect SQL language statement.
If it hits errors it'll report them back to PHP if not it returns the results to PHP. In any case the SQL statements are strings and they get composed before being actually sent to the server.
"Interrupting" a string and concatenating another string to it such as "me"."&"."you" is just part of the process of building the string before sending it to the SQL server.
Try this:
$stmt3 = $dbc->prepare('DELETE FROM temp_storage WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(time) > 3600');
I assume the entry_dt column is a datetime column.
where CURRENT_TIMESTAMP - interval 1 HOUR > entry_dt
You should avoid naming columns the same as sql functions and keywords
ref
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html

Online or offline function PHP

I'm working on a "community". And of course I would like to be able to tell if a user is online or offline.
I've created so that when you log in a row in my table UPDATE's to 1 (default is 0) and then they're online. And when they log out they're offline. But if they don't press the Log out button, they will be online until they press that button.
So what I would like to create is:
After 5 minutes of inactivity the row in my database should UPDATE to 0.
What I'm looking for is how to do this the easiest way. Should I make an mysql_query which UPDATE's the row to 1 every time a page is loaded. Or is there another way to do it?
Instead of using a boolean "Online" field, use a DateTime. When a user makes a request to the page, update the DateTime to NOW(). When you are gathering your list of current users online, your WHERE clause would be something like WHERE lastSeen > DATE_SUB(NOW(), INTERVAL 5 Minutes)
Update: To retrieve individual online status.
select if(lastSeen > date_sub(now(), interval 15 minutes), 1, 0) as status from table where userid=$userid
This tutorial is quite handy: Who Is Online Widget With PHP, MySQL & jQuery
Well, if you don't want to set up a cron job, that would execute some code every 5 minutes, you have no options. But, actually, I think the following approach would be much more efficient:
Change your 1/0 column to timestamp
On each user request update that timestamp to current DateTime.
When checking for active users, check if that timestamp is less than 5 minutes from now
This way you'll be having actual data on users and no recurring queries - just one additional update per request
If you will update the row only on page load, then some of information would be incorrect.
Let's assume that user have opened page and is writing really long text or something. He is doing it for half an hour now. And your database ny now is already updated and he is counted as offline user.
I would write javascript that pings you back each 5 minutes, if opened tab is active.
This ping updates database field 'last_activity' to NOW(). And to count online users, or check if user is online you'll need to compare 'last_activity' to NOW() minus five minutes.
Simpliest ways (IMHO):
You can count sessions in session_save_path() dir.
you can store last visit timestamp in DB, and count rows with (timestamp > current_timestamp - somedelay).

Getting SQLSTATE[HY000]: General error but query is performed anyway

I'm making a system to save users' IPs into a table along with the last time they posted something.
First, I check for an already-existent record of the user's IP with
SELECT lastpost FROM users WHERE ip = '$IP'
I then check whether the result of that query is empty, and if it is it means that the user's IP is not present and it should be recorded, so I proceed by doing this query:
INSERT INTO users (ip, lastpost) VALUES ('$IP', '$ctime')
Where $IP is the user's IP fetched using $_SERVER['REMOTE_ADDR'] and $ctime is a time string created using date("Y-m-j H:i:s").
Even though after performing the latter query the data is present into the table, I keep getting the error
SQLSTATE[HY000]: General error
Which is, by itself, not very helpful. I'd like to understand what I'm doing wrong here. Thanks in advance.
P.S.: I'll use this question to also ask how I could compare, using a query, the time I have calculated with PHP's date() with the time already present in the table (of type "datetime") to see if the one calculated with date() is greater than the one in the database by at least one minute.
I would first try to cast $ctime as a datetime CAST('$ctime' AS DATETIME) to see if that works.
For testing minute difference use TIMEDIFF().
SELECT IF(TIMEDIFF(CAST('$ctime' AS DATETIME), lastpost) > CAST('00:01:00.000000' AS DATETIME), /*do this*/, /*else do this*/)
This will return a time difference. If the time difference is negative, $ctime is earlier than lastpost. But you can get into pretty fine granularity here.
See if the above helps.
(Oh, I found all of this via Google and searching for mysql and datediff, timediff, or cast.)

I want to hide the details of record (of database) from user when date will be expired using php

I'm totally new to php & mysql,
When I'm creating one trial application using php ,there is problem specify below,
I want to hide the details of record (of database) from user when date will be expired using php ,
When one user logedin & create one record entry that time automatically current date is also entered in database, but I want to give 1 week expiry date, after that the record will be not shown to the front end but it available in database. When the creator of this record renew this recod that time automatically date should be updated at current date, & same record will be shown as new entry
PLz help me,
I'm waiting for ur answer,
Thanks in advance.
What kind of column is the date one? Timestamp? or timedate?
Either way, you can do it like so (depending on your column type)
For timedate:
WHERE (date + INTERVAL 1 WEEK) < CURDATE()
For timestamp:
WHERE (timestamp + 604800) < UNIX_TIMESTAMP()
Let me know what you are using for your date column and I can update. You can also see the MySQL date functions here.

Categories