PHP методы отслеживания кликов в email-письмах: подробное руководство

Раздел: Email-маркетинг -> Email-маркетинг

Основной метод: скрипт-редирект с реляционной базой данных

Для достоверного учета переходов по ссылкам из писем применяется архитектура, при которой все ссылки в письме заменяются на адрес PHP-скрипта, который записывает событие в базу и затем перенаправляет пользователя на целевой ресурс. База данных обеспечивает структурированное хранение и возможность дальнейшего анализа.

Создание таблицы click_log:


CREATE TABLE click_log (
  id INT AUTO_INCREMENT PRIMARY KEY,
  campaign_id VARCHAR(50) NOT NULL,
  subscriber_id VARCHAR(100) NOT NULL,
  url TEXT NOT NULL,
  clicked_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  ip_address VARCHAR(45) NOT NULL,
  user_agent TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Pub mail click php (отслеживание кликов в почтовых рассылках php)

Генерация ссылки в письме (пример с использованием base64 и подписи):


$data = $campaign_id . '|' . $subscriber_id . '|' . $target_url;
$token = hash_hmac('sha256', $data, SECRET_KEY);
$encoded_url = base64_encode($target_url);
$link = "https://example.com/track.php?c=$campaign_id&s=$subscriber_id&u=$encoded_url&t=$token";

Обработка в track.php:


$campaign_id = $_GET['c'];
$subscriber_id = $_GET['s'];
$url = base64_decode($_GET['u']);
$token = $_GET['t'];
$expected = hash_hmac('sha256', $campaign_id.'|'.$subscriber_id.'|'.$url, SECRET_KEY);
if (!hash_equals($expected, $token)) die('Invalid link');
$stmt = $pdo->prepare('INSERT INTO click_log (campaign_id,subscriber_id,url,ip_address,user_agent) VALUES (?,?,?,?,?)');
$stmt->execute([$campaign_id, $subscriber_id, $url, $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']]);
header('Location: '.$url);
exit;

Проблема: Если база данных недоступна, пользователь не будет перенаправлен. Решение: использовать транзакцию или сначала записывать в очередь, а затем в БД асинхронно. Другая проблема: производительность при высокой нагрузке. Решение: использовать пул соединений или репликацию.

Как записывать клики в файл без использования базы данных?

Для небольших проектов или временного мониторинга можно вести лог в текстовом файле. Каждый клик дописывается новой строкой.


$timestamp = date('Y-m-d H:i:s');
$line = implode('|', [$timestamp, $subscriber_id, $url, $_SERVER['REMOTE_ADDR']]);
file_put_contents('clicks.log', $line.PHP_EOL, FILE_APPEND | LOCK_EX);

Проблема: При параллельных запросах возможна потеря данных или повреждение файла. Решение: Использовать блокировку (LOCK_EX), но это снижает производительность. Альтернатива - запись в системный лог (syslog).

Как получать информацию о кликах через вебхуки от почтового провайдера?

Если используется ESP (например, Mailgun, SendGrid, SparkPost), они могут отправлять HTTP-запросы на ваш сервер при нажатии на ссылку. Вам нужно только обработать входящий POST/GET.


// Пример обработчика для Mailgun (POST с JSON)
$data = json_decode(file_get_contents('php://input'), true);
if ($data['event'] === 'clicked') {
  $url = $data['url'];
  $recipient = $data['recipient'];
  $timestamp = $data['timestamp'];
  // сохранить в вашу базу
}

Проблема: Необходимо защитить конечную точку от поддельных запросов. Решение: проверять подпись (например, по API-ключу), проверять IP отправителя.

Как использовать NoSQL базу для отслеживания кликов?

MongoDB или Redis могут быть хорошим выбором для высоконагруженных систем. Пример с MongoDB (Php библиотека).


$collection = (new MongoDB\Client)->email->clicks;
$collection->insertOne([
  'campaign_id' => $campaign_id,
  'subscriber_id' => $subscriber_id,
  'url' => $url,
  'time' => new MongoDB\BSON\UTCDateTime(),
  'ip' => $_SERVER['REMOTE_ADDR']
]);

Проблема: Отсутствие транзакций может привести к неконсистентности при сбоях. Решение: Использовать подтверждения записи (write concern).

Расширенные примеры реализации

Полный пример генерации отслеживаемых ссылок и обработки с использованием базы данных MySQL и PDO:

Пример

<?php
// config
$secretKey = 'your-secret-key-here';
$dbHost = 'localhost';
$dbName = 'email_marketing';
$dbUser = 'root';
$dbPass = '';
$baseTrackUrl = 'https://track.example.com/click.php';

// Функция создания отслеживаемой ссылки
function createTrackLink($campaignId, $subscriberId, $targetUrl) {
    global $secretKey, $baseTrackUrl;
    $data = $campaignId . '|' . $subscriberId . '|' . $targetUrl;
    $token = hash_hmac('sha256', $data, $secretKey);
    $urlEncoded = base64_encode($targetUrl);
    return $baseTrackUrl . '?c=' . urlencode($campaignId) . '&s=' . urlencode($subscriberId) . '&u=' . urlencode($urlEncoded) . '&t=' . $token;
}

// Пример использования при отправке письма
$campaignId = 'camp_202503';
$subscriberId = 'user_12345';
$realUrl = 'https://example.com/offer';
$trackableLink = createTrackLink($campaignId, $subscriberId, $realUrl);
echo "Ссылка для письма: $trackableLink\n";
?>
Ссылка для письма: https://track.example.com/click.php?c=camp_202503&s=user_12345&u=aHR0cHM6Ly9leGFtcGxlLmNvbS9vZmZlcg==&t=8f3b...

Полный код click.php:

Пример

<?php
session_start();
require 'config.php'; // содержит $pdo

$c = $_GET['c'] ?? '';
$s = $_GET['s'] ?? '';
$uEncoded = $_GET['u'] ?? '';
$t = $_GET['t'] ?? '';

// Декодирование URL
$url = base64_decode($uEncoded);
if ($url === false) { header('HTTP/1.0 400 Bad Request'); exit; }

// Проверка подписи
$expected = hash_hmac('sha256', $c.'|'.$s.'|'.$url, $secretKey);
if (!hash_equals($expected, $t)) {
    // Логируем попытку подделки
    error_log('Invalid click token: '.$c.' '.$s);
    header('HTTP/1.0 403 Forbidden');
    exit;
}

// Подготовка и выполнение запроса с использованием prepared statements
$stmt = $pdo->prepare('INSERT INTO click_log (campaign_id, subscriber_id, url, ip_address, user_agent) VALUES (?,?,?,?,?)');
$stmt->execute([
    $c,
    $s,
    $url,
    $_SERVER['REMOTE_ADDR'],
    $_SERVER['HTTP_USER_AGENT'] ?? ''
]);

// Перенаправление
header('Location: '.$url, true, 302);
exit;
?>

Пример анализа статистики: вывод количества кликов по каждой кампании за последние 7 дней.

Пример

<?php
$stmt = $pdo->query("SELECT campaign_id, COUNT(*) as clicks FROM click_log WHERE clicked_at >= NOW() - INTERVAL 7 DAY GROUP BY campaign_id ORDER BY clicks DESC");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "<table><tr><th>Кампания</th><th>Клики</th></tr>";
foreach ($results as $row) {
    echo "<tr><td>".htmlspecialchars($row['campaign_id'])."</td><td>".$row['clicks']."</td></tr>";
}
echo "</table>";
?>
(выведет таблицу с данными)

Пример использования очереди Redis для отложенной записи (чтобы не ждать базу при редиректе).

Пример

// click.php с отправкой в очередь
$redis = new Redis();
$redis->connect('127.0.0.1');
$logData = [
    'campaign_id' => $c,
    'subscriber_id' => $s,
    'url' => $url,
    'ip' => $_SERVER['REMOTE_ADDR'],
    'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
    'time' => date('c')
];
$redis->lpush('click_queue', json_encode($logData));
header('Location: '.$url);

Код потребителя (worker.php), запускаемый как отдельный процесс:

Пример

<?php
while (true) {
    $data = $redis->brpop('click_queue', 0);
    $log = json_decode($data[1], true);
    $stmt = $pdo->prepare('INSERT INTO click_log (campaign_id,subscriber_id,url,ip_address,user_agent,clicked_at) VALUES (?,?,?,?,?,NOW())');
    $stmt->execute([$log['campaign_id'], $log['subscriber_id'], $log['url'], $log['ip'], $log['user_agent']]);
}
?>

Отслеживание кликов в почтовых рассылках PHP - comments

En
Pub mail click php (php)