מעקב ניתוב (router trace)

איך מפעילים את מצב המעקב של ה-ROUTER עם ?__router_trace=1, מי רואה אותו, איך קוראים את הטבלה (כל שלב ושלב), ואיך מוסיפים שלבים משלכם.

⏱ 6 דק' קריאה 1096 מילים ערוך דף זה ב-GitHub

כשכתובת מגיעה לעמוד הלא נכון, ל-404 או לבקר שלא ציפיתם לו, אין צורך לנחש איזה כלל תפס אותה. ה-ROUTER רושם כל החלטה שהוא מקבל, ואפשר להציג את הרשימה הזו בתחתית העמוד עם פרמטר אחד. בעמוד הזה: איך מפעילים, מי רשאי לראות, איך קוראים את הטבלה, ומה עושים כשהפאנל לא מופיע.

הפעלה#

מוסיפים __router_trace לכתובת (הערך לא משנה, העיקר שהפרמטר קיים):

https://example.com/news/5?__router_trace=1
https://example.com/some-friendly-url?__router_trace=1

הפאנל מופיע רק לאחד משלושה:

מיהתנאי בקוד
אדמין מחוברADMIN::is_admin()
בקשה מהמכונה עצמהREMOTE_ADDR הוא 127.0.0.1, ::1 או localhost
בקשה מכתובת השרתREMOTE_ADDR שווה ל-SERVER_ADDR

לכל מבקר אחר הפרמטר פשוט לא עושה כלום, והעמוד נראה כרגיל. כך אפשר גם לבדוק מהשרת בלי להתחבר:

curl -s -H "Host: example.com" "http://127.0.0.1/news/5?__router_trace=1" | grep -o "ROUTER TRACE.*" | head
שימו לב

ההרשאה לפי 127.0.0.1 נשענת על REMOTE_ADDR. אם ה-PHP יושב מאחורי reverse proxy מקומי (nginx אל Apache או php-fpm באותה מכונה) שלא משחזר את כתובת הלקוח האמיתית, כל מבקר נראה ל-PHP כ-127.0.0.1, והפאנל, שחושף את הכללים הפנימיים של הניתוב, ייראה לכולם. בדקו פעם אחת, בלי להתחבר, ש-?__router_trace=1 מדפדפן רגיל לא מציג כלום.

איך הפאנל נראה#

פס קבוע בתחתית החלון (position: fixed, גובה מרבי 45% מהמסך, id="router-trace", dir="ltr") עם כפתור [close] שמסיר אותו. בראשו שורת מצב:

שדהמשמעות
requestה-REQUEST_URI המקורי
system_typeclient או admin (CONFIG::$system_type)
is_404האם PAGE::$is_404 הופעל

מתחתיה טבלה עם העמודות הבאות, שורה לכל שלב שנרשם, לפי הסדר:

עמודהמה בה
#המספר הסידורי של השלב
stageשם השלב (ראו הטבלה למטה)
urlהכתובת שנבדקה בשלב הזה
matchedהתבנית או השורה שהתאימה
noteמה נקבע בעקבות זה (module=..., pageUrl=..., האם הניתוב נעצר)

ובתחתיתה final $_GET: ערך $_GET כפי שהוא נראה אחרי הניתוב, כולל module, pname ו-id או sys_controller. זה המקום הכי מהיר לבדוק למה בקר קיבל id ריק.

מילון השלבים#

הסדר בטבלה הוא הסדר שבו ה-ROUTER מנסה כללים (ראו ניתוב). שלב שמסתיים ב-return או die עוצר את הניתוב, ולכן מה שאחריו לא יופיע.

שלב (stage)מתי נרשם
parse_friendly_url ENTERתחילת הניתוב, ה-note מכיל את ה-REQUEST_URI
HOMEPAGEכתובת ריקה: הבקר הוא CONFIG::$default_module
NEWPAGE pagep/<slug>: עמוד NEWPAGE, בקר newpage_public
SCRIPT tag_manager.jstag_manager.js: בקר minify
MINIFY js/cssminify/<id>.js או .css
SCSS (system assets)assets/<קובץ>.scss.css, קומפילציית SCSS מהליבה
SCSS (regular file)<קובץ>.scss.css מהאתר
STATIC FILE servedקובץ סטטי תחת assets/ שהוגש ישירות
ADMIN matchedהכתובת מתחילה ב-CONFIG::$admin_url: נקבעים module, pname, id
ADMIN internal call (ip==server)קריאה מהשרת עצמו: מדלגים על בדיקת המדינה
ADMIN Wizzo address (WIZZO_NET)כתובת של Wizzo: מדלגים על בדיקת המדינה
ADMIN BLOCKED by countryהמדינה לא ברשימה admin_countries: הפניה ל-/ ויציאה
ADMIN → doneהניתוב של האדמין הסתיים
CLIENT sideהכתובת היא של צד לקוח, מתחילים לפתור SEO ובקרים
SEO exact match / SEO exact: noneחיפוש שורת seoUrl מדויקת: נמצאה או לא
SEO regex match / SEO regex match (decoded)כלל regex שהתאים (הגרסה השנייה על הכתובת המפוענחת)
NO SEO → passthroughאין כלל SEO, הכתובת עצמה משמשת כנתיב
URL == "404"הכתובת היא 404: נשלחת כותרת 404 ו-PAGE::$is_404 נדלק
SYSTEM controller, SYSTEM controller/id, SYSTEM controller/page, SYSTEM controller/page/idבקר מערכת (system/...), ראו בקרי מערכת
MODULE module, MODULE module/id, MODULE module/page, MODULE module/page/idבקר אתר, אותן ארבע צורות
ROUTER ERRORאף תבנית לא התאימה (die("router error"))
MODULE::get_htmlנקרא MODULE::get_html, ה-note מכיל את הבקר, המתודה ואם הוא בקר מערכת
MODULE(system) → ERRORPAGEבקר מערכת לא נמצא או שהמתודה לא ציבורית
MODULE → ERRORPAGEבקר אתר חסר, לא פעיל או בלי המתודה, וה-note אומר איזה מהם
MODULE activation promptהקובץ קיים אבל המודול לא הופעל, ומוצג טופס הפעלה לאדמין
errorpage() → re-route to "404"MODULE::errorpage() נכנסת מחדש לניתוב עם 404 (404, 503 ושגיאות)

דוגמה: למה /blat נותן 404#

#  stage                          url    matched           note
0  parse_friendly_url ENTER       blat                     REQUEST_URI=/blat?__router_trace=1
1  CLIENT side                    blat                     resolving SEO / controller
2  SEO exact: none                blat                     no plain seoUrl row
3  NO SEO → passthrough           blat                     pageUrl = url (raw url used as route)
4  MODULE module                  blat   ^(x)$             module=blat → (controller must exist, else MODULE sends to 404)
5  MODULE::get_html               blat/index               module='blat' page=index is_system=false
6  MODULE → ERRORPAGE                                      module 'blat' not found/inactive in modules_tbl and no controller file
7  errorpage() → re-route to "404"                         MODULE returned ERRORPAGE; re-entering ROUTER with url="404"

(הטקסט מקוצר, והשלבים אחרי 7 הם ניתוב מחדש לכתובת 404.) שורה 6 היא התשובה: אין בקר בשם blat. אילו היה קובץ application/controllers/blat.php, השורה הייתה module activation prompt (לאדמין) או MODULE → ERRORPAGE ... active in DB but controller file/class missing, והתיקון שונה לגמרי.

קריאה מתוכנית והוספת שלבים#

ROUTER::$trace הוא מערך סטטי, ואפשר לקרוא אותו מכל קוד, גם בלי להפעיל את הפאנל. שלב נרשם בדיוק באותה צורה גם ממקום אחר, למשל מבקר שמחליט לשלוח לעמוד אחר:

ROUTER::trace('MY RULE', [
	'url'   => $slug,
	'match' => 'legacy-product',
	'note'  => 'redirecting to product ' . $id,
]);

המפתחות url, match ו-note אופציונליים. ROUTER::is_trace_on() מחזיר true כשהפרמטר קיים והמבקר מורשה, ושימושי אם רוצים להדפיס עוד מידע דיבוג רק במצב הזה:

if (ROUTER::is_trace_on()) {
	error_log(json_encode(ROUTER::$trace, JSON_UNESCAPED_UNICODE));
}

כל קריאה ל-ROUTER::trace (בשביל מבקר מורשה עם הפרמטר) רושמת פעם אחת פונקציית register_shutdown_function, שמדפיסה את הפאנל בסוף הבקשה.

מלכודות#

שימו לב
עמוד שמוגש מהמטמון לא עובר ניתוב, ולכן אין לו פאנל. cache_engine::cache_php_check רץ ב-core.php לפני PAGE::load, ובפגיעה במטמון העמוד מוגש ומסתיים שם. מפתח המטמון כולל את מחרוזת השאילתה, ולכן ?__router_trace=1 הוא עמוד נפרד שנוצר בבקשה הראשונה. בעמוד שבקר שלו מפעיל cache_engine::cache_all_page(), הבקשה השנייה לאותה כתובת עם אותו פרמטר תחזור מהמטמון בלי פאנל (הפאנל עצמו לא נשמר, כי הוא מודפס אחרי השמירה). שנו את הערך (?__router_trace=2) או הוסיפו פרמטר אקראי כדי לעקוף.

הערה

הפאנל מודפס ב-shutdown, ולכן הוא מצורף לסוף כל פלט: גם תשובת JSON או קובץ שנוצר בבקר עם pmode=empg תקבל אחריה <div id="router-trace">. כשאתם בודקים endpoint שמחזיר JSON, אל תוסיפו את הפרמטר לבקשה שה-JS עושה, אלא בדקו אותו בדפדפן או ב-curl נפרד.

הערה

הצעדים האחרונים לפני הצגת עמוד מתוך PAGE::load (PAGE::output, ה-theme) לא נרשמים כשלבי ניתוב. ה-trace מכסה את ההחלטה "איזה בקר ומתודה", לא את מה שהבקר עושה אחר כך. לזה משמשים אבחון ולוגים ו-PAGE API.

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.