How to memorize user's progress through the application? - php

I'm facing an architecture problem I didn't manage to solve. I'm developing a little game in PHP and Javascript, and I need to save the user's progress. Now, the problem is that PHP can't determine when the user wins the level: it's done in Javascript. Is there any way to save the user's progress when he wins a level?
For example, when the user wins level 1, he gains access to level 2. If he tries to access level 2 without having completed the previous level, he gets redirected to the last completed one. In my controller I was doing the following:
if (1 !== $id) {
if ($app['session']->get('last_level') !== ($id - 1)) {
// redirect the user
}
}
Now I need a way to store the last_level value into the session, an operation that can't be simulated by the user.
Any hints?

You're going to want to do the different last_level calculations on the server. That way the user can't hack around with the JavaScript, and submit something on a specially crafted form. So depending on what your storage system is (KV store, Database, Textfile, etc.), put that value in there, and retrieve it.
Ajax can help you out, but isn't necessary. It depends on how your game is set up. But if they complete the level, the server needs to be notified.

If a user completes a level and then stays on the same page doing additional work:
Then you'll probably want Ajax to send the new level info to the server as soon as the new level has been achieved. Thus:
Use cookies to store your php session id
From your Javascript client, use Ajax to invoke a php url on your server whenever the user wins a new level. Send the new level as a parameter. Can use POST or GET, doesn't matter.
The php program will receive the session id in the cookie, and the new level as a parameter. The php program will look up the user id from the session id, then store the new level the database.
Next time the main url of the php program is invoked, it will be able to look up the user's level.
If the user presses "Next" button to go onward to the next level:
Use Javascript, not Ajax, to change the POST parameters of the "Next" button.
You'd use POST, not GET, since seeing a url of foo.com/game?level=5 is a bit too obvious for people to cheat your game. POST will not show the level parameter in the url. More security: add a checksum parameter.
If any of the above is not clear, ask in comments or as a follow-up question.

If you're happy to take javascript's word for it that the level has been completed then just set a cookie from javascript.
an operation that can't be simulated by the user
Sorry - but if it's javascript which dtermines when they've completed the level then there's nothing to stop the user falsifying the results.

Related

Similar way to PHP Sessions in Zoho Creator

A short tutorial in W3schools about PHP Sessions writes the following:
When you work with an application, you open it, do some changes, and then you close it. This is much like a Session. The computer knows who you are. It knows when you start the application and when you end. But on the internet there is one problem: the web server does not know who you are or what you do, because the HTTP address doesn't maintain state.
Session variables solve this problem by storing user information to be used across multiple pages (e.g. username, favorite color, etc). By default, session variables last until the user closes the browser.
So; Session variables hold information about one single user, and are available to all pages in one application.
I would like to ask you if there is something similar in Zoho Creator. The reason why I am asking is because I have an application with 3 pages (each page has an embedded form). Each page redirects to the other (1st Page -> 2nd Page -> 3rd Page) and passes data through them via openurl. The final result is an HTML Page with the data of these 3 Pages (they have a unique ID).
Let's say that I am in the second page and for some reason (electricity blackout, do another job and close the browser) I want to escape from the application and the next time to continue from the same point, is there any way to do that??
I can suggest you next way
On first page generate unique session Id for the user and pass this id as a parameter to next page in URL. You can crypt in this id pointer to record from first form for example..

How to get around server flooding by users opening countless tabs?

I have some kind of chat/forum application that checks for new messages using periodic polling (every 15 seconds) using jquery ajax. I was wondering if i can get around the issue of users who try to be 'funny' by loading several same browser instances, with lots of tabs, all pointing to the same application. Each tab is sending an ajax request, which potentially can overflow a server if several users start to do the same thing.
I do store sessions in a table, along with the last access time and IP address, which works fine as long as users don't use the same browser. I could store a unique identifyer that is sent using the ajax POST or GET request, but that would give problems if a regular (non abusing) user refreshes his page, which would then create a new identifyer.
This is not a real problem yet, but better catch it before someone thinks of abusing the system like this :) Any idea how to do this?
One option could be to fetch data like so:
Your script is preparing to poll data. Before executing the request, write (with LocalStorage), a value saying that you're going to fetch data. localStorage.setItem("last-request-timestamp", new Date().getTime());
Poll for data. You get a result. Write that result to the localStorage: localStorage.setItem("latest-messages", ajax_result);
Check if a page is preparing to poll data by checking if localStorage.getItem("last-request-timestamp") is longer than 15 seconds ago. If so, go to step 1. If not, wait 15 seconds and check again.
Regardless if the current page polled for data or not, check the latest-messages variable and update the page.
Other pages will of course share the localStorage data. They won't get data if another page is fetching at the moment. If page #1 is closed, one of the other pages will continue to fetch data.
I haven't used LocalStorage before, but browser support seems decent enough. You should also be able to just use it as a key-value array: localStorage["last-request-timestamp"].
You can only store strings in localStorage, but you can of course serialize it into JSON.
Not sure if it is do-able in javascript. You can check if the tab is active. And only do the ajax on the active tab?
I have the similar problem. Now I force all users to log in (it means i have their e-mails). Also i setup connections limit per account and request limit per connection, after 5 overflows i ask user to enter captcha, then i block account for a 30 min and send e-mail with password recovery link. It's not a clear solution but for now it works for me.
UPD:
The simplest way to do this is to use cookie or session storage. I use cookies. The algorithm is simple:
User login on web.
Check is there any opened session for this user,
is opened, then delete the other session or trigger exception or
switch to that session, you have decide your own the desired
behavior.
Create session id for user and store it in database.
Increase sessions counter field for specific user to detect opened
sessions, so now it doesn't matter is there one browser in use
or many.
Update last access mark (i use microtime(true) + $delay and mysql
decimal(14,4)). Send it to user
Send id to client
On each request:
Search for session by passed id in $_COOKIE.
Check last access mark. If it less then microtime(true) it means that client send requests to frequent, so decide yourself what to do, increase the mark, for example microtime(true) + $delay + $penalty or drop whole session or trigger error. The behavior depends of your application.
Why not throw something like Memcached/Redis at the problem? Cache a response with a 10-15s lifetime and avoid as much processing as possible.

How to block an user from faking requests? Or how to detect fake requests?

Let's suppose that you have a website that contains a single button.
When this button is pushed, an ajax request is sent to the server - who receives the request and adds 1 in an internal counter on its database.
An user could copy the entire request (and its headers) and create a script to send infinite requests to overload the server (and mess with the counter).
I'm trying to avoid:
Recording the user IP
Using Captcha
I'm using php in my back-end. Is there any way to prevent this situation? Is there some way to send an "invisible" request?
Your problem is called "cross site request forgery".
A good way to solve this problem is to generate a random string when the page with the button on it is called, write it into the users session and into the generated page, and send it together with your button press (for example in a GET request).
On the backend side you check if the submitted string matches with the string in the users session and then delete the string from the session. Only proceed if both strings matched and weren't empty.
This way every request URL is only valid one time and only valid for the user who initially opened the page with the button on it.
you can create a unique token that is assigned to the button and can only be submitted once with the button press.
this will mean that the user will need to refresh the page to get a new button, if thats a problem, associate the token with the user and not the button
the above method means that you need to add server side code. you might be able to get away with using something like evercookie to log the button press on the clientside and attempt to prevent the user from sending another request and recieving another request from user - i dont recommend doing this in prod, but it might be fun ;)
ill try to be bit more clear:
generate the button so that it submits a form containing a hidden field called 'uuid' that contains a pre-generated uuid for that button. this uuid will need to be kept in the database or in memory. if you use a good uuid lib, the chance of the user generating an existing uuid are infinitesimal.
now, the user clicked the button and the action goes to /my-button/?uuid=3394b0e0-a3bb-11e1-b3dd-0800200c9a66
now the server checks if the uuid is a previously generated one. if it is, it deletes the uuid from where its stored and lets the action do whatever. the uuid does not exist, it returns a 404.
You can't possibly know how a request is initiated, all you can do is make it more difficult to fake. But if this is something to do with security, then it's the people who can successfully fake the request that you need to be most aware of. So it's likely useless (or even misleading) to attempt this as some kind of security measure.
You can try an encrypted key that the server will only accept once within a certain time lmit, but you will still not know how the request was initiated (and you really shouldn't depend on that). Buttons are a UI feature that might be converted into some other UI artifact based on whatever the user agent has been configured to present to the user (if there is a user invovled at all).

How can I pass variables in PHP from the same page?....logical thinking puzzle

so I've hit a potential problem in my site....it's a post-based system, with the posts being in text files. Uses some Javascript and a lot of PHP.
When you make a submission on the form on the homepage, you are sent to a page where data is posted and processed, but you don't see it because you get redirected back. Then the homepage is changed based on what the post you made says. All that was working fine.
But now I'm trying to add a new feature that modifies the post you made, based on a button you hit which submits a hidden form using javascript, and sends to another process and redirect page you don't see, and it works fine until the block that I realized today. I don't know how to specify that the post being altered is the right one.
I anticipate a good amount of users of this site, so my concern is what if user X makes a post while user Y is making a post, and the post of user X becomes the top post, so user Y's options actually change user X's post.....
I was thinking of adding to the main processing page (the one that happens when you first submit) a COOKIE or something that would make note of the number of the line that post will become, by counting the number of the lines in that file at the time and adding 1 to it. Then checking it against the user's number (each user has a number) to see if it's that user's most recent post....but the problem is I don't know how I would pass that value around to be read in the next page.
Setting a COOKIE is out I think because the page both redirects, AND reads and writes to files. The only output to the page though are currently var_dumps.
POST/GET is out because to my knowledge the user would have to do SOMETHING to submit it, and the user's not even going to see the page.
Writing to a file would be messy if lots of users are trying to get their own data.
I think what I may be looking for is SESSION variables...but I don't know anything about those except that they're used to login to pages, and this site has no login.
To make things more fun, when a user posts the same content within a minute of another user, the first user's post is replaced and it gets a little +1 next to it...which makes it harder to check it against the user's number....
AND in the end I'm trying to use AJAX (which I dont know yet) to make the updates in real-time...now THAT is going to suck. But for now I'm worried about my static little site.
Baby steps.
Any ideas how to go about this??
Use Session variables, just as you have alluded. They aren't just used by login pages, they are used by everything. Sessions are the equivalent of server-side cookies / server-side storage, so you don't have to worry (as much) about your users tampering with them.
If you want to make life more difficult for yourself, you can json encode your variables and store them as an object in a database or even flat text file. But really, read up on sessions.
All you need to know is session_start(); before anything else then $_SESSION['var']=$yourvar; to save data and $_SESSION['yourvar'] to retrieve it later (such as on another page).

jquery - refresh the page when new data stored in to the table across the browser sessions

Environment : PHP/MySQL/Jquery
I would like to refresh the page (ex: index.php) when new data stores in to the table (ex : new_entry_table) checking for every one minute. The same page will be opened in many machines(pc-browsers) at a time all should get refresh when new data arises.
using jquery and database check i tried the following:
setInterval(function(){
$.post("new_data_check.php", function(data) {
if(data > 0){
$("#container").fadeOut('fast').load(location.reload());
}
});
return false;
},60000);
new_data_check.php: : checks
for new data in the test_db where
newdata_field=0 ; : If any new
data arises echo "1"; And update the
newdata_field=1; to stop constantly
refreshing the page. : else echo
"0"; : Just for a trigger
So the above jquery code checks new_data_check.php every 1 min for the trigger , if any trigger arises it will refresh the container.But its getting refresh only one opened session other opened sessions(in other browser or other pc) not getting refreshed.
Suggest a better way to do this. Thanks.
Your new_data_check.php file will need to keep track of all the users that are independently viewing the page.
If not, this will happen:
User 1 and User 2 are both logged into the site.
User 1 does the check 5 seconds before User 1, there is new data.
User 1 completes his request. The server clears the new_data bit.
User 2's request arrives 5 second later. Hedoes his request, but at this point, User 1 has set the new_data field to 0. His data is stale, but User 1 has effectively co-opted him.
By the looks of it, you're not supplying it with any information that would identify the user - unless the server is determining that using the IP address. If that's the case, remember that it's likely everyone behind a small network is going to have the same external ip address. So it can't tell people at an office apart.
What you could do is generate some kind of unique hash for each session and pass that off to the browser. The javascript can then provide the php script that same token.
Another solution without any sort of special bit, would be to pass along a timestamp with the request. Essentially, the client says "my latest bit of data arrived at 9:21:53 PM" The server then checks and responds "My most recent data was created before that, so you're still good. " or "I've got something that was created or modified on 9:22:53PM, you should download it."
With that method, you don't need to worry about who's who. Instead, you need to have modification/creation times on the data you're checking for staleness. You also need to make sure that the clients clock is synchronized correctly - better yet, don't trust the clients date and time information. Maybe utilize your new_data_check.php to provide the script with a timestamp it can pass along on subsequent requests.

Categories