time()) { return false; } // Schon angehalten: weitere Mails dieser Quelle ebenfalls, bis ein Admin entscheidet if (!empty($z['seit'])) { return true; } $stunde = self::letzteStunde($quelle); $grenze = self::grenze($quelle); if ($stunde < $grenze) { return false; } $alle = self::zustand(); $alle[$quelle] = ['seit' => time(), 'stunde' => $stunde, 'grenze' => $grenze, 'frei_bis' => 0]; update_option(self::ZUSTAND, $alle, false); // Admin sofort warnen (eigener Lauf, nicht mitten im Versand dieser Mail) if (!wp_next_scheduled(self::HOOK)) { wp_schedule_single_event(time(), self::HOOK); } return true; } public static function letzteStunde(string $quelle): int { global $wpdb; return (int) $wpdb->get_var($wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE quelle = %s AND zeit >= %s', Protokoll::tabelle(), $quelle, gmdate('Y-m-d H:i:s', time() - HOUR_IN_SECONDS) )); } /** Grenze je Stunde: Dreifaches der hoechsten Stundenzahl der letzten 14 Tage (ohne die letzte Stunde), mindestens die Untergrenze. */ public static function grenze(string $quelle): int { global $wpdb; $schluessel = 'sendmails_bremse_' . md5($quelle); $hoch = get_transient($schluessel); if ($hoch === false) { $hoch = (int) $wpdb->get_var($wpdb->prepare( "SELECT MAX(n) FROM (SELECT COUNT(*) AS n FROM %i WHERE quelle = %s AND zeit >= %s AND zeit < %s AND status <> 'angehalten' GROUP BY substr(zeit, 1, 13)) AS je", Protokoll::tabelle(), $quelle, gmdate('Y-m-d H:i:s', time() - self::RUECKBLICK_TAGE * DAY_IN_SECONDS), gmdate('Y-m-d H:i:s', time() - HOUR_IN_SECONDS) )); set_transient($schluessel, $hoch, HOUR_IN_SECONDS); } return max(max(1, (int) Einstellungen::wert('bremse_min')), self::FAKTOR * (int) $hoch); } /** Angehaltene Quellen mit Zahl der wartenden Mails (fuer Uebersicht, Hinweise und Warnung). */ public static function angehalten(): array { global $wpdb; $zahlen = (array) $wpdb->get_results($wpdb->prepare( "SELECT quelle, COUNT(*) AS mails, MIN(erstellt) AS erste FROM %i WHERE status = 'angehalten' GROUP BY quelle", Warteschlange::tabelle() ), ARRAY_A); $z = self::zustand(); $liste = []; foreach ($zahlen as $r) { $q = (string) $r['quelle']; $liste[$q] = ['quelle' => $q, 'mails' => (int) $r['mails'], 'erste' => (string) $r['erste']] + ($z[$q] ?? ['seit' => strtotime($r['erste'] . ' UTC'), 'stunde' => 0, 'grenze' => 0]); } return $liste; } /** * Entscheidung des Admins: freigeben (Mails senden, Quelle 24 Stunden nicht bremsen), vertrauen (freigeben * und nie mehr bremsen) oder verwerfen (angehaltene Mails loeschen). * * @return int Zahl der betroffenen Mails */ public static function entscheiden(string $quelle, string $was): int { $alle = self::zustand(); if ($was === 'verwerfen') { $n = Warteschlange::angehalteneLoeschen($quelle); unset($alle[$quelle]); } else { $n = Warteschlange::angehalteneFreigeben($quelle); $alle[$quelle] = ['seit' => 0, 'frei_bis' => time() + self::FREI_S]; if ($was === 'vertrauen') { $vertraut = (array) Einstellungen::wert('bremse_vertraut'); $vertraut[] = $quelle; Einstellungen::speichern(['bremse_vertraut' => array_values(array_unique($vertraut))]); } } update_option(self::ZUSTAND, $alle, false); delete_transient('sendmails_bremse_' . md5($quelle)); return $n; } }