Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/modules/sender/lib/integration/sender/mail/
Upload File :
Current File : /var/www/homesaver/www/bitrix/modules/sender/lib/integration/sender/mail/messagemail.php

<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage sender
 * @copyright 2001-2012 Bitrix
 */

namespace Bitrix\Sender\Integration\Sender\Mail;

use Bitrix\Fileman\Block;
use Bitrix\Main\Application;
use Bitrix\Main\Config\Option;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Mail;
use Bitrix\Main\Result;
use Bitrix\Main\SystemException;
use Bitrix\Main\Web\DOM\Document;
use Bitrix\Main\Web\DOM\StyleInliner;
use Bitrix\Sender\Entity;
use Bitrix\Sender\Integration;
use Bitrix\Sender\Integration\Crm\Connectors\Helper;
use Bitrix\Sender\Message;
use Bitrix\Sender\Posting;
use Bitrix\Sender\PostingRecipientTable;
use Bitrix\Sender\Templates;
use Bitrix\Sender\Transport;
use Bitrix\Sender\Transport\TimeLimiter;

Loc::loadMessages(__FILE__);

/**
 * Class MessageMail
 * @package Bitrix\Sender\Integration\Sender\Mail
 */
class MessageMail implements Message\iBase, Message\iMailable
{
	const CODE = self::CODE_MAIL;

	/** @var Message\Configuration $configuration Configuration. */
	protected $configuration;

	/** @var integer $configurationId Configuration ID. */
	protected $configurationId;

	protected $closureRefCountFix;

	/**
	 * MessageMail constructor.
	 */
	public function __construct()
	{
		$this->configuration = new Message\Configuration();
	}

	/**
	 * Get name.
	 *
	 * @return string
	 */
	public function getName()
	{
		return Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_NAME');
	}

	/**
	 * Get code.
	 *
	 * @return string
	 */
	public function getCode()
	{
		return self::CODE;
	}

	/**
	 * Get supported transports.
	 *
	 * @return array
	 */
	public function getSupportedTransports()
	{
		return array(Transport\Adapter::CODE_MAIL);
	}

	/**
	 * Set configuration options
	 * @return void
	 */
	protected function setConfigurationOptions()
	{
		if ($this->configuration->hasOptions())
		{
			return;
		}

		$this->configuration->setArrayOptions(array(
			array(
				'type' => 'string',
				'code' => 'SUBJECT',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_SUBJECT'),
				'required' => true,
				'value' => '',
				'show_in_list' => true,
				'hint' => array(
					'menu' => array_map(
						function ($item)
						{
							return array(
								'id' => '#' . ($item['CODE'] ?? '') . '#',
								'text' => $item['NAME'] ?? '',
								'title' => $item['DESC'] ?? '',
								'items' => isset($item['ITEMS']) ? array_map(
									function ($item)
									{
										return array(
											'id' => '#' . ($item['CODE'] ?? ''). '#',
											'text' => $item['NAME'] ?? '',
											'title' => $item['DESC'] ?? ''
										);
									}, $item['ITEMS']
								) : []
							);
						},
						array_merge(
							Helper::getPersonalizeFieldsFromConnectors(),
							PostingRecipientTable::getPersonalizeList()
						)
					),
				),
			),
			array(
				'type' => 'email',
				'code' => 'EMAIL_FROM',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_EMAIL_FROM'),
				'required' => true,
				'value' => '',
				'show_in_list' => true,
				'readonly_view' => function($value)
				{
					return (new Mail\Address())->set($value)->get();
				},
				//'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
			),
			array(
				'type' => 'mail-editor',
				'code' => 'MESSAGE',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_MESSAGE'),
				'required' => true,
				'templated' => true,
				'value' => '',
				'items' => array(),
			),
			array(
				'type' => 'list',
				'code' => 'PRIORITY',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_PRIORITY'),
				'required' => false,
				'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
				'value' => '',
				'show_in_list' => true,
				'items' => array(
					array('code' => '', 'value' => '(' . Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_NO') . ')'),
					array('code' => '1 (Highest)', 'value' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_PRIORITY_HIGHEST')),
					array('code' => '3 (Normal)', 'value'  => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_PRIORITY_NORMAL')),
					array('code' => '5 (Lowest)', 'value'  => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_PRIORITY_LOWEST')),
				),
				'hint' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_PRIORITY_HINT'),
			),
			array(
				'type' => 'string',
				'code' => 'LINK_PARAMS',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_LINK_PARAMS'),
				'required' => false,
				'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
				'value' => '',
				'show_in_list' => true,
				'items' => array(),
			),
			array(
				'type' => 'file',
				'code' => 'ATTACHMENT',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_ATTACHMENT'),
				'required' => false,
				'multiple' => true,
				'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
				'value' => '',
				'items' => array(),
			), [
				'type' => Message\ConfigurationOption::TYPE_CHECKBOX,
				'code' => 'TRACK_MAIL',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_TRACK_MAIL'),
				'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
				'show_in_list' => false,
				'required' => false,
				'value' => Option::get('sender', 'track_mails')
			],
			[
				'type' => Message\ConfigurationOption::TYPE_CONSENT,
				'code' => 'APPROVE_CONFIRMATION',
				'name' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_APPROVE_CONFIRMATION'),
				'hint' => Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_CONFIG_APPROVE_CONFIRMATION_HINT'),
				'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
				'show_in_list' => false,
				'required' => false,
				'value' => Option::get('sender', 'mail_consent'),
			], [
				'type' => Message\ConfigurationOption::TYPE_CONSENT_CONTENT,
				'code' => 'APPROVE_CONFIRMATION_CONSENT',
				'group' => Message\ConfigurationOption::GROUP_ADDITIONAL,
				'show_in_list' => false,
				'required' => false,
				'show_preview' => true
			],
		));

		TimeLimiter::prepareMessageConfiguration($this->configuration);

		$list = array(
			array(
				'type' => 'template-type',
				'code' => 'TEMPLATE_TYPE',
				'name' => 'Template type',
				'value' => '',
			),
			array(
				'type' => 'template-id',
				'code' => 'TEMPLATE_ID',
				'name' => 'Template id',
				'value' => '',
			),
		);

		foreach ($list as $optionData)
		{
			$optionData = $optionData + array(
				'type' => 'string',
				'name' => '',
				'internal' => true,
			);
			$this->configuration->addOption(new Message\ConfigurationOption($optionData));
		}
	}

	/**
	 * Load configuration.
	 *
	 * @param string|null $id ID.
	 *
	 * @return Message\Configuration
	 */
	public function loadConfiguration($id = null)
	{
		$this->setConfigurationOptions();
		Entity\Message::create()
			->setCode($this->getCode())
			->loadConfiguration($id, $this->configuration);


		// do not remove: increment ref count to closure for rewriting.
		$instance = $this;
		$this->closureRefCountFix = function () use (&$instance)
		{
			return $instance->getMailBody();
		};

		$trackMail = $this->configuration->getOption('TRACK_MAIL')->getValue();
		if (is_null($trackMail))
		{
			$this->configuration->getOption('TRACK_MAIL')->setValue(Option::get('sender', 'track_mails'));
		}

		$optionLinkParams = $this->configuration->getOption('LINK_PARAMS');
		if ($optionLinkParams)
		{
			$optionLinkParams->setView(
				function () use ($id, $optionLinkParams)
				{
					ob_start();
					$GLOBALS['APPLICATION']->IncludeComponent(
						'bitrix:sender.mail.link.editor', '',
						array(
							"INPUT_NAME" => "%INPUT_NAME%",
							"VALUE" => $optionLinkParams->getValue(),
							"USE_DEFAULT" => (
								!$optionLinkParams->getValue()
								&&
								!$id
								&&
								!Application::getInstance()->getContext()->getRequest()->isPost()
							),
							"PLACEHOLDERS" => array(
								array(
									"code" => "campaign",
									"inputName" => "%INPUT_NAME_SUBJECT%"
								)
							),
							"DEFAULT_VALUE" => Option::get(
								'sender',
								'mail_utm',
								'utm_source=newsletter&utm_medium=mail&utm_campaign=%campaign%'
							)
						)
					);
					return ob_get_clean();
				}
			);
		}

		$optionFrom = $this->configuration->getOption('EMAIL_FROM');
		if ($optionFrom)
		{
			$optionFrom->setView(
				function () use ($optionFrom)
				{
					ob_start();
					$GLOBALS['APPLICATION']->IncludeComponent(
						'bitrix:sender.mail.sender', '',
						array(
							"INPUT_NAME" => "%INPUT_NAME%",
							"VALUE" => $optionFrom->getValue()
						)
					);
					return ob_get_clean();
				}
			);
		}

		$this->configuration->set('BODY', $this->closureRefCountFix);

		$mailHeaders = array('Precedence' => 'bulk');
		$mailHeaders = self::fillHeadersByOptionHeaders($mailHeaders);
		$this->configuration->set('HEADERS', $mailHeaders);
		TimeLimiter::prepareMessageConfigurationView($this->configuration);

		return $this->configuration;
	}

	/**
	 * Save configuration.
	 *
	 * @param Message\Configuration $configuration Configuration.
	 * @return Result|null
	 */
	public function saveConfiguration(Message\Configuration $configuration)
	{
		$this->configuration = $configuration;

		try
		{
			$mailBody = $this->getMailBody();
		}
		catch (SystemException $exception)
		{
			$result = new Result();
			$result->addError(new Error($exception->getMessage()));

			return $result;
		}

		$sizeInBytes = mb_strlen($mailBody);
		$sizeInKilobytes = $sizeInBytes / 1024;
		$limitInKilobytes = 2.4 * 1024;
		$saveAsTemplate = $this->configuration->get('save_as_template') === 'Y';

		if ($saveAsTemplate && $sizeInKilobytes > $limitInKilobytes)
		{
			$result = new Result();

			$result->addError(new Error(Loc::getMessage('SENDER_INTEGRATION_MAIL_BODY_LIMIT')));
			return $result;
		}

		if (Integration\Bitrix24\Service::isCloud())
		{
			if ($mailBody && mb_strpos($mailBody, '#UNSUBSCRIBE_LINK#') === false)
			{
				$result = new Result();
				$result->addError(new Error(Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_ERR_NO_UNSUB_LINK')));
			}

			if (
				$mailBody
				&& $configuration->getOption('APPROVE_CONFIRMATION')->getValue() === 'Y'
				&& !$configuration->getOption('APPROVE_CONFIRMATION_CONSENT')->getValue()
			)
			{
				$result = new Result();
				$result->addError(new Error(Loc::getMessage('SENDER_INTEGRATION_MAIL_MESSAGE_ERR_NO_APPROVE_CONFIRMATION_CONSENT')));

				return $result;
			}
		}
		parse_str(
			$this->configuration->getOption('LINK_PARAMS')->getValue(),
			$utmTags
		);

		$utm = [];
		foreach ($utmTags as $utmTag => $value)
		{
			$utm[] = [
				'CODE' => $utmTag,
				'VALUE' => $value
			];
		}

		//TODO: compare with allowed email list
		$emailFrom = $this->configuration->getOption('EMAIL_FROM')->getValue();
		$emailFrom = (new Mail\Address($emailFrom))->get();
		$this->configuration->getOption('EMAIL_FROM')->setValue($emailFrom);

		$trackMail = $this->configuration->getOption('TRACK_MAIL')->getValue();

		if (!$trackMail)
		{
			$this->configuration->getOption('TRACK_MAIL')->setValue('N');
		}
		return Entity\Message::create()
			->setCode($this->getCode())
			->setUtm($utm)
			->saveConfiguration($this->configuration);
	}

	/**
	 * Copy configuration.
	 *
	 * @param integer|string|null $id ID.
	 * @return Result|null
	 */
	public function copyConfiguration($id)
	{
		return Entity\Message::create()
			->setCode($this->getCode())
			->copyConfiguration($id);
	}

	/**
	 * Remove php code from html
	 * @param string $html Input html.
	 * @return string
	 */
	protected function removePhp($html)
	{
		static $isCloud = null;
		if ($isCloud === null)
		{
			$isCloud = Integration\Bitrix24\Service::isCloud();
			Loader::includeModule('fileman');
		}

		if ($isCloud)
		{
			return Block\EditorMail::removePhpFromHtml($html);
		}

		return $html;
	}

	/**
	 * Get main body.
	 *
	 * @return string
	 */
	public function getMailBody()
	{
		Loader::includeModule('fileman');

		$msg = $this->configuration->getOption('MESSAGE')->getValue();
		$template = $this->getTemplate();
		if (!$template)
		{
			return $this->removePhp($msg);
		}
		if (!isset($template['FIELDS']) || !$template['FIELDS']['MESSAGE']['ON_DEMAND'])
		{
			return $this->removePhp($msg);
		}

		$templateHtml = null;
		if (isset($template['FIELDS']) && isset($template['FIELDS']['MESSAGE']))
		{
			$templateHtml = $template['FIELDS']['MESSAGE']['VALUE'];
		}
		if (!$templateHtml && isset($template['HTML']))
		{
			$templateHtml = $template['HTML'];
		}
		if (!$templateHtml)
		{
			return $this->removePhp($msg);
		}

		$document = new Document;
		$document->loadHTML($templateHtml);

		try
		{
			if(!Block\Content\Engine::create($document)->setContent($msg)->fill())
			{
				return '';
			}
		}
		catch (SystemException $exception)
		{
			throw new Posting\StopException();
		}

		StyleInliner::inlineDocument($document);
		$msg = $document->saveHTML();
		unset($document);

		$msg = $this->removePhp($msg);
		$msgTmp = Block\Editor::replaceCharset($msg, '#SENDER_MAIL_CHARSET#', true);
		if ($msgTmp)
		{
			$msg = $msgTmp;
		}

		if (Option::get('sender', 'use_inliner_for_each_template_mail', 'N') != 'Y')
		{
			$this->configuration->set('BODY', $msg);
		}

		return $msg;
	}

	/**
	 * Get template
	 * @return array|null
	 */
	protected function getTemplate()
	{
		if (!$this->configuration->get('TEMPLATE_TYPE') || !$this->configuration->get('TEMPLATE_ID'))
		{
			return null;
		}

		return Templates\Selector::create()
			->withMessageCode(static::CODE)
			->withTypeId($this->configuration->get('TEMPLATE_TYPE'))
			->withId($this->configuration->get('TEMPLATE_ID'))
			->get();
	}

	/**
	 * Add option headers to headers
	 * @param array $headers Headers.
	 * @return array
	 */
	protected static function fillHeadersByOptionHeaders(array $headers = array())
	{
		static $headerList = null;
		if ($headerList === null)
		{
			$headerList = array();
			// add headers from module options
			$optionHeaders = Option::get('sender', 'mail_headers', '');
			$optionHeaders = !empty($optionHeaders) ? unserialize($optionHeaders, ['allowed_classes' => false]) : array();
			foreach ($optionHeaders as $optionHeader)
			{
				$optionHeader = trim($optionHeader);
				if (!$optionHeader)
				{
					continue;
				}

				$optionHeaderParts = explode(':', $optionHeader);
				$optionHeaderName = isset($optionHeaderParts[0]) ? $optionHeaderParts[0] : '';
				$optionHeaderName = trim($optionHeaderName);
				$optionHeaderValue = isset($optionHeaderParts[1]) ? $optionHeaderParts[1] : '';
				$optionHeaderValue = trim($optionHeaderValue);
				if (!$optionHeaderName || !$optionHeaderValue)
				{
					continue;
				}

				$headerList[$optionHeaderName] = $optionHeaderValue;
			}
		}

		foreach ($headerList as $optionHeaderName => $optionHeaderValue)
		{
			$headers[$optionHeaderName] = $optionHeaderValue;
		}

		return $headers;
	}
}