: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
use NF_Exports_BulkSubmissionEmailParameters as BulkSubmissionEmailParameters;
* Email exported submissions as an attachment
class NF_Exports_BulkSubmissionEmail {
* Bulk Submission Email Parameters
* @var BulkSubmissionEmailParameters
protected $bulkSubmissionEmailParameters;
* Comma delineated `To` addresses
* CSV string content, stored in array for multiple attachments
* Directory of final file location
* Temp file name at time of upload, before renaming
* Full file name with path as attached to email
protected $attachmentFilename;
* Instantiated with BulkSubmissionEmailParameters and string CSV content
* @param BulkSubmissionEmailParameters $bulkSubmissionEmailParameters
* @param array $attachmentFilenames Array of string filenames ready for attachment
public function __construct($bulkSubmissionEmailParameters, array $attachmentFilenames) {
$this->bulkSubmissionEmailParameters = $bulkSubmissionEmailParameters;
$this->attachmentFilename = $attachmentFilenames;
protected function setDefaults() {
// set upload director to /uploads
$this->uploadDir = $dir['path'];
* Generate email, attach content, submit email
public function handle() {
$this->sanitizeAddressFields();
$headers = $this->getHeaders();
$attachments = $this->getAttachments();
$message = apply_filters('ninja_forms_action_email_message', $this->bulkSubmissionEmailParameters->getEmailSubject());
$sent = wp_mail($this->toAddresses, strip_tags($this->bulkSubmissionEmailParameters->getEmailSubject()), $message, $headers, $attachments);
* Put every email address through a sanitizing method
protected function sanitizeAddressFields() {
$incomingToAddresses = $this->bulkSubmissionEmailParameters->getEmailTo();
$emailAddresses = explode(',', $incomingToAddresses);
// Loop over our email addresses.
foreach ($emailAddresses as $email) {
$sanitized = $this->sanitizeEmail($email);
// Build our array of the email addresses.
$sanitizedArray[] = $sanitized;
$this->toAddresses = implode(',', $sanitizedArray);
// Sanitized our array of settings.
$this->fromAddress = $this->sanitizeEmail($this->bulkSubmissionEmailParameters->getEmailFrom());
$this->replyTo = $this->bulkSubmissionEmailParameters->getEmailReplyTo();
* Sanitize a given email address
* @param string $incoming
protected function sanitizeEmail($incoming) {
// Trim values in case there is a value with spaces/tabs/etc to remove whitespace
$trimmed = trim($incoming);
if (false !== strpos($trimmed, '<') && false !== strpos($trimmed, '>')) {
preg_match('/(?:<)([^>]*)(?:>)/', $trimmed, $matches);
// skip if email is invalid
if (!is_email($return)) {
* Construct and return header array
* Note that variable headers are run through sanitize_header method
private function getHeaders() {
$contentHeaders[] = 'Content-Type: text/html';
$contentHeaders[] = 'charset=UTF-8';
$contentHeaders[] = 'X-Ninja-Forms:ninja-forms'; // Flag for transactional email.
$contentHeaders[] = $this->formatAddress('from', $this->fromAddress);
$headers = array_merge($contentHeaders, $this->constructRecipientsHeader());
* Sanitize header to prevent attacker is able to create new headers using charecter encoding.
protected function sanitize_header($header){
return preg_replace( '=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', null, $header );
* Construct and return attachments
private function getAttachments() {
$attachments = $this->attachmentFilename;
* Format Reply-To, CC, and BCC address header
private function constructRecipientsHeader() {
// Could include `cc` and `bcc` in future
$recipientParameters = array(
'Reply-to' => $this->bulkSubmissionEmailParameters->getEmailReplyTo(),
foreach ($recipientParameters as $type => $email) {
$headers[] = $this->formatAddress($type, $email);
* Format address for header
private function formatAddress($type, $email, $name = '') {
$formattedType = ucfirst($type);
$recipient = "$formattedType: $name <$email>";
return $this->sanitize_header($recipient);