Return to projects
Project deep dive· Deployed coursework·

Paper & Pixels

Full-stack PHP publishing platform

A deployed multi-user blog built with PHP and MySQL, featuring authentication, role-aware content management, Markdown authoring, image uploads, likes, comments, search, and tags.

PHP
MySQL
Tailwind CSS
PHPMySQLTailwind CSS
Paper & Pixels project cover
Project frame

Overview

Paper & Pixels is a deployed multi-user publishing platform built for the IN2120 Web Application Development course. It uses PHP 8, MySQL, server-rendered pages, Tailwind CSS, and small JavaScript enhancements rather than a full-stack framework.

The project implements the complete publishing loop: account registration, login, guest browsing, role-aware post management, Markdown authoring, cover uploads, tags, search, likes, comments, and administrative moderation.

Building it with direct PHP and SQL made the web's request lifecycle visible. Sessions, redirects, multipart uploads, prepared statements, database relationships, authorization checks, and JSON endpoints are explicit rather than hidden behind an ORM or authentication package.

Data model

The relational schema centers on four records:

TableResponsibility
usersIdentity, password hash, email, and role
postsAuthor, title, Markdown content, tags, cover image, and timestamps
commentsUser-attributed discussion under a post
likesMany-to-many interaction between users and posts
users 1 -------- * posts
users 1 -------- * comments
posts 1 -------- * comments
users * -------- * posts through likes

Database access is configured from environment variables. MySQLi strict reporting is enabled, the connection uses utf8mb4, and connection failures are logged server-side while the visitor receives a generic error.

Authentication and roles

Registration validates password confirmation and requires upper-case, lower-case, and numeric characters with a minimum length. Passwords are stored using PHP's password_hash() and checked with password_verify() during login.

Prepared statements handle account lookup and creation, preventing user input from being concatenated into authentication queries. Session state carries identity and role information across requests.

The product distinguishes three access levels:

  • guests can browse published content;
  • users can create posts and manage their own work;
  • administrators can moderate across the platform.

Authorization helpers protect authoring routes. The distinction between hiding a button and verifying ownership on the server was one of the core lessons of the project.

Publishing workflow

The authoring page accepts a headline, comma-separated tags, Markdown body, and optional cover image. SimpleMDE provides a focused Markdown editor, while the PHP handler stores the post through a prepared statement and redirects to the new article after creation.

authenticated author
  -> title, tags, Markdown, cover image
  -> uploaded file stored with generated name
  -> post row inserted with author ID
  -> redirect to rendered article

Edit and delete operations use the same session and ownership boundaries. Public pages render the article, author, tags, interactions, and discussion together.

Likes, comments, and discovery

Likes are handled through a small JSON endpoint. It verifies that the visitor is logged in, validates the numeric post ID, checks whether the relationship exists, inserts or deletes the like, and returns the updated aggregate count.

Search and tag filters make posts discoverable beyond chronological browsing. Comments retain user attribution and timestamps, providing a second relational workflow alongside publishing.

This combination turned the assignment from a CRUD form into a small social publishing system: identity affects permissions, content produces interactions, and interactions feed aggregate UI state.

Deployment

The application is deployed on PHP-compatible shared hosting with MySQL. Production credentials are loaded from an environment file, HTTPS is enforced through .htaccess, and rules prevent direct web access to sensitive configuration files.

Deploying to conventional shared hosting required working within a different operating model from serverless JavaScript platforms: database import through phpMyAdmin, writable upload directories, Apache rewrite rules, environment placement, and relative PHP include paths all matter.

Security review and next improvements

The implementation includes useful fundamentals—password hashing, prepared statements, output escaping in forms, generic database errors, role checks, HTTPS redirection, and protected configuration.

A production hardening pass should add:

  • CSRF tokens for post, comment, authentication, and like mutations;
  • server-side MIME inspection, size enforcement, and image re-encoding for uploads;
  • randomized session rotation after authentication;
  • stricter cookie attributes and rate limiting;
  • pagination for posts, comments, and search results;
  • a mature Markdown sanitizer with an explicit HTML policy;
  • automated authorization and upload tests.

The current upload flow generates unique filenames but relies mainly on the browser's accepted file types. File validation must never depend only on the client.

What I learned

Paper & Pixels gave me a direct understanding of server-rendered web applications. Every request has an observable path from form data to authorization, SQL, session updates, redirect, and HTML response.

It also showed that “full stack” includes operational details. A feature is not finished when it works locally; database character sets, upload permissions, HTTPS rules, secret placement, production error handling, and hosting constraints are part of the application.

Explore the project