Choose a version here. If you've not already started the tutorial, just go with the latest one.

30 Aug 2014 Preview version Choose
5 Oct 2014 Explicitly adds a specific charset for htmlspecialchars(), and wraps it with a custom function Choose
16 Oct 2014 Updated redirect function to work with vhost subfolders Choose
4 Nov 2014 Minor improvements: added missing docblock, fixed security issue, CSS tweak Choose
25 Nov 2014 Improve the notes on getting started, in particular choosing a programmer's editor. Added introduction to mod_rewrite rules. Choose
OK
NB: There are several versions of this tutorial, each successive one containing additional improvements. If you're in the middle of working through it, please check the versions panel above, to ensure you're not mixing code from different versions.

Make your own blog

What is this?

It's a small, interactive course to teach beginners the PHP programming language.

Who's it for?

Anyone who wants to learn how to create simple database-powered web applications.

How much does it cost?

It's free of charge.

How do I get started?

Click on the first chapter to the right.

How is each change introduced?

I use a visual device known as a diff. Related file changes are grouped into sets, like this example — explore by clicking on the tabs.

Expand/contract code area Select previous tab
Select next tab
1
2
3
4
5
6
7
8
9
10
11
12
<?php
// Work out the path to the database, so SQLite/PDO can connect
$root = __DIR__;
$database = $root . '/data/data.sqlite';
$dsn = 'sqlite:' . $database;
// Connect to the database, run a query, handle errors
$pdo = new PDO($dsn);
$stmt = $pdo->query(
'SELECT
id, title, created_at, body
1
2
 
 
 
 
3
4
5
6
7
8
<?php
require_once 'lib/common.php';
// Connect to the database, run a query, handle errors
$pdo = getPDO();
$stmt = $pdo->query(
'SELECT
id, title, created_at, body
1
 
 
2
3
4
5
6
7
8
40
41
42
43
44
45
46
<?php
// Get the PDO DSN string
$root = realpath(__DIR__);
$database = $root . '/data/data.sqlite';
$dsn = 'sqlite:' . $database;
$error = '';
// Connect to the new database and try to run the SQL commands
if (!$error)
{
$pdo = new PDO($dsn);
$result = $pdo->exec($sql);
if ($result === false)
{
1
2
3
4
5
6
 
7
8
9
40
41
42
43
44
45
46
<?php
require_once 'lib/common.php';
// Get the PDO DSN string
$root = getRootPath();
$database = getDatabasePath();
$error = '';
// Connect to the new database and try to run the SQL commands
if (!$error)
{
$pdo = getPDO();
$result = $pdo->exec($sql);
if ($result === false)
{
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
/**
* Gets the root path of the project
*
* @return string
*/
function getRootPath()
{
return realpath(__DIR__ . '/..');
}
/**
* Gets the full path for the database file
*
* @return string
*/
function getDatabasePath()
{
return getRootPath() . '/data/data.sqlite';
}
/**
* Gets the DSN for the SQLite connection
*
* @return string
*/
function getDsn()
{
return 'sqlite:' . getDatabasePath();
}
/**
* Gets the PDO object for database acccess
*
* @return \PDO
*/
function getPDO()
{
return new PDO(getDsn());
}
1
2
3
4
5
6
7
8
13
14
15
16
17
18
19
<?php
// Work out the path to the database, so SQLite/PDO can connect
$root = __DIR__;
$database = $root . '/data/data.sqlite';
$dsn = 'sqlite:' . $database;
// Get the post ID
if (isset($_GET['post_id']))
}
// Connect to the database, run a query, handle errors
$pdo = new PDO($dsn);
$stmt = $pdo->prepare(
'SELECT
title, created_at, body
1
2
 
 
 
3
4
5
13
14
15
16
17
18
19
<?php
require_once 'lib/common.php';
// Get the post ID
if (isset($_GET['post_id']))
}
// Connect to the database, run a query, handle errors
$pdo = getPDO();
$stmt = $pdo->prepare(
'SELECT
title, created_at, body

What, no framework?

Deliberately so. I think it's a good idea to learn what can be done with a language before using frameworks. Frameworks are good because they hide the nuts and bolts of applications from developers, but they can be bad, because they hide the nuts and bolts of applications from learners.

Is the tutorial finished?

Most tutorials are published and forgotten about, which is why there are so many on the web promoting old or insecure practices. This one is finished in the sense it is ready to use, but I intend to maintain it. If you see something that could be done better, please raise a bug report on GitHub.

Can I offer some general feedback?

That would be great. I've a blog post here and a Reddit conversation here, feel free to comment.

How do I find assistance if I get stuck?

At the time of writing there is no support channel for the site, but I do have some things in the possibly-maybe stage of planning for this!

In the meantime, there are plenty of help forums and chat rooms on the web, many of them catering to beginners. I found searches on Reddit and Twitter particularly fruitful, but if they don't yield anything, feel free to get in touch for up-to-date suggestions.

Any tips on how to break through beginner frustration?

Building a group of fellow programmers of a similar level of learning can be very helpful. You can do this in your local area, or reach out to people over the web via social media. You can use tools like instant messaging, perhaps meeting at an agreed weekly time, to chat whilst you learn.

I've finished this one! Do you plan to offer other tutorials?

Well done! Do please tweet me, so I can boast on your behalf! More tutorials are always a possibility, but they do take quite a lot of time to put together. This site is a hobby at the moment, and time is scarce, but you never know...