I have a simple followers/following system set up within my app.
What would be the best way to store a complete array of 'users following' during a session so that I don't have to query the database multiple times throughout.
To clarify: When a user logs in once they have been authorized I query the database, get a full list of users that the logged in user is following and ultimately store it as a JavaScript variable. This way throughout the site, as the user navigates around I can constantly check the following status against any other user they may come across.
This query is only performed once when the user loads the full page, while navigating around it is not repeated.
This works well for javascript generated content i.e user hovercards etc...
However I would like to store this array (of only userid's) in PHP itself so that I can prevent further queries to the following table while generating content server side that requires a 'follower/following' check to be performed.
What would be the best way to do this?
Please bare in mind that the results are cached in memcached but if I can avoid any lookups at all and have a consistent array to check against that would be great.
Thanks in advance
So let me get this right, you want to store this list so it isn't queried on each page?
First I would recommend you only perform this query on pages that need this data and second I would say that on these pages you don't try this.
Imagine a user stops following or starts following. Some complex cache calculator or event bubbler programmed into your own PHP app to purge the foreign session of data (which is bad, the user has access to data that is not their own, a session infact) could be tiedious with security and performance.
The better thing to do is to perform the query again for each new page. This would be much easier, probably more performant and wouldn't be micro-optimising.
Edit
If you are picking out 10k rows on one page then you might be doing something wrong. You might be looking at it from the wrong perspective.
Store it in the session variable.
http://php.about.com/od/advancedphp/ss/php_sessions.htm
https://www.google.se/search?q=learning+sessions+php
UPDATE
Store the current user in a session and add it to the queries you are already doing to fetch the popup information and add that it tests if the popups person follows the current user.
The two ways that come to mind would be to just write joins with well placed indexes each time, which you've said you don't want to do, and just a simple array in the session, which would probably look something like this:
if (!isset($_SESSION['following']) {
$following = $user->getFollowingIds(); //some query in here to get an array of ids
$_SESSION['following'] = $following;
$_SESSION['following_str'] = implode(',', $following);
}
Then whenever you want to pull all of the statuses for the people that $user is following you can write a query, something like this:
$query('SELECT status.* FROM status WHERE user_id IN (' . $_SESSION['following_str'] . ')'); //not sanitized or safe but you get the idea
Related
I have a panel I'm making that will use session data from another forum to give it permissions. Basically when the user logs into our forum and the session and trust is created on the forum, they can click on the panel and the panel will check their browser cookie for the session id and trust id. It then takes that trust id and checks the forum's database for the user id associated with that trust. Then takes the session id and verifies that it belongs to that user id. The issue is that when I get the session id, the associated user id is part of a blob that i have to cast in order to get the data from the field. So I get a result like this:
('7c64c90413beb7d139c64ccc8b13380b',
'a:12:{s:12:"sessionStart";i:1454075264;s:2:"ip";s:4:"b???";s:11:"sessionCsrf";s:16:"-2Yx13nBLdstUj4H";
s:7:"user_id";i:20;
s:13:"password_date";i:1453353041;s:16:"previousActivity";i:1454072099;s:13:"trophyChecked";b:1;s:16:"promotionChecked";b:1;s:16:"dismissedNotices";a:0:{}s:15:"lastNoticeReset";i:0;s:13:"canAdminUsers";b:1;s:20:"userModerationCounts";a:2:{s:5:"total";i:0;s:13:"lastBuildDate";i:1454075264;}}'),
I know there is a lot there, but I singled out the part that matters to me. The first column returned is the session id, which im using to verify the user id, but the user id is in the middle of that all that crap in the second column. So you can see where I single out the definition, what I want to do is just assign that "20" after "user_id;i:" to a variable and discard the rest. I'm sure this is simply done, but at this point I think I'm just nuking it out and spinning wheels. I was thinking explode, but the structure of that data seems like that's not an option.
That data is simply the result of a PHP serialize() call. You can pass it to unserialize(), which will provide you with an array containing the values.
<?php
$str = 'a:12:{s:12:"sessionStart"…etc…etc…i:1454075264;}}';
$arr = unserialize($str);
var_dump($arr['user_id']);
In case you’re trying to extract the value from within MySQL alone, for some reason I’ve done something similar with an awful query containing lots of nested SUBSTR() and LOCATE() just two weeks ago. I wouldn’t recommend it. Especially because in my case I was doing a one-off reporting query, while you’re trying to do authentication with it. People might try to use specially crafted cookies to circumvent your string extraction and gain illegitimate access.
Here is what my table looks like: http://jsfiddle.net/Draven/kGtx7/14/
Each header cell is clickable to be able to sort by that field and by ASC / DESC.
I want to be able to store that sorting option somewhere, so it get's remembered, but am not sure the best way to do that.
Here are the options I was thinking...
Making sort_field and sort_order fields in the users table
Making a new table that has their userid along with sort_field, and sort_order fields
Or Cookies, but I assume this is the worst option
I don't think we are clear on what you want, but I think you are wanting something like this:
Step 1: Run a query than will populate the sorting values into 2 session variables.
Step 2: Do something like this code.
$sortHeadClicked = $_SESSION['headClicked']
$sortReturnDirection = $_SESSION['returnDirection']
//TODO: validate data before query
if ($result = $mysqli->query("SELECT * FROM table ORDER BY $sortHeadClicked $sortReturnDirection))
{
//TODO: Get results
}
Step 3: Smile like your awesome
Alternatively, you could use some sort of sub select query.
NOTE: This is the simplistic logic so they won't be remember with this example. However, you can put the gets into session variables if you only want them to be remember temporarily
However, if you want these remembered permanently, you need two columns in your user's table where you would either puts them into sessions or use a subselect query
This is left up to interpretation, but each case would have its own uses.
1) Adding two fields to your users table will make the calls to retrieve these values easier but it is a much uglier approach to the problem than..
..2) Relational databases are built to be used as such. I'm not sure in terms of performance, but I do know that using the power of relational databases can make your db easier to navigate and understand/manipulate. While you may need some more complex calls (ie joins and whatnot), I believe the tradeoff is worth it.
and 3) Cookies are a very meh solution. They could be used in temporary cases, but if you are trying to save info for later, cookies can easily be deleted or not even enabled, at which point your site can suffer drastically.
Actually, using a cookie to store the user session id and then keeping session data in a database, flat file, or memcached is pretty common way to solve this. It would help to set up a reusable mechanism for this, like registry of sorts, that you can retrieve per user values at will. This only works if you have a user login of course. Otherwise there is no point in storing that data, as the users identity will be lost once they end the session (close the browser window). Most web apps will use cookies to identify you. If you delete that cookie, it forgets you and you are logged out.
Your first solution will suffer if you ever want to add another per user "preference" as you'd need to modify the underlying table.
Have a look at Zend Session for ideas if you are using PHP. If not the concepts still apply.
To save the sorting order to their profile, make the table inside a form and have the sortable field names be inputs. When they click one of the field names (sort by Location, for example), have the form's action run a PHP snip that updates a field in their profile on the database.
Alternately, if able to use ajax, you could simply add the database updating to an ajax call and skip the form.
I'm afraid that depends on your needs. How I see this problem:
good if you must share this settings between browsers, PCs, in
case if user delete cookies in browser. But it is not flexible - if
you will need to add another table, you will also add two additional
fields
the same as 1 in term of how it is shared between computers, browsers etc, but it is more flexible. You may add a column with table name easily.
If this setting is not so important and you may allow to loose setting in some cases. This solution is simplest, but it may not work for you
I'm using CodeIgniter and I have user data that needs to be stored in some way then updated. Basic things like name, id, points, comment count etc
At the moment when the user logs in I simply get their data and store it in a session. Now obviously the name and id would never change, but the Points and Comment count etc will change from page to page depending on the user actions.
As this data will be constantly changing, what would be the best way to store it , update it and make it available throughout my app? I'm not sure if updating the session every time the user performs an action is the best way though?
I thought about maybe using a CodeIgniter hook to run a function that sets up a variable ready for use?
Whats the best way? Any ideas?
Thanks, Sean Jenkins
Why can't you store the data in a database? If your worried about performance you could use something like Memcache or APC to cache it but it seems like comment count and points are data that need to persist between sessions.
You would still need to write the data to the database as well as the cache but then you could read the data directly from the cache instead of querying for it.
I've created a website where users will be able to add entries, associate rows in different tables and so on. I need to track what actions users are doing for a score table.
I also need to keep track on page views.
I'm trying to figure out what is the most efficient way for tracking / logging this.
Is it best to:
create a new DB and add records here?
Add records on same DB as website?
Use javascript to send parameters by URL to a logging server?
Any other methods that is good?
I don't know how many users I will have on my website when I launch this, but hopefully I will have a bit of trafic.
You can make DB table with rows:
Date and time
IP address
Current URL
Referrer URL
Serialized $_GET
Serialized $_POST
Serialized $_COOKIE
It's very useful if you want track your traffic.
Pseudocode:
if(!$bot) {
$visit = Array(
'date' => date("Y-m-d H:i:s"),
'ip' => $_SERVER['REMOTE_ADDR'],
etc ...
);
$sql = "INSERT INTO visits (`".join("`,`",array_keys($visit)."`) VALUES ('".join("','",array_values($visit)."')";
...
}
Use same DB, so you will have less connections to mysql server.
Do it in PHP script (after mysql_connect is quite good idea), I believe one INSERT per visit is not big challenge for your machine.
I wouldn't use Javascript if you want reliable results as users may have that disabled or may try and manipulate it to cheat somehow.
Ideally I would use a separate schema as that will scale the best (you may in the future want to split that schema off onto a separate server for processing) although it will make it hard to join data between the two schemas. You could start with a new table in the same schema (as long as your code is nicely encapsulated you could always break the logging out into a separate table at a later date).
I advise looking for a solution that is asynchronous (to minimize the performance impact for end users) and integrated with an overall visitor data solution (so that reporting on various metrics can be combined). For example, Google Analytics offers Event Tracking so that you can add to its standard metrics on visitors, page views etc, arbitrary user-action data like those you describe.
Have you considered using HTML5 webstorage: http://www.w3schools.com/html5/html5_webstorage.asp
you could use javascripts sessionstorage object(data is stored in key/value pairs) to store all the page activities as properties of this object, then POST this information alongwith the logout action to the backend script which in turn maintains the corresponding database entries, I believe this way you can avoid uneccessary http requests with all the overheads, by sending the page activity information in one final request.
you should re-initialize the object on every user login.
I'm building a PHP/MySQL app where users can log in and search for media assets. They can also save searches and create lightboxes (collections of assets). Finally, they can create user groups.
Does it make more sense to query all at once, at log in, for the id's for their saved searches, lightboxes, and groups and save those in session vars? Or to perform the queries when they first hit the appropriate pages? I'm looking for efficiency, and the sessions seem the way to go, but am I overlooking anything?
Biggest Rule: Only put in the session what you need in the session
I don't think it would be wise at all to put everything you need in the session all at once because you'll have a lot of occurrences where that isn't needed. The user might not stay long enough to make use of all the data in there, so you just wasted time and resources putting it there.
Put your information in there on demand (when they go to each page that requires that information).
Always keep your session object neat and slim and your performance will thank you.
Querying all at login is a bad idea. First it slows down login and 2nd it creates a static workload on your SQL server for every login.
If you query when applicable, you have a varied load. (even if you cache the results to be used later)
Also if you store results in sessions, then you are increasing the memory used for each request for that user.
There are many things that can be good for your particular site but we need more data to be able to answer that better.
Query only what you need and when is necessary.
Short example that proves that all in one query is wrong:
If you query for login and user data and the login goes bad, the rest of the query will not be used.