Srv Bebeboutik 340bc7c146 push site
2016-01-04 12:48:08 +01:00

353 lines
9.2 KiB
PHP
Executable File

<?php
/**
* Swift Mailer Sendmail Connection component.
* Please read the LICENSE file
* @author Chris Corbyn <chris@w3style.co.uk>
* @package Swift_Connection
* @license GNU Lesser General Public License
*/
require_once dirname(__FILE__) . "/../ClassLoader.php";
Swift_ClassLoader::load("Swift_ConnectionBase");
/**
* Swift Sendmail Connection
* @package Swift_Connection
* @author Chris Corbyn <chris@w3style.co.uk>
*/
class Swift_Connection_Sendmail extends Swift_ConnectionBase
{
/**
* Constant for auto-detection of paths
*/
const AUTO_DETECT = -2;
/**
* Flags for the MTA (options such as bs or t)
* @var string
*/
protected $flags = null;
/**
* The full path to the MTA
* @var string
*/
protected $path = null;
/**
* The type of last request sent
* For example MAIL, RCPT, DATA
* @var string
*/
protected $request = null;
/**
* The process handle
* @var resource
*/
protected $proc;
/**
* I/O pipes for the process
* @var array
*/
protected $pipes;
/**
* Switches to true for just one command when DATA has been issued
* @var boolean
*/
protected $send = false;
/**
* The timeout in seconds before giving up
* @var int Seconds
*/
protected $timeout = 10;
/**
* Constructor
* @param string The command to execute
* @param int The timeout in seconds before giving up
*/
public function __construct($command="/usr/sbin/sendmail -bs", $timeout=10)
{
$this->setCommand($command);
$this->setTimeout($timeout);
}
/**
* Set the timeout on the process
* @param int The number of seconds
*/
public function setTimeout($secs)
{
$this->timeout = (int)$secs;
}
/**
* Get the timeout on the process
* @return int
*/
public function getTimeout()
{
return $this->timeout;
}
/**
* Set the operating flags for the MTA
* @param string
*/
public function setFlags($flags)
{
$this->flags = $flags;
}
/**
* Get the operating flags for the MTA
* @return string
*/
public function getFlags()
{
return $this->flags;
}
/**
* Set the path to the binary
* @param string The path (must be absolute!)
*/
public function setPath($path)
{
if ($path == self::AUTO_DETECT) $path = $this->findSendmail();
$this->path = $path;
}
/**
* Get the path to the binary
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* For auto-detection of sendmail path
* Thanks to "Joe Cotroneo" for providing the enhancement
* @return string
*/
public function findSendmail()
{
$log = Swift_LogContainer::getLog();
if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
{
$log->add("Sendmail path auto-detection in progress. Trying `which sendmail`");
}
$path = @trim(shell_exec('which sendmail'));
if (!is_executable($path))
{
if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
{
$log->add("No luck so far, trying some common paths...");
}
$common_locations = array(
'/usr/bin/sendmail',
'/usr/lib/sendmail',
'/var/qmail/bin/sendmail',
'/bin/sendmail',
'/usr/sbin/sendmail',
'/sbin/sendmail'
);
foreach ($common_locations as $path)
{
if (is_executable($path)) return $path;
}
if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
{
$log->add("Falling back to /usr/sbin/sendmail (but it doesn't look good)!");
}
//Fallback (swift will still throw an error)
return "/usr/sbin/sendmail";
}
else return $path;
}
/**
* Set the sendmail command (path + flags)
* @param string Command
* @throws Swift_ConnectionException If the command is not correctly structured
*/
public function setCommand($command)
{
if ($command == self::AUTO_DETECT) $command = $this->findSendmail() . " -bs";
if (!strrpos($command, " -"))
{
throw new Swift_ConnectionException("Cannot set sendmail command with no command line flags. e.g. /usr/sbin/sendmail -t");
}
$path = substr($command, 0, strrpos($command, " -"));
$flags = substr($command, strrpos($command, " -")+2);
$this->setPath($path);
$this->setFlags($flags);
}
/**
* Get the sendmail command (path + flags)
* @return string
*/
public function getCommand()
{
return $this->getPath() . " -" . $this->getFlags();
}
/**
* Write a command to the open pipe
* @param string The command to write
* @throws Swift_ConnectionException If the pipe cannot be written to
*/
protected function pipeIn($command, $end="\r\n")
{
if (!$this->isAlive()) throw new Swift_ConnectionException("The sendmail process is not alive and cannot be written to.");
if (!@fwrite($this->pipes[0], $command . $end) && !empty($command)) throw new Swift_ConnectionException("The sendmail process did not allow the command '" . $command . "' to be sent.");
fflush($this->pipes[0]);
}
/**
* Read data from the open pipe
* @return string
* @throws Swift_ConnectionException If the pipe is not operating as expected
*/
protected function pipeOut()
{
if (strpos($this->getFlags(), "t") !== false) return;
if (!$this->isAlive()) throw new Swift_ConnectionException("The sendmail process is not alive and cannot be read from.");
$ret = "";
$line = 0;
while (true)
{
$line++;
stream_set_timeout($this->pipes[1], $this->timeout);
$tmp = @fgets($this->pipes[1]);
if ($tmp === false)
{
throw new Swift_ConnectionException("There was a problem reading line " . $line . " of a sendmail SMTP response. The response so far was:<br />[" . $ret . "]. It appears the process has died.");
}
$ret .= trim($tmp) . "\r\n";
if ($tmp{3} == " ") break;
}
fflush($this->pipes[1]);
return $ret = substr($ret, 0, -2);
}
/**
* Read a full response from the buffer (this is spoofed if running in -t mode)
* @return string
* @throws Swift_ConnectionException Upon failure to read
*/
public function read()
{
if (strpos($this->getFlags(), "t") !== false)
{
switch (strtolower($this->request))
{
case null:
return "220 Greetings";
case "helo": case "ehlo":
return "250 hello";
case "mail": case "rcpt": case "rset":
return "250 ok";
case "quit":
return "221 bye";
case "data":
$this->send = true;
return "354 go ahead";
default:
return "250 ok";
}
}
else return $this->pipeOut();
}
/**
* Write a command to the process (leave off trailing CRLF)
* @param string The command to send
* @throws Swift_ConnectionException Upon failure to write
*/
public function write($command, $end="\r\n")
{
if (strpos($this->getFlags(), "t") !== false)
{
if (!$this->send && strpos($command, " ")) $command = substr($command, strpos($command, " ")+1);
elseif ($this->send)
{
$this->pipeIn($command);
}
$this->request = $command;
$this->send = (strtolower($command) == "data");
}
else $this->pipeIn($command, $end);
}
/**
* Try to start the connection
* @throws Swift_ConnectionException Upon failure to start
*/
public function start()
{
$log = Swift_LogContainer::getLog();
if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
{
$log->add("Trying to start a sendmail process.");
}
if (!$this->getPath() || !$this->getFlags())
{
throw new Swift_ConnectionException("Sendmail cannot be started without a path to the binary including flags.");
}
if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
{
$log->add("Trying to stat the executable '" . $this->getPath() . "'.");
}
if (!@lstat($this->getPath()))
{
throw new Swift_ConnectionException(
"Sendmail cannot be seen with lstat(). The command given [" . $this->getCommand() . "] does not appear to be valid.");
}
$pipes_spec = array(
array("pipe", "r"),
array("pipe", "w"),
array("pipe", "w")
);
$this->proc = proc_open($this->getCommand(), $pipes_spec, $this->pipes);
if (!$this->isAlive())
{
throw new Swift_ConnectionException(
"The sendmail process failed to start. Please verify that the path exists and PHP has permission to execute it.");
}
}
/**
* Try to close the connection
*/
public function stop()
{
$log = Swift_LogContainer::getLog();
if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
{
$log->add("Terminating sendmail process.");
}
foreach ((array)$this->pipes as $pipe)
{
@fclose($pipe);
}
if ($this->proc)
{
proc_close($this->proc);
$this->pipes = null;
$this->proc = null;
}
}
/**
* Check if the process is still alive
* @return boolean
*/
public function isAlive()
{
return ($this->proc !== false
&& is_resource($this->proc)
&& is_resource($this->pipes[0])
&& is_resource($this->pipes[1])
&& $this->proc !== null);
}
/**
* Destructor.
* Cleans up by stopping any running processes.
*/
public function __destruct()
{
$this->stop();
}
}