כל בקשה שמגיעה ל-index.php עוברת דרך המחלקה ROUTER (system/collections/ROUTER.php). היא לא מריצה קוד של אתר: היא רק קוראת את הכתובת ומכניסה ל-$_GET את המפתחות module, pname, id (או sys_controller לקונטרולר מערכת), וקובעת אם הבקשה היא client או admin. אחריה MODULE::get_html() טוען את הקונטרולר ומריץ את המתודה. בעמוד הזה מתואר הסדר המדויק של ההחלטות, כדי שתדעו לצפות איך כתובת תתפרש לפני שאתם כותבים קונטרולר.
system/ בעמוד הזה הוא תיקיית הליבה הפרוסה (api/core בריפו), ו-{admin} הוא CONFIG::$admin_url.
איפה הניתוב רץ#
PAGE::load($_SERVER['REQUEST_URI']) מאפס את PAGE, מאתחל PARAMS ו-SEO, וקורא ל-ROUTER::parse_friendly_url($url). בסיום הוא בודק הפניות 301 (ROUTER::redirections(), ראו הפניות 301) וטוען את application/includes. התמונה המלאה של מחזור הבקשה נמצאת ב-מחזור חיי בקשה.
מה ROUTER מחזיר: מפתחות ב-$_GET#
parse_friendly_url לא מחזיר ערך. התוצאה היא מצב גלובלי:
| מפתח | מתי נקבע | משמעות |
|---|---|---|
CONFIG::$system_type | תמיד | "client" או "admin" |
$_GET["module"] | קונטרולר של אתר, ופאנל ניהול | שם הקלאס (וקובץ הקונטרולר) |
$_GET["sys_controller"] | קונטרולר מערכת | שם קובץ ב-system/controllers/ |
$_GET["pname"] | תמיד | שם המתודה; ריק פירושו index |
$_GET["id"] | כתובת עם מקטע מספרי או שלישי | המקטע האחרון |
ל-pname ריק, MODULE::get_html מחליף ל-index.
סדר ההחלטות#
הבדיקות רצות לפי הסדר הזה, והראשונה שמתאימה מכריעה. רובן מסתיימות ב-return (ללא ה-seoUrl), חלקן מגישות קובץ ויוצאות.
| # | התנאי (אחרי הסרת / מההתחלה ומהסוף) | מה קורה |
|---|---|---|
| 1 | פיצול ב-? | מה שאחרי ה-? נפרס ב-parse_str ומחליף את $_GET (ראו למטה) |
| 2 | מצב הסוואה | MASK::in($url) מחזיר נתיב אמיתי מנתיב מוסווה |
| 3 | כתובת ריקה | דף הבית: client, module = CONFIG::$default_module, pname = "" |
| 4 | <32 תווי hex>.txt | מפתח IndexNow של חבילת ה-SEO |
| 5 | poosh-sw.js, tjs.js, pjs.js | קבצי שירות של Wizzo Market, מוגשים מהדומיין של האתר עצמו |
| 6 | p/<slug> | sys_controller=newpage_public, np_slug=<slug> (דף נחיתה של "דף חדש") |
| 7 | pg.js, pg.css | פרוקסי מטמון לנכסי "דף חדש" |
| 8 | tag_manager.js | minify/tag_manager |
| 9 | minify/<id>.js או .css | minify עם id (צינור הנכסים) |
| 10 | assets/<path>.scss.css ו-<path>.scss.css | minify/scss עם file |
| 11 | assets/<path>.(js|css|jpg|png|svg|woff2...) | אם הקובץ קיים ב-system/assets/, הוא מוגש ב-readfile ויוצא |
| 12 | קידומת {admin} | system_type = "admin": ראו פאנל הניהול |
| 13 | כל השאר (לקוח) | חיפוש ב-seoUrl (כתובות ידידותיות), ואז פירוק הכתובת לפי תבניות |
פירוק כתובת של אתר#
אחרי שה-seoUrl החליט מה "הנתיב הפנימי" (או שלא נמצאה התאמה והכתובת עצמה היא הנתיב), הנתיב מפורק ב-regex לפי הסדר. קודם system/..., ואחר כך מודול רגיל:
| תבנית | דוגמה | תוצאה |
|---|---|---|
system/x/<ספרות> | system/pdf_viewer/15 | sys_controller=pdf_viewer, id=15 |
system/x/y/z | system/Tools/gallery/3 | sys_controller, pname=y, id=z |
system/x/y | system/analytics/index | sys_controller, pname=y |
system/x | system/mcp | sys_controller=x |
x/<ספרות> | news/12 | module=news, id=12 (ללא pname) |
x/y/z | news/item/12 | module=news, pname=item, id=12 |
x/y | news/archive | module=news, pname=archive |
x | news | module=news |
כל מה שלא מתאים (למשל // באמצע הכתובת) מגיע ל-die("router error").
id
news/item/2024/05 מפורק ל-pname=item ו-id=2024/05: המקטע השלישי לוקח את כל מה שנשאר, כולל לוכסנים. אם אתם צריכים כמה פרמטרים, או שתפרקו את $_GET["id"] בעצמכם, או שתגדירו כתובת ידידותית עם regex.פרמטרים: id, pname ומחרוזת השאילתה#
קונטרולר קורא את הפרמטרים ישירות מ-$_GET. אין הזרקת ארגומנטים למתודה.
<?php
// application/controllers/news.php
// GET /news/12 -> index() עם $_GET["id"] = "12"
// GET /news/archive -> archive()
// GET /news/item/12 -> item() עם $_GET["id"] = "12"
class news extends wz_controller
{
function index()
{
$id = (int)($_GET["id"] ?? 0); // תמיד המירו: הערך מגיע כמחרוזת
if ($id === 0) return $this->view("news/list");
$row = DB::query("news", ["id" => $id])->get_row();
if (!$row) return "ERRORPAGE"; // הופך ל-404 (ראו שגיאות)
return $this->view("news/item", ["row" => $row]);
}
function archive() { return $this->view("news/archive"); }
function item() { return $this->index(); }
}
$_GET מוחלף, לא ממוזג#
כשבכתובת יש ?, הניתוב מבצע $_GET = $arrget: המערך שנבנה מה-REQUEST_URI מחליף את מה ש-PHP בנה. התוצאה בדרך כלל זהה, אבל שני הבדלים חשובים:
- הפיצול הוא
explode("?", $url)בלי הגבלה, ולכן אם יש בכתובת שני סימני?, רק החלק שבין הראשון לשני נקרא. - פרמטרי מעקב ידועים (
utm_*,gclid,fbclidועוד, הרשימה ב-cache_engine::$tracking_params) מוסרים מה-REQUEST_URIלפני הניתוב, בשביל מטמון העמודים. הניתוב מחזיר אותם ל-$_GETמהמקור, כך שהם זמינים לקוד שלכם.
פרמטרים שה-seoUrl מוסיף דרך ? בנתיב הפנימי (למשל pageurl = news/item?lang=en) ממוזגים לתוך $_GET ודורסים מפתח באותו שם.
pmode: תשובה בלי עטיפת HTML#
אם $_GET["pmode"] הוא empg או inner, PAGE::output() לא עוטף את הפלט ב-theme וב-<html>: מוחזר רק מה שהקונטרולר החזיר. כך נכתבים נתיבי JSON וקבצים, למשל /news/feed?pmode=empg. (ב-PAGE::output נשלחות גם כותרות scripts ו-scripts_ver עם רשימת הנכסים.)
ה-API הציבורי של ROUTER#
| חתימה | מה עושה |
|---|---|
ROUTER::parse_friendly_url(string $url) | הניתוב עצמו; ממלא $_GET ו-CONFIG::$system_type |
ROUTER::redirections() | בודק את טבלת redirections ועונה 301; ראו הפניות 301 |
ROUTER::get_seo_tbl() | כל שורות seoUrl לפי ord, במטמון seoUrl_tbl |
ROUTER::get_by_url($url) | נתיב פנימי => הכתובת הידידותית שלו (או הנתיב עצמו אם אין) |
ROUTER::get_by_friendly($url) | כתובת ידידותית => הנתיב הפנימי (או הכתובת עצמה אם אין) |
ROUTER::remove_by_url($url) | מוחק שורות seoUrl שה-pageurl שלהן שווה ל-$url |
ROUTER::is_trace_on() | האם מצב הדיבוג דלוק לבקשה הזו |
ROUTER::trace($stage, $detail = []) | רושם שלב בהחלטה (url, match, note) |
ROUTER::trace_render() | מדפיס את הפאנל; נרשם אוטומטית ב-shutdown |
ROUTER::$trace | מערך השלבים שנרשמו |
הכתובת הידידותית לרשומה (כשיש seoUrl) נוצרת כך:
$url = ROUTER::get_by_url("news/item?id=" . (int)$row["id"]); // "my-news-title" או הנתיב עצמו
echo "<a href=\"/" . htmlspecialchars($url) . "\">" . htmlspecialchars($row["title"]) . "</a>";
die("router error") ו-die("URL ERROR") עונים 200
כתובת שלא מתאימה לאף תבנית, ובקשה לדומיין שלא מופיע ב-platforms.domain או ב-allowed_domains (כש-CONFIG::$ignore_domain_check אינו true), מסתיימות ב-die עם סטטוס 200 וללא רישום ל-error_log. לכלי ניטור שמסתמכים על קוד סטטוס זה נראה כמו עמוד תקין.החלק הראשון בכתובת הופך ישירות לשם קלאס וקובץ ב-application/controllers/<name>.php. בשרת Linux השם רגיש לאותיות גדולות וקטנות, והתו היחיד שאסור בו הוא /. קונטרולר ששמו p יתנגש עם /p/<slug> (המסלול של "דף חדש" נבדק קודם), ושם system לא יהיה זמין כמודול.
ראו גם#
- כתובות ידידותיות (seoUrl): מיפוי כתובות לנתיבים פנימיים, כולל regex
- קונטרולרים של אתר ו-קונטרולרי מערכת
- דיבוג ניתוב:
?__router_trace=1 - 404, 503 ושגיאות
- ROUTER ו-MODULE (רפרנס)