Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  /**
   3   * Copyright 2010-2017 Horde LLC (http://www.horde.org/)
   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   * @category  Horde
  32   * @copyright 2010-2017 Horde LLC
  33   * @license   http://www.horde.org/licenses/bsd New BSD License
  34   * @package   Mail
  35   */
  36  
  37  /**
  38   * Sendmail interface.
  39   *
  40   * @author    Chuck Hagenbuch <chuck@horde.org>
  41   * @author    Michael Slusarz <slusarz@horde.org>
  42   * @category  Horde
  43   * @copyright 2010-2017 Horde LLC
  44   * @license   http://www.horde.org/licenses/bsd New BSD License
  45   * @package   Mail
  46   */
  47  class Horde_Mail_Transport_Sendmail extends Horde_Mail_Transport
  48  {
  49      /**
  50       * Any extra command-line parameters to pass to the sendmail or
  51       * sendmail wrapper binary.
  52       *
  53       * @var string
  54       */
  55      protected $_sendmailArgs = '-i';
  56  
  57      /**
  58       * The location of the sendmail or sendmail wrapper binary on the
  59       * filesystem.
  60       *
  61       * @var string
  62       */
  63      protected $_sendmailPath = '/usr/sbin/sendmail';
  64  
  65      /**
  66       * Constructor.
  67       *
  68       * @param array $params  Additional parameters:
  69       *   - sendmail_args: (string) Any extra parameters to pass to the sendmail
  70       *                    or sendmail wrapper binary.
  71       *                    DEFAULT: -i
  72       *   - sendmail_path: (string) The location of the sendmail binary on the
  73       *                    filesystem.
  74       *                    DEFAULT: /usr/sbin/sendmail
  75       */
  76      public function __construct(array $params = array())
  77      {
  78          if (isset($params['sendmail_args'])) {
  79              $this->_sendmailArgs = $params['sendmail_args'];
  80          }
  81  
  82          if (isset($params['sendmail_path'])) {
  83              $this->_sendmailPath = $params['sendmail_path'];
  84          }
  85      }
  86  
  87      /**
  88       */
  89      public function send($recipients, array $headers, $body)
  90      {
  91          $recipients = implode(' ', array_map('escapeshellarg', $this->parseRecipients($recipients)));
  92  
  93          $headers = $this->_sanitizeHeaders($headers);
  94          list($from, $text_headers) = $this->prepareHeaders($headers);
  95          $from = $this->_getFrom($from, $headers);
  96  
  97          $mail = @popen($this->_sendmailPath . (empty($this->_sendmailArgs) ? '' : ' ' . $this->_sendmailArgs) . ' -f ' . escapeshellarg($from) . ' -- ' . $recipients, 'w');
  98          if (!$mail) {
  99              throw new Horde_Mail_Exception('Failed to open sendmail [' . $this->_sendmailPath . '] for execution.');
 100          }
 101  
 102          // Write the headers following by two newlines: one to end the headers
 103          // section and a second to separate the headers block from the body.
 104          fputs($mail, $text_headers . $this->sep . $this->sep);
 105  
 106          if (is_resource($body)) {
 107              stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol');
 108              stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep));
 109  
 110              rewind($body);
 111              while (!feof($body)) {
 112                  fputs($mail, fread($body, 8192));
 113              }
 114          } else {
 115              fputs($mail, $this->_normalizeEOL($body));
 116          }
 117          $result = pclose($mail);
 118  
 119          if (!$result) {
 120              return;
 121          }
 122  
 123          switch ($result) {
 124          case 64: // EX_USAGE
 125              $msg = 'command line usage error';
 126              break;
 127  
 128          case 65: // EX_DATAERR
 129              $msg =  'data format error';
 130              break;
 131  
 132          case 66: // EX_NOINPUT
 133              $msg = 'cannot open input';
 134              break;
 135  
 136          case 67: // EX_NOUSER
 137              $msg = 'addressee unknown';
 138              break;
 139  
 140          case 68: // EX_NOHOST
 141              $msg = 'host name unknown';
 142              break;
 143  
 144          case 69: // EX_UNAVAILABLE
 145              $msg = 'service unavailable';
 146              break;
 147  
 148          case 70: // EX_SOFTWARE
 149              $msg = 'internal software error';
 150              break;
 151  
 152          case 71: // EX_OSERR
 153              $msg = 'system error';
 154              break;
 155  
 156          case 72: // EX_OSFILE
 157              $msg = 'critical system file missing';
 158              break;
 159  
 160          case 73: // EX_CANTCREAT
 161              $msg = 'cannot create output file';
 162              break;
 163  
 164          case 74: // EX_IOERR
 165              $msg = 'input/output error';
 166  
 167          case 75: // EX_TEMPFAIL
 168              $msg = 'temporary failure';
 169              break;
 170  
 171          case 76: // EX_PROTOCOL
 172              $msg = 'remote error in protocol';
 173              break;
 174  
 175          case 77: // EX_NOPERM
 176              $msg = 'permission denied';
 177              break;
 178  
 179          case 78: // EX_CONFIG
 180              $msg = 'configuration error';
 181              break;
 182  
 183          case 79: // EX_NOTFOUND
 184              $msg = 'entry not found';
 185              break;
 186  
 187          default:
 188              $msg = 'unknown error';
 189              break;
 190          }
 191  
 192          throw new Horde_Mail_Exception('sendmail: ' . $msg . ' (' . $result . ')', $result);
 193      }
 194  
 195  }