PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.5.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.5.0
5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 3.0.0 3.0.1 3.0.2 3.0.3 3.0.5 3.0.51 3.0.60 3.0.61 3.0.62 3.0.70 3.0.71 3.0.72 3.1.0 All 34 releases
double-opt-in / logger / logger.php

logger.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification 5.5.0, at logger/logger.php

177 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Forge12\Shared;
3
4 // Sicherstellen, dass Interface existiert
5 if (! interface_exists('Forge12\Shared\LoggerInterface')) {
6 require_once __DIR__ . '/logger.interface.php';
7 }
8
9 if (!defined('F12_DEBUG')) {
10 define('F12_DEBUG', false);
11 }
12
13 if (!defined('F12_DEBUG_LOG_LEVEL')) {
14 define('F12_DEBUG_LOG_LEVEL', 200);
15 }
16
17 if ( ! class_exists( 'Forge12\Shared\Logger' ) ) {
18 class Logger implements LoggerInterface {
19 private static $instance;
20 private $log_file;
21 private $log_level;
22 private $log_dir;
23
24 const DEBUG = 100;
25 const INFO = 200;
26 const NOTICE = 250;
27 const WARNING = 300;
28 const ERROR = 400;
29 const CRITICAL = 500;
30
31 private function __construct() {
32 if ( ! defined( 'F12_DEBUG' ) || ! F12_DEBUG ) {
33 // Wenn F12_DEBUG nicht definiert ist oder false, beenden wir.
34 return;
35 }
36
37 $upload_dir = wp_upload_dir();
38 $this->log_dir = $upload_dir['basedir'] . '/f12-logs';
39
40 if ( ! file_exists( $this->log_dir ) ) {
41 wp_mkdir_p( $this->log_dir );
42 }
43
44 // Tagesbasiert loggen
45 $this->log_file = $this->log_dir . '/plugins-' . date('Y-m-d') . '.log';
46
47 // Setze Level je nach WP_DEBUG
48 $this->log_level = F12_DEBUG_LOG_LEVEL;
49 }
50
51 public static function getInstance() {
52 if ( ! self::$instance ) {
53 self::$instance = new self();
54 }
55 return self::$instance;
56 }
57
58 private function sanitizeContext(array $context): array {
59 foreach ($context as $key => $value) {
60 if (in_array(strtolower($key), ['ip', 'user_ip'])) {
61 $context[$key] = $this->mask_ip($value);
62 }
63 if (in_array(strtolower($key), ['email', 'user_email'])) {
64 $context[$key] = $this->mask_email($value);
65 }
66 if (in_array(strtolower($key), ['password', 'pwd'])) {
67 $context[$key] = $this->mask_password($value);
68 }
69 }
70 return $context;
71 }
72
73 private function mask_password(string $password): string {
74 return '********';
75 }
76
77 private function mask_email(string $email): string {
78 if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
79 return 'invalid';
80 }
81 [$user, $domain] = explode('@', $email, 2);
82 $len = strlen($user);
83 if ($len <= 2) {
84 $maskedUser = substr($user, 0, 1) . '*';
85 } else {
86 $maskedUser = substr($user, 0, 1) . str_repeat('*', $len - 2) . substr($user, -1);
87 }
88 return $maskedUser . '@' . $domain;
89 }
90
91 private function mask_ip(string $ip): string {
92 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
93 $parts = explode('.', $ip);
94 $parts[3] = '0';
95 return implode('.', $parts);
96 }
97 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
98 return substr($ip, 0, 20) . '::';
99 }
100 return 'unknown';
101 }
102
103 private function rotateLogs(int $maxSize = 52428800, int $maxFiles = 5): void {
104 if (file_exists($this->log_file) && filesize($this->log_file) > $maxSize) {
105 for ($i = $maxFiles - 1; $i >= 1; $i--) {
106 $old = $this->log_file . '.' . $i;
107 $new = $this->log_file . '.' . ($i + 1);
108 if (file_exists($old)) {
109 rename($old, $new);
110 }
111 }
112 rename($this->log_file, $this->log_file . '.1');
113 }
114 }
115
116 private function cleanupOldLogs(int $days = 7): void {
117 foreach (glob($this->log_dir . '/plugins-*.log*') as $file) {
118 if (filemtime($file) < strtotime("-{$days} days")) {
119 @unlink($file);
120 }
121 }
122 }
123
124 private function writeLog( $level, $levelName, $message, array $context = [] ) {
125 if ( ! defined( 'F12_DEBUG' ) || ! F12_DEBUG ) {
126 // Wenn F12_DEBUG nicht definiert ist oder false, beenden wir.
127 return;
128 }
129
130 if ( $level < $this->log_level ) {
131 return;
132 }
133
134 // Cleanup & Rotation bei jedem Schreiben
135 $this->cleanupOldLogs();
136 $this->rotateLogs();
137
138 $context = $this->sanitizeContext($context);
139
140 $time = date( 'Y-m-d H:i:s' );
141 $plugin = $context['plugin'] ?? 'unknown';
142 $msg = sprintf( "[%s] [%s] [%s] %s %s\n",
143 $time,
144 strtoupper( $levelName ),
145 $plugin,
146 $message,
147 $context ? json_encode( $context ) : ''
148 );
149 error_log( $msg, 3, $this->log_file );
150 }
151
152 public function debug( $message, array $context = [] ) :void {
153 $this->writeLog( self::DEBUG, 'DEBUG', $message, $context );
154 }
155
156 public function info( $message, array $context = [] ) : void {
157 $this->writeLog( self::INFO, 'INFO', $message, $context );
158 }
159
160 public function error( $message, array $context = [] ) : void {
161 $this->writeLog( self::ERROR, 'ERROR', $message, $context );
162 }
163
164 public function warning( $message, array $context = [] ) : void {
165 $this->writeLog( self::WARNING, 'WARNING', $message, $context );
166 }
167
168 public function notice( $message, array $context = [] ) : void {
169 $this->writeLog( self::NOTICE, 'NOTICE', $message, $context );
170 }
171
172 public function critical( $message, array $context = [] ) : void {
173 $this->writeLog( self::CRITICAL, 'CRITICAL', $message, $context );
174 }
175 }
176 }
177