Core/System/Config — Yapılandırma, ortam değişkeni ve sır okuyucuları
Doğrulanan kod tabanı:
d508f5e1(dalfeat/fw-license-master) · Tarih: 2026-10-05 · Yayın: 0.9.7 = bu commit + sonrası; belge yalnız doğrulama anındaki kodu anlatır
Kaynak klasör:Core/System/Config/— 22*.php+ 3README.md(sır dosyasıSecrets/secrets.phpbilerek okunmadı/anlatılmadı; yalnız adı ve kuralları var).
Envanter: 22 php dosyasının 22'si ve 3 README aşağıda anlatıldı (secrets.phpdahil; içeriği hariç).
1. Ne işe yarar, kim kullanır
Çatının "ayar" kapısıdır; üç ayrı kaynağı üç ayrı tek okuyucuya böler:
| Ne | Tek okuyucu | Kaynak |
|---|---|---|
Gizli değer (parola, app_key, jeton, API anahtarı) |
Secrets |
Secrets/secrets.php (bölümlü tek dosya) |
| Ortam bayrağı / kill-switch / çalışma ayarı | Secrets::app() |
Secrets/secrets.php → app bölümü (opsiyonel) |
Dosya tabanlı ayar (project-settings.php vb.) |
Config (+ ConfigResolver) |
proje Core/Config/ klasörü |
Framework işletim sistemi ortam değişkeni okumaz (FW-096-D8; ADR Core/System/Config/README.md). Veritabanı bağlantı bilgisi: DbProfileResolver master/common için Secrets::masterDb(), proje için Secrets::optional() → sabit varsayılan sırasını izler.
Kimler çağırır: kernel aşamaları (Kernel/Base/PreBoot, Stages/*), Core/Database bağlantı sağlayıcıları, Core/Services/Gatekeepers (veritabanı bekçisi), Packages/RbnEmail (SMTP), CLI komutları. Ölçülen çağrı sayıları (yalnız Core, Bundles, Packages, Resources altındaki *.php): Config::get( 21, Secrets:: 38+ (D8 sonrası Secrets::app() dahil; Env::* 0), DbProfileResolver:: 21, SmtpProfileResolver:: 9, ProjectDbProfileResolver:: 5.
2. Klasör/dosya envanteri
2.1 Kök (Rbn\Framework\Core\System\Config)
| Dosya | Görev | Önemli public yöntemler |
|---|---|---|
Config.php |
Statik "proxy hub": noktalı anahtarla dosya ayarı okur, bellek önbelleği tutar. | get(string $key, mixed $default = null): mixed, set(string $key, mixed $value): void, clear(?string $key = null): void, setSurvivalMode(bool), isResolving(): bool |
Secrets.php |
Sır dosyasının ince cephesi (bölümlü API + düz API). ConfigFileLoader ve SecretsFlatApi trait'lerini kullanır. |
section(string $name): array, masterDb(): array, smtp(): array, cpanel(): array, api(string $name): array, appKey(): string, app(): array (ortam bayrağı + çalışma ayarları, güvenli varsayılanlı), legacySalt(): ?string, cpanelHost()/cpanelUser()/cpanelToken(): string, setTestDirectory(?string), resetCache(); trait'ten: all(), get($key), masterDbPass(), masterSmtpPass(), optional($key): ?string |
2.2 Definitions/ — yalnız sabit/tanım (ad alanı …\Config\Definitions)
| Dosya | Görev |
|---|---|
ConfigMap.php |
BaseConfig'ten türeyen küçük çekirdek ayar kısayolları: getAppDebug(), getAppLogging(), getAppEnv(), getAppIsCli(), getAppSessionTimeout() (hepsi static). |
SecretsSchema.php |
Sır dosyasının şeması: yol, bölüm kuralları, düz anahtar adları (final class, yalnız public const). |
2.3 Definitions/DbProfiles/ — veritabanı profil sabitleri (yalnız sabit)
| Dosya | Görev |
|---|---|
MasterDbData.php |
Master veritabanı: PREFIX='MASTER_DB', CHARSET, REQUIRED_TABLES (5 tablo), KEYS_MAP. Bağlantı değerleri sır dosyasındandır. |
CommonDbData.php |
Ortak (common) veritabanı: DB_NAME='rbncore_common', USER_ENV='COMMON_DB_USER', PASS_ENV='COMMON_DB_PASS', REQUIRED_TABLES (6), CLEANUP_ALLOWED_TABLES (4), KEYS_MAP. |
ProjectDbData.php |
Proje veritabanı: HOST='127.0.0.1', DEFAULT_DB_USER='root', USER_ENV='DB_USER', PASS_ENV='DB_PASS', DB_USER_KEY='db_user', DB_PASS_KEY='db_pass', REQUIRED_TABLES (11), CLEANUP_ALLOWED_TABLES (2), kiracı sözleşmesi (TENANT_COLUMN='project_key', TENANT_COLUMN_TYPE='varchar(64)', TENANT_INDEX_PREFIX='ix_', TENANT_TABLES — 12 tekil tablo), KEYS_MAP. |
(Ayrıca DbProfiles/README.md bu üç sabit dosyasını anlatan yerel nottur.)
2.4 Engine/Config/ — dosya yükleme tekniği (ad alanı …\Engine\Config)
| Dosya | Görev | Yöntemler |
|---|---|---|
ConfigResolver.php |
Ayar adı → dosya yolu çözümü; özyineleme (isResolving) ve "survival" bayrağı. |
resolve($name, ?$projectKey): string, resolveContext($type, ?$name, ?$projectKey): mixed, guard(): mixed, setSurvivalMode(), isResolving(), setResolving() |
ConfigFileLoader.php |
Ortak dosya tekniği (trait): bul → izin/içerik koru → require → normalize → doğrula; sonuç bellekte önbelleklenir. |
includeArray($dir,$file,$displayPath): array, normalize(array): array, validate($flat,$required,$nonEmpty,$label,$displayPath), load(...), resetCache() |
ConfigFileGuard.php |
Sır dosyası koruması (trait): izin tavanı 0600 ve <?php/return sızıntı denetimi. |
guardFileMode(), guardFileContent(), examplePath(), hint() |
2.5 Engine/Database/ — bağlantı profili çözücüleri (ad alanı …\Engine\Database)
| Dosya | Görev | Yöntemler |
|---|---|---|
DatabaseConfig.php |
Değişmez (readonly) bağlantı değer nesnesi: host, database, user, password, charset. |
fromFile(string $path, string $name): self, fromRaw(array $data, string $name): self |
DbProfileResolver.php |
Profil sınıfı (MasterDbData/CommonDbData/ProjectDbData) → bağlantı değerleri. |
credentials($profile): array, host(), port(), databaseName(), user(), password(), charset(), keysMap() |
ProjectDbProfileResolver.php |
project-settings.php içindeki DB_PROFILES (local/production) seçici. |
activeProfile(): string, resolve(array $data, ?string $profile = null): array, requiredKeys(): array; sabitler PROFILES_KEY='DB_PROFILES', PROFILE_LOCAL, PROFILE_PRODUCTION, PLACEHOLDER='__DOLDUR__' |
SmtpProfileResolver.php |
SMTP alanlarını sır dosyasının smtp bölümünden okur. |
enabled(): bool, host(), port(): int, secure(), user(), pass(), fromAddress(), fromName() |
2.6 Engine/Secrets/ — sır okuma motoru (ad alanı …\Engine\Secrets)
| Dosya | Görev | Yöntemler |
|---|---|---|
SecretsLoader.php |
Yol çözümü + ham dosya okuma (TEK okuma kapısı); test için dizin değiştirilebilir. | raw(): array, rootDirectory(), fileName(), displayPath(), fullPath(), isFileMissing(), setDirectory(?string), resetCache() |
SecretsSections.php |
Bölüm okuma + şema doğrulama + düz anahtar haritaları. | read($name): array, readAll(): array, topLevelScalars(): array, topLevel($key): ?string, optionalFlat(): array |
SecretsValidator.php |
Bölüm adı ve okunabilirlik doğrulaması. | sectionName(string): string (yalnız [A-Za-z0-9_]+), readable($fullPath,$displayPath,$fileName) |
SecretsFlatApi.php |
Eski "düz anahtar" okuma yüzeyi (trait; Secrets üzerinde kalır). |
all(), get($key), masterDbPass(), masterSmtpPass(), optional($key) |
2.7 Secrets/ — veri klasörü
| Dosya | Görev |
|---|---|
secrets.example.php |
Şablon (depoya girer): master_db, smtp, cpanel bölümleri, üst düzey app_key, api {hizmet ⇒ alanlar}; her alan CHANGE_ME. |
secrets.php |
Gerçek sır dosyası; .gitignore'lu. Bu belge içeriğini okumaz, yazmaz. |
README.md |
Klasörün kısa kullanım notu (45 satır). |
3. Akışlar
3.1 Config::get('dosya.anahtar.alt') (Config.php:56)
ConfigResolver::isResolving()doğruysa varsayılan döner (özyineleme koruması,Config.php:59).setResolving(true)yapılır (:63);finallybloğufalse'a çevirir (:111-113).- Anahtar
database,database_master,database_commonya dadatabase_projectise dosyaya bakılmaz;ConfigResolver::resolveContext()döner (:67-69). - Aksi halde anahtar
.ile bölünür; ilk parça dosya adıdır.ConfigResolver::resolve($dosya)yolu verir, dosya varsaincludeedilipself::$items[$dosya]içine alınır (:72-77). project-settingsiçin aktif proje anahtarı (active_project_key()) varsa,ResolvesProjectConfigTrait::getRouteConfig()çıktısı dosya dizisinin ÜZERİNE yazılır (:88-97).- Kalan parçalar iç içe dizide yürütülür; bulunamazsa varsayılan döner (
:100-108). HerThrowablevarsayılana çevrilir (:109-110).
3.2 Yol çözümü (ConfigResolver::resolve, ConfigResolver.php:71)
database_master→<frameworkRoot>/Core/System/Config/Definitions/DbProfiles/MasterDbData.php;database_common→CommonDbData.php(:75-94).database_project→ proje anahtarı verildiyseresolveProjectPath($key, 'Core/Config/project-settings.php'); yoksaPaths::project()->configs('project-settings.php')(:96-102).- Diğer adlar:
guard()birdatabaseGuardservisi döndürürse onunresolvePath()çağrılır; dönmezsePaths::project()->configs($ad.'.php')(:104-111).
3.3 Veritabanı bağlantı değeri üretimi
DatabaseConfig::fromRaw($data, $ad) (DatabaseConfig.php:52):
database_master→new self(...DbProfileResolver::credentials(MasterDbData::class))(:55-57).database_common→ aynı,CommonDbDataile (:60-62).- diğer →
ProjectDbProfileResolver::resolve($data)(profil seçimi) sonraDefinition::get('database_project','KEYS_MAP')ile alan eşlemesi; eşleme yoksa boş varsayılan nesne (:64-84).
DbProfileResolver çözüm sırası:
| Alan | master | common | proje |
|---|---|---|---|
| host | Secrets::masterDb()['host'] |
aynı | ProjectDbData::HOST (127.0.0.1) |
| database | master_db.name |
CommonDbData::DB_NAME |
'' (DatabaseConfig'te DB_NAME anahtarından) |
| user | master_db.user |
env COMMON_DB_USER → master_db.user |
env DB_USER → sır db_user → root |
| password | master_db.pass |
env COMMON_DB_PASS → master_db.pass |
env DB_PASS → sır db_pass → hata (sessiz boş parola yok, DbProfileResolver.php:155) |
port() proje için bilerek RuntimeException fırlatır (:83-89): proje portu profil katmanında yoktur.
3.4 DB_PROFILES seçimi (ProjectDbProfileResolver.php)
activeProfile() (:99-107): önce secrets.php app.db_profile (local/production, başka her değer yok sayılır; declaredProfile() :180-189, ortam değişkeni okunmaz); yoksa framework kökünde tam localhost yol segmenti varsa local (:204-215); aksi production. Karar istemciden bağımsızdır (sunucu kimliği); is_local() kullanılmaz (gerekçe docblock :66-98).
resolve() (:121-171): DB_PROFILES yoksa/boşsa dosya aynen döner (geriye uyum). Seçilen profil yoksa, profilde zorunlu anahtar (DB_HOST,DB_NAME,DB_USER,DB_PASS,DB_CHARSET) eksikse ya da değer __DOLDUR__ ise RuntimeException; başka profile düşülmez.
3.5 Sır okuma (Secrets::section → SecretsSections::read)
- Bölüm adı
SecretsValidator::sectionName()ile doğrulanır. SecretsLoader::raw()→ConfigFileLoader::includeArray(): dosya var mı (is_file/is_readable),guardFileMode(Linux'ta mod& ~0600≠ 0 ise hata; Windows'ta atlanır,ConfigFileGuard.php:79),guardFileContent(ilk 8 KiB:<?phpile başlamalı,returniçermeli,return'den önce?>olmamalı), sonrarequire; sonuçarraydeğilse hata.- Değerler
normalize()ile string'e çevrilir (skaler olmayan''olur,ConfigFileLoader.php:106). SecretsSchema::SECTION_RULESilevalidate(): eksik alan,CHANGE_MEşablon değeri, boş zorunlu alan → hata (:129-156).- Hata metinleri yalnız dosya/bölüm/alan adını yazar; değer yazmaz.
4. Ayar anahtarları ve varsayılanlar
4.1 app bölümü (eski 16 ortam değişkeninin yerine)
Ortam değişkeni katmanı (Env.php + EnvKeys.php) FW-096-D8 ile kaldırıldı. Alanlar ve güvenli varsayılanlar SecretsSchema::APP_DEFAULTS'tadır: environment (production), debug/dev (false), guard_failclosed (true), log_throttle (true), db_profile (''), tg_send_delay_ms (0), allow_legacy_salt (false). Metin alanlarının izinli değerleri APP_ALLOWED. Tipi tutmayan değer varsayılana düşer ve loglanır; environment yoksa production + bir kez log. Eski ad → yeni alan eşlemesi: kavramlar/02-yapilandirma.md §6.
4.2 Sır dosyası şeması (SecretsSchema)
BASE_DIR='Core/System/Config',FILE='/Secrets/secrets.php',SECRET_FILE_MODE=0600,CHANGE_ME='CHANGE_ME',APP_KEY_NAME='app_key',API_SECTION='api'.SECTION_RULES:master_db(host, port, name, user, pass;passboş olabilir),smtp(enabled, host, port, secure, user, pass, from_address, from_name),cpanel(host, user, token — hepsi dolu).OPTIONAL_SECTIONS = ['master_db','smtp']; düz anahtar adlarımaster_db_pass,master_smtp_pass,rbncore_master_user.
4.3 ConfigMap (Definitions/ConfigMap.php:23)
| Yöntem | Kural | Varsayılan |
|---|---|---|
getAppDebug() |
RBN_DEBUG sabiti tanımlıysa o, yoksa app.debug |
false |
getAppLogging() |
app.logging |
true |
getAppEnv() |
PreBoot::isProductionDeclared() (secrets.php app.environment; TEK karar noktası) |
production |
getAppIsCli() |
RBN_CLI sabiti, yoksa PHP_SAPI === 'cli' |
— |
getAppSessionTimeout() |
RBN_SESSION_TIMEOUT sabiti |
30 (dakika) |
5. Tuzaklar ve kurallar (kodda görülen)
Config::get()bütünlük denetimine uğramaz.get()içeridesetResolving(true)yaptığı içinConfigResolver::guard()hepnulldöner (Config.php:63,ConfigResolver.php:53). Sonuç:database_*dışındaki her adPaths::project()->configs($ad.'.php')yoluna düşer;DatabaseGuardHandler::validateIntegritybu yolda devreye girmez. Guard'ı yalnızConfigResolver::resolve()doğrudan (resolving kapalıyken) çağrılırsa kullanabilirsiniz. (Eskiacik-sorular.md§1.4 — kodla doğrulandı, buraya taşındı.)- Ortam değişkeni okunmaz. Framework ağacında
getenv(/$_ENVokuyucusu yoktur (birim testifw_ortam_tek_kaynak). Ortam bayrağıSecrets::app(). appokuması güvenli tarafa düşer: dosya yok / bölüm yok / alan yok → şema varsayılanı; dosya var ama okunamaz →Secrets::app()fırlatır,PreBootbunu production sayıp loglar.Config::set()0 çağrı. Çalışma anında ayar yazmak fiilen kullanılmıyor.ConfigMapneredeyse kullanılmıyor: tek çağrıCore/Render/Handlers/UI/PanelHandler.php:111(getAppSessionTimeout).- Sır dosyası izin denetimi Windows'ta atlanır (
ConfigFileGuard.php:79); Linux'ta 0600'den geniş izinRuntimeException'dır. Sır dosyasında?>kapanışıreturn'den önceyse reddedilir (aksi halde dosyarequireedilince ekrana basılır). cpanel()anahtarları dönüşür: bölümdehost/user/token, amaSecrets::cpanel()cpanel_host/cpanel_user/cpanel_tokendöndürür (kabul testleriyle sabit,Secrets.php:152).master_db.passvesmtp.passboş olabilir,cpanelveapideğerleri boş olamaz (SecretsSchema::SECTION_RULES,SecretsSections::readAll).- Geriye uyum yok: eski iki ayrı sır dosyası kaldırıldı;
secrets.phpyoksa uygulama açık hata verir, sessizroot/''fallback yoktur. - Sıra:
Secretskernel öncesi çalıştığı için IoC/Paths kullanmaz, komşu dosyalarırequire_onceeder (Secrets.php:17). - Düzeltilen bayat bilgi:
Core/System/Config/README.mdPSR-4 tablosuDatabaseConfig,DbProfileResolver,SmtpProfileResolver'ıEngine/Config/altında gösteriyor; gerçekteEngine/Database/altındadır,ProjectDbProfileResolvertabloda hiç yoktur (§2.4–2.5 doğrusudur). (Eskiacik-sorular.md§1.1.) TENANT_TABLES: tam liste 12 tekil tablo (11 paylaşılanz_*/app_*+ 1 ürün tablosu);asw_*listede yoktur (ProjectDbData.php:138). (Eskiacik-sorular.md§2.2 — kodla doğrulandı.)MasterDbData::REQUIRED_TABLESz_sys_heartbeatssayar (MasterDbData.php:54) amaMasterRbnHeartbeatsModelrbn_heartbeatstablosunu bildirir;Registry'de yalnızmaster.rbnHeartbeatanahtarıyla kayıtlıdır ve ölçüm taramasında çağıran bulunmadı. Gerçek master'da hangisinin var olduğuacik-sorular.md'de duruyor.
Ölçüm: yerel-ortam kararı ile DB profili aynı değil (PHP 8.3, Windows)
PreBoot::isTrustedLocalEnvironment(host, REMOTE_ADDR) ve ProjectDbProfileResolver::activeProfile() aynı süreçte çalıştırıldı:
| Host | REMOTE_ADDR | isTrustedLocalEnvironment |
|---|---|---|
example.tr.test |
127.0.0.1 |
true |
example.tr.test |
203.0.113.9 (doküman IP'si) |
false |
x.test.evil.com |
127.0.0.1 |
false |
localhost:8080 ve [::1] |
::1 |
true |
a.test |
::ffff:10.0.0.5 (IPv4-eşlenmiş) |
true |
A.TEST. |
192.168.1.2 |
true |
| (boş) | 127.0.0.1 |
false |
Aynı süreçte REMOTE_ADDR=203.0.113.9, HTTP_HOST=example.tr.test iken ProjectDbProfileResolver::activeProfile() = local: DB profili istemci adresinden etkilenmez; is_local() ve RBN_DEV etkilenir. Bu, ProjectDbProfileResolver docblock'ındaki tasarım gerekçesini (aynı sunucuda istek kimliğine göre farklı veritabanına bağlanılmaması) kodla doğrular. (Eski acik-sorular.md §2.6 — karar ayrımı yeniden ölçüldü. Docblock'taki "8 dosyada hata" sayısı kabul harness'inin ölçümüdür; harness bu görevin kapsamı dışında olduğundan o sayı yeniden üretilmedi.)
6. Örnek (gerçek koddan)
// Packages/RbnEmail/Handlers/EmailConfigHandler.php:64-65
'enabled' => $useMaster ? SmtpProfileResolver::enabled() : ...,
'host' => $useMaster ? SmtpProfileResolver::host() : ...,
// DB profili: project-settings.php içinde tek dosyada iki profil
'DB_PROFILES' => [
'local' => ['DB_HOST' => …, 'DB_NAME' => …, 'DB_USER' => …, 'DB_PASS' => …, 'DB_CHARSET' => …],
'production' => ['DB_HOST' => …, 'DB_NAME' => …, 'DB_USER' => …, 'DB_PASS' => …, 'DB_CHARSET' => …],
]
// (ProjectDbProfileResolver.php docblock'undan; "…" yerine gerçek değer yazılır, "__DOLDUR__" reddedilir)
7. İlgili belgeler
- Kavram: yapılandırma · Kavram: veritabanı ve kiracılık
- Core/System genel bakış · Kernel (
PreBootEnv/Secrets'ı kullanır) · Discovery (Definition::get,ProjectDataMapper) - Kaynak içi notlar:
Core/System/Config/README.md,Secrets/README.md,Definitions/DbProfiles/README.md - Açık sorular