PHP

Siehe auch

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:

/etc/php-fpm.d/www.conf
listen = /run/php-fpm/www.sock
pm.status_path = /fpm-status
/etc/httpd/conf/httpd.conf
<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:

/etc/php-fpm.d/www.conf
ping.path = /fpm-ping
/etc/httpd/conf/httpd.conf
<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:

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_filesize kann beliebig gesetzt werden.

  • post_max_size muss grösser als upload_max_filesize sein, wenn Formulare mit Datei-Uploads unterstützt werden.

  • memory_limit muss grösser als post_max_size sein.

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

Debugging

Damit man unter PHP-FPM mit „print“-Statements debuggen kann, müssen folgende Einstellungen für den PHP-FPM-Worker gesetzt sein:

/etc/php-fpm.d/www.conf
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));

Built on 2024-09-30