/** * Converts links to trackable links and tokens * * @param EmailSendEvent $event * * @return array */ protected function convertTrackableLinks(EmailSendEvent $event) { // Get a list of tokens for the tokenized link conversion $currentTokens = $event->getTokens(); /** @var \Mautic\PageBundle\Model\RedirectModel $redirectModel */ $redirectModel = $this->factory->getModel('page.redirect'); // Parse the content for links $body = $event->getContent(); // Find links using DOM to only find <a> tags $libxmlPreviousState = libxml_use_internal_errors(true); libxml_use_internal_errors(true); $dom = new \DOMDocument(); $dom->loadHTML('<?xml encoding="UTF-8">' . $body); libxml_clear_errors(); libxml_use_internal_errors($libxmlPreviousState); $links = $dom->getElementsByTagName('a'); $foundLinks = $tokenizedLinks = array(); foreach ($links as $link) { $url = $link->getAttribute('href'); // The editor will have converted & to & but DOMDocument will have converted them back so this must be accounted for $url = str_replace('&', '&', $url); $this->validateLink($url, $currentTokens, $foundLinks); } // Process plain text as well $plainText = $event->getPlainText(); if (!empty($plainText)) { // Plaintext links preg_match_all('@(?<![.*">])\\b(?:(?:https?|ftp|file)://|[a-z]\\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]@i', $plainText, $matches); if (!empty($matches[0])) { foreach ($matches[0] as $url) { // Remove anything left on at the end; just in case $url = preg_replace('/^\\PL+|\\PL\\z/', '', trim($url)); $this->validateLink($url, $currentTokens, $foundLinks); } } } $trackedLinks = array(); if (!empty($foundLinks)) { $links = $redirectModel->getRedirectListByUrls($foundLinks, $this->emailEntity); foreach ($links as $url => $link) { if (!$link->getId() && !isset($persistEntities[$url])) { $persistEntities[$url] = $link; } $trackedLinks[$url] = $link; } } if (!empty($persistEntities)) { // Save redirect entities $redirectModel->getRepository()->saveEntities($persistEntities); } unset($foundLinks, $links, $persistEntities); return $trackedLinks; }
/** * Parses content for URLs and tokens. * * @param EmailSendEvent $event * @param $emailId * * @return mixed */ protected function parseContentForUrls(EmailSendEvent $event, $emailId) { static $convertedContent = []; // Prevent parsing the exact same content over and over if (!isset($convertedContent[$event->getContentHash()])) { $html = $event->getContent(); $text = $event->getPlainText(); $contentTokens = $event->getTokens(); list($content, $trackables) = $this->pageTrackableModel->parseContentForTrackables([$html, $text], $contentTokens, $emailId ? 'email' : null, $emailId); list($html, $text) = $content; unset($content); if ($html) { $event->setContent($html); } if ($text) { $event->setPlainText($text); } $convertedContent[$event->getContentHash()] = $trackables; // Don't need to preserve Trackable or Redirect entities in memory $this->em->clear('Mautic\\PageBundle\\Entity\\Redirect'); $this->em->clear('Mautic\\PageBundle\\Entity\\Trackable'); unset($html, $text, $trackables); } return $convertedContent[$event->getContentHash()]; }
/** * Converts links to trackable links and tokens * * @param EmailSendEvent $event * * @return array */ protected function convertTrackableLinks(EmailSendEvent $event) { $taggedDoNotTrack = array(); // Get a list of tokens for the tokenized link conversion $currentTokens = $event->getTokens(); // Parse the content for links $body = $event->getContent(); // Find links using DOM to only find <a> tags $libxmlPreviousState = libxml_use_internal_errors(true); libxml_use_internal_errors(true); $dom = new \DOMDocument(); $dom->loadHTML('<?xml encoding="UTF-8">' . $body); libxml_clear_errors(); libxml_use_internal_errors($libxmlPreviousState); $links = $dom->getElementsByTagName('a'); $foundLinks = $tokenizedLinks = array(); /** @var \DOMElement $link */ foreach ($links as $link) { $url = $link->getAttribute('href'); // The editor will have converted & to & but DOMDocument will have converted them back so this must be accounted for $url = str_replace('&', '&', $url); // Check for a do not track if ($link->hasAttribute('mautic:disable-tracking')) { $taggedDoNotTrack[$url] = true; continue; } $this->validateLink($url, $currentTokens, $foundLinks); } // Process plain text as well $plainText = $event->getPlainText(); if (!empty($plainText)) { // Plaintext links preg_match_all('/((https?|ftps?):\\/\\/)([a-zA-Z0-9-\\.{}]*[a-zA-Z0-9=}]*)(\\??)([^\\s\\]]+)?/i', $plainText, $matches); if (!empty($matches[0])) { foreach ($matches[0] as $url) { $url = trim($url); // Validate the link if it has not already been marked as do not track by attribute in the HTML version if (!isset($taggedDoNotTrack[$url])) { $this->validateLink($url, $currentTokens, $foundLinks); } } } } /** @var \Mautic\PageBundle\Model\RedirectModel $redirectModel */ $redirectModel = $this->factory->getModel('page.redirect'); if (!empty($foundLinks)) { $links = $redirectModel->getRedirectListByUrls($foundLinks, $this->emailEntity); foreach ($links as $url => $link) { if (!$link->getId() && !isset($persistEntities[$url])) { $persistEntities[$url] = $link; } $this->emailTrackedLinkSettings['trackedLinks'][$url] = $link; } } if (!empty($persistEntities)) { // Save redirect entities $redirectModel->getRepository()->saveEntities($persistEntities); } unset($foundLinks, $links, $persistEntities); }