PHP¶
Siehe auch
- Verwandte Artikel
- Offizielle Dokumentation
- Linuxfabrik
Installation¶
- CentOS 8
Aus dem Remi-Repo:
dnf -y module reset php # PHP 7.4 dnf -y module install php:remi-7.4 # PHP 8.0 dnf -y module install php:remi-8.0 # this is how to additional packages dnf -y install php-mbstring
Alternativ (und älter) aus dem EPEL-Repo:
dnf -y module reset php # PHP 7.3 dnf module enable php:7.3 # this is how to additional packages dnf -y install php-mbstring
- CentOS 7
Aus dem Remi-Repo:
# PHP 7.4 yum-config-manager --disable 'remi-php*' yum-config-manager --enable remi-php74 yum -y install php # this is how to additional packages yum -y install php-mbstring
Der integrierte Webserver¶
Start:
php -S localhost:8080 path/to/my/project.php
PHP-FPM¶
PHP-FPM (FastCGI Process Manager) ist eine alternative PHP FastCGI-Implementierung, die eine Reihe zusätzlicher Funktionen enthält.
Statusseite aktivieren:
listen = /run/php-fpm/www.sock
pm.status_path = /fpm-status
<LocationMatch "/fpm-status">
Require local
ProxyPass unix:/run/php-fpm/www.sock|fcgi://localhost/fpm-status
</LocationMatch>
curl 'http://localhost/fpm-status?json&full'
Ping-Seite aktivieren:
ping.path = /fpm-ping
<Location "/fpm-ping">
Require local
ProxyPass unix:/run/php-fpm/www.sock|fcgi://localhost/fpm-ping
</Location>
curl 'http://localhost/fpm-ping'
Test der Konfigurationsdatei:
php-fpm --test
PHP-FPM Process Hintergründe und Calculator:
Composer¶
Composer ist ein Paketmanager für PHP >= 5.3.2, wird über die Kommandozeile ausgeführt und installiert auch notwendige Abhängigkeiten.
Installation - aus dem remi-Repo (bevorzugt):
yum -y install composer
Installation - manuell von der Composer-Webseite:
wget --output-document=composer https://getcomposer.org/composer.phar
chmod +x composer
Update:
composer update
Paket installieren - direkt per composer (bevorzugt):
composer require graylog2/gelf-php
Paket installieren - per manuellem Eintrag in der composer.json:
{
"require": {
"graylog2/gelf-php": "^1.7"
}
}
Paket mit Abhängigkeiten entfernen:
composer remove graylog2/gelf-php --update-with-dependencies
Logging¶
So loggt man per GELF gegen einen Graylog:
<?php
$graylog_hostname = '10.74.143.6';
$graylog_port = '12201';
$graylog_facility = 'my-facility-name';
require_once __DIR__ . '/vendor/autoload.php';
// We need a transport - UDP via port 12201 is standard.
$transport = new Gelf\Transport\UdpTransport(
$graylog_hostname,
$graylog_port,
Gelf\Transport\UdpTransport::CHUNK_SIZE_LAN
);
$publisher = new Gelf\Publisher();
$publisher->addTransport($transport);
// The implementation of PSR-3 is encapsulated in the Logger-class.
// It provides high-level logging methods, such as alert(), info(), etc.
$logger = new Gelf\Logger($publisher, $graylog_facility);
// Now we can log...
$logger->emergency('My Emergency');
$logger->alert('My Alert');
$logger->critical('My Critical');
$logger->error('My Error');
$logger->warning('My Warning');
$logger->notice('My Notice');
$logger->info('My Info');
$logger->debug('My Debug');
Wie erhält man im Log neben dem Stacktrace auch die Parameter einer Funktion und deren Werte, wenn diese beim Aufruf mit einer Exception abbricht? Dafür gibt es keine php.ini-Einstellung - hier hilft nur die Definition eines eigenen Error-Handlers:
<?php
// user-defined error handler
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
// print all the stacktrace details including function parameters and values
print_r(debug_backtrace());
return false;
}
// function that causes an error
function exampleFunction($param1, $param2)
{
$undefinedVar->callUndefinedFunction();
}
set_error_handler('myErrorHandler');
exampleFunction('linuxfabrik', 2016);
Keycloak (OAuth)¶
PHP-Applikationen können sich mit Hilfe des PHP League’s OAuth 2.0 Client per OAuth identifizieren. Hier finden sich die offiziellen Provider (Facebook & Co.), hier die Liste der Third-Party Provider.
Keycloak wird durch den Third-Party Provider stevenmaguire/oauth2-keycloak unterstützt, der sich per composer require stevenmaguire/oauth2-keycloak installieren lässt.
Für die Auswertung in PHP-Applikationen: Apache setzt Umgebungsvariablen, die sich in $_SERVER finden:
[OIDC_access_token] => eyJhbGciOiJ...Wpb8YpL8J4w
[OIDC_access_token_expires] => 1507893465
[OIDC_CLAIM_acr] => 0
[OIDC_CLAIM_aud] => example
[OIDC_CLAIM_auth_time] => 1507892808
[OIDC_CLAIM_azp] => example
[OIDC_CLAIM_email] => info@linuxfabrik.ch
[OIDC_CLAIM_exp] => 1507893465
[OIDC_CLAIM_family_name] =>
[OIDC_CLAIM_given_name] =>
[OIDC_CLAIM_iat] => 1507893165
[OIDC_CLAIM_iss] => http://192.168.122.235:8080/auth/realms/example
[OIDC_CLAIM_jti] => 1fff1dc8-...5056749451
[OIDC_CLAIM_nbf] => 0
[OIDC_CLAIM_nonce] => XbHe4AZO4Y3mLo1UF1OXfgHiRTuqQ
[OIDC_CLAIM_preferred_username] => ellen.lang
[OIDC_CLAIM_session_state] => cea4da5c-...c106cbb3fefb
[OIDC_CLAIM_sub] => b9c2a39a...b-c84e9382d5bc
[OIDC_CLAIM_typ] => ID
[REDIRECT_OIDC_access_token] => eyJhbGciOiJSUz...8YpL8J4w
[REDIRECT_OIDC_access_token_expires] => 1507893465
[REDIRECT_OIDC_CLAIM_acr] => 0
[REDIRECT_OIDC_CLAIM_aud] => example
[REDIRECT_OIDC_CLAIM_auth_time] => 1507892808
[REDIRECT_OIDC_CLAIM_azp] => example
[REDIRECT_OIDC_CLAIM_email] => info@linuxfabrik.ch
[REDIRECT_OIDC_CLAIM_exp] => 1507893465
[REDIRECT_OIDC_CLAIM_family_name] =>
[REDIRECT_OIDC_CLAIM_given_name] =>
[REDIRECT_OIDC_CLAIM_iat] => 1507893165
[REDIRECT_OIDC_CLAIM_iss] => http://192.168.122.199:8080/auth/realms/example
[REDIRECT_OIDC_CLAIM_jti] => 1fff1dc8-...5056749451
[REDIRECT_OIDC_CLAIM_nbf] => 0
[REDIRECT_OIDC_CLAIM_nonce] => XbHe4AZO4Y3mLo1UF1OXfgHiRTuqQ
[REDIRECT_OIDC_CLAIM_preferred_username] => ellen.lang
[REDIRECT_OIDC_CLAIM_session_state] => cea4da5c-...c106cbb3fefb
[REDIRECT_OIDC_CLAIM_sub] => b9c2a39a...b-c84e9382d5bc
[REDIRECT_OIDC_CLAIM_typ] => ID
[REDIRECT_STATUS] => 200
[REDIRECT_UNIQUE_ID] => WeCgFf0L41OaqnZmBvJ2MQAAAAY
[UNIQUE_ID] => WeCgFf0L41OaqnZmBvJ2MQAAAAY
Caching¶
Code-Caching mit dem integrirten Zend OPcache.
Abfrage der Statistiken mit php -r 'print_r(json_encode(opcache_get_status(), JSON_PRETTY_PRINT));'. Wichtig: opcache.memory_consumption=200 legt die Gesamtgrösse fest. Wird beispielsweise opcache.interned_strings_buffer auf 100 (MB) gesetzt, stehen nur noch 50% des OpCaches für die maximal opcache.max_accelerated_files compilierten Dateien zur Verfügung.
So funktioniert der Cache anschaulich:
memory_consumption=200 (MB)
davon "wasted" max. 5%
┌─────────────────────────────────┐
│ │
│ interned_string_buffer=50 (MB) │
│ │
│ │
├─────────────────────────────────┤ ------
│ │
│ max_accelerated_files=16229 (#) │ Hit Rate
│ ("Keys") │
│ │
│ │
│ │
│ │
│ │
└─────────────────────────────────┘
Data Caches
APCu: für lokales Caching
Memcached: für verteiltes Caching
Redis: lokal, verteilt, File Lock Caching - aber langsamer als APCu
memory_limit vs. post_max_size vs. upload_max_filesize¶
Angenommen, man möchte Uploads für 2 GB grosse Dateien erlauben. Welche Settings in der php.ini sind wie anzupassen?
PHP verfügt über verschiedene POST-Readers und -Handler, je nach Inhaltstyp der Anfrage. Im Falle von „multipart/form-data“ (was für das Senden von Dateien verwendet wird), agiert der rfc1867_post_handler als mixed Reader/Handler. Er füllt sowohl $_POST als auch $_FILES. Beides zählt in Bezug auf memory_limit. Allerdings enthält $_FILES nur Metadaten über die Dateien, nicht die Dateien selbst. Dateien werden nur auf die Festplatte (auf unter Linux je nach Konfiguration z.B. in /tmp) geschrieben und zählen daher nicht für memory_limit.
Generell gilt also:
upload_max_filesizekann beliebig gesetzt werden.post_max_sizemuss grösser alsupload_max_filesizesein, wenn Formulare mit Datei-Uploads unterstützt werden.memory_limitmuss grösser alspost_max_sizesein.
In obigem Beispiel kann also folgendes genügen:
memory_limit = 128M
post_max_size = 8M ; belongs to sapi_globals
upload_max_filesize = 1G ; belongs to core_globals
Preloading¶
Preloading bezeichnet das Verfahren, bei dem PHP-Skripte beim Start des PHP-FPM-Prozesses direkt in den OPCache geladen werden, sodass der Cache von Beginn an warm ist. Ohne Preloading werden Skripte erst beim ersten Aufruf in den Cache aufgenommen, was bei den initialen Anfragen zu einem Mehraufwand führt.
Damit Preloading funktioniert, muss in der php.ini folgendes gesetzt werden:
opcache.preload=/var/www/html/preload.php
opcache.preload_user=apache
Das referenzierte PHP-Skript lädt dann die gewünschten Dateien in den OPCache:
<?php
$files = glob('/var/www/html/src/*.php');
foreach ($files as $file) {
opcache_compile_file($file);
}
Ob Preloading sinnvoll ist, hängt jedoch vom konkreten Anwendungsfall ab. Skripte, die selten oder gar nicht aufgerufen werden, belegen unnötig Arbeitsspeicher, ohne einen messbaren Vorteil zu bringen. Preloading empfiehlt sich daher nur dann, wenn klar definiert ist, welche Skripte regelmässig benötigt werden.
Debugging¶
Damit man unter PHP-FPM mit „print“-Statements debuggen kann, müssen folgende Einstellungen für den PHP-FPM-Worker gesetzt sein:
catch_workers_output = yes
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
Nun kann so geprintet werden:
error_log("hello world");
error_log(print_r($myArray, true));
// print a stacktrace
error_log(print_r(debug_backtrace(), true));
// with reduced memory usage
error_log(print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true));