Issues (1844)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

class/pear/Mail/mime.php (18 issues)

1
<?php
2
// +-----------------------------------------------------------------------+
3
// | Copyright (c) 2002  Richard Heyes                                     |
4
// | All rights reserved.                                                  |
5
// |                                                                       |
6
// | Redistribution and use in source and binary forms, with or without    |
7
// | modification, are permitted provided that the following conditions    |
8
// | are met:                                                              |
9
// |                                                                       |
10
// | o Redistributions of source code must retain the above copyright      |
11
// |   notice, this list of conditions and the following disclaimer.       |
12
// | o Redistributions in binary form must reproduce the above copyright   |
13
// |   notice, this list of conditions and the following disclaimer in the |
14
// |   documentation and/or other materials provided with the distribution.|
15
// | o The names of the authors may not be used to endorse or promote      |
16
// |   products derived from this software without specific prior written  |
17
// |   permission.                                                         |
18
// |                                                                       |
19
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
20
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
21
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
23
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
25
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
28
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
30
// |                                                                       |
31
// +-----------------------------------------------------------------------+
32
// | Author: Richard Heyes <[email protected]>                           |
33
// |         Tomas V.V.Cox <[email protected]> (port to PEAR)                |
34
// +-----------------------------------------------------------------------+
35
//
36
37
require_once XHELP_PEAR_PATH . '/PEAR.php';
38
require_once XHELP_PEAR_PATH . '/Mail/mimePart.php';
39
40
/**
41
 * Mime mail composer class. Can handle: text and html bodies, embedded html
42
 * images and attachments.
43
 * Documentation and examples of this class are avaible here:
44
 * https://pear.php.net/manual/
45
 *
46
 * @notes   This class is based on HTML Mime Mail class from
47
 *   Richard Heyes <[email protected]> which was based also
48
 *   in the mime_mail.class by Tobias Ratschiller <[email protected]> and
49
 *   Sascha Schumann <[email protected]>.
50
 *
51
 * @author  Richard Heyes <[email protected]>
52
 * @author  Tomas V.V.Cox <[email protected]>
53
 */
54
class Mail_mime
55
{
56
    /**
57
     * Contains the plain text part of the email
58
     * @var string
59
     */
60
    public $_txtbody;
61
    /**
62
     * Contains the html part of the email
63
     * @var string
64
     */
65
    public $_htmlbody;
66
    /**
67
     * contains the mime encoded text
68
     * @var string
69
     */
70
    public $_mime;
71
    /**
72
     * contains the multipart content
73
     * @var string
74
     */
75
    public $_multipart;
76
    /**
77
     * list of the attached images
78
     * @var array
79
     */
80
    public $_html_images = [];
81
    /**
82
     * list of the attachements
83
     * @var array
84
     */
85
    public $_parts = [];
86
    /**
87
     * Build parameters
88
     * @var array
89
     */
90
    public $_build_params = [];
91
    /**
92
     * Headers for the mail
93
     * @var array
94
     */
95
    public $_headers = [];
96
    /*
97
     * Constructor function
98
     *
99
     * @access public
100
     */
101
102
    /**
103
     * Mail_mime constructor.
104
     * @param string $crlf
105
     */
106
    public function __construct(string $crlf = "\r\n")
107
    {
108
        if (!defined('MAIL_MIME_CRLF')) {
109
            define('MAIL_MIME_CRLF', $crlf, true);
110
        }
111
112
        $this->_boundary = '=_' . md5(uniqid(time(), true));
0 ignored issues
show
Bug Best Practice introduced by
The property _boundary does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
113
114
        $this->_build_params = [
115
            'text_encoding' => '7bit',
116
            'html_encoding' => 'quoted-printable',
117
            '7bit_wrap'     => 998,
118
            'html_charset'  => 'ISO-8859-1',
119
            'text_charset'  => 'ISO-8859-1',
120
            'head_charset'  => 'ISO-8859-1',
121
        ];
122
    }
123
124
    /**
125
     * Accessor function to set the body text. Body text is used if
126
     * it's not an html mail being sent or else is used to fill the
127
     * text/plain part that emails clients who don't support
128
     * html should show.
129
     *
130
     * @param string $data   Either a string or the file name with the
131
     *                       contents
132
     * @param bool   $isfile If true the first param should be trated
133
     *                       as a file name, else as a string (default)
134
     * @param bool   $append If true the text or file is appended to the
135
     *                       existing body, else the old body is overwritten
136
     * @return bool|\myservices_PEAR_Error|object|\PEAR_Error|string true on success or PEAR_Error object
0 ignored issues
show
The type myservices_PEAR_Error was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
137
     * @access public
138
     */
139
    public function setTXTBody(string $data, bool $isfile = false, bool $append = false)
140
    {
141
        if ($isfile) {
142
            $cont = $this->_file2str($data);
143
            if (PEAR::isError($cont)) {
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::isError() is not static, but was called statically. ( Ignorable by Annotation )

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

143
            if (PEAR::/** @scrutinizer ignore-call */ isError($cont)) {
Loading history...
144
                return $cont;
145
            }
146
            if ($append) {
147
                $this->_txtbody .= $cont;
148
            } else {
149
                $this->_txtbody = $cont;
0 ignored issues
show
Documentation Bug introduced by
It seems like $cont can also be of type PEAR_Error. However, the property $_txtbody is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
150
            }
151
        } else {
152
            if (!$append) {
153
                $this->_txtbody = $data;
154
            } else {
155
                $this->_txtbody .= $data;
156
            }
157
        }
158
159
        return true;
160
    }
161
162
    /**
163
     * Adds a html part to the mail
164
     *
165
     * @param string $data   Either a string or the file name with the
166
     *                       contents
167
     * @param bool   $isfile If true the first param should be trated
168
     *                       as a file name, else as a string (default)
169
     * @return bool|\myservices_PEAR_Error|object|\PEAR_Error|string true on success or PEAR_Error object
170
     */
171
    public function setHTMLBody(string $data, bool $isfile = false)
172
    {
173
        if ($isfile) {
174
            $cont = $this->_file2str($data);
175
            if (PEAR::isError($cont)) {
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::isError() is not static, but was called statically. ( Ignorable by Annotation )

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

175
            if (PEAR::/** @scrutinizer ignore-call */ isError($cont)) {
Loading history...
176
                return $cont;
177
            }
178
            $this->_htmlbody = $cont;
0 ignored issues
show
Documentation Bug introduced by
It seems like $cont can also be of type PEAR_Error. However, the property $_htmlbody is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
179
        } else {
180
            $this->_htmlbody = $data;
181
        }
182
183
        return true;
184
    }
185
186
    /**
187
     * Adds an image to the list of embedded images.
188
     *
189
     * @param string $file       The image file name OR image data itself
190
     * @param string $c_type     The content type
191
     * @param string $name       The filename of the image. Only use if $file is the image data
192
     * @param bool   $isfilename Whether $file is a filename or not. Defaults to true
193
     * @return bool|\myservices_PEAR_Error|object|\PEAR_Error|string true on success or PEAR_Error object
194
     * @access public
195
     */
196
    public function addHTMLImage(string $file, string $c_type = 'application/octet-stream', string $name = '', bool $isfilename = true)
197
    {
198
        $filedata = ($isfilename) ? $this->_file2str($file) : $file;
199
        $filename = ($isfilename) ? basename($file) : basename($name);
200
        if (PEAR::isError($filedata)) {
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::isError() is not static, but was called statically. ( Ignorable by Annotation )

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

200
        if (PEAR::/** @scrutinizer ignore-call */ isError($filedata)) {
Loading history...
201
            return $filedata;
202
        }
203
        $this->_html_images[] = [
204
            'body'   => $filedata,
205
            'name'   => $filename,
206
            'c_type' => $c_type,
207
            'cid'    => md5(uniqid(time(), true)),
208
        ];
209
210
        return true;
211
    }
212
213
    /**
214
     * Adds a file to the list of attachments.
215
     *
216
     * @param string $file       The file name of the file to attach OR the file data itself
217
     * @param string $c_type     The content type
218
     * @param string $name       The filename of the attachment. Only use if $file is the file data
219
     * @param bool   $isfilename Whether $file is a filename or not. Defaults to true
220
     * @return bool|\myservices_PEAR_Error|object|\PEAR_Error|string true on success or PEAR_Error object
221
     * @access public
222
     */
223
    public function addAttachment(string $file, string $c_type = 'application/octet-stream', string $name = '', bool $isfilename = true, string $encoding = 'base64')
224
    {
225
        $filedata = ($isfilename) ? $this->_file2str($file) : $file;
226
        if ($isfilename) {
227
            // Force the name the user supplied, otherwise use $file
228
            $filename = !empty($name) ? $name : $file;
229
        } else {
230
            $filename = $name;
231
        }
232
        if (empty($filename)) {
233
            return PEAR::raiseError('The supplied filename for the attachment can\'t be empty');
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::raiseError() is not static, but was called statically. ( Ignorable by Annotation )

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

233
            return PEAR::/** @scrutinizer ignore-call */ raiseError('The supplied filename for the attachment can\'t be empty');
Loading history...
234
        }
235
        $filename = basename($filename);
236
        if (PEAR::isError($filedata)) {
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::isError() is not static, but was called statically. ( Ignorable by Annotation )

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

236
        if (PEAR::/** @scrutinizer ignore-call */ isError($filedata)) {
Loading history...
237
            return $filedata;
238
        }
239
240
        $this->_parts[] = [
241
            'body'     => $filedata,
242
            'name'     => $filename,
243
            'c_type'   => $c_type,
244
            'encoding' => $encoding,
245
        ];
246
247
        return true;
248
    }
249
250
    /**
251
     * Returns the contents of the given file name as string
252
     * @param string $file_name
253
     * @return false|\myservices_PEAR_Error|object|\PEAR_Error|string
254
     * @acces private
255
     */
256
    private function &_file2str(string $file_name)
257
    {
258
        if (!is_readable($file_name)) {
259
            return PEAR::raiseError('File is not readable ' . $file_name);
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::raiseError() is not static, but was called statically. ( Ignorable by Annotation )

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

259
            return PEAR::/** @scrutinizer ignore-call */ raiseError('File is not readable ' . $file_name);
Loading history...
260
        }
261
        if (!$fd = fopen($file_name, 'rb')) {
262
            return PEAR::raiseError('Could not open ' . $file_name);
263
        }
264
        $cont = fread($fd, filesize($file_name));
265
        fclose($fd);
266
267
        return $cont;
268
    }
269
270
    /**
271
     * Adds a text subpart to the mimePart object and
272
     * returns it during the build process.
273
     *
274
     * @param mixed  $obj  The object to add the part to, or
275
     *                     null if a new object is to be created.
276
     * @param string $text The text to add.
277
     * @return \Mail_mimePart  The text mimePart object
278
     */
279
280
    private function &_addTextPart($obj, string $text): Mail_mimePart
281
    {
282
        $params['content_type'] = 'text/plain';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
283
        $params['encoding']     = $this->_build_params['text_encoding'];
284
        $params['charset']      = $this->_build_params['text_charset'];
285
        if (is_object($obj)) {
286
            return $obj->addSubPart($text, $params);
287
        }
288
289
        return new Mail_mimePart($text, $params);
290
    }
291
292
    /**
293
     * Adds a html subpart to the mimePart object and
294
     * returns it during the build process.
295
     *
296
     * @param mixed $obj The object to add the part to, or
297
     *                   null if a new object is to be created.
298
     * @return \Mail_mimePart  The html mimePart object
299
     */
300
    private function &_addHtmlPart($obj): Mail_mimePart
301
    {
302
        $params['content_type'] = 'text/html';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
303
        $params['encoding']     = $this->_build_params['html_encoding'];
304
        $params['charset']      = $this->_build_params['html_charset'];
305
        if (is_object($obj)) {
306
            return $obj->addSubPart($this->_htmlbody, $params);
307
        }
308
309
        return new Mail_mimePart($this->_htmlbody, $params);
310
    }
311
312
    /**
313
     * Creates a new mimePart object, using multipart/mixed as
314
     * the initial content-type and returns it during the
315
     * build process.
316
     *
317
     * @return \Mail_mimePart  The multipart/mixed mimePart object
318
     */
319
    private function &_addMixedPart(): Mail_mimePart
320
    {
321
        $params['content_type'] = 'multipart/mixed';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
322
323
        return new Mail_mimePart('', $params);
324
    }
325
326
    /**
327
     * Adds a multipart/alternative part to a mimePart
328
     * object, (or creates one), and returns it  during
329
     * the build process.
330
     *
331
     * @param mixed $obj The object to add the part to, or
332
     *                   null if a new object is to be created.
333
     * @return \Mail_mimePart  The multipart/mixed mimePart object
334
     */
335
    private function &_addAlternativePart($obj): Mail_mimePart
336
    {
337
        $params['content_type'] = 'multipart/alternative';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
338
        if (is_object($obj)) {
339
            return $obj->addSubPart('', $params);
340
        }
341
342
        return new Mail_mimePart('', $params);
343
    }
344
345
    /**
346
     * Adds a multipart/related part to a mimePart
347
     * object, (or creates one), and returns it  during
348
     * the build process.
349
     *
350
     * @param mixed $obj The object to add the part to, or
351
     *                   null if a new object is to be created.
352
     * @return \Mail_mimePart  The multipart/mixed mimePart object
353
     */
354
    private function &_addRelatedPart($obj): Mail_mimePart
355
    {
356
        $params['content_type'] = 'multipart/related';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
357
        if (is_object($obj)) {
358
            return $obj->addSubPart('', $params);
359
        }
360
361
        return new Mail_mimePart('', $params);
362
    }
363
364
    /**
365
     * Adds an html image subpart to a mimePart object
366
     * and returns it during the build process.
367
     *
368
     * @param Mail_mimePart $obj   The mimePart to add the image to
369
     * @param array         $value The image information
370
     * @return void The image mimePart object
371
     */
372
    private function &_addHtmlImagePart(Mail_mimePart $obj, array $value): void
373
    {
374
        $params['content_type'] = $value['c_type'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
375
        $params['encoding']     = 'base64';
376
        $params['disposition']  = 'inline';
377
        $params['dfilename']    = $value['name'];
378
        $params['cid']          = $value['cid'];
379
        $obj->addSubPart($value['body'], $params);
380
    }
381
382
    /**
383
     * Adds an attachment subpart to a mimePart object
384
     * and returns it during the build process.
385
     *
386
     * @param Mail_mimePart $obj   The mimePart to add the image to
387
     * @param array         $value The attachment information
388
     * @return void The image mimePart object
389
     * @access private
390
     */
391
    private function &_addAttachmentPart(Mail_mimePart $obj, array $value): void
392
    {
393
        $params['content_type'] = $value['c_type'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
394
        $params['encoding']     = $value['encoding'];
395
        $params['disposition']  = 'attachment';
396
        $params['dfilename']    = $value['name'];
397
        $obj->addSubPart($value['body'], $params);
398
    }
399
400
    /**
401
     * Builds the multipart message from the list ($this->_parts) and
402
     * returns the mime content.
403
     *
404
     * @param array|null $build_params  Build parameters that change the way the email
405
     *                                  is built. Should be associative. Can contain:
406
     *                                  text_encoding  -  What encoding to use for plain text
407
     *                                  Default is 7bit
408
     *                                  html_encoding  -  What encoding to use for html
409
     *                                  Default is quoted-printable
410
     *                                  7bit_wrap      -  Number of characters before text is
411
     *                                  wrapped in 7bit encoding
412
     *                                  Default is 998
413
     *                                  html_charset   -  The character set to use for html.
414
     *                                  Default is iso-8859-1
415
     *                                  text_charset   -  The character set to use for text.
416
     *                                  Default is iso-8859-1
417
     *                                  head_charset   -  The character set to use for headers.
418
     *                                  Default is iso-8859-1
419
     * @return false|mixed The mime content
420
     */
421
    public function get(array $build_params = null)
422
    {
423
        if (isset($build_params)) {
424
            foreach ($build_params as $key => $value) {
425
                $this->_build_params[$key] = $value;
426
            }
427
        }
428
429
        if (!empty($this->_html_images) && isset($this->_htmlbody)) {
430
            foreach ($this->_html_images as $value) {
431
                $this->_htmlbody = str_replace($value['name'], 'cid:' . $value['cid'], $this->_htmlbody);
432
            }
433
        }
434
435
        $null        = null;
436
        $attachments = !empty($this->_parts);
437
        $html_images = !empty($this->_html_images);
438
        $html        = !empty($this->_htmlbody);
439
        $text        = (!$html and !empty($this->_txtbody));
440
441
        switch (true) {
442
            case $text and !$attachments:
443
                $message = &$this->_addTextPart($null, $this->_txtbody);
444
                break;
445
            case !$text and !$html and $attachments:
446
                $message = &$this->_addMixedPart();
447
448
                for ($i = 0, $iMax = count($this->_parts); $i < $iMax; ++$i) {
449
                    $this->_addAttachmentPart($message, $this->_parts[$i]);
450
                }
451
                break;
452
            case $text and $attachments:
453
                $message = &$this->_addMixedPart();
454
                $this->_addTextPart($message, $this->_txtbody);
455
456
                for ($i = 0, $iMax = count($this->_parts); $i < $iMax; ++$i) {
457
                    $this->_addAttachmentPart($message, $this->_parts[$i]);
458
                }
459
                break;
460
            case $html and !$attachments and !$html_images:
461
                if (isset($this->_txtbody)) {
462
                    $message = &$this->_addAlternativePart($null);
463
                    $this->_addTextPart($message, $this->_txtbody);
464
                    $this->_addHtmlPart($message);
465
                } else {
466
                    $message = &$this->_addHtmlPart($null);
467
                }
468
                break;
469
            case $html and !$attachments and $html_images:
470
                if (isset($this->_txtbody)) {
471
                    $message = &$this->_addAlternativePart($null);
472
                    $this->_addTextPart($message, $this->_txtbody);
473
                    $related = &$this->_addRelatedPart($message);
474
                } else {
475
                    $message = &$this->_addRelatedPart($null);
476
                    $related = &$message;
477
                }
478
                $this->_addHtmlPart($related);
479
                for ($i = 0, $iMax = count($this->_html_images); $i < $iMax; ++$i) {
480
                    $this->_addHtmlImagePart($related, $this->_html_images[$i]);
481
                }
482
                break;
483
            case $html and $attachments and !$html_images:
484
                $message = &$this->_addMixedPart();
485
                if (isset($this->_txtbody)) {
486
                    $alt = &$this->_addAlternativePart($message);
487
                    $this->_addTextPart($alt, $this->_txtbody);
488
                    $this->_addHtmlPart($alt);
489
                } else {
490
                    $this->_addHtmlPart($message);
491
                }
492
                for ($i = 0, $iMax = count($this->_parts); $i < $iMax; ++$i) {
493
                    $this->_addAttachmentPart($message, $this->_parts[$i]);
494
                }
495
                break;
496
            case $html and $attachments and $html_images:
497
                $message = &$this->_addMixedPart();
498
                if (isset($this->_txtbody)) {
499
                    $alt = &$this->_addAlternativePart($message);
500
                    $this->_addTextPart($alt, $this->_txtbody);
501
                    $rel = &$this->_addRelatedPart($alt);
502
                } else {
503
                    $rel = &$this->_addRelatedPart($message);
504
                }
505
                $this->_addHtmlPart($rel);
506
                for ($i = 0, $iMax = count($this->_html_images); $i < $iMax; ++$i) {
507
                    $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
508
                }
509
                for ($i = 0, $iMax = count($this->_parts); $i < $iMax; ++$i) {
510
                    $this->_addAttachmentPart($message, $this->_parts[$i]);
511
                }
512
                break;
513
        }
514
515
        if (isset($message)) {
516
            $output         = $message->encode();
517
            $this->_headers = array_merge($this->_headers, $output['headers']);
518
519
            return $output['body'];
520
        }
521
522
        return false;
523
    }
524
525
    /**
526
     * Returns an array with the headers needed to prepend to the email
527
     * (MIME-Version and Content-Type). Format of argument is:
528
     * $array['header-name'] = 'header-value';
529
     *
530
     * @param array|null $xtra_headers Assoc array with any extra headers. Optional.
531
     * @return array Assoc array with the mime headers
532
     */
533
    public function headers(array $xtra_headers = null): array
534
    {
535
        // Content-Type header should already be present,
536
        // So just add mime version header
537
        $headers['MIME-Version'] = '1.0';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$headers was never initialized. Although not strictly required by PHP, it is generally a good practice to add $headers = array(); before regardless.
Loading history...
538
        if (isset($xtra_headers)) {
539
            $headers = array_merge($headers, $xtra_headers);
540
        }
541
        $this->_headers = array_merge($headers, $this->_headers);
542
543
        return $this->_encodeHeaders($this->_headers);
544
    }
545
546
    /**
547
     * Get the text version of the headers
548
     * (usefull if you want to use the PHP mail() function)
549
     *
550
     * @param array|null $xtra_headers Assoc array with any extra headers. Optional.
551
     * @return string Plain text headers
552
     */
553
    public function txtHeaders(array $xtra_headers = null): string
554
    {
555
        $headers = $this->headers($xtra_headers);
556
        $ret     = '';
557
        foreach ($headers as $key => $val) {
558
            $ret .= "$key: $val" . MAIL_MIME_CRLF;
559
        }
560
561
        return $ret;
562
    }
563
564
    /**
565
     * Sets the Subject header
566
     *
567
     * @param string $subject String to set the subject to
568
     *                        access  public
569
     */
570
    public function setSubject(string $subject): void
571
    {
572
        $this->_headers['Subject'] = $subject;
573
    }
574
575
    /**
576
     * Set an email to the From (the sender) header
577
     *
578
     * @param string $email The email direction to add
579
     */
580
    public function setFrom(string $email): void
581
    {
582
        $this->_headers['From'] = $email;
583
    }
584
585
    /**
586
     * Add an email to the Cc (carbon copy) header
587
     * (multiple calls to this method is allowed)
588
     *
589
     * @param string $email The email direction to add
590
     */
591
    public function addCc(string $email): void
592
    {
593
        if (isset($this->_headers['Cc'])) {
594
            $this->_headers['Cc'] .= ", $email";
595
        } else {
596
            $this->_headers['Cc'] = $email;
597
        }
598
    }
599
600
    /**
601
     * Add an email to the Bcc (blank carbon copy) header
602
     * (multiple calls to this method is allowed)
603
     *
604
     * @param string $email The email direction to add
605
     */
606
    public function addBcc(string $email): void
607
    {
608
        if (isset($this->_headers['Bcc'])) {
609
            $this->_headers['Bcc'] .= ", $email";
610
        } else {
611
            $this->_headers['Bcc'] = $email;
612
        }
613
    }
614
615
    /**
616
     * Encodes a header as per RFC2047
617
     *
618
     * @param array $input The header data to encode
619
     * @return array Encoded data
620
     */
621
    public function _encodeHeaders(array $input): array
622
    {
623
        foreach ($input as $hdr_name => $hdr_value) {
624
            preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches);
625
            foreach ($matches[1] as $value) {
626
                $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
627
                $hdr_value   = str_replace($value, '=?' . $this->_build_params['head_charset'] . '?Q?' . $replacement . '?=', $hdr_value);
628
            }
629
            $input[$hdr_name] = $hdr_value;
630
        }
631
632
        return $input;
633
    }
634
} // End of class
635