Bei der Verarbeitung von Serverprotokolldateien stoßen wir häufig auf Probleme mit inkonsistenten Formaten. Beispielsweise kann die IP -Adresse führende Nullen haben, das Zeitstempelformat kann inkonsistent sein und der Anforderungspfad kann verschiedene Parameter haben. Um diese Felder einheitlich zu verarbeiten, ist preg_replace_callback_array ein sehr leistungsstarkes Tool, mit dem wir verschiedene Rückruffunktionen separat an mehrere reguläre Ausdrücke binden und die komplexe Ersatzlogik in einem Traversal komplett machen können.
In diesem Artikel wird vorgestellt, wie Sie preg_replace_callback_array verwenden, um IP- und Zeitfelder im Protokoll einheitlich zu formatieren.
Angenommen, wir haben den folgenden Protokollinhalt (vereinfachte Version):
127.000.000.001 - - [21/Apr/2025:15:32:01 +0000] "GET /index.php?id=123 HTTP/1.1" 200
192.168.1.10 - - [21-Apr-2025 15:32:01] "POST /submit.php HTTP/1.1" 404
Wir hoffen:
Normalisieren Sie die IP -Adresse (Entfernen führender Nullen);
Vereinheitsen Sie die Zeit in Yyyy-MM-DD HH: MM: SS- Format;
Optional: Maskenparameter im Pfad, z. B. /Idex.php?id=123 → /Idex.php
<?php
$log = <<<LOG
127.000.000.001 - - [21/Apr/2025:15:32:01 +0000] "GET /index.php?id=123 HTTP/1.1" 200
192.168.1.10 - - [21-Apr-2025 15:32:01] "POST /submit.php HTTP/1.1" 404
LOG;
// Definieren Sie reguläre und entsprechende Verarbeitungsrufe
$patterns = [
// IP Adressformatierung:Entfernen Sie führende Nullen
'/\b(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\b/' => function ($matches) {
return implode('.', array_map('intval', array_slice($matches, 1, 4)));
},
// Apache Stilzeitstempel [21/Apr/2025:15:32:01 +0000]
'/\[(\d{2})\/(\w{3})\/(\d{4}):(\d{2}):(\d{2}):(\d{2}) [+\-]\d{4}\]/' => function ($matches) {
$monthMap = [
'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04',
'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08',
'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12'
];
return sprintf('%s-%s-%s %s:%s:%s',
$matches[3], // Jahr
$monthMap[$matches[2]] ?? '01', // Mond
$matches[1], // Tag
$matches[4], $matches[5], $matches[6]
);
},
// Tag志格式中另一种时间 [21-Apr-2025 15:32:01]
'/(\d{2})-(\w{3})-(\d{4}) (\d{2}):(\d{2}):(\d{2})/' => function ($matches) {
$monthMap = [
'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04',
'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08',
'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12'
];
return sprintf('%s-%s-%s %s:%s:%s',
$matches[3],
$monthMap[$matches[2]] ?? '01',
$matches[1],
$matches[4], $matches[5], $matches[6]
);
},
// Entfernen URL Parameter(wie /index.php?id=123 → /index.php)
'#(GET|POST|PUT|DELETE|HEAD) (/[\w\-\/\.]+)(\?[^\s"]*)?#' => function ($matches) {
return $matches[1] . ' ' . $matches[2];
}
];
// Anwendungsersatz
$formatted = preg_replace_callback_array($patterns, $log);
// Ausgangsergebnis
echo nl2br(htmlspecialchars($formatted));
?>
Nach dem Ausführen des obigen Skripts wird der Protokollinhalt als:
127.0.0.1 - - 2025-04-21 15:32:01 "GET /index.php HTTP/1.1" 200
192.168.1.10 - - 2025-04-21 15:32:01 "POST /submit.php HTTP/1.1" 404
Mit preg_replace_callback_array können wir mehrere Felder in verschiedenen Formaten im Protokoll auf sehr elegante Weise verarbeiten. Sein Vorteil ist, dass es mehrere Modi gleichzeitig übernimmt. Jeder Modus hat eine eigene Rückruffunktion unabhängig, was eine klare Logik und eine einfache Wartung aufweist.