/** * HKS Landing Page Plugin - Dynamic & Secure * * @package HKS_Landing * @version 2.0.0 * @author Hakan Hoca * * Security Features: * - CSRF Protection (WordPress Nonces) * - SQL Injection Prevention (Prepared Statements) * - XSS Protection (Data Sanitization) * - Rate Limiting * - Honeypot Field * - IP Logging * * Clean Code: * - PSR-12 Standards * - Single Responsibility Principle * - DRY (Don't Repeat Yourself) * - Modular Architecture */ /* Plugin Name: HKS Landing Page Dynamic Description: Dinamik, güvenli ve clean code ile yazılmış landing page sistemi Version: 2.0.0 Author: Hakan Hoca Text Domain: hks-landing */ if (!defined('ABSPATH')) { exit; // Doğrudan erişimi engelle } /** * Main Plugin Class */ class HKS_Landing_Plugin { /** * Plugin version */ private const VERSION = '2.0.0'; /** * Database table name */ private const TABLE_NAME = 'hks_applications'; /** * Nonce action */ private const NONCE_ACTION = 'hks_form_submit'; /** * Rate limit: max submissions per IP per hour */ private const RATE_LIMIT = 5; /** * Singleton instance */ private static $instance = null; /** * Get singleton instance */ public static function get_instance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { $this->init_hooks(); } /** * Initialize WordPress hooks */ private function init_hooks() { register_activation_hook(__FILE__, [$this, 'activate']); register_deactivation_hook(__FILE__, [$this, 'deactivate']); add_action('wp_ajax_hks_submit_form', [$this, 'handle_form_submission']); add_action('wp_ajax_nopriv_hks_submit_form', [$this, 'handle_form_submission']); add_action('admin_menu', [$this, 'add_admin_menu']); add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts']); add_shortcode('hks_landing', [$this, 'render_landing_page']); } /** * Plugin activation */ public function activate() { $this->create_database_table(); $this->set_default_options(); flush_rewrite_rules(); } /** * Plugin deactivation */ public function deactivate() { flush_rewrite_rules(); } /** * Create database table */ private function create_database_table() { global $wpdb; $table_name = $wpdb->prefix . self::TABLE_NAME; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS {$table_name} ( id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, phone varchar(50) NOT NULL, exam varchar(50) NOT NULL, field varchar(50) NOT NULL, target_score int(3) NOT NULL, daily_hours decimal(3,1) NOT NULL, message text, ip_address varchar(45) NOT NULL, user_agent text, status varchar(20) DEFAULT 'pending', created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY ip_address (ip_address), KEY created_at (created_at), KEY status (status) ) {$charset_collate};"; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta($sql); } /** * Set default options */ private function set_default_options() { $defaults = [ 'hks_whatsapp_number' => '905052991316', 'hks_enable_notifications' => '1', 'hks_notification_email' => get_option('admin_email'), 'hks_recaptcha_site_key' => '', 'hks_recaptcha_secret_key' => '', ]; foreach ($defaults as $key => $value) { if (get_option($key) === false) { add_option($key, $value); } } } /** * Handle form submission via AJAX */ public function handle_form_submission() { try { // Security: Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], self::NONCE_ACTION)) { throw new Exception('Güvenlik doğrulaması başarısız.'); } // Security: Check honeypot if (!empty($_POST['website'])) { throw new Exception('Bot tespit edildi.'); } // Security: Verify reCAPTCHA v3 if configured $this->verify_recaptcha_token($_POST['recaptcha_token'] ?? ''); // Security: Rate limiting $this->check_rate_limit(); // Validate and sanitize input $data = $this->validate_and_sanitize_input($_POST); // Save to database $application_id = $this->save_application($data); // Send notification $this->send_notification($data, $application_id); // Success response wp_send_json_success([ 'message' => 'Başvurunuz alındı! En kısa sürede WhatsApp\'tan dönüş yapacağım.', 'application_id' => $application_id, ]); } catch (Exception $e) { // Error response wp_send_json_error([ 'message' => $e->getMessage(), ]); } } /** * Check rate limit */ private function check_rate_limit() { global $wpdb; $ip = $this->get_client_ip(); $table_name = $wpdb->prefix . self::TABLE_NAME; $one_hour_ago = date('Y-m-d H:i:s', strtotime('-1 hour')); $count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE ip_address = %s AND created_at > %s", $ip, $one_hour_ago )); if ($count >= self::RATE_LIMIT) { throw new Exception('Çok fazla başvuru yaptınız. Lütfen 1 saat sonra tekrar deneyin.'); } } /** * Validate and sanitize input */ private function validate_and_sanitize_input($post_data) { $data = []; // Name validation if (empty($post_data['name'])) { throw new Exception('Ad Soyad alanı zorunludur.'); } $data['name'] = sanitize_text_field($post_data['name']); // Phone validation if (empty($post_data['phone'])) { throw new Exception('Telefon alanı zorunludur.'); } $phone = sanitize_text_field($post_data['phone']); if (!preg_match('/^[0-9\s\+\-\(\)]+$/', $phone)) { throw new Exception('Geçersiz telefon numarası.'); } $data['phone'] = $phone; // Exam validation if (empty($post_data['exam']) || !in_array($post_data['exam'], ['yokdil', 'yds'])) { throw new Exception('Geçersiz sınav seçimi.'); } $data['exam'] = sanitize_text_field($post_data['exam']); // Field validation if (empty($post_data['field']) || !in_array($post_data['field'], ['saglik', 'fen', 'sosyal'])) { throw new Exception('Geçersiz alan seçimi.'); } $data['field'] = sanitize_text_field($post_data['field']); // Target score validation $target = intval($post_data['target']); if ($target < 50 || $target > 100) { throw new Exception('Hedef puan 50-100 arasında olmalıdır.'); } $data['target_score'] = $target; // Daily hours validation $daily = floatval($post_data['daily']); if ($daily < 1 || $daily > 10) { throw new Exception('Günlük çalışma süresi 1-10 saat arasında olmalıdır.'); } $data['daily_hours'] = $daily; // Message (optional) $data['message'] = !empty($post_data['message']) ? sanitize_textarea_field($post_data['message']) : ''; // Additional data $data['ip_address'] = $this->get_client_ip(); $data['user_agent'] = sanitize_text_field($_SERVER['HTTP_USER_AGENT'] ?? ''); return $data; } /** * Save application to database */ private function save_application($data) { global $wpdb; $table_name = $wpdb->prefix . self::TABLE_NAME; $result = $wpdb->insert( $table_name, $data, [ '%s', // name '%s', // phone '%s', // exam '%s', // field '%d', // target_score '%f', // daily_hours '%s', // message '%s', // ip_address '%s', // user_agent ] ); if ($result === false) { throw new Exception('Veritabanı hatası. Lütfen tekrar deneyin.'); } return $wpdb->insert_id; } /** * Send notification email */ private function send_notification($data, $application_id) { if (get_option('hks_enable_notifications') !== '1') { return; } $to = get_option('hks_notification_email'); $subject = 'Yeni HKS Başvurusu - ' . $data['name']; $message = "Yeni bir başvuru alındı:\n\n"; $message .= "Başvuru ID: {$application_id}\n"; $message .= "Ad Soyad: {$data['name']}\n"; $message .= "Telefon: {$data['phone']}\n"; $message .= "Sınav: " . strtoupper($data['exam']) . "\n"; $message .= "Alan: " . ucfirst($data['field']) . "\n"; $message .= "Hedef Puan: {$data['target_score']}\n"; $message .= "Günlük Süre: {$data['daily_hours']} saat\n"; if (!empty($data['message'])) { $message .= "Mesaj: {$data['message']}\n"; } $message .= "\nIP: {$data['ip_address']}\n"; $message .= "Tarih: " . date('d.m.Y H:i') . "\n"; wp_mail($to, $subject, $message); } /** * Get client IP address */ private function get_client_ip() { $ip_keys = [ 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR' ]; foreach ($ip_keys as $key) { if (array_key_exists($key, $_SERVER) === true) { foreach (explode(',', $_SERVER[$key]) as $ip) { $ip = trim($ip); if (filter_var($ip, FILTER_VALIDATE_IP) !== false) { return $ip; } } } } return '0.0.0.0'; } /** * Add admin menu */ public function add_admin_menu() { add_menu_page( 'HKS Başvurular', 'HKS Başvurular', 'manage_options', 'hks-applications', [$this, 'render_admin_page'], 'dashicons-welcome-learn-more', 30 ); add_submenu_page( 'hks-applications', 'HKS Ayarlar', 'Ayarlar', 'manage_options', 'hks-settings', [$this, 'render_settings_page'] ); } /** * Render admin page */ public function render_admin_page() { global $wpdb; $table_name = $wpdb->prefix . self::TABLE_NAME; // Handle status update if (isset($_POST['update_status']) && isset($_POST['application_id'])) { check_admin_referer('hks_update_status'); $application_id = intval($_POST['application_id']); $status = sanitize_text_field($_POST['status']); $wpdb->update( $table_name, ['status' => $status], ['id' => $application_id], ['%s'], ['%d'] ); echo '

Durum güncellendi.

'; } // Get applications $applications = $wpdb->get_results( "SELECT * FROM {$table_name} ORDER BY created_at DESC LIMIT 100" ); include plugin_dir_path(__FILE__) . 'admin/applications.php'; } /** * Render settings page */ public function render_settings_page() { if (isset($_POST['save_settings'])) { check_admin_referer('hks_save_settings'); update_option('hks_whatsapp_number', sanitize_text_field($_POST['whatsapp_number'])); update_option('hks_enable_notifications', isset($_POST['enable_notifications']) ? '1' : '0'); update_option('hks_notification_email', sanitize_email($_POST['notification_email'])); update_option('hks_recaptcha_site_key', sanitize_text_field($_POST['recaptcha_site_key'])); update_option('hks_recaptcha_secret_key', sanitize_text_field($_POST['recaptcha_secret_key'])); echo '

Ayarlar kaydedildi.

'; } include plugin_dir_path(__FILE__) . 'admin/settings.php'; } /** * Enqueue scripts */ public function enqueue_scripts() { if (is_page() && has_shortcode(get_post()->post_content, 'hks_landing')) { $recaptcha_site_key = get_option('hks_recaptcha_site_key'); if (!empty($recaptcha_site_key)) { wp_enqueue_script( 'hks-recaptcha', 'https://www.google.com/recaptcha/api.js?render=' . urlencode($recaptcha_site_key), [], null, true ); } wp_enqueue_script( 'hks-landing-js', plugin_dir_url(__FILE__) . 'assets/js/hks-landing.js', ['jquery'], self::VERSION, true ); wp_localize_script('hks-landing-js', 'hksAjax', [ 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce(self::NONCE_ACTION), 'whatsapp' => get_option('hks_whatsapp_number', '905052991316'), 'recaptchaSiteKey' => $recaptcha_site_key, ]); } } /** * Verify reCAPTCHA token */ private function verify_recaptcha_token($token) { $secret = get_option('hks_recaptcha_secret_key'); if (empty($secret)) { return; } if (empty($token)) { throw new Exception('Güvenlik doğrulaması eksik.'); } $response = wp_remote_post('https://www.google.com/recaptcha/api/siteverify', [ 'timeout' => 10, 'body' => [ 'secret' => $secret, 'response' => $token, 'remoteip' => $this->get_client_ip(), ], ]); if (is_wp_error($response)) { throw new Exception('Güvenlik doğrulaması başarısız.'); } $data = json_decode(wp_remote_retrieve_body($response), true); $score = isset($data['score']) ? (float) $data['score'] : 0.0; $success = isset($data['success']) ? (bool) $data['success'] : false; if (!$success || $score < 0.5) { throw new Exception('Güvenlik doğrulaması başarısız.'); } } /** * Render landing page */ public function render_landing_page($atts) { ob_start(); include plugin_dir_path(__FILE__) . 'templates/landing-page.php'; return ob_get_clean(); } } // Initialize plugin HKS_Landing_Plugin::get_instance();