IP Modülü Yazma
Bir konum ve proxy tespiti sağlayıcısını, ürünün ziyaretçinin yerini ve adresin riskini sorduğu tek noktaya bağlayın.
Genel Bakış
Bir IP modülü bir adres hakkında iki soruyu yanıtlar. Nerede, ve proxy mi? Aynı anda tek modül etkindir; seçim modules/ip altında saklanır. Diğer her şey bunu UserManager::ip_info() ve UserManager::is_proxy() üzerinden okur.
Bu cevaplar uzağa uzanır. Para birimi ülke kodundan seçilir, giriş akışı ülkesi değişen oturumu doğrulatır, formlar proxy'yi reddedebilir.
İki modül gelir: WAtlas ve ip_api. Taban sınıf yoktur; sözleşme çağrı noktasının kendisidir.
Ön Koşullar
- IPv4 ya da IPv6 adresini en azından bir ISO ülke koduna çözen bir sağlayıcı. O alanın yedeği yoktur.
- Sağlayıcıya dışa HTTP erişimi ve hız sınırı planı.
- Modül Anatomisi ve Modül Yapılandırması.
Yapı
coremio/modules/IP/AcmeGeo/
├── AcmeGeo.php AcmeGeo sınıfı (taban sınıf yok, ad alanı gerekmez)
├── config.php ['website' => 'AcmeGeo', 'key' => '']
└── pages/
└── settings.php kimlik bilgisi alanları, Ayarlar içinde render edilir
info() çağırıp önbelleğe alır.
proxy() bildirilmişse çağırır, sonra beyaz listeyi uygular.
new kullanılmaz.
pages/settings.php parçasını Ayarlar ekranına yerleştirir.
Adım Adım
1. Modül İskeletini Kurun
coremio/modules/IP/AcmeGeo/dizininiAcmeGeo.phpile açın. Sınıf adı klasörle aynı olmalı.config.phpyazın. Açılır listewebsiteanahtarını kullanır.- Ayar alanlarınızı boş anahtarlar olarak ekleyin.
2. info() Metodunu Uygulayın
- Size verilen adresle sağlayıcınızı çağırın; çekirdek adresi zaten çözdü.
- Cevabı normalize edin. İki kural zorunlu:
countryCodeküçük harf, sağlayıcı yalnız bölge verse bilecitydolu. - Başarısızlıkta
$this->erroryazın ve false döndürün.
3. proxy() Metodunu Uygulayın ya da Uygulamayın
- Metot isteğe bağlıdır. Yalnız konum çözen bir modül onsuz da tamamdır; proxy engelleme o zaman karar üretmez.
- İki anahtar benzer görünür:
proxy"proxy'ye benziyor",result"bunu engelle" demektir. Yalnızresultbir şeyi durdurur. - Otonom sistemi
asanahtarındaAS15169 Example Orgbiçiminde döndürün; beyaz liste ilk parçayla eşleşir.
4. Ayarlar Sayfasını Ekleyin
pages/settings.phpoluşturun: form değil, Ayarlar formuna eklenen düz bir parça.- Her girdiyi
ip_api_config[anahtar]olarak adlandırın; ad doğrudan config anahtarıdır. - Mevcut değerleri
$module->configüzerinden okuyun. - Ayarlar'da modülünüzü seçin ve kaydedin. Seçim
modules/ipanahtarına düşer.
Referans
İki Metot
Uygulanacak bir arayüz yoktur. Aşağıdakiler tam olarak çağrı noktalarıdır.
public $error; // false dönüşünden sonra çekirdek tarafından okunur
public $config = []; // yapıcıda modülün config.php dosyasından doldurulur
public function __construct();
// Konum. ZORUNLU. Aşağıdaki diziyi döndürün, ya da $this->error dolu olarak false.
// classes/UserManager.php içindeki UserManager::ip_info() metodundan çağrılır.
public function info($ip = '');
// Risk puanlama. İSTEĞE BAĞLI - çekirdek çağırmadan önce method_exists() ile yoklar.
// classes/UserManager.php içindeki UserManager::is_proxy() metodundan çağrılır.
public function proxy($ip = '');
// classes/UserManager.php, ip_info()
$ip_module = Config::get("modules/ip");
$obj = Modules::getInstance("IP", $ip_module);
if (!$obj) return ['status' => "error", 'message' => "IP module '{$ip_module}' could not be loaded."];
$result = $obj->info($ip);
if (!$result) {
// Zaman aşımı düz bir false olarak yutulur; başka her şey loglanır ve yüzeye çıkarılır.
if (stristr($obj->error, 'timed out')) return false;
Modules::save_log("IP", $ip_module, "check", $ip, $obj->error);
return ['status' => "error", 'message' => $obj->error];
}
// classes/UserManager.php, is_proxy()
$proxy_obj = Modules::getInstance("IP", $ip_module);
if ($proxy_obj && method_exists($proxy_obj, 'proxy')) {
$pdata = $proxy_obj->proxy($ip);
if ($pdata === false) $error = $proxy_obj->error;
}
info() Ne Döndürür
Tüketicilerin okuduğu anahtarlar, bekledikleri biçimle.
| Anahtar | Biçim | Kim okur |
|---|---|---|
countryCode | küçük harf ISO kodu, örn. nl | Para birimi ve konum denetimi. Yoksa sorgu başarısız. |
city | şehir, yoksa bölge adı | Şehir hassasiyetinde konum denetimi. |
regionName | bölge ya da eyalet adı | Gösterim; çoğu modül city içine kopyalar. |
country | İngilizce ülke adı | Gösterim. |
as | AS15169 Example Org | Proxy beyaz listesi, ilk parça. |
query | sorgulanan adres | Girdinin yankısı. |
zip, lat, lon, timezone, isp | dize ya da sayı | Opsiyonel; saklanır, zorunlu değildir. |
Çağıranlar boş countryCode değerini "bilinmiyor" sayar; ama dolu dizi yine başarılı sorgu sayılıp önbelleğe alınır. Arıza, dosya silinene kadar o adrese yapışır.
proxy() Ne Döndürür
Ayrıntılı biçim yalnız üç boolean döndürür:
// Üçüncü argüman true, çıplak karar yerine ayrıntılı dökümü ister.
$verdict = UserManager::is_proxy($ip, false, true);
// ['proxy' => bool, 'hosting' => bool, 'risky' => bool]
// 'risky' sizin 'result' değerinizdir, operatörün beyaz listesi uygulandıktan sonra.
// Giriş ve kayıt kapılarının kullandığı yaygın biçim:
if (Config::get('options/proxy-block') && UserManager::is_proxy() === true)
throw new Exception(Language::g('errors/error9'));
Önbellek ve Kota
Çekirdek sağlayıcınızı siz kod çalıştırmadan önce korur. Bir düzeltmenin etkisiz görünmesinin sebebi de bu dosyalardır.
info() sonucu, adres başına, süresiz.
proxy() için aynısı. Bir adresi yeniden denerken ikisini de silin.
ip_info() hata dizisi döner ve sizi çağırmaz. options/ip-overload-limit, varsayılan 2000; 0 sınırı kaldırır.
options/proxy-overload-limit, varsayılan 100.
Ayarlar Sözleşmesi
$v["config"]["website"] değerinden. Anahtar yoksa seçenek boş görünür.
operations/AdminGeneralSettings.php).
Örnek
Eksiksiz bir modül, ayarlar parçası ve tüketici tarafı.
<?php
class AcmeGeo
{
public $error;
public $config = [];
public function __construct()
{
$this->config = Modules::Config("IP", __CLASS__);
}
public function info($ip = '')
{
$this->error = null;
$key = (string) ($this->config["key"] ?? '');
$url = "https://api.acmegeo.example/v1/lookup/" . rawurlencode($ip);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: " . $key]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
$this->error = curl_error($ch);
$response = false;
}
curl_close($ch);
if ($response === false) return false;
$data = Utility::jdecode((string) $response, true);
if (!is_array($data)) {
$this->error = "Invalid response from AcmeGeo.";
return false;
}
// Ülke yoksa kullanılabilir cevap da yok. Burada dolu bir dizi döndürmek başarı
// sayılıp önbelleğe alınır ve dosya silinene dek o adres bozuk kalır.
$iso = (string) ($data["country_code"] ?? '');
if (!$iso) {
$this->error = "Country code not found : " . $ip;
return false;
}
$region = (string) ($data["region"] ?? '');
$city = (string) ($data["city"] ?? '');
return [
'status' => "success",
'query' => (string) ($data["ip"] ?? $ip),
'countryCode' => strtolower($iso), // küçük harf zorunludur
'country' => (string) ($data["country_name"] ?? ''),
'regionName' => $region ?: $city,
'city' => $city ?: $region, // city alanını asla boş bırakmayın
'zip' => (string) ($data["postal"] ?? ''),
'lat' => $data["latitude"] ?? '',
'lon' => $data["longitude"] ?? '',
'timezone' => (string) ($data["time_zone"] ?? ''),
'as' => isset($data["asn"]) ? trim("AS" . $data["asn"] . " " . ($data["asn_org"] ?? '')) : '',
];
}
public function proxy($ip = '')
{
$this->error = null;
$ch = curl_init("https://api.acmegeo.example/v1/risk/" . rawurlencode($ip));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: " . (string) ($this->config["key"] ?? '')]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
$this->error = curl_error($ch);
$response = false;
}
curl_close($ch);
if ($response === false) return false;
$data = Utility::jdecode((string) $response, true);
if (!is_array($data)) {
$this->error = "AcmeGeo risk lookup failed.";
return false;
}
$score = (int) ($data["score"] ?? 0);
return [
// 'result' engeller, 'proxy' yalnız tanımlar. İkisini birleştirmeyin.
'result' => $score >= 60,
'proxy' => $score >= 30,
'hosting' => (bool) ($data["datacenter"] ?? false),
'score' => $score,
'as' => isset($data["asn"]) ? trim("AS" . $data["asn"] . " " . ($data["asn_org"] ?? '')) : '',
];
}
}
<?php
return [
'website' => "AcmeGeo", // Ayarlar açılır listesinin gösterdiği etiket
'key' => '', // kayıt yolu tarafından geri yazılır, asla elle değil
];
<div class="row mb-3 pb-3 pt-3 border-bottom">
<label for="acmegeo_key" class="col-sm-1 col-form-label text-sm-end">
<span class="d-block fw-semibold">Api Key</span>
</label>
<div class="col-sm-11">
<!-- Ad, config anahtarıdır: ip_api_config[key] config.php dosyasına 'key' olarak düşer. -->
<input type="text" class="form-control" id="acmegeo_key"
name="ip_api_config[key]"
value="<?php echo $module->config["key"] ?? ''; ?>">
</div>
</div>
// helpers/Money.php - ziyaretçinin para birimi ülke kodundan gelir.
$info = UserManager::ip_info();
// Günlük kota tükendiğinde ya da modül yüklenemediğinde ip_info() ayrıca
// ['status' => 'error', 'message' => ...] döndürür: dolu, ama countryCode yok. Null-güvenli okuyun.
$needle = strtoupper($info["countryCode"] ?? '');
// classes/Auth.php - giriş konum denetimi, ülke ya da şehir hassasiyetinde.
$country = is_array($info) ? (string) ($info['countryCode'] ?? '') : '';
$city = is_array($info) ? (string) ($info['city'] ?? '') : '';
if ($country === '') return false; // ulaşılamayan bir sorgu asla değişiklik sayılmaz
Tuzaklar
Sağlama, ödeme ve servis sağlayıcı modülleri hata fırlatır ve çağıranları yakalar. Buradaki iki giriş noktası yakalamaz: boş bir dönüş arar, sonra $this->error okur. info() içinde doğan bir hata küresel işleyiciye kaçar. Özelliği yazın, false döndürün.
Bu sorgular sıradan isteklerin içinde çalışır. Hazır modüller iki ile on saniye arası kullanır. İçinde "timed out" ya da "timeout" geçen mesaj bilerek false olarak yutulur.
Adres başına önbellek dosyalarının süresi yoktur, yani ilk çağrıdan sonra yeni kodunuza o adres için hiç ulaşılmaz. Ölçmeden önce iki dosyayı da silin.
Ödeme yöntemlerinin aksine bu, modules/ip altında saklanan tekil bir seçimdir. Modülünüzü kurmak hiçbir şeyi açmaz; önce operatörün onu seçmesi gerekir.
İlgili Makaleler
Geri bildiriminiz için teşekkürler!
Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.