When I update from PHP code my DB table based on any column name(id, username, whatever) - everything goes well. But if I try to update it based on an IP - it fails.
I store the IP as varchar(39) and using MySQL.
Perhaps someone here would know why is it can't access(update) it based on IP?
Thanks
Update:
The schema of the table is very simple, it contains:
|id|userid|username|ip|date
The code is coming from class to class... I tried to use it as best as I could with OOP with lots of helpers. But the main point is that it works great, but not with the IPs...
By googling I found out ip2long function, so it's probably something related to the issue.
Update 2:
+----------+-------------+------+-----+
| Field | Type | Null | Key |
+----------+-------------+------+-----+
| id | int(11) | NO | PRI |
| userid | int(11) | NO | |
| username | varchar(20) | NO | |
| ip | varchar(39) | NO | |
| date | datetime | NO | |
+----------+-------------+------+-----+-
Made it by hand :) No idea what should be the datetime exactly
I'm trying to create a system which keeps the user logged in (something like remember me checked). Ok I have a table like this:
// cookies
+---------+-------------------------+------------------+------------+------------+
| id | email | cookie | date_time | device |
+---------+-------------------------+------------------+------------+------------+
| int(11) | varchar(50) | varchar(128) | int(11) | |
+---------+-------------------------+------------------+------------+------------+
| 1 | jack_2009#gmail.com | ojer0f934mf2... | 1467204523 | |
| 2 | peter.zm#yahoo.com | ko4398f43043... | 1467205521 | |
| 3 | matrix_john23#gmail.com | 34fjkg3j438t... | 1467205601 | |
| 4 | peter.zm#yahoo.com | 0243hfd348i4... | 1467206039 | |
+---------+-------------------------+------------------+------------+------------+
As you see, this user peter.zm#yahoo.com have logged in by two different devices:
| 2 | peter.zm#yahoo.com | ko4398f43043... | 1467205521 | |
| 4 | peter.zm#yahoo.com | 0243hfd348i4... | 1467206039 | |
So email column isn't unique and each device has its own row.
My question: How can I fill device column?
Why do I need to determine devices? Because when an user removes his browser's cookies, then my website identifies him as a new user and creates a new row for him into table above. So after a while, there will be some redundant rows in the table.
For example: Imagine peter has just two devices (laptop, phone). And he have two rows into table above. Ok, he removes his browser's cookies and logs in. What happens? My website creates a new row into table above. Now peter has 3 rows into table above (while he has just two devices). So surely one of those three rows is redundant. That's why I need to detect devices to remove redundant rows.
How about with the User Agent string from their last interaction with your application?
As an additional defence-in-depth security measure, you could also validate that the user agent matches their previously used one for this device in order to mitigate session hijacking. Be aware that any browser or OS upgrades will invalidate the "remember-me" on that device though.
As a side note, you are better off keying on a unique ID rather than email address because that way it is much easier to update a user's email should you need to in future.
Use the web authn api or the credentials api
I have created a privilege system for my application which allows/disallows access to specific pages based on user input.
The table looks something like this:
page_id | client_id | sys_group_no | name | friendly_name | viewable |
1 | 4 | 1 | home | Home | true |
2 | 4 | 1 | admin| Admin Home | false |
So if the user in client_id 4 is of group 1 they are NOT allowed to view 'Admin Home' it isn't actually quite this simple but for the sake of this question we can pretend.
The problem is as maintenance goes on this table get out of date quickly, and when you have a few thousand rows, constantly checking the table against the actual page names (using scandir() and array_diff()) will be expensive. Is there a different paradigm for checking this kind of integrity other than direct comparison? - For instance would hashing my $page_array and comparing it be a better approach?
On my website, I display 5 questions (MCQs) per page and when the user requests new page, I am calling a script score_update() with the score of this page and then presenting him with the next page.
The scoreUpdate() script is something like
<?php
//connect to database
//update the score
?>
The problem is that the user may refresh the page and the score may be updated twice or the number of times he refreshes the page or he may directly call the script by viewing the source code.
How can I implement this system?I need an idea.
EDIT
Here is my database schema
user
------------------------------------------
user_id | username | password | points
------------------------------------------
PS :The user may attempt the same question again at some point in future. There is no restriction on it. So no need to keep track of questions attempted by him. He must get marks only if he attempted the question and knocked it right. Hope I am clear.
I would recommend saving the user's state in your database. You should add another table in order to do so.
-----------------------------------
user_id | question_id | answer
-----------------------------------
When a user answers a question you can check if the user had already answered this question.
If so, update his answer and if it's the correct answer update him score. This method works assuming you won't present the same question again if the user already answered it correctly.
If you want to use questions multiple times I recommend another method.
Use 2 tables:
----------------------------
user_id | questionnaire_id
----------------------------
and
------------------------------------------
questionnaire_id | question_id | answer
------------------------------------------
Each questionnaire is unique and contains some questions - the answer to each question is empty at the start. Generate new questionnaire each time the user gets new questionnaire and save his answers per questionnaire. This way you can make sure the user can't submit the same questionnaire results twice (or more). If it's the first time the user submit this questionnaire you can update the score, if not, do nothing.
To make sure the user does not change his questionnaire_id manually you can save it in a session on the server so the user won't have access to it.
I would suggest using form keys, also known as NONCE.
This means that each time a submission is made, a new form key (NONCE) is generated.
Each NONCE can only be used once and the NONCE must be valid for the form submission to work.
Most modern frameworks have something like this built in as standard.
See this article for a more in depth explanation of the idea:
http://net.tutsplus.com/tutorials/php/secure-your-forms-with-form-keys/
And this section of the Symfony2 CSRF protection on forms which uses the same technique:
http://symfony.com/doc/current/book/forms.html#csrf-protection
There are different possible solutions for problems like this. It is basically the same with visitor counters or polls.
Atleast you have to store your information somewhere if there user as already triggered that script and redentify him on every page call.
The first and best method is a user account to login and save it in the PHP $_SESSION or directly in the database linked to the user_id / account_id. But this if your page doesnt have a login right now this is too much for a smaller problem I guess. But if you have already one login panel this is by far the best solution.
Another method is to save a cookie which may be a legal problem in some countries lately if the user doesnt agree to that before hand and cookies can be deleted so there it is easy to manipulate.
You can also save the users IP Address: Harder to manipulate (requires restart of internet and such and noone will do that a dozen times to fake your score counter) but if multiple people are sharing the same internet connection only one of them can achive one score.
All of them have different advantages and disadvantages. Depending on how paranoid you are you could also combine multiple of them if you want to make cheating / abusing harder but that decision is up to you.
Consider the following setup;
users
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| user_id | smallint(5) | NO | PRI | NULL | auto_increment |
| username | varchar(10) | NO | | NULL | |
+------------+-------------+------+-----+---------+----------------+
... You'll have more columns, but you get the idea
-
questions
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| qid | smallint(5) | NO | PRI | NULL | auto_increment |
| question | varchar(10) | NO | | NULL | |
| votes | smallint(5) | NO | | 0 | |
+----------+--------------+------+-----+---------+----------------+
-
votes
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| qid | smallint(5) | NO | | NULL | |
| user_id| smallint(5) | NO | | NULL | |
+--------+-------------+------+-----+---------+-------+
In this setup, I'm userid 1 and voting for question id 1
When a user votes, their vote is placed within votes
INSERT INTO `votes` (`qid`,`user_id`) VALUES (1, 1);
To check they've already voted, simply do;
SELECT `user_id` FROM `votes` WHERE (`user_id`=1) AND (`qid`=1);
If that query returns any rows, we know the user has already voted, and we shouldn't process the duplicate vote.
Of course this only restricts us to one type of voting - positive, or negative - whichever you decide to track. We can adapt votes to store the type of vote it is;
ALTER TABLE votes ADD type ENUM('up', 'down') NOT NULL DEFAULT 'up';
Which will make our table structure to the following;
+---------+-------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------------+------+-----+---------+-------+
| qid | smallint(5) | NO | | NULL | |
| user_id | smallint(5) | NO | | NULL | |
| type | enum('up','down') | NO | | up | |
+---------+-------------------+------+-----+---------+-------+
And, again, adapt the lookup query;
SELECT `user_id` FROM `votes` WHERE (`user_id`=1) AND (`qid`=1) AND (`type`='up');
Check the $_SERVER['HTTP_REFERER'] value.
If it's the same the page: is reloaded. (do nothing)
If it is the previous: update database
If it is another domain: illegal access (redirect to first question)
The most foolproof system I see is based on tracking the whole lifetime of a given quizz.
If you store a "current question number" associated with the user and this particular quizz, you can easily filter out duplicate responses:
update_score ($question_number, $choice)
if current question for this quizz and user is not set to $question_number
ignore request
else
set choice for this specific question and update score
increment current question (possibly reaching the end of the quizz)
When the last question is answered, the final score is displayed/recorded and the "current question" reset to 0.
If the user wants to retry the test, current question is set to 1 and the whole process restarts.
If the user wants to cancel the current test and restart, he/she can do so by going back to quizz start page.
So any attempt to submit a second answer to the same question would fail (be it from accidental refresh or malicious attempts), until the quizz is finished and you can start back with question 1.
You can use a toggle session variable approach (name it as flag),which is the simplest and has a good level of security against duplicate requests.
Make a script called updateScore.php .When the user login set the flag=1 ,which means when the next request comes for updation,process it in updateScore.php and at the end of ths script make flag=0. When the next page appears again make flag=1.This way you alternate the values and also set a maximum update limit in your script,say, in your case you have 5 questions so you can set it to 50 (+10 per question). You can take more complicate values of flag to reduce guess chances.
I want to store user's login history on my site.
table:
mysql> desc user_stat;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | varchar(64) | YES | | NULL | |
| login | varchar(64) | YES | | NULL | |
| logout | varchar(64) | YES | | NULL | |
| diff | varchar(64) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
When user log In I perform insert.
insert into user_stat(id,login) values('".$id."','".NOW()."');
But for logout situation is confusing. As user may have logged in twise in two diff browser. So how can I maintain logout time? something like session management (though I have not used session var for login logout). JS sdk for login logout I used : http://jsfiddle.net/YCFpH/
Also How can I get the differene of logout and login time in diff column?
One way is to convert string of data-time into number and getting differece of it. But I dont what that method.
Anyother solution for data time diff?
But for logout situation is confusing. As user may have logged in twise in two diff browser. So how can I maintain logout time?
Each Login must have some sort of session identifier. Otherwise, you will never properly correlate your logout time with the correct login time. There are any number of ways to get this and that will depend on your web server platform. At the very least, you can create a uid on the client (see Create GUID / UUID in JavaScript? ) and pass the uid in when the user logs out.
Additionally, if you are not sorting by or joining by the difference time, login and logout should likely be datetime datatypes and the difference simply calculated each time you want it instead of stored. For example.
set #time1 = now();
set #time2 = date_add(now(), interval 30 second);
select #time1, #time2, (timediff(#time1,#time2))
Now you get the difference between the times in seconds.
2013-12-26 14:17:32 2013-12-26 14:18:02 -00:00:30