Example #1
0
 /**
  * Send the DATA command.
  *
  * @param mixed $data      The message data, either as a string or an open
  *                         file resource.
  * @param string $headers  The message headers. If $headers is provided,
  *                         $data is assumed to contain only body data.
  *
  * @throws PEAR_Exception
  */
 public function data($data, $headers = null)
 {
     /* Verify that $data is a supported type. */
     if (!is_string($data) && !is_resource($data)) {
         return Net_SMTP::raiseError('Expected a string or file resource');
     }
     /* Start by considering the size of the optional headers string.  We
      * also account for the addition 4 character "\r\n\r\n" separator
      * sequence. */
     $size = is_null($headers) ? 0 : strlen($headers) + 4;
     if (is_resource($data)) {
         $stat = fstat($data);
         if ($stat === false) {
             return Net_SMTP::raiseError('Failed to get file size');
         }
         $size += $stat['size'];
     } else {
         $size += strlen($data);
     }
     /* RFC 1870, section 3, subsection 3 states "a value of zero indicates
      * that no fixed maximum message size is in force".  Furthermore, it
      * says that if "the parameter is omitted no information is conveyed
      * about the server's fixed maximum message size". */
     $limit = isset($this->_esmtp['SIZE']) ? $this->_esmtp['SIZE'] : 0;
     if ($limit > 0 && $size >= $limit) {
         $this->disconnect();
         return Net_SMTP::raiseError('Message size exceeds server limit');
     }
     /* Initiate the DATA command. */
     //if (PEAR::isError($error = $this->_put('DATA'))) {
     if (($error = $this->_put('DATA')) === false) {
         return $error;
     }
     //if (PEAR::isError($error = $this->_parseResponse(354))) {
     if (($error = $this->_parseResponse(354)) === false) {
         return $error;
     }
     /* If we have a separate headers string, send it first. */
     if (!is_null($headers)) {
         $this->quotedata($headers);
         //if (PEAR::isError($result = $this->_send($headers . "\r\n\r\n"))) {
         if (($result = $this->_send($headers . "\r\n\r\n")) === false) {
             return $result;
         }
     }
     /* Now we can send the message body data. */
     if (is_resource($data)) {
         /* Stream the contents of the file resource out over our socket
          * connection, line by line.  Each line must be run through the
          * quoting routine. */
         while (strlen($line = fread($data, 8192)) > 0) {
             /* If the last character is an newline, we need to grab the
              * next character to check to see if it is a period. */
             while (!feof($data)) {
                 $char = fread($data, 1);
                 $line .= $char;
                 if ($char != "\n") {
                     break;
                 }
             }
             $this->quotedata($line);
             //if (PEAR::isError($result = $this->_send($line))) {
             if (($result = $this->_send($line)) === false) {
                 return $result;
             }
         }
     } else {
         /* Break up the data by sending one chunk (up to 512k) at a time.
          * This approach reduces our peak memory usage. */
         for ($offset = 0; $offset < $size;) {
             $end = $offset + 512000;
             /* Ensure we don't read beyond our data size or span multiple
              * lines.  quotedata() can't properly handle character data
              * that's split across two line break boundaries. */
             if ($end >= $size) {
                 $end = $size;
             } else {
                 for (; $end < $size; $end++) {
                     if ($data[$end] != "\n") {
                         break;
                     }
                 }
             }
             /* Extract our chunk and run it through the quoting routine. */
             $chunk = substr($data, $offset, $end - $offset);
             $this->quotedata($chunk);
             /* If we run into a problem along the way, abort. */
             //if (PEAR::isError($result = $this->_send($chunk))) {
             if (($result = $this->_send($chunk)) === false) {
                 return $result;
             }
             /* Advance the offset to the end of this chunk. */
             $offset = $end;
         }
     }
     /* Finally, send the DATA terminator sequence. */
     //if (PEAR::isError($result = $this->_send("\r\n.\r\n"))) {
     if (($result = $this->_send("\r\n.\r\n")) === false) {
         return $result;
     }
     /* Verify that the data was successfully received by the server. */
     //if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
     if (($error = $this->_parseResponse(250, $this->pipelining)) === false) {
         return $error;
     }
     return true;
 }