<?php
// ========== НАСТРОЙКИ СМТП (ВАШ ДОМЕН) ==========
define('SMTP_HOST',   'smtp.yandex.ru');     // Ваш SMTP-сервер
define('SMTP_PORT',   465);                  // 465 (SSL) или 587 (TLS)
define('SMTP_SECURE', 'ssl');                // 'ssl' или 'tls'
define('SMTP_AUTH',   true);
define('SMTP_USER',   'no-reply@ваш-домен.ru');
define('SMTP_PASS',   'пароль_приложения');
define('FROM_EMAIL',  'no-reply@ваш-домен.ru');
define('FROM_NAME',   'Рассылка сайта');

// ========== ИНИЦИАЛИЗАЦИЯ SQLite ==========
$db_file = 'subscribers.db';
$pdo = new PDO("sqlite:$db_file");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Таблица подписчиков
$pdo->exec("CREATE TABLE IF NOT EXISTS subscribers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email TEXT UNIQUE NOT NULL,
    name TEXT,
    active INTEGER DEFAULT 1
)");

// Таблица очереди писем
$pdo->exec("CREATE TABLE IF NOT EXISTS mail_queue (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    to_email TEXT NOT NULL,
    to_name TEXT,
    subject TEXT,
    html_body TEXT,
    status TEXT DEFAULT 'pending',
    error TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)");

// ========== ОБРАБОТКА ДЕЙСТВИЙ ==========
$message = '';

// Добавление подписчика через форму
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_subscriber'])) {
    $email = trim($_POST['email']);
    $name = trim($_POST['name']);
    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
        try {
            $stmt = $pdo->prepare("INSERT INTO subscribers (email, name) VALUES (?, ?)");
            $stmt->execute([$email, $name]);
            $message = "✅ Подписчик $email добавлен";
        } catch (PDOException $e) {
            $message = "⚠️ Ошибка: email уже существует";
        }
    } else {
        $message = "❌ Неверный email";
    }
}

// Загрузка CSV
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] === UPLOAD_ERR_OK) {
    $file = fopen($_FILES['csv_file']['tmp_name'], 'r');
    $added = 0;
    while (($row = fgetcsv($file)) !== false) {
        $email = trim($row[0]);
        $name = isset($row[1]) ? trim($row[1]) : '';
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            try {
                $stmt = $pdo->prepare("INSERT OR IGNORE INTO subscribers (email, name) VALUES (?, ?)");
                $stmt->execute([$email, $name]);
                if ($stmt->rowCount()) $added++;
            } catch (Exception $e) {}
        }
    }
    fclose($file);
    $message = "📥 Импортировано $added подписчиков";
}

// Создание рассылки (постановка в очередь)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_campaign'])) {
    $subject = $_POST['subject'];
    $html = $_POST['html_content'];
    // Получаем всех активных подписчиков
    $subs = $pdo->query("SELECT email, name FROM subscribers WHERE active = 1")->fetchAll(PDO::FETCH_ASSOC);
    $queued = 0;
    $stmt = $pdo->prepare("INSERT INTO mail_queue (to_email, to_name, subject, html_body) VALUES (?, ?, ?, ?)");
    foreach ($subs as $sub) {
        $personalized = str_replace('{name}', htmlspecialchars($sub['name'] ?: 'друг'), $html);
        $stmt->execute([$sub['email'], $sub['name'], $subject, $personalized]);
        $queued++;
    }
    $message = "✉️ $queued писем поставлено в очередь";
}

// Принудительная отправка очереди (вызывается вручную или по cron)
if (isset($_GET['process_queue']) && $_GET['process_queue'] === '1') {
    $pending = $pdo->query("SELECT * FROM mail_queue WHERE status = 'pending' LIMIT 10")->fetchAll(PDO::FETCH_ASSOC);
    $sent = 0;
    foreach ($pending as $mail) {
        $result = smtp_send(
            $mail['to_email'],
            $mail['to_name'],
            $mail['subject'],
            $mail['html_body']
        );
        if ($result['success']) {
            $pdo->prepare("UPDATE mail_queue SET status = 'sent' WHERE id = ?")->execute([$mail['id']]);
            $sent++;
        } else {
            $pdo->prepare("UPDATE mail_queue SET status = 'failed', error = ? WHERE id = ?")->execute([$result['error'], $mail['id']]);
        }
    }
    $message = "📨 Отправлено $sent из " . count($pending) . " писем";
}

// Функция отправки через SMTP
function smtp_send($to, $to_name, $subject, $html_body) {
    $text_body = strip_tags($html_body);
    $boundary = md5(uniqid(time()));
    $headers = "MIME-Version: 1.0\r\n";
    $headers .= "From: " . FROM_NAME . " <" . FROM_EMAIL . ">\r\n";
    $headers .= "Reply-To: " . FROM_EMAIL . "\r\n";
    $headers .= "Content-Type: multipart/alternative; boundary=\"$boundary\"\r\n";

    $message = "--$boundary\r\n";
    $message .= "Content-Type: text/plain; charset=utf-8\r\n\r\n$text_body\r\n";
    $message .= "--$boundary\r\n";
    $message .= "Content-Type: text/html; charset=utf-8\r\n\r\n$html_body\r\n";
    $message .= "--$boundary--";

    $to_address = $to_name ? "$to_name <$to>" : $to;
    $subject_enc = '=?UTF-8?B?' . base64_encode($subject) . '?=';

    $host = SMTP_HOST;
    $port = SMTP_PORT;
    $secure = SMTP_SECURE;
    $user = SMTP_USER;
    $pass = SMTP_PASS;

    if ($secure === 'ssl') {
        $host = 'ssl://' . $host;
        $port = $port ?: 465;
    }
    $smtp = fsockopen($host, $port, $errno, $errstr, 30);
    if (!$smtp) return ['success' => false, 'error' => "Не удалось подключиться: $errstr"];

    $response = fgets($smtp, 515);
    if (substr($response, 0, 3) != '220') return ['success' => false, 'error' => "SMTP: $response"];

    fputs($smtp, "EHLO " . gethostname() . "\r\n");
    $response = fgets($smtp, 515);
    if (substr($response, 0, 3) != '250') return ['success' => false, 'error' => "EHLO: $response"];

    if ($secure === 'tls') {
        fputs($smtp, "STARTTLS\r\n");
        $response = fgets($smtp, 515);
        if (substr($response, 0, 3) != '220') return ['success' => false, 'error' => "STARTTLS: $response"];
        stream_socket_enable_crypto($smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
        fputs($smtp, "EHLO " . gethostname() . "\r\n");
        $response = fgets($smtp, 515);
    }

    if (SMTP_AUTH) {
        fputs($smtp, "AUTH LOGIN\r\n");
        $response = fgets($smtp, 515);
        if (substr($response, 0, 3) != '334') return ['success' => false, 'error' => "AUTH: $response"];
        fputs($smtp, base64_encode($user) . "\r\n");
        $response = fgets($smtp, 515);
        if (substr($response, 0, 3) != '334') return ['success' => false, 'error' => "USER: $response"];
        fputs($smtp, base64_encode($pass) . "\r\n");
        $response = fgets($smtp, 515);
        if (substr($response, 0, 3) != '235') return ['success' => false, 'error' => "PASS: $response"];
    }

    fputs($smtp, "MAIL FROM: <" . FROM_EMAIL . ">\r\n");
    $response = fgets($smtp, 515);
    if (substr($response, 0, 3) != '250') return ['success' => false, 'error' => "MAIL FROM: $response"];

    fputs($smtp, "RCPT TO: <$to>\r\n");
    $response = fgets($smtp, 515);
    if (substr($response, 0, 3) != '250') return ['success' => false, 'error' => "RCPT TO: $response"];

    fputs($smtp, "DATA\r\n");
    $response = fgets($smtp, 515);
    if (substr($response, 0, 3) != '354') return ['success' => false, 'error' => "DATA: $response"];

    fputs($smtp, "Subject: $subject_enc\r\n$headers\r\n$message\r\n.\r\n");
    $response = fgets($smtp, 515);
    if (substr($response, 0, 3) != '250') return ['success' => false, 'error' => "SEND: $response"];

    fputs($smtp, "QUIT\r\n");
    fclose($smtp);
    return ['success' => true, 'error' => null];
}

// Статистика для интерфейса
$subscribers_count = $pdo->query("SELECT COUNT(*) FROM subscribers WHERE active = 1")->fetchColumn();
$queue_count = $pdo->query("SELECT COUNT(*) FROM mail_queue WHERE status = 'pending'")->fetchColumn();
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Email рассыльщик — ваш домен</title>
    <style>
        * { box-sizing: border-box; font-family: system-ui, 'Segoe UI', Roboto, sans-serif; }
        body { background: #f1f5f9; margin: 0; padding: 20px; }
        .container { max-width: 1200px; margin: 0 auto; }
        .card { background: white; border-radius: 24px; padding: 24px; margin-bottom: 24px; box-shadow: 0 8px 20px rgba(0,0,0,0.05); }
        h1, h2 { margin-top: 0; color: #0f172a; }
        .stats { display: flex; gap: 20px; margin-bottom: 24px; flex-wrap: wrap; }
        .stat { background: white; border-radius: 20px; padding: 20px; flex: 1; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
        .stat-number { font-size: 2.5rem; font-weight: bold; color: #3b82f6; }
        .stat-label { color: #475569; margin-top: 8px; }
        .btn { background: #3b82f6; color: white; border: none; padding: 10px 20px; border-radius: 40px; cursor: pointer; font-weight: 600; transition: 0.2s; }
        .btn:hover { background: #2563eb; }
        .btn-outline { background: white; border: 1px solid #cbd5e1; color: #1e293b; }
        .btn-outline:hover { background: #f8fafc; }
        input, textarea, .file-label { width: 100%; padding: 12px; border: 1px solid #cbd5e1; border-radius: 16px; margin-top: 8px; margin-bottom: 16px; font-size: 1rem; }
        textarea { font-family: monospace; }
        .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
        .message { background: #e0f2fe; padding: 12px; border-radius: 16px; margin-bottom: 20px; }
        hr { margin: 24px 0; border: none; border-top: 1px solid #e2e8f0; }
        table { width: 100%; border-collapse: collapse; }
        th, td { text-align: left; padding: 12px; border-bottom: 1px solid #e2e8f0; }
        th { background: #f8fafc; }
        .badge { background: #f1f5f9; padding: 4px 10px; border-radius: 40px; font-size: 0.8rem; }
    </style>
</head>
<body>
<div class="container">
    <div class="card">
        <h1>📧 Рассыльщик на вашем домене</h1>
        <p>Работает через ваш SMTP (<strong><?= htmlspecialchars(SMTP_HOST) ?></strong>). Письма подписываются DKIM/SPF, если вы настроили DNS.</p>
        <div class="stats">
            <div class="stat"><div class="stat-number"><?= $subscribers_count ?></div><div class="stat-label">Активных подписчиков</div></div>
            <div class="stat"><div class="stat-number"><?= $queue_count ?></div><div class="stat-label">Писем в очереди</div></div>
            <div class="stat"><div class="stat-number"><a href="?process_queue=1" class="btn btn-outline" style="text-decoration:none;">▶️ Отправить 10</a></div><div class="stat-label">Запустить очередь вручную</div></div>
        </div>
        <?php if ($message): ?><div class="message"><?= $message ?></div><?php endif; ?>
    </div>

    <div class="grid-2">
        <!-- Управление подписчиками -->
        <div class="card">
            <h2>📋 Подписчики</h2>
            <form method="POST" enctype="multipart/form-data">
                <label>CSV файл (email,name)</label>
                <input type="file" name="csv_file" accept=".csv">
                <button type="submit" class="btn">📤 Импортировать CSV</button>
            </form>
            <hr>
            <form method="POST">
                <input type="email" name="email" placeholder="Email" required>
                <input type="text" name="name" placeholder="Имя (необязательно)">
                <button type="submit" name="add_subscriber" class="btn">➕ Добавить подписчика</button>
            </form>
            <hr>
            <div style="max-height: 300px; overflow-y: auto;">
                <table>
                    <thead><tr><th>Email</th><th>Имя</th></tr></thead>
                    <tbody>
                        <?php
                        $subs = $pdo->query("SELECT email, name FROM subscribers WHERE active = 1 LIMIT 20")->fetchAll();
                        foreach ($subs as $s): ?>
                        <tr><td><?= htmlspecialchars($s['email']) ?></td><td><?= htmlspecialchars($s['name']) ?></td></tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>

        <!-- Создание рассылки -->
        <div class="card">
            <h2>✍️ Новая рассылка</h2>
            <form method="POST">
                <input type="text" name="subject" placeholder="Тема письма" required>
                <textarea name="html_content" rows="10" placeholder="HTML-содержимое письма. Можно использовать {name} для подстановки имени." required></textarea>
                <button type="submit" name="create_campaign" class="btn">🚀 Поставить в очередь (всем подписчикам)</button>
            </form>
            <div class="badge" style="margin-top: 16px;">💡 Совет: используйте переменную <code>{name}</code> — она заменится на имя подписчика.</div>
        </div>
    </div>

    <!-- Лог последних отправленных писем -->
    <div class="card">
        <h2>📜 Последние письма (очередь)</h2>
        <table style="width:100%">
            <thead><tr><th>Кому</th><th>Тема</th><th>Статус</th><th>Ошибка</th></tr></thead>
            <tbody>
                <?php
                $logs = $pdo->query("SELECT to_email, subject, status, error FROM mail_queue ORDER BY id DESC LIMIT 15")->fetchAll();
                foreach ($logs as $log): ?>
                <tr>
                    <td><?= htmlspecialchars($log['to_email']) ?></td>
                    <td><?= htmlspecialchars($log['subject']) ?></td>
                    <td><?= $log['status'] === 'sent' ? '✅ Отправлено' : ($log['status'] === 'pending' ? '⏳ В очереди' : '❌ Ошибка') ?></td>
                    <td><?= htmlspecialchars($log['error']) ?></td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        <p class="badge" style="margin-top: 12px;">🔁 Очередь обрабатывается автоматически при заходе на страницу ?process_queue=1 или вы можете настроить CRON: <code>wget -q -O /dev/null "https://ваш-домен/index.php?process_queue=1"</code></p>
    </div>
</div>
</body>
</html>
Прокрутить вверх