Dolandırıcılık Modülü Yazma
Dolandırıcılık modülü, hiçbir şey kaydedilmeden önce sipariş denemesini inceler ve tek bir soruyu yanıtlar: ilerleyebilir mi.
Genel Bakış
Bir dolandırıcılık modülü FraudModule'ü genişletir ve coremio/modules/Fraud/{Ad}/{Ad}.php altında yaşar. Her şekilden bir tane gelir: WFraud yerel veriden puanlar, MaxMind denemeyi dış bir sağlayıcıya iletir.
Kapı bir kez, ödeme akışından, sipariş, fatura ya da hizmet yokken çalışır.
// Bu noktada hiçbir şey kalıcılaştırılmamıştır: engellenen bir deneme geriye
// ne sipariş, ne fatura, ne de hizmet bırakır.
if ($fraudError = \FraudModule::run_checks($this->fraud_payload($pricing, $pmethod, (float) $taxCalc['total'], $member)))
throw new \Exception($fraudError);
Bu kapının iki özelliği modülü nasıl yazacağınızı belirler:
- Fırlatan modül geçmiş sayılır, hata uyarı olarak loglanır.
- Engelleme, false dönüşü artı bir mesaj. Puan, inceleme durumu ya da kuyruk yoktur.
Ön Koşullar
- Yükün ne taşıdığını bilin; orada olmayanı kendiniz getirirsiniz.
- Uzaktan puanlıyorsanız bir sağlayıcı hesabı; yerel puanlıyorsanız ek bir şey gerekmez.
- Modül iskeleti: bkz. Modül Anatomisi.
- Tekrar tekrar verebileceğiniz bir test siparişi. Fazla engelleyen kural yalnız kayıtlar tablosunda görünür.
Yapı
Acme.php namespace WISECP\Modules\Fraud; class Acme extends FraudModule
config.php ['meta' => [...], 'status' => false, 'settings' => []]
lang/en.php
lang/tr.php
logo.png
run_checks() $row['config']['status'] true değilse modülü atlar; ayar ekranı da oraya yazar. meta altında sorunsuz kaydedilir ve hiç çağrılmaz.
Ayar ekranını siz kurmazsınız; onu taban birleştirir. Durum anahtarı kapalıyken bütün alanlar devre dışıdır.
Adım Adım
Sınıfı Bildirin
<?php
namespace WISECP\Modules\Fraud;
// Dosya bir ad alanı içindedir, yani her global sınıf import edilmeli ya da
// başına ters bölü konmalıdır. Nitelenmemiş bir ad bu ad alanının içine çözülür
// ve çalışma anında patlar; sözdizimi denetimi bunu yakalamaz.
use FraudModule;
use Language;
use User;
use UserManager;
class Acme extends FraudModule
{
public function check($params = []): bool
{
return true;
}
}
Ayar Alanlarını Bildirin
fields() alan tanımları döner. Anahtarlar: type, name, description, value, anahtar için checked, açılır liste için options. Güncel değerler $this->config['settings']'ten gelir.
Bozuk Kimlik Bilgisini Kaydetmeden Reddedin
save_fields() bildirirseniz kaydetme onu kalıcılaştırmadan önce çalıştırır. Açılmanın gerçek bir iş yapması gerekiyorsa activate() ve deactivate() bildirin.
Kuralı Yazın
Yükü okuyun ve karar verin. Engellerken sırayla: $this->error'ı çevrilmiş bir cümleye ayarlayın, insert_record() çağırın, false dönün.
İki Yönü de Doğrulayın
- Geçmesi gereken bir sipariş verin. Tamamlanır ve kayıtlar tablosu boş kalır.
- Engellenmesi gereken birini verin. Ödeme ekranı mesajınızı gösterir, hiçbir şey oluşmaz.
- Sağlayıcıyı yanlış bir anahtarla bozun. Sipariş yine tamamlanır ve log modülünüzün adını taşıyan bir uyarı içerir.
Referans
Taban Sınıfın Verdikleri
// Kapı. Ödeme akışı çağırır, bir modül asla çağırmaz.
public static function run_checks(array $params = []): string; // '' = devam, aksi hâlde mesaj
// Kayıtlar
public function insert_record($user_id = 0, $message = '', $ip = '');
public function records($rCount = false, $filters = [], $orders = [], $start = 0, $end = -1);
public function record_table(): WISECP\Components\Table|string;
// Ayar ekranı, sizin için birleştirilir
public function page_settings(): string;
public function save_config($data = []): int|bool;
// Yönetici controller'ları, operation=module_controller&controller={name} ile erişilir
public function controller_records(): string;
public function controller_save_settings(): array;
public function controller_clear_records(): array;
// Public durum
public ?string $error; // false döndüğünüzde müşterinin gördüğü mesaj
public ?array $config; // ['status' => bool, 'settings' => [...], 'meta' => [...]]
public ?array $lang;
public ?array $user; // giriş yapmış üye, yapıcıda çözülür
public ?array $admin;
public ?string $dir;
public string $url; // dikkat: komşularının aksine nullable değil
public ?string $area_link;
config['status']'ü true olan her modülü kayıt sırasıyla gezer, check metodu olmayanı atlar, ilk false'ta döner. Boş dize "ilerleyebilir" demektir.
fraud_detected_records'a modül adınız, kullanıcı id'si, gerekçeniz ve IP ile tek satır yazar. IP boşsa istek IP'si kullanılır.
setConfigureTab()'in eklediği sekmeler. Ezmeyin, geri çağrımı kullanın.
website/checkout/error-fraud'a düşer.
Sizin Bildirdikleriniz
// ZORUNLU. true = geçir, false = engelle ($this->error ayarlanmış olarak).
public function check($params = []): bool;
// İSTEĞE BAĞLI
public function fields(): array; // ayar formu tanımlayıcıları
public function save_fields($fields = []): array; // kalıcılaştırmadan önce doğrula
public function activate(): bool; // modülü açma
public function deactivate(): bool; // modülü kapatma
public function setConfigureTab(\WISECP\Components\Tab $obj): void; // ek ayar sekmeleri
Başarıda (gerekirse temizlenmiş) alan dizisini dönün; o config['settings'] olur. Başarısızlıkta ['status' => 'error', 'message' => '...'] dönün, kaydetme fırlatır.
$params İçinde Ne Var
Ödeme akışı bunu kapıdan hemen önce kurar; girdinin tamamı budur.
id, email, name, surname, full_name, phone, country, blacklist, company_name, identity, gsm_cc, gsm_number, ip, user_agent ve ayrıca address. Cep telefonu gsm_number'dır, gsm değil.
address, city, country_code, zipcode. Form yalnız ülke id'si gönderdiyse ülke kodu ondan çözülür.
user_data.id 0'dır ve kimlik gönderilen formdan gelir; yalnız email, name, surname ve full_name dolar. Profil alanları boş değil, hiç yoktur.
Money::Currency() ile çözün.
PayTR. MaxMind bunu payment-gateways tablosuyla kendi sözcüklerine eşler.
['items' => ['coupon' => [['name' => 'KOD'], ...]]]. Üç seviye iç içedir, kupon kullanılmadıysa hiç yoktur.
İki Şekil
| Yön | Yerel puanlama | Uzak puanlama |
|---|---|---|
| Referans | WFraud | MaxMind |
| Kurallar | Kara liste, IP ülkesine karşı fatura ülkesi, proxy ya da VPN | Tek sağlayıcı puanının eşikle karşılaştırılması |
| Ayarlar | Kural başına bir anahtar | Kimlik bilgileri, sağlayıcı katmanı, risk puanı, sağlayıcı anahtarları |
| Kimlik bilgisi | Yok | Zorunlu; save_fields()'te doğrulanır |
| Sipariş başına maliyet | Sıfır | Faturalanabilir bir API çağrısı |
Örnek
Anahtarı, eşiği ve kaydı olan bir kural. Sözleşme alan anahtarı: fields() bildirir, save_fields() doğrular, check() okur.
public function fields(): array
{
$settings = $this->config['settings'] ?? [];
return [
'api-key' => [
'wrap_width' => 100,
'type' => 'text',
'name' => $this->lang['api-key'] ?? 'API Key',
'value' => $settings['api-key'] ?? '',
],
'risk-score' => [
'wrap_width' => 100,
'width' => 15,
'type' => 'number',
'name' => $this->lang['risk-score'] ?? 'Risk Score',
'description' => $this->lang['risk-score-desc'] ?? '',
'value' => $settings['risk-score'] ?? '20',
],
'block-country-mismatch' => [
'wrap_width' => 100,
'type' => 'approval', // bir anahtar: 'value', kutu işaretliyken gönderilen değerdir
'name' => $this->lang['country-mismatch'] ?? 'Block country mismatch',
'value' => 1,
'checked' => $settings['block-country-mismatch'] ?? false,
],
];
}
public function save_fields($fields = []): array
{
// Burada reddetmek, modülün yarım yapılandırılmışken açılmayı geri çevirme yoludur.
if (\Validation::isEmpty($fields['api-key'] ?? ''))
return ['status' => "error", 'message' => $this->lang['error-is-empty'] ?? 'API key is required.'];
return $fields;
}
public function check($params = []): bool
{
$settings = $this->config['settings'] ?? [];
$user = (array) ($params['user_data'] ?? $this->user ?? []);
$ip = (string) ($user['ip'] ?? '');
$uid = (int) ($user['id'] ?? 0); // misafir denemesinde 0
// Her kural bağımsız olarak açılıp kapanır, yani değeri değil bayrağı okuyun.
if ((int) ($settings['block-country-mismatch'] ?? 0) === 1) {
$billing = strtoupper((string) ($user['address']['country_code'] ?? ''));
$origin = strtoupper((string) (UserManager::ip_info($ip)['countryCode'] ?? ''));
// Yalnız KESİN bir uyuşmazlık engeller. Aksi hâlde çözülemeyen bir IP ya da
// eksik bir fatura ülkesi, her yarım profili bir yanlış pozitife çevirirdi;
// burada bir yanlış pozitif ise kaybedilmiş bir satıştır.
if ($billing !== '' && $origin !== '' && $billing !== $origin) {
// Bunun için çekirdekte bir dize var; WFraud da aynı anahtarı kullanır.
$this->error = Language::gc("website/checkout/error-fraud-country");
$this->insert_record($uid, "IP country ({$origin}) does not match billing country ({$billing})", $ip);
return false;
}
}
// Uzak bir puan. Buradaki hiçbir hata engellememeli: kapı fırlatılan bir
// istisnayı geçiş sayar, bu erken dönüş de bozuk bir yanıt için aynısını yapar.
$score = $this->remote_score($params);
if ($score === null) return true;
if ($score >= (int) ($settings['risk-score'] ?? 20)) {
// Kendi ifadeniz SİZİN dil dosyanıza aittir. Language::gc(), çekirdekte
// olmayan bir anahtar için false döner; bu da $error'ı boş bırakır ve
// genel "güvenlik denetimlerimizden geçemedi" cümlesine düşülür.
$this->error = $this->lang['error-risk-score'] ?? 'Your order could not be approved automatically.';
$this->insert_record($uid, "Risk score {$score} reached the configured threshold", $ip);
return false;
}
return true;
}
// coremio/classes/FraudModule.php, run_checks()
foreach ($modules as $name => $row) {
if (!(bool) ($row['config']['status'] ?? false)) continue; // etkin değil: atlanır
try {
$module = Modules::getInstance("Fraud", (string) $name);
if (!$module || !method_exists($module, 'check')) continue;
if ($module->check($params) !== false) continue; // geçti: sonraki modül
$message = trim((string) ($module->error ?? ''));
return $message !== ''
? $message
: Language::gc("website/checkout/error-fraud", ['{module}' => (string) $name]);
}
catch (\Throwable $e) {
// Bir sağlayıcının çökmesi ödeme akışını da beraberinde çökertmemelidir.
Logger::warning("Fraud module '{$name}' check failed: " . $e->getMessage());
}
}
return ''; // etkin her modül geçti
Dönen dize, ödeme akışının fırlattığı istisnaya dönüşür; müşteri sizin $this->error'unuzu okur. Ayrıntıyı kayda bırakın.
Tuzaklar
Olumlu kanıt arayın: doğrulanmış uyuşmazlıkta engelleyin, eksik değerde asla. Buradaki hata, hiç verilmemiş siparişler olarak görünür.
Zaman aşımı dolandırıcılık kanıtı değildir. İstisna kaçsın ya da true dönün; kapı bir uyarı loglar ve sipariş geçer.
Dolandırıcılık modülleri ad alanı içindedir; çıplak bir UserManager::ip_info() WISECP\Modules\Fraud\UserManager'a çözülür ve patlar. Global sınıfları import edin ya da başına ters bölü koyun.
Misafir denemesinde user_data.id'ye dayanan kural ya çöker ya sessizce hiç çalışmaz.
Operatörün kapıya açılan tek penceresi kayıtlar sekmesidir. Kaydı olmayan bir engelleme, izsiz kaybolmuş bir sipariştir.
İ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.