Web Geliştirme ve Frameworkler kod örnekli
EVREN API'sine PHP ile İlk İstek: Şart Onayı ve 403 Tuzağı
EVREN'in auto kipi cevap verecek modeli isteğe ve filo yüküne göre seçer; seçileni yanıttaki tek bir alan söyler. 403 ve 429 dahil, cURL ile tek dosyalık PHP istemcisi.

İçindekiler
- Adım 1: Anahtarı ortam değişkenine koyun
- Adım 2: Tek dosyalık cURL istemcisini yazın
- Taban adres ve hata sınıfı
- Kimlik başlığı ve zaman aşımı
- Yanıtı çözmek ve hatayı ayırmak
- Adım 3: Kullanım şartlarını API'den onaylayın
- Adım 4: Hesabınıza tanımlı modelleri listeleyin
- Adım 5: auto ile ilk sohbeti gönderin ve modeli okuyun
- Adım 6: 429 ve 503'te ne zaman beklenir, ne zaman durulur
- Çıktıdan kurulumun hangi adımda kaldığını bulun
- Hata satırı ve dönülecek adım
- Sertifika hatası ve öteki 4xx kodları
Bu yazıyı dinle
Yapay zekâ sesiyle yaklaşık 2 dakikalık özet
EVREN'in büyük dil modeli uç noktası OpenAI'nin REST sözleşmesini uyguladığı için EVREN API'sine PHP ile istek atmak yeni bir kütüphane istemez: curl eklentisiyle yazılmış tek dosyalık bir istemci yeter. Anahtarı alıp doğrudan sohbet ucunu çağıran kod ise 403 terms_not_accepted alır, çünkü önce kullanım şartlarının onaylanması gerekir. Adımların sonunda bu onayı yapan bir betik, auto isteğine hangi modelin cevap verdiğini gösteren ilk çağrı ve 429'da ne zaman bekleneceğini bilen bir fonksiyon elinizde olacak. Gerekenler: PHP 8.1 ya da üstü, curl ve mbstring eklentileri ve EVREN hesabınızdan alınmış bir anahtar.

Adım 1: Anahtarı ortam değişkenine koyun
Anahtar EVREN panelinin LLM Çıkarım menüsündeki API Anahtarları sayfasında (/api-keys) üretilir, evren_llm_ ile başlar ve oluşturulduğu anda bir kez gösterilir. Platformun API belgesi aynı menüdeki Modeller ve API sayfasıdır (/llm/models, giriş ister); yazıda belge denince bu sayfa kastedilir. Kodun içine yazılan anahtar Git geçmişine ve yedeklere de girer, bu yüzden istemci anahtarı EVREN_API_KEY ortam değişkeninden okuyacak. Anahtar kopyalarının nasıl izleneceğini .env dosyasından sır kasasına geçiş yazımız anlatıyor. PowerShell'de anahtarı oturuma tanımlayın ve PHP'nin hem curl eklentisini hem değişkeni gördüğünü tek komutla doğrulayın:
$env:EVREN_API_KEY = 'evren_llm_...'
C:\xampp\php\php.exe -r "var_dump(extension_loaded('curl'), getenv('EVREN_API_KEY') !== false);"Çıktıda iki kez bool(true) görünmelidir. php.exe PATH'te olmayabileceği için komut XAMPP'teki tam yolu kullanır. Tek tırnak, anahtarda $ varsa PowerShell'in onu değişken sanmasını önler. Değişken o PowerShell penceresi kapanınca silinir. Git Bash'te karşılığı export EVREN_API_KEY='evren_llm_...' satırıdır. CodeIgniter 4 uygulamasında aynı değeri .env dosyasına EVREN_API_KEY = evren_llm_... diye yazın: CI4 .env değerlerini putenv() ile ortama koyar ve istemcideki getenv() onları okur.
Anahtar sızdıysa API Anahtarları sayfasındaki yenileme yeni bir gizli anahtar üretir ama eskisini hemen kapatmaz: liste eski anahtarın kaç dakika sonra devre dışı kalacağını gösterir ve sızan anahtar bu sürede istek atabilir. Aynı satırda anahtarı iptal etmek için ayrı bir düğme vardır. Yenileme o günkü token kullanımını sıfırlamaz.
Adım 2: Tek dosyalık cURL istemcisini yazın
İstemcinin üç işi vardır: her isteğe anahtarı eklemek, yanıtı JSON olarak çözmek ve HTTP hatasını ayrıntılı bir istisnaya çevirmek. Üç parça aynı evren.php dosyasına sırayla yazılır. Python kullanan biri aynı bağlantıyı resmî openai paketine base_url ve api_key vererek kurar (belgedeki örnek); PHP tarafında curl yeter.
Taban adres ve hata sınıfı
Bütün uçlar https://evren-llmapi.ssyz.org.tr/v1 altındadır. İstisna sınıfı HTTP kodunu, hata kodunu ve yanıt başlıklarını taşır. 6. adımdaki kota kararı bu başlıklara bakar.
<?php
// evren.php: EVREN API istemcisi (PHP 8.1+, curl ve mbstring eklentileri)
const EVREN_TABAN = 'https://evren-llmapi.ssyz.org.tr/v1';
final class ApiHatasi extends RuntimeException
{
public function __construct(
string $mesaj,
public readonly int $http = 0, // 0: HTTP yanıtı hiç gelmedi
public readonly string $hataKodu = '', // error.code, yoksa error.type
public readonly array $basliklar = [], // kota kararı için yanıt başlıkları
) {
parent::__construct($mesaj);
}
}Kimlik başlığı ve zaman aşımı
Belge kimlik için iki başlığı da kabul eder: ilk çağrıya kadarki dört adım ve uçtan uca örnek X-API-Key, Desteklenen uçlar kartlarındaki curl örnekleri Authorization: Bearer gönderir. İstemci Bearer kullanır: resmî SDK'ların kendiliğinden gönderdiği başlık budur, ileride SDK'ya geçildiğinde sunucuya giden kimlik bilgisi aynı kalır.
// Yanıt başlıkları da toplanır: 429'da beklemek mi durmak mı, kalan token başlığı söyler.
function istek_secenekleri(string $yontem, ?array $govde, int $sure, array &$basliklar): array
{
$anahtar = getenv('EVREN_API_KEY') ?: throw new ApiHatasi('EVREN_API_KEY ortam değişkeni boş');
$secenek = [
CURLOPT_CUSTOMREQUEST => $yontem,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => $sure,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $anahtar, 'Content-Type: application/json'],
CURLOPT_HEADERFUNCTION => function ($ch, string $satir) use (&$basliklar): int {
if (str_contains($satir, ':')) {
[$ad, $deger] = explode(':', $satir, 2);
$basliklar[strtolower(trim($ad))] = trim($deger);
}
return strlen($satir);
},
];
if ($govde !== null) {
$secenek[CURLOPT_POSTFIELDS] = json_encode($govde, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
}
return $secenek;
}PHP kılavuzuna göre CURLOPT_TIMEOUT varsayılan olarak 0'dır, yani yanıt gelmezse aktarım hiç zaman aşımına uğramaz. Bağlanma beklemesinin varsayılanı da 300 saniyedir. Sohbet yanıtının süresi modele ve max_tokens değerine göre değiştiği için toplam süre parametre oldu, bağlanma 10 saniyeyle sınırlandı.
Yanıtı çözmek ve hatayı ayırmak
Son parça isteği gönderir ve üç arıza yolunu ayırır: hiç yanıt gelmemesi, JSON olmayan gövde ve 4xx ya da 5xx durum kodu.
function evren(string $yontem, string $yol, ?array $govde = null, int $sure = 120): array
{
$basliklar = [];
$ch = curl_init(EVREN_TABAN . $yol);
curl_setopt_array($ch, istek_secenekleri($yontem, $govde, $sure, $basliklar));
$ham = curl_exec($ch);
if ($ham === false) {
throw new ApiHatasi('Bağlantı hatası: ' . curl_error($ch));
}
$http = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$veri = json_decode($ham, true);
if (! is_array($veri)) { // boş gövde, yarım JSON ya da aradaki bir vekil sunucunun HTML sayfası
throw new ApiHatasi("HTTP $http, JSON olmayan yanıt: " . mb_strcut($ham, 0, 120, 'UTF-8'), $http, '', $basliklar);
}
if ($http >= 400) {
$hata = $veri['error'] ?? [];
$kod = (string) ($hata['code'] ?? $hata['type'] ?? '');
$mesaj = is_string($hata['message'] ?? null) ? $hata['message'] : mb_strcut($ham, 0, 200, 'UTF-8');
throw new ApiHatasi(trim("HTTP $http $kod") . ': ' . $mesaj, $http, $kod, $basliklar);
}
return $veri;
}Hata kodu önce error.code, yoksa error.type alanından okunur. Gövdede error.message yoksa ya da metin değilse mesajın yerine ham gövdenin ilk 200 baytı yazılır; mb_strcut() Türkçe bir harfi ortadan bölmeden keser. Belge hata gövdesinin OpenAI sözleşmesine uyduğunu söyler ama 403 gövdesinin alanlarını tek tek göstermez.
Adım 3: Kullanım şartlarını API'den onaylayın
Şart onayı üç çağrıdır: GET /v1/terms/status yanıtındaki current_version okunur, GET /v1/terms/text ile metin alınır ve aynı sayı POST /v1/terms/accept gövdesinde {"version": N} olarak geri gönderilir. Belgeye göre bu adım hesap başına bir kez gerekir, atlanırsa sohbet çağrısı 403 terms_not_accepted döner. sartlar.php metni dosyaya yazar ve onayınızı bekler:
<?php
require __DIR__ . '/evren.php';
$durum = evren('GET', '/terms/status');
$surum = $durum['current_version'];
if ($durum['accepted']) {
exit("Şartlar zaten onaylı (sürüm $surum).\n");
}
$metin = evren('GET', '/terms/text');
file_put_contents("sartlar-v$surum.md", $metin['content']);
echo "Şartlar sartlar-v$surum.md dosyasına yazıldı. Okuyup onaylıyorsanız evet yazın: ";
if (trim((string) fgets(STDIN)) !== 'evet') {
exit("Onay verilmedi, sohbet istekleri 403 ile dönmeye devam eder.\n");
}
$kabul = evren('POST', '/terms/accept', ['version' => $surum]);
echo "Onaylandı: sürüm {$kabul['accepted_version']}, {$kabul['accepted_at']}\n";Sürüm numarası koda yazılmaz, status yanıtından gelir. Belgeye göre onay, yeni esaslı bir sürüm yayınlanana kadar geçerlidir. O gün betik yeni sayıyı kendisi gönderir, sohbet kodunuz ise 403'ü yeniden görebilir; 5. adımdaki kod bu yüzden hatayı yakalar. Panelin Test Alanı'ndaki anahtar kutusu da belgeye göre bu üç adımı tek tıkla yapar.
Adım 4: Hesabınıza tanımlı modelleri listeleyin
GET /v1/models hesabınıza tanımlı modellerin kimliklerini döndürür. model alanına yazılacak değer bu listeden gelir.
<?php
require __DIR__ . '/evren.php';
foreach (evren('GET', '/models')['data'] as $model) {
echo str_pad($model['id'], 24), implode(', ', $model['modalities'] ?? []), "\n";
}Belgedeki örnek yanıtta glm-5.3, deepseek-v4.1-flash ve auto görünür. Her kaydın pricing alanı token fiyatını ve free_until tarihini taşır. Bu kimliklerin arkasındaki açık ağırlıklı modelleri ve platformun yapısını EVREN yapay zekâ platformunu anlatan yazımızda ele aldık.
Adım 5: auto ile ilk sohbeti gönderin ve modeli okuyun
auto belirli bir model sayılmaz, geçidin yönlendirme kipidir. EVREN'in herkese açık LLM çıkarım sayfasına göre isteğin yeteneğini, bağlamını ve anlık filo yükünü değerlendirip uygun modeli seçer. Belgedeki örnekte auto isteğinin yanıtında model alanı zai/glm-5.3-fp8 yazar; cevabı veren model bu yüzden bu alandan okunur.
<?php
require __DIR__ . '/evren.php';
try {
$yanit = evren('POST', '/chat/completions', [
'model' => 'auto',
'messages' => [['role' => 'user', 'content' => "PHP'de bir dizinin son elemanını nasıl alırım?"]],
'max_tokens' => 4096,
]);
} catch (ApiHatasi $e) {
if ($e->http === 403) { // belge bu durumu "403 terms_not_accepted" diye anar, gövde alanlarını vermez
exit($e->getMessage() . "\nŞartlar onaylanmamış olabilir: php sartlar.php\n");
}
throw $e;
}
$secim = $yanit['choices'][0];
echo "Yanıtlayan model: {$yanit['model']} · bitiş: {$secim['finish_reason']}\n";
echo $secim['message']['content'] ?? '', "\n";
$u = $yanit['usage'];
echo "Token: {$u['prompt_tokens']} girdi + {$u['completion_tokens']} çıktı = {$u['total_tokens']}\n";Şart dalı hata koduna değil HTTP 403'e bakar, çünkü 403 gövdesinin hangi alanda terms_not_accepted taşıdığı belgede yazmaz; sunucunun metni ipucundan önceki satır ya da satırlarda görünür (uzun gövdenin yalnız başı). max_tokens 4096 verildi, çünkü auto düşünen bir modele de gidebilir. Belge DeepSeek ve Qwen gibi akıl yürüten modellerde bu sınırın düşünme ile cevap arasında paylaşıldığını yazar ve en az 2048, tercihen 4096 önerir. Bitiş nedeni length ise yanıt bu sınırda kesilmiştir. Aynı istem farklı saatte başka bir modele gidebileceği için model ve usage alanlarını istekle birlikte günlüğe yazmak işinize yarar.
Belirli bir modelle çalışmak için auto yerine kısa kimliği (glm-5.3) ya da tam repo adını (zai/glm-5.3-fp8) yazın; belge ikisini de destekler. Bu istemci yanıtı tek parça bekler. Gövdeye "stream": true eklenirse sunucu SSE akışı döner ve evren() onu JSON olmayan yanıt diye reddeder; akış için yanıtı parça parça okuyan ayrı bir kod (ör. CURLOPT_WRITEFUNCTION) ya da bir SDK'nın akış desteği gerekir.
Adım 6: 429 ve 503'te ne zaman beklenir, ne zaman durulur
429 geldiğinde kalan token başlığı 0 ise durun, değilse en fazla 60 saniye bekleyip yeniden deneyin. 503'te kısa bir bekleme yeter. Belgeye göre 429 hesap kotasını, 503 sunucunun anlık doluluğunu bildirir ve dakikalık sınırda bekleme en fazla 60 saniye sürer. Günlük kota bütün modellerin ve bütün anahtarlarınızın toplamıdır, yeni anahtar onu artırmaz. Ekim 2026 itibarıyla herkese açık LLM çıkarım sayfası bu kotayı 1 Kasım 2026'ya kadar 15 milyon token olarak gösteriyor, her gün 03:00'te (TSİ) yenilendiğini yazıyor ve hız sınırını da HTTP 429 diye anıyor. Kalan token her yanıtın x-evren-daily-remaining-tokens başlığında da gelir, bu yüzden başlık 0 iken beklemek sonucu değiştirmez. Başlığın biçimi belgede yazmadığı için aşağıdaki fonksiyon orada sayı göremezse dakikalık sınır varsayar ve en fazla üç kez dener. Fonksiyonu evren.php dosyasının sonuna ekleyin:
// 429: günlük kota ya da dakikalık sınır; 503: sunucu anlık dolu. Öteki hatalar yeniden denenmez.
function evren_dayanikli(string $yontem, string $yol, ?array $govde = null, int $enFazla = 3): array
{
for ($deneme = 1; ; $deneme++) {
try {
return evren($yontem, $yol, $govde);
} catch (ApiHatasi $e) {
$kalan = $e->basliklar['x-evren-daily-remaining-tokens'] ?? null;
if ($e->http === 429 && is_numeric($kalan) && (int) $kalan <= 0) {
throw new ApiHatasi('Günlük kota bitti, 03:00 (TSİ) sonrası yenilenir', 429, 'kota', $e->basliklar);
}
if (! in_array($e->http, [429, 503], true) || $deneme >= $enFazla) {
throw $e;
}
sleep($e->http === 429 ? 60 : 5 * $deneme); // belge: dakikalık sınırda bekleme en fazla 60 sn
}
}
}sleep() çağrıldığı süreci bekletir. Ziyaretçiye dönen bir sayfada 60 saniye beklemek yerine işi kuyruğa alın. Herkese açık LLM çıkarım sayfasına göre aynı anahtarla en fazla 32 istek aynı anda etkin olabilir, kuyruk işçilerinin sayısı bunu aşmamalı. Kuyruk ve devre kesici gibi genel önlemleri üçüncü parti API dayanıklılığı yazımızda anlattık. Kalan kotayı ve sıfırlanma zamanını GET /v1/quota da verir; belge bu ucun yanıt örneğini yayımlamadığı için fonksiyon başlığa bakar.
Çıktıdan kurulumun hangi adımda kaldığını bulun
Üç betik sorunsuz çalıştığında ilk.php çıktısının son satırı Token: … girdi + … çıktı olur. Bir yerde durursa istemcinin yazdığı satır dönülecek adımı gösterir.
Hata satırı ve dönülecek adım
Tablodaki her satır istemcinin kendi mesajıyla başlar:
| Çıktı | Anlamı | Dönülecek yer |
|---|---|---|
EVREN_API_KEY ortam değişkeni boş | PHP anahtarı görmüyor | Adım 1, aynı terminal penceresinde |
HTTP 403 ve Şartlar onaylanmamış olabilir | Şartlar onaylanmamış ya da yeni esaslı sürüm çıkmış; başka bir neden varsa sunucunun metni ipucundan önceki satırlardadır | Adım 3 |
HTTP 429 / HTTP 503 | Kota, dakikalık sınır ya da anlık doluluk | evren_dayanikli() (Adım 6); Günlük kota bitti derse 03:00 (TSİ) sonrası |
JSON olmayan yanıt | Gövde boş, yarım, araya giren bir vekil sunucunun HTML sayfası ya da istekte "stream": true | Taban adres, ağ çıkışı, istek gövdesi |
Bağlantı hatası: … timed out | Yanıt süre içinde gelmedi | $sure ya da max_tokens |
Bağlantı hatası: SSL certificate problem | php.ini'de CA dosyası tanımlı değil ya da tanımlı dosyada sunucunun kök sertifikası yok | php.ini'deki openssl.cafile ya da curl.cainfo satırı |
Sertifika hatası ve öteki 4xx kodları
PHP'nin curl eklentisi CA dosyasını önce openssl.cafile, o boşsa curl.cainfo satırından alır (eklentinin kaynak kodu). XAMPP 8.2.12 kurulumunda ikisi de apache\bin\curl-ca-bundle.crt dosyasını gösterir; ikisi de boşsa aynı HTTPS isteği sertifika hatasıyla durur. Başka bir 4xx kodunda istemci sunucunun metnini yazar. HTTP 401 kimlik bilgisinin kabul edilmediğini söyler, bakılacak yer anahtardır: yenilenen bir anahtarın eskisi kısa süre sonra devre dışı kalır. 400 ya da 404'te model kimliğini 4. adımdaki listeyle karşılaştırın.
Test ortamı: Kod PHP 8.2.12 (libcurl 8.4.0), CodeIgniter 4.7.4, Windows 10, PowerShell 5.1 ve Git Bash ile, belgedeki istek–yanıt örneklerini taklit eden yerel bir sunucuya karşı denendi; gerçek EVREN uç noktasına anahtarla istek atılmadı. HTTPS ve CA dosyası davranışı herkese açık bir adrese (repo.packagist.org) atılan GET isteğiyle denendi. Uç nokta adları, kota, eşzamanlılık ve hata kodları Modeller ve API sayfasına ve herkese açık LLM çıkarım sayfasına (Ekim 2026) göre yazıldı.
Anahtarı aldığınız gün terminalde önce sartlar.php betiğini çalıştırın; çıktıda Onaylandı: sürüm … ya da Şartlar zaten onaylı satırı görünmelidir. Ardından gelen ilk.php çıktısında sonraki kararı Yanıtlayan model satırı verir. Orada yazan kimlik birkaç denemede aynı kalıyor ve cevaplar işinize uyuyorsa auto yerinde kalabilir. Kimlik denemeden denemeye değişiyorsa ya da cevabın biçimi her seferinde aynı olmalıysa o kimliği model alanına sabitleyin. Bundan sonra cevabı her istekte sizin seçtiğiniz model üretir.
Sık sorulan sorular
EVREN API'si ücretli mi?
Ekim 2026 itibarıyla hayır: platform 1 Kasım 2026'ya kadar bütün çıkarım isteklerini kredi bakiyesinden bağımsız ve ücretsiz sunuyor. Günlük 15 milyon token kotası da bu tarihe kadar tanımlı. /v1/models yanıtındaki pricing alanı her modelin token fiyatını ve free_until tarihini gösterir.
PHP için OpenAI SDK'sı EVREN ile çalışır mı?
Çalışması gerekir: EVREN Bearer başlığını ve OpenAI sözleşmesini kabul eder, topluluğun openai-php/client paketi (0.21.0) de taban adresi withBaseUri() ile değiştirip anahtarı Bearer başlığıyla gönderir. Belge PHP örneği vermez; bu yol taklit sunucumuza karşı denendi ve sohbet isteği aynı yanıtı verdi.
EVREN API anahtarımı kaybettim, yeniden görebilir miyim?
Hayır. Anahtar oluşturulduğu anda bir kez gösterilir, API Anahtarları sayfası onu bir daha göstermez. Kayıp anahtarı yenilerseniz eskisi kısa süre sonra devre dışı kalır ve onunla çalışan uygulamalara yeni değeri girmeniz gerekir. Yeni anahtar oluşturmak günlük kotayı artırmaz.
OpenAI SDK'sında base_url ortam değişkeniyle verilebilir mi?
Python SDK'sında evet: base_url verilmezse OPENAI_BASE_URL, api_key verilmezse OPENAI_API_KEY ortam değişkeni okunur; ikisine EVREN'in adresini ve anahtarını yazmak yeter. openai-php/client ortamı kendisi okumaz, adres withBaseUri() ile kodda verilir; değeri getenv() ile ortamdan almak size kalır.
Yazan
Çılgın Yazılım
Ben Evren Çılgın; yazılım geliştirme, web teknolojileri ve sistem tasarımı alanlarında uzmanlaşmış bir geliştiriciyim. Uzun yıllardır hem frontend hem de backend tarafında üretken, ölçeklenebilir ve kullanıcı dostu çözümler üretiyorum.
Bu konuda bir projeniz mi var?
İhtiyacınızı birkaç cümleyle anlatın; uygun yaklaşımı birlikte belirleyelim.
İlgili yazılar
Yorumlar
Henüz yorum yok. Sorunuzu ya da deneyiminizi ilk siz yazın.
Yorum yazın
Yorumunuz onaylandıktan sonra yayınlanır. Ekibimiz gerekirse konuyla ilgili bir yanıt da paylaşır.
