I have a member sign-up process which requires a monthly subscription payment. I have a script running which can update my member's database using an IPN script. I am curious about the best way to go about validating a new user once they have successfully submitted payment. Here is the work flow that I have envisioned for this process, but please advise if you have done something similar in a more direct fashion.
Step 1) New User completes signs up form which includes their username and password.
At this point I would take the the password they generated and manipulate it in the database. This way if they tried to log in they would be denied access.
Step 2) User submits credit card payment through a third party processor. Third party processor sends out IPN to update database.
Using the IPN script, once their payment method is validated I would set the password back to the one that they created.
Step 3) User is validated with a successful payment.
Since their password is back to the one they initially wanted, the user can login.
I don't see any reason this would not work, but it seems clunky. Is there a better way? Thanks.
Rather than not setting their password correctly, why not just have an extra field named 'paid' and default that to '0' and then if/when they pay it's set to '1'.
Then in the login script simply make sure that field is set to '1' when they try to login.
I'm assuming they buy 30 days of subscription? If so when the payment comes in set a field called DaysLeft to 30, then every day you subtract 1 from that field. When a user tries to log in, it gets their name and verifies their password, then check to make sure they have days left DaysLeft > 0. This allows them to log in.
It would be a simple stored procedure that you can run every day, and handles every user. It also keeps track of how long until they need to pay again. You could set a reminder on login when they have less than 5 days left or something. Just some ideas
Related
I'm not familiar with PHP / MySQL and Emails. And I'm pretty sure this question has been asked somewhere already, but I cannot find it. So I apologise if this is troubling and thank you in advance!
Is it possible to do something that user has to click on a link in email first before the user is added into database???
And you know how, for some websites, they have a unique web address for each email validation (Shown in red on the picture)? How do they create a webpage that's unique in for every email ?
Picture credited: https://kayako.atlassian.net/wiki/download/attachments/5734920/subs-validation.png?version=1&modificationDate=1291956283000&api=v2
Thank you a lot for the attention! If it's possible, I prefer not having straight scripts that I can copy and paste because I like to find out myself :P But please do give me some hints because I'm totally lost.
If there's anything that's not clear, please tell me, I'll try my best to clarify it!
The Registration process
User fills out a form online with basic details including an email and password, and submits the form to register.php
register.php adds user info to a temporary location, such as a pending_users table which has all the fields the user submitted along with an expiration and an activation_code fields. This code can be any random, impossible to guess value. eg: hash('sha1', mt_rand(10000,99999).md_rand(10000,99999)). Just don't do anything predictable such as hash the current time, or the username
register.php sends an email to the user with a URL that will link to activate.php and that includes the activation code. eg: example.com/activate.php?code=a2ef24... The email should also inform the user of the expiration (1 to 12hrs validity seems ok to me)
When user clicks the link, she triggers a GET request to activate.php. In doing so, the user proves ownership of the email address
activate.php gets the code from the request parameters, eg: $code=$_GET['code']. With that code, the script queries the pending_users table for the record matching that code.
If the code is found, check that it hasn't expired before proceeding. Expiration prevents someone else much later who gets in the user's account from completing the registration.
If the code is valid, capture the user details from the matching record and delete that record from pending_users table.
Write a matching record in the regular users table. Until this is done, the user could not log in because login script only checks the users table, and ignores the pending_users table.
Registration complete.
Security Note I:
For your users' protection, never store passwords in cleartext. When you receive it from the registration form (eg: $_POST['pwd'], do:
$pwd = $_POST['pwd'];
//first validate; it should meet minimum requirements
$pwd_hash = password_hash($pwd, PASSWORD_DEFAULT); // <- the hash gets stored
Later, to verify the password, do:
password_verify($cleartext_pwd, $pwd_hash);
It will return true if the password is correct; false otherwise.
Security Note II:
For your protection, never insert user supplied values directly in your DB queries. This means any value that arrives from the outside. Not just usernames, emails, passwords... but also values that you're getting back from the user such as activation_code above or cookie values or headers (eg User-Agent). Instead, learn to use prepared statements. This will protect you from SQL injection.
Not sure if it's possible to add datas in database after the validation...
When I want to do something like that, I create a data in the users table (or metas users table) like "validate".
If this data is "true", then the user already did the validation and he can use his account. If it's still set on "false", the user didn't validate his account : he can't use it.
With that, you have to make sure the account is validate when the user tries to log in, but it's not a big deal ^^
Hope it's usefull.
Those are not a unique websites, there is only one script validating the registration finalization. The incoming requests (when the user has clicked the link) are routed all to the same script by means of server side "request rewriting", so that the random token value is available as an argument (parameter) to the script execution.
What the script does: it checks if that random token value does exist in the database where it has been generated and stored before when the user actually registered.
The only thing left to do for that script is to remove the confirmation random token and/or set a flag indicating that the registered use has actually confirmed his identify (email address) by clicking the link.
Easy and straight forward. Hard to bypass, since you cannot guess what random token value has been generated for what registered user without receiving the email. However take into consideration that it is trivial for an attacking script to use anonymous email services (one time email addresses) to receive and evaluate such a confirmation request, if the process is known to the attacker.
I'm working on a project where I'll fetch items from a database for different users and display them my their own page. At the minute their items are got by getting the username query string from the url then selecting the data relating to that username. The problem I'm having is the actual payment bit. Stripe payment itself isn't' the problem, it's pointing that payment to the right direction. Stripe uses a stripe user ID to tell where the payment should go, that stripeUserID is stored in the database and linked to their own user ID.
At the minute it goes users item page>get items page> users item page(populated) and when another person buys something here it then goes to the payment php file. I could get an identifier for a user by either storing their username or userid in a session variable or even using the current query string stored in a session variable, the problem here is if they loaded another users item page at the same time, the variables would be overwritten sending the payment to the wrong location. Another idea was to get the userid from the getitems page and store it in a form on the items page then post it in a hidden input field, however, this could be changed by the user if they knew how. I could put some validation in the payment php file to check if the posted userid is correct but what could I even compare it to to check? I'm confused as to how I actually make a secure dynamic identifier which can be sent from different pages and not be changed.
I have written a PHP code. When a user submits the form, it saves all information in session and redirect user to PayPal Payment page. When user successfully makes Payment, Paypal sends user to Return path. The return path page gets values from session and enter user in database. But, after submitting the form if user manually visit Return path URL, it will save information in database without getting payment. Any solution for this?
Without sharing your code, it's difficult to give an accurate answer, but based upon what you've provided...
Paypal allows you to provide 2 URLs to it's submission, a return_url and a notify_url.
With the return_url, it should be for display only (e.g. www.website.com/order_complete/), and should NEVER have any functionality behind it, such as updating an order status for the exact reason you've asked the question. Therefore, when you query the order in the DB, it would still be marked as unpaid, and then you can put in the appropriate response.
Validating the order is what the notify_url is for (see https://developer.paypal.com/docs/classic/products/instant-payment-notification/ for more information). Basically, this does a checkback to paypal to confirm that the order you have attempted to make has actually gone through successfully, and then you do your DB updates (setting the order to complete).
The solution for you would be to remove the 'order updating' functionality from the return_url, and implement the IPN.
I am hoping to use the PayPal Pro Hosted Solution to handle payments for my website, and what i would like to achieve is that user submitted data is NOT inserted into my database until PayPal confirms i have received payment for their entry.
From what I've read, i understand the IPN is the best way to achieve this.
So at the moment, users are entering their data with a form, which i am then previewing to them, and if they approve their entry, i am inserting into a database (using PHP/MySQL). The form data at the moment is being passed along in SESSION variables and working fine. The file process is:
User enters data
User is presented with their entered data on a knew page and if they approve...
They click a button which handles the insert into the database.
However what i would like to do is, if they approve their entry on the preview page, when they click approve, instead of the database being updated there and then, send them to PayPal to make the payment and only update the database with their entry if the payment is approved, like this:
User enters data
User is presented with their entered data on a knew page and if they approve...
They click a button which takes them to the payment page
If payment is received, their data is added to the database.
Does anyone have any experience of this type of approach point me in the right direction or give me some guidance on how to go about this please?
I have looked over the PayPal documentation but because I'm new to this, i need things explained in a pretty simple manner.
My original idea was just to store the form is SESSION variables but i will lose this by redirecting people to the payment page. Another thought i had was to create an identical database to what i already have as a temporary holding stage for data, then if the IPN comes back approved, move the data to the final hosting database, but this seems like over engineering the problem a bit.
I hope someone can help.
Thanks
Dan
Using PayPal IPN seems to be the best solution in this case.
In my opinion, using temporary table seems to be the best solution. It'll be following KISS rule.
Please consider using following scenario:
user enters the data
the form is being submitted
data is stored in temporary table in database
while redirecting to PayPal website you can add custom field that will be used to identify user when we be back on your page
update transaction status
insert data in the table of your needs
It seems to be the simplest solution.
One matter to recognize regarding IPN is that it is an 'Asynchronous' response from PayPal - it is not in the user's browser session, so session variables will not work if you are relying exclusively on IPN (other than if you receive the IPN response and then match it to the user's session). PayPal also offers PDT (Payment Data Transfer) which is an 'in-session' response which could return the user to your site.
I would not rely exclusively on IPN for payment notifications (see my answer in the following SO topic) Can one rely on Paypal IPN solely to record purchases?.
Our system uses a combination of both IPN and PDT, with the 'cart' data stored in a DB (as your 'temporary' record) until notification of the completed payment by either PDT or IPN - whichever arrives first which completes the transaction (your 'permanent' database insertion) and deletes the 'temporary' record (so a subsequent IPN or PDT does not trigger a duplicate transaction).
My original idea was just to store the form is SESSION variables but i will lose this by redirecting people to the payment page.
Not necessarily. Sessions can generally persist for as long as the current browser (session) is open. This is not the same as "as long as the current page is viewed" provided you set the session cookie correctly. You can if you do it right have the sessions persist for days, months, years...
Another thought i had was to create an identical database to what i already have as a temporary holding stage for data, then if the IPN comes back approved, move the data to the final hosting database, but this seems like over engineering the problem a bit.
No this is not overkill.
It deals with the situation where a transaction is not completed. This could occur for a number of reasons, for example your user goes to lunch and forgets to complete the process before the session times out (the default is 20 or so minutes) or where there is a problem with the Paypal end (unlikely but you have to presume it can occur) or where there is a general network issue (isp goes down mid transaction), or where your mobile users goes out of network coverage. Anything can disturb a transaction and you need to have a fall-back position. Otherwise it becomes annoying for you (because you don't know anything about what interrupted the transaction and at what point) and for your user who has to start over again.
Having a temporary database allows you to monitor incomplete transactions and if necessary prompting the user to complete if they do not do so within a given period of time.
How would I go about creating a system in which a user must click a link to validate something.
Let us say that on my website, each user has their own folders that are not shared. I want their to be an option for each user on their account page in which they can create a trust with another user to access each others folders. Perhaps by typing in the name of the user in which they want to create a trust with.
So in this case, user Jim types into his create trust input box "Tom", and so a trust needs to be established. I figure, A) There will need to be something that stores Jim's request, B. then assigns it as unverified, C. and finally then sends the vaerification link to Tom. Tom then recieves a message somehow? (not sure yet), perhaps with something to check and see if there are any verification links for Tom? and then Tom clicks the verification link sent to verify that he wants to also establish a trust with Jim. once Tom clicks it, A. tells whatever it is that stored Jim's request that Tom accepted, B. assigns validation as verified C. notifies Jim that Tom's request has been accepted or declined.,
HOWEVER there also needs to be a way to remove the validation storage (whatever it will be) if 24 hours runs up, or Tom declines Jim's request.
Can anyone please help me? :)
Sounds like a good job for a database. When user A requests a share, it is entered in the database as pending. When user B is notified, he can click a link who's script will check the database for the original request, verify that it is within 24 hours, and if so, the database record us updated as accepted or declined. If 24 hours is up, the record is updated as expired.
If you're using a database, this is simple. Just generate some sort of unique ID for each request, and store the request (with status "awaiting response" or similar) in the database, then send an email to Tom with a link to one of your php pages with the unique ID of the request in the querystring.
This way, you can save update the "time accepted" field for the request to whenever Tom clicked the link in his email, and change the status to "accepted".
It is trivial to logically determine if 24 hours have passed, and you can deny access to the trusted share after this time period.
You can define a table wich has the attributes:
-Unique ID
-ID1 (Of Person 1)
-ID2 (Of Person 2)
-Validated State (TRUE OR FALSE)
-Validation Hash MD5(Name(ID1)+RANDOM(100,99999),Name(ID2))
-Date and Time of requested relationship
-Other information pertinent to the system that needs this function...
Then you proceed like you said.
1)On 12/5/2009 at 5:25pm Tom (ID=15) asks Mark(ID=21) to join his network, then your script add the data to the table as follows:
-Unique ID: Assigned automatically by autoincrement
-ID1: 15
-ID2: 21
-Validated: False
-Validation Hash MD5: MD5("Tom".42574."Mark")=bedbcfc6e679be69ff3587f15213c83f
-Date and Time: 12/5/2009 at 5:25pm
-Other information pertinent to the system that needs this function...
Be sure that, before setting the data into database, check for duplicates.
After that, erase all fields wich Date And Time is older than 24 hours =D
2)If no duplicates, Send mail to Mark with a link back to your page, including md5 hash as a Get attribute of the url. Lets sat the page name is validate.php?h=bedbcfc6e679be69ff3587f15213c83f
3)Your script validate.php recieves a request with the get parameter h=bedbcfc6e679be69ff3587f15213c83f
Proceed to chek de db.
If hash exists, and date and time is not older than 24hours, set Validated to true, and send a mail to Tom's email with the info of his new friend.
If hash does not exists, inform it to Mark throught the validation page results.
Ok. Thats all. Hope its usefull to you in some way.