/** * Surcharge la méthode __toString() de la classe parente. * Signe et/ou chiffre l’email résultant à l’aide du programme GnuPG. * * @access public * @return string */ public function __toString() { if (!is_executable($this->gpg_bin)) { throw new Exception(sprintf("[%s] is not a valid executable.", $this->gpg_bin)); } if (!(file_exists($this->logfile) && is_writable($this->logfile) || is_writable(dirname($this->logfile)))) { throw new Exception(sprintf("Unable to write log file [%s].", $this->logfile)); } $tmpdir = escapeshellarg($this->tmpdir); $logfile = escapeshellcmd($this->logfile); $digest_algo = escapeshellarg($this->digest_algo); $gpg_cmd = escapeshellcmd($this->gpg_bin); $gpg_cmd .= " --no-verbose --no-tty --batch --textmode --armor" . " --always-trust --comment \"Using GnuPG with Wamailer\""; if (!is_null($this->homedir)) { $gpg_cmd .= sprintf(" --homedir %s", escapeshellarg($this->homedir)); } /** * Les emails signés et/ou chiffrés doivent être restreints * aux caractères 7bit uniquement (us-ascii) * * @see RFC 3156#3 - Content-Transfer-Encoding restrictions */ if ($this->_sign || $this->_encrypt) { if (!is_null($this->_textPart)) { $this->_textPart->encoding = 'quoted-printable'; } if (!is_null($this->_htmlPart)) { $this->_htmlPart->encoding = 'quoted-printable'; } } parent::__toString(); $headers = $this->headers_txt; $message = $this->message_txt; $tmpfile = tempnam($this->tmpdir, 'wa'); file_put_contents($tmpfile, $message); // // Le message doit être chiffré (+ éventuellement signé) // if ($this->_encrypt) { if (!is_null($this->cipher_algo)) { $gpc_cmd .= sprintf(' --cipher-algo %s', escapeshellarg($this->cipher_algo)); } if ($this->encryption == self::A_ENCRYPTION) { if (count($this->recipients) == 0) { throw new Exception("No recipient specified!"); } foreach ($this->recipients as $recipient) { $gpg_cmd .= sprintf(' --recipient %s', escapeshellarg($recipient)); } if ($this->_sign) { if (!is_null($this->secretkey)) { $gpg_cmd .= sprintf(" --local-user %s", escapeshellarg($this->secretkey)); } if (!is_null($this->passphrase)) { $gpg_cmd = sprintf("echo %s | %s --passphrase-fd 0", escapeshellarg($this->passphrase), $gpg_cmd); } $gpg_cmd = sprintf("%s --output - --digest-algo %s --encrypt --sign %s", $gpg_cmd, $digest_algo, escapeshellarg($tmpfile)); } else { $gpg_cmd = sprintf("%s --output - --encrypt %s", $gpg_cmd, escapeshellarg($tmpfile)); } } else { $password = escapeshellarg($this->password); if ($this->_sign) { if (!is_null($this->secretkey)) { $gpg_cmd .= sprintf(" --local-user %s", escapeshellarg($this->secretkey)); } $gpg_cmd = sprintf("echo %s | %s --passphrase-fd 0" . " --output - --digest-algo %s --symmetric --sign %s", $password, $gpg_cmd, $digest_algo, escapeshellarg($tmpfile)); } else { $gpg_cmd = sprintf("echo %s | %s --passphrase-fd 0" . " --output - --symmetric %s", $password, $gpg_cmd, escapeshellarg($tmpfile)); } } exec("{$gpg_cmd} 2>{$logfile}", $output, $result); if ($result !== 0) { unlink($tmpfile); throw new Exception("Cannot encrypt email (GPG error)"); } $encrypted_msg = implode("\r\n", $output); $gpg_sub1 = new Mime_Part(); $gpg_sub1->headers->set('Content-Type', 'application/pgp-encrypted'); $gpg_sub1->headers->set('Content-Description', 'PGP/MIME version identification'); $gpg_sub1->body = 'Version: 1'; $gpg_sub2 = new Mime_Part(); $gpg_sub2->headers->set('Content-Type', 'application/octet-stream'); $gpg_sub2->headers->get('Content-Type')->param('name', 'encrypted.asc'); $gpg_sub2->headers->set('Content-Description', 'OpenPGP encrypted message'); $gpg_sub2->headers->set('Content-Disposition', 'inline'); $gpg_sub2->headers->get('Content-Disposition')->param('filename', 'encrypted.asc'); $gpg_sub2->body = $encrypted_msg; $gpg_sub2->wraptext = false; // // Bloc MIME global // $gpg = new Mime_Part(); $gpg->headers->set('Content-Type', 'multipart/encrypted'); $gpg->headers->get('Content-Type')->param('protocol', 'application/pgp-encrypted'); $gpg->body = 'This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)'; $gpg->addSubPart($gpg_sub1); $gpg->addSubPart($gpg_sub2); $message = $gpg->__toString(); } else { if ($this->_sign) { if (!is_null($this->secretkey)) { $gpg_cmd .= sprintf(" --local-user %s", escapeshellarg($this->secretkey)); } if (!is_null($this->passphrase)) { $gpg_cmd = sprintf("echo %s | %s --passphrase-fd 0", escapeshellarg($this->passphrase), $gpg_cmd); } $gpg_cmd = sprintf("%s --output - --digest-algo %s --detach-sign %s", $gpg_cmd, $digest_algo, escapeshellarg($tmpfile)); exec("{$gpg_cmd} 2>{$logfile}", $output, $result); if ($result !== 0) { unlink($tmpfile); throw new Exception("Cannot sign email (GPG error)"); } $signature = implode("\r\n", $output); $gpg_sub = new Mime_Part(); $gpg_sub->headers->set('Content-Type', 'application/pgp-signature'); $gpg_sub->headers->get('Content-Type')->param('name', 'signature.asc'); $gpg_sub->headers->set('Content-Description', 'OpenPGP digital signature'); $gpg_sub->headers->set('Content-Disposition', 'attachment'); $gpg_sub->headers->get('Content-Disposition')->param('filename', 'signature.asc'); $gpg_sub->body = $signature; $gpg_sub->wraptext = false; // // Bloc MIME global // $gpg = new Mime_Part(); $gpg->headers->set('Content-Type', 'multipart/signed'); $gpg->headers->get('Content-Type')->param('micalg', "pgp-{$this->digest_algo}"); $gpg->headers->get('Content-Type')->param('protocol', 'application/pgp-signature'); $gpg->body = "This is an OpenPGP/MIME signed message (RFC 2440 and 3156)."; $gpg->addSubPart($message); $gpg->addSubPart($gpg_sub); $message = $gpg->__toString(); } } unlink($tmpfile); return $headers . $message; }
/** * Retourne l'email sous forme de chaîne formatée prète à l'envoi * * @access public * @return string */ public function __toString() { $this->headers->set('Date', date(DATE_RFC2822)); $this->headers->set('MIME-Version', '1.0'); $this->headers->set('Message-ID', sprintf('<%s@%s>', md5(microtime() . rand()), MAILER_HOSTNAME)); $this->headers_txt = $this->headers->__toString(); if (!empty($this->message_txt)) { return $this->headers_txt . $this->message_txt; } $rootPart = null; $attachParts = $this->_attachParts; if (!is_null($this->_htmlPart)) { $rootPart = $this->_htmlPart; if (!is_null($this->_textPart)) { $rootPart = new Mime_Part(); $rootPart->addSubPart($this->_textPart); $rootPart->addSubPart($this->_htmlPart); $rootPart->headers->set('Content-Type', 'multipart/alternative'); } $embedParts = array(); foreach ($attachParts as &$attach) { if ($attach->headers->get('Content-ID') == null) { $name = $attach->headers->get('Content-Type')->param('name'); $regexp = '/<([^>]+=\\s*)(["\'])cid:' . preg_quote($name, '/') . '\\2([^>]*)>/S'; if (!preg_match($regexp, $this->_htmlPart->body)) { continue; } $cid = md5(microtime()) . '@' . MAILER_HOSTNAME; $this->_htmlPart->body = preg_replace($regexp, '<\\1\\2cid:' . $cid . '\\2\\3>', $this->_htmlPart->body); $attach->headers->set('Content-ID', "<{$cid}>"); } array_push($embedParts, $attach); $attach = null; } if (count($embedParts) > 0) { $embedPart = new Mime_Part(); $embedPart->addSubPart($rootPart); $embedPart->addSubPart($embedParts); $embedPart->headers->set('Content-Type', 'multipart/related'); $embedPart->headers->get('Content-Type')->param('type', $rootPart->headers->get('Content-Type')->value); $rootPart = $embedPart; } } else { if (!is_null($this->_textPart)) { $rootPart = $this->_textPart; } } // filtrage nécessaire après la boucle de traitement des objets embarqués plus haut $attachParts = array_filter($attachParts); if (count($attachParts) > 0) { if (!is_null($rootPart)) { $mixedPart = new Mime_Part(); $mixedPart->headers->set('Content-Type', 'multipart/mixed'); $mixedPart->addSubPart($rootPart); $mixedPart->addSubPart($attachParts); } else { if (count($attachParts) == 1) { $mixedPart = $attachParts[0]; } else { $mixedPart = new Mime_Part(); $mixedPart->headers->set('Content-Type', 'multipart/mixed'); $mixedPart->addSubPart($attachParts); } } $rootPart = $mixedPart; } // // Le corps d'un email est optionnel (cf. RFC 2822#3.5) // if (!is_null($rootPart)) { // // Par convention, un bref message informatif est ajouté aux emails // composés de plusieurs sous-parties, au cas où le client mail // ne supporterait pas ceux-ci… // if (strncasecmp($rootPart->headers->get('Content-Type')->value, 'multipart', 9) == 0) { $rootPart->body = "This is a multi-part message in MIME format."; } $this->message_txt = $rootPart->__toString(); } return $this->headers_txt . $this->message_txt; }