1010 lines
30 KiB
Markdown
1010 lines
30 KiB
Markdown
---
|
||
categories: web
|
||
title: Howto PHP
|
||
...
|
||
|
||
* Documentation : <http://php.net/manual/en/>
|
||
* Rôle Ansible : <https://forge.evolix.org/projects/ansible-roles/repository/show/php>
|
||
|
||
[PHP](http://php.net/) est un langage de programmation populaire
|
||
pour le développement web. PHP peut s'utiliser en CLI (ligne de
|
||
commande), via mod_php (module intégré à [Apache](HowtoApache)) ou
|
||
via FPM (FastCGI Process Manager).
|
||
|
||
|
||
Il existe [plusieurs versions de PHP](http://php.net/supported-versions.php).
|
||
Voici les versions de PHP actuellement supportées sous Debian :
|
||
|
||
* Debian 7 : PHP 5.4
|
||
* Debian 8 : PHP 5.6
|
||
* Debian 9 : PHP 7.0
|
||
* Debian 10 : PHP 7.3
|
||
* Debian 11 : PHP 7.4
|
||
* Debian 12 : PHP 8.2
|
||
|
||
## Installation
|
||
|
||
Nous installons toujours PHP CLI, certaines dépendances classiques
|
||
ainsi que les outils [Composer](https://getcomposer.org/) et
|
||
[PHPMailer](https://github.com/PHPMailer/PHPMailer) :
|
||
|
||
~~~
|
||
# apt install php php-cli php-curl php-mysql php-pgsql php-ldap php-imap php-gd php-ssh2 php-xml composer libphp-phpmailer
|
||
|
||
$ php -v
|
||
PHP 7.4.25 (cli) (built: Oct 23 2021 21:53:50) ( NTS )
|
||
Copyright (c) The PHP Group
|
||
Zend Engine v3.4.0, Copyright (c) Zend Technologies
|
||
with Zend OPcache v7.4.25, Copyright (c), by Zend Technologies
|
||
|
||
$ composer -V
|
||
Composer 2.0.9 2021-01-27 16:09:27
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 9/10, on installe aussi les paquets `php-mcrypt` et `php-gettext`
|
||
|
||
|
||
> *Note* : Pour Debian 8, on a PHP 5.6 qu'il faut installer ainsi (et il n'y a pas de package pour _composer_) :
|
||
>
|
||
> ~~~
|
||
> # apt install php5 php5-cli php5-curl php5-mysql php5-pgsql php5-mcrypt php5-ldap php5-imap php5-gd php5-ssh2 php-gettext libphp-phpmailer
|
||
> ~~~
|
||
|
||
### PHP avec deb.sury.org
|
||
|
||
Si l'on a vraiment besoin d'une version de PHP plus récente (par exemple PHP 8.0 ou 8.1),
|
||
il est possible de l'installer avec le dépôt [deb.sury.org](https://deb.sury.org/)
|
||
d'Ondřej Surý (l'un des mainteneurs officiels des paquets PHP sous Debian).
|
||
|
||
On peut d'ailleurs ainsi avoir plusieurs versions de PHP en même temps,
|
||
que l'on pourra utiliser pour différents sites web, via PHP-FPM par exemple.
|
||
|
||
~~~
|
||
# wget -O /etc/apt/trusted.gpg.d/sury.gpg https://packages.sury.org/php/apt.gpg
|
||
# dos2unix /etc/apt/trusted.gpg.d/sury.gpg
|
||
# chmod 644 /etc/apt/trusted.gpg.d/sury.gpg
|
||
# echo "deb https://packages.sury.org/php/ bullseye main" > /etc/apt/sources.list.d/sury.list
|
||
~~~
|
||
|
||
Attention, vous aurez automatiquement la version la plus récente installée,
|
||
car les paquets "php-foo" dépendent de la dernière version de PHP disponible.
|
||
Lors d'une mise-à-jour, vous pourrez avoir la surprise de voir
|
||
votre ligne de commande `php` passer de PHP 8.0 à 8.1 par exemple.
|
||
|
||
Pour éviter cela, et avoir strictement une seule version fixe de PHP, nous proposons
|
||
des paquets "php-foo" fixes. Ainsi, pour PHP 8.0, vous aurez dans vos sources :
|
||
|
||
~~~
|
||
deb http://pub.evolix.org/evolix bullseye-php80 main
|
||
deb https://packages.sury.org/php/ bullseye main
|
||
~~~
|
||
|
||
Et vous installerez PHP normalement (à part les paquets php-igbinary et php-redis que vous devrez forcer en version 8.0) :
|
||
|
||
~~~
|
||
# apt install php php-cli php-curl php-mysql php-pgsql php-ldap php-imap php-gd php-xml composer libphp-phpmailer php-ssh2
|
||
~~~
|
||
|
||
Pour PHP 8.1, mettez dans vos sources :
|
||
|
||
~~~
|
||
deb http://pub.evolix.org/evolix bullseye-php81 main
|
||
deb https://packages.sury.org/php/ bullseye main
|
||
~~~
|
||
|
||
Puis installez PHP normalement :
|
||
|
||
~~~
|
||
# apt install php php-cli php-curl php-mysql php-pgsql php-ldap php-imap php-gd php-xml composer libphp-phpmailer php-ssh2
|
||
~~~
|
||
|
||
**Nettoyage :**
|
||
|
||
Si des paquets Sury sont déjà installés (par exemple) en PHP 7.4, ils ne seront pas forcément mis à jour en 8.0, il faudra le faire à la main :
|
||
|
||
1. Lister les paquets non PHP 8.0 restants : `dpkg -l 'php*' | grep -P '^ii.*php\d\.\d' | grep -v php8.0`
|
||
2. Vérifier qu'ils sont bien présents comme `php-<module>` ou `php8.0-<module>` : `dpkg -l 'php*' | grep '^ii' | grep -E "php[(8.0)-]"`
|
||
3. S'ils manquent, les installer avec le paquet « générique » (`apt install php-<module>`). Si le paquet générique n'existe pas, les installer avec le paquet PHP 8.0 (`apt install php8.0-<module>`)
|
||
4. Purger les paquets des anciennes versions (exemple avec PHP 7.4, à adapter) : dpkg -l php7.4* | awk '/php7.4/ {print $2}' | xargs apt purge -y
|
||
|
||
|
||
Idem pour PHP 8.1 :
|
||
|
||
~~~
|
||
deb http://pub.evolix.org/evolix bullseye-php81 main
|
||
deb https://packages.sury.org/php/ bullseye main
|
||
~~~
|
||
|
||
~~~
|
||
# apt install php php-cli php-curl php-mysql php-pgsql php-ldap php-imap php-gd php-xml composer libphp-phpmailer php-ssh2
|
||
~~~
|
||
|
||
**Nettoyage :** voir si dessus comme pour PHP 8.0.
|
||
|
||
|
||
### PHP-FPM
|
||
|
||
PHP-FPM (FastCGI Process Manager) est une façon alternative d'utiliser
|
||
PHP avec [Apache](HowtoApache) ou [Nginx](HowtoNginx).
|
||
|
||
~~~
|
||
# apt install php-fpm
|
||
|
||
# systemctl status php7.0-fpm
|
||
● php7.0-fpm.service - The PHP 7.0 FastCGI Process Manager
|
||
Loaded: loaded (/lib/systemd/system/php7.0-fpm.service; enabled; vendor preset: enabled)
|
||
Docs: man:php-fpm7.0(8)
|
||
Main PID: 1516 (php-fpm7.0)
|
||
Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
|
||
CGroup: /system.slice/php7.0-fpm.service
|
||
├─1516 php-fpm: master process (/etc/php/7.0/fpm/php-fpm.conf)
|
||
├─1517 php-fpm: pool www
|
||
└─1518 php-fpm: pool www
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 8, il faut installer ainsi :
|
||
>
|
||
> ~~~
|
||
> # apt install php5-fpm
|
||
> ~~~
|
||
|
||
|
||
### mod_php
|
||
|
||
~~~
|
||
# apt install libapache2-mod-php
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 8, il faut installer ainsi :
|
||
>
|
||
> ~~~
|
||
> # apt install libapache2-mod-php5
|
||
> ~~~
|
||
|
||
|
||
## Configuration
|
||
|
||
<https://secure.php.net/manual/en/install.fpm.configuration.php>
|
||
|
||
Fichiers de configuration :
|
||
|
||
~~~
|
||
/etc/php/7.0/
|
||
├── apache2
|
||
│ ├── conf.d
|
||
│ │ ├── [...]
|
||
│ │ └── 20-xsl.ini -> /etc/php/7.0/mods-available/xsl.ini
|
||
│ └── php.ini
|
||
├── cli
|
||
│ ├── conf.d
|
||
│ │ ├── [...]
|
||
│ │ └── 20-xsl.ini -> /etc/php/7.0/mods-available/xsl.ini
|
||
│ └── php.ini
|
||
├── fpm
|
||
│ ├── conf.d
|
||
│ │ ├── [...]
|
||
│ │ └── 20-xsl.ini -> /etc/php/7.0/mods-available/xsl.ini
|
||
│ ├── php-fpm.conf
|
||
│ ├── php.ini
|
||
│ └── pool.d
|
||
│ └── www.conf
|
||
└── mods-available
|
||
├── [...]
|
||
└── xsl.ini
|
||
~~~
|
||
|
||
On peut valider une configuration avec le binaire php-fpmx.y
|
||
|
||
~~~
|
||
# php-fpm7.3 -t
|
||
~~~
|
||
|
||
### Configuration de base (php.ini)
|
||
|
||
Il existe un fichier `php.ini` distinct suivant l’utilisation de
|
||
PHP : cli, mod_php et FPM.
|
||
Par exemple `/etc/php/7.0/fpm/php.ini` pour FPM.
|
||
|
||
Le fichier `/etc/php/7.0/fpm/conf.d/z-evolinux-defaults.ini` contient
|
||
nos optimisations basiques :
|
||
|
||
~~~
|
||
short_open_tag = Off
|
||
expose_php = Off
|
||
display_errors = Off
|
||
log_errors = On
|
||
html_errors = Off
|
||
allow_url_fopen = Off
|
||
memory_limit = 128M
|
||
max_execution_time = 10
|
||
open_basedir = /home
|
||
disable_functions = exec, shell-exec, system, passthru, putenv, popen
|
||
~~~
|
||
|
||
### Configuration FPM
|
||
|
||
Voici les directives de base :
|
||
|
||
~~~
|
||
[global]
|
||
pid = /run/php/php7.0-fpm.pid
|
||
error_log = /var/log/php5-fpm.log
|
||
~~~
|
||
|
||
On définit ensuite un ou plusieurs *pools* FPM via
|
||
`/etc/php/7.0/fpm/pool.d/*.conf` :
|
||
|
||
~~~
|
||
[www]
|
||
listen = /run/php/php7.0-fpm.sock
|
||
;listen = 127.0.0.1:9000
|
||
user = www-data
|
||
group = www-data
|
||
pm = dynamic
|
||
|
||
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f return-path@example.com
|
||
php_flag[display_errors] = off
|
||
php_admin_value[error_log] = /var/log/fpm-php.www.log
|
||
php_admin_flag[log_errors] = on
|
||
php_admin_value[memory_limit] = 32M
|
||
~~~
|
||
|
||
L'option **pm** (process manager) permet de choisir comment seront
|
||
contrôlés les process fils : static, ondemand ou dynamic.
|
||
|
||
Le mode standard est **dynamic** : FPM va préparer des process en
|
||
attente (au minimum 1) et les faire varier en fonction de la demande
|
||
(de façon similaire à ce que peut faire
|
||
[Apache](HowtoApache#configuration-de-base)).
|
||
|
||
|
||
~~~
|
||
pm = dynamic
|
||
pm.max_children = 100
|
||
pm.start_servers = 25
|
||
pm.min_spare_servers = 20
|
||
pm.max_spare_servers = 30
|
||
pm.max_requests = 100
|
||
~~~
|
||
|
||
Avec de nombreux pools, on optera pour le mode **ondemand** qui ne
|
||
prépare pas de process mais les crée à chaque demande. D'après nos
|
||
tests, les performances restent − étonnamment − tout à fait
|
||
acceptables.
|
||
|
||
|
||
~~~
|
||
pm = ondemand
|
||
pm.max_children = 100
|
||
pm.process_idle_timeout = 10s
|
||
~~~
|
||
|
||
D'autres options de FPM sont intéressantes :
|
||
|
||
~~~
|
||
slowlog = /var/log/php-fpm_$pool.log.slow
|
||
request_slowlog_timeout = 5s
|
||
|
||
pm.status_path = /fpm_status
|
||
request_terminate_timeout = 60s
|
||
chroot = /home/foo
|
||
access.log = log/$pool.access.log
|
||
~~~
|
||
|
||
Pour slowlog, lire <https://serverpilot.io/docs/how-to-read-the-php-slow-request-log>
|
||
|
||
#### Configuration FPM avec Nginx
|
||
|
||
On configure FPM avec Nginx, par exemple dans un Virtualhost :
|
||
|
||
~~~
|
||
server {
|
||
listen 80;
|
||
server_name www.example.com example.com;
|
||
root /home/foo/www;
|
||
index index.php;
|
||
|
||
location ~ \.php$ {
|
||
try_files $uri =404;
|
||
#fastcgi_pass 127.0.0.1:9000;
|
||
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
|
||
fastcgi_param SCRIPT_FILENAME /home/foo/www$fastcgi_script_name;
|
||
include fastcgi_params;
|
||
}
|
||
}
|
||
~~~
|
||
|
||
#### Configuration FPM avec Apache
|
||
|
||
Cela nécessite le module proxy_fcgi :
|
||
|
||
~~~
|
||
# a2enmod proxy_fcgi
|
||
Considering dependency proxy for proxy_fcgi:
|
||
Enabling module proxy.
|
||
Enabling module proxy_fcgi.
|
||
~~~
|
||
|
||
On configure FPM avec Apache, par exemple dans un VirtualHost :
|
||
|
||
~~~{.apache}
|
||
DocumentRoot /home/bench/www/
|
||
#ProxyPassMatch "^/(.*\.php(/.*)?)$" "fcgi://127.0.0.1:9000//home/foo/www/$1"
|
||
ProxyPassMatch "^/(.*\.php(/.*)?)$" "unix:/var/run/php/php7.0-fpm.sock|fcgi://localhost/home/foo/www/"
|
||
~~~
|
||
|
||
### Configuration mod_php
|
||
|
||
Avec mod_php on peut forcer la plupart des options du php.ini dans
|
||
la configuration Apache.
|
||
|
||
|
||
Par exemple, au sein d'un VirtualHost on peut mettre les paramètres
|
||
suivants :
|
||
|
||
~~~
|
||
<VirtualHost *:80>
|
||
|
||
#php_admin_flag engine off
|
||
#AddType text/html .html
|
||
#php_admin_flag display_errors On
|
||
#php_flag short_open_tag On
|
||
#php_flag register_globals On
|
||
#php_admin_value memory_limit 256M
|
||
#php_admin_value max_execution_time 60
|
||
#php_admin_value upload_max_filesize 8M
|
||
#php_admin_flag allow_url_fopen Off
|
||
php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f www-XXX"
|
||
php_admin_value open_basedir "/usr/share/php:HOME_DIR/XXX:/tmp"
|
||
~~~
|
||
|
||
|
||
## Sessions PHP
|
||
|
||
<http://php.net/manual/en/book.session.php>
|
||
|
||
Lorsque des sessions PHP sont utilisées (fonctions session_XXX()
|
||
dans le code), des informations sont stockées côté serveur. Le
|
||
navigateur conserve uniquement l'identifiant pour accéder à ces
|
||
informations, stockés dans un cookie ou une variable du type PHPSESSID
|
||
dans l'URL (cela tend à être obsolète).
|
||
|
||
Par défaut, ces informations sont conservées dans des fichiers sur
|
||
le disque (un fichier par session) mais il est conseillé d'utiliser
|
||
une méthode plus performante si vous avez un serveur dédié. Évidemment
|
||
il est fortement déconseillé de stocker les sessions dans une base
|
||
de données SQL…
|
||
|
||
|
||
|
||
* La méthode la plus simple si votre site web est en mono-serveur ou en mode sticky est de monter le répertoire qui stocker les fichiers en *TMPFS*. Cela se fait par exemple en ajoutant la ligne suivante dans votre _fstab_ :
|
||
|
||
|
||
~~~
|
||
tmpfs /var/lib/php/sessions tmpfs defaults,noexec,nosuid,nodev,size=256m 0 0
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 8 :
|
||
>
|
||
> ~~~
|
||
> tmpfs /var/lib/php5 tmpfs defaults,noexec,nosuid,nodev,size=256m 0 0
|
||
> ~~~
|
||
|
||
* Les sessions peuvent être stockées dans un ou plusieurs serveurs *Memcached* avec les paramètres suivants :
|
||
|
||
~~~
|
||
session.save_handler = memcached
|
||
session.save_path = "192.0.2.10:11211,192.0.2.11:11211"
|
||
~~~
|
||
|
||
Par contre, contrairement aux idées reçues, ce n'est pas conseillé.
|
||
Memcached est fait pour « cacher » et non « stocker ». Voir le
|
||
blog d'un développeur de Memcached à ce sujet :
|
||
<http://dormando.livejournal.com/495593.html>
|
||
|
||
* Les sessions peuvent être stockées dans un ou plusieurs serveurs *Redis* avec les paramètres suivants :
|
||
|
||
~~~
|
||
session.save_handler = redis
|
||
session.save_path = "tcp://192.0.2.10:6379?auth=PASSWORD,tcp://192.0.2.11:6379?auth=PASSWORD"
|
||
~~~
|
||
|
||
* Les sessions peuvent être stockées dans [Sharedance](http://www.pureftpd.org/project/sharedance), un petit logiciel spécialement conçu pour stocker les sessions PHP. Il n'est plus maintenu, mais très simple, il est toujours fonctionnel. Voici un exemple d'utilisation :
|
||
|
||
~~~
|
||
auto_prepend_file = /usr/local/etc/sharedance.php
|
||
;session.save_handler = user
|
||
;session.save_handler = files
|
||
~~~
|
||
|
||
* Les sessions peuvent être stockées dans *Tokyo Tyrant/Tycoon* avec les paramètres suivants :
|
||
|
||
~~~
|
||
tokyo_tyrant.session_salt="randomlongstring"
|
||
session.save_handler=tokyo_tyrant
|
||
session.save_path="tcp://192.0.2.10:1978,tcp://192.0.2.10:1978"
|
||
~~~
|
||
|
||
|
||
## Composer
|
||
|
||
* Documentation : <https://getcomposer.org/doc/>
|
||
|
||
[Composer](https://getcomposer.org/) est un outil moderne de gestion
|
||
des bibliothèques PHP, qui tend à remplacer le vieil outil
|
||
[PEAR](https://pear.php.net/). Il est disponible à partir de Debian
|
||
9.
|
||
|
||
Composer s'utilise sans les droits _root_. Il s'appuie sur la
|
||
présence d'un fichier `composer.json` qui déclare les bibliothèques
|
||
à installer.
|
||
|
||
~~~
|
||
$ composer about
|
||
Composer – Package Management for PHP
|
||
Composer is a dependency manager tracking local dependencies of your projects and libraries.
|
||
See https://getcomposer.org/ for more information.
|
||
|
||
$ echo '{"require": {"twig/extensions": "~1.0"}}' > composer.json
|
||
|
||
$ composer update
|
||
Loading composer repositories with package information
|
||
Updating dependencies (including require-dev)
|
||
- Installing symfony/polyfill-mbstring (v1.5.0)
|
||
Loading from cache
|
||
|
||
- Installing twig/twig (v2.4.3)
|
||
Loading from cache
|
||
|
||
- Installing twig/extensions (v1.5.1)
|
||
Loading from cache
|
||
|
||
twig/extensions suggests installing symfony/translation (Allow the time_diff output to be translated)
|
||
Writing lock file
|
||
Generating autoload files
|
||
|
||
$ composer show
|
||
symfony/polyfill-mbstring v1.5.0 Symfony polyfill for the Mbstring extension
|
||
twig/extensions v1.5.1 Common additional features for Twig that do not directly belong in core
|
||
twig/twig v2.4.3 Twig, the flexible, fast, and secure template language for PHP
|
||
~~~
|
||
|
||
|
||
### Installer la dernière version de Composer
|
||
|
||
Documentation officicelle :
|
||
|
||
* [Installation](https://getcomposer.org/doc/00-intro.md)
|
||
* [Installer programmatiquement](https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md)
|
||
|
||
Si on veut une version de Composer plus récente que celle fournie par la distribution Debian, on peut l'installer à partir du site de composer.
|
||
|
||
On peut installer Composer localement pour un utilisateur, ou globalement sur le sytème.
|
||
|
||
Evolix recommande des installations locales spécifiques pour chaque utilisateur.
|
||
|
||
Nous déconseillons une installation globale pour plusieurs raions de sécurité : exécution en tant que root, exécutable global sans les mises-à-jour de sécurité…
|
||
|
||
Télécharger Composer :
|
||
|
||
~~~
|
||
# su - <USER>
|
||
$ wget -q -O setup-composer.php https://getcomposer.org/installer
|
||
~~~
|
||
|
||
Vérifier la somme de contrôle :
|
||
|
||
~~~
|
||
$ sha384sum setup-composer.php
|
||
$ curl https://composer.github.io/installer.sig; echo
|
||
~~~
|
||
|
||
Installer Composer pour l'utilisateur :
|
||
|
||
~~~
|
||
$ mkdir bin
|
||
$ php setup-composer.php --install-dir=./bin --filename=composer
|
||
$ rm setup-composer.php
|
||
$ bin/composer --version
|
||
~~~
|
||
|
||
Exceptionnellement, s'il est nécessaire d'installer Composer globalement :
|
||
|
||
~~~
|
||
# php setup-composer.php --install-dir=/usr/local/bin --filename=composer
|
||
# rm setup-composer.php
|
||
# composer --version
|
||
~~~
|
||
|
||
|
||
## Module du framework phalcon
|
||
|
||
<https://docs.phalconphp.com/fr/latest/reference/install.html>
|
||
<https://github.com/phalcon/phalcon-devtools>
|
||
|
||
### Installation à partir des dépot
|
||
|
||
``` shell
|
||
# echo "deb https://packagecloud.io/phalcon/stable/debian/ $(awk -F= '/VERSION_CODENAME/{print$2}' /etc/os-release) main" \
|
||
> /etc/apt/sources.list.d/php-phalcon.list
|
||
# curl -Lo /etc/apt/trusted.gpg.d/php-phalcon.asc https://packagecloud.io/phalcon/stable/gpgkey
|
||
# chmod 644 /etc/apt/trusted.gpg.d/php-phalcon.asc
|
||
# apt update
|
||
# apt install php7.3-psr php7.3-phalcon
|
||
# php -m | grep phalcon
|
||
phalcon
|
||
```
|
||
|
||
### Instllation à partir de git (obsolète)
|
||
|
||
Installer les dépendances suivantes :
|
||
|
||
~~~
|
||
# apt install php7.0-dev libpcre3-dev gcc make php7.0-mysql
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 8 :
|
||
>
|
||
> ~~~
|
||
> # apt install php5-dev libpcre3-dev gcc make php5-mysql
|
||
> ~~~
|
||
|
||
Cloner la dernière version stable :
|
||
|
||
~~~
|
||
$ git clone --depth=1 https://github.com/phalcon/cphalcon.git
|
||
~~~
|
||
|
||
Compiler et installer le module :
|
||
|
||
~~~
|
||
$ cd cphalcon/build
|
||
# ./install
|
||
~~~
|
||
|
||
Configurer PHP et Apache :
|
||
|
||
Ajouter un fichier `phalcon.ini` :
|
||
|
||
~~~
|
||
extension=phalcon.so
|
||
~~~
|
||
|
||
Puis activer la configuration :
|
||
|
||
~~~
|
||
# ln -s mods-available/phalcon.ini cli/conf.d/30-phalcon.ini
|
||
# ln -s mods-available/phalcon.ini apache2/conf.d/30-phalcon.ini
|
||
# systemctl reload apache2
|
||
~~~
|
||
|
||
Pour installer les phalcon devtools :
|
||
|
||
~~~
|
||
$ git clone https://github.com/phalcon/phalcon-devtools.git
|
||
# cp phalcon-devtools/phalcon.php /usr/local/bin/phalcon
|
||
# chmod 755 /usr/local/bin/phalcon
|
||
~~~
|
||
|
||
|
||
## Debug
|
||
|
||
### strace
|
||
|
||
Au niveau système, on peut utilise `strace` pour voir exactement
|
||
ce qui est fait (ouvertures de fichiers, connexions distantes,
|
||
requêtes MySQL).
|
||
|
||
Exemple d'utilisations :
|
||
|
||
~~~
|
||
# Affiche les fichiers ouverts.
|
||
$ strace -ff -e trace=open php index.php
|
||
# Affiche les appels réseaux.
|
||
$ strace -ff -e trace=network php index.php
|
||
# Compte les appels systèmes et le temps passé.
|
||
$ strace -c php index.php
|
||
# Calcul du temps d'exécution d'un appel.
|
||
$ strace -T php index.php
|
||
# Affichage d'un timestamp devant chaque appel.
|
||
$ strace -ttt php index.php
|
||
# Strace verbeux.
|
||
$ strace -s 65535 -ff php index.php
|
||
~~~
|
||
|
||
Dans certains cas, des CMS gèrent mal le fait qu'on exécute le code
|
||
via PHP-CLI. On pourra utiliser PHP-CGI pour le tromper, c'est
|
||
notamment le cas de Magento.
|
||
|
||
~~~
|
||
$ HTTP_HOST="www.monsite.com" strace php-cgi index.php
|
||
~~~
|
||
|
||
Par exemple, on peut récupérer les requêtes MySQL ainsi.
|
||
|
||
~~~
|
||
$ strace -s65535 -e trace=write -ff -o strace php-cgi index.php
|
||
$ grep SELECT strace.*
|
||
~~~
|
||
|
||
### xdebug
|
||
|
||
<https://xdebug.org/docs/>
|
||
|
||
[Xdebug](https://xdebug.org/) est un débogueur PHP.
|
||
|
||
~~~
|
||
# aptitude install php-xdebug
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 8 :
|
||
>
|
||
> ~~~
|
||
> # aptitude install php5-xdebug
|
||
> ~~~
|
||
|
||
On aura ainsi un fichier `xdebug.ini` que l'on pourra compléter
|
||
ainsi :
|
||
|
||
~~~
|
||
zend_extension=/usr/lib/php5/20090626/xdebug.so
|
||
;xdebug.auto_trace=On
|
||
;xdebug.profiler_enable=1
|
||
xdebug.profiler_output_dir=/home/xdebug
|
||
xdebug.trace_output_dir=/home/xdebug
|
||
~~~
|
||
|
||
Pour activer dans un vhost Apache :
|
||
|
||
~~~
|
||
php_admin_value xdebug.profiler_enable 1
|
||
~~~
|
||
|
||
Attention, bien mettre les bons droits sur le répertoire _/home/xdebug_.
|
||
Notez qu'il peut se remplir très vite une fois activé !
|
||
|
||
On obtient des fichiers `trace.XXX.xt` et `cachegrind.out.XXXX`
|
||
|
||
Les fichiers `trace.XXX.xt` sont des traces de tous les appels aux
|
||
fonctions PHP du code préfixé par le temps d'exécution. Idéal pour
|
||
trouver une fonction anormalement longue. La seconde colonne contient
|
||
l'empreinte mémoire, idéal aussi pour repérer une fonction qui
|
||
utilise trop de mémoire.
|
||
|
||
Les fichiers `cachegrind.out.XXXX` peuvent être lus avec l'outil
|
||
_kcachegrind_ (pour Linux) ou _wincachegrind_ (sous Windows), cela
|
||
permet de schématiser les appels aux fonctions PHP et de voir le
|
||
temps passé en % et le nombre d'appels.
|
||
|
||
Voici un exemple :
|
||
|
||
![Ici, 30% du temps est passé dans php::uasort, appelé par Mage_Core_Model_Layout->getOutput.](/call141f0.png)
|
||
|
||
Webgrind en PHP permet de faire comme kcachegrind mais via un
|
||
navigateur :
|
||
|
||
~~~
|
||
$ git clone https://github.com/jokkedk/webgrind.git
|
||
~~~
|
||
|
||
Il faut mettre _profilerDir_ à _/home/xdebug_ dans `config.php`
|
||
Pour profiter du graphique « call graph » il faut installer le
|
||
package _graphviz_ et mettre dotExecutable à /usr/bin/dot.
|
||
|
||
### coredump
|
||
|
||
<https://bugs.php.net/bugs-generating-backtrace.php>
|
||
|
||
Installation :
|
||
|
||
~~~
|
||
# echo 'deb http://deb.debian.org/debian-debug/ stretch-debug main' > /etc/apt/sources.list.d/debug.list
|
||
# apt update
|
||
# apt install php7.0-common-dbgsym php7.0-cli-dbgsym
|
||
~~~
|
||
|
||
> *Note* : Pour Debian 8 :
|
||
>
|
||
> ~~~
|
||
> # aptitude install gdb php5-dbg
|
||
> ~~~
|
||
|
||
Pour activer :
|
||
|
||
~~~
|
||
# echo 1 > /proc/sys/kernel/core_uses_pid
|
||
# mkdir /home/coredump
|
||
# chmod 1777 /home/coredump
|
||
# echo '/home/coredump/core-%e-%p' > /proc/sys/kernel/core_pattern
|
||
# echo "* soft core unlimited" >> /etc/security/limits.conf
|
||
# ulimit -c unlimited
|
||
# echo "ulimit -c unlimited" >> /etc/default/apache2
|
||
# /etc/init.d/apache2 restart
|
||
~~~
|
||
|
||
Pour désactiver :
|
||
|
||
~~~
|
||
# echo '' > /proc/sys/kernel/core_pattern
|
||
~~~
|
||
|
||
Pour lire les traces de FPM :
|
||
|
||
~~~
|
||
$ gdb /usr/sbin/php-fpm core-php5-fpm.7409
|
||
|
||
(gdb) bt
|
||
(gdb) bt -100
|
||
~~~
|
||
|
||
Message typique, des erreurs de mémoire (souvent des boucles) :
|
||
|
||
~~~
|
||
#0 xbuf_format_converter (xbuf=0x77a812cee810, fmt=0xa6d5a1 "%ld", ap=Cannot access memory at address 0x77a812cedf10)
|
||
|
||
#0 0x00007ffd348abe53 in _zend_mm_free_canary_int (heap=0x7ffd39b11130, p=0x21143c453bb97f0f) at /build/buildd/php5-5.3.2/Zend/zend_alloc_canary.c:2090
|
||
2090 /build/buildd/php5-5.3.2/Zend/zend_alloc_canary.c: No such file or directory.
|
||
in /build/buildd/php5-5.3.2/Zend/zend_alloc_canary.c
|
||
|
||
#0 0x00000000007e10b1 in zend_mm_free_cache ()
|
||
~~~
|
||
|
||
Astuce : utiliser xdebug pour en savoir plus sur la boucle (xdebug
|
||
étant limité à 100 récursions, il affichera les infos via une PHP
|
||
Fatal Error :
|
||
|
||
~~~
|
||
Fatal error: Maximum function nesting level of '100' reached, aborting! in [...]
|
||
~~~
|
||
|
||
|
||
## Performance
|
||
|
||
### mod_php VS Apache/FPM VS Nginx/FPM
|
||
|
||
Fin 2016, voici nos résultats d'un test sur un serveur physique «
|
||
standard » avec une [application Symfony de
|
||
test](https://github.com/acseo/symfony-perf).
|
||
Nous avons utilisé `ab -n 1000 -c 100` (1000 requêtes dont 100 en
|
||
parallèle) avec nos configurations système par défaut :
|
||
|
||
~~~
|
||
* Apache prefork FPM :
|
||
|
||
Symfony hello ~105ms
|
||
Symfony form ~168ms
|
||
|
||
|
||
* Apache prefork mod_php :
|
||
|
||
Symfony hello ~106ms
|
||
Symfony form ~170ms
|
||
|
||
|
||
* Nginx FPM :
|
||
|
||
Symfony hello ~102ms
|
||
Symfony form ~164ms
|
||
~~~
|
||
|
||
### OpCache
|
||
|
||
OpCache est un module PHP qui réduit le temps d'exécution du code PHP. Il pré-compile le code PHP en byte-code et le stocke en cache.
|
||
Il remplace les « accélérateurs » comme APC, eAccelerator, etc. utilisés dans les versions précédentes de PHP.
|
||
|
||
~~~
|
||
# apt install phpX.X-opcache
|
||
~~~
|
||
|
||
La configuration se fait dans /etc/php/X.X/apache2/php.ini, `/etc/php/X.X/mods-available/opcache.ini`, mais on préfère mettre la configuration personnalisée dans `/etc/php/X.X/apache2/conf.d/*`.
|
||
|
||
Principaux paramètres :
|
||
|
||
* `opcache.memory_consumption` : Taille du cache, valeur par défaut : `128M`.
|
||
* `opcache.max_accelerated_files` : Nombre maximum de scripts cachés, valeur par défaut : `10000`. Attention [la valeur utilisée par OpCache](https://www.php.net/manual/fr/opcache.configuration.php#ini.opcache.max-accelerated-files) n'est pas exactement celle spécifiée).
|
||
|
||
Pour surveiller OpCache, on peut utiliser :
|
||
|
||
* <https://github.com/amnuts/opcache-gui>
|
||
* Plugins Munin : <https://github.com/munin-monitoring/contrib/blob/master/plugins/php/php_opcache> + <https://github.com/munin-monitoring/contrib/blob/master/plugins/php/php_opcache.php>
|
||
|
||
|
||
#### Reset du cache d'OpCache
|
||
|
||
OpCache ne détecte pas les changements dans le code PHP lorsque les déploiements sont fait avec des liens symboliques. Il existe une solution « automatique » seulement pour Nginx :
|
||
|
||
Dans le vhost, dans le bloc indiquant le chemin du socket PHP, ajouter après la dernière directive :
|
||
|
||
~~~
|
||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||
fastcgi_param DOCUMENT_ROOT $realpath_root;
|
||
~~~
|
||
|
||
**Attention :** Ces paramètres doivent être ajoutés après les inclusions (par exemple `include snippets/fastcgi-php.conf;`), car sinon les paramètres contenus dans la configuration inclue risqueraient d'écraser ceux que l'on vient d'ajouter.
|
||
|
||
Les autres possibilités, notamment dans le cas Apache, sont de reset le cache à la main.
|
||
|
||
On peut :
|
||
|
||
* Appeler la fonction PHP opcache_reset() (solution applicative)
|
||
* Note : dans le workflow de déploiement, cette fonction doit être appelée par le serveur web, et non par PHP en CLI.
|
||
* Redémarrer le service PHP-FPM (solution radicale).
|
||
* Utiliser CacheTool (solution CLI) :
|
||
|
||
~~~
|
||
php bin/cachetool.phar --fcgi=php-fpm73.sock opcache:reset --cli
|
||
~~~
|
||
|
||
**Attention :** Si l'on oublie l'option `--cli`, on rencontrera l'erreur suivante : `Error: Access denied`.
|
||
|
||
|
||
## HHVM
|
||
|
||
<https://github.com/facebook/hhvm/wiki/Prebuilt-Packages-on-Debian-8>
|
||
<https://github.com/facebook/hhvm/wiki/FastCGI>
|
||
|
||
~~~
|
||
# cd /etc/apt/trusted.gpg.d
|
||
# wget 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x36aef64d0207e7eee352d4875a16e7281be7a449' -O hhvm.asc
|
||
# chmod 644 hhvm.asc
|
||
# echo deb http://dl.hhvm.com/debian jessie main > /etc/apt/sources.list.d/hhvm.list
|
||
# apt update
|
||
# install hhvm
|
||
~~~
|
||
|
||
Configuration via le fichier `/etc/hhvm/server.ini`, on pourra
|
||
passer en mode socket plutôt que sur un port TCP :
|
||
|
||
~~~
|
||
;hhvm.server.port = 9000
|
||
hhvm.server.file_socket=/var/run/hhvm/sock
|
||
~~~
|
||
|
||
Mise en place avec Nginx :
|
||
|
||
~~~
|
||
# /usr/share/hhvm/install_fastcgi.sh
|
||
# /etc/init.d/nginx restart
|
||
~~~
|
||
|
||
Cela crée le fichier `/etc/nginx/hhvm.conf` :
|
||
|
||
~~~
|
||
location ~ \.(hh|php)$ {
|
||
fastcgi_keep_conn on;
|
||
#fastcgi_pass 127.0.0.1:9000;
|
||
fastcgi_pass unix:/var/run/hhvm/sock
|
||
fastcgi_index index.php;
|
||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||
include fastcgi_params;
|
||
}
|
||
~~~
|
||
|
||
HHVM écoute par défaut sur le port 9000 (attention si vous avez une
|
||
configuration FPM qui écoute aussi sur ce port-là). Il faudra
|
||
inclure ce fichier de configuration dans votre vhost qui a besoin
|
||
de HHVM.
|
||
|
||
~~~
|
||
include /etc/nginx/hhvm.conf;
|
||
~~~
|
||
|
||
|
||
## FAQ
|
||
|
||
### Utiliser locale fr_FR.utf-8
|
||
|
||
PHP utilise les locales situés dans le dossier /usr/lib/locale/fr_FR/. Si le dossier est vide alors on peut le completer avec le paquet `locales-all`.
|
||
|
||
### J'ai un message d'erreur du type : _/usr/lib/php5/20090626/xcache.so doesn't appear to be a valid Zend extension_
|
||
|
||
Remplacer `zend_extension=` par `extension=` pour le chargement du
|
||
module PHP.
|
||
|
||
### Certaines fonctions GD n'existent pas : imagerotate(), imageantialias(), etc.
|
||
|
||
Pour des raisons de sécurité et de maintenabilité, la version de
|
||
PHP de Debian n'embarque par le GD modifié par PHP. Ces fonctions
|
||
ne sont pas disponibles. Pour contourner ce problème, nous conseillons
|
||
d'écrire vos propres fonctions (il y a des exemples sur
|
||
<https://secure.php.net/>). Cela peut éventuellement être mis dans
|
||
un fichier partagé qui sera ensuite inclus systématiquement dans
|
||
votre code lorsque l'utilisation est nécessaire.
|
||
|
||
|
||
### Site avec accents en ISO-8859 cassés
|
||
|
||
Si vous avez des fichiers PHP en ISO-8859, on peut forcer son
|
||
utilisation via `default_charset ISO-8859-15`. À noter que pour les
|
||
fichiers HTML ou TXT, on peut utiliser l'option Apache `AddDefaultCharset
|
||
ISO-8859-15`.
|
||
|
||
### Mes fonctions mysql_connect, mysql_pconnect, etc. ne fonctionnent plus en PHP 7
|
||
|
||
Il est conseillé d'utiliser PDO_MySQL, mais une méthode rapide est
|
||
d'utiliser l'extension mysqli : <http://php.net/manual/fr/book.mysqli.php>
|
||
La plupart des fonctions sont identiques avec mysqli... il suffit
|
||
de remplacer `mysql_` par `mysqli_` !
|
||
|
||
Quelques exceptions :
|
||
|
||
* mysql_pconnect() doit être remplacé par mysqli_connect()
|
||
* mysqli_error() doit avoir un argument : le résultat de mysqli_connect()
|
||
* mysqli_select_db(), mysqli_query() doivent avoir le résultat de mysqli_connect() en 1er argument et non plus en second
|
||
|
||
### Erreurs avec le module php5-mysql
|
||
|
||
Si vous avez des erreurs avec le module php5-mysql de Debian 7 (PHP
|
||
5.4) du type _ ERROR 1148 : The used command is not allowed with
|
||
this MySQL version_ une solution peut être d'utiliser le module
|
||
alternatif php5-mysqlnd
|
||
|
||
### Connaître les codes d'Error Reporting php :
|
||
|
||
Pour calculer le nombre d'error reporting php dans la configuration
|
||
php, dans un vhost ou un .htacccess ce lien les répertories :
|
||
<https://maximivanov.github.io/php-error-reporting-calculator/>
|
||
|
||
### Désactiver l'envoi de mail (dans un VirtualHost par exemple)
|
||
|
||
Il faut configurer la variable *sendmail_path* à /bin/true comme
|
||
ceci, par exemple dans un VirtualHost :
|
||
|
||
~~~
|
||
php_admin_value sendmail_path "/bin/true -t -i -f www-foo"
|
||
~~~
|
||
|
||
### Désactiver la fonction mail()
|
||
|
||
~~~
|
||
php_admin_value sendmail_path "/bin/true"
|
||
~~~
|
||
|
||
### `allow_url_fopen = Off` empêche d’utiliser file_get_contents
|
||
|
||
La solution est d’utiliser
|
||
[fsockopen()](https://secure.php.net/manual/fr/function.fsockopen.php)
|
||
plutôt que
|
||
[file_get_contents()](https://secure.php.net/manual/fr/function.file-get-contents.php).
|
||
Il faut faire attention parce que cette API est aussi vulnérable a
|
||
[certaines attaques](https://www.owasp.org/index.php/PHP_Top_5).
|
||
|
||
|
||
Exemple pour [Google Recaptcha](http://www.google.com/recaptcha/intro/v3.html):
|
||
|
||
Remplacer
|
||
|
||
```
|
||
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
|
||
```
|
||
|
||
Par
|
||
|
||
```
|
||
$recaptcha = new \ReCaptcha\ReCaptcha($secret, new \ReCaptcha\RequestMethod\SocketPost());
|
||
```
|
||
|
||
|
||
### Répertoire temporaire pour ImageMagick
|
||
|
||
Par défaut ImageMagick met ses données temporaires dans `/tmp`. Dans le cas où le volume monté sur `/tmp` est trop petit, on peut modifier le répertoire temporaire dans le fichier `/etc/ImageMagick-6/policy.xml` :
|
||
|
||
```xml
|
||
<policymap>
|
||
<policy domain="resource" name="temporary-path" value="/home/imagicktmp"/>
|
||
</policymap>
|
||
```
|
||
|
||
|
||
### Erreur opendir /var/lib/php/sessions failed Permission denied
|
||
|
||
Contrairement à ce qui est affirmé sur certains forums, il ne faut pas changer les permissions sur ce dossier, au risque de s'exposer à des usurpations de sessions.
|
||
|
||
Sur Debian, les sessions sont nettoyées automatiquement par le service systemd `phpsessionclean` déclenché par un timer. C'est pour cette raison que la variable PHP session.gc_probability est mise à 0 dans la configuration par défaut de Debian.
|
||
|
||
Certaines applications comme Symfony outrepassent cette configuration et tentent d'effectuer elles-mêmes le nettoyage de sesssion. Il faut le désactiver explicitement au niveau de l'application.
|
||
|
||
Le service systemd `phpsessionclean` est parfois en erreur dans les conteneurs LXC Debian 10 et 11 à cause de AppArmor. Pour résoudre le problème, il faut ajouter `lxc.apparmor.profile = unconfined` à la configuration du conteneur et le redémarrer. On peut ensuite vérifier le bon fonctionnement du service `phpsessionclean`.
|
||
|
||
|