There is another way, but it requires Ajax. No storing of credit card numbers AND a review page.
Page 1: Form to capture shipping, billing and credit card information. Ensure that the "body" of the page, including the form, is in a DIV with a unique ID to allow you reference it with JavaScript.
Page 2: A file on the server that will accept a GET/POST request with the form fields in it and return a properly formatted "review" page to your liking.
Checkout process:
- Validate form.
- Copy credit card related fields into global JavaScript variables.
- Loop through form fields and build a query/data string with the form fields (excluding credit card related fields)
- Do an Ajax request to the "review" page, passing the query string of form field/values with it. Render on server and return to calling Ajax function.
- Take rendered HTML review page returned from Ajax request and replace content in your "DIV" container with it (effectively replacing the form and other elements with the review HTML).
- Use JavaScript to copy the credit card data stored in global JS variables into the appropriate place on the review page. You may also copy the card data to hidden form fields to submit when the user "completes" the order from the "review" page.
- User submits order from review page to server, performing card validation with the processor's gateway and then either placing the order, or returning to error handling page, never having stored the card details.
- I would recommend that the "place order" function perform a full HTTP request (rather than Ajax) in order to reload the browser with a page that no longer has the card data stored in global JS variables.
It's a bit of a hack, but when done properly, it's 100% seamless to the user and allows you a single transmission of the card data with no need to assume risks with temp DB storing, etc.