php


Symfony 5 skeleton project on Ubuntu

This guide will present the steps we followed on a GNU/Linux Ubuntu 20.04LTS to create a new project out of the Symfony 5 website skeleton.

Install core dependecies

First of all, we need to install all dependencies that we will need for sure.

sudo apt install curl gzip git php-cli php-xml php-mbstring php-intl php-mysql p7zip-full;

We chose to install the php-cli package instead of the php as we do not need to install all the additional dependencies php has, like apache2. Since we are working on a development computer, we can skip the required packages for deployment.

We decided to use MySQL in our project, so we installed the php-mysql package that provides the PDO for that database technology.

php-intl and php-mbstring were installed to suppress the following warnings:

Optional recommendations to improve your setup
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 * mb_strlen() should be available
   > Install and enable the mbstring extension.

 * intl extension should be available
   > Install and enable the intl extension (used for validators).

Downloading and installing symfony

Since Symfony version 5, there is a new support application for the development of Symfony projects. Using the following commands:

  • we downloaded it from the official website,
  • installed it to our home folder,
  • and then moved it to /user/local/bin/symfony to be accessible from any terminal without changing the path each time.
wget https://get.symfony.com/cli/installer -O - | bash;
sudo mv ~/.symfony/bin/symfony /usr/local/bin/symfony;

In case you do not want to move the binary to /usr/local/bin you can either use it as a local file:

~/.symfony/bin/symfony;

or add it to your $PATH variable:

export PATH="$HOME/.symfony/bin:$PATH";

Creating a new project and making sure dependencies are met

After the above steps are done, we can clone the Symfony 5 skeleton and then use the symfony support application to check that our system has all the needed features.

symfony new symfony_project;
cd symfony_project;
symfony check:req;

If everything is OK, you should get a message similar to the one below:

$ symfony check:req

Symfony Requirements Checker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

> PHP is using the following php.ini file:
/etc/php/7.4/cli/php.ini

> Checking Symfony requirements:

...................................

                                              
 [OK]                                         
 Your system is ready to run Symfony projects 
                                              

Note  The command console can use a different php.ini file
~~~~  than the one used by your web server.
      Please check that both the console and the web server
      are using the same PHP version and configuration.

Starting a minimal web server to see the skeleton application

Using PHP’s built-in server, we can execute the skeleton application and see the result in our browser:

php -S 127.0.0.1:8000 -t public/;

Starting the Symfony minimal web server to see the skeleton application

Another option to check out your application is using the Symfony built-in web server, which is richer in features than the PHP server but lighter than Apache or Nginx. Below we present how to start it as an application in a terminal and how to start it as a detached service (leaving your terminal free for other operations).

#If you start it as it as an application, you will need to press Ctrl + C to kill it.
symfony serve;

Starting Symfony server as a detached service:

symfony serve -d;
#To stop it, use the following
symfony server:stop;
#Please note that the command contains the word server and not serve like before.

Adding more features to our project

To make our project more dynamic and versatile, we need to install a few packages using composer. Composer is a PHP utility for managing dependencies. It allows you to indicate the libraries your project relies on, and it will take care of installing and updating them. To fast install it, open a terminal and type the following command:

curl -Ss getcomposer.org/installer | php;
# Moving the composer into the /usr/local/bin/ folder will allow us to access it from any folder later on as that folder is in the default PATH variable. You could again avoid this step but it makes the process more user friendly.
sudo mv composer.phar /usr/local/bin/composer;

Allowing code annotations in our PHP code

After the composer is successfully installed, we can install the annotations package, which among other features, will allow us to define routes inside our PHP controller files.

composer require annotations;

A code example of that is the following:

<?php


namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class QuestionController extends AbstractController
{
    /**
     * @Route("/", name="app_homepage")
     */
    public function homepage()
    {
        return new Response('Done');
    }

    /**
     * @Route("/questions/{slug}", name="app_question_show")
     */
    public function show($slug)
    {
        $answers = [
            'a',
            'b',
            'c'
        ];
        dump($this);

        return $this->render('question/show.html.twig', [
            'question' => ucwords(str_replace('-', ' ', $slug)),
            'answers' => $answers
        ]);
        #return new Response(sprintf("The question: %s", $slug));
    }
}

Installing the twig package that allows us to work better with HTML templates

To avoid embedding HTML code in our PHP code, we can install twig, which provides a framework of templates to build several sites quickly.

composer require template;

Enriching the development experience

To debug in a better way our applications, we install the following two groups of packages that provide several debugging features, including a logging mechanism.

composer require profiler --dev;
composer require debug;

Avoid hardcoding assets in the HTML DOM

To avoid hardcoding items in your DOM (and forcing yourself to remember to edit them depending on the deployment options you are using), you can use the asset package that will handle most of those issues.

composer require symfony/asset;

Serializing more items and objects to JSON and XML

To enrich the power of API calls that return JSON or XML objects (like the code below)

return $this->json(/*...*/);

we can install the following serializer:

composer require symfony/serializer;

and be used as follows:

$serializer->serialize(
  $myObject,
  'json'
);

Develop using HTTPS / SSL for free

Although we are not super happy about installing local Certificate Authorities on our machines, we used the following commands to install the Symfony Certifying Authority certificate and enable HTTPS/SSL development without accepting a non-verified certificate in the browser each time.

sudo apt install libnss3-tools;
symfony server:ca:install;

If you do not install libnss3-tools, you will get the following warning:

$ symfony server:ca:install
You might have to enter your root password to install the local Certificate Authority certificate
Sudo password:
The local CA is now installed in the system trust store!
WARNING "certutil" is not available, so the CA can't be automatically installed in Firefox and/or Chrome/Chromium!
Install "certutil" with "apt install libnss3-tools" and re-run the command
                                                                                                        
 [OK] The local Certificate Authority is installed and trusted                                          
                                                                      

After you install it, the message will change as follows:

$ symfony server:ca:install
The local CA is now installed in the Firefox and/or Chrome/Chromium trust store (requires browser restart)!
                                                                                                        
 [OK] The local Certificate Authority is installed and trusted

Install Webpack Encore for the assets

To install Webpack encore, we need yarn. To get yarn, we need npm. So we need the following installation steps:

sudo apt install npm;
sudo npm install --global yarn;

After these steps are successful, in the project folder, execute the following commands to allow the yarn to perform all necessary installations and then use encore to monitor the assets and rebuild its cache. The settings are depended on the file webpack.config.js.

yarn install;
yarn encore dev --watch;

Below, we present an example file of webpack.config.js.

var Encore = require('@symfony/webpack-encore');

// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
    Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}

Encore
    // directory where compiled assets will be stored
    .setOutputPath('public/build/')
    // public path used by the web server to access the output path
    .setPublicPath('/build')
    // only needed for CDN's or sub-directory deploy
    //.setManifestKeyPrefix('build/')

    /*
     * ENTRY CONFIG
     *
     * Add 1 entry for each "page" of your app
     * (including one that's included on every page - e.g. "app")
     *
     * Each entry will result in one JavaScript file (e.g. app.js)
     * and one CSS file (e.g. app.css) if your JavaScript imports CSS.
     */
    .addEntry('app', './assets/js/app.js')
    //.addEntry('page1', './assets/js/page1.js')
    //.addEntry('page2', './assets/js/page2.js')

    // When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
    .splitEntryChunks()

    // will require an extra script tag for runtime.js
    // but, you probably want this, unless you're building a single-page app
    .enableSingleRuntimeChunk()

    /*
     * FEATURE CONFIG
     *
     * Enable & configure other features below. For a full
     * list of features, see:
     * https://symfony.com/doc/current/frontend.html#adding-more-features
     */
    .cleanupOutputBeforeBuild()
    .enableBuildNotifications()
    .enableSourceMaps(!Encore.isProduction())
    // enables hashed filenames (e.g. app.abc123.css)
    .enableVersioning(Encore.isProduction())

    // enables @babel/preset-env polyfills
    .configureBabelPresetEnv((config) => {
        config.useBuiltIns = 'usage';
        config.corejs = 3;
    })

    // enables Sass/SCSS support
    //.enableSassLoader()

    // uncomment if you use TypeScript
    //.enableTypeScriptLoader()

    // uncomment to get integrity="..." attributes on your script & link tags
    // requires WebpackEncoreBundle 1.4 or higher
    //.enableIntegrityHashes(Encore.isProduction())

    // uncomment if you're having problems with a jQuery plugin
    //.autoProvidejQuery()

    // uncomment if you use API Platform Admin (composer req api-admin)
    //.enableReactPreset()
    //.addEntry('admin', './assets/js/admin.js')
;

module.exports = Encore.getWebpackConfig();

Some settings for PHPStorm by JetBrains

Since the IDE we are using for PHP development is PHPStorm, we installed the recommended plugins for Symfony to it. In the following image, we list the three plugins that we installed.

Specifically, we installed:

  • Symfony Support
  • PHP Annotations
  • PHP Toolbox

After installing the three plugins, we navigated to the Symfony Plugin settings (which you can find either using the search functionality or under the menu: Languages & Frameworks > PHP > Symfony).

From there, we clicked on the Enable Plugin for this Project and then changed the Web Directory from web to public.


Create a project using Symfony website-skeleton version 4 and then create a docker image out of it

This guide will present the steps we followed on a GNU/Linux Ubuntu 20.04LTS to create a new project out of the Symfony website skeleton and then create a new docker application image of it.

Install core dependecies

Install php-cli instead of php as we do not want to install the additional dependencies of php like apache2.
p7zip-full is needed for the package manager of composer later on. If it is missing, we will be getting one of the following errors:

Failed to download symfony/requirements-checker from dist: The zip extension and unzip/7z commands are both missing, skipping.
As there is no 'unzip' nor '7z' command installed zip files are being unpacked using the PHP zip extension.

php-xml will be required later on while creating the skeleton project for Symfony. If it is missing, you will get the following error:

symfony/framework-bundle requires ext-xml * -> it is missing from your system. Install or enable PHP's xml extension
sudo apt install php-cli php-xml p7zip-full;

Composer is a PHP utility for managing dependencies. It allows you to indicate the libraries your project relies on, and it will take care of installing and updating them. To fast install it, open a terminal and type the following command:

curl -Ss getcomposer.org/installer | php;
# Moving the composer into the /usr/local/bin/ folder will allow us to access it from any folder later on as that folder is in the default PATH variable.
sudo mv composer.phar /usr/local/bin/composer;

Symfony provides a tool to check if your operating system meets the required requirements rapidly. In addition, if suitable, the tool makes installation recommendations. To install the tool, run the following command:

composer require symfony/requirements-checker;
$ composer require symfony/requirements-checker;
Using version ^2.0 for symfony/requirements-checker
./composer.json has been updated
Running composer update symfony/requirements-checker
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking symfony/requirements-checker (v2.0.1)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing symfony/requirements-checker (v2.0.1): Extracting archive
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!

Once done, you can safely delete the requirements-checker:

composer remove symfony/requirements-checker;

Create the Symfony project

Using the basic skeleton, you can create a minimal Symfony project with the following command. We install the latest version of version 4.4 of the website skeleton project in this example. We found the list of versions here https://packagist.org/packages/symfony/website-skeleton.

composer create-project symfony/website-skeleton=4.4.99 symfony-skeleton;

When we got the following warning, we typed y, not sure what changes, so we stayed with the default option:

  -  WARNING  symfony/mailer (>=4.3): From github.com/symfony/recipes:master
    The recipe for this package contains some Docker configuration.

    This may create/update docker-compose.yml or update Dockerfile (if it exists).

    Do you want to include Docker configuration from recipes?
    [y] Yes
    [n] No
    [p] Yes permanently, never ask again for this project
    [x] No permanently, never ask again for this project
    (defaults to y): y

Then you need to run the following commands to install all dependencies and execute the project:

cd symfony-skeleton;
composer install;
composer require --dev symfony/web-server-bundle;
php bin/console server:start *:8000;

By now, you should see in a browser the landing page of your skeleton project.

# Stop the php webserver and release the port, we will need it later on.
php bin/console server:stop;

Install docker on Ubuntu

First of all, make sure your system is clean and remove any old versions:

sudo apt-get remove docker docker-engine docker.io containerd runc;
# You might want to execute `sudo apt autoremove -y;` as well to cleanup everything. We cannot ask everyone to do so as we are not sure of what complications it might have on each computer+software configurations.

We will be installing docker by adding its repositories to our system:

sudo apt-get update;
sudo apt-get install ca-certificates curl gnupg lsb-release;
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg;
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null;
sudo apt-get update;
sudo apt-get install docker-ce docker-ce-cli containerd.io;
sudo docker run hello-world;

If the installation was OK, you should see the following message:

n$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:cc15c5b292d8525effc0f89cb299f1804f3a725c8d05e158653a563f15e4f685
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Make the docker application image

Execute the following command on a terminal to get your php version:

php --version;

In case you get something different than version 7.4, please note it and update the contents of the DockerFile below accordingly. In our case, the results for the version were the ones right below and that is why we used the line FROM php:7.4-cli in our DockerFile.

$ php --version
PHP 7.4.3 (cli) (built: Oct 25 2021 18:20:54) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies

If you are not already at the root of your project (e.g., the symfony-skeleton folder), go to that folder and create a new text file with the name Dockerfile in there. The contents of the file should be the following:

# Dockerfile
FROM php:7.4-cli

RUN apt-get update -y && apt-get install -y libmcrypt-dev

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN apt-get update && apt-get install -y libonig-dev
RUN docker-php-ext-install pdo

WORKDIR /app
COPY . /app

RUN composer install

EXPOSE 8000
CMD php bin/console server:run 0.0.0.0:8000

Once you have Docker and Docker Machine installed on your machine, creating the container is a breeze. The command below will seek your Dockerfile and download all of the layers required to execute your container image. It will then complete the commands in the Dockerfile, leaving you with a container that is ready to use.

You’ll use the docker build command to create your php Symfony docker container, and you’ll give it a tag or a name so you can refer to it later when you want to execute it. The command’s final component instructs Docker to build from a specific directory.

sudo docker build -t symfony-project .;

To execute the new application image:

sudo docker run -it -p 8000:8000 symfony-project;

To export the Docker image as a tar file:

sudo docker save -o ~/symfony-skeleton.tar symfony-project;

To import the Docker image from the tar file:

sudo docker load -i symfony-skeleton.tar;


Simple PHP script that lists all files in a directory, sorts them by modification date, and creates hyperlinks for each

<?php

echo '<html>';

$ignore = array('.', '..', 'index.php');
$files = array();

foreach (scandir($dir) as $file) {
  if (in_array($file, $ignore)) {
    continue;
  }
  $files[$file] = filemtime($dir . '/' . $file);
}

arsort($files);

$keys = array_keys($files);

foreach ($files as $key => $value) {
  echo date('r', $value), ' <a href="', $dir, '/', $key, '">', $key, '</a><br/>';
}

echo 'Done';

echo '</html>';
?>

How To Install on GNU/Linux CentOS 7 the LAMP stack (Apache, MySQL, PHP) + phpMyAdmin

Following you will find the commands to perform the installation of the LAMP stack (Apache, MySQL, PHP) and phpMyAdmin on a GNU/Linux CentOS 7.
In this guide we kept the information to the bare minimum about what is what.

Installation

To perform the installation, please execute the following as a user with administrative rights:

#Update your system
sudo yum update -y;
#Install Apache, MariaDB (MySQL), PHP (with MySQL support and phpMyAdmin which is a free software tool written in PHP, intended to handle the administration of MySQL over the Web)
sudo yum install httpd mariadb-server mariadb php php-mysql phpmyadmin -y;
#Start Apache (PHP will start with Apache as module)
sudo systemctl start httpd;
#Enable Apache to start on boot
sudo systemctl enable httpd;
#Start MariaDB(MySQL)
sudo systemctl start mariadb;
#Enable MariaDB(MySQL) to start on boot
sudo systemctl enable mariadb;

Configuration of MariaDB (MySQL)

By now, your system should have all necessary packages installed and the services up and running.
Now it is best to configure your MariaDB (MySQL) in a way to disable some test data and test accounts and assign a password to your root user.
Execute the following to do so:

sudo mysql_secure_installation;

This tool will ask you for your current database root password. Since you just installed MariaDB (MySQL) you should not have one, so leave the field empty and press enter.
We recommend to answer with Y (Yes) in all of the security questions of this tool and set a strong password for your root user.

sudo mysql_secure_installation;

Following is the output we got from this tool:

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
 SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
 password for the root user.  If you've just installed MariaDB, and
 you haven't set the root password yet, the password will be blank,
 so you should just press enter here.

Enter current password for root (enter for none):
 OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
 root user without the proper authorisation.

Set root password? [Y/n] Y
 New password:
 Re-enter new password:
 Password updated successfully!
 Reloading privilege tables..
 ... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone
 to log into MariaDB without having to have a user account created for
 them.  This is intended only for testing, and to make the installation
 go a bit smoother.  You should remove them before moving into a
 production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
 ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
 access.  This is also intended only for testing, and should be removed
 before moving into a production environment.

Remove test database and access to it? [Y/n] Y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
 will take effect immediately.

Reload privilege tables now? [Y/n] Y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
 installation should now be secure.

Thanks for using MariaDB!

Configuration of the firewall

Executing the following will enable access to your web-server from the network for http and https.

sudo firewall-cmd --permanent --zone=public --add-service=http;
sudo firewall-cmd --permanent --zone=public --add-service=https;
sudo firewall-cmd --reload;

Location of files / Where to upload your website

In CentOS 7, the directory where the website pages are located is at /var/www/html/.
You can place your html and php code there.

Configuration of phpMyAdmin

phpMyAdmin should be available at http://<IP of the web server>/phpmyadmin
The access to phpMyAdmin is controlled by the Apache Virtual Host File for phpMyAdmin that is found here /etc/httpd/conf.d/phpMyAdmin.conf.
By default, this configuration file only allows access to phpMyAdmin from the localhost (127.0.0.1).
In case you want to access it from another machine, you need to modify this file.
Before doing any changes, make a backup of the original file first:

 sudo cp /etc/httpd/conf.d/phpMyAdmin.conf /etc/httpd/conf.d/phpMyAdmin.conf.original;

To enable access only for a specific IP

Edit the Apache Virtual Host File for phpMyAdmin (/etc/httpd/conf.d/phpMyAdmin.conf) and change every reference of 127.0.0.1 with the IP address of the machine you want to give access to.

There should be four lines that you need to change.
In our installation it was the following lines:

  1. 17Require ip 127.0.0.1
  2. 25Allow from 127.0.0.1
  3. 34Require ip 127.0.0.1
  4. 42Allow from 127.0.0.1

Then restart the Apache service to apply the changes:

sudo systemctl restart httpd;

To enable access to any IP

Delete the existing file and create a new one.

sudo rm /etc/httpd/conf.d/phpMyAdmin.conf;
sudo touch /etc/httpd/conf.d/phpMyAdmin.conf;

Using the editor of your choice add the following content and save it:

Alias /phpMyAdmin /usr/share/phpMyAdmin
Alias /phpmyadmin /usr/share/phpMyAdmin

<Directory /usr/share/phpMyAdmin/>
 AllowOverride None
 Options None
 Allow from All
 Require all granted
</Directory>

Then restart the Apache service to apply the changes:

sudo systemctl restart httpd;

Following is the original content of our Apache Virtual Host File for phpMyAdmin (/etc/httpd/conf.d/phpMyAdmin.conf)

phpMyAdmin.conf (compressed) (706 downloads)

$ cat /etc/httpd/conf.d/phpMyAdmin.conf
 # phpMyAdmin - Web based MySQL browser written in php
 #
 # Allows only localhost by default
 #
 # But allowing phpMyAdmin to anyone other than localhost should be considered
 # dangerous unless properly secured by SSL

Alias /phpMyAdmin /usr/share/phpMyAdmin
Alias /phpmyadmin /usr/share/phpMyAdmin

<Directory /usr/share/phpMyAdmin/>
 AddDefaultCharset UTF-8

 <IfModule mod_authz_core.c>
  # Apache 2.4
  <RequireAny>
   Require ip 192.168.0.20
   Require ip ::1
  </RequireAny>
 </IfModule>
 <IfModule !mod_authz_core.c>
  # Apache 2.2
  Order Deny,Allow
  Deny from All
  Allow from 192.168.0.20
  Allow from ::1
  </IfModule>
</Directory>

<Directory /usr/share/phpMyAdmin/setup/>
 <IfModule mod_authz_core.c>
  # Apache 2.4
  <RequireAny>
   Require ip 192.168.0.20
   Require ip ::1
  </RequireAny>
 </IfModule>
 <IfModule !mod_authz_core.c>
  # Apache 2.2
  Order Deny,Allow
  Deny from All
  Allow from 192.168.0.20
  Allow from ::1
 </IfModule>
</Directory>

# These directories do not require access over HTTP - taken from the original
# phpMyAdmin upstream tarball
#
 <Directory /usr/share/phpMyAdmin/libraries/>
  Order Deny,Allow
  Deny from All
  Allow from None
 </Directory>

<Directory /usr/share/phpMyAdmin/setup/lib/>
  Order Deny,Allow
  Deny from All
  Allow from None
</Directory>

<Directory /usr/share/phpMyAdmin/setup/frames/>
 Order Deny,Allow
 Deny from All
 Allow from None
</Directory>

# This configuration prevents mod_security at phpMyAdmin directories from
# filtering SQL etc.  This may break your mod_security implementation.
#
#<IfModule mod_security.c>
#    <Directory /usr/share/phpMyAdmin/>
#        SecRuleInheritance Off
#    </Directory>
#</IfModule>

phpMyAdmin.conf (compressed) (706 downloads)


PHP: Convert JavaScript-escaped Unicode characters to HTML hex references

There are cases where one might receive in PHP, escaped Unicode characters from the client side JavaScript. According to the RFC it is normal for JavaScript to convert characters to that format and in effect that we receive any character in the escaped format of \uXXXX in PHP.

Any character may be escaped.
If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF),
then it may be represented as a six-character sequence:
a reverse solidus, followed by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point.
The hexadecimal letters A though F can be upper or lowercase.

A sample input you might receive could look like this George\u2019s treasure box instead of George’s treasure box.

This kind of input should not be stored as is as it does not make sense to the HTML language, instead we should fix it up using preg_replace.

$decoded = preg_replace('/\\\\u([a-fA-F0-9]{4})/', '&#x\\1;', $input);

The above command will look for all instances of \uXXXX in the $input and it will replace each one with the appropriate character using the XXXX value that it will match.

What this part '/\\\\u([a-fA-F0-9]{4})/' of the code do is the following:

  • \\\\ – Find the character \ in the string, the reason we have four \ instead of one, is because it has special meaning in the regular expression and we have to escape it. For that reason we need to use two of them and get \\. After that, we need to escape each of them again due to the special meaning they have in PHP and we end up with four of them.
  • u – The previous step must be followed by a u character.
  • ([a-fA-F0-9]{4}) – After the previous step has matched, we need to match 4 characters. Each of them must be either a character from A-Z or a-z or 0-9.

This part '&#x\\1;' will:

  • &#x – Is a constant string that will print the characters &#x. These characters will instruct HTML to print the character that will occur using hexadecimal entity reference that will follow.
  • \\1 – Contains the reference of the 1st parenthesized pattern. In this case we only have a parenthesis around the XXXX part of the \uXXXX so \\1 will be replaced with the XXXX value.