Passed
Push — master ( 47c5a8...15e316 )
by Andreas
24:56
created

org_openpsa_mail_message::_process_attachments()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 15.5468

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 7
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 14
ccs 2
cts 8
cp 0.25
crap 15.5468
rs 9.6111
1
<?php
2
/**
3
 * @package org.openpsa.mail
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
use Symfony\Component\Mime\Email;
10
use Symfony\Component\Mime\Part\DataPart;
11
use Symfony\Component\Mime\MimeTypes;
12
13
/**
14
 * Wrapper class for emails
15
 *
16
 * @package org.openpsa.mail
17
 */
18
class org_openpsa_mail_message
19
{
20
    private $_to;
21
22
    private $_encoding;
23
24
    private $_headers;
25
26
    private $_body;
27
    private $_html_body;
28
29
    /**
30
     * @var Email
31
     */
32
    private $_message;
33
34 8
    public function __construct($to, array $headers, string $encoding)
35
    {
36 8
        $this->_to = $this->_encode_address_field($to);
37 8
        $this->_headers = $headers;
38 8
        $this->_encoding = $encoding;
39
40 8
        $this->_message = new Email;
41
    }
42
43 8
    public function get_recipients()
44
    {
45 8
        return $this->_to;
46
    }
47
48
    public function get_message() : Email
49
    {
50
        // set headers
51
        $headers_setter_map = [
52
            "from" => "from",
53
            "to" => "to",
54
            "cc" => "cc",
55
            "bcc" => "bcc",
56
            "reply-to" => "replyTo",
57
            "subject" => "subject",
58
            "date" => "date",
59
            "return-path" => "returnPath"
60
        ];
61
62
        // map headers we got to sf mailer setter methods
63
        $msg_headers = $this->_message->getHeaders();
64
65
        foreach ($this->get_headers() as $name => $value) {
66
            if (array_key_exists(strtolower($name), $headers_setter_map)) {
67
                $setter = $headers_setter_map[strtolower($name)];
68
                $this->_message->$setter($value);
69
            } elseif ($msg_headers->has($name)) {
70
                // header already exists => just set a new value
71
                $msg_headers->get($name)->setValue($value);
0 ignored issues
show
Bug introduced by
The method setValue() does not exist on Symfony\Component\Mime\Header\HeaderInterface. It seems like you code against a sub-type of Symfony\Component\Mime\Header\HeaderInterface such as Symfony\Component\Mime\Header\UnstructuredHeader. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

71
                $msg_headers->get($name)->/** @scrutinizer ignore-call */ setValue($value);
Loading history...
72
            } else {
73
                $msg_headers->addTextHeader($name, $value);
74
            }
75
        }
76
77
        // somehow we need to set the body after the headers...
78
        if (!empty($this->_html_body)) {
79
            $this->_message->html($this->_html_body);
80
        }
81
        $this->_message->text($this->_body);
82
83
        return $this->_message;
84
    }
85
86
    public function set_header_field(string $name, $value)
87
    {
88
        $this->_headers[$name] = $value;
89
    }
90
91 8
    public function get_headers() : array
92
    {
93 8
        reset($this->_headers);
94 8
        foreach ($this->_headers as $header => $value) {
95 8
            if (is_string($value)) {
96 8
                $this->_headers[$header] = trim($value);
97
            }
98 8
            if (in_array(strtolower($header), ['from', 'reply-to', 'to'])) {
99 7
                $this->_headers[$header] = $this->_encode_address_field($value);
100
            }
101
        }
102
103 8
        return $this->_headers;
104
    }
105
106 8
    public function get_body()
107
    {
108 8
        return $this->_body;
109
    }
110
111 6
    public function set_body($body)
112
    {
113 6
        $this->_body = $body;
114 6
        $this->_html_body = null;
115
    }
116
117 2
    public function set_html_body(string $body, string $altBody, array $attachments, bool $do_image_embedding)
118
    {
119 2
        $this->_body = $altBody;
120 2
        $this->_html_body = $body;
121
122
        // adjust html body
123 2
        if ($do_image_embedding) {
124 1
            $this->_embed_images();
125
        }
126
127
        // process attachments
128 2
        $this->_process_attachments($attachments);
129
    }
130
131 1
    private function _embed_images()
132
    {
133
        // anything with SRC = "" something in it (images etc)
134 1
        $regExp_src = "/(src|background)=([\"'�])(((https?|ftp):\/\/)?(.*?))\\2/i";
135 1
        preg_match_all($regExp_src, $this->_html_body, $matches_src);
136 1
        debug_print_r("matches_src:", $matches_src);
137
138 1
        $matches = [
139 1
            "whole" => $matches_src[0],
140 1
            "uri" => $matches_src[3],
141 1
            "proto" => $matches_src[4],
142 1
            "location" => $matches_src[6]
143
        ];
144
145 1
        foreach ($matches["whole"] as $key => $match) {
146
            $location = $matches["location"][$key];
147
            // uri is fully qualified
148
            if ($matches['proto'][$key]) {
149
                $uri = $matches["uri"][$key];
150
            }
151
            // uri is absolute
152
            elseif (str_starts_with($location, '/')) {
153
                $uri = midcom::get()->get_host_name() . $location;
154
            } else {
155
                debug_add('No usable uri found, skipping embed', MIDCOM_LOG_WARN);
156
                continue;
157
            }
158
159
            // replace src by embedded image
160
            $name = basename($uri);
161
            $mimetype = null;
162
            if ($ext = pathinfo($name, PATHINFO_EXTENSION)) {
163
                $mimetype = (new MimeTypes)->getMimeTypes($ext)[0] ?? null;
0 ignored issues
show
Bug introduced by
It seems like $ext can also be of type array; however, parameter $ext of Symfony\Component\Mime\MimeTypes::getMimeTypes() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

163
                $mimetype = (new MimeTypes)->getMimeTypes(/** @scrutinizer ignore-type */ $ext)[0] ?? null;
Loading history...
164
            }
165
166
            $part = (new DataPart(fopen($uri, 'r'), $name, $mimetype))
167
                ->asInline();
168
            $this->_message->attachPart($part);
169
170
            $new_html = str_replace($location, 'cid:' . $part->getContentId(), $match);
171
            $this->_html_body = str_replace($match, $new_html, $this->_html_body);
172
        }
173
    }
174
175 2
    private function _process_attachments(array $attachments)
176
    {
177 2
        foreach ($attachments as $att) {
178
            if (empty($att['mimetype'])) {
179
                $att['mimetype'] = "application/octet-stream";
180
            }
181
182
            // we got a file path
183
            if (!empty($att['file'])) {
184
                $this->_message->attachFromPath($att['file'], $att['name'], $att['mimetype']);
185
            }
186
            // we got the contents (bytes)
187
            elseif (!empty($att['content'])) {
188
                $this->_message->attach($att['content'], $att['name'], $att['mimetype']);
189
            }
190
        }
191
    }
192
193
    /**
194
     * Helper function that provides backwards compatibility
195
     * to addresses specified in a "Name <[email protected]>" format
196
     *
197
     * @param string $value The value to encode
198
     * @return mixed the encoded value
199
     */
200 8
    private function _encode_address_field($value)
201
    {
202 8
        if (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
203
            array_walk($value, [$this, '_encode_address_field']);
204
            return $value;
205
        }
206 8
        if ($pos = strpos($value, '<')) {
207 1
            $name = substr($value, 0, $pos);
208 1
            $name = preg_replace('/^\s*"/', '', $name);
209 1
            $name = preg_replace('/"\s*$/', '', $name);
210 1
            $address = substr($value, $pos + 1);
211 1
            $address = substr($address, 0, strlen($address) - 1);
212 1
            $value = [$address => $name];
213
        }
214 8
        return $value;
215
    }
216
}
217