PageRenderTime 38ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/swift/Swift/Connection/SMTP.php

https://gitlab.com/staging06/myproject
PHP | 452 lines | 289 code | 7 blank | 156 comment | 33 complexity | 549c4fbe26755891068c6b202cdb1e4b MD5 | raw file
  1. <?php
  2. /**
  3. * Swift Mailer SMTP Connection component.
  4. * Please read the LICENSE file
  5. * @author Chris Corbyn <chris@w3style.co.uk>
  6. * @package Swift_Connection
  7. * @license GNU Lesser General Public License
  8. */
  9. require_once dirname(__FILE__) . "/../ClassLoader.php";
  10. Swift_ClassLoader::load("Swift_ConnectionBase");
  11. Swift_ClassLoader::load("Swift_Authenticator");
  12. /**
  13. * Swift SMTP Connection
  14. * @package Swift_Connection
  15. * @author Chris Corbyn <chris@w3style.co.uk>
  16. */
  17. class Swift_Connection_SMTP extends Swift_ConnectionBase
  18. {
  19. /**
  20. * Constant for TLS connections
  21. */
  22. const ENC_TLS = 2;
  23. /**
  24. * Constant for SSL connections
  25. */
  26. const ENC_SSL = 4;
  27. /**
  28. * Constant for unencrypted connections
  29. */
  30. const ENC_OFF = 8;
  31. /**
  32. * Constant for the default SMTP port
  33. */
  34. const PORT_DEFAULT = 25;
  35. /**
  36. * Constant for the default secure SMTP port
  37. */
  38. const PORT_SECURE = 465;
  39. /**
  40. * Constant for auto-detection of paramters
  41. */
  42. const AUTO_DETECT = -2;
  43. /**
  44. * A connection handle
  45. * @var resource
  46. */
  47. protected $handle = null;
  48. /**
  49. * The remote port number
  50. * @var int
  51. */
  52. protected $port = null;
  53. /**
  54. * Encryption type to use
  55. * @var int
  56. */
  57. protected $encryption = null;
  58. /**
  59. * A connection timeout
  60. * @var int
  61. */
  62. protected $timeout = 15;
  63. /**
  64. * A username to authenticate with
  65. * @var string
  66. */
  67. protected $username = false;
  68. /**
  69. * A password to authenticate with
  70. * @var string
  71. */
  72. protected $password = false;
  73. /**
  74. * Loaded authentication mechanisms
  75. * @var array
  76. */
  77. protected $authenticators = array();
  78. /**
  79. * Fsockopen() error codes.
  80. * @var int
  81. */
  82. protected $errno;
  83. /**
  84. * Fsockopen() error codes.
  85. * @var string
  86. */
  87. protected $errstr;
  88. /**
  89. * Constructor
  90. * @param string The remote server to connect to
  91. * @param int The remote port to connect to
  92. * @param int The encryption level to use
  93. */
  94. public function __construct($server="localhost", $port=null, $encryption=null)
  95. {
  96. $this->setServer($server);
  97. $this->setEncryption($encryption);
  98. $this->setPort($port);
  99. }
  100. /**
  101. * Set the timeout to connect in seconds
  102. * @param int Timeout to use
  103. */
  104. public function setTimeout($time)
  105. {
  106. $this->timeout = (int) $time;
  107. }
  108. /**
  109. * Get the timeout currently set for connecting
  110. * @return int
  111. */
  112. public function getTimeout()
  113. {
  114. return $this->timeout;
  115. }
  116. /**
  117. * Set the remote server to connect to as a FQDN
  118. * @param string Server name
  119. */
  120. public function setServer($server)
  121. {
  122. if ($server == self::AUTO_DETECT)
  123. {
  124. $server = @ini_get("SMTP");
  125. if (!$server) $server = "localhost";
  126. }
  127. $this->server = (string) $server;
  128. }
  129. /**
  130. * Get the remote server name
  131. * @return string
  132. */
  133. public function getServer()
  134. {
  135. return $this->server;
  136. }
  137. /**
  138. * Set the remote port number to connect to
  139. * @param int Port number
  140. */
  141. public function setPort($port)
  142. {
  143. if ($port == self::AUTO_DETECT)
  144. {
  145. $port = @ini_get("SMTP_PORT");
  146. }
  147. if (!$port) $port = ($this->getEncryption() == self::ENC_OFF) ? self::PORT_DEFAULT : self::PORT_SECURE;
  148. $this->port = (int) $port;
  149. }
  150. /**
  151. * Get the remote port number currently used to connect
  152. * @return int
  153. */
  154. public function getPort()
  155. {
  156. return $this->port;
  157. }
  158. /**
  159. * Provide a username for authentication
  160. * @param string The username
  161. */
  162. public function setUsername($user)
  163. {
  164. $this->setRequiresEHLO(true);
  165. $this->username = $user;
  166. }
  167. /**
  168. * Get the username for authentication
  169. * @return string
  170. */
  171. public function getUsername()
  172. {
  173. return $this->username;
  174. }
  175. /**
  176. * Set the password for SMTP authentication
  177. * @param string Password to use
  178. */
  179. public function setPassword($pass)
  180. {
  181. $this->setRequiresEHLO(true);
  182. $this->password = $pass;
  183. }
  184. /**
  185. * Get the password for authentication
  186. * @return string
  187. */
  188. public function getPassword()
  189. {
  190. return $this->password;
  191. }
  192. /**
  193. * Add an authentication mechanism to authenticate with
  194. * @param Swift_Authenticator
  195. */
  196. public function attachAuthenticator(Swift_Authenticator $auth)
  197. {
  198. $this->authenticators[$auth->getAuthExtensionName()] = $auth;
  199. $log = Swift_LogContainer::getLog();
  200. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  201. {
  202. $log->add("Authentication mechanism '" . $auth->getAuthExtensionName() . "' attached.");
  203. }
  204. }
  205. /**
  206. * Set the encryption level to use on the connection
  207. * See the constants ENC_TLS, ENC_SSL and ENC_OFF
  208. * NOTE: PHP needs to have been compiled with OpenSSL for SSL and TLS to work
  209. * NOTE: Some PHP installations will not have the TLS stream wrapper
  210. * @param int Level of encryption
  211. */
  212. public function setEncryption($enc)
  213. {
  214. if (!$enc) $enc = self::ENC_OFF;
  215. $this->encryption = (int) $enc;
  216. }
  217. /**
  218. * Get the current encryption level used
  219. * This method returns an integer corresponding to one of the constants ENC_TLS, ENC_SSL or ENC_OFF
  220. * @return int
  221. */
  222. public function getEncryption()
  223. {
  224. return $this->encryption;
  225. }
  226. /**
  227. * Read a full response from the buffer
  228. * inner !feof() patch provided by Christian Rodriguez:
  229. * <a href="http://www.flyspray.org/">www.flyspray.org</a>
  230. * @return string
  231. * @throws Swift_ConnectionException Upon failure to read
  232. */
  233. public function read()
  234. {
  235. if (!$this->handle) throw new Swift_ConnectionException(
  236. "The SMTP connection is not alive and cannot be read from." . $this->smtpErrors());
  237. $ret = "";
  238. $line = 0;
  239. while (!feof($this->handle))
  240. {
  241. $line++;
  242. stream_set_timeout($this->handle, $this->timeout);
  243. $tmp = @fgets($this->handle);
  244. if ($tmp === false && !feof($this->handle))
  245. {
  246. throw new Swift_ConnectionException(
  247. "There was a problem reading line " . $line . " of an SMTP response. The response so far was:<br />[" . $ret .
  248. "]. It appears the connection has died without saying goodbye to us! Too many emails in one go perhaps?" .
  249. $this->smtpErrors());
  250. }
  251. $ret .= trim($tmp) . "\r\n";
  252. if ($tmp{3} == " ") break;
  253. }
  254. return $ret = substr($ret, 0, -2);
  255. }
  256. /**
  257. * Write a command to the server (leave off trailing CRLF)
  258. * @param string The command to send
  259. * @throws Swift_ConnectionException Upon failure to write
  260. */
  261. public function write($command, $end="\r\n")
  262. {
  263. if (!$this->handle) throw new Swift_ConnectionException(
  264. "The SMTP connection is not alive and cannot be written to." .
  265. $this->smtpErrors());
  266. if (!@fwrite($this->handle, $command . $end) && !empty($command)) throw new Swift_ConnectionException("The SMTP connection did not allow the command '" . $command . "' to be sent." . $this->smtpErrors());
  267. }
  268. /**
  269. * Try to start the connection
  270. * @throws Swift_ConnectionException Upon failure to start
  271. */
  272. public function start()
  273. {
  274. if ($this->port === null)
  275. {
  276. switch ($this->encryption)
  277. {
  278. case self::ENC_TLS: case self::ENC_SSL:
  279. $this->port = 465;
  280. break;
  281. case null: default:
  282. $this->port = 25;
  283. break;
  284. }
  285. }
  286. $server = $this->server;
  287. if ($this->encryption == self::ENC_TLS) $server = "tls://" . $server;
  288. elseif ($this->encryption == self::ENC_SSL) $server = "ssl://" . $server;
  289. $log = Swift_LogContainer::getLog();
  290. if ($log->hasLevel(Swift_log::LOG_EVERYTHING))
  291. {
  292. $log->add("Trying to connect to SMTP server at '" . $server . ":" . $this->port);
  293. }
  294. if (!$this->handle = @fsockopen($server, $this->port, $errno, $errstr, $this->timeout))
  295. {
  296. $error_msg = "The SMTP connection failed to start [" . $server . ":" . $this->port . "]: fsockopen returned Error Number " . $errno . " and Error String '" . $errstr . "'";
  297. if ($log->isEnabled())
  298. {
  299. $log->add($error_msg, Swift_Log::ERROR);
  300. }
  301. $this->handle = null;
  302. throw new Swift_ConnectionException($error_msg);
  303. }
  304. $this->errno =& $errno;
  305. $this->errstr =& $errstr;
  306. }
  307. /**
  308. * Get the smtp error string as recorded by fsockopen()
  309. * @return string
  310. */
  311. public function smtpErrors()
  312. {
  313. return " (fsockopen: " . $this->errstr . "#" . $this->errno . ") ";
  314. }
  315. /**
  316. * Authenticate if required to do so
  317. * @param Swift An instance of Swift
  318. * @throws Swift_ConnectionException If authentication fails
  319. */
  320. public function postConnect(Swift $instance)
  321. {
  322. if ($this->getUsername() && $this->getPassword())
  323. {
  324. $this->runAuthenticators($this->getUsername(), $this->getPassword(), $instance);
  325. }
  326. }
  327. /**
  328. * Run each authenticator in turn an try for a successful login
  329. * If none works, throw an exception
  330. * @param string Username
  331. * @param string Password
  332. * @param Swift An instance of swift
  333. * @throws Swift_ConnectionException Upon failure to authenticate
  334. */
  335. public function runAuthenticators($user, $pass, Swift $swift)
  336. {
  337. $log = Swift_LogContainer::getLog();
  338. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  339. {
  340. $log->add("Trying to authenticate with username '" . $user . "'.");
  341. }
  342. //Load in defaults
  343. if (empty($this->authenticators))
  344. {
  345. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  346. {
  347. $log->add("No authenticators loaded; looking for defaults.");
  348. }
  349. $dir = dirname(__FILE__) . "/../Authenticator";
  350. $handle = opendir($dir);
  351. while (false !== $file = readdir($handle))
  352. {
  353. if (preg_match("/^[A-Za-z0-9-]+\\.php\$/", $file) && $file != "index.php")
  354. {
  355. $name = preg_replace('/[^a-zA-Z0-9]+/', '', substr($file, 0, -4));
  356. require_once $dir . "/" . $file;
  357. $class = "Swift_Authenticator_" . $name;
  358. $this->attachAuthenticator(new $class());
  359. }
  360. }
  361. closedir($handle);
  362. }
  363. $tried = 0;
  364. $looks_supported = true;
  365. //Allow everything we have if the server has the audacity not to help us out.
  366. if (!$this->hasExtension("AUTH"))
  367. {
  368. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  369. {
  370. $log->add("Server (perhaps wrongly) is not advertising AUTH... manually overriding.");
  371. }
  372. $looks_supported = false;
  373. $this->setExtension("AUTH", array_keys($this->authenticators));
  374. }
  375. foreach ($this->authenticators as $name => $obj)
  376. {
  377. //Server supports this authentication mechanism
  378. if (in_array($name, $this->getAttributes("AUTH")) || $name{0} == "*")
  379. {
  380. $tried++;
  381. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  382. {
  383. $log->add("Trying '" . $name . "' authentication...");
  384. }
  385. if ($this->authenticators[$name]->isAuthenticated($user, $pass, $swift))
  386. {
  387. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  388. {
  389. $log->add("Success! Authentication accepted.");
  390. }
  391. return true;
  392. }
  393. }
  394. }
  395. //Server doesn't support authentication
  396. if (!$looks_supported && $tried == 0)
  397. throw new Swift_ConnectionException("Authentication is not supported by the server but a username and password was given.");
  398. if ($tried == 0)
  399. throw new Swift_ConnectionException("No authentication mechanisms were tried since the server did not support any of the ones loaded. " .
  400. "Loaded authenticators: [" . implode(", ", array_keys($this->authenticators)) . "]");
  401. else
  402. throw new Swift_ConnectionException("Authentication failed using username '" . $user . "' and password '". str_repeat("*", strlen($pass)) . "'");
  403. }
  404. /**
  405. * Try to close the connection
  406. * @throws Swift_ConnectionException Upon failure to close
  407. */
  408. public function stop()
  409. {
  410. $log = Swift_LogContainer::getLog();
  411. if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))
  412. {
  413. $log->add("Closing down SMTP connection.");
  414. }
  415. if ($this->handle)
  416. {
  417. if (!fclose($this->handle))
  418. {
  419. throw new Swift_ConnectionException("The SMTP connection could not be closed for an unknown reason." . $this->smtpErrors());
  420. }
  421. $this->handle = null;
  422. }
  423. }
  424. /**
  425. * Check if the SMTP connection is alive
  426. * @return boolean
  427. */
  428. public function isAlive()
  429. {
  430. return ($this->handle !== null);
  431. }
  432. /**
  433. * Destructor.
  434. * Cleans up any open connections.
  435. */
  436. public function __destruct()
  437. {
  438. $this->stop();
  439. }
  440. }