What is PHP?

PHP (short for Hypertext Preprocessor) is an Open-Source scripting language which is mainly used to generate HTML-code when developing websites.

Example:

<?php
   $variable = "Testvariable";
   echo "This variable contains following text: " . $variable;
?>

Result:

This variable contains following text: Testvariable

In this example a basic variable is being defined and directly after that being outputted via “echo” after the text “This variable contains following text: “.

Due to the fact that PHP is a scripting language the content of the PHP file is being processed on every request. In contrast Java or C need to be “compiled” into machine code before it can be executed.

PHP offers quite a few functionalities out of the box – for example:

  • Database operations (MySQL, PostgreSQL, SQLite etc.)
  • Filesystem operations (Create/Edit/Delete folders or files etc.)
  • String manipulation (Create/Edit/Delete text etc.)
  • XML operations (Create/Edit/Delete XML data structures etc.)
  • and much more

These are just some basic which you can basically can find in any “Default PHP” installation. But PHP has so called “PHP modules” to extend the functionality PHP offers.

Popular PHP modules are:

  • XDebug (Extended Debug functionality)
  • OPCache (Saves precompiled bytecode from PHP in RAM instead of recompiling it on every request => performance boost)
  • MBString (Adds the ability to handle “MultiByte Strings” in PHP – e.g. Emoji Icons)
  • GD (Image editing in PHP like rotating or converting)
  • SOAP (A special, XML like data structure)
  • and much more

How PHP can be used via web servers or via the CLI can be seen in “CLI vs WebServer Integration“.

Due to the fact that PHP is always evolving I have gather the most important changes of PHP 7.1, 7.2 and 7.3 HERE.

Sources:
PHP: What is PHP – https://www.php.net/manual/de/intro-whatis.php

PHP versions

Everywhere in software development we have versions which evolve over time to improve performance, fix security issues and add new functionality. The following list contains a short overview of the changes from PHP 7.1 to 7.3.

PHP 5.6 and 7.0 will not be included here because they are no longer being supported (php.net) (April 2019)

PHP 7.1

“Nullable types”

function test1(?array $a) {
 
}
 
function test2($a): ?array {
 
}

The first function (test1) defines, that the first parameter can have the type “Array”, but can also be “null” (? before the array)

The second function (test2) defines, that the return value can have the type “Array”, but also “null” too.

Without the prefixed ? the function test1 called with a parameter “null” or the second function test2 with a return value of “null” would lead into a “Fatal Error” when executing that code.

Array and list have same functionality

Old Code:

$array = array(0 => 'a', 1 => 'b');
 
list($a, $b) = $array;
 
// $a is = 'a'
// $b is = 'b'

New Code:

$array = array(0 => 'a', 1 => 'b', 2 => 'c');
 
[$a, $b] = $array;
 
// $a is = 'a'
// $b is = 'b'
 

list(1 => $b, 2 => $c) = $array;
// same as above
[1 => $b, 2 => $c] = $array;

Visibility of constants in classes

As already common in other object oriented programming languages you can now set “visibilities” for class constants.

  • public Access to variable allowed from everywhere.
  • protected Access to variable only allowed in its own class AND all extended classes.
  • private Access to variable only allowed in its own class.
class test {
    const PUBLIC1 = 'TEST';
 
    public const PUBLIC2 = 'TEST';
    protected const PROTECTED = 'TEST';
    private const PRIVATE = 'TEST';
}

Multi catch exception handling

You can now have multiple exceptions in one try-catch block.

try {
     throw new Exception('Fehler');
} catch (Exception | AndererExceptionTyp $catchedException) {
     var_dump($catchedException);
}

mcrypt extension deprecated => use OpenSSL

The functions of the “mcrypt” extension (function names all start with “mcrypt_”) will be marked as “deprecated” markiert and therefore produce a line in the error.log.

Use the OpenSSL extension as a replacement.

PHP 7.2

Native support for BMP image format

Since PHP 7.2 the GD extension allows to handle .bmp images.

Typ “object” bei Parameter- und Rückgabewerten einstellbar

A new type, object, has been introduced that can be used for parameter typing and return typing of any objects.

function test (object $a): object {

}

Enhancements to the EXIF extension

EXIF (Exchangeable Image File Format) is a standard to save metadata in image files.

Till now the automatically parsed EXIFF data for images files was very limited. With PHP 7.2 many EXIF formats from well known camera suppliers have been added. See HERE

Encrypted ZIP-Archives

With PHP 7.2 you can now create ZIP archives with a password protection.

PHP 7.3

Trailing Commas are allowed in Calls

With PHP 7.3. it is now allowed to have a trailing comma even if it is the last parameter in a function call.

my_function(
    $param1,
    $param2,
);

JSON_THROW_ON_ERROR

Till now json_decode() returns null if an error occurs.
But null can also be a valid result, which can lead to confusion.

So now you can check for json errors with these functions:

  • json_last_error()
    • Returns (if present) the last error, which has occurred on the las encoding/decoding process for a JSON.
  • json_last_error_msg()
    • Return “No error” if the encode /decode was a success and FALSE if there were problems.

An anonymous user has written a very nice helper function on the json_last_error_msg() definition page on php.net:

<?php
    if (!function_exists('json_last_error_msg')) {
        function json_last_error_msg() {
            static $ERRORS = array(
                JSON_ERROR_NONE => 'No error',
                JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
                JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)',
                JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
                JSON_ERROR_SYNTAX => 'Syntax error',
                JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
            );

            $error = json_last_error();
            return isset($ERRORS[$error]) ? $ERRORS[$error] : 'Unknown error';
        }
    }
?>

Alternatively you an also solve that problem with a try-catch block:

try {
    json_decode("{", false, 512, JSON_THROW_ON_ERROR);
}
catch (\JsonException $exception) {
    echo $exception->getMessage(); // echoes "Syntax error"
}

is_countable function

Currently it is common to check a variable if it can be looped through a foreach with the following code:

$array = [1,2,3,4,5,6,7,8];

if(is_array($array) && sizeof($array) > 0){
  foreach($array as $value){
    
  }
}

But with PHP 7.3 you can write:

$array = [1,2,3,4,5,6,7,8];

if(is_countable($array)){
  foreach($array as $value){
    
  }
}

array_key_first(), array_key_last()

Till now it was not “easy” to get the first and last “key” of an array. But with PHP 7.3 you now have the functions array_key_first()and array_key_last().

Sources

mod_php vs (Fast)CGI vs FPM

mod_php

“mod_php” is a module for the web-server “apache”.

With this module PHP is therefore “integratedinto the web-server. Therefore there is no extra PHP-Prozess which handles the PHP interpretation. Instead everything is handled by the apache process.

The main advantage for using “mod_php” is performance. Compared to CGI you usually gain 300-500% when changing to mod_php.

Main reason for that is the ability to cache PHP modules, or specifically the configuration which usually (in CGI and FastCGI) has to be parsed on every request.

CGI

The “Common Gateway Interface” (show CGI) implementation means, the the web-server starts an extra PHP process for each request. Therefore all PHP modules, the php.ini and all other configuration needs to be loaded and parsed on every request, which is inefficient.

Main advantage for using CGI is the complete separation between the executing web-server Code and the PHP code.

FastCGI

FastCGI is a PHP implementation, which contains the security advantages from CGI but also being efficient like mod_php.

Here we don’t start a new PHP process on every request, instead we use “ready made” PHP interpreter instances which only get the PHP files passed on to be handled.

FPM

The „PHP-FastCGI Process Manager“ (short PHP-FPM) is an alternative to the FastCGI implementation.

Here the main difference is, that there is always a “parallel” PHP-FPM Process which is connected to the web-server process.

For more details see HERE

Source: https://blog.layershift.com/which-php-mode-apache-vs-cgi-vs-fastcgi/

PHP-FPM

The “PHP-FastCGI Process Manager” (short PHP-FPM) is an alternative FastCGI Implementation for PHP in a web-server.

Here we always have (at least) one PHP-FPM process parallel to the web-server process which handles PHP interpretation.

FPM processes group up into different “pools”. In these pools there will usually be several proccess created which handle PHP interpretation for a specific web page.

The amount of these processes and many more settings can be set in the FPM configuration (see bellow).

Installation (Debian based Distros)

sudo apt install php7.2 php7.2-common php7.2-cli php7.2-fpm

FPM Configuration

This is located in “/etc/php/7.2/fpm/pool.d/”.
Here we should create one file per socket/website.

[<pool-name>]
user = <username>
group = <groupname>
listen = /run/php/<socket-name>.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
chroot = <docroot-path>
php_admin_value[openssl.capath] = /etc/ssl/certs

The “listen” defines where the linux socket should be placed in the file system. This socket will be created after the PHP-FPM process has been restarted.

Via this socket the web-server can redirect PHP interpretation to the FPM process (see bellow)

Web-Server Configuration (NGINX)

The web-server has to know how and where it should send PHP-Files to the corresponding PHP process.

This is an example for: /etc/nginx/sites-available/<domain-name>.conf

server {
    listen 443 ssl http2; # managed by Certbot
    listen [::]:443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/<domain-name>/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/<domain-name>/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    root <path-to-docroot>;
    server_name <domain-name>;

    index index.html index.htm index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }	

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
	fastcgi_pass unix:/run/php/<fpm-socket-name>.sock;
    }
	
    error_log <path-to-logs>/error.log warn;
    access_log <path-to-logs>/access.log apm;
}

server {
    if ($host = <domain-name>) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
	
    listen 80;
    listen [::]:80;

    server_name <domain-name>;
    return 404; # managed by Certbot
}

The following line is responsible for the “redirection” to the FPM process:

fastcgi_pass unix:/run/php/<fpm-socket-name>.sock;

When you change something in the PHP-FPM config or the NGINX config you should always restart both services:

sudo systemctl restart php7.2-fpm.service nginx

CLI vs web-server integration

As described in PHP-FPM you can have different configurations for different web pages.

One advantage for that is the fact, that you can have different PHP versions for different web pages.

But these configurations don’t change the system-wide installed PHP version.

This means, that the PHP version from a PHP-Info file doesn’t have the be the same coming from the web-server and coming from the CLI.

php -v
PHP 7.2.19-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: May 31 2019 11:17:15) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.19-1+ubuntu18.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.7.1, Copyright (c) 2002-2019, by Derick Rethans

How to change the system-wide default PHP version?

Note: This is only possible if you have root/sudo privileges on the server!

Via the following command you can find out where the php command is located:

which php

On my server this is:

/usr/bin/php

If you now check this “file” you see:

ls -al /usr/bin/php        
lrwxrwxrwx 1 root root 21 Jan  3  2018 /usr/bin/php -> /etc/alternatives/php

This means, that /usr/bin/php only points to /etc/alternatives/php. But as you can see on the path this is handled by the “alternatives”.

If you check this “file” you see:

ls -al /etc/alternatives/php        
lrwxrwxrwx 1 root root 15 May 31  2018 /etc/alternatives/php -> /usr/bin/php7.2

This now points to the “real” binary, which executes PHP.

ls -al /usr/bin/php7.2      
-rwxr-xr-x 1 root root 4899864 May 31 13:17 /usr/bin/php7.2

Therefore the command “php” points to “/usr/bin/php”, which points to “/etc/alternatives/php” and finally to “/usr/bin/php7.2”.

To change this “link” (and therefore change the CLI PHP version) you can execute the following command:

sudo update-alternatives --set php /usr/bin/php7.3

After that you successfully changed the PHP CLI from 7.2 to 7.3.

php -v
PHP 7.3.6-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: May 31 2019 11:06:48) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.6, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.6-1+ubuntu18.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.7.1, Copyright (c) 2002-2019, by Derick Rethans

What is a webserver?

A webserver delivers data over the HTTP protocoll to a web browser. Typically these are HTML, CSS, JavaScript and image files.

Dependent on the chosen webserver you can use scripting languages or deliver dynamic data with for example:

  • PHP
  • JS
  • ASP
  • JSP

Typical webserver implementations:

  • Apache
  • NGINX
  • Microsoft ISS
  • NodeJS
  • Tomcat (Java)
  • lighthttpd

Currently the distribution of webservers (22nd february 2020) is:

Source: https://en.wikipedia.org/wiki/Web_server

Apache

The Apache HTTP server ist a free to use, open source webserver which has been published in 1995 and is currently the most used webserver (February 2020 – see “What is a webserver?“).

The installations process for the Apache webserver is mostly different on every linux distribution. In the following example I will show you how to install it on a Debian/Ubuntu based system.

sudo apt-get install apache2

After that you should be able to check the Apache2 version with:

apache2 -v

As usual in Debian based distributions the config files are located in /etc/apache2

In this folder we have the following files and folders:

  • apache2.conf
    • General Apache2 config file
  • conf-available
    • Contains additional config files which can be added to the default config
  • conf-enabled
    • Contains symbolic links to the “conf-available” which to show which configs should be enabled and which not.
  • envvars
    • Environment config for the Apache2
  • mods-available
    • same as conf-available just for Apache2 modules
  • mods-enabled
    • same as conf-enabled just for Apache2 modules
  • ports.conf
    • contains settings on which ports the server should listen
  • sites-available
    • same as conf-available just for vHost configs
  • sites-enabled
    • same as conf-available just for vHost configs
  • magic
    • Rules on which MIME-Types should be detected

Standard Apache vHost config

Folder: /etc/apache2/sites-available/<filename>

<VirtualHost *:80>
    ServerName www.domain.com
    ServerAlias domain.com
    DocumentRoot /var/www/html/docroot
</VirtualHost>

Explenation

  • VirtualHost *:80
    • Listen on the port 80
  • ServerName www.domain.com
    • Use this configuration if the hostname is “www.domain.com”
  • ServerAlias domain.com
    • Also use this configuration if the hostname is “domain.com”
  • DocumentRoot /var/www/html/docroot
    • Show the content of the folder “/var/www/html/docroot”

Activate a new vHost config

ln -s /etc/apache2/sites-available/<Dateiname> /etc/apache2/sites-enabled/<Dateiname>

Test the new Apache vHost config

apache2ctl configtest

Restart the Apache webserver

apache2ctl restart

Add a PHP-Handler

In Ubuntu/Debian based systems its pretty easy since its just a package which you can install via apt-get.

sudo apt-get install -y php7.2-curl php7.2-gd php7.2-json php7.2-mbstring php7.2-mcrypt libapache2-mod-php7.2

The most important package here is “libapache2-mod-php7.2” which connects the globally installed PHP and the Apache webserver. See mod_php for more details.

Instead of php7.2 you can of course use php7.3 or any other future PHP version.

If everything went well you can restart the webserver with apachectl restart and create a new file /var/www/html/info.php with the following content:

<?php phpinfo();

After that you can open your webbrowser and open the following URL

http://<Server-IP>/info.php

Now you should see a PHP-Info page.

NGINX

NGINX is a free to use, open source webserver which has been invented in 1999 by Igor Sysoev and ist currently the number 2 of the most used webservers (February 2020 – see „What is a webserver?„).

Why do you need any other webserver then Apache?

NGINX was created primarily because of the “C10k Problem”.

The “C10k Problem” is about optimizing and handling a large amount of network sockets.

C => Connection | 10k => 10.000

NGINX with its event based, async architecture was the base for future “high performance” server software and was therefore declared the fastest available webserver.

Installation and configuration

As mentioned in the apache installation process this can be different on your used linux distribution but the following example is based on a Debian/Ubuntu distribution.

sudo apt-get install nginx

After that you can check the installed version with the following command:

nginx -v

Similar to other linux packages the configuration files for NGINX are located in /etc/nginx.

Here we can find the following files and folders:

  • conf.d/
    • Directory to add additional configuration files
  • fastcgi.conf & fastcgi_params
    • Sets default parameters for FastCGI requests
  • mime.types
    • Mapping for file endings and their associated MIME-Type
  • modules-available/
    • Contains modules which are available to include into NGINX
  • modules-enabled/
    • Contains symlinks to the modules (in modules-available) which should actually be “activated” in NGINX
  • nginx.conf
    • Base NGINX-Config File
    • Here all activated modules, configurations and vHosts are being loaded
  • proxy_params
    • Default Proxy parameters can be found here
  • scgi_params
    • Sets default SCGI parameters
  • sites-available/
    • Contains configuration files for each vHost
  • sites-enabled/
    • Same as “modules-enabled” just for vHost files
  • snippets/
    • Contains snippets for how to use PHP files over FastCGI and how to use a self signed HTTPS certificate

Not so important files

  • uwsgi_params
  • koi-utf
    • Mapping for “KOI8-R” (Cyrillic) to “UTF-8” characters
  • koi-win
    • Mapping for “KOI8-R” (Cyrillic) to “Windows-1251” characters
  • win-utf
    • Mapping for “Windows-1251” to “UTF-8” characters

Create a new vHost

In /etc/nginx/sites-available there is a “default” file

This basically contains the following (comments (#) have been removed)

server {
	listen 80 default_server; # IPv4 listen on Port 80
	listen [::]:80 default_server; # IPv6 listen on Port 80

	root /var/www/html; # Absolute path to Document-Root

	# Set default files to show when accessing the website
	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name mydomain.at; # the domain name

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	# pass PHP scripts to FastCGI server
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
}

If you want to activate your configuration you have to create a “Symlink” in the folder /etc/nginx/sites-enabled.

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default

Or if you want to deactivate an already activated config:

unlink /etc/nginx/sites-enabled/default

Before you restart the NGINX server you should check your config syntax if you got any typos or wrong syntax:

nginx -t

After each change in the NGINX config you have to realod the NGINX to see the effect of the config chage

systemctl reload nginx

Source: https://www.nginx.com/resources/glossary/nginx/

Free HTTPS certificate with Lets Encrypt

Valid HTTPS certificates are necessary to show the lock beside of your URL.

Types of Certificates

  • Self-Signed Certificates
    • Everyone can create certificates and implement them in their websites.
    • But these will NOT be marked as “secure” and therefore don’t get a lock symbol.
    • To use these certificates every client has to mark these certificate as “secure” once in their system..
  • Wildcard Certificate
    • Are often used for Subdomain Certificates so you don’t have to create a new certificate when you add a new subdomain to your server.
    • Example: *.pfiff.me
  • Domain Validation (DV)
    • Here the applicant is being checked if he is actually the owner of the given domain. No other information like the identity of the company is being checked and therefore no other information is being displayed in the certificate.
    • Wildcard-Certificates are possible!
    • This is the default approach for LetsEncrypt certificates.
  • Organization Validation (OV)
    • Basically the same as a DV but additionally the companies name and locations is being checked. These information are then being displayed in the certificate.
    • Wildcard-Certificates are possible!
  • Extended Validation (EV)
    • Same as OV, but it’s a more detailed check of the company.
    • In the past with an EV certificate the name of the company was being displayed next to the lock but this feature has been removed from every currently common browser (Chrome, Firefox, Safari etc.). Therefore its debatable if this option is a good choice.
      See https://www.troyhunt.com/extended-validation-certificates-are-dead/
    • Wildcard-Certificates are NOT possible!

What is a “Certificate Authority” (CA)?

A “Certificate Authority” (short CA) is necessary to check certificates with specific, predefined methods and if that validation has been successful to sign these certificates. Additionally on each validation the certificate a date will be set when the certificate is being expired. After that period the certificate has to be checked and signed again.

In the past it was only possible to buy HTTPS certificates. But since 2015 “LetsEncrypt” or better the python script “Certbot” which makes this process way easier.

LetsEncrypt uses the “Domain-Vaildation” (DV) process. Therefore everyone, who is the owner a domain and shows the domain to a server, a signed LetsEncrypt certificate can be generated for this server to use this domain.

What is Certbot?

Certbot ist a software, which automatically generated and manages HTTPS certificates.

Currently there are even plugins available for the 2 mostly used webservers (Apache and NGINX), which even handle the configuration for the vhost files to include the certificate.

The easiest way to use certbot is to go to https://certbot.eff.org, enter your OS and your uses webserver and follow the instructions.

Usually a certificate generated by Certbot/LetsEncrypt is valid for 90 days. But Certbot checks the status of each installed certificate regularly and automatically renews certificates which will get expired in 30 days.

Therefore you only need to create and install your certificates once and everything else is handled by certbot.

Informations of a certificate

Source: https://www.digitalocean.com/community/tutorials/a-comparison-of-let-s-encrypt-commercial-and-private-certificate-authorities-and-self-signed-ssl-certificates