mirror of
https://github.com/freescout-helpdesk/freescout.git
synced 2024-11-24 03:12:46 +01:00
Replace base64 images in messages with attachment URLs - closes #3057
This commit is contained in:
parent
ac76251b75
commit
0ef404f3ef
@ -753,6 +753,13 @@ class ConversationsController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$body = $request->body;
|
||||
|
||||
// Replace base64 images with attachment URLs in case text
|
||||
// was copy and pasted into the editor.
|
||||
// https://github.com/freescout-helpdesk/freescout/issues/3057
|
||||
$body = Thread::replaceBase64ImagesWithAttachments($body);
|
||||
|
||||
// List of emails.
|
||||
$to_array = [];
|
||||
if ($is_forward) {
|
||||
@ -789,7 +796,7 @@ class ConversationsController extends Controller
|
||||
$conversation = new Conversation();
|
||||
$conversation->type = $type;
|
||||
$conversation->subject = $request->subject;
|
||||
$conversation->setPreview($request->body);
|
||||
$conversation->setPreview($body);
|
||||
$conversation->mailbox_id = $request->mailbox_id;
|
||||
$conversation->created_by_user_id = auth()->user()->id;
|
||||
$conversation->source_via = Conversation::PERSON_USER;
|
||||
@ -937,7 +944,7 @@ class ConversationsController extends Controller
|
||||
$conversation->threads_count++;
|
||||
// We need to set preview here as when conversation is created from draft,
|
||||
// ThreadObserver::created() method is not called.
|
||||
$conversation->setPreview($request->body);
|
||||
$conversation->setPreview($body);
|
||||
}
|
||||
$conversation->save();
|
||||
|
||||
@ -993,7 +1000,7 @@ class ConversationsController extends Controller
|
||||
$thread->created_by_user_id = auth()->user()->id;
|
||||
$thread->edited_by_user_id = null;
|
||||
$thread->edited_at = null;
|
||||
$thread->body = $request->body;
|
||||
$thread->body = $body;
|
||||
if ($is_create && !$is_multiple && count($to_array) > 1) {
|
||||
$thread->setTo($to_array);
|
||||
} else {
|
||||
|
@ -1331,7 +1331,7 @@ class Helper
|
||||
$links = array();
|
||||
|
||||
// Extract existing links and tags
|
||||
$value = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links) { return '<' . array_push($links, $match[1]) . '>'; }, $value ?? '');
|
||||
$value = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links) { return '<' . array_push($links, $match[1]) . '>'; }, $value ?? '') ?: $value;
|
||||
|
||||
$value = $value ?? '';
|
||||
|
||||
@ -1339,14 +1339,17 @@ class Helper
|
||||
foreach ((array)$protocols as $protocol) {
|
||||
switch ($protocol) {
|
||||
case 'http':
|
||||
case 'https': $value = preg_replace_callback('~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) { if ($match[1]) $protocol = $match[1]; $link = $match[2] ?: $match[3]; return '<' . array_push($links, "<a $attr href=\"$protocol://$link\">$protocol://$link</a>") . '>'; }, $value); break;
|
||||
case 'mail': $value = preg_replace_callback('~([^\s<>]+?@[^\s<]+?\.[^\s<]+)(?<![\.,:])~', function ($match) use (&$links, $attr) { return '<' . array_push($links, "<a $attr href=\"mailto:{$match[1]}\">{$match[1]}</a>") . '>'; }, $value); break;
|
||||
default: $value = preg_replace_callback('~' . preg_quote($protocol, '~') . '://([^\s<]+?)(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) { return '<' . array_push($links, "<a $attr href=\"$protocol://{$match[1]}\">$protocol://{$match[1]}</a>") . '>'; }, $value); break;
|
||||
case 'https': $value = preg_replace_callback('~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) { if ($match[1]) $protocol = $match[1]; $link = $match[2] ?: $match[3]; return '<' . array_push($links, "<a $attr href=\"$protocol://$link\">$protocol://$link</a>") . '>'; }, $value) ?: $value;
|
||||
break;
|
||||
case 'mail': $value = preg_replace_callback('~([^\s<>]+?@[^\s<]+?\.[^\s<]+)(?<![\.,:])~', function ($match) use (&$links, $attr) { return '<' . array_push($links, "<a $attr href=\"mailto:{$match[1]}\">{$match[1]}</a>") . '>'; }, $value) ?: $value;
|
||||
break;
|
||||
default: $value = preg_replace_callback('~' . preg_quote($protocol, '~') . '://([^\s<]+?)(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) { return '<' . array_push($links, "<a $attr href=\"$protocol://{$match[1]}\">$protocol://{$match[1]}</a>") . '>'; }, $value) ?: $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert all link
|
||||
return preg_replace_callback('/<(\d+)>/', function ($match) use (&$links) { return $links[$match[1] - 1]; }, $value ?? '');
|
||||
return preg_replace_callback('/<(\d+)>/', function ($match) use (&$links) { return $links[$match[1] - 1]; }, $value ?? '') ?: $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1873,4 +1876,14 @@ class Helper
|
||||
$then = mb_substr($string, 1, null, $encoding);
|
||||
return mb_strtoupper($first_char, $encoding) . $then;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is needed to allow using regexes for large texts.
|
||||
*/
|
||||
public static function setPcreBacktrackLimit()
|
||||
{
|
||||
if ((int)ini_get('pcre.backtrack_limit') <= 1000000) {
|
||||
ini_set('pcre.backtrack_limit', 1000000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,11 +308,12 @@ class Thread extends Model
|
||||
|
||||
// Change "background:" to "background-color:".
|
||||
// https://github.com/freescout-helpdesk/freescout/issues/2560
|
||||
$body = preg_replace("/(<[^<>]+style=[\"'][^\"']*)background: *([^;() ]+;)/", '$1background-color:$2', $body);
|
||||
// Keep in mind that with large texts preg_replace() may return null.
|
||||
$body = preg_replace("/(<[^<>]+style=[\"'][^\"']*)background: *([^;() ]+;)/", '$1background-color:$2', $body) ?: $body;
|
||||
|
||||
// Cut out "collapse" class as it hides elements.
|
||||
$body = preg_replace("/(<[^<>\r\n]+class=([\"'][^\"']* |[\"']))(collapse|hidden)([\"' ])/", '$1$4', $body);
|
||||
|
||||
$body = preg_replace("/(<[^<>\r\n]+class=([\"'][^\"']* |[\"']))(collapse|hidden)([\"' ])/", '$1$4', $body) ?: $body;
|
||||
|
||||
return \Helper::purifyHtml($body);
|
||||
}
|
||||
|
||||
@ -352,7 +353,7 @@ class Thread extends Model
|
||||
return sprintf('target="_blank" %s', array_shift($m2));
|
||||
}, $tpl);
|
||||
|
||||
}, $body);
|
||||
}, $body) ?: $body;
|
||||
|
||||
return $body;
|
||||
}
|
||||
@ -1440,4 +1441,36 @@ class Thread extends Model
|
||||
{
|
||||
return $this->type == self::TYPE_MESSAGE;
|
||||
}
|
||||
|
||||
public static function replaceBase64ImagesWithAttachments($body, $user_id = null)
|
||||
{
|
||||
\Helper::setPcreBacktrackLimit();
|
||||
|
||||
$body = preg_replace_callback("#(<img[^<>]+src=[\"'])data:image/([^;]+);base64,([^\"']+)([\"'])#",
|
||||
function ($match) {
|
||||
$attachment = null;
|
||||
$data = base64_decode($match[3]);
|
||||
|
||||
if ($data) {
|
||||
$attachment = Attachment::create(
|
||||
$file_name = number_format(microtime(true), 4, '', '').'.'.$match[2],
|
||||
$mime_type = 'image/'.$match[2],
|
||||
$type = Attachment::TYPE_IMAGE,
|
||||
$data,
|
||||
$uploaded_file = null,
|
||||
$embedded = true,
|
||||
$thread_id = null,
|
||||
$user_id = \Auth::id()
|
||||
);
|
||||
}
|
||||
if ($attachment) {
|
||||
return $match[1].$attachment->url().$match[4];
|
||||
} else {
|
||||
return $match[0];
|
||||
}
|
||||
}, $body
|
||||
);
|
||||
|
||||
return $body;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user