Apache2 on Ubuntu
It’s always interesting when I build new instances. Ubuntu 22.0.4 was no different but I ran into an issue with installing Apache2 and eventually loading the mysqli module.
The Apache2 error was an issue with an unsupported module or hidden prerequisite. The MySQLi required an Apache reload after installation. Contrary to some erroneous posts the mysqli driver is supported on PHP 8.1.
Apache2 installation starts first and the mysqli module reload and verification script follows. On Ubuntu, you install Apache2 if you’re unaware of the hidden pre-requisite, otherwise install the pre-requisite first and avoid the error.
This is the command to install the apache2 module:
sudo apt-get install -y apache2 |
It generated the following error message:
apache2: Syntax error on line 146 of /etc/apache2/apache2.conf: Syntax error on line 1 of /etc/apache2/mods-enabled/wsgi.load: Cannot load /usr/lib/apache2/modules/mod_wsgi.so into server: /usr/lib/apache2/modules/mod_wsgi.so: cannot open shared object file: No such file or directory Action 'start' failed. The Apache error log may have more information. |
Line 146 in the /etc/apache2/apache2.conf file contains the instruction to load modules. The error says it can’t find the mod_wsgi.so library, which was originally part of the deprecated Python 2.7 release.
IncludeOptional mods-enabled/*.load |
The first step I pursued was finding the missing library, which appeared to be in the libapache2-mod-wsgi package. However, it became clear there is no installation candidate for that module, which supported Python 3.x. A little more research led me to find the appropriate library version for Python 3, which is found in the libapache2-mod-wsgi-py3 package.
I installed the libapache2-mod-wsgi-py3 package with the following syntax:
sudo apt-get install -y libapache2-mod-wsgi-py3 |
Display detailed console log →
Reading package lists... Done Building dependency tree... Done Reading state information... Done The following NEW packages will be installed: libapache2-mod-wsgi-py3 0 upgraded, 1 newly installed, 0 to remove and 10 not upgraded. Need to get 106 kB of archives. After this operation, 304 kB of additional disk space will be used. Get:1 http://us.archive.ubuntu.com/ubuntu jammy-updates/main amd64 libapache2-mod-wsgi-py3 amd64 4.9.0-1ubuntu0.1 [106 kB] Fetched 106 kB in 1s (135 kB/s) Selecting previously unselected package libapache2-mod-wsgi-py3. (Reading database ... 228859 files and directories currently installed.) Preparing to unpack .../libapache2-mod-wsgi-py3_4.9.0-1ubuntu0.1_amd64.deb ... Unpacking libapache2-mod-wsgi-py3 (4.9.0-1ubuntu0.1) ... Setting up libapache2-mod-wsgi-py3 (4.9.0-1ubuntu0.1) ... apache2_invoke wsgi: already enabled |
After applying it, I was able to start Apache2. Then, typing in localhost returns the Apache2 index.htm page, like:
After creating the following file in the default directory:
<?php phpinfo(); ?> |
Typing in localhost/infophp returns the Apache2 info.php page, like:
After the basics for PHP, the next step is the mysqli module for the MySQL database. This can be done in two steps on Ubuntu.
- Install the MySQLi software with the following syntax on Ubuntu:
sudo apt-get install -y php8.1-mysql
If you forget and use the old php-mysqli, it will redirect to the new PHP 8.1 MySQL module.
- You need to reload the Apache configuration with the following syntax:
sudo systemctl reload apache2
Now, you can use the following PHP program to verify that the mysqli and pdo drivers are installed:
<html> <header> <title>Module Verification</title> </header> <body> <?php if (!function_exists('mysqli_init') && !extension_loaded('mysqli')) { print 'mysqli not installed.'; } else { print 'mysqli installed.'; } if (!function_exists('pdo_init') && !extension_loaded('pdo')) { print '<p>pdo not installed.</p>'; } else { print '<p>pdo installed.</p>'; } ?> </script> </body> </html> |
If everything is correct, it should return the following in a browser when you query it from localhost/the-file-name and the file is in the /var/www/html directory:
mysqli installed. pdo installed. |
This means you can now write PHP applications, like the following example for my students:
I also have some demonstration programs that upload PNG files. As usual, I forgot about that while building the Ubuntu installation with MySQL 8, PHP 8.1 and Apache2. Fortunately, I solved it back in the day when moving from PHP 5.7 to 7.1 and here are the equivalent steps for Ubuntu:
I installed the libapache2-mod-wsgi-py3 package with the following syntax:
sudo apt-get install -y php-gd |
Display detailed console log →
Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: php8.1-gd The following NEW packages will be installed: php-gd php8.1-gd 0 upgraded, 2 newly installed, 0 to remove and 13 not upgraded. Need to get 34.7 kB of archives. After this operation, 158 kB of additional disk space will be used. Get:1 http://us.archive.ubuntu.com/ubuntu jammy-updates/main amd64 php8.1-gd amd64 8.1.2-1ubuntu2.14 [32.9 kB] Get:2 http://us.archive.ubuntu.com/ubuntu jammy/main amd64 php-gd all 2:8.1+92ubuntu1 [1,828 B] Fetched 34.7 kB in 1s (39.3 kB/s) sh: 0: getcwd() failed: No such file or directory sh: 0: getcwd() failed: No such file or directory sh: 0: getcwd() failed: No such file or directory sh: 0: getcwd() failed: No such file or directory Selecting previously unselected package php8.1-gd. (Reading database ... 228928 files and directories currently installed.) Preparing to unpack .../php8.1-gd_8.1.2-1ubuntu2.14_amd64.deb ... Unpacking php8.1-gd (8.1.2-1ubuntu2.14) ... Selecting previously unselected package php-gd. Preparing to unpack .../php-gd_2%3a8.1+92ubuntu1_all.deb ... Unpacking php-gd (2:8.1+92ubuntu1) ... Setting up php8.1-gd (8.1.2-1ubuntu2.14) ... Creating config file /etc/php/8.1/mods-available/gd.ini with new version Setting up php-gd (2:8.1+92ubuntu1) ... Processing triggers for libapache2-mod-php8.1 (8.1.2-1ubuntu2.14) ... Processing triggers for php8.1-cli (8.1.2-1ubuntu2.14) ... |
Then, I restarted the Apache2 server to incorporate the php-gd library in my PHP module with this syntax:
sudo systemctl restart apache2.service |
Retesting the PHP form to upload and render a PNG image file with this code (note that the only thing you can display is the html header and converted image, as shown on lines 64 and 65):
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?php /* ConvertBlobToImage.php * by Michael McLaughlin * * This script queries an image from a BLOB column and * converts it to a PNG image. * * ALERT: * * The header must be inside the PHP script tag because nothing * can be rendered before the header() function call that signals * this is a PNG file. */ // Database credentials must be set manually because an include_once() function // call puts something ahead of the header, which causes a failure when rendering // an image. // Include the credential library. include_once("MySQLCredentials.inc"); // Return successful attempt to connect to the database. if (!$c = @mysqli_connect(HOSTNAME,USERNAME,PASSWORD,DATABASE)) { // Print user message. print "Sorry! The connection to the database failed. Please try again later."; // Assign the OCI error and format double and single quotes. print mysqli_error(); // Kill the resource. die(); } else { // Declare input variables. $id = (isset($_GET['id'])) ? (int) $_GET['id'] : 1023; // Initialize a statement in the scope of the connection. $stmt = mysqli_stmt_init($c); // Declare a SQL SELECT statement returning a MediumBLOB. $sql = "SELECT item_blob FROM item WHERE item_id = ?"; // Prepare statement and link it to a connection. if (mysqli_stmt_prepare($stmt,$sql)) { mysqli_stmt_bind_param($stmt,"i",$id); // Execute the PL/SQL statement. if (mysqli_stmt_execute($stmt)) { // Bind result to local variable. mysqli_stmt_bind_result($stmt, $image); // Read result. mysqli_stmt_fetch($stmt); } } // Disconnect from database. mysqli_close($c); // Print the header first. header('Content-type: image/png'); imagepng(imagecreatefromstring($image)); } ?> |
The call to the ConvertMySQLBlobToImage.php is handled in an image tag, as shown:
<img src="ConvertMySQLBlobToImage.php?id='.$id.'"> |
Rendering a web page, like:
As always, I hope this explains something worthwhile.