Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
100.00% |
1 / 1 |
|
100.00% |
13 / 13 |
CRAP | |
100.00% |
109 / 109 |
| Magentron_EmailImages_Helper_Data | |
100.00% |
1 / 1 |
|
100.00% |
13 / 13 |
42 | |
100.00% |
109 / 109 |
| isEnabled() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| getCacheTime() | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
| getRegularExpression() | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
| getRegularExpressionIndex() | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
| addImages( Zend_Mail $mail, $context = null ) | |
100.00% |
1 / 1 |
4 | |
100.00% |
9 / 9 |
|||
| cleanCache() | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| _getImageUrlsFromMail( Zend_Mail $mail, $context = null ) | |
100.00% |
1 / 1 |
7 | |
100.00% |
20 / 20 |
|||
| _getImageUrlsFromBodyHtml( $bodyHtml ) | |
100.00% |
1 / 1 |
4 | |
100.00% |
15 / 15 |
|||
| _getContextDataFromCache( $context_cache_id ) | |
100.00% |
1 / 1 |
2 | |
100.00% |
2 / 2 |
|||
| _getBodyHtml( Zend_Mail $mail ) | |
100.00% |
1 / 1 |
5 | |
100.00% |
11 / 11 |
|||
| _saveContextDataToCache( $context_cache_id, $isHtml, $urls ) | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| _attachImageUrls( Zend_Mail $mail, array $urls ) | |
100.00% |
1 / 1 |
5 | |
100.00% |
13 / 13 |
|||
| _retrieveImageData( $url ) | |
100.00% |
1 / 1 |
6 | |
100.00% |
18 / 18 |
|||
| <?php | |
| /** | |
| * Magentron EmailImages Extension | |
| * | |
| * @category Magentron | |
| * @package Magentron_EmailImages | |
| * @author Jeroen Derks | |
| * @copyright Copyright (c) 2011 Jeroen Derks http://www.magentron.com | |
| * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) | |
| */ | |
| class Magentron_EmailImages_Helper_Data extends Mage_Core_Helper_Abstract | |
| { | |
| /** Configuration path for extension enablement. | |
| * @var string | |
| * @see isEnabled() | |
| */ | |
| const XML_EMAIL_IMAGES_ENABLE = 'system/emailimages/enable'; | |
| /** Configuration path for maximum cache lifetime. | |
| * @var string | |
| * @see getCacheTime() | |
| */ | |
| const XML_EMAIL_IMAGES_CACHE_TIME = 'system/emailimages/cache_time'; | |
| /** Configuration path for regular expression used to find image URLs in HTML. | |
| * @var string | |
| * @see getRegularExpression() | |
| */ | |
| const XML_EMAIL_IMAGES_REGEXP = 'system/emailimages/regexp'; | |
| /** Configuration path for index into matches of regular expression used to find image URLs in HTML. | |
| * @var string | |
| * @see XML_EMAIL_IMAGES_REGEXP, | |
| * getRegularExpressionIndex() | |
| */ | |
| const XML_EMAIL_IMAGES_REGEXP_INDEX = 'system/emailimages/regexp_index'; | |
| /** Default maximum lifetime used for cache. | |
| * @var integer | |
| * @see getCacheTime() | |
| */ | |
| const DEFAULT_CACHE_TIME = 86400; | |
| /** Default regular expression to extract image URLs from the email HTML body. | |
| * @var string | |
| * @see getRegularExpression() | |
| */ | |
| const DEFAULT_REGEXP = '/((<[iI][mM][gG] [^>]*[sS][rR][cC]|[Bb][Aa][Cc][Kk][Gg][Rr][Oo][Uu][Nn][Dd])="|image:url\(\'?)([^\'"\)]*)(["\'\)])/'; | |
| /** Default index in the regular expression matches to extract the image URLs from the email HTML body. | |
| * @var integer | |
| * @see getRegularExpressionIndex() | |
| */ | |
| const DEFAULT_REGEXP_INDEX = 3; | |
| /** Cache tag to use. | |
| * @var string | |
| */ | |
| const CACHE_TAG = 'MAGENTRON_EMAILIMAGES'; | |
| /** Cache type to use. | |
| * @var string | |
| */ | |
| const CACHE_TYPE = 'emailimages'; | |
| /** | |
| * Is the EmailImages extension enabled to actually attach images? | |
| * | |
| * @return boolean | |
| * | |
| * @see XML_EMAIL_IMAGES_ENABLE | |
| */ | |
| public function isEnabled() | |
| { | |
| return (boolean) Mage::getStoreConfig(self::XML_EMAIL_IMAGES_ENABLE); | |
| } | |
| /** | |
| * Retrieve the maximum lifetime for caching in seconds. | |
| * | |
| * @return integer | |
| * | |
| * @see XML_EMAIL_IMAGES_CACHE_TIME, DEFAULT_CACHE_TIME | |
| */ | |
| public function getCacheTime() | |
| { | |
| $config = Mage::getStoreConfig(self::XML_EMAIL_IMAGES_CACHE_TIME); | |
| if ( !is_numeric($config) ) | |
| $config = self::DEFAULT_CACHE_TIME; | |
| return (integer) $config; | |
| } | |
| /** | |
| * Retrieve the regular expression to extract the image URLs from the email HTML body. | |
| * | |
| * @return string | |
| * | |
| * @see XML_EMAIL_IMAGES_REGEXP, DEFAULT_REGEXP | |
| */ | |
| public function getRegularExpression() | |
| { | |
| $config = Mage::getStoreConfig(self::XML_EMAIL_IMAGES_REGEXP); | |
| if ( '' == $config ) | |
| $config = self::DEFAULT_REGEXP; | |
| return (string) $config; | |
| } | |
| /** | |
| * Retrieve the index in the regular expression matches to extract the image URLs from the email HTML body. | |
| * | |
| * @return integer | |
| * | |
| * @see XML_EMAIL_IMAGES_REGEXP_INDEX, DEFAULT_REGEXP_INDEX | |
| */ | |
| public function getRegularExpressionIndex() | |
| { | |
| $config = Mage::getStoreConfig(self::XML_EMAIL_IMAGES_REGEXP_INDEX); | |
| if ( !is_numeric($config) ) | |
| $config = self::DEFAULT_REGEXP_INDEX; | |
| return (integer) $config; | |
| } | |
| /** | |
| * Attach images to mail object. | |
| * | |
| * @param Zend_Mail $mail Zend_Mail instance to attach images to. | |
| * @param string $context [optional] Set to unique identifier for template, so that body needs to be parsed only once per template (NB: case-insensitive). | |
| * @return void Fails silently if unable to attach image, warning message sent to log. | |
| * | |
| * @see isEnabled(), _getImageUrlsFromMail(), _attachImageUrls() | |
| */ | |
| public function addImages( Zend_Mail $mail, $context = null ) | |
| { | |
| // check whether the administrator has enabled the module | |
| if ( !$this->isEnabled() ) | |
| { | |
| Mage::log('EmailImages - extension disabled'); | |
| return; | |
| } | |
| try | |
| { | |
| $urls = $this->_getImageUrlsFromMail($mail, $context); | |
| if ( $urls ) | |
| $this->_attachImageUrls($mail, $urls); | |
| } | |
| catch ( Exception $e ) | |
| { | |
| // ignore exception, but do log it | |
| Mage::log('EmailImages - ERROR: exception caught: ' . $e, Zend_Log::ERR); | |
| } | |
| } | |
| /** | |
| * Remove cached image and context data from the cache. | |
| * | |
| * @return Magentron_EmailImages_Helper_Data Provides fluent interface | |
| * | |
| * @see CACHE_TAG, | |
| * Mage_Core_Model_Cache::flush() | |
| */ | |
| public function cleanCache() | |
| { | |
| /** @var $cache Mage_Core_Model_Cache */ | |
| $cache = Mage::getSingleton('core/cache'); | |
| $cache->flush(self::CACHE_TAG); | |
| return $this; | |
| } | |
| /** | |
| * Retrieve image URLs from email content | |
| * | |
| * @param Zend_Mail $mail Zend_Mail instance to attach images to. | |
| * @param string $context [optional] Set to unique identifier for template, so that body needs to be parsed only once per template (NB: case-insensitive). | |
| * @return array Array of image URLs. | |
| * | |
| * @see CACHE_TYPE, | |
| * _getContextDataFromCache(), _getBodyHtml(), _getImageUrlsFromBodyHtml(), _saveContextDataToCache(), | |
| * Mage_Core_Model_Cache::canUse() | |
| */ | |
| protected function _getImageUrlsFromMail( Zend_Mail $mail, $context = null ) | |
| { | |
| // check cache for context | |
| /** @var $cache Mage_Core_Model_Cache */ | |
| $cache = Mage::getSingleton('core/cache'); | |
| $context_data = null; | |
| $use_cache = null !== $context && $cache->canUse(self::CACHE_TYPE); | |
| Mage::log(__CLASS__ . '::' . __FUNCTION__ . '(): use_cache = ' . var_export($use_cache, 1)); | |
| if ( $use_cache ) | |
| { | |
| $context_cache_id = self::CACHE_TYPE . '-urls-' . (is_string($context) ? $context : md5(serialize($context))); | |
| $context_data = $this->_getContextDataFromCache($context_cache_id); | |
| } | |
| if ( !$context_data ) | |
| { | |
| $bodyHtml = $this->_getBodyHtml($mail); | |
| $urls = $this->_getImageUrlsFromBodyHtml($bodyHtml); | |
| // save URLs to cache, if context defined | |
| if ( $use_cache ) | |
| { | |
| $isHtml = (boolean) $bodyHtml; | |
| $this->_saveContextDataToCache($context_cache_id, $isHtml, $urls); | |
| } | |
| } | |
| else | |
| { | |
| $urls = $context_data['is_html'] ? $context_data['urls'] : array(); | |
| Mage::log('EmailImages - loaded URLs from cache (cache ID: ' . $context_cache_id . ')'); | |
| } | |
| return $urls; | |
| } | |
| /** | |
| * Retrieve image URL from email body HTML | |
| * | |
| * @param string $bodyHtml Email body HTML to use. | |
| * @return array Array of image URLs. | |
| * | |
| * @see getRegularExpression(), getRegularExpressionIndex() | |
| */ | |
| protected function _getImageUrlsFromBodyHtml( $bodyHtml ) | |
| { | |
| $urls = array(); | |
| Mage::log('EmailImages - parsing HTML body'); | |
| if ( $bodyHtml ) | |
| { | |
| // find image URLs in email HTML body | |
| $regexp = $this->getRegularExpression(); | |
| if ( preg_match_all($regexp, $bodyHtml, $matches) ) | |
| { | |
| $index = $this->getRegularExpressionIndex(); | |
| $urls = $matches[$index]; | |
| $urls = array_unique($urls); | |
| } | |
| if ( 0 == count($urls) ) // no URLs in HTML body? | |
| Mage::log('EmailImages - no images found in email HTML body', Zend_Log::WARN); | |
| } | |
| else // otherwise no HTML body? | |
| { | |
| Mage::log('EmailImages - no HTML body for email', Zend_Log::WARN); | |
| } | |
| return $urls; | |
| } | |
| /** | |
| * Retrieve cached context data. | |
| * | |
| * @param string $context_cache_id Cached context data cache ID. | |
| * @return array Array containing keys 'isHtml' to indicate a HTML body, 'urls' for image URLs from that HTML body. | |
| * | |
| * @see Mage_Core_Model_Cache::load() | |
| */ | |
| protected function _getContextDataFromCache( $context_cache_id ) | |
| { | |
| /** @var $cache Mage_Core_Model_Cache */ | |
| $cache = Mage::getSingleton('core/cache'); | |
| $context_data = $cache->load($context_cache_id); | |
| if ( $context_data ) | |
| $context_data = unserialize($context_data); | |
| Mage::log(__CLASS__ . '::' . __FUNCTION__ . '(): context_data=' . print_r($context_data, 1)); | |
| return $context_data; | |
| } | |
| /** | |
| * Retrieve HTML body from mail object. | |
| * | |
| * @param Zend_Mail $mail Mail object instance to use. | |
| * @return string|false HTML body from the mail object instance, if any; | |
| * false, otherwise. | |
| * | |
| * @see Zend_Mail::getBodyHtml(), Zend_Mime_Part::getContent() | |
| */ | |
| protected function _getBodyHtml( Zend_Mail $mail ) | |
| { | |
| $bodyHtmlObject = $mail->getBodyHtml(); | |
| if ( $bodyHtmlObject instanceof Zend_Mime_Part ) | |
| { | |
| $bodyHtml = $bodyHtmlObject->getContent(); | |
| if ( $bodyHtmlObject->encoding == Zend_Mime::ENCODING_QUOTEDPRINTABLE ) | |
| $bodyHtml = quoted_printable_decode($bodyHtml); | |
| } | |
| else | |
| { | |
| $bodyHtml = $bodyHtmlObject; | |
| } | |
| if ( !is_string($bodyHtml) ) | |
| { | |
| Mage::log(__CLASS__ . '::' . __FUNCTION__ . '(): unsupported bodyHtml = ' . substr(var_export($bodyHtml, 1), 0, 128) . '...'); | |
| $bodyHtml = false; | |
| } | |
| Mage::log(__CLASS__ . '::' . __FUNCTION__ . '(): bodyHtml = ' . ($bodyHtml ? preg_replace('/[\s\t\r\n\k]+/', ' ', substr($bodyHtml, 0, 128)) : '<empty>')); | |
| return $bodyHtml; | |
| } | |
| /** | |
| * Save context data to cache. | |
| * | |
| * @param string $context_cache_id Cache ID to use. | |
| * @param boolean $isHtml Set to true if email body is HTML. | |
| * @param array $urls Array of image URLs from HTML body. | |
| * @return void | |
| * | |
| * @see CACHE_TAG, | |
| * getCacheTime(), | |
| * Mage_Core_Model_Cache::save() | |
| */ | |
| protected function _saveContextDataToCache( $context_cache_id, $isHtml, $urls ) | |
| { | |
| /** @var $cache Mage_Core_Model_Cache */ | |
| $cache = Mage::getSingleton('core/cache'); | |
| $cache_time = $this->getCacheTime(); | |
| $context_data = array( | |
| 'urls' => $urls, | |
| 'is_html' => $isHtml, | |
| ); | |
| $context_data = serialize($context_data); | |
| $cache->save($context_data, $context_cache_id, array( self::CACHE_TAG ), $cache_time); | |
| Mage::log('EmailImages - saved context URLs to cache'); | |
| } | |
| /** | |
| * Attach image URLs to the email. | |
| * | |
| * @param Zend_Mail $mail Zend_Mail instance to attach images to. | |
| * @param array $urls Array of image URLs to attach. | |
| * @return void | |
| * | |
| * @see _retrieveImageData(), | |
| * Zend_Mime::MULTIPART_RELATED, | |
| * Zend_Mail::createAttachment(), Zend_Mail::setType(), | |
| * Zend_Mime_Part | |
| */ | |
| protected function _attachImageUrls( Zend_Mail $mail, array $urls ) | |
| { | |
| foreach ( $urls as $index => $url ) | |
| { | |
| if ( $url ) | |
| { | |
| // retrieved image data | |
| $data = $this->_retrieveImageData($url); | |
| if ( $data ) | |
| { | |
| // attach image data | |
| $mp = $mail->createAttachment($data['image'] | |
| , $data['size']['mime'] | |
| , Zend_Mime::DISPOSITION_INLINE | |
| , Zend_Mime::ENCODING_BASE64, basename($url) | |
| ); | |
| $mp->id = md5($url); | |
| $mp->location = $url; | |
| } | |
| else | |
| { | |
| Mage::log('EmailImages - unable to retrieve image from URL ' . $url, Zend_Log::WARN); | |
| // remove images that failed to load | |
| UnSet($urls[$index]); | |
| } | |
| } | |
| } | |
| // set Content-Type to multipart/related to properly display the images inline, if any | |
| if ( 0 < count($urls) ) | |
| $mail->setType(Zend_Mime::MULTIPART_RELATED); | |
| } | |
| /** | |
| * Retrieve image data from URL. | |
| * NB: uses file_get_contents(). | |
| * | |
| * @TODO should we try to use curl if available? should that be configurable by admin? | |
| * | |
| * @param string $url URL to retrieve image data from. | |
| * @return array|false Array with keys 'image' for image binary, 'size' for image size, if successfully retrieved image from URL; | |
| * false, otherwise. | |
| * | |
| * @see CACHE_TAG, CACHE_TYPE, | |
| * getCacheTime(), | |
| * Mage_Core_Model_Cache::canUse(), Mage_Core_Model_Cache::load(), Mage_Core_Model_Cache::save(), | |
| * file_get_contents() | |
| */ | |
| protected function _retrieveImageData( $url ) | |
| { | |
| // retrieve image from cache or URL | |
| /** @var $cache Mage_Core_Model_Cache */ | |
| $cache = Mage::getSingleton('core/cache'); | |
| $use_cache = $cache->canUse(self::CACHE_TYPE); | |
| $data = false; | |
| if ( $use_cache ) | |
| { | |
| $cache_id = self::CACHE_TYPE . $url; | |
| $data = $cache->load(self::CACHE_TYPE . $url); | |
| if ( $data ) | |
| $data = unserialize($data); | |
| } | |
| if ( !$data ) | |
| { | |
| // retrieve image data from URL | |
| Mage::log('EmailImages - loading image from URL ' . $url); | |
| $data = file_get_contents($url); | |
| if ( $data ) | |
| { | |
| $data = array( | |
| 'image' => $data, | |
| 'size' => getimagesize($url), | |
| ); | |
| } | |
| // save retrieved image data to cache even if retrieving the image failed, if allowed | |
| if ( $use_cache ) | |
| { | |
| $serialized_data = serialize($data); | |
| $cache_time = $this->getCacheTime(); | |
| $cache->save($serialized_data, $cache_id, array( self::CACHE_TAG ), $cache_time); | |
| Mage::log('EmailImages - saved image to cache'); | |
| } | |
| } | |
| else | |
| { | |
| Mage::log('EmailImages - loaded image from cache'); | |
| } | |
| return $data; | |
| } | |
| } |