Skip to content

Instantly share code, notes, and snippets.

@tored
Last active December 3, 2024 12:11
Show Gist options
  • Save tored/484657ec657f17dd5b635b04356b510d to your computer and use it in GitHub Desktop.
Save tored/484657ec657f17dd5b635b04356b510d to your computer and use it in GitHub Desktop.
Manual WAMP setup for Windows, Apache, MySQL and PHP

Manual WAMP setup for Windows, Apache, MySQL and PHP

There many ways to setup a PHP development environment for Windows, WSL, Docker, Virtual Machine, WAMP and similar pre-packaged installers, etc, all of them works fine. I prefer somewhat old school approach to setup everything manually. Here is how

Preparation

I will setup this environment for 64 bit Windows. If you are on 32 bit you have to download the appropriate packages for that. I also setup everything for a local User, if you prefer to make it global for everyone you can do that as well (e.g install everything in C:\Wamp).

Create a directory somewhere called Wamp (or whatever). I will put mine at %OneDrive%\Program\Wamp. That way I can share my development environment between machines. (My %OneDrive%\Program directory consist of various Windows programs and tools I share between my machines, thus it makes sense to create a subdirectory there).

Inside the Wamp directory we create another directory called cmd, here we will place batch scripts to launch the different services and programs. Now add the cmd directory, e.g. %OneDrive%\Program\Wamp\cmd, to your User's (or globally) PATH environment variable (run rundll32 sysdm.cpl,EditEnvironmentVariables)

PHP

Go to https://windows.php.net/download/ to download PHP for Windows. Easiest setup for PHP+Apache is to load PHP as a Apache module, thus we need to download the thread safe PHP package. This is the easiest way to run PHP+Apache on Windows to avoid running a fastcgi service, the drawback is that you need a separate Apache install per PHP version, but is relatively easy to just copy an existing install.

At the time of this writing I'm downloading PHP 8.3.12 VS16 x64 Thread Safe zip package (php-8.3.12-Win32-vs16-x64.zip). In order to run the PHP executable we also need Visual C++ Redistributable for Visual Studio 2015-2022 that can be downloaded here https://aka.ms/vs/17/release/vc_redist.x64.exe

Unzip the zip file into the Wamp directory as directory named after your php version, e.g php-8.3.12 (If you are planning to also run non-thread safe PHP executables on your machines you need to introduce a naming convention to separate the two)

Go into the new directory and copy the file php.ini-development to php.ini.

Edit php.ini and update the following

extension_dir = "${OneDrive}\\Program\\Wamp\\php-8.3.12\\ext"

We need to set this path so when PHP is running inside Apache it can still find all of the extensions. When we are here uncomment the pdo driver

extension=pdo_mysql

Now go into your cmd directory and create a file named similar as the php directory, e.g php-8.3.12.cmd. Inside the file we add (or wherever you put your Wamp directory)

@"%OneDrive%\Program\Wamp\php-8.3.12\php.exe" %*

We also add another batch script called php-8.3.cmd

Inside that file we add

@php-8.3.12 %*

Now we have an easy way to run PHP from the command line. If you need to run many different minior versions of the same PHP major version, setup up them separately like above with both the major and the minor release name in the directory name, just change the php-8.3.cmd to the new version.

Apache

We download Apache from Apache Lounge https://www.apachelounge.com/download/ . At the time of this writing I pick Apache 2.4.62-240904 Win64 (httpd-2.4.62-240904-win64-VS17.zip). What is important is that the Visual Studio version for PHP and Apache match. VS17 is backward compatible thus it will work with php-8.3.12-Win32-vs16-x64.

Unzip the zip package directly inside our Wamp directory. Apache Lounge adds an extra directory inside the zip called Apache24. The unzipped Wamp\ReadMe.txt describes the Apache Lounge build, rename that to ReadMe-AL.txt and move that into the Apache24 directory (Apache has it's own README.txt, thus the rename). There is also an leftover file called something like -- Win64 VS17 --, delete that, not needed. Rename the Apache24 directory to httpd-2.4.62-8.3. We include both the major and the minor release of Apache of in the directory name but also add the PHP major version we configure for it, thus the suffix -8.3

We add batch script to the cmd directory called httpd-2.4-8.3 and add this (or with your install path)

@"%OneDrive%\Program\Wamp\httpd-2.4.62-8.3\bin\httpd.exe" %*

Configurating Apache

Now we need to configure Apache to work with our PHP.

Open %OneDrive%\Program\Wamp\httpd-2.4.62-8.3\conf\httpd.conf

Change SVROOT

Define SRVROOT "${OneDrive}/Program/Wamp/httpd-2.4.62-8.3"

Set ServerName to

ServerName 127.0.0.1:80

(Optional) Set ErrorLog to

ErrorLog "${TEMP}/httpd_error.log"

(Optional) Set CustomLog to

CustomLog "${TEMP}/httpd_access.log" common

I don't want global error and access logs to spam my OneDrive to I just put it into the %TEMP% directory. It can be good to have it but it is rare you need to look into it. We will setup per site specific log later.

Uncomment the line that includes Virtual hosts

Include conf/extra/httpd-vhosts.conf

At the end of the httpd.conf put

AddType application/x-httpd-php .php
AddHandler application/x-httpd-php .php
LoadModule php_module "${OneDrive}/Program/Wamp/php-8.3.12/php8apache2_4.dll"
PHPiniDir "${OneDrive}/Program/php-8.3.12"

Configurating our site (Virtual host)

Open %OneDrive%\Program\Wamp\httpd-2.4.62-8.3\conf\extra\httpd-vhosts.conf

Delete the existing <VirtualHost> declarations, we don't need them. Add instead

<VirtualHost *:80>
    Define ROOT "${OneDrive}/Work/myproject"
    DocumentRoot "${ROOT}/www"
    ServerName myproject.local
    DirectoryIndex index.html index.php
    Options +Indexes
    ErrorLog "${ROOT}/logs/error.log"
    CustomLog "${ROOT}/logs/access.log" common
    <Directory />
      AllowOverride All 
      Require all granted
    </Directory>
</VirtualHost>

On port 80 (the same that Apache Listen (see httpd.conf) we define variable ROOT that points to our project directory "${OneDrive}/Work/myproject" or wherever. Create that directory %OneDrive%\Work\myproject and inside that create the directories logs and www.

Now start our apache by writing in a terminal

httpd-2.4-8.3

You should get Firewall popup from apache asking for allowing to access internet, allow it but you only need to allow for private networks (uncheck public)

Now we need to add our site myproject.local to our Windows hosts file, as administrator do notepad C:\Windows\System32\drivers\etc\hosts

Add to the end of the file and save.

127.0.0.1 myproject.local

MySQL

Go to https://dev.mysql.com/downloads/mysql/ and download the "Windows (x86, 64-bit), ZIP Archive", lets pick MySQL 9 (mysql-9.0.1-winx64.zip) Unzip it into our Wamp directory, it should exist a containing directory inside zip, I rename that to mysql-9.0.1.

Create a batch file in our cmd directory called mysqld-9.0.cmd (I don't change minor version that often)

@"%OneDrive%\Program\Wamp\mysql-9.0.1\bin\mysqld.exe" %*

Also create a mysql-9.0.cmd

@"%OneDrive%\Program\Wamp\mysql-9.0.1\bin\mysql.exe" %*

Where do you want your databases stored?

Either you accept the default location inside the installation directory, this can become a problem if you are working with large databases and you place the installation on OneDrive, you can set another datadir with the the --datadir="<path>" command line option or inside the my.ini, see https://dev.mysql.com/doc/refman/9.0/en/data-directory-initialization.html

Initialize

Create file my.ini (or my.cnf) in %OneDrive%\Program\Wamp\mysql-9.0.1\ and put the following

[client]
port=3390

[mysqld]
port=3390

I picked port 3390 as for MySQL 9.0, if you have other MySQL version setups you can follow the same pattern, e.g. port 3384 for MySQL 8.4. In [mysqld] group you can add a datadir=... directive if you want your databases stored elsewhere.

Then Open a terminal and go to %OneDrive%\Program\Wamp\mysql-9.0.1\bin and run

mysqld --initialize --console

That will setup the datadir and default databases.

Important! to have --console otherwise it will not print out the root password. Take note of the root password printed, this password needs to be changed.

Start mysqld

mysqld-9.0

Firewall popup asking for permission, allow for private network only.

Now we will secure our installation and set a new root password , from %OneDrive%\Program\Wamp\mysql-9.0.1\bin run

mysql_secure_installation.exe

Follow the instructions, because the root password has expired you need to give a new one, I put that to root (or whatever your want) You have also the option to remove test databases, removing anonymous users and limiting remove access for root. Recommended to do all of them.

Now run

mysql-9.0 -u root -p -e "create database myproject"

for creating our project database

Creating our PHP site

Go to %OneDrive%\Work\myproject, add inside www directory the file .htaccess

FallbackResource /index.php

Also in www create the file index.php with

<?php
declare(strict_types=1);
require __DIR__ . '/../src/bootstrap.php';

Then create %OneDrive%\Work\myproject\src\bootstrap.php

And add

<?php
declare(strict_types=1);

$host = '127.0.0.1';
$port = 3390;
$db = 'myproject';
$user = 'root';
$pass = 'root';
$charset = 'utf8mb4';

$dsn = "mysql:host={$host};port={$port};dbname={$db};charset={$charset}";
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => true,
];
$pdo = new PDO($dsn, $user, $pass, $options);

$pdo->exec("CREATE TABLE IF NOT EXISTS test (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255) NOT NULL
)");

$stmt = $pdo->prepare("INSERT INTO test (title) VALUES (?)");
$stmt->execute([date('c')]);

$stmt = $pdo->prepare("SELECT * FROM test");
$stmt->execute();

?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>test</title>
    </head>

    <body>
    <ul>
        <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
            <li><?= $row['title'] ?></li>
        <?php endwhile; ?>
    </ul>
    </body>
    </html>
<?php

If everything works as it should you can go to http://myproject.local and see a list of dates, one for each request.

Happy coding!

Setting up a new project

When you need another project

Of an already configured PHP major version

Then you only need to edit %OneDrive%\Program\Wamp\httpd-2.4.62-8.3\conf\extra\httpd-vhosts.conf copy an existing <VirtualHost> and modify it and then update the hosts file C:\Windows\System32\drivers\etc\hosts and add the new project.

For a new PHP major version

Then go thru the setup as before, follow the existing naming conventions and you can handle multiple Apache+PHP configurations at the same time.

Extra

Setting up sqlite

How to get sqlite working with Apache.

Open php.ini and uncomment the sqlite PDO extension

extension=pdo_sqlite

Copy this dll from %OneDrive%\Program\Wamp\php-8.3.12\libsqlite3.dll to %OneDrive%\Program\Wamp\httpd-2.4.62-8.3\bin

Restart apache and test with the following in your bootstrap.php

<?php
declare(strict_types=1);

$db = __DIR__ . '/../myproject.sqlite';
if (!is_file($db)) {
    $fp = fopen($db, 'w');
    if ($fp === false) {
        throw new RuntimeException("Failed creating file {$db}");
    }
    fclose($fp);
}

$dsn = "sqlite:{$db}";

$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => true,
];
$pdo = new PDO($dsn, null, null, $options);

$pdo->exec("CREATE TABLE IF NOT EXISTS test (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title VARCHAR(255) NOT NULL
)");

$stmt = $pdo->prepare("INSERT INTO test (title) VALUES (?)");
$stmt->execute([date('c')]);

$stmt = $pdo->prepare("SELECT * FROM test");
$stmt->execute();

?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>test</title>
    </head>

    <body>
    <ul>
        <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
            <li><?= $row['title'] ?></li>
        <?php endwhile; ?>
    </ul>
    </body>
    </html>
<?php

If everything works as it should you can go to http://myproject.local and see a list of dates, one for each request.

Setting up Curl

How to get curl working with Apache.

Download cacert.pem from here https://curl.se/docs/caextract.html Save it at %OneDrive%\Program\Wamp\extra\cacert.pem"

Open php.ini and uncomment the curl extension

extension=curl

Find curl.cainfo and set to the pem file

curl.cainfo = "${OneDrive}\\Program\\Wamp\\extra\\cacert.pem"

Copy this dll from %OneDrive%\Program\Wamp\php-8.3.12\libssh2.dll to %OneDrive%\Program\Wamp\httpd-2.4.62-8.3\bin

Restart apache and test with the following in your bootstrap.php

<?php
declare(strict_types=1);

$ch = curl_init();
curl_setopt_array($ch, [
        CURLOPT_URL => 'https://news.ycombinator.com/',
        CURLOPT_RETURNTRANSFER => true,
]);
$output = curl_exec($ch);
if (curl_errno($ch) !== CURLE_OK) {
    throw new RuntimeException(curl_error($ch));
}
curl_close($ch);
echo $output;

If everything works you should see Hacker News at http://myproject.local

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment