קונפיגורציה (CONFIG_USER)

איפה מוגדרת הקונפיגורציה של אתר WIZZO CMS, כל מאפיין שהליבה קוראת (חובה, אופציונלי, ברירת מחדל ומקום הקריאה), הפרמטרים של preinit ו-init, ודוגמאות מלאות.

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

הקונפיגורציה של אתר היא מחלקה אחת, CONFIG_USER, בקובץ system/config.php של האתר. הליבה לא מגדירה אותה: היא מצפה שהאתר כבר הגדיר אותה לפני שהיא נטענת, ומרחיבה אותה במחלקה משלה. הדף הזה מפרט כל מאפיין שהליבה קוראת, אילו חובה, מה קורה כשהם חסרים, ואיפה בקוד כל אחד נקרא.

נתיבי קבצי ליבה בדף כתובים יחסית ל-api/core בריפו (למשל collections/DB.php). בעת הפריסה התיקייה הזו יושבת ב-system/core/ של האתר, ראו מבנה התיקיות של אתר. רשימת הפניות בסגנון ספר חתימות נמצאת ב-CONFIG_USER (רפרנס).

איפה הקונפיגורציה מוגדרת ומתי היא נטענת#

הסדר הוא קבוע, והוא נובע מ-index.php של האתר ומ-core.php:

  1. index.php עושה require_once("system/config.php"). הקובץ מגדיר class CONFIG_USER עם מאפיינים סטטיים.
  2. index.php הופך את CONFIG_USER::$core_path מנתיב יחסי לנתיב מוחלט (ראו הערה בהמשך).
  3. index.php טוען את core.php של הליבה. הוא טוען את כל קבצי collections/*.php, ביניהם collections/CONFIG.php שמגדיר class CONFIG extends CONFIG_USER.
  4. CONFIG::preinit() רץ ראשון, אחריו MISC::cli_check() ואז CONFIG::init(). רק אחרי כל אלה נטען application/includes/init.php של האתר, ואחריו בדיקת ה-page cache וניתוב הבקשה.

כל הקוד של הליבה והאתר פונה אל CONFIG::$something (לא אל CONFIG_USER). בזכות הירושה שני השמות מצביעים על אותם נתונים, אבל CONFIG היא גם זו שמוסיפה את המאפיינים שהיא מחשבת בעצמה.

<?php
// system/config.php: הקובץ היחיד שהאתר כותב, הליבה לא נוגעת בו
class CONFIG_USER
{
    static $db_type = "PDO";
    // ... ראו את הטבלה ואת הדוגמה המלאה בהמשך
}
מאפיין שלא הוצהר הוא שגיאה קטלנית
CONFIG היא מחלקה רגילה עם מאפיינים סטטיים. קריאה ישירה למאפיין שאף מחלקה לא הצהירה עליו (CONFIG::$mail_queue באתר שלא הגדיר אותו) זורקת Error: Access to undeclared static property, והעמוד נופל. הליבה קוראת בצורה מוגנת (isset, property_exists) רק את המאפיינים שבקבוצה "אופציונליים" בטבלה. כל השאר חייבים להיות מוצהרים, גם אם הערך שלהם ריק או false.

מאפיין סטטי בלי מילת visibility

בקוד האתר כותבים static $x = ... (בלי public), וזה ציבורי כברירת מחדל ב-PHP. אותו סגנון משמש בכל הליבה.

core_path: מה index.php עושה איתו#

ב-system/config.php רושמים את core_path כנתיב יחסי, "system/core" בהתקנה רגילה. index.php של האתר ממיר אותו לנתיב מוחלט, והליבה קוראת אותו כנתיב מוחלט בכל מקום (CONFIG::$core_path מופיע בקוד הליבה כ-470 פעמים).

<?php
// index.php של האתר (ללא display_errors: בייצור לא מציגים שגיאות בדפדפן)
error_reporting(E_ALL);

ob_start("ob_gzhandler");

require_once("system/config.php");

// מציאת נתיב הליבה האמיתי
$ex = explode("../", CONFIG_USER::$core_path);
$realPath = dirname(__FILE__);
if (CONFIG_USER::$core_path != "system/core") for ($i = 0; $i < (count($ex)); $i++) $realPath = dirname($realPath);
CONFIG_USER::$core_path = $realPath . "/" . $ex[(count($ex) - 1)];

// טעינת הליבה
require_once(CONFIG_USER::$core_path . "/core.php");

עבור "system/core" המשתנה $realPath נשאר שורש האתר והתוצאה היא <שורש האתר>/system/core. אם הליבה יושבת מחוץ לאתר (ליבה משותפת למספר אתרים), הערך נכתב עם קידומת ../, והלולאה מטפסת count($ex) רמות מעל שורש האתר, כלומר רמה אחת יותר ממספר ה-../ שכתבתם.

נתיב מוחלט ב-core_path שובר את index.php

אם כותבים core_path מוחלט (למשל __DIR__ . "/system/core"), התנאי != "system/core" מתקיים, הלולאה מטפסת רמה אחת מעל השורש והנתיב המתקבל שגוי. השתמשו ב-"system/core" או בנתיב יחסי עם ../, ובדקו את התוצאה כשמעבירים ליבה לתיקייה משותפת.

עדכון ליבה מניח מבנה של תיקיית אחות
admin/wizzo_update.php מחשב dirname(CONFIG::$core_path) ומניח שהיא התיקייה שמכילה את הליבה: הוא פורס את הגרסה החדשה ל-core_new_<תאריך> ומשאיר גיבוי core_bup_<תאריך> באותה תיקייה (שורות 506 ו-531). הליבה חייבת לשבת בתיקייה שבה מותר ליצור תיקיות אחיות. ראו עדכון ליבה.

מאפיינים ש-CONFIG מגדירה בעצמה#

אל תצהירו על המאפיינים האלה ב-CONFIG_USER. collections/CONFIG.php מצהיר עליהם (שורות 6-16, מסומנים שם "Do not defind this variables") ומחשב אותם בכל בקשה.

מאפייןמי קובע אותומשמעות
$protocolpreinit, שורות 25-32"https" ב-CLI, אחרת לפי $_SERVER["HTTPS"] == "on"
$base_pathpreinit, שורות 35-37התיקייה של סקריפט הכניסה (index.php), כלומר שורש האתר. נלקח מה-backtrace, לא מ-getcwd()
$db_fullprefixinit, שורות 66-67$db_prefix . "_" (כלומר CRM_). משמש לשאילתות SQL גולמיות (כ-190 מקומות)
$platform_datainit, שורות 81-106שורת הפלטפורמה הנוכחית מ-CRM_platforms, ראו להלן
$env_urlinit, שורות 79, 98, 121כתובת הבסיס של הסביבה: ה-host המבוקש כשמדובר ב-allowed domain, אחרת $site_url
$site_urlinit, שורה 111<protocol>://<platform domain>/ (עם סלאש סוגר)
$original_site_urlinit, שורה 112אותו דבר לפי $_SERVER['HTTP_HOST'] המקורי
$base_domaininit, שורות 114-118$set_base_domain אם הוגדר, אחרת $_SERVER['HTTP_HOST']. משמש לדומיין של cookies
$langinit, שורה 129ה-id של הפלטפורמה שנבחרה (גם MISC::$GLOBALS["lang"])
$system_typeROUTER, collections/ROUTER.php שורות 176 ו-413 ואילך"client" או "admin", נקבע לפי ה-URL
$site_configלא מוקצה בשום מקום בליבהמוצהר בלבד, אין לו שימוש

CONFIG::preinit#

preinit() רץ לפני כל גישה למסד הנתונים ועושה ארבעה דברים:

  • קובע date_default_timezone_set('Asia/Jerusalem'). האזור קבוע בקוד ולא ניתן להגדרה ב-CONFIG_USER.
  • קובע את $protocol ואת $base_path.
  • הופך את $models_folder ל-נתיב מוחלט: $base_path . "/" . $models_folder, ואם הוא מכיל ../ עובר דרך realpath().
  • עושה את אותו דבר ל-$cache_folder.
realpath על תיקייה שלא קיימת

כש-$cache_folder או $models_folder מכילים ../, preinit מפעיל realpath(). אם התיקייה לא קיימת, realpath() מחזיר false והנתיב נשבר בשקט. כשמשתמשים ב-"../cache" צרו את התיקייה לפני העלאת האתר.

CONFIG::init: בחירת הפלטפורמה#

init() קורא את CRM_platforms דרך cache_engine::get("platforms", ..., 24*30, false) (מטמון גלובלי ל-30 יום, מפתח לפי עמודת domain) וממפה את הבקשה לפלטפורמה:

  1. התאמה מדויקת של $_SERVER['SERVER_NAME'] לעמודת domain.
  2. אם אין, מחפשים בעמודת allowed_domains של כל פלטפורמה (מפוצלת לפי MISC::bgl_explode) שם שמכיל את ה-host. אם נמצא, גם $env_url מתעדכן ל-host המבוקש.
  3. אם עדיין אין, נבחרת הפלטפורמה הראשונה בטבלה.

כלומר הליבה אף פעם לא נכשלת בבחירת פלטפורמה. הדחייה של דומיין לא מוכר קורה אחר כך, ב-PAGE::load (ראו $ignore_domain_check). פרטי הפלטפורמות בדף פלטפורמות ורב-לשוניות.

הטבלה המלאה: מאפיינים שהאתר חייב להצהיר עליהם#

ה"חובה" בטבלה פירושו שהליבה קוראת את המאפיין בלי isset. גם מאפיין שנקרא רק בתנאי (למשל SMTP) מסומן, עם התנאי בעמודת המשמעות, כי כשהתנאי מתקיים המאפיין חייב להיות קיים.

מסד נתונים#

מאפייןסוגחובהדוגמהמשמעותנקרא ב-
$db_typestringכן"PDO"סוג החיבור: "PDO" (MySQL, מומלץ), "mysql" (הרחבה ישנה שהוסרה מ-PHP 7), "pg" (PostgreSQL), "clickhouse"collections/DB.php:78
$db_hoststringכן"localhost"שרת המסדDB.php:83
$db_dbnamestringכן"mysite"שם בסיס הנתונים. נקרא גם בשאילתות INFORMATION_SCHEMA של פאנלי הניהולDB.php:83
$db_userstringכן"mysite"משתמשDB.php:83
$db_passwordstringכן"secret"סיסמהDB.php:83
$db_portintלא (isset)3306פורט. ב-PDO מצורף ל-DSN רק אם הוגדר; ב-ClickHouse ברירת המחדל 8123; ב-pg הפורט קבוע 5432 בקודDB.php:83, DB.php:124
$db_protocolstringלא (isset)"https"ClickHouse בלבד: ברירת מחדל "http"DB.php:125
$db_prefixstringכן"CRM"קידומת הטבלאות בלי קו תחתוןCONFIG.php:67
db_prefix חייב להישאר CRM
$db_prefix נקרא בקוד, אבל כ-66 קבצי ליבה מכילים שאילתות SQL גולמיות עם CRM_ כתוב ישירות בטקסט (SELECT * FROM CRM_platforms כבר ב-CONFIG::init). קידומת אחרת שוברת את האתר בשקט בשאילתות הגולמיות. התייחסו ל-"CRM" כקבוע. טבלאות ובוני שאילתות: שכבת ה-DB, שאילתות.

נתיבים וניתוב#

מאפייןסוגחובהדוגמהמשמעותנקרא ב-
$core_pathstringכן"system/core"נתיב הליבה (יחסי בקובץ, מוחלט אחרי index.php). בלי / בסוףcore.php:24, 470 מקומות
$models_folderstringכן"application/models"תיקיית ה-models, יחסית לשורש האתר. הופך למוחלט ב-preinitCONFIG.php:40, MODULE.php:226
$cache_folderstringכן"cache"תיקיית המטמון, יחסית לשורש האתר (או "../cache"). הופך למוחלט ב-preinitCONFIG.php:52, cache_engine.php:101
$admin_urlstringכן"wizzocms"ה-slug של פאנל הניהול, בלי סלאשים. מוזרק ישירות לתוך ביטוי רגולריROUTER.php:411-441
$default_modulestringכן"home"הקונטרולר של דף הבית (כשה-URL ריק)ROUTER.php:178
admin_url הוא חלק מ-regex ולא נחסם
ROUTER בונה '/^' . CONFIG::$admin_url . '$/' בלי preg_quote. השתמשו באותיות, ספרות ומקף בלבד. תו מיוחד של regex (נקודה, סוגריים) משנה את התאמת הכתובת. בנוסף, ה-slug הוא נתיב הפאנל הציבורי, ולכן ערך שאפשר לנחש מקל על תקיפה: ראו הקשחה.

cache_folder לא מכסה את כל המטמונים

קבצי ה-.chc של cache_engine, ה-page cache, וה-composer ו-perf_advisor נשמרים תחת $cache_folder. לעומת זאת מטמוני ה-SCSS, ה-minify וה-Smarty כתובים בקוד כנתיב יחסי cache/... (collections/FILES.php:10, FILES.php:435, controllers/minify.php:90) ומתעלמים מהמאפיין. אם מעבירים את $cache_folder למקום אחר, התיקייה cache/ בשורש האתר עדיין חייבת להתקיים וניתנת לכתיבה. פירוט ב-איך המטמון עובד.

התנהגות#

מאפייןסוגחובהדוגמהמשמעותנקרא ב-
$allow_cacheboolכןtrueמאפשר שמירה והגשה של page cache (רק בצד לקוח) ופעולות cache_engine. כש-false, cache_engine לא שומר דברcore.php:43, cache_engine.php:120, :448
$use_smartytrue / "plain" / אחרכןtrueמצב התבניות: true = Smarty; "plain" = החזרת הקובץ כמות שהוא; כל ערך אחר = ענף ישן שמריץ את התבנית עם eval. אפשר לדרוס בכל קריאה דרך הגדרות התבניתcollections/FILES.php:205-256
$minify_htmlboolכןtruefalse מבטל כיווץ HTML של העמודcollections/PAGE.php:663
$ignore_domain_checkboolכןfalsetrue מדלג על die("URL ERROR") כשה-host לא מופיע ב-domain או ב-allowed_domains של הפלטפורמה. נקבע ל-true אוטומטית בהרצת CLIPAGE.php:719, MISC.php:167
ignore_domain_check וגישה בלי דומיין

בדיקת הדומיין חלה על בקשות צד-לקוח בלבד, ופטורות ממנה בקשות ל-minify ול-Tools ול-CRM.js. בקשה לדומיין שלא רשום בפלטפורמות מקבלת את הפלטפורמה הראשונה ואז נעצרת ב-URL ERROR. כדי להגיש את האתר מכתובת נוספת רשמו אותה ב-allowed_domains במקום להדליק $ignore_domain_check.

אחסון קבצים#

מאפייןסוגחובהדוגמהמשמעותנקרא ב-
$storage_remotestringכן"""" = דיסק מקומי (media/Storage), "ftp", "s3" (טוען את ספריית AWS בכל בקשה)core.php:28, STORAGE.php:195
$storage_remote_urlstringכש-ftp"https://cdn.example.com"קידומת ה-URL של קבצים שהועלו ב-FTPSTORAGE.php:704
$storage_remote_ftp_hoststringכש-ftp"ftp.example.com"שרת FTPSTORAGE.php:740
$storage_remote_ftp_usernamestringכש-ftp"cdnuser"משתמש FTPSTORAGE.php:768
$storage_remote_ftp_passwordstringכש-ftp"secret"סיסמת FTPSTORAGE.php:768

מפתחות S3 לא ב-CONFIG. הליבה קוראת אותם מ-MISC::$GLOBALS["Storage_remote_s3_key"], ["Storage_remote_s3_secret"] ו-["Storage_remote_s3_bucket"] (STORAGE.php:446-452), ואף קובץ בליבה לא מגדיר אותם. האתר מציב אותם ב-application/includes/init.php (ראו הדוגמה בהמשך). פרטי ההעלאה ב-STORAGE: העלאה ואחסון.

שתי תכונות של S3 שכדאי להכיר

כתובת קובץ ב-S3 נבנית כ-https://s3.amazonaws.com/<path> (STORAGE.php:705): שם ה-bucket לא מתווסף אליה על ידי הקוד, ולכן צריך שיהיה חלק מה-path אם ה-URL צריך אותו. בנוסף, בענף ההעלאה של STORAGE הענף s3 לא מסתיים ב-break, ולכן אחרי ההעלאה ל-S3 מתבצעת גם עותק מקומי אל media/Storage (STORAGE.php סביב שורות 442-470). אל תניחו שבשימוש ב-S3 תיקיית media/ נשארת ריקה.

דואר#

מאפייןסוגחובהדוגמהמשמעותנקרא ב-
$mail_queueboolכן, בשליחה דרך mail_tplfalsetrue = ההודעה נכנסת לתור ונשלחת מאוחר יותר; false = שליחה מיידית (והתוצאה נרשמת בתור)libraries/mail_tpl.php:254
$mail_is_smtpboolכן, בכל שליחהtrueרק === true מפעיל SMTP. אחרת PHPMailer שולח דרך mail() של PHPmail_tpl.php:149, MISC.php:789
$mail_smtp_hoststringכש-SMTP"smtp.example.com"שרתMISC.php:792
$mail_smtp_portintכש-SMTP587פורטMISC.php:797
$mail_smtp_securestringכש-SMTP"tls""tls" או "ssl"MISC.php:796
$mail_smtp_authboolכש-SMTPtrueהזדהותMISC.php:793
$mail_smtp_usernamestringכש-SMTP"user"משתמשMISC.php:794
$mail_smtp_passwordstringכש-SMTP"secret"סיסמהMISC.php:795

פירוט נוסף בדף שליחת דואר.

מאפיינים אופציונליים#

הליבה קוראת אותם רק אחרי isset או property_exists, ולכן אפשר להשמיט אותם:

מאפייןסוגברירת מחדל כשחסרמשמעותנקרא ב-
$set_base_domainstring$_SERVER['HTTP_HOST']דומיין בסיס ל-cookies, למשל ".example.com" כדי לשתף cookie בין תת-דומייניםCONFIG.php:114
$environmentstringללא סינון"dev" או "production": סינון סקריפטים של tag manager לפי עמודת environment (הערך "all" תמיד עובר)controllers/minify.php:321-323
$show_wizzo_creditsbooltruefalse מסיר את <meta name="copyright"> של WIZZO מראש העמודPAGE.php:521
$admin_countriesarray או falseללא הגבלהקודי מדינה מותרים להתחברות לפאנל. הקובץ system/admin_countries.json קודם למאפיין הזהlibraries/admin_countries.php:40
$maskfalse / true / arrayכבוימצב הסוואה: מפה של נתיבים אמיתיים לנתיבים נייטרליים. true = ברירת מחדל מובנית. ראו מצב הסוואה (MASK)collections/MASK.php:60
$mask_wordsarrayריקהחלפות מילים לפלט בלבד (אמיתי => נייטרלי), פעיל רק כש-$mask פעילMASK.php:96
ערך null שקול להיעדר
isset מחזיר false גם למאפיין שהוצהר עם null. כדי לכבות אופציה כתבו false או מחרוזת ריקה במקום null.

מאפיין אחד שרידי: $zend_db נקרא רק ב-zend_query של DB.php (שורה 1282), פונקציה שבורה שלא נקראת מהליבה. אל תצהירו עליו.

שכבות קונפיגורציה אחרות#

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

  • פלטפורמה (CRM_platforms): דומיין, allowed_domains, ערכת נושא ברירת מחדל (deftheme), כותרת ותיאור SEO ברירת מחדל, כיוון שפה. השורה הנבחרת היא CONFIG::$platform_data. ראו פלטפורמות ורב-לשוניות.
  • פרמטרים (CRM_params): מפתח וערך (sysName, value) שנטענים כולם בבקשה לזיכרון דרך PARAMS::init() ונקראים עם PARAMS::get("key"). מטמון של 30 יום. ראו פרמטרים ומילים.
  • מילים (CRM_langs_words): טקסטים לפי שפה, דרך LANGS::init_words(), מטמון words_lang<lang> ל-4 שעות.

כלל אצבע: ערך שמשתנה בין סביבות (dev ו-production) או מכיל סוד נשאר ב-CONFIG_USER; ערך שעורך תוכן או מנהל אמור לשנות נכנס ל-PARAMS.

דוגמה מינימלית#

האתר הקטן ביותר שרץ: מסד MySQL, אחסון מקומי, בלי SMTP.

<?php
// system/config.php
class CONFIG_USER
{
    // מסד נתונים
    static $db_type     = "PDO";
    static $db_host     = "localhost";
    static $db_dbname   = "mysite";
    static $db_user     = "mysite";
    static $db_password = "change-me";
    static $db_prefix   = "CRM";                    // חייב להישאר CRM

    // נתיבים וניתוב
    static $core_path      = "system/core";         // יחסי: index.php הופך אותו למוחלט
    static $models_folder  = "application/models";
    static $cache_folder   = "cache";
    static $admin_url      = "wizzocms";
    static $default_module = "home";

    // התנהגות
    static $allow_cache         = true;
    static $use_smarty          = true;
    static $minify_html         = true;
    static $ignore_domain_check = false;

    // אחסון מקומי
    static $storage_remote = "";

    // דואר: PHP mail()
    static $mail_queue   = false;
    static $mail_is_smtp = false;
}

דוגמה לייצור: S3, SMTP ואופציות#

אתר ייצור עם הסביבה מוגדרת, SMTP, הסוואה, והגבלת מדינות. כל הערכים שבדוגמה הם מקומות שמורים, ולא ערכים אמיתיים.

<?php
// system/config.php (מוגן ע"י system/.htaccess ואסור לשמור אותו ב-git)
class CONFIG_USER
{
    static $db_type     = "PDO";
    static $db_host     = "127.0.0.1";
    static $db_port     = 3306;
    static $db_dbname   = "prod_site";
    static $db_user     = "prod_site";
    static $db_password = "from-your-secret-store";
    static $db_prefix   = "CRM";

    static $core_path      = "system/core";
    static $models_folder  = "application/models";
    static $cache_folder   = "cache";
    static $admin_url      = "manage-7f3a";          // slug לא צפוי, אותיות ומקף בלבד
    static $default_module = "home";

    static $allow_cache         = true;
    static $use_smarty          = true;
    static $minify_html         = true;
    static $ignore_domain_check = false;
    static $environment         = "production";
    static $show_wizzo_credits  = false;
    static $set_base_domain     = ".example.com";    // cookie משותף לכל תתי-הדומיינים
    static $admin_countries     = ["IL"];
    static $mask                = true;              // הסוואת נתיבי theme / minify / system/js

    // אחסון ב-S3: המפתחות ב-MISC::$GLOBALS (ראו init.php בהמשך)
    static $storage_remote = "s3";

    // דואר דרך SMTP
    static $mail_queue         = true;
    static $mail_is_smtp       = true;
    static $mail_smtp_host     = "smtp.example.com";
    static $mail_smtp_port     = 587;
    static $mail_smtp_secure   = "tls";
    static $mail_smtp_auth     = true;
    static $mail_smtp_username = "mailer@example.com";
    static $mail_smtp_password = "from-your-secret-store";
}
<?php
// application/includes/init.php: נטען בכל בקשה אחרי CONFIG::init()
MISC::$GLOBALS["Storage_remote_s3_key"]    = "AKIA...";   // להביא ממשתנה סביבה או מכספת
MISC::$GLOBALS["Storage_remote_s3_secret"] = "...";
MISC::$GLOBALS["Storage_remote_s3_bucket"] = "my-bucket";
סודות בקובץ קונפיגורציה
system/config.php מכיל סיסמת מסד נתונים וסיסמת SMTP. הוא מוגן מהגשה ב-HTTP על ידי system/.htaccess (שהליבה כותבת), אבל אסור להעלות אותו ל-git ואסור שיהיה קריא בשרתים שלא מריצים Apache. אם אפשר, קראו את הערכים ממשתני סביבה. ראו מודל האבטחה.

איפה בודקים בפועל מה נטען

כשמשהו לא מתנהג כמצופה, בדקו קודם את CONFIG::$platform_data (איזו פלטפורמה נבחרה) ואת CONFIG::$system_type (אדמין או לקוח), אלה שני הערכים שמשנים את רוב ההחלטות של הליבה.

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