I would like to understand why CI's session table structure has these three primary keys: session_id, ip_address and user_agent.
CREATE TABLE IF NOT EXISTS `ci_sessions` (
session_id varchar(40) DEFAULT '0' NOT NULL,
ip_address varchar(45) DEFAULT '0' NOT NULL,
user_agent varchar(120) NOT NULL,
last_activity int(10) unsigned DEFAULT 0 NOT NULL,
user_data text NOT NULL,
PRIMARY KEY (session_id, ip_address, user_agent),
KEY `last_activity_idx` (`last_activity`)
);
Please explain the most you can, also, I would like to hear suggestions to improve this structure. Why are ip_address and user_agent primary_keys, not just indexes? What's the difference?
Another info, this table adds a row to every user's access to the system, so, it is very bloated.
Edit: Another question that come to mind. Why would I care about user agent match?
The idea here is that each session will be unique. How does it identify a session? By the three values in the primary key: session_id, ip_address, and user_agent.
If you think about it, this makes sense:
If the session_id changes, then (obviously) you're dealing with a different (new) session.
If the ip_addess changes, then somebody's logging in from a different PC - this will be a new session.
If the user_agent value changes, then somebody's using a different browser - again, this will be a new session.
So imagine that only the session_id is the primary key: changing either ip_address or user_agent would simply update the existing row for the session_id. If that were the case, knowing only the session_id would make it possible for me to continue the same session on another PC or with a different browser, which might be a security concern.
You also wrote "this table adds a row to every user's access to the system, so, it is very bloated". I'm not sure if you mean every time user A accesses the system it adds a row (which is false on my application, I just tested it) or if you mean it adds a row for each user accessing the system (which is true, and the way it's supposed to work - each user using the system has a session). Maybe you could clarify that last comment.
"primary keys" is an oxymoron. A table cannot ever have more than one "primary key". And as written up, there is only one primary key - it's just a COMPOSITE key that contains 3 separate fields.
That means
(42, 127.0.0.1, "Chrome")
(42, 127.0.0.1, "Firefox")
are two entirely different sessions as far as CI is concerned, even though the IP and session ID numbers are duplicates. The 3-way tuple is unique, but individual components can be duplicated.
Related
Problem:
I have the following table in MySQL.
For this example lets say that there is (and always will be) only one person in the world called "Tom" "Bell". So (name, surname) is the PRIMARY KEY in my table. Every person has his salary, an unsigned integer.
CREATE TABLE IF NOT EXISTS `user` (
`name` varchar(64) NOT NULL DEFAULT 'Default_name',
`surname` varchar(64) NOT NULL DEFAULT 'Default_surname',
`salary` int(10) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `id` (`name`,`surname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Whenever I insert a row using a PHP script I want my function to return the primary key of the inserted row (an array key=>value).
From PHP context I do not know what the primary key of table 'user' consists of and I do not always need to set all primary key values (example 2, very stupid, but possible).
I can add another argument to my insert function (for example I could pass the table name, in this case "user").
If this matters, I am using PDO (php data objects) to connect with my MySQL database.
Example 1:
$db->insert('INSERT INTO `user` (`name`,`surname`,`salary`) VALUES ('Tom','Bell','40');');
should return an array:
$arr = ['name' => 'Tom', 'surname' => 'Bell'];
Example 2:
$db->insert('INSERT INTO `user` (`name`,`salary`) VALUES ('Nelly','40');');
should return an array:
$arr = ['name' => 'Nelly', 'surname' => 'Default_surname'];
Disclaimer & other information:
I know this is not a well-designed table, I could use an auto_increment id column to make it much easier and probably more efficient as well. This is just an example to show the problem without having to explain my project structure.
Without loss of generality: Using functions like "getLastInsertId()" or "##identity" will return 0, I guess the reason is because the table does not have an auto_increment column.
What have I tried? Nothing (other than things stated in point 2 (which I was certain it wouldn't work) and searching for a solution).
There aren't "nice" ways around this problem. One of the reasons for having an auto_increment is to avoid having problems like you described.
Now, to avoid my answer to be one of those that take into account only half the picture - I do realize that sometimes you inherit a project or you simply screw up during initial stages and you have to fix things quickly.
To reflect on your example - your PK is a natural PK, not a surrogate one like auto_increment is. Due to that fact it's implied that you always know the PK.
In your example #1 - you inserted Tom Bell - that means you knew the PK was Tom Bell since you instructed MySQL to insert it. Therefore, since you knew what the PK was even before insert, you know how to return it.
In your example #2 you specified only a part of the PK. However, your table definition says thtat default values for both name and surname are Default_surname. That means, if you omit either part of the PK, you know it'll assume the default value. That also means you already know before insertion what the PK is.
Since you have to use a natural PK instead of a surrogate, the responsibility of "knowing" it shifts to you instead of RDBMS. There is no other way of performing this action. The problem becomes even more complex if you allow for a default value to become null. That would let you insert more than 1 Tom with null as surname, and the index constraint wouldn't apply (null is not equal to null, therefore (tom, null) is not equal to (tom, null) and insert can proceed).
Long story short is that you need a surrogate PK or the auto_increment. It does everything you require based on the description. If you can't use it then you have a huge problem at your hands that might not be solvable.
I'm studying a login system at http://www.androidhive.info/2012/01/android-login-and-registration-with-php-mysql-and-sqlite/.
And I want to ask, what is the main function of uniqid(”, true)?
The tutorial from the website says
"user unique id – I am generating unique user id in php using uniqid(”, true) function. Sample user id will be like 4f074eca601fb8.88015924"
Why it must generate the user id? For security or for what?
Thank you so much guys.
This is the mysql query for my database.
create table users(
uid int(11) primary key auto_increment,
unique_id varchar(23) not null unique,
name varchar(50) not null,
email varchar(100) not null unique,
encrypted_password varchar(80) not null,
salt varchar(10) not null,
created_at datetime,
updated_at datetime null
); /** Creating Users Table **/
Maybe this unique_id is used for data submission. For example, submitting a form with ajax may require the user id of the person submitting it, so to prevent hackers from changing the data sent to the server, unique id are used to make the change almost useless cuz they don't know the pattern of how people are assigned IDs. Another reason, unique id might be useful in, it might be used in the url to show the profile of someone. example: profile.php?id=unique_long_id
This prevents people from knowing how many users exist in the website ...
There is unlimited ways you can be creative with unique ids :)
Usually, something like a "complex" (understand not an auto_increment thing) id is used so that no user can guess an other user's id.
If you used something like the uid (the primary key auto_increment column), it would be easy to guess that users 145th, 146th, ... exist. A user may try to brute force some requests manipulating the id.
In a badly coded website where you don't have any security check before updating a value, let's assume you have this URL to update a password : http://example.com/update_password?uid=150&password=trolling. Easy to change any users password right ? But with the unique_id, it's more complex.
Now why the 2 arguments in uniqid('',true) ? Because from the manual :
/* We can also activate the more_entropy parameter, which is
* required on some systems, like Cygwin. This makes uniqid()
* produce a value like: 4b340550242239.64159797
*/
I am building a application. It is basically a E-commerce Order fulfillment application. IN this audit trials i.e. who changed what and how many times it was changed and others make a important aspect. How should i maintain this in database / table level ? Say if a record is altered by 3 people, how will i maintain all the changes and track of who changed what ?
First, you need create for every table which you want track with structure like this:
create table user_track_logs {
id bigint(20) primary key auto_increment,
key_id int (11),
user_id (int),
created timestamp default now(),
field varchar(128)// set bigger if you have long named columns (like this_columns_is_very_important_for_me_and_my_employers...)
field_value_was text null,
field_value_new text null,
}
Second you need set current user ID in var in MySQL's connection, or you can use MySQL's user. You can create for every user separate MySQL's login.
Third create triggers insert/update/delete which will be store in user_track_logs.
Or you can emulate this process in PHP, but in PHP it will be more difficult.
I have loginlog table as following
Field Type
login_id int(10) NOT NULL
platform varchar(50) NOT NULL
browser varchar(50) NOT NULL
ipaddress varchar(50) NOT NULL
last_login datetime NULL
last_logout datetime NULL
But on this structure I am confuse that I can add login time but its hard to update it for logout time. I have not added primary key because logs are frequent and primarykey will soon reach it max value. What should be the best way? Please help.
Having a single row with both login and logout like that is just asking for trouble, because it assumes that every login has a corresponding logout, which is just not the case. Sometimes they will login on a public computer and never log out, sometimes they will open an anonymous window and login.
Instead, I would cut it down to just a type:
login_id
platform
browser
ip_address
date
type (login / logout)
Why not just create table logout log, with 2 columns.
with a reference to corresponding login_id, and the time of logout.
And last_login, and last_logout do not make sense to me, but your logic may require it. Because IMO you should avoid having columns, which can have NULL.
EDIT: As a addon, I would say why would you accumulate so much data. If it is only for analyzing user's browser, platform, you can use Google Analytics. And you can just keep last_login, and last_logout for each user, then. Again, your business logic may require it.
my suggestion is that if you want information of last log in and last log out only then.... make the user_id as primary key... and just change that information instead add new record... you can add one count field to enhance your functionality... to get number of count the person is log in...
and if you want each and every login data... just go with the serialization concept... it will help... make array set count as key and your last login, logout, browser as a value of array...serialize that and store in database...
My suggestion is to update entry for each user once he/she relogins to avoid primary key reaching its max value.
I have a table in my MySQL DB with information from each user that they submitted during registration.
I would now like to allow users to change one of those columns (Column X), but only once.
What is the best way to do that?
The only way I can think of is to add an additional column (Column Z) to the table with a binary value that defaults to 0, and changes to 1 when Column X is updated by the user. If Column Z is 0, the site allows the change, otherwise, it does not allow it.
Is there a better way? Should Column Z be in the same table as Column X? Any other relevant points/issues I should consider?
Thanks.
You could have a default value for column x that gets created once the row is inserted to the table. Then when the user wants to update his row, the db checks this value, if it has not changed since insertion, then the user can be allowed to update. Otherwise it rejects
CREATE TABLE example_table (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
data VARCHAR(100),
value_to_be_updated_once DEFAULT NULL
);
in your code you can check if the column (value_to_be_updated_once) is null, then the user should be allowed to edit.
You must make sure that the user does not set this value to NULL, unless that is something you want to have. (maybe the user changed his/her mind and will edit later)
You may, at some point, decide to allow the user to change columnX 3 times. A boolean will not allow for this. And what if you decide to allow the user to change columnY too. What then?
If you are absolutely positive that you will never need to change your rules, a binary flag will work fine. But if you will potentially be allowing and limiting changes on multiple columns with possibly different limits, you might consider a User_Edits table. It might look something like this:
tablename varchar(30) not null,
columnname varchar(30) not null,
user_id int unsigned not null,
changetime timestamp default current_timestamp,
oldvalue text
To find out how many edits a user had done:
SELECT COUNT(user_id) FROM User_Edits
WHERE tablename='Mytable' AND columnname='ColumnX';
And, as an added bonus, you'll have an audit trail that allows you to undo changes.