$credID = mysql_result($r, 0); // Make sure they haven't requested a reset in the last 15 minutes. $q = "SELECT `Timestamp` FROM `PwdResetTokens` WHERE `CredentialsID`='{$credID}' ORDER BY `ID` DESC LIMIT 1"; // Find most recent $result = mysql_fetch_array(DB::Run($q)); $tooSoon = strtotime("+15 minutes", strtotime($result['Timestamp'])); if (time() < $tooSoon) { Response::Send(403, "Please wait at least 15 minutes before requesting another email to be sent."); } // Generate reset token $token = urlencode(randomString(15, false)); // Prepare the email $subj = "Reset your ward website password"; $msg = "Hi!\n\nYou or somebody else is trying to log in with this account on " . SITE_DOMAIN . ".\n\nTo reset your password, go to:\n\n----------------------------------------------------\nhttps://" . SITE_DOMAIN . "/newpwd?key={$token}\n----------------------------------------------------\n\nIf you didn't ask for a password reset, just ignore and delete this message. It expires in 48 hours anyway.\n\nHave a great day!\n-" . SITE_DOMAIN; // Save the reset token in the DB $q = "INSERT INTO `PwdResetTokens` (CredentialsID, Token, Timestamp) VALUES ('{$credID}', '{$token}', CURRENT_TIMESTAMP)"; if (!DB::Run($q)) { Response::Send(500, "Couldn't save password reset token. Please report this: " . mysql_error()); } // Send the email $mail = new Mailer(); $mail->FromAndReplyTo(SITE_NAME, "no-reply@" . SITE_DOMAIN); $mail->Subject("Reset your ward website password"); $mail->Body($msg); $mail->To("", $eml); $mail->Send(); if (count($mail->FailedRecipients()) > 0) { Response::Send(500, "Could not send password reset email. Please try again, or report this if the problem persists."); } // Send 200 OK. Email sent; we're done here. Response::Send(200);
// Currently, these actual rates mean we can send about 4,500 emails in an hour. An email to an entire // ward with, say, 160 members, would take just over 2 minutes. Previously, at 1 per second, it would take just under 3 minutes. // TODO: If we are seeing a high volume of emails: // - Spawn up other threads to handle a single job, if the job is large enough, like stake-wide. Deal with concurrency. Yay... // - See if 2 or more other jobs are running; if so, wait time before trying. Run anyway after a certain length of time. // Mark the job as started if not already. If already started or missing info, bail. if ($job->Started > 0 || !$job->Subject || !$job->Message || !$job->SenderName() || !$job->SenderEmail()) { fail("Job properties incorrect (already started, or missing necessary information.\r\n"); } // Ready... set... go! $job->Started = now(); $job->Save(); // Prepare and send the emails $mail = new Mailer(); $mail->IsHTML($job->IsHTML); $mail->From($job->SenderName(), EMAIL_FROM); $mail->ReplyTo($job->SenderName(), $job->SenderEmail()); $mail->Subject($job->Subject); $mail->Body($job->Message); $mail->RecipientArray($job->RecipientsAsArray()); // Send the messages! $mail->Send(); // Store the list of those who didn't receive the email for whatever reason $failedRecipients = $mail->FailedRecipients(); foreach ($failedRecipients as $recip) { $job->AddFailedRecipient($recip['name'], $recip['email']); } // This deed is done. $job->Ended = now(); $job->Save(); exit;
if ($segment->status == 0) { // Successful send. // Convert cost from EUR to USD (https://getsatisfaction.com/nexmo/topics/is_the_message_price_thats_returned_from_a_rest_request_in_eur_or_usd) $job->Cost += $segment->{'message-price'} * $euroToUsd; } else { // Problem sending. // Status codes available at: https://docs.nexmo.com/index.php/messaging-sms-api/send-message if ($segment->status == 2 || $segment->status == 3 || $segment->status == 4 || $segment->status == 8 || $segment->status == 9 || $segment->status == 12 || $segment->status == 19 || $segment->status == 20) { // All of those codes should terminate the whole job because they're all show-stoppers. // Status Code 9 is the most likely: "Partner quota exceeded," meaning: // "Your pre-pay account does not have sufficient credit to process this message" // Alert the webmaster via email because this will require attention. $mail = new Mailer(); $mail->FromAndReplyTo(ERR_HANDLE_FROM_NAME, EMAIL_BLACKHOLE); $mail->Subject("Ward website alert: SMS provider returned fatal error during send"); $mail->Body("While sending a text message from the ward website:\n\nStatus Code {$segment->status}\n\nReason:" . $segment->{'error-text'} . "\n\nJob ID " . $job->ID() . " ended unexpectedly."); $mail->To(WEBMASTER_NAME, WEBMASTER_EMAIL); $mail->Send(); $errorCode = $segment->status; $errorReason = $segment->{'error-text'}; $abort = true; break; } else { if ($job->Recipients[$i]->attempts >= SMS_MAX_ATTEMPTS_PER_RECIPIENT) { // Can't try anymore for this recipient; already tried maximum number of times. $job->AddFailedRecipient($recipID, $recipName, $recipPhone, $segment->status, $segment->{'error-text'}); break; /* NOTE: At some point, something changed with Nexmo which doesn't allow multi-segment (concatenated) messages to US carriers, and each one would get a "throttled" error. They used to automatically split the message up and send them in segments for us. (I suspect this breaking change, which
function errorHandler($level, $errorMsg, $file, $line) { // Don't handle it if the error was suppressed (maybe with @) (or error reporting is off) if (!error_reporting()) { return true; } $errorType; if ($level == E_USER_ERROR) { $errorType = "Error"; } else { if ($level == E_USER_WARNING) { $errorType = "Warning"; } else { if ($level == E_USER_NOTICE) { $errorType = "Notice"; } else { $errorType = "Unknown"; } } } $alertSubject = $errorType . ": " . $errorMsg; $alertBody = "FILE: {$file}\r\nLINE: {$line}\r\nPROBLEM: {$errorType}: {$errorMsg}\r\n"; // See if there's a logged-in user $user = Member::Current(); if (!$user) { $user = StakeLeader::Current(); } if ($user) { $alertBody .= "Currently logged-in user:\r\n" . print_r($user, true); } $alertBody .= "\r\n\r\n--\r\nAutomatically generated by the PHP error handling subsystem for debugging purposes."; $mail = new Mailer(); $mail->FromAndReplyTo(ERR_HANDLE_FROM_NAME, EMAIL_BLACKHOLE); $mail->Subject($alertSubject); $mail->Body($alertBody); $mail->To(WEBMASTER_NAME, WEBMASTER_EMAIL); $mail->Send(); // Write this to the server's internal log file... error_log("{$errorType}: {$errorMsg} in {$file} on line {$line}\n", LOG_TYPE, LOG_FILE); // Don't execute PHP's internal error handler return true; }