Building a Secure Airport Transfer Booking System with PHP and MySQL
Building a booking website is much more than creating a form and saving customer information to a database. A reliable airport transfer platform needs a pricing engine, a booking workflow, payment verification, an administration panel, and a secure way to manage customer data.
In this article, I'll explore how to approach the architecture of an airport transfer booking platform using PHP and MySQL, with deployment on a typical cPanel hosting environment in mind.
- Start with the right architecture
For a project that must run on shared hosting, the technology stack needs to be practical as well as maintainable.
A reasonable starting point is:
- PHP 8.2 or a compatible supported version
- MySQL or MariaDB
- PDO for database access
- HTML, CSS, and JavaScript
- Composer for dependency management
- An MVC-style application structure
The application can be organized into several layers:
app/
Controllers/
Models/
Services/
Repositories/
Middleware/
Views/
config/
database/
migrations/
seeds/
public/
index.php
assets/
routes/
storage/
logs/
cache/
tests/
The exact structure depends on whether you choose Laravel or a lightweight custom PHP framework.
The important principle is separation of responsibilities. Controllers should handle HTTP requests, services should implement business rules, and repositories or models should manage database operations.
- Design the database around the business
A booking platform has several connected entities.
A simplified database design might include:
Table| Purpose
users| Admins, staff, and driver accounts
customers| Passenger contact information
locations| Airports, hotels, and destinations
routes| Supported pickup and destination combinations
vehicles| Vehicle categories and capacities
route_prices| Configurable prices by route and vehicle
bookings| Reservation details and status
booking_extras| Child seats and optional services
payments| Payment method, amount, and status
drivers| Driver profiles
driver_assignments| Drivers assigned to transfers
content_translations| Localized page content
Use foreign keys, indexes, and appropriate unique constraints to maintain data integrity.
Confirmed bookings should also store a snapshot of the agreed route, vehicle, price, currency, and extras. Otherwise, changing a route's current price could accidentally affect how an older booking is displayed.
- Keep pricing on the server
One of the most important design decisions is where prices are calculated.
Never trust a total price submitted by the browser. A user can modify JavaScript variables or send a custom HTTP request.
Instead, send the selected route, vehicle, dates, and extras to the server. The server should validate these values and calculate the price using trusted database records.
A simplified example:
function calculateTransferPrice(
int $basePriceCents,
int $extrasPriceCents,
int $discountCents = 0
): int {
if (
$basePriceCents < 0 ||
$extrasPriceCents < 0 ||
$discountCents < 0
) {
throw new InvalidArgumentException(
'Price values cannot be negative.'
);
}
$total = $basePriceCents + $extrasPriceCents;
if ($discountCents > $total) {
throw new InvalidArgumentException(
'Discount exceeds the total price.'
);
}
return $total - $discountCents;
}
This example demonstrates integer-based money arithmetic. In a real application, the server must also retrieve the applicable prices, validate the discount, determine the currency, and apply the configured pricing rules.
Production pricing logic should account for seasonal rates, return transfers, extra stops, taxes where applicable, and vehicle capacity.
- Build the booking workflow as a state machine
A booking should not be represented by a single boolean such as "confirmed".
Consider keeping booking status separate from payment status.
For example, a booking might have these states:
- Pending
- Confirmed
- In progress
- Completed
- Cancelled
Payment status could independently be:
- Unpaid
- Pending
- Paid
- Failed
- Refunded
This distinction matters because a customer can have a confirmed pay-on-arrival booking without having paid online.
Define valid state transitions and enforce them on the server. For example, a completed booking should not silently return to pending through an ordinary edit request.
For operations that involve several database writes, use transactions to prevent partially saved bookings.
- Handle online payments securely
Supporting online payment introduces additional responsibilities.
A robust integration should:
- Create a payment session using the server-calculated amount.
- Redirect the customer to the payment provider's hosted checkout when appropriate.
- Receive the provider's webhook.
- Verify the webhook signature.
- Confirm the transaction with the provider where required.
- Update the payment record idempotently.
- Update the booking according to the payment result.
A browser redirect to a success page is not proof that a payment succeeded.
Webhook handlers must also tolerate duplicate delivery. The same payment event should not create multiple payment records or trigger repeated business actions.
For a shared hosting environment, verify that the selected payment provider supports the required webhook workflow and that the hosting account allows secure outbound HTTPS requests.
Never store raw card details in the application database.
- Secure the administration panel
An admin panel can manage routes, prices, vehicles, bookings, customers, and drivers. It also creates a significant security boundary.
At minimum, implement:
- Password hashing with "password_hash()" and verification with "password_verify()".
- PDO prepared statements.
- CSRF protection for state-changing requests.
- Output escaping to prevent cross-site scripting.
- Server-side role-based authorization.
- Secure session cookies.
- Login rate limiting.
- Audit logs for sensitive changes.
- Secure password reset flows.
Authorization must be checked on every protected server endpoint, not only by hiding buttons in the interface.
For example, a driver should only be able to access assigned transfers. A regular staff account should not automatically have permission to change payment records or manage administrator accounts.
- Support multiple languages correctly
An airport transfer business may serve customers who speak different languages.
For example, English and German versions could use separate URLs:
/en/airports/antalya
/en/destinations/alanya
/de/flughaefen/antalya
/de/reiseziele/alanya
A multilingual implementation should localize more than the visible page text. Booking labels, validation errors, email notifications, metadata, and destination descriptions also need translations.
Use language-specific canonical URLs and reciprocal "hreflang" annotations for equivalent pages.
Do not automatically assume that every English page has a published German equivalent. Only include valid, accessible language alternatives in the annotations and sitemap.
- Make SEO part of the architecture
Technical SEO is easier to implement correctly from the beginning than to retrofit later.
The platform should generate:
- Unique titles and meta descriptions.
- Canonical URLs.
- XML sitemaps containing indexable pages.
- A correct "robots.txt".
- Breadcrumb navigation.
- Descriptive internal links.
- Valid structured data where appropriate.
- Appropriate HTTP status codes.
- Useful 404 pages.
Airport and destination pages should contain genuinely useful information, not just a location name and a repeated paragraph.
Private booking pages, admin routes, and internal search results should not become indexable landing pages.
- Deploy safely on cPanel
A working local application is not necessarily ready for production.
Before deployment, check the PHP version, required extensions, database privileges, Composer availability, document root, rewrite support, SSL certificate, SMTP configuration, and cron availability.
Where possible, keep application code, environment secrets, logs, and backups outside the public web root. Expose only the necessary public entry point and static assets.
A practical deployment sequence is:
- Create the database and restricted database user.
- Upload the application.
- Configure environment variables securely.
- Run database migrations.
- Create the first administrator through a secure setup process.
- Configure HTTPS and email.
- Configure payment sandbox credentials and webhooks.
- Test the complete booking workflow.
- Verify backup and recovery procedures.
- Switch to production payment credentials only after successful testing.
Do not assume that every cPanel provider supports the same features. Deployment instructions should reflect the actual hosting environment.
- Test the complete customer journey
Test more than individual pages.
A useful end-to-end scenario is:
- A customer selects an airport and destination.
- The system validates the requested route.
- The customer selects a suitable vehicle.
- The server calculates the price.
- The customer enters passenger details.
- The booking is saved with a unique reference.
- The customer chooses pay-on-arrival or online payment.
- The payment state is verified where applicable.
- The administrator sees the booking.
- The customer receives the correct confirmation.
Also test duplicate submissions, invalid prices, unsupported routes, unauthorized booking access, failed payments, duplicate webhooks, and German-language pages.
Conclusion
A reliable airport transfer platform is a combination of business rules, data integrity, secure payments, operational tools, and a well-designed customer experience.
PHP and MySQL can provide a practical foundation for this type of application, including on compatible cPanel hosting. The key is to keep pricing and authorization on the server, model booking and payment states explicitly, and test the entire workflow before going live.
The best starting point is a small but complete vertical slice: one route, one vehicle category, one valid price, one booking, and a working admin view. Once that flow is reliable, expand the platform with more routes, languages, vehicles, payments, and SEO landing pages.
Disclosure: AI assistance was used to help prepare this article. The architecture and examples should be validated against the requirements and hosting environment of the actual project.
Top comments (0)