PHP introduction: the basics of PHP on a Unix server
PHP is the language behind a large share of the web, including WordPress, Drupal, MediaWiki and Nextcloud. It runs on the server, produces HTML, and is easy to start with on any Linux machine.
Versions
PHP 8 is the current major version, with a new minor release every November. Each release gets two years of bug fixes and two more years of security fixes. Check the supported versions page and do not run a release that no longer receives security updates; PHP 7 and older have been unsupported for years. Debian 13 ships PHP 8.4.
Install and try it
sudo apt install php-cli php-mbstring php-mysql # interpreter plus the extensions used below
php -v
php -r 'echo "Hello from PHP " . PHP_VERSION . "\n";'
# a built-in web server for development (never for production)
mkdir site && cd site
echo '<?php phpinfo();' > index.php
php -S 127.0.0.1:8000
Open http://127.0.0.1:8000/ to see the page. For a real server, follow setting up a LAMP server.
The basics
PHP code goes between <?php and ?> inside an otherwise normal file. Everything outside those tags is sent to the browser unchanged.
<?php
declare(strict_types=1);
$name = "Ann"; // variables start with $
$count = 3;
$users = ["ann", "bob", "eve"]; // a list
$uid = ["ann" => 1001, "bob" => 1002]; // an associative array
echo "Hello, $name. You have $count messages.\n";
foreach ($users as $u) {
echo "user: $u\n";
}
function greet(string $who, string $greeting = "Hello"): string {
return "$greeting, $who!";
}
echo greet("Bob"), "\n";
$status = match (true) {
$count === 0 => "no messages",
$count < 10 => "a few messages",
default => "many messages",
};
Use === (same value and type) rather than ==, which converts types in surprising ways.
Handling a form
<form method="post">
<label>Your name <input name="name"></label>
<button>Send</button>
</form>
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
if ($name === '' || mb_strlen($name) > 100) {
echo "<p>Please enter a name.</p>";
} else {
echo "<p>Hello, " . htmlspecialchars($name) . "!</p>";
}
}
htmlspecialchars() is essential: it stops visitors from injecting HTML and JavaScript into your page.
Talking to a database safely
Use PDO with prepared statements. Never build SQL by gluing user input into a string; that is how SQL injection happens.
<?php
$pdo = new PDO(
'mysql:host=localhost;dbname=site;charset=utf8mb4',
'site', getenv('DB_PASSWORD'),
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$stmt = $pdo->prepare('SELECT id, title FROM articles WHERE author = ? ORDER BY id DESC LIMIT 10');
$stmt->execute([$_GET['author'] ?? '']);
foreach ($stmt as $row) {
echo htmlspecialchars($row['title']), "<br>\n";
}
Keep passwords out of the code: read them from the environment or from a configuration file outside the web root.
Composer and libraries
Composer installs PHP libraries and loads them automatically. Most modern PHP projects and frameworks (Laravel, Symfony) use it.
sudo apt install composer
composer require monolog/monolog
# in your code:
require __DIR__ . '/vendor/autoload.php';
Security checklist
- Escape all output with
htmlspecialchars()and use prepared statements for all SQL. - Hash passwords with
password_hash()and check them withpassword_verify(); never store them in plain text or with MD5. - Set
display_errors = Offon production servers and log errors instead. - Validate uploaded files, store them outside the web root or in a directory where PHP cannot run, and never trust the file name or type the browser sends.
- Keep PHP, your framework and every plugin updated.
Learn more
- The PHP manual: every function, with examples and comments.
- PHP: The Right Way: current best practice in one page.
- OWASP PHP configuration cheat sheet.