Personal Portfolio Site with Contact Form
Build a personal portfolio website in plain PHP: a home page about you, a projects page showing your work in a grid, and a contact page with a form. When a visitor submits the form, the site checks the input, protects against spam, and emails the message to you using PHPMailer. Shared parts like the header and footer are written once and reused on every page. It's a practical first PHP project: you'll learn how PHP builds pages on the server, how to reuse templates with include, how to handle and validate form submissions safely, and how to send email through SMTP, all while ending up with a site you can actually use.
- Estimate
- ~8.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
PHPMailer
Project roadmap
- 01
Build the page structure
~1.5hInstall PHP 8. Create includes/header.php and includes/footer.php with the site's HTML head, navigation (Home, Projects, Contact) and footer, and three pages, index.php, projects.php and contact.php, that include them. Highlight the current page in the navigation. Run it with php -S localhost:8000. Done when: all three pages open with the same header and footer, and the menu links work.
- 02
List your projects from a data file
~1.5hStore your projects in data/projects.json: title, short description, technologies, image path and link. In projects.php, read the file with json_decode and loop over it to render a card for each project in a responsive CSS grid. Escape every value with htmlspecialchars. Done when: the projects page shows one card per project in the JSON file.
- 03
Build the contact form
~1hAdd a form to contact.php with name, email, subject and message fields, submitted with POST to the same page. Add a hidden honeypot field that real visitors never fill in, to catch simple spam bots. After a failed submission, keep what the user typed in the fields. Done when: the form submits and shows the typed values again.
- 04
Validate the input
~1.5hOn submit, trim every field and check: name and message are required, the email passes filter_var with FILTER_VALIDATE_EMAIL, the subject is at most 100 characters and the message at most 2,000. Silently ignore submissions where the honeypot is filled in. Show each error next to its field. Done when: invalid submissions show clear errors and nothing is sent.
- 05
Send the email with PHPMailer
~2hInstall PHPMailer with Composer. Read the SMTP host, port, username and password from a config file that's excluded from Git (commit a config.example.php). Send the message to yourself with the visitor's address as Reply-To, then redirect to contact.php?sent=1 to show a thank-you message, so refreshing doesn't send it again. For testing, use a local catcher such as Mailpit. Done when: a valid submission arrives in Mailpit, or your inbox.
- 06
Polish and handle failures
~1hIf sending fails, show a friendly message and log the PHPMailer error to a file, never to the page. Make the site look good on phones and desktops with CSS, and write a README with setup steps. Done when: a wrong SMTP password shows a friendly error while the real error is written to the log file.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack