Basically, I am trying to make a split-test web app, and I'm a bit confused on how to do this without any race conditions.
Basically, there are 3 pages:
main_page.php
page1.php
page1_alt.php
So the process is as follows:
user visits main_page.php
main_page.php checks for a cookie
a. if there is no cookie create a cookie,
b. check the page the last visitor was sent to
c. send the current visitor to the other page (if last visitor went to page1.php, send this one to page1_alt.php)
I have the cookie issue sorted out, I just want to know what you think is the best method on how to do step 2b. If i write to the db, it would be impractical. If I refer to a text file, it would produce possible race conditions.
EDIT: If you think there's an easier way than starting from scratch, do give me some suggestions.:)
I'm not sure I completely understand why you want to do this, or why writing to the DB would be impractical. If you want to split them with exact precision, this seems to me to be the best possible solution.
If however you just need to split them approximately without DB-access, you could be creative:
if (date('s') % 2 == 1) {
header("Location: page1.php");
} else {
header("Location: page1_alt.php");
}
Of course there is some chance involved in this, but since seconds are equally distributed, if you have enough users, the two groups should be quite close to equal size.
I know google analytic can do split testing, I'm not sure what your end goal is but with GA It will split the users and test which page get's the user to the goal the most. Sorry if this wasn't what you were looking for.
Consider using sessions instead of cookies. Sessions are more flexible and secure way to track user activities.
You should be using sessions and header("Location:...);. From that you can do something like this
if (!isset($_SESSION["var"])) {
header("Location: main_page.php");
}
Where $_SESSION["cookie"] is whatever you want to set it to be. I guess in your case you could set to what page they were at last. Then you can just check if it exists and/or what it is and use header to send them to the appropriate page.
Related
I want to count image views on my website. Until now, I set a cookie that contains the last 20 viewed images like 1254.12.963.4328.32 and so on.
This is to prevent multiple counting if somebody presses F5 / reloads the page. Also I don't want to count crawlers and spiders. (I somewhere read that bots won't set this cookie, but I don't know)
Would I count only real users, when I use the session id and save an array with the viewed image-ids in the session? I use laravel with database session driver. And how much data can be stored per session?
This is a home-made way to do that. Of course, there are some libraries that do a better job than this. However, this is a good start. Specially, if you want to do it yourself.
<?php
if (!$_SESSION['counter'] || !isCrawler()) {
$_SESSION['counter'] = 'whatever-counter';
}
function isCrawler() {
$crawlers = array('googlebot'); //add more crawlers agents
foreach ($crawlers as $crawler) {
if (strstr(strtolower($_SERVER['HTTP_USER_AGENT']), strtolower($crawler))) {
return true;
}
}
return false;
}
Probably you want to determ by browser.
See in to this project which provide browser list and documentation how to catch it.
BrowsCap
Would I count only real users, when I use the session id and save an array with the viewed image-ids in the session?
No. I guess the answer is no to question if you would count real users because you would have to require some action to verify that it is a real user. That's why - for example captchas are used when submtting forms.
However, you could narrow it down though so you could check "who's" browsing your page. You've got a great answer from Lea Tano which I beiieve would give you a hint where to start.
And how much data can be stored per session?
Sessions are (by default) stored to the server, so the actual limits is determined by PHP's memory_limit() and diskspace (on the server).
I am designing a simple drag and drop quiz. We are limiting the number of attempts to get a correct answer to two for each box/answer. However, I'd like to keep the functionality and state of the quiz separate from the display/view.
Currently, as the user attempts to get a correct answer by dropping an answer box on top of a question box, an ajax call is made to a PHP page which returns a 'true' or 'false' value.
We have been evaluating if we want to use Session variables on the PHP page, cookies, or something even more simple to track how many attempts each box has consumed. It would be preferable (for good form's sake) to somehow maintain the state of this data on the server - so the client has no idea what is going on. Session variables seemed to make sense to me - as the user continues to make attempts with different question/answer combos, the server tracks the number of tries and returns (in the ajax response) the result of a user's question (right/wrong, and how many tries that answer has remaining, if any) but I'm wondering if there's a better solution. Any input?
Session seems like a good fit to me. Cookies can be tampered with so I would avoid that if you need the error count to be accurate.
Sessions is probably your best bet. Cookies could be used as well, or if you can guarantee availability of HTML5 localStorage in the browser, you could use that as well.
Unfortunately to keep the functionality separate, there is not. You can use a session variable, or database storage paired with a session id stored in a cookie.
Store current user state into session (temporary storage) and track what he have answered what not etc. at the last step store data into database, or file (permanent storage). Session is individual for every user. Users can't alter your site sessions.
Session usage
I'm currently building a web application that uses a combination of OpenID and uname/pw authentication to authenticate users. Users are supplied a PHP session when they login successfully, and some information about their account (email address, usergroup, blah blah) is written to that session.
However, there may be a need for me or someone else as an administrator to update a users details (or to ban them immediately if they're very naughty). I'm hesitant to use a killsession tag like this (pseudocode):
session_start();
mysql_start(connection_stuff);
if (mysql_query("SELECT FROM users WHERE uid = '$_SESSION['uid']' AND KillSession = true")) { Kill session, force reauthentication };
However, doing it like this has two flaws:
We have to query the database every time someone loads a page to see if something changed
We gotta log the user out which just annoys him (or reload all of his session variables, which doesn't seem efficient)
Is there some way I can modify a user's session while they're still in it without having to resort to forcing them to login again? Some people seem to suggest in this stackoverflow thread using session_id to change to the user and then fiddle with their variables, but that seems like a shoehorn way of doing it. Thanks in advance!
I think instead of storing that stuff along with the session, it should be kept (and cached) separately. That way you avoid data duplication and the issue you're running into right now.
If an admin needs to kill the session, just DELETE it from the table.
Even though you express concerns about having to query the database on every page load, my guess is that it most likely does not affect performance noticeably. If the website is database driven in the first place, them it's just a matter of a single more query. I'd actually say that moving the entire session handling to the database (store session variables in a table) can make your system better in terms on flexibility. It will be much easier to deploy your system on multiple servers and do proper load balancing if that is someting you think will become necessary at son point. That is how the bigger CMS systems handle their sessions. My advise is, in other words, to stick with the extra query and actually consider to move session state to the database.
Good day,
I would like to know how to protect my website from ajax-spam. I'm looking to limit any ajax action per
users. Let's say 8 ajax-actions per minute.
An example of an action would be: a button to add/remove a blog posts "as my favorites".
Unless I'm wrong, I believe the best way would be using $_SESSION's variable and to avoid someone/a bot to clear
cookies to avoid my protection. I'm allowing ajax-functions only to logged-on users.
Using database would make my protection useless because it's the unwanted database's writes I'm trying to avoid.
I have to mention that I actually use PHP as server-language and jQuery to proceeds my ajax calls.
Thank you
Edit:
The sentense
... to protect my website ...
is confusing but it's not about cross-domain ajax.
Edit 2011-04-20:
I added a bounty of 50 to it.
Since you're only allowing AJAX actions to logged in users, this is really simple to solve.
Create a timestamp field for each account. You can do this in the database, or leverage Memcached, or alternatively use a flat file.
Each time the user makes a request through your AJAX interface, add the current timestamp to your records, and:
Check to make sure the last eight timestamps aren't all before one minute ago.
From there you can add additional magic, like tempbanning accounts that flagrantly violate the speed limit, or comparing the IPs of violators against blacklists of known spammers, et cetera.
Are you talking about specific ajax-spam to your site, or ajax-spam in general?
If the latter, you can use hashes to prevent auto-sending forms, i.e. write your hash() one-way function which takes string and makes sha1-checksum of it.
So that's how you use it:
// the page is a blog post #357
$id = 357;
$type = 'post';
$hash = hash($_SERVER['REMOTE_ADDR'].$type.$id);
Put that hash in hidden field which is not within the comment form or even hidden div, somewhere at the bottom of the page, and name it "control_hash" or something. Attach it's value to the ajax-request on form submit. When the form is received by the script, make a new hash from $_REQUEST data (excluding existing $control_hash) and check if they match.
If the form was submitted by bot, it won't have $control_hash, so it won't pass.
Yes, your idea in principle is good. Some things to consider though:
If you track the limits globally then you may run into the issue of a bot DoSing your server and preventing legitimate users from being able to use your "Favourite" button.
If you track the requests based on their IP then someone could use a bot network (multiple IPs) to get around your blocking. Depending on your site and what your preference is, perhaps limit based on a subnet of the IP.
Install and use Memcache to store and track the requests, particularly if you are going to be tracking based on the IP. This should be faster than using session variables (someone might correct me on this).
If you have access to the source code of the web-site, you can rewrite some of the javascript code that actually performs AJAX-request. I.e. your pages can have a hidden counter field, that is incremented every time a user clicks the button. And also you can have a timefield hidden on the page, in order to rate the frequency of clicks.
The idea is that you don't even have to send anything to the server at all - just check it on the client side inside the script. Of course, that will not help against the bots adressing directly to the server.
It really depends on the result of such a spam. If you just want to avoid writing to your database, all these check could end up taking more ressources than actually writing to the database.
Does the end justify the means?
You also have to judge what's the probability of such a spam. Most bots are not very smart and will miserably fail when there's some logging involved.
Just my 2 cents, the other answers are perfectly valid to avoid spam.
Buy more powerful hosting to be able serve requests, don't limit them.
8 requests per minute it's ridiculous.
Anyway, if requests are 'legal', you should find ways how to serve requests, not how to limit them. And if not 'legal' - then deny them without any 'time' limitations.
You can use a session field with a global variable holding the time of last ajax request. Since you want to allow 8 requests, make it an array of size 8 and check for the time differences. If it increases, (important) it might not always be a bot. give the user a chance with captcha or something similar. (a math problem maybe?)
once the captcha is validated, allow the next few posts etc..
But do make sure that you are checking for that particular session and user.
Kerin's answer is good, I just wanted to emphasize on captcha.
yes you need to use a function in every function views can interact, also, it should be in global library so you can use it anywhere.
if(is_logged_in())
{
// do you code here
}
while is_logged in is defined as follows
function is_logged_in($activated = TRUE)
{
return $this->ci->session->userdata('status') === ($activated ? STATUS_ACTIVATED : STATUS_NOT_ACTIVATED);
}
you should set the status session when user login successfully.
Using PHP.. I have a small app that I built that currently uses a querystring to navigate and grab data from a database. The key in the database is also in the string and that is not acceptable anymore. I need to change it. I would like to hide the db key and use a session in place of it but I'm not sure how to do that. In fact, there are also other variables in the query string that I would like to use sessions for if at all possible.
page.php?var1&var2&id=1
This is what my string looks like. I am looping through the results in the database and have given each row the id so that when the user clicks the row they want, but I'm not sure how I could do this with a session.
Does anyone have any ideas?
Thanks
EDIT:
I'm developing an email type system where senders and recipients are getting and sending mail. Each piece of mail that is stored on the server will have its own unique key. Currently, I am using that number to retreive the message but the problem is that I don't want people to change the number and read other people's mail. I can probably use a GUID for this or even some sort of hash but I really hate long query strings. I was just thinking it would be so much cleaner if there was a way to "hide" the id all together.
UPDATED (Again ... Yeah, I know.)
Allowing access to a particular set of data through a $_GET parameter is much more accessible to any user that happens to be using the application.
UPDATED
For storing a private record key, you are probably going to want to use post data, and if you really want it to look like a link, you can always use CSS for that part.
Honestly, the best way to stop people from reading other people's mail is by having a relationship table that says only X person is able to access Y email (by id). That or have a field that says who is the 'owner' of the email.
The fact is that users can still get access to POST parameters, and can easily forge their own POST parameters. This means that anyone could realistically access anyone else's email if they knew the naming scheme.
In an ideal system, there would be a Sender, and a Recipient (The Recipient could be comma separated values). Only the people that are on one of those columns should be allowed to access the email.
How To Use Sessions (From Earlier)
First start off with calling session_start(), and then after that check for variables from previous scripts. If they aren't present, generate them. If they are, grab them and use them.
session_start();
if(!isset($_SESSION['db_key']))
{
$_SESSION['db_key'] = // generate your database key
}
else
{
$db_key = $_SESSION['db_key'];
}
Sessions are stored in the $_SESSION array. Whenever you want to use $_SESSION, you need to call session_start() FIRST and then you can assign or grab anything you like from it.
When you want to destroy the data, call session_destroy();
Also check out php.net's section on Sessions
Your question isn't too clear to me, but I understand it like this:
You need some variables to decide what is being displayed on the page. These variables are being passed in the URL. So far so good, perfectly normal. Now you want to hide these variables and save them in the session?
Consider this: Right now, every page has a unique URL.
http://mysite.com/page?var1=x&var2=y
displays a unique page. Whenever you visit the above URL, you'll get the same page.
What you're asking for, if I understand correctly, is to use one URL like
http://mysite.com/page
without variables, yet still get different pages?
That's certainly possible, but that means you'll need to keep track of what the user is doing on the server. I.e. "user clicked on 'Next Page', the last time I saw him he was on page X, so he should now be on page Y, so when he's requesting the site the next time, I'll show him page Y."
That's a lot of work to do, and things can get awkward quickly if the user starts to use the back button. I don't think this is a good idea.
If you need to take sensitive information out of the URL, obfuscate them somehow (hashes) or use alternative values that don't have any meaning by themselves.
It completely depends on your application of course, if the user is accumulating data over several pages, Sessions are the way to go obviously. Can you be a bit more descriptive on what your app is doing?
Edit:
but the problem is that I don't want people to change the number and read other people's mail
If your primary concern is security, that's the wrong way to do it anyway. Security through obscurity is not gonna work. You need to explicitly check if a user is allowed to see a certain piece of info before displaying it to him, not just relying on him not guessing the right id.
There are some examples on how to use $_SESSION on php.
Registering a variable with $_SESSION
The issue with using sessions for using it in place of S$_GET or $_POST is that you need some way to read the user's input so that you can store it in the session, and you need a way to trigger a page refresh. Traditional means is via hyperlinks, which defaults to GET (unless you use Javascript) or forms, which defaults to POST.
Maybe ajax will help you here. Once the user has enter info into a form or a checkbox, use JS to send a request to insert the info to the PHP and send info back, whether it is to refresh the page or to fill a with content.
Hope this helps