Ich verwende hook_init()
, um die letzte Zugriffszeit der Benutzer zu überprüfen. Wenn die letzte Zugriffszeit gestern ist, erhöhe ich einen Zähler und setze einige Variablen.
Das Problem ist, dass hook_init()
manchmal mehr als einmal (ich kann dies mit verwenden dsm()
) für dieselbe Seitenladung ausgeführt wird, so dass mein Code mehrmals ausgeführt wird, was zu falschen Variablen führt.
Warum wird hook_init()
mehr als einmal ausgeführt?
Was wäre der beste Ansatz für mein Problem? Soll ich einen anderen Haken verwenden?
Ich habe etwas mehr darüber
nachgedacht : Ich suche nach Aufrufen von hook_init () (nach Zeichenfolge gesucht module_invoke_all('init');
), habe aber nur den Kernaufruf gefunden). Ich weiß nicht, ob dies anders genannt werden kann.
Das ist mein hook_init ()
function episkeptis_achievements_init(){
dsm('1st execution');
dsm('REQUEST_TIME: '.format_date(REQUEST_TIME, 'custom', 'd/m/Y H:i:s').' ('.REQUEST_TIME.')');
}
und das ist die Ausgabe:
1st execution
REQUEST_TIME: 09/07/2012 11:20:32 (1341822032)
Dann wurde die Nachricht dsm () in geändert dsm('2nd execution');
und erneut ausgeführt. Dies ist die Ausgabe:
1st execution
REQUEST_TIME: 09/07/2012 11:20:34 (1341822034)
2nd execution
REQUEST_TIME: 09/07/2012 11:22:28 (1341822148)
Sie können sehen, dass der Code zweimal ausgeführt wird. Beim ersten Mal wird jedoch eine alte Kopie des Codes ausgeführt, beim zweiten Mal die aktualisierte Kopie. Es gibt auch einen Zeitunterschied von 2 Sekunden.
Dies ist eine d7-Version mit PHP 5.3.10
REQUEST_TIME
wäre der gleiche.REQUEST_TIME
der Wert der Seite gleich ist , wenn er von derselben Seitenanforderung stammt. Es gibt nicht einmal einen Unterschied von zwei Sekunden. Überprüfen Sie, ob es keinen Code gibt, der den Wert von ändertREQUEST_TIME
.Antworten:
hook_init()
wird von Drupal nur einmal für jede angeforderte Seite aufgerufen; Dies ist der letzte Schritt in _drupal_bootstrap_full () .Wenn
hook_init()
es mehr als einmal ausgeführt wird, sollten Sie herausfinden, warum dies geschieht. Soweit ich sehen kann,hook_init()
überprüft keine der Implementierungen in Drupal, ob sie zweimal ausgeführt wird (siehe zum Beispiel system_init () oder update_init () ). Wenn dies normalerweise mit Drupal passieren kann,update_init()
prüfen Sie zunächst, ob es bereits ausgeführt wurde.Wenn der Zähler die Anzahl der aufeinanderfolgenden Tage ist, an denen sich ein Benutzer angemeldet hat, würde ich lieber einen
hook_init()
Code implementieren , der dem folgenden ähnlich ist.Wenn
hook_init()
es während derselben Seitenanforderung zweimal hintereinander aufgerufen wird,REQUEST_TIME
denselben Wert enthält und die Funktion zurückgegeben wirdFALSE
.Der Code in
mymodule_increase_counter()
ist nicht optimiert. Es soll nur ein Beispiel zeigen. In einem realen Modul würde ich lieber eine Datenbanktabelle verwenden, in der der Zähler und die anderen Variablen gespeichert sind. Der Grund dafür ist, dass$conf
beim Drupal-Bootstraps alle Drupal-Variablen in die globale Variable geladen werden (siehe _drupal_bootstrap_variables () und variable_initialize () ). Wenn Sie dafür Drupal-Variablen verwenden, lädt Drupal Speicherinformationen über alle Benutzer, für die Sie Informationen gespeichert haben, wenn für jede angeforderte Seite nur ein Benutzerkonto in der globalen Variablen gespeichert ist$user
.Wenn Sie die Anzahl der von den Benutzern an aufeinanderfolgenden Tagen besuchten Seiten zählen, würde ich den folgenden Code implementieren.
Sie werden feststellen, dass ich in meinem Code keine verwende
$user->access
. Der Grund ist, dass$user->access
dies während des Drupal-Bootstraps aktualisiert werden könnte, bevorhook_init()
es aufgerufen wird. Der von Drupal verwendete Session Write Handler enthält den folgenden Code. (Siehe _drupal_session_write () .)Für einen anderen Hook, den Sie verwenden können, können Sie mit Drupal 7 hook_page_alter () verwenden . Sie ändern einfach nicht den Inhalt von
$page
, sondern erhöhen Ihren Zähler und ändern Ihre Variablen.In Drupal 6 können Sie hook_footer () verwenden , den Hook, der von template_preprocess_page () aufgerufen wird . Sie geben nichts zurück, sondern erhöhen Ihren Zähler und ändern Ihre Variablen.
Auf Drupal 6 und Drupal 7 können Sie hook_exit () verwenden . Beachten Sie, dass der Hook auch aufgerufen wird, wenn der Bootstrap nicht vollständig ist. Der Code konnte keinen Zugriff auf Funktionen haben, die von Modulen oder anderen Drupal-Funktionen definiert wurden, und Sie sollten zuerst überprüfen, ob diese Funktionen verfügbar sind. Einige Funktionen sind immer verfügbar
hook_exit()
, z. B. die in bootstrap.inc und cache.inc definierten . Der Unterschied besteht darin, dass erhook_exit()
auch für zwischengespeicherte Seitenhook_init()
aufgerufen wird , während er nicht für zwischengespeicherte Seiten aufgerufen wird.Ein Beispiel für Code, der von einem Drupal-Modul verwendet wird, finden Sie unter statistics_exit () . Das Statistikmodul protokolliert Zugriffsstatistiken für eine Site und verwendet, wie Sie sehen
hook_exit()
, nichthook_init()
. Um die erforderlichen Funktionen aufrufen zu können, wird drupal_bootstrap () aufgerufen, wobei der richtige Parameter übergeben wird, wie im folgenden Code.Aktualisieren
Vielleicht gibt es einige Verwirrung darüber, wann
hook_init()
aufgerufen wird.hook_init()
wird für jede Seitenanforderung aufgerufen, wenn die Seite nicht zwischengespeichert ist. Es wird nicht einmal für jede Seitenanforderung aufgerufen, die vom selben Benutzer stammt. Wenn Sie besuchen zum Beispiel http://example.com/admin/appearance/update und dann http://example.com/admin/reports/status ,hook_init()
wird zweimal aufgerufen werden: eine für jede Seite."Der Hook wird zweimal aufgerufen" bedeutet, dass es ein Modul gibt, das den folgenden Code ausführt, sobald Drupal seinen Bootstrap abgeschlossen hat.
Wenn dies der Fall ist, würde die folgende Implementierung von
hook_init()
zweimal denselben Wert anzeigen.Wenn Ihr Code für
REQUEST_TIME
zwei Werte angezeigt wird , für die die Differenz wie in Ihrem Fall 2 Minuten beträgt, wird der Hook nicht zweimal aufgerufen, sondern einmal für jede angeforderte Seite, wie es passieren sollte.REQUEST_TIME
wird in bootstrap.inc mit der folgenden Zeile definiert.Bis die aktuell angeforderte Seite nicht an den Browser zurückgegeben wird,
REQUEST_TIME
ändert sich der Wert von nicht. Wenn Sie einen anderen Wert sehen, beobachten Sie den auf einer anderen Anforderungsseite zugewiesenen Wert.quelle
Ich erinnere mich, dass dies in Drupal 6 viel passiert ist (ich bin mir nicht sicher, ob es in Drupal 7 immer noch passiert), aber ich habe nie herausgefunden, warum. Ich erinnere mich an einen Ort, an dem Drupal Core diesen Hook nicht zweimal aufruft.
Ich fand es immer am einfachsten, eine statische Variable zu verwenden, um festzustellen, ob der Code bereits ausgeführt wurde:
Dadurch wird sichergestellt, dass es beim Laden einer einzelnen Seite nur einmal ausgeführt wird.
quelle
hook_init()
Implementierungen, und einige von ihnen würden gerne vermeiden, zweimal hintereinander ausgeführt zu werden. Es ist auch wahrscheinlich, dass das OPhook_init()
einmal pro Tag ausgeführt werden soll, wenn der Zähler die Anzahl der aufeinander folgenden Tage zählt, an denen sich die Benutzer auf der Site angemeldet haben.hook_init
wenn das OP prüft, ob es bereits einmal für diesen Tag ausgeführt wird, und wenn dies der Fall ist, wird es gerettet. Dann wird das Ganze sowieso kein ThemaMöglicherweise wird hook_init () mehrmals aufgerufen, wenn auf der Seite AJAX auftritt (oder Sie Bilder aus einem privaten Verzeichnis laden - obwohl ich mir da nicht so sicher bin). Es gibt einige Module, die AJAX verwenden, um beispielsweise das Zwischenspeichern von Seiten für bestimmte Elemente zu umgehen. Die einfachste Möglichkeit, dies zu überprüfen, besteht darin, den Netzmonitor in einem Debugger Ihrer Wahl (Firefox oder Web Inspector) zu öffnen und nach Anforderungen zu suchen gemacht werden, die den Bootstrap-Prozess auslösen könnten.
Sie erhalten dpm () jedoch nur beim Laden der nächsten Seite, wenn es sich um einen AJAX-Aufruf handelt. Angenommen, Sie aktualisieren die Seite 5 Minuten später. Sie erhalten den AJAX-Anruf sowohl aus der Init-Nachricht vor 5 Minuten als auch aus der neuen.
Eine Alternative zu hook_init () ist hook_boot (), das aufgerufen wird, bevor überhaupt ein Caching durchgeführt wird. Es sind auch noch keine Module geladen, so dass Sie hier wirklich nicht viel Leistung haben, außer globale Variablen festzulegen und einige Drupal-Funktionen auszuführen. Es ist nützlich, um das reguläre Level-Caching zu umgehen (aber das aggressive Caching wird nicht umgangen).
quelle
In meinem Fall wurde dieses Verhalten durch das Verwaltungsmenü-Modul (admin_menu) verursacht.
hook_init wurde nicht bei jeder Anfrage aufgerufen, aber das Admin-Menü führte dazu, dass / js / admin_menu / cache / 94614e34b017b19a78878d7b96ccab55 sehr kurz nach der Hauptanforderung vom Browser des Benutzers geladen wurde und einen weiteren Drupal-Bootstrap auslöste.
Es wird andere Module geben, die ähnliche Aufgaben ausführen, aber admin_menu ist wahrscheinlich eines der am häufigsten bereitgestellten.
quelle