Reference Guide

Database Integration: MySQL with PHP on Ubuntu 24 Server

A Comprehensive Content Guide for Web Application Development


Table of Contents

  1. Introduction & Architecture Overview

  2. Installing & Configuring MySQL on Ubuntu 24

  3. MySQL Server Administration Essentials

  4. PHP & MySQL Connection Methods

  5. CRUD Operations with PHP & MySQL

  6. Prepared Statements & Parameterized Queries

  7. Database Design & Schema Management

  8. Working with Joins & Complex Queries in PHP

  9. Transactions & Data Integrity

  10. User Authentication with MySQL

  11. Pagination, Search & Filtering

  12. File Uploads & Binary Data Storage

  13. Error Handling & Logging

  14. Security Best Practices

  15. Performance Optimization

  16. Building a Complete CRUD Application

  17. Troubleshooting Common Issues


1. Introduction & Architecture Overview

What is Database Integration?

Database integration is the process of connecting a web application's front-end and back-end logic to a persistent data storage system. In a typical LAMP stack (Linux, Apache, MySQL, PHP), the architecture follows a clear flow:

Request Lifecycle:

  1. The user's browser sends an HTTP request to the Apache web server.

  2. Apache identifies the request as a PHP file and hands it to the PHP interpreter.

  3. PHP executes the script, which may include SQL queries sent to the MySQL server.

  4. MySQL processes the queries and returns result sets to PHP.

  5. PHP formats the data into HTML (or JSON) and sends it back through Apache.

  6. The browser renders the final response for the user.

Why MySQL?

MySQL is one of the most widely deployed relational database management systems (RDBMS) in the world. It powers major platforms including WordPress, Facebook, Twitter, and YouTube. Key advantages include open-source licensing, excellent performance, broad hosting support, a mature ecosystem of tools, and strong community documentation.

Why Ubuntu 24?

Ubuntu 24.04 LTS (Noble Numbat) provides long-term support through 2029, making it an ideal production server environment. It ships with modern versions of PHP (8.3+), MySQL (8.0+), and Apache (2.4+), ensuring compatibility with current web development standards and security patches.

PHP's MySQL Extensions: A Brief History

PHP has offered several extensions for MySQL connectivity over the years:

Extension
Status
Notes

mysql_*

Removed (PHP 7.0+)

Original procedural API. No prepared statements. Completely insecure by modern standards.

mysqli_*

Active & Recommended

"MySQL Improved." Supports both procedural and object-oriented syntax. Full prepared statement support.

PDO (PHP Data Objects)

Active & Recommended

Database-agnostic abstraction layer. Works with MySQL, PostgreSQL, SQLite, and many others. Named and positional placeholders.

Course Standard: Throughout this guide, we will primarily use MySQLi (object-oriented) for direct MySQL work and introduce PDO for comparison. Both are industry-standard approaches.


2. Installing & Configuring MySQL on Ubuntu 24

Step 1: Update the System

Always begin by updating the package lists and upgrading installed packages:

Step 2: Install MySQL Server

Verify the installation and check the running version:

Step 3: Secure the Installation

MySQL ships with a security script that walks you through hardening the default configuration:

This interactive script will prompt you to:

  • Set up the VALIDATE PASSWORD component — Choose the password validation policy level (LOW = 8+ chars, MEDIUM = mixed case + numbers + special, STRONG = dictionary checks).

  • Set/change the root password — Create a strong root password.

  • Remove anonymous users — Answer Y to prevent unauthenticated access.

  • Disallow root login remotely — Answer Y for security (root should only connect from localhost).

  • Remove the test database — Answer Y to delete the default test database.

  • Reload privilege tables — Answer Y to apply changes immediately.

Step 4: Install PHP and the MySQL Extension

This installs:

  • php — The PHP interpreter (version 8.3+ on Ubuntu 24).

  • php-mysql — The MySQLi and PDO MySQL drivers.

  • php-cli — Command-line PHP for testing scripts without Apache.

  • libapache2-mod-php — The Apache module that allows PHP processing.

Verify PHP installation:

Verify the MySQL extensions are loaded:

Step 5: Restart Apache

Step 6: Test PHP Processing

Create a test file to verify Apache is processing PHP correctly:

Navigate to http://your-server-ip/info.php in a browser. You should see the PHP information page. Look for sections labeled mysqli and PDO to confirm the database drivers are loaded.

Security Warning: Always delete info.php after testing. It exposes sensitive server configuration details.

Step 7: Configure MySQL for PHP Access

By default, the MySQL root user authenticates using auth_socket (OS-level authentication), which means PHP scripts cannot connect as root using a password. You need to either change root's authentication method or (recommended) create a dedicated application user.

Option A: Create a Dedicated Application User (Recommended)

Best Practice: In production, never grant ALL PRIVILEGES on *.*. Instead, grant only the specific permissions needed on specific databases. The above is acceptable only in a development/learning environment.

Option B: Change Root Authentication (Development Only)

Step 8: Verify the Connection from Command Line


3. MySQL Server Administration Essentials

Managing the MySQL Service

The MySQL Configuration File

The primary configuration file is located at /etc/mysql/mysql.conf.d/mysqld.cnf. Key settings to be aware of:

After modifying the configuration file, restart MySQL:

Creating Databases and Users via Command Line

Useful Administrative Commands

MySQL Log Files on Ubuntu 24

Log File
Location
Purpose

Error Log

/var/log/mysql/error.log

Startup errors, crashes, warnings

General Query Log

/var/log/mysql/general.log

Every query executed (verbose, disable in production)

Slow Query Log

/var/log/mysql/slow.log

Queries exceeding long_query_time threshold

Binary Log

/var/log/mysql/binlog.*

All data-modifying statements (used for replication and recovery)


4. PHP & MySQL Connection Methods

Method 1: MySQLi (Object-Oriented)

This is the most common method for MySQL-specific applications. The object-oriented syntax is cleaner and preferred over the procedural alternative.

Method 2: MySQLi (Procedural)

The procedural approach uses functions instead of objects. It works identically but is considered less elegant:

Method 3: PDO (PHP Data Objects)

PDO provides a database-agnostic abstraction layer. If you ever switch from MySQL to PostgreSQL or SQLite, your code changes are minimal.

Creating a Reusable Connection File

In real applications, you never duplicate connection code. Create a single configuration file that all scripts include:

config/database.php

Usage in another script:

MySQLi vs. PDO: When to Use Which

Feature
MySQLi
PDO

Database Support

MySQL/MariaDB only

12+ databases (MySQL, PostgreSQL, SQLite, etc.)

API Style

Procedural + OOP

OOP only

Named Parameters

No (positional ? only)

Yes (:name and ?)

Prepared Statements

Yes

Yes

Fetch Modes

Limited

Extensive (FETCH_ASSOC, FETCH_OBJ, FETCH_CLASS, etc.)

Multiple Statements

multi_query() support

Not natively supported (safer)

Performance

Slightly faster for MySQL

Negligible difference

Portability

Not portable

Highly portable

Recommendation

MySQL-only projects, legacy codebases

New projects, multi-database environments


5. CRUD Operations with PHP & MySQL

CRUD stands for Create, Read, Update, Delete — the four fundamental operations for any database-driven application.

Setting Up a Sample Database

First, let's create the database schema we'll use throughout these examples:


CREATE — Inserting Data

Simple Insert (MySQLi)

$conn->insert_id returns the auto-generated ID from the most recent INSERT operation. This is essential when you need the new record's ID immediately after creation.

Insert with Prepared Statement (MySQLi) — The Correct Way

Insert with PDO

Notice: PDO supports named placeholders (:first_name) which makes the code more readable than positional ? marks, especially for queries with many parameters.


READ — Retrieving Data

Fetch All Rows

Critical: Always use htmlspecialchars() when outputting database values into HTML. This prevents Cross-Site Scripting (XSS) attacks by converting special characters like <, >, ", and & into their HTML entity equivalents.

Fetch Methods Comparison

Fetch a Single Record by ID

Fetch with PDO


UPDATE — Modifying Data

Important: $stmt->affected_rows returns the number of rows actually changed. If you run an UPDATE with the same values that already exist, affected_rows will be 0 even though the query executed successfully. This is expected behavior.

Update with PDO


DELETE — Removing Data

Soft Delete (Best Practice)

In production applications, records are rarely physically deleted. Instead, use a "soft delete" by setting a flag:

Then modify all SELECT queries to filter:


6. Prepared Statements & Parameterized Queries

Why Prepared Statements Are Non-Negotiable

Prepared statements are the single most important security measure for database-driven applications. They completely prevent SQL injection attacks by separating SQL logic from user-supplied data.

The SQL Injection Problem

Consider this dangerously vulnerable code:

If a malicious user submits the username as admin' --, the query becomes:

The -- is a SQL comment that disables the password check, giving the attacker access to any account.

Even worse, submitting '; DROP TABLE users; -- could destroy your entire table:

The Prepared Statement Solution

With prepared statements, the database engine treats the ? placeholders as data positions, not SQL code. No matter what the user submits, it will always be treated as a literal string value, never as executable SQL.

MySQLi Prepared Statement Lifecycle

Bind Parameter Types Reference

Type Code
PHP Type
MySQL Type
Example

s

string

VARCHAR, TEXT, CHAR, DATE, DATETIME

"hello", "2024-01-15"

i

integer

INT, TINYINT, SMALLINT, BIGINT

42, -7

d

double

DECIMAL, FLOAT, DOUBLE

3.14, 99.99

b

blob

BLOB, LONGBLOB

Binary data (file contents)

PDO Prepared Statement with Named Parameters

PDO with Explicit Type Binding

Handling Dynamic WHERE Clauses Safely

A common challenge is building queries where the WHERE conditions depend on user input (e.g., a search form with optional filters):


7. Database Design & Schema Management

Data Types Quick Reference

Numeric Types

Type
Storage
Range (Signed)
Use Case

TINYINT

1 byte

-128 to 127

Boolean flags, small counters

SMALLINT

2 bytes

-32,768 to 32,767

Zip codes, small IDs

INT

4 bytes

-2.1B to 2.1B

Primary keys, counts

BIGINT

8 bytes

±9.2 quintillion

Very large IDs (Twitter, etc.)

DECIMAL(p,s)

Variable

Exact precision

Currency, GPA, prices

FLOAT

4 bytes

~7 decimal digits

Scientific measurements

DOUBLE

8 bytes

~15 decimal digits

Higher precision decimals

Rule of Thumb: Use DECIMAL for money and grades (exact precision required). Use FLOAT/DOUBLE only when approximate values are acceptable.

String Types

Type
Max Length
Use Case

CHAR(n)

255 chars (fixed)

State codes, zip codes, country codes

VARCHAR(n)

65,535 chars (variable)

Names, emails, URLs

TEXT

65,535 chars

Descriptions, comments

MEDIUMTEXT

16 MB

Blog posts, articles

LONGTEXT

4 GB

Full documents (rarely needed)

ENUM('a','b','c')

One of listed values

Status fields, fixed categories

Date/Time Types

Type
Format
Example
Use Case

DATE

YYYY-MM-DD

2025-03-15

Birthdays, enrollment dates

TIME

HH:MM:SS

14:30:00

Event times

DATETIME

YYYY-MM-DD HH:MM:SS

2025-03-15 14:30:00

Scheduled events

TIMESTAMP

YYYY-MM-DD HH:MM:SS

2025-03-15 14:30:00

Auto-tracking created_at/updated_at

DATETIME vs. TIMESTAMP: TIMESTAMP converts to UTC for storage and back to the server's timezone on retrieval, and supports DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP. DATETIME stores the literal value without timezone conversion.

Indexes

Indexes dramatically speed up SELECT queries on large tables, but they add overhead to INSERT/UPDATE/DELETE operations (the index must be maintained).

When to add an index:

  • Columns frequently used in WHERE clauses

  • Columns used in JOIN conditions

  • Columns used in ORDER BY

  • Columns used in GROUP BY

When NOT to index:

  • Small tables (under a few hundred rows)

  • Columns with very low cardinality (e.g., a boolean is_active column with only 2 values)

  • Tables with heavy INSERT/UPDATE/DELETE and rare SELECT

Foreign Keys & Referential Integrity

Foreign keys enforce relationships between tables, preventing orphaned records:

ON DELETE / ON UPDATE Options:

Option
Behavior

CASCADE

Delete/update child rows automatically

SET NULL

Set the foreign key column to NULL

SET DEFAULT

Set to the column's default value

RESTRICT

Prevent the parent row from being deleted/updated (default)

NO ACTION

Same as RESTRICT in MySQL

Altering Tables


8. Working with Joins & Complex Queries in PHP

Understanding JOINs Visually

INNER JOIN — Only Matching Rows

Returns only students who are enrolled in at least one course:

Null Coalescing Operator ??: The expression $row['grade'] ?? 'In Progress' returns 'In Progress' if $row['grade'] is NULL. This is a clean PHP 7+ alternative to isset() checks.

LEFT JOIN — All Left Table Rows, Even Without Matches

Returns ALL students, including those not enrolled in any courses:

GROUP_CONCAT() is a powerful MySQL aggregate function that concatenates values from multiple rows into a single string. In this example, it produces output like "CS101, CS301" for a student enrolled in two courses.

Aggregate Queries

Subqueries


9. Transactions & Data Integrity

What Are Transactions?

A transaction groups multiple SQL operations into a single atomic unit. Either ALL operations succeed (COMMIT), or ALL are rolled back (ROLLBACK). This ensures data consistency even if an error occurs mid-operation.

ACID Properties

Property
Meaning

Atomicity

All operations in the transaction succeed or none do

Consistency

The database moves from one valid state to another

Isolation

Concurrent transactions don't interfere with each other

Durability

Once committed, changes survive system crashes

Transaction Example: Enrolling a Student

Enrolling a student requires multiple operations: checking prerequisites, checking seat availability, inserting the enrollment record, and updating the enrollment count. If any step fails, we need to undo everything.

Transaction with PDO


10. User Authentication with MySQL

Database Schema for Authentication

Registration: Hashing Passwords

Never store plain-text passwords. PHP's password_hash() function uses the bcrypt algorithm by default:

Login: Verifying Passwords

Session-Based Access Control

auth_check.php — Include this at the top of every protected page:

Usage on a protected page:

Admin-only page:


11. Pagination, Search & Filtering

Basic Pagination

Pagination displays a subset of rows per page, preventing the browser from loading thousands of records at once.

Search with Pagination

Combining a search feature with pagination requires passing the search term through pagination links:


12. File Uploads & Binary Data Storage

Store uploaded files on the filesystem and save only the file path in the database. This is more efficient and scalable than storing binary data directly.

Approach 2: Store Binary Data in Database (BLOB)

For small files or when database portability is important:


13. Error Handling & Logging

PHP Error Handling Levels

Configure error reporting in php.ini or at runtime:

MySQLi Error Handling

Custom Error Logger

Try-Catch Pattern for Database Operations


14. Security Best Practices

The Security Checklist

Every database-driven PHP application should implement the following protections:

1. SQL Injection Prevention

Always use prepared statements with parameterized queries. No exceptions.

2. Cross-Site Scripting (XSS) Prevention

Always escape output with htmlspecialchars():

3. Cross-Site Request Forgery (CSRF) Protection

Add CSRF tokens to all forms that modify data:

4. Password Security

5. Database Connection Security

6. Principle of Least Privilege

7. Input Validation & Sanitization


15. Performance Optimization

Query Optimization

Use EXPLAIN to Analyze Queries

Key columns in EXPLAIN output:

Column
Good Values
Warning Signs

type

const, eq_ref, ref

ALL (full table scan)

key

An index name

NULL (no index used)

rows

Low number

Very high number

Extra

Using index

Using filesort, Using temporary

Index Optimization

PHP Optimization

Connection Pooling with Persistent Connections

Fetch Only What You Need

Use Buffered vs. Unbuffered Queries

Batch Inserts

Caching Strategies


16. Building a Complete CRUD Application

Project Structure

includes/functions.php

includes/header.php

includes/footer.php

index.php — Student Listing

student_add.php — Add Student


17. Troubleshooting Common Issues

Connection Errors

Error
Cause
Solution

Access denied for user 'root'@'localhost'

Wrong password or auth method

Check credentials; use ALTER USER to set password

Can't connect to local MySQL server through socket

MySQL service not running

sudo systemctl start mysql

Connection refused

MySQL not listening or wrong port

Check bind-address and port in mysqld.cnf

Unknown database 'mydb'

Database doesn't exist

Create it: CREATE DATABASE mydb;

No such file or directory

Socket path mismatch

Use 127.0.0.1 instead of localhost

PHP Errors

Error
Cause
Solution

Call to undefined function mysqli_connect()

php-mysql extension not installed

sudo apt install php-mysql && sudo systemctl restart apache2

Fatal error: Uncaught Error: Class "mysqli" not found

Same as above

Install php-mysql and restart Apache

Headers already sent

Output before header() or session_start()

Ensure no HTML/whitespace before <?php

Maximum execution time exceeded

Query too slow or infinite loop

Optimize query; add indexes; increase max_execution_time

MySQL Query Errors

Error
Cause
Solution

1062: Duplicate entry

UNIQUE constraint violation

Check for existing records before inserting

1451: Cannot delete or update a parent row

Foreign key constraint

Delete child records first, or use ON DELETE CASCADE

1054: Unknown column

Typo in column name

Check spelling; run DESCRIBE table_name

1064: SQL syntax error

Malformed SQL

Check quotes, commas, parentheses

1146: Table doesn't exist

Table not created or wrong database

Run SHOW TABLES; to verify

Debugging Checklist

  1. Enable error display (development only):

  2. Print the actual SQL being executed:

  3. Check MySQL error output:

  4. Check the MySQL error log:

  5. Check the PHP error log:

  6. Test the query directly in MySQL CLI:

    Then paste and run the SQL directly to isolate PHP vs. MySQL issues.

  7. Check PHP extension status:

  8. Verify Apache is loading PHP:


Quick Reference Card

MySQLi Connection Template

Prepared Statement Template

PDO Connection Template

Essential Security Functions


Last updated