Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F726789
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Jan 6, 12:29 AM
Size
25 KB
Mime Type
text/x-diff
Expires
Wed, Jan 8, 12:29 AM (1 d, 13 h ago)
Engine
blob
Format
Raw Data
Handle
536881
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/core/kernel/utility/email.php
===================================================================
--- branches/5.2.x/core/kernel/utility/email.php (revision 16749)
+++ branches/5.2.x/core/kernel/utility/email.php (revision 16750)
@@ -1,919 +1,920 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2012 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kEmail extends kBase {
/**
* Reference to class, that could send out e-mail
*
* @var kEmailSendingHelper
* @access protected
*/
protected $sender = null;
/**
* Parameters of e-mail
*
* @var Array
* @access protected
* @see kEmail::_getCustomParams() List of possible system parameters supported
*/
protected $params = Array ();
/**
* Reference to e-mail template object, that would be used as data source
*
* @var kDBItem
*/
protected $emailTemplate = null;
/**
* Sender name
*
* @var string
* @access protected
*/
protected $fromName = '';
/**
* Sender e-mail
*
* @var string
* @access protected
*/
protected $fromEmail = '';
/**
* Recipient name
*
* @var string
* @access protected
*/
protected $toName = '';
/**
* Recipient e-mail
*
* @var string
* @access protected
*/
protected $toEmail = '';
/**
* ID of recipient user
*
* @var int
*/
protected $recipientUserId = null;
/**
* List of e-mail recipients
*
* @var Array
* @access protected
*/
protected $recipients = Array (
EmailTemplate::RECIPIENT_TYPE_TO => Array (),
EmailTemplate::RECIPIENT_TYPE_CC => Array (),
EmailTemplate::RECIPIENT_TYPE_BCC => Array (),
);
/**
* Creates e-mail instance
*/
public function __construct()
{
parent::__construct();
$this->sender = $this->Application->recallObject('EmailSender');
}
/**
* Resets state of e-mail
*
* @return void
* @access protected
*/
protected function _resetState()
{
$this->fromEmail = $this->fromName = '';
$this->Application->removeObject('u.email-from');
$this->recipients = Array (
EmailTemplate::RECIPIENT_TYPE_TO => Array (),
EmailTemplate::RECIPIENT_TYPE_CC => Array (),
EmailTemplate::RECIPIENT_TYPE_BCC => Array (),
);
$this->toEmail = $this->toEmail = '';
$this->Application->removeObject('u.email-to');
}
/**
* Finds e-mail template matching user data
*
* @param string $name
* @param int $type
* @return bool
* @throws InvalidArgumentException
* @access public
*/
public function findTemplate($name, $type)
{
if ( !$name || !preg_match('/^[A-Z\.]+$/', $name) ) {
throw new InvalidArgumentException('Invalid e-mail template name "<strong>' . $name . '</strong>". Only <strong>UPPERCASE characters</strong> and <strong>dots</strong> are allowed.');
}
if ( $type != EmailTemplate::TEMPLATE_TYPE_ADMIN && $type != EmailTemplate::TEMPLATE_TYPE_FRONTEND ) {
throw new InvalidArgumentException('Invalid e-mail template type');
}
// use "-item" special prevent error, when e-mail sent out from e-mail templates list
$this->emailTemplate = $this->Application->recallObject('email-template.-item', null, Array ('skip_autoload' => true));
if ( !$this->emailTemplate->isLoaded() || !$this->_sameTemplate($name, $type) ) {
// get template parameters by name & type
$this->emailTemplate->Load(Array ('TemplateName' => $name, 'Type' => $type));
}
return $this->_templateUsable();
}
/**
* Detects, that given e-mail template data matches currently used e-mail template
*
* @param string $name
* @param int $type
* @return bool
* @access protected
*/
protected function _sameTemplate($name, $type)
{
return $this->emailTemplate->GetDBField('TemplateName') == $name && $this->emailTemplate->GetDBField('Type') == $type;
}
/**
* Determines if we can use e-mail template we've found based on user data
*
* @return bool
* @access protected
*/
protected function _templateUsable()
{
if ( !$this->emailTemplate->isLoaded() || $this->emailTemplate->GetDBField('Enabled') == STATUS_DISABLED ) {
return false;
}
if ( $this->emailTemplate->GetDBField('FrontEndOnly') && $this->Application->isAdmin ) {
return false;
}
return true;
}
/**
* Sets e-mail template params
*
* @param Array $params
* @access public
*/
public function setParams($params)
{
$this->params = $params;
}
/**
* Returns any custom parameters, that are passed when invoked e-mail template sending
*
* @return Array
* @access protected
*/
protected function _getCustomParams()
{
$ret = $this->params;
$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'overwrite_to_email', 'language_id', 'use_custom_design', 'delivery');
foreach ($send_keys as $send_key) {
unset($ret[$send_key]);
}
return $ret;
}
/**
* Sends e-mail now or puts it in queue
*
* @param integer $recipient_user_id Recipient user id.
* @param boolean $immediate_send Immediate send.
*
* @return boolean
*/
public function send($recipient_user_id = null, $immediate_send = null)
{
$this->recipientUserId = $recipient_user_id;
$this->_resetState();
$this->_processSender();
$this->_processRecipients();
$this->_changeLanguage(false);
// 1. set headers
$message_headers = $this->_getHeaders();
$message_subject = isset($message_headers['Subject']) ? $message_headers['Subject'] : 'Mail message';
$this->sender->SetSubject($message_subject);
foreach ($message_headers as $header_name => $header_value) {
$this->sender->SetEncodedHeader($header_name, $header_value);
}
if ( $this->_storeEmailLog() ) {
// 2. prepare log
$log_fields_hash = Array (
'From' => $this->fromName . ' (' . $this->fromEmail . ')',
'To' => $this->toName . ' (' . $this->toEmail . ')',
'OtherRecipients' => serialize($this->recipients),
'Subject' => $message_subject,
'SentOn' => TIMENOW,
'TemplateName' => $this->emailTemplate->GetDBField('TemplateName'),
'EventType' => $this->emailTemplate->GetDBField('Type'),
'EventParams' => serialize($this->_getCustomParams()),
);
$this->params['email_access_key'] = $this->_generateAccessKey($log_fields_hash);
}
// 3. set body
$html_message_body = $this->_getMessageBody(true);
$plain_message_body = $this->_getMessageBody(false);
if ( $html_message_body === false && $plain_message_body === false ) {
+ $this->sender->Clear();
trigger_error('Message template is empty (maybe after parsing).', E_USER_WARNING);
return false;
}
if ( $html_message_body !== false ) {
$this->sender->CreateTextHtmlPart($html_message_body, true);
}
if ( $plain_message_body !== false ) {
$this->sender->CreateTextHtmlPart($plain_message_body, false);
}
$this->_changeLanguage(true);
if ( $this->_storeEmailLog() ) {
// 4. set log
$log_fields_hash['HtmlBody'] = $html_message_body;
$log_fields_hash['TextBody'] = $plain_message_body;
$log_fields_hash['AccessKey'] = $this->params['email_access_key'];
$this->sender->setLogData($log_fields_hash);
}
if ( !isset($immediate_send) ) {
if ( isset($this->params['delivery']) ) {
$delivery = $this->params['delivery'];
}
else {
$delivery = $this->Application->ConfigValue('EmailDelivery');
}
$immediate_send = $delivery == EmailDelivery::IMMEDIATE;
}
return $this->sender->Deliver(null, $immediate_send);
}
/**
* Determines whatever we should keep e-mail log or not
*
* @return bool
* @access protected
*/
protected function _storeEmailLog()
{
return $this->Application->ConfigValue('EnableEmailLog');
}
/**
* Generates access key for accessing e-mail later
*
* @param Array $log_fields_hash
* @return string
* @access protected
*/
protected function _generateAccessKey($log_fields_hash)
{
$ret = '';
$use_fields = Array ('From', 'To', 'Subject');
foreach ($use_fields as $use_field) {
$ret .= $log_fields_hash[$use_field] . ':';
}
return md5($ret . microtime(true));
}
/**
* Processes email sender
*
* @return void
* @access protected
*/
protected function _processSender()
{
if ( $this->emailTemplate->GetDBField('CustomSender') ) {
$this->_processCustomSender();
}
// update with custom data given during event execution
if ( isset($this->params['from_email']) ) {
$this->fromEmail = $this->params['from_email'];
}
if ( isset($this->params['from_name']) ) {
$this->fromName = $this->params['from_name'];
}
// still nothing, set defaults
$this->_ensureDefaultSender();
$this->sender->SetFrom($this->fromEmail, $this->fromName);
}
/**
* Processes custom e-mail sender
*
* @return void
* @access protected
*/
protected function _processCustomSender()
{
$address = $this->emailTemplate->GetDBField('SenderAddress');
$address_type = $this->emailTemplate->GetDBField('SenderAddressType');
switch ($address_type) {
case EmailTemplate::ADDRESS_TYPE_EMAIL:
$this->fromEmail = $address;
break;
case EmailTemplate::ADDRESS_TYPE_USER:
$sql = 'SELECT FirstName, LastName, Email, PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE Username = ' . $this->Conn->qstr($address);
$user_info = $this->Conn->GetRow($sql);
if ( $user_info ) {
// user still exists
$this->fromEmail = $user_info['Email'];
$this->fromName = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
/** @var UsersItem $user */
$user = $this->Application->recallObject(
'u.email-from',
null,
array('live_table' => true, 'skip_autoload' => true)
);
$user->Load($user_info['PortalUserId']);
}
break;
}
if ( $this->emailTemplate->GetDBField('SenderName') ) {
$this->fromName = $this->emailTemplate->GetDBField('SenderName');
}
}
/**
* Ensures, that sender name & e-mail are not empty
*
* @return void
* @access protected
*/
protected function _ensureDefaultSender()
{
if ( !$this->fromEmail ) {
$this->fromEmail = $this->Application->ConfigValue('DefaultEmailSender');
}
if ( !$this->fromName ) {
$this->fromName = strip_tags($this->Application->ConfigValue('Site_Name'));
}
}
/**
* Processes email recipients
*
* @return void
* @access protected
*/
protected function _processRecipients()
{
$this->_collectRecipients();
$header_mapping = $this->getHeaderMapping();
$default_email = $this->Application->ConfigValue('DefaultEmailSender');
$this->recipients = array_map(Array ($this, '_transformRecipientsIntoPairs'), $this->recipients);
foreach ($this->recipients as $recipient_type => $recipients) {
// add recipients to email
if ( !$recipients ) {
continue;
}
if ( $recipient_type == EmailTemplate::RECIPIENT_TYPE_TO ) {
$this->toEmail = $recipients[0]['email'] ? $recipients[0]['email'] : $default_email;
$this->toName = $recipients[0]['name'] ? $recipients[0]['name'] : $this->toEmail;
}
$header_name = $header_mapping[$recipient_type];
foreach ($recipients as $recipient) {
$email = $recipient['email'] ? $recipient['email'] : $default_email;
$name = $recipient['name'] ? $recipient['name'] : $email;
$this->sender->AddRecipient($header_name, $email, $name);
}
}
}
/**
* Collects e-mail recipients from various sources
*
* @return void
* @access protected
*/
protected function _collectRecipients()
{
$this->_addRecipientsFromXml($this->emailTemplate->GetDBField('Recipients'));
$this->_overwriteToRecipient();
$this->_addRecipientByUserId();
$this->_addRecipientFromParams();
$this->_moveDirectRecipients();
if ( ($this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN) && !$this->recipients[EmailTemplate::RECIPIENT_TYPE_TO] ) {
// admin email template without direct recipient -> send to admin
$this->_addDefaultRecipient();
}
}
/**
* Adds multiple recipients from an XML
*
* @param string $xml
* @return bool
* @access protected
*/
protected function _addRecipientsFromXml($xml)
{
if ( !$xml ) {
return false;
}
/** @var MInputHelper $minput_helper */
$minput_helper = $this->Application->recallObject('MInputHelper');
// group recipients by type
$records = $minput_helper->parseMInputXML($xml);
foreach ($records as $record) {
$this->recipients[$record['RecipientType']][] = $record;
}
return true;
}
/**
* Remove all "To" recipients, when not allowed
*
* @return void
* @access protected
*/
protected function _overwriteToRecipient()
{
$overwrite_to_email = isset($this->params['overwrite_to_email']) ? $this->params['overwrite_to_email'] : false;
if ( !$this->emailTemplate->GetDBField('CustomRecipient') || $overwrite_to_email ) {
$this->recipients[EmailTemplate::RECIPIENT_TYPE_TO] = Array ();
}
}
/**
* Update with custom data given during event execution (user_id)
*
* @return void
* @access protected
*/
protected function _addRecipientByUserId()
{
if ( !is_numeric($this->recipientUserId) ) {
return;
}
if ( $this->recipientUserId <= 0 ) {
// recipient is system user with negative ID (root, guest, etc.) -> send to admin
$this->_addDefaultRecipient();
return;
}
$language_field = $this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_FRONTEND ? 'FrontLanguage' : 'AdminLanguage';
$sql = 'SELECT FirstName, LastName, Email, ' . $language_field . ' AS Language
FROM ' . TABLE_PREFIX . 'Users
WHERE PortalUserId = ' . $this->recipientUserId;
$user_info = $this->Conn->GetRow($sql);
if ( !$user_info ) {
return;
}
$add_recipient = Array (
'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $user_info['Email'],
'RecipientName' => trim($user_info['FirstName'] . ' ' . $user_info['LastName']),
);
if ( $user_info['Language'] && !isset($this->params['language_id']) ) {
$this->params['language_id'] = $user_info['Language'];
}
array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $add_recipient);
/** @var UsersItem $user */
$user = $this->Application->recallObject(
'u.email-to',
null,
array('live_table' => true, 'skip_autoload' => true)
);
$user->Load($this->recipientUserId);
}
/**
* Update with custom data given during event execution (email + name)
*
* @return void
* @access protected
*/
protected function _addRecipientFromParams()
{
$add_recipient = Array ();
if ( isset($this->params['to_email']) && $this->params['to_email'] ) {
$add_recipient['RecipientName'] = '';
$add_recipient['RecipientAddressType'] = EmailTemplate::ADDRESS_TYPE_EMAIL;
$add_recipient['RecipientAddress'] = $this->params['to_email'];
}
if ( isset($this->params['to_name']) && $this->params['to_name'] ) {
$add_recipient['RecipientName'] = $this->params['to_name'];
}
if ( $add_recipient ) {
array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $add_recipient);
}
}
/**
* Move recipients, that were added manually via "$this->sender->Add*" methods.
*
* @return void
* @access protected
*/
protected function _moveDirectRecipients()
{
foreach ( $this->getHeaderMapping() as $recipient_type => $header_name ) {
$manual_recipients = $this->sender->GetRecipientsByHeader($header_name);
if ( !$manual_recipients ) {
continue;
}
foreach ( $manual_recipients as $manual_recipient ) {
$this->recipients[$recipient_type][] = array(
'RecipientName' => $manual_recipient['Name'],
'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $manual_recipient['Email'],
);
}
$this->sender->SetHeader($header_name, '');
}
}
/**
* Returns mapping between recipient type and header name.
*
* @return array
*/
protected function getHeaderMapping()
{
return array(
EmailTemplate::RECIPIENT_TYPE_TO => 'To',
EmailTemplate::RECIPIENT_TYPE_CC => 'Cc',
EmailTemplate::RECIPIENT_TYPE_BCC => 'Bcc',
);
}
/**
* This is default recipient, when we can't determine actual one
*
* @return void
* @access protected
*/
protected function _addDefaultRecipient()
{
$xml = $this->Application->ConfigValue('DefaultEmailRecipients');
if ( !$this->_addRecipientsFromXml($xml) ) {
$recipient = Array (
'RecipientName' => $this->Application->ConfigValue('DefaultEmailSender'),
'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $this->Application->ConfigValue('DefaultEmailSender'),
);
array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $recipient);
}
}
/**
* Transforms recipients into name/e-mail pairs
*
* @param Array $recipients
* @return Array
* @access protected
*/
protected function _transformRecipientsIntoPairs($recipients)
{
if ( !$recipients ) {
return Array ();
}
$pairs = Array ();
foreach ($recipients as $recipient) {
$address = $recipient['RecipientAddress'];
$address_type = $recipient['RecipientAddressType'];
$recipient_name = $recipient['RecipientName'];
switch ($address_type) {
case EmailTemplate::ADDRESS_TYPE_EMAIL:
$pairs[] = Array ('email' => $address, 'name' => $recipient_name);
break;
case EmailTemplate::ADDRESS_TYPE_USER:
$sql = 'SELECT FirstName, LastName, Email
FROM ' . TABLE_PREFIX . 'Users
WHERE Username = ' . $this->Conn->qstr($address);
$user_info = $this->Conn->GetRow($sql);
if ( $user_info ) {
// user still exists
$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
$pairs[] = Array (
'email' => $user_info['Email'],
'name' => $name ? $name : $recipient_name,
);
}
break;
case EmailTemplate::ADDRESS_TYPE_GROUP:
$sql = 'SELECT u.FirstName, u.LastName, u.Email
FROM ' . TABLE_PREFIX . 'UserGroups g
JOIN ' . TABLE_PREFIX . 'UserGroupRelations ug ON ug.GroupId = g.GroupId
JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId
WHERE g.Name = ' . $this->Conn->qstr($address);
$users = $this->Conn->Query($sql);
foreach ($users as $user_info) {
$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
$pairs[] = Array (
'email' => $user_info['Email'],
'name' => $name ? $name : $recipient_name,
);
}
break;
}
}
return $pairs;
}
/**
* Change system language temporarily to send e-mail on user language
*
* @param bool $restore
* @return void
* @access protected
*/
protected function _changeLanguage($restore = false)
{
static $prev_language_id = null;
if ( !isset($prev_language_id) ) {
$prev_language_id = $this->Application->GetVar('m_lang');
}
// ensure that language is set
if ( !isset($this->params['language_id']) ) {
$this->params['language_id'] = $this->Application->GetVar('m_lang');
}
$language_id = $restore ? $prev_language_id : $this->params['language_id'];
$this->Application->SetVar('m_lang', $language_id);
/** @var LanguagesItem $language */
$language = $this->Application->recallObject('lang.current');
$language->Load($language_id);
$this->Application->Phrases->LanguageId = $language_id;
$this->Application->Phrases->Phrases = Array ();
}
/**
* Parses message headers into array
*
* @return Array
* @access protected
*/
protected function _getHeaders()
{
$headers = $this->emailTemplate->GetDBField('Headers');
$headers = 'Subject: ' . $this->emailTemplate->GetField('Subject') . ($headers ? "\n" . $headers : '');
$headers = explode("\n", $this->_parseText($headers));
$ret = Array ();
foreach ($headers as $header) {
$header = explode(':', $header, 2);
$ret[ trim($header[0]) ] = trim($header[1]);
}
if ( $this->Application->isDebugMode() ) {
// set special header with template name, so it will be easier to determine what's actually was received
$template_type = $this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN ? 'ADMIN' : 'USER';
$ret['X-Template-Name'] = $this->emailTemplate->GetDBField('TemplateName') . ' - ' . $template_type;
}
return $ret;
}
/**
* Applies design to given e-mail text
*
* @param string $text
* @param bool $is_html
* @return string
* @access protected
*/
protected function _applyMessageDesign($text, $is_html = true)
{
static $design_templates = Array();
$design_key = 'L' . $this->params['language_id'] . ':' . ($is_html ? 'html' : 'text');
if ( !isset($design_templates[$design_key]) ) {
/** @var LanguagesItem $language */
$language = $this->Application->recallObject('lang.current');
$design_template = $language->GetDBField($is_html ? 'HtmlEmailTemplate' : 'TextEmailTemplate');
if ( !$is_html && !$design_template ) {
$design_template = $this->sender->ConvertToText($language->GetDBField('HtmlEmailTemplate'), true);
}
$design_templates[$design_key] = $design_template;
}
return $this->_parseText(str_replace('$body', $text, $design_templates[$design_key]), $is_html);
}
/**
* Returns message body
*
* @param bool $is_html
* @return bool|string
* @access protected
*/
protected function _getMessageBody($is_html = false)
{
$message_body = $this->emailTemplate->GetField($is_html ? 'HtmlBody' : 'PlainTextBody');
if ( !trim($message_body) && !$is_html ) {
// no plain text part available -> make it from html part then
$message_body = $this->sender->ConvertToText($this->emailTemplate->GetField('HtmlBody'), true);
}
if ( !trim($message_body) ) {
return false;
}
if ( isset($this->params['use_custom_design']) && $this->params['use_custom_design'] ) {
$message_body = $this->_parseText($message_body, $is_html);
}
else {
$message_body = $this->_applyMessageDesign($message_body, $is_html);
}
return trim($message_body) ? $message_body : false;
}
/**
* Parse message template and return headers (as array) and message body part
*
* @param string $text
* @param bool $is_html
* @return string
* @access protected
*/
protected function _parseText($text, $is_html = true)
{
$text = $this->_substituteReplacementTags($text);
if ( !$text ) {
return '';
}
// init for cases, when e-mail is sent from event before page template rendering
$this->Application->InitParser();
$parser_params = $this->Application->Parser->Params; // backup parser params
$this->Application->Parser->SetParams($this->params);
$template_name = 'et_' . $this->emailTemplate->GetID() . '_' . crc32($text);
$text = $this->Application->Parser->Parse($this->_normalizeLineEndings($text), $template_name);
$this->Application->Parser->SetParams($parser_params); // restore parser params
/** @var CategoryHelper $category_helper */
$category_helper = $this->Application->recallObject('CategoryHelper');
return $category_helper->replacePageIds($is_html ? $this->_removeTrailingLineEndings($text) : $text);
}
/**
* Substitutes replacement tags in given text
*
* @param string $text
* @return string
* @access protected
*/
protected function _substituteReplacementTags($text)
{
$default_replacement_tags = Array (
'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Username"',
'<inp:touser _Field' => '<inp2:u_Field name',
);
$replacement_tags = $this->emailTemplate->GetDBField('ReplacementTags');
$replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array ();
$replacement_tags = array_merge($default_replacement_tags, $replacement_tags);
foreach ($replacement_tags as $replace_from => $replace_to) {
$text = str_replace($replace_from, $replace_to, $text);
}
return $text;
}
/**
* Convert Unix/Windows/Mac line ending into Unix line endings
*
* @param string $text
* @return string
* @access protected
*/
protected function _normalizeLineEndings($text)
{
return str_replace(Array ("\r\n", "\r"), "\n", $text);
}
/**
* Remove trailing line endings
*
* @param $text
* @return string
* @access protected
*/
protected function _removeTrailingLineEndings($text)
{
return preg_replace('/(\n|\r)+/', "\\1", $text);
}
}
Event Timeline
Log In to Comment