PHP sürümünü kurmak
PHP sürümü olduğu gibi paylaşımlı bir barındırmaya bırakılır: Composer yok, paket yöneticisi yok, çalışır tutulacak bir servis yok. Bir klasör, bir yapılandırma dosyası, bir zamanlanmış görev. Bu kılavuz boş klasörden üretimdeki kuruluma kadar gider; çoğu kılavuzun atladığı şeyler de içinde: izinler, TLS, zamanlanmış görev, yedekler ve güncelleme.
Gerekenler#
| Öğe | Sürüm | Neden |
|---|---|---|
| PHP | 8.1 ya da daha yenisi | Birleşim türleri, enum, readonly, never: kod bunları kullanıyor. |
pdo_sqlite | — | Veritabanının tamamı. Onsuz hiçbir şey çalışmaz. |
mbstring | — | On altı dilde dizgilerin doğru işlenmesi. |
openssl | önerilir | Veritabanındaki sırların şifrelenmesi (SMTP parolaları, dışa aktarma belirteçleri). |
curl | önerilir | Giden web kancaları ve yedeklerin üçüncü tarafa bırakılması. |
intl | önerilir | Tarihler Node sürümündeki gibi yazılır. Yoksa ay adları sözlüklerden gelir. |
Kurulum sihirbazı bunların hepsini denetler ve devam etmenize izin vermeden önce ekranda gösterir: engelleyen şey kurulumu durdurur, isteğe bağlı olan ise engellemeden bildirilir.
composer ile kurulacak hiçbir şey yoktur: IMAP okuyucusu,
tar.gz arşivi, PDF, CSV, QR kodu ve HTTP istemcisi ürünün içinde yazılmıştır.
Komut satırınızın olmadığı bir barındırmaya bırakabilmenizi sağlayan da budur.
1. Dosyaları yüklemek#
PHP sürümünün arşivini alın, sonra yükleyin. Klasör şöyle görünür:
toutadmin/
├── app/ kod (web sunucusu bunu asla sunmaz)
│ ├── Core/ çekirdek: yönlendirme, veritabanı, oturumlar, güvenlik
│ ├── Modules/ iş katmanı: insan kaynakları, mali işler, projeler, kalite…
│ ├── Controllers/
│ ├── views/ şablonlar
│ ├── locales/ on altı sözlük
│ └── schema.sql şema, Node sürümündekinin aynısı
├── public/ ← web kökü buraya bakar, başka hiçbir yere değil
│ ├── index.php ön denetleyici
│ ├── css/ js/
├── data/ veritabanı, kasa, imza klasörü, gelen belgeler, yedekler
├── tools/ cron.php, check-keys.php
├── tests/
├── config.sample.php
└── VERSION
public/ dizinine bakar
Bu sayfanın en önemli noktası budur. Sunucu klasörün tamamını sunarsa,
data/app.sqlite herkesçe indirilebilir hâle gelir: veritabanının tamamı, parola
özetleri ve kasa dahil. data/ klasörü public/ dizininin üstünde,
ve bu bilerek böyledir.
Paylaşımlı barındırmada#
İki durum çıkar. Barındırıcınız bir alan adının kökünü seçmenize izin veriyorsa (cPanel,
Plesk ve «kök klasör» kipindeki barındırmaların çoğu), klasörü www/ dışına
bırakın ve alan adını toutadmin/public dizinine yönlendirin.
Kök dayatılmışsa — çoğunlukla www/ ya da public_html/ —
public/ içeriğini oraya, gerisini ise üstüne bırakın; sonra
public/index.php dosyasının başındaki yolu düzeltin:
www/ ← dayatılan kök
├── index.php
├── css/ js/
toutadmin/ ← gerisi, webin erişemeyeceği yerde
├── app/
├── data/
└── config.php
// www/index.php — düzeltilecek satır
require_once __DIR__ . '/../toutadmin/app/bootstrap.php';
Son çare olarak, kökün üstüne hiçbir şey koyamıyorsanız, data/ içinde gelen
.htaccess dosyası erişimi zaten reddeder. Bu bir emniyet kemeridir, çözüm
değildir: her zaman kök dışındaki klasörü yeğleyin.
2. Yapılandırmayı yazmak#
cp config.sample.php config.php
Sonra config.php dosyasını açın:
<?php
return [
// SQLite veritabanı ve veri klasörü: web kökünün dışında.
'db_path' => __DIR__ . '/data/app.sqlite',
'data_dir' => __DIR__ . '/data',
// Bu kuruluma özgü anahtar. Bir kez üretilir:
// php -r "echo bin2hex(random_bytes(32));"
'session_secret' => '…',
// Kurulum belirteci: bir sonraki adıma bakın.
'install_token' => '',
// Genel adres, e-postayla gönderilen bağlantılar için.
'base_url' => 'https://intranet.ornek.com.tr',
// Yalnızca güvenilir bir vekil sunucunun ardında açın.
'trust_proxy' => false,
// Tavanlar: adres başına çeyrek saatte oturum açma denemesi,
// adres başına dakikada istek.
'login_rate_limit' => 10,
'global_rate_limit' => 300,
// Sona erme: işlemsizlik, ardından hiçbir etkinliğin uzatmadığı mutlak süre.
'session_idle_minutes' => 60,
'session_max_hours' => 12,
];
İmza klasöründeki imzaları mühürler ve veritabanındaki sırları şifreler. Onu yitirmek
imzaları geçersiz kılar. Örnekteki değeri olduğu gibi bırakırsanız ürün kendi başına
data/.instance-key içinde bir tane üretir (izinler 0600) — o
zaman bu dosyayı da geri kalanla birlikte yedeklemeyi unutmayın.
Yapılandırmayı başka bir yerde de tutabilirsiniz: TOUTADMIN_CONFIG ortam
değişkeni başka bir dosyayı gösterir.
3. Kurulum belirteci koymak#
Dosyaların yüklenmesiyle sihirbaza uğramanız arasında kurulum onu bulanın olur: ilk gelen yönetim hesabını oluşturur. Pencere kısadır, ama yeter. O yüzden yayına almadan önce rastgele bir değer koyun:
php -r "echo bin2hex(random_bytes(16));"
# sonra config.php içine:
'install_token' => 'c3f1…',
Sihirbaz bunu ister, sabit sürede karşılaştırır — sıradan bir karşılaştırma belirteci karakter karakter tahmin ettirirdi — ve her reddi günlüğe yazar. Belirteç olmadan hiçbir şey oluşturulmaz. Kurulum bittiğinde sihirbaz kendiliğinden kapanır: belirteç kalabilir, artık bir işe yaramaz.
4. İzinler#
| Yol | Haklar | Kim yazar |
|---|---|---|
data/ | 0770 | Web sunucusu, yalnızca o |
data/app.sqlite | 0660 | Kurulum tarafından oluşturulur |
config.php | 0640 | Kimse — sunucu için salt okunur |
app/, public/ | 0755 | Kimse — salt okunur |
# PHP'nin www-data olarak çalıştığı bir sunucuda örnek
sudo chown -R siz:www-data /var/www/toutadmin
sudo find /var/www/toutadmin -type d -exec chmod 750 {} \;
sudo find /var/www/toutadmin -type f -exec chmod 640 {} \;
sudo chmod 770 /var/www/toutadmin/data
sudo chmod 750 /var/www/toutadmin/public
SQLite ayrıca komşu dosyalar da yazar (-wal, -shm): yazılabilir
olması gereken klasördür, yalnızca veritabanı değil.
5. Web sunucusu#
Nginx#
server {
listen 443 ssl http2;
server_name intranet.ornek.com.tr;
root /var/www/toutadmin/public; # ve başka hiçbir şey
index index.php;
ssl_certificate /etc/letsencrypt/live/intranet.ornek.com.tr/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/intranet.ornek.com.tr/privkey.pem;
client_max_body_size 20M; # kasaya yüklemeler, gelen belgeler
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Yüklenen dosyalar hiçbir zaman doğrudan sunulmaz: oturumu ve özeti
# denetleyen bir yoldan geçerler.
location ~ ^/(data|app|tools|tests)/ { deny all; }
}
server {
listen 80;
server_name intranet.ornek.com.tr;
return 301 https://$host$request_uri;
}
Apache#
<VirtualHost *:443>
ServerName intranet.ornek.com.tr
DocumentRoot /var/www/toutadmin/public
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/intranet.ornek.com.tr/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/intranet.ornek.com.tr/privkey.pem
<Directory /var/www/toutadmin/public>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Ürünle gelen public/.htaccess dosyası bütün adresleri zaten
index.php dosyasına yönlendirir. Apache'li paylaşımlı barındırmada gereken tek
şey budur.
TLS#
Ürün, bağlantı şifreli olur olmaz Strict-Transport-Security başlığını koyar ve
asla açık metinde koymaz: şifresiz bir sayfadan duyurulsa okunmazdı, üstelik yerel bir denemeyi
altı ay boyunca https içine hapsederdi. Kendi yönettiğiniz bir sunucuda:
sudo certbot --nginx -d intranet.ornek.com.tr
TLS'i sonlandıran bir vekil sunucunun ya da yük dağıtıcının ardında
'trust_proxy' => true yapın — ve yalnızca orada: yoksa herkes bir başlıkta
dilediği IP adresini ve protokolü duyurabilir.
6. Zamanlanmış görev#
Bir PHP sitesi yalnızca bir istek sırasında çalışır. Node sürümünün saatlik süpürmesinde yaptığı sekiz işlem burada barındırmanın cron'undan yapılır:
* * * * * /usr/bin/php /var/www/toutadmin/tools/cron.php >> /var/log/toutadmin-cron.log 2>&1
| Görev ne yapar | Hangi sıklıkta |
|---|---|
| Sözleşmesi biten hesapları kapatır | her geçişte |
| Vadesi gelen aboneliklerin faturalarını keser | her geçişte, asla iki kez faturalamadan |
| Vadeleri bildirime çevirir | her geçişte, yinelemeden arındırılmış |
| Okunmuş bildirimleri ve denetim günlüğünü temizler | seçilen saklama süresine göre |
| Muhasebe posta kutusunu toplar (IMAP) | toplama yapılandırılmışsa |
| Web kancası kuyruğunu, yeniden denemeleriyle boşaltır | her geçişte |
| Otomatik yedeği alır ve dışarı gönderir | aralık dolduğunda |
Betiği ayarlanan aralıktan daha sık çağırmak daha sık yedek almaz: vadesi gelmeden hiçbir şey
tetiklenmez. Cron'u çeyrek saatte bir geçişle sınırlayan bir barındırmada
* * * * * yerine */15 * * * * yazın — web kancaları yalnızca bu
gecikmeyle yola çıkar.
Kimi giriş seviyesi paketlerde cron yoktur. Üçüncü taraf bir servisten (erişilebilirlik
izleyicisi ve benzerleri) gelen HTTP çağrısı yetmez: cron.php komut satırı
dışında çalıştırılmayı reddeder — tam da genel bir adres yedeklemeyi tetikleyemesin diye. Bu
durumda yedek, Yedekler ekranından elle alınır.
7. Sihirbaz#
Alan adınızı açın. Hiçbir hesap yokken bütün adresler /installation adresine
yönlenir. Sihirbaz tek sayfaya sığar:
- Önkoşullar, denetlenip gösterilir — engelleyen öyle işaretlenir.
- Kurulum belirteci, ayarlanmışsa.
- Şirket: her yerde görünen ad ve serbest çalışan olmayan her yeni personele verilen yıllık izin günü sayısı.
- Kurulumun varsayılan dili, 16 dil arasından.
- Yönetim hesabı: adres ve en az on iki karakterlik bir parola.
Her şey tek bir işlemde yazılır. Bir hesap oluşur oluşmaz
/installation giriş sayfasına yönlendirir: sihirbaz kendiliğinden kapanmıştır,
elle silinecek hiçbir dosya yoktur.
8. Her şeyin yürüdüğünü doğrulamak#
# testler, makine üzerinde (veritabanınıza yazmazlar)
php tests/run.php
# çeviriler: hiçbir ekran sözlüklerde bulunmayan bir anahtarı kullanmaz
php tools/check-keys.php
Sonra arayüzde: bir üye oluşturun, onunla girin, bir ek yükleyin, elle bir yedek alın ve Yedekler ekranından doğrulayın. Bu dört hareket veritabanına, dosyalara, yetkilere ve arşive dokunur — yani barındırmanın yapabilmesi gereken her şeye.
9. Güncellemek#
# 1. önce bir yedek, her zaman
php tools/cron.php # ya da Yedekler ekranı
# 2. kodu değiştirin, veriyi değil
# app/ public/ tools/ tests/ VERSION ← değiştirilir
# data/ config.php ← olduğu gibi bırakılır
# 3. veritabanı ilk istekte kendini günceller
Şema eşgüçlü göçlerle ilerler: güncellemeyi yeniden oynatmak hiçbir şeyi bozmaz. Node sürümünün bir kurulumu ile PHP sürümünün bir kurulumu aynı şemayı — 142 tablo, 1311 sütun — ve aynı parolaları paylaşır: bir veritabanı birinden ötekine dönüştürme olmadan geçer.
10. Gerçekten yedeklemek#
tar.gz arşivi veritabanını (VACUUM INTO ile kopyalanır, dolayısıyla
yazma sırasında bile tutarlıdır) ve beş dosya klasörünü taşır: profil fotoğrafları, gelen
özgeçmişler, kasa, imza klasörü, gelen belgeler. Arşivdeki her dosya kendi SHA-256 özetini
taşır ve bu özet geri yüklemede doğrulanır.
Koruduğu sunucuda kalan bir arşiv hiçbir şeyi korumaz: Yedekler ekranından uzak bir hedef (FTPS ya da Google Drive) ayarlayın. Ayrıntısı Yedekleme ve geri yükleme sayfasındadır.
Önce yerelde denemek#
cp config.sample.php config.php
php -S localhost:8000 -t public public/index.php
PHP'nin gömülü sunucusu ürünü tanımaya yeter. Üretime uygun değildir: tek bir süreç, TLS yok, yük sınırı yok.
Toutadmin belgeleri — 2026-09-13 tarihinde derlendi. Yazılımdan bağımsız, kendi başına bir site.