Lines 100.00% 16 / 16
Methods 100.00% 2 / 2
Classes 100.00% 1 / 1
Covered by tests of size
Name Lines Methods CRAP
 send 100.00% 15 / 15 100.00% 1 / 1 6
 stripNewlines 100.00% 1 / 1 100.00% 1 / 1 1
27class Builtin implements MailUserAgentInterface
28{
29    /**
30     * Send the message using an email through the PHP built-in mail() function.
31     *
32     * @param string $recipients Recipients of the e-mail as a comma-separated list of RFC 2822 compliant items
33     * @param array<string, int|string|null> $headers Headers of the e-mail
34     * @param string $body Body of the e-mail
35     */
36    public function send(string $recipients, array $headers, string $body): int
37    {
38        // Get the subject of the e-mail, RFC 2047 compliant. Strip CR/LF defensively so an
39        // untrusted value can never inject additional headers, independent of upstream validation.
40        $subject = self::stripNewlines((string) $headers['Subject']);
41        $headers['Subject'] = null;
42        unset($headers['Subject']);
43
44        $sender = '';
45        if (
46            'WIN' !== strtoupper(substr(PHP_OS, offset: 0, length: 3))
47            && !ini_get('safe_mode')
48            && array_key_exists('Return-Path', $headers)
49        ) {
50            $sender = str_replace(['<', '>'], replace: '', subject: (string) $headers['Return-Path']);
51            unset($headers['Return-Path']);
52        }
53
54        // Prepare the headers for the email
55        $mailHeaders = '';
56        foreach ($headers as $key => $value) {
57            $mailHeaders .= self::stripNewlines((string) $key) . ': ' . self::stripNewlines((string) $value) . PHP_EOL;
58        }
59
60        // Send the email
61        if ($sender === '') {
62            return (int) mail($recipients, $subject, $body, $mailHeaders);
63        }
64
65        return (int) mail($recipients, $subject, $body, $mailHeaders, '-f' . $sender);
66    }
67
68    /**
69     * Removes CR and LF characters to prevent e-mail header (CRLF) injection.
70     */
71    private static function stripNewlines(string $value): string
72    {
73        return str_replace(["\r", "\n"], replace: '', subject: $value);
74    }
75}