diff --git a/docs/tr/README.md b/docs/tr/README.md index ad8d345d3f..e2208d1172 100644 --- a/docs/tr/README.md +++ b/docs/tr/README.md @@ -122,27 +122,40 @@ sudo systemctl start frankenphp ## Docs - [Worker modu](worker.md) +- [Classic mod](classic.md) - [Early Hints desteği (103 HTTP durum kodu)](early-hints.md) - [Real-time](mercure.md) +- [Günlük kaydı](logging.md) +- [Büyük statik dosyaları verimli sunma](x-sendfile.md) - [Konfigürasyon](config.md) - [Docker imajları](docker.md) - [Production'a dağıtım](production.md) - [**Bağımsız** kendiliğinden çalıştırılabilir PHP uygulamaları oluşturma](embed.md) - [Statik binary'leri oluşturma](static.md) - [Kaynak dosyalarından derleme](config.md) +- [Gözlemlenebilirlik](observability.md) +- [Metrikler](metrics.md) +- [Nginx/PHP-FPM'den geçiş](migrate.md) +- [Güvenlik modeli](security.md) +- [WordPress entegrasyonu](wordpress.md) +- [Symfony entegrasyonu](symfony.md) - [Laravel entegrasyonu](laravel.md) +- [Yii 3 entegrasyonu](yii3.md) - [Bilinen sorunlar](known-issues.md) - [Demo uygulama (Symfony) ve kıyaslamalar](https://github.com/dunglas/frankenphp-demo) +- [Go kütüphanesi olarak kullanma](library.md) - [Go kütüphane dokümantasonu](https://pkg.go.dev/github.com/dunglas/frankenphp) - [Katkıda bulunma ve hata ayıklama](CONTRIBUTING.md) +- [İç yapı (mimariye genel bakış)](internals.md) ## Örnekler ve iskeletler -- [Symfony](https://github.com/dunglas/symfony-docker) +- [Symfony](symfony.md) - [API Platform](https://api-platform.com/docs/distribution/) - [Laravel](https://frankenphp.dev/docs/laravel/) - [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) - [WordPress](https://github.com/StephenMiracle/frankenwp) +- [Yii 3](yii3.md) - [Drupal](https://github.com/dunglas/frankenphp-drupal) - [Joomla](https://github.com/alexandreelise/frankenphp-joomla) - [TYPO3](https://github.com/ochorocho/franken-typo3) diff --git a/docs/tr/classic.md b/docs/tr/classic.md new file mode 100644 index 0000000000..4abad90d5d --- /dev/null +++ b/docs/tr/classic.md @@ -0,0 +1,11 @@ +# Classic modu kullanma + +Ek bir yapılandırma olmadan FrankenPHP klasik modda çalışır. Bu modda FrankenPHP, PHP dosyalarını doğrudan sunan geleneksel bir PHP sunucusu gibi davranır. Bu da onu PHP-FPM veya Apache + mod_php için kesintisiz bir yerine geçen çözüm haline getirir. + +Caddy'ye benzer şekilde FrankenPHP sınırsız sayıda bağlantı kabul eder ve bunları [sabit sayıda iş parçacığı](config.md#caddyfile-config) ile karşılar. Kabul edilen ve kuyruğa alınan bağlantı sayısı yalnızca mevcut sistem kaynaklarıyla sınırlıdır. +PHP iş parçacığı havuzu, başlangıçta sabit sayıda iş parçacığıyla çalışır; bu, PHP-FPM'nin static moduna benzer. İş parçacıklarının [çalışma zamanında otomatik ölçeklenmesine](performance.md#max_threads) izin vermek de mümkündür; bu da PHP-FPM'nin dynamic moduna benzer. + +Kuyruktaki bağlantılar, bir PHP iş parçacığı müsait olana kadar süresiz bekler. Bunu önlemek için FrankenPHP'nin genel yapılandırmasındaki max_wait_time [ayarını](config.md#caddyfile-config) kullanarak, bir isteğin boş bir PHP iş parçacığı için reddedilmeden önce ne kadar bekleyebileceğini sınırlayabilirsiniz. +Ayrıca Caddy'de makul bir [yazma zaman aşımı](https://caddyserver.com/docs/caddyfile/options#timeouts) ayarlayabilirsiniz. + +Her Caddy örneği yalnızca bir FrankenPHP iş parçacığı havuzu başlatır; bu havuz tüm `php_server` blokları arasında paylaşılır. diff --git a/docs/tr/internals.md b/docs/tr/internals.md new file mode 100644 index 0000000000..7a096a2038 --- /dev/null +++ b/docs/tr/internals.md @@ -0,0 +1,250 @@ +# İç yapı + +Bu belge FrankenPHP'nin iç mimarisini açıklar; odak noktası iş parçacığı yönetimi, durum makinesi ve Go ile C/PHP arasındaki CGO sınırıdır. + +## FrankenPHP mimarisine genel bakış + +FrankenPHP, PHP yorumlayıcısını CGO aracılığıyla doğrudan Go'ya gömer. Her PHP yürütmesi gerçek bir POSIX iş parçacığında çalışır (goroutine değil); çünkü PHP'nin ZTS (Zend Thread Safety) modeli bunu gerektirir. Go bu iş parçacıklarını bir durum makinesi üzerinden yönetir; C ise PHP SAPI yaşam döngüsünü üstlenir. + +Ana katmanlar şunlardır: + +1. **Go katmanı** (`frankenphp.go`, `phpthread.go`, `thread*.go`, `scaling.go` gibi üst düzey `*.go` dosyaları): İş parçacığı havuzu yönetimi, istek yönlendirme, otomatik ölçekleme +2. **C katmanı** (`frankenphp.c`, `frankenphp.h`): PHP SAPI uygulaması, betik yürütme döngüsü, süper küresel yönetimi +3. **Durum makinesi** (`internal/state/`): Go goroutine'leri ile C iş parçacıkları arasında eşzamanlama + +## FrankenPHP iş parçacığı türleri + +### Ana iş parçacığı (`phpmainthread.go`) + +Ana PHP iş parçacığı (`phpMainThread`) PHP çalışma zamanını başlatır: + +1. `php.ini` geçersiz kılmalarını uygular +2. Sanal alan için ortamın bir anlık görüntüsünü (`main_thread_env`) alır +3. PHP SAPI modülünü başlatır +4. Go tarafına hazır olduğunu bildirir + +Sunucunun ömrü boyunca hayatta kalır. Diğer tüm iş parçacıkları o `Ready` sinyalini verdikten sonra başlatılır. + +### Düzenli iş parçacıkları (`threadregular.go`) + +Klasik, çağrı başına bir istek PHP betiklerini işler. Her istek: + +1. `requestChan` veya paylaşılan `regularRequestChan` üzerinden bir istek alır +2. `beforeScriptExecution()` ile betik dosya adını döndürür +3. C katmanı PHP betiğini yürütür +4. `afterScriptExecution()` istek bağlamını kapatır + +### Worker iş parçacıkları (`threadworker.go`) + +Bir PHP betiğini birden fazla istek boyunca canlı tutar. PHP betiği bir döngüde `frankenphp_handle_request()` çağırır: + +1. `beforeScriptExecution()` worker betik dosya adını döndürür +2. C katmanı PHP betiğini yürütmeye başlar +3. PHP betiği `frankenphp_handle_request()` çağırır; bu da Go'da `waitForWorkerRequest()` çağırır +4. Go bir istek gelene kadar bekler, ardından istek bağlamını kurar +5. PHP geri çağrısı isteği işler +6. `go_frankenphp_finish_worker_request()` istek bağlamını temizler +7. PHP betiği 3. adıma döner + +Betik çıktıktan sonra, worker en az bir kez `frankenphp_handle_request()`'e ulaşmışsa (çıkış temiz olsa da ölümcül bir hatanın sonucu olsa da) hemen yeniden başlatılır. Üstel geri çekme yalnızca ardışık başlatma hatalarına uygulanır; burada betik `frankenphp_handle_request()`'e hiç ulaşmadan çıkar. + +## FrankenPHP iş parçacığı durum makinesi + +Her iş parçacığının yaşam döngüsünü yöneten bir `ThreadState`'i vardır (`internal/state/state.go` içinde tanımlanır). Durum makinesi tüm durum geçişleri için bir `sync.RWMutex` ve engelleyen beklemeler için kanal tabanlı bir abone kalıbı kullanır. + +### FrankenPHP iş parçacığı durumları + +```text +Lifecycle: Reserved → BootRequested → Booting → Inactive → Ready ⇄ (processing) + ↓ +Shutdown: ShuttingDown → Done → Reserved + ↑ +Restart (admin/watcher): Restarting → Yielding → Ready + ↑ +ZTS reboot (max_requests): Rebooting → RebootReady → Ready + ↑ +Handler transition: TransitionRequested → TransitionInProgress → TransitionComplete +``` + +Durumların tam kümesi `internal/state/state.go` içinde tanımlanır: + +| Durum | Açıklama | +| ---------------------- | ------------------------------------------------------------------------------------------------- | +| `Reserved` | İş parçacığı yuvası ayrılmıştır ancak henüz başlatılmamıştır. İstek üzerine başlatılabilir. | +| `BootRequested` | Başlatma kuyruğa alınmıştır (ör. ana iş parçacığı tarafından) ancak POSIX iş parçacığı henüz başlamamıştır. | +| `Booting` | Alttaki POSIX iş parçacığı başlıyordur. | +| `Inactive` | İş parçacığı canlıdır ancak atanmış bir işleyicisi yoktur. Bellek ayak izi küçüktür. | +| `Ready` | İş parçacığının bir işleyicisi vardır ve iş kabul etmeye hazırdır. | +| `ShuttingDown` | İş parçacığı kapanıyordur. | +| `Done` | İş parçacığı tamamen kapanmıştır. Olası yeniden kullanım için `Reserved`'a döner. | +| `Restarting` | Worker iş parçacığı yeniden başlatılıyordur (ör. admin API veya dosya izleyici aracılığıyla). | +| `Yielding` | Worker iş parçacığı denetimi bırakmıştır ve yeniden etkinleştirilmeyi bekliyordur. | +| `Rebooting` | Worker iş parçacığı tam bir ZTS yeniden başlatması için C döngüsünden çıkıyordur (ör. `max_requests`). | +| `RebootReady` | C iş parçacığı çıkmıştır ve ZTS durumu temizlenmiştir; yeni bir C iş parçacığı doğurmaya hazırdır. | +| `TransitionRequested` | Go tarafından bir işleyici değişikliği istenmiştir. | +| `TransitionInProgress` | C iş parçacığı geçiş isteğini kabul etmiştir. | +| `TransitionComplete` | Go tarafı yeni işleyiciyi kurmuştur. | + +### Temel durum makinesi işlemleri + +**`RequestSafeStateChange(nextState)`**: Dış goroutine'lerin durum değişikliği istemesinin birincil yoludur. Şunları yapar: + +- `Ready` veya `Inactive`'ten atomik olarak başarılı olur (mutex altında) +- `ShuttingDown`, `Done` veya `Reserved`'tan hemen `false` döndürür +- Diğer herhangi bir durumdan `Ready`, `Inactive` veya `ShuttingDown` bekleyerek engeller ve yeniden dener + +Bu karşılıklı dışlamayı güvence altına alır: belirli bir iş parçacığında aynı anda `shutdown()`, `setHandler()` veya `drainWorkerThreads()`'ten yalnızca biri başarılı olabilir. + +**`WaitFor(states...)`**: İş parçacığı belirtilen durumlardan birine ulaşana kadar engeller. Bekleyenlerin verimli bildirilmesi için kanal tabanlı bir abone kalıbı kullanır. + +**`Set(nextState)`**: Koşulsuz durum değişikliği. İş parçacığının kendisi (C geri çağrılarından) durum geçişlerini bildirmek için kullanır. + +**`CompareAndSwap(compareTo, swapTo)`**: Atomik karşılaştır-ve-değiştir. Başlatma ilklendirmesi için kullanılır. + +### İşleyici geçiş protokolü + +Bir iş parçacığının işleyicisini değiştirmesi gerektiğinde (ör. inactive'den worker'a): + +```text +Go side (setHandler) C side (PHP thread) +───────────────── ───────────────── +RequestSafeStateChange( + TransitionRequested) +close(drainChan) + detects drain + Set(TransitionInProgress) +WaitFor(TransitionInProgress) + → unblocked WaitFor(TransitionComplete) +handler = newHandler +drainChan = make(chan struct{}) +Set(TransitionComplete) + → unblocked + newHandler.beforeScriptExecution() +``` + +Bu protokol, işleyici işaretçisinin asla eşzamanlı okunup yazılmamasını sağlar. + +### Worker yeniden başlatma protokolü + +Worker'lar yeniden başlatıldığında (ör. admin API aracılığıyla): + +```text +Go side (RestartWorkers) C side (worker thread) +───────────────── ───────────────── +RequestSafeStateChange( + Restarting) +close(drainChan) + detects drain in waitForWorkerRequest() + returns false → PHP script exits + beforeScriptExecution(): + state is Restarting → + Set(Yielding) +WaitFor(Yielding) + → unblocked WaitFor(Ready, ShuttingDown) +drainChan = make(chan struct{}) +Set(Ready) + → unblocked + beforeScriptExecution() recurse: + state is Ready → normal execution +``` + +## Go ile PHP arasındaki CGO sınırı + +### Dışa aktarılan Go işlevleri + +C kodu CGO dışa aktarımları üzerinden Go işlevlerini çağırır. Ana geri çağrılar şunlardır: + +| İşlev | Ne zaman çağrılır | +| ------------------------------------------- | -------------------------------------------------------- | +| `go_frankenphp_before_script_execution` | C döngüsü yürütülecek sonraki betiğe ihtiyaç duyduğunda | +| `go_frankenphp_after_script_execution` | PHP betiği yürütmeyi bitirdiğinde | +| `go_frankenphp_worker_handle_request_start` | Worker'ın `frankenphp_handle_request()`'i çağrıldığında | +| `go_frankenphp_finish_worker_request` | Worker istek işleyicisi döndüğünde | +| `go_ub_write` | PHP çıktı ürettiğinde (`echo` vb.) | +| `go_read_post` | PHP POST gövdesini okuduğunda (`php://input`) | +| `go_read_cookies` | PHP çerezleri okuduğunda | +| `go_write_headers` | PHP yanıt başlıklarını gönderdiğinde | +| `go_sapi_flush` | PHP çıktıyı boşalttığında | +| `go_log_attrs` | PHP yapılandırılmış bir mesaj kaydettiğinde | + +Tüm bu işlevler çağıran iş parçacığını tanımlayan bir `threadIndex` parametresi alır. Bu, iş parçacığı başlatılırken ayarlanan C'deki iş parçacığı yerel bir değişkendir (`__thread uintptr_t thread_index`). + +### C iş parçacığı ana döngüsü + +Her PHP iş parçacığı `frankenphp.c` içinde `php_thread()` çalıştırır: + +```c +// frankenphp.c: php_thread() ana betik yürütme döngüsü +while ((scriptName = go_frankenphp_before_script_execution(thread_index))) { + php_request_startup(); + php_execute_script(&file_handle); + php_request_shutdown(); + go_frankenphp_after_script_execution(thread_index, exit_status); +} +``` + +Bailout'lar (ölümcül PHP hataları) `zend_catch` tarafından yakalanır; bu, iş parçacığını sağlıksız olarak işaretler ve temizliği zorlar. + +### CGO sınırı boyunca bellek yönetimi + +- **Go → C dizeleri**: `C.CString()` `malloc()` ile ayırır. Serbest bırakmak C tarafının sorumluluğundadır (ör. `frankenphp_free_request_context()` çerez verisini serbest bırakır). +- **Go dize sabitleme**: `phpThread` (`phpthread.go` içinde) Go'nun [`runtime.Pinner`](https://pkg.go.dev/runtime#Pinner)'ını gömer. `thread.Pin()` / `thread.Unpin()` C'den başvurulan Go belleğini kopyalamadan canlı tutar. İş parçacığı her betik yürütmesinden sonra serbest bırakılır. +- **PHP belleği**: Zend bellek yöneticisi (`emalloc`/`efree`) tarafından yönetilir. İstek kapanışında otomatik serbest bırakılır. + +## FrankenPHP iş parçacığı otomatik ölçeklemesi + +FrankenPHP, talebe göre PHP iş parçacığı sayısını otomatik ölçekleyebilir (`scaling.go`). + +### Otomatik ölçekleme yapılandırması + +- `num_threads`: Açılışta başlatılan başlangıç iş parçacığı sayısı +- `max_threads`: İzin verilen en fazla iş parçacığı sayısı (otomatik ölçeklenenler dahil) + +### Yukarı ölçekleme + +Ayrılmış bir goroutine tamponlanmamış bir `scaleChan`'den okur: + +1. Bir istek işleyicisi müsait bir iş parçacığı bulamaz +2. İstek bağlamını `scaleChan`'e gönderir +3. Ölçekleme goroutine'i şunları kontrol eder: + - İstek yeterince uzun süre takılı kaldı mı? (en az 5 ms) + - CPU kullanımı eşiğin altında mı? (%80) + - İş parçacığı sınırına ulaşıldı mı? +4. Tüm kontroller geçerse yeni bir iş parçacığı başlatılır ve atanır + +### Aşağı ölçekleme + +Ayrı bir goroutine periyodik olarak (her 5 sn) boştaki otomatik ölçeklenmiş iş parçacıklarını kontrol eder. `Ready` durumunda `maxIdleTime`'dan (varsayılan 5 sn) daha uzun süre boşta kalan iş parçacıkları `Inactive`'e dönüştürülür (döngü başına en fazla 10). Tamamen durdurulmazlar: bunun için bir kod yolu vardır ancak şu anda devre dışıdır; çünkü bazı PECL eklentileri bellek sızdırır ve iş parçacıklarının temiz kapanmasını engeller. + +## İş parçacığı başına ortam sanal alanı + +FrankenPHP ortam değişkenlerini iş parçacığı başına sanal alana alır: + +1. Başlangıçta ana iş parçacığı `os.Environ()`'u `main_thread_env` (bir PHP `HashTable`) içine anlık görüntüler. +2. `$_SERVER`, `main_thread_env`'in bir kopyası artı isteğe özgü değişkenlerden oluşturulur (`frankenphp_register_server_vars` içinde). Her istek için, worker betiğinin her yinelemesi dahil, yeniden kurulur. +3. `$_ENV` aynı anlık görüntüden PHP'nin `php_import_environment_variables` kancası aracılığıyla doldurulur. Düzenli modda bu her betik yürütmesinde bir kez olur; worker modunda worker betiği başladığında bir kez olur ve worker istekleri arasında **yeniden kurulmaz**; bu yüzden `$_ENV` yazmaları istekler arasında sızar (bkz. [Worker modu](worker.md)). +4. `frankenphp_putenv()` / `frankenphp_getenv()` `main_thread_env`'den tembel başlatılan iş parçacığı yerel `sandboxed_env` üzerinde çalışır; global C ortamındaki yarış koşullarını önler. +5. `reset_sandboxed_environment()` her PHP betik yürütmesinden sonra `sandboxed_env`'i serbest bırakır. Düzenli modda bu istek başınadır; worker modunda yalnızca worker betiğinin kendisi çıktığında çalışır, bu yüzden `putenv()` yazmaları betik yeniden başlayana kadar aynı iş parçacığındaki sonraki worker isteklerinde görünür. + +## İstek akışı (düzenli mod) + +1. HTTP isteği Caddy'ye gelir +2. FrankenPHP'nin Caddy modülü PHP betik yolunu çözer +3. İstek ve betik bilgisiyle bir `frankenPHPContext` oluşturulur +4. Bağlam `requestChan` üzerinden müsait bir düzenli iş parçacığına gönderilir +5. İş parçacığının `beforeScriptExecution()`'ı betik dosya adını döndürür +6. C katmanı PHP betiğini yürütür +7. Yürütme sırasında Go geri çağrıları G/Ç'yi işler (`go_ub_write`, `go_read_post` vb.) +8. Yürütmeden sonra `afterScriptExecution()` tamamlanmayı bildirir +9. Yanıt istemciye gönderilir + +## İstek akışı (worker modu) + +1. HTTP isteği Caddy'ye gelir +2. FrankenPHP'nin Caddy modülü bu istek için worker'ı çözer +3. Bir `frankenPHPContext` oluşturulur +4. Bağlam worker'ın `requestChan`'ine veya belirli bir iş parçacığının `requestChan`'ine gönderilir +5. Worker iş parçacığının `waitForWorkerRequest()`'i onu alır +6. PHP'nin `frankenphp_handle_request()` geri çağrısı tetiklenir +7. Geri çağrı döndükten sonra `go_frankenphp_finish_worker_request()` temizler +8. Worker `waitForWorkerRequest()`'e döner diff --git a/docs/tr/library.md b/docs/tr/library.md new file mode 100644 index 0000000000..7cf10267c7 --- /dev/null +++ b/docs/tr/library.md @@ -0,0 +1,64 @@ +# FrankenPHP'yi bir Go kütüphanesi olarak kullanma + +FrankenPHP yalnızca bir Caddy modülü değildir: PHP betiklerini `net/http` ile çalıştırmak için herhangi bir Go programına kütüphane olarak gömülebilir. + +Derleme gereksinimleri [FrankenPHP'yi kaynaktan derlemek](compile.md) ile aynıdır: embed SAPI ve ZTS etkin bir PHP ve eşleşen CGO bayrakları. + +## Başlarken + +Bir `Server` oluşturun, FrankenPHP'yi başlatırken kaydedin ve bir `http.Handler` olarak kullanın: + +Minimal bir örnek için [https://pkg.go.dev](https://pkg.go.dev/github.com/dunglas/frankenphp#example-ServeHTTP) adresine bakın. + +`NewServer()`; worker'ları, metrikleri ve günlükleri bu sunucuya atamak için kullanılan insan tarafından okunabilir bir ad (boşsa kayıtta `server_` olur), belge kökü, yol ayırma sonekleri (varsayılan `[".php"]`), her isteğe sunulan ortam değişkenleri ve bir `*slog.Logger` (varsayılan olarak global logger) alır. + +`Init()` PHP çalışma zamanını başlatır ve istek sunulmadan önce tam olarak bir kez çağrılmalıdır; `Shutdown()` onu durdurur. `Init()` öncesi veya `Shutdown()` sonrası `Server.ServeHTTP()` çağrısı `ErrNotRunning` döndürür. Aynı `*Server`, örneğin yapılandırmayı yeniden yüklemek için, bir `Shutdown()` sonrasında yeniden `Init()`'e geçilebilir. + +## Birden fazla sunucu + +Birden fazla sunucu aynı anda kaydedilebilir; her birinin kendi belge kökü, ortamı ve logger'ı vardır. Bu, Caddyfile'daki birden fazla `php_server` bloğunun yaptığını yansıtır: + +```go +// Ayrı belge köklerine sahip iki sunucu kaydetme +api, _ := frankenphp.NewServer("api/public/") +admin, _ := frankenphp.NewServer("admin/public/") + +err := frankenphp.Init( + frankenphp.WithServer(api), + frankenphp.WithServer(admin), +) +``` + +`api.ServeHTTP()` üzerinden sunulan istekler yalnızca o sunucunun yapılandırmasını (ve aşağıda görüleceği gibi worker'larını) görür. + +## Worker'lar + +[Worker betikleri](worker.md) `WithWorkers()` ile bildirilir. Bir worker `WithWorkerServerScope()` ile bir sunucuya kapsamlandırılabilir: yalnızca bu sunucu örneğinin işlediği istekler worker'a ulaşır. İstekler betik yoluna veya `WithWorkerMatcher()` ile kaydedilen özel bir eşleştiriciye göre eşleştirilir: + +```go +// Worker'ları bir sunucuya kapsamlandırma +server, _ := frankenphp.NewServer("public/") + +err := frankenphp.Init( + frankenphp.WithServer(server), + frankenphp.WithWorkers("app", "public/index.php", 4, + frankenphp.WithWorkerServerScope(server), + ), + frankenphp.WithWorkers("api", "public/api.php", 2, + frankenphp.WithWorkerServerScope(server), + frankenphp.WithWorkerMatcher(func(r *http.Request) bool { + return strings.HasPrefix(r.URL.Path, "/api/") + }), + ), +) +``` + +Sunucu kapsamı olmadan bildirilen worker'lar globaldir: herhangi bir sunucuda dosya yoluna göre eşleşirler. Global bir worker'ın eşleştireceği belirli bir istek kümesi olmadığından `WithWorkerMatcher()` ile global bir worker'ı birleştirmek bir yapılandırma hatasıdır ve `Init()` bunu reddeder. + +## İstek başına seçenekler + +`Server.ServeHTTP()`, tek bir istek için sunucu yapılandırmasını geçersiz kılmak üzere `RequestOption`'lar kabul eder; örn. `WithRequestDocumentRoot()`, `WithRequestSplitPath()`, `WithRequestEnv()` veya `WithRequestLogger()`. + +## Server öncesi API ile uyumluluk + +Paket düzeyindeki `frankenphp.ServeHTTP()` işlevi herhangi bir sunucu kaydetmeden çalışmaya devam eder: `frankenphp.NewRequestWithContext()` ile hazırlanan istekler, global yapılandırmayı taşıyan dahili bir yedek sunucuda yürütülür. Yeni kod açık `Server` örneklerini tercih etmelidir. diff --git a/docs/tr/logging.md b/docs/tr/logging.md new file mode 100644 index 0000000000..5e5da4f61e --- /dev/null +++ b/docs/tr/logging.md @@ -0,0 +1,74 @@ +# Günlük kaydı + +> [!TIP] +> Günlük kaydı, FrankenPHP'nin gözlemlenebilirlik öyküsünün bir parçasıdır. Gerçek zamanlı izleme ve metrikler dahil tam tablo için [Gözlemlenebilirlik](observability.md) sayfasına bakın. + +FrankenPHP, [Caddy'nin günlük sistemiyle](https://caddyserver.com/docs/logging) sorunsuz entegre olur. +Standart PHP işlevleriyle mesaj kaydedebilir veya gelişmiş yapılandırılmış günlük yetenekleri için özel `frankenphp_log()` işlevini kullanabilirsiniz. + +## `frankenphp_log()` + +`frankenphp_log()` işlevi, yapılandırılmış günlükleri doğrudan PHP uygulamanızdan üretmenizi sağlar; +bu da Datadog, Grafana Loki veya Elastic gibi platformlara aktarımı ve OpenTelemetry desteğini kolaylaştırır. + +Perde arkasında `frankenphp_log()`, zengin günlük özellikleri sunmak için [Go'nun `log/slog` paketini](https://pkg.go.dev/log/slog) sarmalar. + +Bu günlükler şiddet düzeyini ve isteğe bağlı bağlam verisini içerir. + +```php +function frankenphp_log(string $message, int $level = FRANKENPHP_LOG_LEVEL_INFO, array $context = []): void +``` + +### Parametreler + +- **`message`**: Günlük mesajı dizesi. +- **`level`**: Günlüğün şiddet düzeyi. Herhangi bir tamsayı olabilir. Yaygın düzeyler için kolaylık sabitleri sağlanır: `FRANKENPHP_LOG_LEVEL_DEBUG` (`-4`), `FRANKENPHP_LOG_LEVEL_INFO` (`0`), `FRANKENPHP_LOG_LEVEL_WARN` (`4`) ve `FRANKENPHP_LOG_LEVEL_ERROR` (`8`). Varsayılan `FRANKENPHP_LOG_LEVEL_INFO`'dur. +- **`context`**: Günlük kaydına eklenecek ek verilerin ilişkisel dizisi. + +### Örnek + +```php + memory_get_usage(), + 'peak_usage' => memory_get_peak_usage(), + ], +); + +``` + +Günlükler görüntülendiğinde (ör. `docker compose logs` ile) çıktı yapılandırılmış JSON olarak görünür: + +```json +{"level":"info","ts":1704067200,"logger":"frankenphp","msg":"Hello from FrankenPHP!"} +{"level":"warn","ts":1704067200,"logger":"frankenphp","msg":"Memory usage high","current_usage":10485760,"peak_usage":12582912} +``` + +## `error_log()` + +FrankenPHP, standart `error_log()` işleviyle günlük kaydına da izin verir. `$message_type` parametresi `4` (SAPI) ise +bu mesajlar Caddy logger'ına yönlendirilir. + +Varsayılan olarak `error_log()` ile gönderilen mesajlar yapılandırılmamış metin olarak işlenir. +Standart PHP kütüphanesine dayanan mevcut uygulamalar veya kütüphanelerle uyumluluk için kullanışlıdır. + +### error_log() örneği + +```php +error_log("Database connection failed", 4); +``` + +Bu, Caddy günlüklerinde görünür; çoğu zaman PHP'den geldiğini belirten bir önekle. + +> [!TIP] +> Üretim ortamlarında daha iyi gözlemlenebilirlik için `frankenphp_log()` tercih edin; +> çünkü günlükleri düzeye göre (Debug, Error vb.) süzmenize +> ve günlük altyapınızda belirli alanları sorgulamanıza olanak tanır. diff --git a/docs/tr/metrics.md b/docs/tr/metrics.md new file mode 100644 index 0000000000..b1b1f133a3 --- /dev/null +++ b/docs/tr/metrics.md @@ -0,0 +1,78 @@ +# Metrikler + +> [!TIP] +> Gerçek zamanlı panolar ve üretim izlemesi dahil eksiksiz bir gözlemlenebilirlik kurulumu için [Gözlemlenebilirlik](observability.md) sayfasına bakın. + +## Prometheus dışa aktarımı + +[Caddy metrikleri](https://caddyserver.com/docs/metrics) etkinleştirildiğinde FrankenPHP şu metrikleri yayınlar: + +- `frankenphp_total_threads`: Toplam PHP iş parçacığı sayısı. +- `frankenphp_busy_threads`: Şu anda bir isteği işleyen PHP iş parçacığı sayısı (çalışan worker'lar her zaman bir iş parçacığı tüketir). +- `frankenphp_queue_depth`: Kuyruğa alınmış olağan istek sayısı. +- `frankenphp_total_workers{worker="[worker_name]"}`: Toplam worker sayısı. +- `frankenphp_busy_workers{worker="[worker_name]"}`: Şu anda bir isteği işleyen worker sayısı. +- `frankenphp_worker_request_time{worker="[worker_name]"}`: Tüm worker'ların istekleri işlemek için harcadığı süre. +- `frankenphp_worker_request_count{worker="[worker_name]"}`: Tüm worker'ların işlediği istek sayısı. +- `frankenphp_ready_workers{worker="[worker_name]"}`: En az bir kez `frankenphp_handle_request` çağırmış worker sayısı. +- `frankenphp_worker_crashes{worker="[worker_name]"}`: Bir worker'ın beklenmedik şekilde sonlandığı sayı. +- `frankenphp_worker_restarts{worker="[worker_name]"}`: Bir worker'ın bilinçli olarak yeniden başlatıldığı sayı. +- `frankenphp_worker_queue_depth{worker="[worker_name]"}`: Kuyruğa alınmış istek sayısı. + +Worker metriklerinde `[worker_name]` yer tutucusu Caddyfile'daki worker adıyla değiştirilir; aksi halde worker dosyasının mutlak yolu kullanılır. + +## İş parçacığı durumu uç noktası + +FrankenPHP, [Caddy admin API](https://caddyserver.com/docs/api) üzerinden bir `/frankenphp/threads` uç noktası yayınlar. +Tüm etkin PHP iş parçacıklarının JSON anlık görüntüsünü döndürür; hata ayıklama ve gözlemlenebilirlik araçları oluşturmak için kullanışlıdır. + +```console +curl -s http://localhost:2019/frankenphp/threads | jq . +``` + +### Yanıt biçimi + +Uç nokta şu yapıda bir JSON nesnesi döndürür: + +```json +{ + "ThreadDebugStates": [ + { + "Index": 0, + "Name": "worker-/path/to/worker.php", + "State": "ready", + "IsWaiting": true, + "IsBusy": false, + "WaitingSinceMilliseconds": 1234, + "CurrentURI": "", + "CurrentMethod": "", + "RequestStartedAt": 0, + "RequestCount": 42, + "MemoryUsage": 2097152 + } + ], + "ReservedThreadCount": 3 +} +``` + +### Alanlar + +| Alan | Tür | Açıklama | +|---|---|---| +| `ReservedThreadCount` | integer | Otomatik ölçekleme için ayrılmış, henüz etkin olmayan iş parçacığı sayısı. | + +`ThreadDebugStates` içindeki her girdi şunları içerir: + +| Alan | Tür | Açıklama | +|---|---|---| +| `Index` | integer | İş parçacığının indisi. | +| `Name` | string | İş parçacığının adı (ör. worker dosya yolu). | +| `State` | string | İş parçacığının iç durumu (ör. `ready`, `shutting down`). | +| `IsWaiting` | boolean | İş parçacığının bir istek bekleyip beklemediği. | +| `IsBusy` | boolean | İş parçacığının şu anda bir isteği işleyip işlemediği. | +| `WaitingSinceMilliseconds` | integer | İş parçacığının milisaniye cinsinden ne kadar süredir boşta olduğu. İş parçacığı meşgulse `0`. | +| `CurrentURI` | string | Şu anda işlenen URI. İş parçacığı boştaysa boş. | +| `CurrentMethod` | string | Geçerli isteğin HTTP metodu (ör. `GET`, `POST`). İş parçacığı boştaysa boş. | +| `RequestStartedAt` | integer | Geçerli isteğin başladığı Unix zaman damgası (milisaniye). İş parçacığı boştaysa `0`. | +| `RequestCount` | integer | Bu iş parçacığının başladığından beri işlediği toplam istek sayısı. | +| `MemoryUsage` | integer | İş parçacığının geçerli PHP bellek kullanımı, bayt cinsinden. | diff --git a/docs/tr/migrate.md b/docs/tr/migrate.md new file mode 100644 index 0000000000..f4b25cccf4 --- /dev/null +++ b/docs/tr/migrate.md @@ -0,0 +1,197 @@ +# Nginx/PHP-FPM'den geçiş + +FrankenPHP hem web sunucunuzu (Nginx, Apache) hem PHP-FPM'i tek bir ikili dosyayla değiştirir. +Bu kılavuz tipik bir PHP uygulaması için temel geçişi kapsar. + +## Temel farklar + +| PHP-FPM kurulumu | FrankenPHP karşılığı | +| --------------------------------- | -------------------------------------------------------- | +| Nginx/Apache + PHP-FPM | Tek `frankenphp` ikili dosyası | +| `php-fpm.conf` havuz ayarları | [`frankenphp` genel seçeneği](config.md#caddyfile-config) | +| Nginx `server {}` bloğu | `Caddyfile` site bloğu | +| `php_value` / `php_admin_value` | [`php_ini` Caddyfile yönergesi](config.md#php-config) | +| `pm = static` / `pm.max_children` | `num_threads` | +| `pm = dynamic` | [`max_threads auto`](performance.md#max_threads) | +| Web sunucusu istek süzme | Caddy route'ları ve eşleştiriciler | + +## HTTP istek süzme + +Stok bir Nginx veya Apache paketinden geçiş yaparken, PHP-FPM isteği almadan önce web sunucusunun uyguladığı istek süzmeyi kontrol edin. +FrankenPHP Caddy üzerine kuruludur; geçerli HTTP metodları ve başlıkları, `Caddyfile`'ınız veya başka bir vekil onları önce reddetmedikçe Caddy'nin olağan yönlendirmesinden geçer. + +Örneğin bazı web sunucuları `TRACE` isteklerini varsayılan olarak reddeder. +Uygulamanız bu davranışı korumalıysa `php_server` öncesine açık bir eşleştirici ekleyin: + +```caddyfile +example.com { + @trace method TRACE + respond @trace 405 + + root /var/www/app/public + php_server +} +``` + +Önceki web sunucunuzun uyguladığı daha katı metod veya başlık politikalarına aynı yaklaşımı uygulayın. +Aynı durum istek başlık adları için de geçerlidir: bazı web sunucuları veya vekiller geçerli ama alışılmadık HTTP alan adlarını PHP-FPM görmeden reddeder veya düşürür; FrankenPHP ise bunları PHP uygulamasına geçirebilir. + +## 1. adım: web sunucusu yapılandırmasını değiştirin + +Tipik bir Nginx + PHP-FPM yapılandırması: + +```nginx +# /etc/nginx/sites-available/example.com +server { + listen 80; + server_name example.com; + root /var/www/app/public; + index index.php; + + location / { + try_files $uri $uri/ /index.php$is_args$args; + } + + location ~ \.php$ { + fastcgi_pass unix:/run/php/php-fpm.sock; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } +} +``` + +Tek bir `Caddyfile` olur: + +```caddyfile +example.com { + root /var/www/app/public + php_server +} +``` + +Bu kadar. `php_server` yönergesi PHP yönlendirmesini, `try_files` benzeri davranışı ve statik dosya sunumunu halleder. + +## 2. adım: PHP yapılandırmasını taşıyın + +Mevcut `php.ini` dosyanız olduğu gibi çalışır. Kurulum yöntemine göre nereye koyacağınız için [Konfigürasyon](config.md) belgesine bakın. + +Yönergeleri doğrudan `Caddyfile` içinde de ayarlayabilirsiniz: + +```caddyfile +{ + frankenphp { + php_ini memory_limit 256M + php_ini max_execution_time 30 + } +} + +example.com { + root /var/www/app/public + php_server +} +``` + +## 3. adım: havuz boyutunu ayarlayın + +PHP-FPM'de worker süreç sayısını denetlemek için `pm.max_children` ayarlanır. +FrankenPHP'de karşılığı `num_threads`'tir: + +```caddyfile +{ + frankenphp { + num_threads 16 + } +} +``` + +Varsayılan olarak FrankenPHP CPU başına 2 iş parçacığı başlatır. PHP-FPM'nin `pm = dynamic` ayarına benzer dinamik ölçekleme için: + +```caddyfile +{ + frankenphp { + num_threads 4 + max_threads auto + } +} +``` + +## 4. adım: Docker geçişi + +Tipik bir PHP-FPM Docker kurulumu (Nginx + PHP-FPM, iki konteyner) tek bir konteynerle değiştirilebilir: + +**Önce:** + +```yaml +# compose.yaml +services: + nginx: + image: nginx:1 + volumes: + # Nginx yapılandırmasını konteynere bağlayın + - ./config:/etc/nginx/conf.d + - .:/var/www/app + ports: + - "80:80" + - "443:443" + + php: + image: php:8.5-fpm + volumes: + - .:/var/www/app +``` + +**Sonra:** + +```yaml +# compose.yaml +services: + php: + image: dunglas/frankenphp:1-php8.5 + volumes: + - .:/var/www/app + # Caddyfile'ı konteynere bağlayın + - ./config:/etc/frankenphp + - caddy_data:/data + - caddy_config:/config + ports: + - "80:80" + - "443:443" + - "443:443/udp" + +volumes: + caddy_data: + caddy_config: +``` + +Ek PHP eklentilerine ihtiyacınız varsa [özel Docker imajı oluşturma](docker.md#how-to-install-more-php-extensions) belgesine bakın. + +Çerçeveye özel Docker kurulumları için [Symfony Docker](https://github.com/dunglas/symfony-docker) ve [Laravel'i FrankenPHP Docker imajıyla çalıştırma](laravel.md#running-laravel-with-the-frankenphp-docker-image) belgelerine bakın. + +## 5. adım: worker modunu değerlendirin (isteğe bağlı) + +[Klasik modda](classic.md) FrankenPHP PHP-FPM gibi çalışır: her istek uygulamayı sıfırdan başlatır. Geçiş için güvenli bir başlangıç noktasıdır. + +Daha iyi performans için [worker moduna](worker.md) geçebilirsiniz; bu mod uygulamayı bir kez başlatır ve bellekte tutar: + +```caddyfile +example.com { + root /var/www/app/public + php_server { + root /var/www/app/public + worker index.php 4 + } +} +``` + +> [!CAUTION] +> +> Worker modu uygulamanızı istekler arasında bellekte tutar. Kodunuzun istekler arasında global durumun sıfırlanmasına dayanmadığından emin olun. [Symfony](worker.md#worker-mode-for-symfony), [Laravel](laravel.md#laravel-octane) ve [API Platform](https://api-platform.com) gibi çerçeveler bu modu yerel olarak destekler. + +## Neleri kaldırabilirsiniz + +Geçişten sonra şunlara artık ihtiyacınız yoktur: + +- Nginx veya Apache +- PHP-FPM (`php-fpm` servisi/süreci) +- FastCGI yapılandırması +- Kendi yönettiğiniz TLS sertifikaları (Caddy bunları otomatik halleder) diff --git a/docs/tr/observability.md b/docs/tr/observability.md new file mode 100644 index 0000000000..bcc197a7a8 --- /dev/null +++ b/docs/tr/observability.md @@ -0,0 +1,35 @@ +# Gözlemlenebilirlik + +FrankenPHP yerleşik gözlemlenebilirlik özellikleri sunar: [Prometheus uyumlu metrikler](metrics.md) ve [yapılandırılmış günlük kaydı](logging.md). +Bu özellikler, aşağıda önerilen araçlarla birlikte, PHP uygulamanızın geliştirme ve üretimdeki davranışına tam görünürlük sağlar. + +## Ember TUI ve Prometheus dışa aktarıcı + +[Ember](https://github.com/alexandre-daubois/ember), FrankenPHP'yi izlemenin en kullanıcı dostu yoludur. + +Caddy'nin admin API'sine bağlanır ve FrankenPHP ile derinlemesine entegre olur; sıfır yapılandırma ve harici altyapı olmadan gerçek zamanlı görünürlük sağlar. + +Hem geliştirmede hem üretimde kullanılmak üzere tasarlanmıştır: yerel kullanım için bir TUI panosu ve üretim izlemesi için bir Prometheus dışa aktarma daemon modu vardır. + +> [!TIP] +> Özelliklerin tam listesi ve kurulum ayrıntıları için [Ember belgelerine](https://github.com/alexandre-daubois/ember) bakın. + +## Metrikler + +[Caddy metrikleri](https://caddyserver.com/docs/metrics) etkinleştirildiğinde FrankenPHP; iş parçacıkları, worker'lar, istek işleme ve kuyruk derinliği için Prometheus uyumlu metrikler yayınlar. + +Kullanılabilir metriklerin tam listesi için [Metrikler](metrics.md) sayfasına bakın. + +## Günlük kaydı + +FrankenPHP, Caddy'nin günlük sistemine entegre olur ve şiddet düzeyi ile bağlam verisi içeren yapılandırılmış günlükler için `frankenphp_log()` sağlar; bu da Datadog, Grafana Loki veya Elastic gibi platformlara aktarımı kolaylaştırır. + +Kullanım ayrıntıları için [Günlük kaydı](logging.md) sayfasına bakın. + +## Özel Prometheus/Grafana kurulumu + +Özel bir izleme yığını tercih ediyorsanız FrankenPHP metriklerini doğrudan toplayabilirsiniz. +İki seçenek vardır: + +1. **Caddy'yi doğrudan tarayın**: Caddy, metrikleri admin uç noktasında yayınlar (varsayılan: `localhost:2019/metrics`) +2. **Ember üzerinden tarayın**: Ember `--expose` ile çalışırken FrankenPHP metriklerini, Caddy verisinden türetilen hesaplanmış metriklerle (RPS, gecikme yüzdelikleri, hata oranları) birlikte özel bir uç noktada yayınlar. diff --git a/docs/tr/security.md b/docs/tr/security.md new file mode 100644 index 0000000000..45143d1c8b --- /dev/null +++ b/docs/tr/security.md @@ -0,0 +1,58 @@ +# Güvenlik modeli + +Bu belge FrankenPHP'nin güven modelini açıklar: hangi girdilerin güvenilir olduğu, hangilerinin olmadığı ve aralarındaki sınırın nerede durduğu. +Amaç, güvenlik denetimlerinin ve otomatik tarayıcıların **FrankenPHP'nin kendisini** (sunduğu PHP uygulamalarını değil) değerlendirmesine yardımcı olmaktır. + +Burada atıfta bulunulan iç mekanikler (iş parçacıkları, CGO sınırı, ortam sanal alanı) için [İç yapı](internals.md) belgesine bakın. +Uzun ömürlü süreçlerde durum kalıcılığı için [Worker modu](worker.md) belgesine bakın. + +## Güven sınırları + +FrankenPHP dört ayrı aktörden oluşan bir yığında çalışır: + +| Aktör | Güven | Notlar | +| ------------------------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Uzak istemci** | Güvenilmez | HTTP isteği (metod, URI, başlıklar, çerezler, gövde, yüklemeler) kirli girdinin birincil kaynağıdır. | +| **Operatör** | Güvenilir | Dağıtım yapılandırmasını sağlar: `Caddyfile`, ortam değişkenleri, `php.ini`, yüklü PHP eklentileri ve Caddy modülleri, ve uygulamanın kendi kodu. | +| **PHP uygulama kodu** | *Kaynağı itibarıyla* güvenilir | Operatör tarafından dağıtılır, bu yüzden FrankenPHP saldırganın sağladığı kodu asla çalıştırmaz; ancak bu kod güvenilmez istek verisini *tüketir*. | +| **FrankenPHP (Go + C)** | Güvenilir hesaplama tabanı | PHP'yi gömer, veriyi içeri ve dışarı taşır, istekleri ve iş parçacıklarını yalıtır. Bu belgenin kapsamı kendi kusurlarıdır. | + +## Kod kaynağı ve veri kirliliği + +Bu, en önemli ayrımdır ve "PHP'ye güveniyor muyuz yoksa güvenmiyor muyuz?" kafa karışıklığının çoğunu çözer: + +- **Kod kaynağı güvenilirdir.** FrankenPHP yalnızca operatörün dağıttığı PHP dosyalarını çalıştırır: belge kökü altında çözümlenen betik veya yapılandırılmış worker betiği. İsteğin kendisinde taşınan kodu (gövde, sorgu dizesi, başlıklar) asla değerlendirmez: SAPI sınırı *veri* taşır, güvenilmez *kod* değil. +- **İstek verisi kirlidir.** PHP kodunun istekten okuduğu her şey (`$_GET`, `$_POST`, `$_COOKIE`, `$_FILES`, `$_SERVER`, `php://input`) herhangi bir PHP SAPI'sinde olduğu gibi güvenilmezdir. Bunu arındırmak uygulamanın işidir. + +Dolayısıyla "PHP'den gelene güveniyoruz" *kod* için doğru iken "SAPI güvenilmez girdi taşır" *veri* için doğrudur: ikisi çelişmez. +FrankenPHP'nin işi bu kirli veriyi sadakatle taşımak ve bir isteğin verisinin diğerine sızmasını önlemektir. + +## FrankenPHP'nin sorumlulukları + +Güvenilir hesaplama tabanının üç işi vardır. FrankenPHP'deki güvenlik kusurları bunlardan birinde yaşar: + +1. **Sadık taşıma**: isteği PHP süper küresellerine ve `php://input`'a eşle, PHP'nin çıktısını ve başlıklarını istemciye geri taşı; enjeksiyon (başlık/CRLF enjeksiyonu, istek kaçırma, yanlış dosyanın çalıştırılması) eklemeden. +2. **Yalıtım**: istek kapsamlı durumun istekler, PHP iş parçacıkları ve worker yinelemeleri arasında geçmesini önle. +3. **Bellek güvenliği**: CGO sınırını (Go ↔ C/PHP) belleği bozmadan yönet. + +## Kapsamda: FrankenPHP'nin kendi saldırı yüzeyi + +Bunlar FrankenPHP'nin sahip olduğu yüzeylerdir. Buradaki bir zafiyet FrankenPHP zafiyetidir: + +- **İstekten süper küresele eşleme** (`cgi.go`, `frankenphp_register_server_vars`): `$_SERVER`, `REMOTE_ADDR`, `SCRIPT_NAME`, `PATH_INFO` ve diğer CGI değişkenlerini istekten oluşturma. +- **PHP betik yolu çözümlemesi**: istek yolu `split_path` (varsayılan `.php`) ile `SCRIPT_NAME` / `PATH_INFO` olarak ayrılır, ardından `sanitizedPathJoin` (`filepath.Join(root, filepath.Clean("/"+reqPath))`) ile belge köküne birleştirilir; bu `SCRIPT_FILENAME`'in belge kökünden kaçmasını (path traversal) önler. `php_server` yönergesi ayrıca istekleri mevcut dosyalara veya ön denetleyiciye yönlendiren varsayılan bir `try_files` yeniden yazması ayarlar; böylece PHP-FPM'nin klasik tuzaklarından biri olan yanlış dosyanın çalıştırılması azaltılır. +- **Worker modu durum yalıtımı**: FrankenPHP istekler arasında `$_GET`, `$_POST`, `$_COOKIE`, `$_FILES`, `$_SERVER` ve `$_REQUEST`'i sıfırlar ve `$_SESSION`'ı açıkça temizler (aksi halde istekler arasında sızardı), ancak **`$_ENV` sıfırlanmaz**; `putenv()` yazmaları, `static` değişkenler, sınıf statik özellikleri ve globaller aynı iş parçacığındaki istekler boyunca kalır. Bu durumda bırakılan istek veya kullanıcıya özgü veri sonraki bir isteğe sızabilir (bkz. [Worker modu](worker.md#state-persistence)). +- **İş parçacığı başına ortam sanal alanı**: `frankenphp_putenv()` / `frankenphp_getenv()` iş parçacığı yerel `sandboxed_env` üzerinde çalışır, böylece eşzamanlı iş parçacıkları global C ortamında yarışmaz (bkz. [İç yapı](internals.md#per-thread-environment-sandboxing)). +- **CGO bellek sınırı**: Go dize sabitleme ve Go ↔ C sınırında `C.CString()` / `free()` ömürleri. +- **Caddy admin API**: `/frankenphp/workers/restart` ve `/frankenphp/threads` uç noktaları, Caddy'nin admin API'si üzerinden sunulur (varsayılan olarak `localhost:2019` dinler). Bu uç noktayı localhost dışına açmak operatör kararıdır. +- **Güvenilir vekil işleme**: gelen `X-Forwarded-*` başlıkları her zaman PHP'ye kirli `$_SERVER['HTTP_X_FORWARDED_*']` değerleri olarak ulaşır; gerçek istemci IP'sini ve şemayı türetmek için yalnızca [`trusted_proxies`](production.md#running-behind-a-reverse-proxy) yapılandırıldığında güvenilir kabul edilirler. +- **Yavaş istek gövdeleri**: bir gövde duyurup ardından damla damla gönderen veya takılan bir istemci, işleyen iş parçacığını süre boyunca tutar. Sınırlı bir iş parçacığı havuzuyla yeterince böyle bağlantı havuzu tüketir (yavaş-POST DoS). FrankenPHP gövde okumalarına varsayılan olarak 60 sn boşta kalma zaman aşımı uygular ([`request_body_timeout`](config.md#caddyfile-config)); her okumadan önce son tarihi sıfırlar, böylece her boyutta istikrarlı bir yükleme başarılı olurken takılan bir yükleme kesilir ve iş parçacığı serbest bırakılır. + +## Kapsam dışı + +- **Uygulamanın PHP kodundaki zafiyetler** (SQL enjeksiyonu, XSS, güvensiz serileştirme vb.). FrankenPHP güvenilmez istek verisini uygulamaya değiştirmeden iletir; buna karşı savunma, herhangi bir SAPI'de olduğu gibi uygulamanın sorumluluğudur. +- **FrankenPHP'nin kullandığı üst bileşenlerdeki kusurlar** (PHP, Caddy, Go) veya üzerine inşa edilen projelerdeki kusurlar (Laravel Octane, Symfony Runtime). Bunları ilgili projeye bildirin. + +## Bir zafiyet bildirme + +FrankenPHP'yi etkileyen bir güvenlik sorununu nasıl bildireceğiniz için [`SECURITY.md`](../../SECURITY.md) dosyasına bakın. diff --git a/docs/tr/symfony.md b/docs/tr/symfony.md new file mode 100644 index 0000000000..75c249a225 --- /dev/null +++ b/docs/tr/symfony.md @@ -0,0 +1,210 @@ +# Symfony + +## Symfony'yi Symfony Docker ile çalıştırma + +[Symfony](https://symfony.com) projeleri için FrankenPHP'nin yazarı tarafından bakımı yapılan resmi Symfony Docker kurulumu olan [Symfony Docker](https://github.com/dunglas/symfony-docker)'ı öneririz. FrankenPHP, otomatik HTTPS, HTTP/2, HTTP/3 ve worker modu desteğiyle kutudan çıkar çıkmaz eksiksiz bir Docker tabanlı ortam sağlar. + +## Symfony'yi FrankenPHP ile yerel kurma + +Alternatif olarak Symfony projelerinizi FrankenPHP ile yerel makinenizden çalıştırabilirsiniz: + +1. [FrankenPHP'yi kurun](../#getting-started) +2. Aşağıdaki yapılandırmayı Symfony projenizin kök dizinindeki `Caddyfile` adlı bir dosyaya ekleyin: + + ```caddyfile + # Caddyfile + # Sunucunuzun alan adı + localhost + + root public/ + php_server { + # İsteğe bağlı: daha iyi performans için worker modunu etkinleştirin + worker ./public/index.php + } + ``` + + Daha fazla iyileştirme için [performans belgelerine](performance.md) bakın. + +3. FrankenPHP'yi Symfony projenizin kök dizininden başlatın: `frankenphp run` + +## FrankenPHP ile Symfony worker modu + +Symfony 7.4'ten itibaren FrankenPHP worker modu yerel olarak desteklenir. + +Daha eski sürümler için [PHP Runtime](https://github.com/php-runtime/runtime) FrankenPHP paketini kurun: + +```console +composer require runtime/frankenphp-symfony +``` + +FrankenPHP Symfony Runtime'ını kullanmak için `APP_RUNTIME` ortam değişkenini tanımlayarak uygulama sunucunuzu başlatın: + +```console +docker run \ + -e FRANKENPHP_CONFIG="worker ./public/index.php" \ + -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \ + -v $PWD:/app \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +[Worker modu](worker.md) hakkında daha fazla bilgi edinin. + +### Worker uyumluluğunu denetleme + +[Igor PHP](https://github.com/igor-php/igor-php), Symfony projelerini üretimde sorun çıkmadan önce durum sızıntılarına karşı tarayan statik bir linter'dır: `ResetInterface` eksik servisler, sıfırlanmayan durumlu özellikler, değiştirilebilir yerel static'ler, `exit()`/`die()` çağrıları ve süper küresel yazmaları. Hem uygulama kodunuzu hem `vendor/` içinde bildirilen servisleri denetler. + +```console +composer require --dev igor-php/igor-php +vendor/bin/igor-php . +``` + +## Symfony için sıcak yeniden yükleme + +Sıcak yeniden yükleme [Symfony Docker](https://github.com/dunglas/symfony-docker) içinde varsayılan olarak etkindir. + +[Sıcak yeniden yükleme](hot-reload.md) özelliğini Symfony Docker olmadan kullanmak için [Mercure](mercure.md)'ü etkinleştirin ve `Caddyfile`'ınızdaki `php_server` yönergesine `hot_reload` alt yönergesini ekleyin: + +```caddyfile +localhost + +mercure { + anonymous +} + +root public/ +php_server { + hot_reload + worker ./public/index.php +} +``` + +Ardından aşağıdaki kodu `templates/base.html.twig` dosyanıza ekleyin: + +```twig +{# templates/base.html.twig #} +{% if app.request.server.has('FRANKENPHP_HOT_RELOAD') %} + + + +{% endif %} +``` + +Son olarak Symfony projenizin kök dizininden `frankenphp run` çalıştırın. + +## Varlıkları önceden sıkıştırma + +Symfony'nin [AssetMapper bileşeni](https://symfony.com/doc/current/frontend/asset_mapper.html) dağıtım sırasında varlıkları Brotli ve Zstandard ile önceden sıkıştırabilir. FrankenPHP (Caddy'nin `file_server`'ı aracılığıyla) bu önceden sıkıştırılmış dosyaları doğrudan sunabilir ve anlık sıkıştırma yükünü ortadan kaldırır. + +1. Varlıklarınızı derleyin ve sıkıştırın: + + ```console + php bin/console asset-map:compile + ``` + +2. Önceden sıkıştırılmış varlıkları sunmak için `Caddyfile`'ınızı güncelleyin: + + ```caddyfile + # Caddyfile + localhost + + @assets path /assets/* + file_server @assets { + precompressed zstd br gzip + } + + root public/ + php_server { + worker ./public/index.php + } + ``` + +`precompressed` yönergesi Caddy'ye istenen dosyanın önceden sıkıştırılmış sürümlerini (ör. `app.css.zst`, `app.css.br`) aramasını ve istemci destekliyorsa bunları doğrudan sunmasını söyler. + +## Büyük statik dosyaları sunma (`X-Sendfile`) + +FrankenPHP, PHP kodunu çalıştırdıktan sonra [büyük statik dosyaları verimli sunmayı](x-sendfile.md) destekler (erişim denetimi, istatistikler vb. için). + +Symfony HttpFoundation [bu özelliği yerel olarak destekler](https://symfony.com/doc/current/components/http_foundation.html#serving-files). +[`Caddyfile`'ınızı yapılandırdıktan](x-sendfile.md#configuring-x-accel-redirect-in-the-frankenphp-caddyfile) sonra `X-Accel-Redirect` başlığı için doğru değeri otomatik belirler ve yanıta ekler: + +```php +use Symfony\Component\HttpFoundation\BinaryFileResponse; + +BinaryFileResponse::trustXSendfileTypeHeader(); +$response = new BinaryFileResponse(__DIR__.'/../private-files/file.txt'); + +// ... +``` + +## Symfony uygulamalarını bağımsız ikili dosyalar olarak dağıtma + +[FrankenPHP'nin uygulama gömme özelliğini](embed.md) kullanarak Symfony uygulamalarını +bağımsız ikili dosyalar olarak dağıtmak mümkündür. + +Symfony uygulamanızı hazırlamak ve paketlemek için şu adımları izleyin: + +1. Uygulamanızı hazırlayın: + + ```console + # .git/ vb. dosyalarından kurtulmak için projeyi dışa aktarın + mkdir $TMPDIR/my-prepared-app + git archive HEAD | tar -x -C $TMPDIR/my-prepared-app + cd $TMPDIR/my-prepared-app + + # Uygun ortam değişkenlerini ayarlayın + echo APP_ENV=prod > .env.local + echo APP_DEBUG=0 >> .env.local + + # Yer kazanmak için testleri ve diğer gereksiz dosyaları kaldırın + # Alternatif olarak bu dosyaları .gitattributes dosyanızda export-ignore özniteliğiyle ekleyin + rm -Rf tests/ + + # Bağımlılıkları yükleyin + composer install --ignore-platform-reqs --no-dev -a + + # .env'yi optimize edin + composer dump-env prod + ``` + +2. Uygulamanızın deposunda `static-build.Dockerfile` adlı bir dosya oluşturun: + + ```dockerfile + # static-build.Dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder-gnu + # İkili dosyayı musl-libc sistemlerinde çalıştırmayı düşünüyorsanız bunun yerine static-builder-musl kullanın + + # Uygulamanızı kopyalayın + WORKDIR /go/src/app/dist/app + COPY . . + + # Statik ikili dosyayı derleyin + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` + + > [!CAUTION] + > + > Bazı `.dockerignore` dosyaları (ör. varsayılan [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) + > `vendor/` dizinini ve `.env` dosyalarını yok sayar. Derlemeden önce `.dockerignore` dosyasını ayarladığınızdan veya kaldırdığınızdan emin olun. + +3. Derleyin: + + ```console + docker build -t static-symfony-app -f static-build.Dockerfile . + ``` + +4. İkili dosyayı çıkarın: + + ```console + docker cp $(docker create --name static-symfony-app-tmp static-symfony-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-symfony-app-tmp + ``` + +5. Sunucuyu başlatın: + + ```console + ./my-app php-server + ``` + +Kullanılabilir seçenekler ve diğer işletim sistemleri için ikili dosya derleme hakkında daha fazla bilgiyi [uygulama gömme](embed.md) +belgelerinde bulabilirsiniz. diff --git a/docs/tr/wordpress.md b/docs/tr/wordpress.md new file mode 100644 index 0000000000..08d5daa87e --- /dev/null +++ b/docs/tr/wordpress.md @@ -0,0 +1,60 @@ +# WordPress + +[WordPress](https://wordpress.org/)'i FrankenPHP ile çalıştırarak otomatik HTTPS, HTTP/3 ve Zstandard sıkıştırmalı modern, yüksek performanslı bir yığının tadını çıkarın. + +## WordPress'i FrankenPHP ile kurma + +1. [WordPress'i indirin](https://wordpress.org/download/) +2. ZIP arşivini çıkarın ve çıkarılan dizinde bir terminal açın +3. Şunu çalıştırın: + + ```console + frankenphp php-server + ``` + +4. `http://localhost/wp-admin/` adresine gidin ve kurulum yönergelerini izleyin +5. Tadını çıkarın! + +Üretime hazır bir kurulum için `frankenphp run` ile şöyle bir `Caddyfile` kullanmayı tercih edin: + +```caddyfile +example.com + +php_server +encode zstd br gzip +log +``` + +## WordPress için sıcak yeniden yükleme + +[Sıcak yeniden yükleme](hot-reload.md) özelliğini WordPress ile kullanmak için [Mercure](mercure.md)'ü etkinleştirin ve `Caddyfile`'ınızdaki `php_server` yönergesine `hot_reload` alt yönergesini ekleyin: + +```caddyfile +localhost + +mercure { + anonymous +} + +php_server { + hot_reload +} +``` + +Ardından WordPress temanızın `functions.php` dosyasına JavaScript kütüphanelerini yüklemek için gereken kodu ekleyin: + +```php +// wp-content/themes//functions.php +function hot_reload() { + ?> + + + + + + run(); +``` + +Uygulamayı worker modunda başlatmak için `Caddyfile`'ınızı güncelleyin: + +```caddyfile +{ + frankenphp +} + +localhost { + encode zstd br gzip + php_server { + root public/ + worker ./worker.php { + # Tüm istekleri worker'a gönder + match * + # PHP dosyaları değiştiğinde worker'ları yeniden yükle (yalnızca geliştirme) + watch ./**/*.php + } + } +} +``` + +Uygulamanız [resmi Yii uygulama şablonuna](https://github.com/yiisoft/app) dayanıyorsa; debug, ortam ve hata işleyici yapılandırması içeren eksiksiz bir `worker.php` örneği için [paket readme](https://github.com/yiisoft/yii-runner-frankenphp) dosyasına bakın. + +Bir worker'ın yeniden başlatılmadan önce işlediği istek sayısını sınırlamak için (bellek sızıntılarını azaltmakta yararlıdır) `MAX_REQUESTS` ortam değişkenini ayarlayın. Varsayılan olarak worker'lar istekleri süresiz işler. + +Worker modunu kullanırken durum tutan servislerin her istekten sonra sıfırlandığından emin olun. Ayrıntılar için [worker modu belgelerine](worker.md) ve [Yii DI `StateResetter` belgelerine](https://github.com/yiisoft/di#resetting-services-state) bakın.