--- categories: web title: Howto PHP ... * Documentation : * Rôle Ansible : [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.45 * Debian 8 : PHP 5.6.19 * Debian 9 : PHP 7.0.10 ## 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-mcrypt php-ldap php-imap php-gd php-ssh2 php-gettext composer libphp-phpmailer $ php -v PHP 7.0.19-1 (cli) (built: May 11 2017 14:04:47) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies with Zend OPcache v7.0.19-1, Copyright (c) 1999-2017, by Zend Technologies $ composer -V Composer version 1.2.2 2016-11-03 17:43:15 ~~~ > *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 absolument besoin d'une version de PHP plus récente (par exemple PHP 7.3), il est possible de l'installer pour Debian 9 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). Il est d'ailleurs préférable d'utiliser les paquets PHP qui précisent la version de php (php7.0, php7.1, php7.2 ou php7.3 - exemple php7.3-curl ou libapache2-mod-php7.3) car les paquets génériques php-foo dépendent de la dernière version de PHP disponible. Exemple, si on souhaite seulement php7.3 : ~~~ # apt install wget apt-transport-https # wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg # echo "deb https://packages.sury.org/php/ stretch main" > /etc/apt/sources.list.d/sury.list # cat << EOT > /etc/apt/preferences.d/z-sury Package: php* libapache2-mod-php* libpcre2* libzip4* Pin: origin packages.sury.org Pin-Priority: 999 Package: * Pin: origin packages.sury.org Pin-Priority: 50 EOT # apt update # apt install php7.3 php7.3-cli php7.3-curl php7.3-mysql php7.3-pgsql php7.3-ldap php7.3-imap php7.3-gd php7.3-intl php-ssh2 php-gettext composer libphp-phpmailer $ php -v PHP 7.3.4-1+0~20190412071350.37+stretch~1.gbpabc171 (cli) (built: Apr 12 2019 07:13:50) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.4, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.3.4-1+0~20190412071350.37+stretch~1.gbpabc171, Copyright (c) 1999-2018, by Zend Technologies ~~~ ### 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 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 ~~~ ### 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 = log/$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 ~~~ #### 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 : ~~~ #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 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 : * 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 : [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 ~~~ ### Composer sous Debian 8 ~~~ $ wget -q -O setup-composer.php https://getcomposer.org/installer $ sha384sum setup-composer.php $ mkdir bin $ php -d allow_url_fopen=On setup-composer.php --install-dir=bin --filename=composer $ php bin/composer --version PHP Warning: putenv() has been disabled for security reasons Composer version 1.5.1 2017-08-09 16:07:22 ~~~ ## Module du framework phalcon 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 git://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 [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 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 ~~~ # apt install php7.0-opcache ~~~ Depuis PHP 5.6 (Debian 8), un cache d'OPcode (code "intermédiaire" généré par PHP) intégré à PHP permet d'accélérer la génération du résultat des scripts PHP. Il remplace les « accélérateurs » comme APC, eAccelerator, etc. utilissé dans les versions précédentes de PHP. C'est le module OpCache configurable via `/etc/php5/mods-available/opcache.ini`. La valeur de cache par défaut est de **64M**, paramètre `opcache.memory_consumption`. Pour surveiller OpCache on peut utiliser : - - Plugin Munin + ## HHVM ~~~ # apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449 # 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 ### 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 ). 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 : 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 : ### 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()); ```