How to prevent race condition in online hotel booking - php

I am writing a hotel booking software using PHP and MySQL. I am pretty much done with it but I ran into a race condition problem. For example there is only one standard room left and when 2 guests both select it it shows available to both of them. I tried fixing it by checking the room again when the guest clicks confirm before payment but that still has issues. I also tried making the room status to pending when whoever clicks the confirm first but I can't figure out how to change it back to available if the guest decides not to pay or just closes the browser. I searched SO for answers but I didn't really find a definitive answer. Thanks in advance

One solution is to add two columns to a table in the database. One column is the session ID or user ID or whatever of the user that is being offered the room. The second column is a timestamp indicating when that offer will expire.
Then, in your app, only show rooms that have an expired timestamp in the hold column. (Set the initial timestamp to 0 so that it starts out expired.) When a room is selected, check the column again. If there's an unexpired timestamp there, the user gets a "sorry, you were too slow" message. Otherwise, put a timestamp there for 15 minutes into the future or whatever, and proceed.
You see this on travel sites and ticket-purchasing sites a lot where it says something like "We're holding these seats for you for another 14 minutes. Please complete the transaction by then or it will be released blah blah blah."

I would also go with the pending state. You could save the state together with the session id of this user and have a cronjob that deletes all pending states that have expired session ids associated to them.

Related

Conference session selection via form exclusivity through radio button or jquery

My application allows organizations to create events that have sessions in multiple tracks. These tracks need not be 100% symmetrical (see example image below).
I need to make it so that a single session that might overlap multiple session times, would have a mutual exclusivity-selection relationship.
In this example, if a registrant selects the Workshop session (from 1-5pm) currently the form prevents the selection of the sessions from 1-2:30pm.
I've achieved this simply by having the name of the radio button for those 3 sessions that all start at 1pm all have the same name.
Ideally, it should also prevent the selection of the sessions from 3-4:30pm.
I cannot use the same solution (having the sessions starting at 3pm have the same name) because then it would prevent registrants from attending a session at 1pm and another at 3pm (w/o selecting the workshop from 1-5pm).
The relevant fields of my session table are as follows:
sessionID int
trackID int
eventID int
sessionName varchar
confDay int
start datetime
end datetime
order int
How can I achieve the desired result without an overwhelming amount of code?
The code to render this form can be seen at jsfiddle.net.
Not having received an answer, I ended up solving this in a way that I'm not sure is the most elegant. When I shopped the idea around to some colleagues they understood the problem and my solution wondered if there could be something more elegant but acknowledged that this solution solves the problem.
I welcome alternative approaches. Here's hoping this helps someone else.
I refer to the session setup above as "asymmetric" because the tracks do not all have the same number of sessions with the exact same timing.
The relevant columns in the session table are listed in the original question. To enable this solution, the following field was added:
isLinked int
Note1: isLinked is either 0 or the sessionID of the not-deleted session that is the one that should appear in the session list with a radio button.
Note2: isLinked is set for the deleted and not-deleted sessions that "overlap."
I have a loop that cycles over the conference_days, then tracks, then sessions (in order, up to 5 in a day). The event setup UI allows a user to soft-delete sessions that are not relevant.
In that UI, the user also specifies if a session will overlap other sessions and, if so, enable the user to set that field for deleted sessions in the same track as well.
The UI for session selection is then facilitated by the following pseudo-code to generate html and javascript to emulate the desired behavior:
foreach($conference_days as $day){
foreach($tracks as $track){
for($so=1;$so<=5;$so++){
// $so = session_order
grab the session for the current $day, track ID, and $so
if(not soft-deleted && !isLinked) { // isLinked == 0
display as normal with all details + radio button
} elseif(not soft-deleted && isLinked) {
display as normal with all details + radio button
also add javascript that when above radio button is selected
a variable* number of to-be-created, hidden, radio buttons
(below) are also selected;
*count the isLinked sessions with same ID that are soft-deleted
} else {
display nothing, but...
output a radio button with style.visiblity=hidden named in a
predictable way based on $day, $track, and $so
add javascript that to monitor changes to the radio selection in
this row so it auto-deselects the visible radio button above.
}
}
}
}

Is this good implementation of action-based user levelling system?

For now, the system should have 6 different user levels.
Each level will be gained upon user activity, for example:
Level 1 - When user register
Level 2 - When user completes a mission
Level 3 - When user completes more than one mission
Level 4 - When user donate > $X amount of money
Level 5 - When user write more than 50 comments in blog
Level 6 - When user complete quiz
And now... I'm wondering, what's the best database schema to achieve this? I should keep track of all actions related to user's activities, that's why I though about xp_events table... Something like this:
id # primary key
event # type of event, e.g. 'register', 'complete_quiz', etc.
user_id # id of user
delta # number of "exp" which will be gained after specific action
And... in users table I will keep record of current level and "exp" which each user has earned until now.
When user makes any activity, I will call a trigger which will check if user have new level unlocked.
But... I'm aware that in long term (e.g. if more levels are added), this isn't optimal solution.
Looking forward for any suggestions.
I see two obvious possibilities here.
One is to have an event table like you say, with a user ID, event ID, dollar amount (for donations), probably a date/time, maybe other data. If the only reason why you are keeping any of this data is to determine each user's level, this is simple and effective.
If you're keeping track of this data for other purposes also, you probably want to separate it into multiple tables. In such a case you would likely have other data you need to keep for each event. Like for a donation you would need dollar amounts, which I assume don't apply to comments and missions. For comments you likely need the text of the comment and some indication of the thread this comment is on or what it's subject is. For a mission -- I don't know what a "mission" is in this context, but you likely want some information about the type of mission and where it was or who they were supposed to kill or whatever. Most of this data would not be applicable to events of different types. A comment probably doesn't have a dollar amount, a mission doesn't have a thread, etc. So you'd end up with a lot of irrelevant data and bunches of null fields.

PHP application database logic flawed

I have a page on my application that is supposed to keep track of students. Once a counselor accepts the student for a in real life session. doing so the students records are then put into a table called support. My issue is that once that happens for any reason if a counselor needs to cut the session in half and place them back to the que if another counselor accepts the session then I have double, triple, quadruple (etc etc) of the same data being written to the table. Example :
is there a way that I can have it so if the session already exists in the database table called support then when the counselor hits session start, rather then inserting it updates? So an example would be :
Staff member john accepts student bobby
Staff member john has a family emergency and needs to end the session putting the student back in the que.
staff member Sara sees the student in the que and accepts the student
Rather then the session start button inserting the same session id (example 60) in again it will just update what was already done?
What I have in mind is to set up a Finish student button that will just update the support table rather then just rewrite to the table.
Does this solution seem feasible? - if not what can I do? Sorry for the way I asked this question I am trying to be as specific as possible.
EDIT : New pic for further examples :
You can alter the table to add a new attribute - "Session completed", that is by default 0, 1 if the student is accepted and currently in session, and 2 if it is completed. When a student is accepted, the 0 changes to 1, and if the student is done, councilor clicks OK, and Session Complete can change to 2 (every once in a while all students with 2 will be erased to not overpopulate the table). If an emergency happens, the councilor clicks Cancel and the 1 changes back to 0...

Synchronizing database update/checking for bidding platform

I am building a platform on php/mysql that allows users to but for a percentage of a product. Basically they choose what percentage they want to bid for and the markup price they'd like to bid at e.g. 1.2.
The issue I have is that if there are several bids placed simultaneously for the same product, I need to queue the bids so when processed only the valid ones go through. For example, if there is 20% available at a value of 1.2 and two users simultaneously bid for 20% at 1.2, the process for each bid would be:
1----- select current bids
2----- php processing to work out if bid is still available
3----- place bid
The issue here is if both of the 'check if availables' happen before either of the 'place bids' then both bids will go through and effectively cause a stock issue.
Is there a way of queuing this process so the whole of steps 1-3 happen for a bid before the next one can run.
My initial thought was to use a cache table to store all the bids and then run a cron every few seconds which will process in order of ID from the cache table and notify accordingly but this seems like it may not be viable on a high traffic system as the server would get hammered over it.
Any help much appreciated
If two bids can never be identical I would solve it at the data layer. Create a unique key on your bid table based on item_id, bid_value and whatever else needs to be unique. The second insert will fail and you can let user know they were beaten to the post
I solved this at PHP level by injecting the bid as an 'accepted bid' first so that any subsequent bids would fail. Then I ran the check to see if the bid was ok, if not the bid gets removed, if it is the table gets updated as required in place for new bids.

Publish submitted form content directly to page

I have a very basic form consisting of only two dropdown boxes (though the contents of the second dropdown vary depending on the selection made in the first). I then have a bit of text that displays under the second dropdown box once a selection has been made, and what the text says is unique to whatever selection is made.
What I want to be able to do is have this information directly publish into a table that will be included at the bottom of the same page the form is located on, once a user hits the submit button. In other words, when a user submits the form, I don't want it to simply spit the user's info back to them; I want the info to actually publish to the page in a table, so that anyone who logs in can see it, and can add their own published info to the table as well.
You could think of it sort of like a blog commenting system that automatically publishes new content to the page every time a visitor submits the form, except, instead of text areas that allow users to insert whatever they want, I have dropdown boxes that only allow them to select a certain option, and then have that selected info publish to a table.
How would I go about doing this? I have a beginner's knowledge of PHP, and almost no knowledge of javascript. But depending on how detailed and helpful of an answer that may be provided, I could work with either.
This form is only accessible to members who are logged in, and I have 6 bits of info that I want to have published into a row of 6 columns in the table every time a user hits Submit. Those 6 things are: (1) Username, (2) Time Stamp (Date & Time at which the form was submitted), (3) Selection result of 1st Dropdown, (4) Selection result of 2nd Dropdown, (5) The unique text that is displayed according to whichever selection is made in the 2nd dropdown, and (6) a second time stamp which is calculated as 30 days beyond the time generated in the 2nd column.
Any help would be appreciated. I'm experimenting with PHP a bit but my knowledge is really not advanced enough yet to really allow me to progress much of anywhere on my own.
EDIT:
I did some playing around earlier and have made a few changes. First, I'm now wanting 1 dropdown box, not 2. Second, there are 9 columns in the table, not 6. Third, I have a database with the following 4 tables:
table: members
member_id
firstname
lastname
login
passwd
rank_id
table: ranks
id
name
table: jobs
id
name
requirement_1
requirement_2
requirement_3
salary
rank_id
table: workorders
date
username
rank
job
requirement_1
requirement_2
requirement_3
salary
due_date
Here is the current site I am working on: http://www.kiithsoban.com/membership
You may use a guest login to gain access:
Username: username
Password: password
This is a personal project made for an online gaming clan (in EVE Online), with all of maybe 20 unique visitors a month, so quality and proper coding technique is not much of an issue (not at this point anyway). The primary concern is simply that it will work.
The reason I suggested posting a PHP table rather than taking the javascript route is because I already have a table created in a database (and I'm also more familiar with PHP and just want to get the first version of this online ASAP), and I already have it posting to the website as well, as you'll see on the above page. This is the "workorders" table.
You'll notice upon logging in that there are instructions on the index page referring to a dropdown box, which does not yet exist. The dropdown box will consist of 49 "jobs" to select from. When a user selects an option and submits the form, I want their selection to insert into the "job" field of the workorders table on my database; and, I also want the site to detect the additional information in the other 8 fields in order to automatically insert them as well.
I've been experimenting with one idea, but I'm not sure if it would work, or how to do it exactly. In my members and jobs tables, I've included a "rank_id" field, in which each entry will have a matching value to the "id" field in the ranks table. Now, there are 49 "jobs" to choose from, however, depending on what rank a user is, their job salary will vary (given that there are 7 ranks, 49 * 7 = 343 total possible job/salary combinations that can result from the form submission). What I want the site to do is detect the logged in user's "rank_id" (in the members table), and after the user selects a job from the drop down, find the corresponding job in the jobs table that has the same "rank_id". That, I'm assuming, would allow the site to gather the "User", "Rank", "1st Requirement", "2nd Requirement", "3rd Requirement", and "Salary" info (all of which are contained in the members and jobs tables), and then insert that info into the appropriate fields in the workorders table, so that the info will then post to the site.
At that point all I would need to worry about are the "Date" and "Due By" columns - the "date" being automatically generated as the current date when the form is submitted, and the "due by" being automatically calculated as the current date plus 30 days.
I hope that's a more helpful explanation, and not too confusing.
You will need to create an OnSubmit event for the form which will return false inside the javascript function. The function will then need to add the content to the page. I would give more detailed code if you provided a layout.

Categories