signin_mailer.php
1 <?php 2 3 // Link expiration time. Will be isnerted the email message. 4 define('LINK_TTL', '24 hours'); 5 // Time after which entries will be deleted even if the email wasn't sent 6 define('ENTRY_TTL', 3600); // in seconds 7 // Number of emails to send per run 8 define('BATCH_SIZE', 100); 9 // Table name 10 define('TBL', 'email_signins_queue'); 11 12 // --- 13 14 echo "[" . date('r') . "] - Mailer run started\n"; 15 16 // Only one mailer instance can run at a time 17 $run_lock = fopen(sys_get_temp_dir() . '/signin_mailer.lock', 'a'); 18 19 if (!$run_lock) { 20 echo "Couldn't create lock file. Aborting\n"; 21 exit(-1); 22 } 23 24 if (!flock($run_lock, LOCK_EX | LOCK_NB)) { 25 echo "Previous run hasn't finished yet. Aborting\n"; 26 exit(0); 27 } 28 29 // --- 30 31 require_once 'lib/db.php'; 32 33 set_time_limit(60); 34 35 function send_email($email, $token) { 36 $ttl = LINK_TTL; 37 38 $subject = "Email Verification Request"; 39 $message =<<<MSG 40 Hello, 41 42 We have received a request to verify this email address for use on 4chan. If you requested this verification, please go to the following URL: 43 44 https://sys.4chan.org/signin?action=verify&tkn=$token 45 46 This link will expire in $ttl. You can use it multiple times to authorize as many of your devices as needed. 47 48 If you did NOT request to verify this email address, do not click on the link. 49 50 Sincerely, 51 52 Team 4chan. 53 MSG; 54 55 $headers = "From: 4chan <noreply@4chan.org>\r\n"; 56 $headers .= "MIME-Version: 1.0\r\n"; 57 $headers .= "Content-Type: text/plain; charset=UTF-8\r\n"; 58 59 $opts = '-f noreply@4chan.org'; 60 61 return mail($email, $subject, $message, $headers, $opts); 62 } 63 64 // --- 65 66 // Cleanup expired entries to not keep plaintext emails for too long. 67 $tbl = TBL; 68 69 $ttl = (int)ENTRY_TTL; 70 71 $sql = "DELETE FROM `$tbl` WHERE created_on <= DATE_SUB(NOW(), INTERVAL $ttl SECOND)"; 72 73 $res = mysql_global_call($sql); 74 75 if (!$res) { 76 echo "DB error while pruning stale entries. Aborting\n"; 77 exit(-1); 78 } 79 80 // Start sending mails 81 $batch_size = (int)BATCH_SIZE; 82 83 $sql = "SELECT id, email, token FROM `$tbl` ORDER BY id ASC LIMIT $batch_size"; 84 85 $res = mysql_global_call($sql); 86 87 if (!$res) { 88 echo "DB error while fetching entries. Aborting\n"; 89 exit(-1); 90 } 91 92 $sent_count = 0; 93 $error_count = 0; 94 95 while ($row = mysql_fetch_assoc($res)) { 96 $id = (int)$row['id']; 97 $email = $row['email']; 98 $token = $row['token']; 99 100 if (!$email || !$token) { 101 $error_count++; 102 continue; 103 } 104 105 $ret = send_email($email, $token); 106 107 if ($ret) { 108 $sent_count++; 109 $sql = "DELETE FROM `$tbl` WHERE id = $id LIMIT 1"; 110 mysql_global_call($sql); 111 } 112 else { 113 $error_count++; 114 } 115 116 //usleep(10000); // 10ms 117 } 118 119 // --- 120 121 fclose($run_lock); 122 123 echo "[" . date('r') . "] - Mailer run finished: sent $sent_count, errors $error_count\n"; 124 125 exit(0);