I am programming an educational web in PHP and JS and I interact with another webpage that corrects for me some programming exercises.
I don't know when this correction will finish, but this correction webpage calls a given address when the correction is available.
Is it possible to wait for that result with PHP or JS and then do some stuff (not just showing the result to the user), even if the user closes the tab?
Thanks in advance.
STEP BY STEP explanation:
A student is trying to do a programming exercise. The statement of the exercise is shown, as well as other details to complete it.
When he thinks he has reached a solution, he uploads his code. Then, he can wait (or not) for the correction to finish.
My web page uploads then the code file (with other files as well as an address to callback when it finishes) to the corrector webpage.
I keep waiting until the callback is made.
When the correction is finished, I do some stuff like assigning a grade to the student and, if he/she stayed on the same page, he/she can see details of the correction.
The correction is done by another webpage and I don't know when it would finish, but when it finishes it calls a given adress (for example: www.example.com/ex1sub1usr1 ).
The doubts are between step 2 and 3. It is possible to do all this process with PHP/JS? If not, what are the alternatives?
Updated Answer
Create a PHP script on your server which updates your grade database when visited with a specially formulated URL, eg. http://yourserver.com/update.php?user=2429&sub=1&ex=1
specify this as the target URL when you submit for correction
if you are restricted to your /ex1sub1usr1 format then just use regex to parse the URL
When user refreshes (or returns to your site) the data should be appropriately pulled from your PHP backend
For bonus points, you could have your submission screen (or the entire website) intermittently poll another PHP script URL on your server (with XHR) for an "updated" flag, and live update the page.
Considerations
Your only major concern will then be ensuring that the form data (ie. their code) is submitted completely. Consider using XHR to submit your form data and temporarily enabling a window closure warning until upload is complete.
Original "Answer"
Since there isn't much information to go by here, I will have to make a few assumptions:
you presumably can't reliably spawn a process to watch the associated results address
you don't need to notify the user immediately (push notifications), but they need eventually see their result, eg. when they return to your page
results stay around for a while
as you mention, this must work even if the user closes the tab
Given this scenario, I would merely check the results page when the user returns to your site.
Just store the results address in session vars - either via PHP or a cookie - then when the user returns you can perform any unfinished checks and update accordingly.
NB: Should further information surface in the question I will gladly provide further details
You can perform all necessary actions on a script behind the given address that is called by the remote website after the excersises have been corrected.
It is absolutely not possible to show/do anything on client side if the user has closed the tab.
Related
Background and Problem
I have a system that has core users augmented by some minor contributors who only need to be able to provide approvals for certain things. To support this, the system reacts to database changes and emails those approvers with a single button in the body of the email. This button is just a link to a unique url - something like https://myapp/response/12345-abcdefg-6789.
That "response" page is listed in the web config as not requiring a log in. Thus, the approver should only have to click on the link in the email, and the system should detect that and mark their response.
In all of our testing, this works great. All we're doing is marking the response via the page's code behind, and then displaying a message on the page that the response was received. On the surface, this seems like about as easy of a task as you can dream up.
However, we're getting false positives in production. The approvers are telling us that things are being marked as approved when they never clicked the link. I assume this has something to do with their browsers checking the links for safety or something - and by performing that safety check, it's triggering the system to record the response. Unfortunately, i haven't been able to reproduce this - even when we have some of the approvers on the phone while we try it.
The question is - what is the best strategy to avoid a false positive with buttons in an email?
Lots of companies do this kind of thing - i'm looking right now at an invitation from a friend via evite. It has Yes, Maybe, and No which appear to have the same kind of setup i described above.
Is there something i should be doing with redirects after x seconds? Is there some other javascript i should be deploying on the page? Is there some other potential cause for this? The IIS logs seem to indicate that the "fake clicks" are coming from the target users computers. Which is a bit of a relief, since it's hard to imagine how some other external machine could end up at a GUID based url that is not represented by a physical file that could be crawled over in some way.
I would like to avoid having another button for the user to click, where they would click "Approve" in the email, and then when they get to the page they have click the same thing again.
Thanks!
From my understanding there are two ways to go about it. But both methods assume the current "response" page is just an intermediary.
Add another button on the page (#
https://myapp/response/12345-abcdefg-6789 for instance) that actually
submits the response (or redirects to the actual response page). It would add an extra step for your approvers but
it should work. (You can even add a captcha there if paranoid)
Once the page is loaded, redirect to the actual response page via
javascript. The idea being if the link is automatically opened by
some kind of bot it's unlikely it runs the script.
I need to send form data to another page that will allow the user to do something in a form and return the result of that form back to the original page? Is this possible? I know it's not ideal, but the issue is that I need to make a "drop-in" solution that does not need to be integrated with other code. I know it's a very specific request and scenario.
I know how to send POST data that doesn't require any user input on the processing page. i.e. I can send POST data to 'calculate.php' which will do the math and send it back, but if I need additional user input on 'calculate.php', how can I still send it back?
An example of expected results would be:
Page #1: User enters a number and presses submit to go to next page.
Page #2: User enters a second number and presses submit to finish.
Back to Page #1: User receives sum of both numbers.
Obviously, this is a really redundant thing to do, but I'm trying to simplify the problem as much as possible.
EDIT: There a few restrictions I forgot to add.
Page #1 is not my application, I am developing Page #2 as a "drop-in" solution for Page #1. Essentially, I can only use Page #1 to call Page #2 and receive a response from it. The problem is that I need to be able to allow for user input on Page #2.
I know I can post to Page #2 and then post to Page #1 again, but what if I need to maintain the state of Page #1. For example, if there's an open Web Socket connection.
Please note, I understand that this may be impossible or extremely difficult, but if I don't ask I'll never know right?
You want it with PHP or any other language. If you are running Php on server side then you can use Global variables like $_GET and $_POST.
Page #1: Use Post/Get method to send data to second page.
Page #2: Receive all fields' values using Globe variables ($_GET and $_POST). You can use these values as default values of form fields. Now submit this data to page 1 using post or get method.
Back to Page #1: Here you will receive the data of first page from second page and newly posted data from page 2
Either of these should work:
Never leave the page - use AJAX / XMLHttpRequest to call out to other pages to process chunks of data
Do everything on page 1 using "postbacks" -- the form targets are the same page, there is a state variable like "stage=1", and you use JavaScript to add set hidden variables for any additional state that's needed.
... PHP state validation and processing for the different stages ...
... one or more blocks of HTML for the page (PHP if / else can be used to choose between multiple page views) ...
Edit for added restrictions:
Have page 2 use postbacks or AJAX to collect the additional information
I figured out a few ways to do it.
Update a Database (or Data Store of some sort, depends on security needs) and have Page #1 listen for events from a separate page (on the same server as the database). Very similar to the way PayPal's Instant Payment Notification (IPN) works. I was actually able to set up server sent events with it as well.
Essentially, Page #1 sends data to Page #2 where the user will perform the function and then Page #2 will send POST data to a listener somewhere (either on the same server or Page #1's server), the listener will update a database and Page #1 will be listening or pulling to an event handler that will send an update once the database updates.
Use JavaScript Child/Parent Window functions. This is okay if Page #1 and Page #2 are on the same server, but can get messy and browsers have a lot of restrictions and it varies depending on browser.
Page #1 will open Page #2 in a child window, after the user performs a function, Page #2 will call a function that accepts the result data on Page #1.
I am a beginner doing a single player browser game as a hobby mostly to learn javascript + php + mySQL.
For some reason I want front end to be done exclusively with javascript (drawing levels, inventory, etc.) Broadly speaking, I will be heavily manipulating DOM using jQuery.
In the backend there is a mySQL database. In the middle there is PHP which I see serving two purposes: i) speak to DB , ii) validate logic and respond to requests coming from front end (i.e javascript).
For example, intended flow is:
user wants to open a door and interacts with a relevant element in the browser - clicks on it.
Action requires validation. AJAX call to PHP saying “user wants to open the door”.
PHP check with DB to see if the user has got a key in inventory, does some backend logic checks to ensure that the right door can be opened and responds, e.g. with “1” , meaning that the user has got the right key and action is "valid". PHP could also tag this door's status in DB as "unlocked" which means that player does not need a key to pass through it again. Key is removed from inventory record in DB.
Javascript receives PHP response and renders inventory and location anew (e.g. image of a key is now missing in player’s inventory and the door is drawn differently), could possibly start a dialog on screen and perform other DOM manipulations.
I would really appreciate some advice on how to handle the “session part” of such setup. Obviously, if there is a number of players playing the game at the same time, PHP needs to look up records in DB relevant for the player, which would be normally used by userid attribute in $_SESSION.
I understand that javascript can only operate with cookies and not with sessions. I would think that a cookie could be generated with some random ID and this random ID would be written to DB. Then, when AJAX posts to PHP, this ID would be included into the post and used to look up things in DB. Then PHP would respond and front end would be changed accordingly to the player affected but not for everyone else. Am I on the right track?
Would be most happy to have some small piece of code which could illustrate this or another solution.
On another note, would such setup be OK in terms of performance or should I consider fully using .php and leave JS do to some minor job (e..g initial validation of forms before posting, etc.)?
OK, the tite seems a little confusing, so I'll try to explain more thoroughly...
The process the page does currently follows the following sequence:
- User clicks a button
- server-side code goes retrieve data from the DB and exposes said data to the client using, populating, let's say, hidden fields.
- client-side code uses this data to fire up a an ActiveX component which performs a few tasks with the data provided.
And this works fine, however, we need to optimize the process because the ActiveX component is not fit to handle high volumes of data. We need to send data into "blocks" to the component, rather them send all data at once as it is done today.
However, I just hit a roadblock here, on how can I make the page go back and forth from server to client code multiple times? Like... "user clicks a button, server retrieves first block of data, sends to client, client executes ActiveX for the first block, client requests next block, server retrieves second block, sends to client, client executes ActiveX for the second block, client requests third block... and so on"? I can't get past the first request, since I can't register a client script block 2 times and expect AJAX to handle those multiple sequential callbacks...
Or is there a way?
This sounds more like an architectural issue than anything else.
What you should be doing here is:
1) User clicks a button. This is NOT a regular submit button. Just a plain old button that executes some local javascript.
2) Local javascript makes an AJAX request to determine how many records are available.
3) That javascript then does a loop based on the number of available records divided by the amount you want to pull per chunk.
3.a) Execute AJAX request for a chunk
3.b) Throw the data into your ActiveX control - which, btw, I really would suggest you guys think about getting rid of. There are so many issues with ActiveX that it's not even funny.
4) Repeat 3.a and 3.b until completion.
You'll notice that at no point was a full post back performed. You'll also notice that you shouldn't have to register any client script blocks.
Now the draw back here is purely in the ActiveX control. Can it be instantiated from javascript multiple times in a page or are you forced to only use a single instance?
If it's limited to a single instance, then you'll need a different approach entirely.
I'm working on something similar to a pastebin (yeah, it's that generic) but allowing for multiple user editing. The obvious problem is that of multiple users attempting to edit the same file. I'm thinking along the lines of locking down the file when one user is working on it (it's not the best solution, but I don't need anything too complex), but to prevent/warn the user I'd obviously need a system for monitoring each user's edit sessions. Working with database and ajax, I'm thinking of two solutions.
The first would be to have the edit page ping the server at a arbitrary interval, say a minute, and it would update the edit session entry in the db. Then the next time a script request to edit, it checks for the most recent ping, and if the most recent was another arbitrary time ago, say five minute, then we assume that the previous user had quited and the file can be edited again. Of course, the problem with this method is that the assumption that the previous user had quited is simply an assumption. He could be having flaky wi-fi connection and simply dropped out for ten minutes, all the time with the window still open.
Of course, to deal with this problem, we'd have to have the server respond to new request from previously closed sessions with an error, telling the client side to point out to the user that his session has ended, and then deal with it by, say, saving it as another file on the server and asking the user to manually merge it, etc. It goes without saying that this is rather horrible for the end user.
So I've came around to think of another solution. It may also be possible to get a unload event to fire when the user's session ends, but I cannot be sure whether this will work reliably.
Does anybody has any other, more elegant solution to this problem?
If you expect the number of concurrent edits to the file to be minor, you could just store a version number for the file in the db, and when the user downloads the file into their browser they also get the version number. They are only allowed to upload their changes if the version number matches. First one to upload wins. When a conflict is detected you should send back the latest file and the user's changes so that the user can manually merge in the changes. The advantage is that this works even if it's the same user making two simultaneous edits. If this feature ends up being frequently used you could add client-side merging similar to what a diff tool uses (but you might need to keep the old revisions in that case).
You're probably better off going for a "merge" solution. Using this approach you only need to check for changes when the user posts their document to the server.
The basic approach would be:
1. User A gets the document for editing, document is at version 1
2. User B gets the document for editing, document is at version 1
3. User B posts some changes, including the base version number of 1
4. Server updates document, document now at version 2
5. User B posts some changes, including the base version number of 1
6. Server responds saying document has changed since the user starts editing, and sends user the new document, and their version - user will then need to perform any merging of their changes into document version 2, and post back to the server. User is essentially now editing document version 2
7. User A posts some changes, including the version number of 2
8. Server updates the document, which is now at version 3
You can still do a "ping" every minute, to get the current version number - you already know what version they're editing, so if a new version is available you can let them know and let them download the latest version to make their changes into.
The main benefit of this approach is that users never lock files, so you don't need any arbitrary "time-outs".
I would say you are on the right track. I would probably implement a hybrid solution:
Have a single table called "active_edits" or something like that with a column for the document_id, the user, and the last_update_time. Lets say your ping time is 1 minute and your timeout is 5 minutes. So a use-case would look like this:
Bob opens a document. It checks the last_update_time. If it is over 5 minutes ago, update the table with Bob and the current time. If it is not, someone else is working on the document, so give an error message. Assuming it is not being edited, Bob works on the document for a while and the client pings an update time every minute.
I would say do include a "finish editing" button and a onunload handler. Onunload, from what I understand can be flaky, but might as well add it. Both of these would send a single send-only post to the server saying that Bob is done. Even if Bob doesn't hit "finish editing" and onunload flakes out, the worst case is that another user would have to wait 5 more minutes to edit. The advantage is that if these normally work (a fair assumption) then the system works a bit better.
In the case you described where a Bob is on a bad wireless connection or takes a break: I would say this isn't a big deal. Your ping function should make sure that the document hasn't been taken over by someone else since Bob's last ping. If it has, just give Bob a message saying "someone else has started working on the document" and give them the option to reload.
EDIT: Also, I would be looking into window.onbeforeunload, not onunload. I believe it executes earlier. I believe this is the function website (slashdot included) use to allow you to confirm that you actually want to leave the page. I think it works in the major browsers except Opera.
As with this SO question How do you manage concurrent access to forms?, I would not try to implement pessimistic locking. It is simply too difficult to get working reliably in a stateless environment. Instead, I would use optimistic locking. However, in this case I used something like a SHA hash of the file to determine if the file had changed since the user last read from the file. For each request to change the file, you would run a SHA hash of the file bytes and compare it with the version you pulled when you first read the data. If had changed, you reject the change and either force the user to do their edits again (pulling a fresh copy of the file contents) or you provide a fancier conflict resolution.