PageRenderTime 98ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php

https://gitlab.com/techniconline/kmc
PHP | 321 lines | 209 code | 31 blank | 81 comment | 34 complexity | b841b1207cfa7f6aed9cab98f5e7bfa6 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of SwiftMailer.
  4. * (c) 2004-2009 Chris Corbyn
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * A generic IoBuffer implementation supporting remote sockets and local processes.
  11. *
  12. * @author Chris Corbyn
  13. */
  14. class Swift_Transport_StreamBuffer extends Swift_ByteStream_AbstractFilterableInputStream implements Swift_Transport_IoBuffer
  15. {
  16. /** A primary socket */
  17. private $_stream;
  18. /** The input stream */
  19. private $_in;
  20. /** The output stream */
  21. private $_out;
  22. /** Buffer initialization parameters */
  23. private $_params = array();
  24. /** The ReplacementFilterFactory */
  25. private $_replacementFactory;
  26. /** Translations performed on data being streamed into the buffer */
  27. private $_translations = array();
  28. /**
  29. * Create a new StreamBuffer using $replacementFactory for transformations.
  30. *
  31. * @param Swift_ReplacementFilterFactory $replacementFactory
  32. */
  33. public function __construct(Swift_ReplacementFilterFactory $replacementFactory)
  34. {
  35. $this->_replacementFactory = $replacementFactory;
  36. }
  37. /**
  38. * Perform any initialization needed, using the given $params.
  39. *
  40. * Parameters will vary depending upon the type of IoBuffer used.
  41. *
  42. * @param array $params
  43. */
  44. public function initialize(array $params)
  45. {
  46. $this->_params = $params;
  47. switch ($params['type']) {
  48. case self::TYPE_PROCESS:
  49. $this->_establishProcessConnection();
  50. break;
  51. case self::TYPE_SOCKET:
  52. default:
  53. $this->_establishSocketConnection();
  54. break;
  55. }
  56. }
  57. /**
  58. * Set an individual param on the buffer (e.g. switching to SSL).
  59. *
  60. * @param string $param
  61. * @param mixed $value
  62. */
  63. public function setParam($param, $value)
  64. {
  65. if (isset($this->_stream)) {
  66. switch ($param) {
  67. case 'timeout':
  68. if ($this->_stream) {
  69. stream_set_timeout($this->_stream, $value);
  70. }
  71. break;
  72. case 'blocking':
  73. if ($this->_stream) {
  74. stream_set_blocking($this->_stream, 1);
  75. }
  76. }
  77. }
  78. $this->_params[$param] = $value;
  79. }
  80. public function startTLS()
  81. {
  82. return stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
  83. }
  84. /**
  85. * Perform any shutdown logic needed.
  86. */
  87. public function terminate()
  88. {
  89. if (isset($this->_stream)) {
  90. switch ($this->_params['type']) {
  91. case self::TYPE_PROCESS:
  92. fclose($this->_in);
  93. fclose($this->_out);
  94. proc_close($this->_stream);
  95. break;
  96. case self::TYPE_SOCKET:
  97. default:
  98. fclose($this->_stream);
  99. break;
  100. }
  101. }
  102. $this->_stream = null;
  103. $this->_out = null;
  104. $this->_in = null;
  105. }
  106. /**
  107. * Set an array of string replacements which should be made on data written
  108. * to the buffer.
  109. *
  110. * This could replace LF with CRLF for example.
  111. *
  112. * @param string[] $replacements
  113. */
  114. public function setWriteTranslations(array $replacements)
  115. {
  116. foreach ($this->_translations as $search => $replace) {
  117. if (!isset($replacements[$search])) {
  118. $this->removeFilter($search);
  119. unset($this->_translations[$search]);
  120. }
  121. }
  122. foreach ($replacements as $search => $replace) {
  123. if (!isset($this->_translations[$search])) {
  124. $this->addFilter(
  125. $this->_replacementFactory->createFilter($search, $replace), $search
  126. );
  127. $this->_translations[$search] = true;
  128. }
  129. }
  130. }
  131. /**
  132. * Get a line of output (including any CRLF).
  133. *
  134. * The $sequence number comes from any writes and may or may not be used
  135. * depending upon the implementation.
  136. *
  137. * @param int $sequence of last write to scan from
  138. *
  139. * @throws Swift_IoException
  140. *
  141. * @return string
  142. */
  143. public function readLine($sequence)
  144. {
  145. if (isset($this->_out) && !feof($this->_out)) {
  146. $line = fgets($this->_out);
  147. if (strlen($line) == 0) {
  148. $metas = stream_get_meta_data($this->_out);
  149. if ($metas['timed_out']) {
  150. throw new Swift_IoException(
  151. 'Connection to ' .
  152. $this->_getReadConnectionDescription() .
  153. ' Timed Out'
  154. );
  155. }
  156. }
  157. return $line;
  158. }
  159. }
  160. /**
  161. * Reads $length bytes from the stream into a string and moves the pointer
  162. * through the stream by $length.
  163. *
  164. * If less bytes exist than are requested the remaining bytes are given instead.
  165. * If no bytes are remaining at all, boolean false is returned.
  166. *
  167. * @param int $length
  168. *
  169. * @throws Swift_IoException
  170. *
  171. * @return string|bool
  172. */
  173. public function read($length)
  174. {
  175. if (isset($this->_out) && !feof($this->_out)) {
  176. $ret = fread($this->_out, $length);
  177. if (strlen($ret) == 0) {
  178. $metas = stream_get_meta_data($this->_out);
  179. if ($metas['timed_out']) {
  180. throw new Swift_IoException(
  181. 'Connection to ' .
  182. $this->_getReadConnectionDescription() .
  183. ' Timed Out'
  184. );
  185. }
  186. }
  187. return $ret;
  188. }
  189. }
  190. /** Not implemented */
  191. public function setReadPointer($byteOffset)
  192. {
  193. }
  194. /** Flush the stream contents */
  195. protected function _flush()
  196. {
  197. if (isset($this->_in)) {
  198. fflush($this->_in);
  199. }
  200. }
  201. /** Write this bytes to the stream */
  202. protected function _commit($bytes)
  203. {
  204. if (isset($this->_in)) {
  205. $bytesToWrite = strlen($bytes);
  206. $totalBytesWritten = 0;
  207. while ($totalBytesWritten < $bytesToWrite) {
  208. $bytesWritten = fwrite($this->_in, substr($bytes, $totalBytesWritten));
  209. if (false === $bytesWritten || 0 === $bytesWritten) {
  210. break;
  211. }
  212. $totalBytesWritten += $bytesWritten;
  213. }
  214. if ($totalBytesWritten > 0) {
  215. return ++$this->_sequence;
  216. }
  217. }
  218. }
  219. /**
  220. * Establishes a connection to a remote server.
  221. */
  222. private function _establishSocketConnection()
  223. {
  224. $host = $this->_params['host'];
  225. if (!empty($this->_params['protocol'])) {
  226. $host = $this->_params['protocol'] . '://' . $host;
  227. }
  228. $timeout = 15;
  229. if (!empty($this->_params['timeout'])) {
  230. $timeout = $this->_params['timeout'];
  231. }
  232. $options = array();
  233. if (!empty($this->_params['sourceIp'])) {
  234. $options['socket']['bindto'] = $this->_params['sourceIp'] . ':0';
  235. }
  236. $this->_stream = @stream_socket_client($host . ':' . $this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
  237. if (false === $this->_stream) {
  238. throw new Swift_TransportException(
  239. 'Connection could not be established with host ' . $this->_params['host'] .
  240. ' [' . $errstr . ' #' . $errno . ']'
  241. );
  242. }
  243. if (!empty($this->_params['blocking'])) {
  244. stream_set_blocking($this->_stream, 1);
  245. } else {
  246. stream_set_blocking($this->_stream, 0);
  247. }
  248. stream_set_timeout($this->_stream, $timeout);
  249. $this->_in = &$this->_stream;
  250. $this->_out = &$this->_stream;
  251. }
  252. /**
  253. * Opens a process for input/output.
  254. */
  255. private function _establishProcessConnection()
  256. {
  257. $command = $this->_params['command'];
  258. $descriptorSpec = array(
  259. 0 => array('pipe', 'r'),
  260. 1 => array('pipe', 'w'),
  261. 2 => array('pipe', 'w'),
  262. );
  263. $this->_stream = proc_open($command, $descriptorSpec, $pipes);
  264. stream_set_blocking($pipes[2], 0);
  265. if ($err = stream_get_contents($pipes[2])) {
  266. throw new Swift_TransportException(
  267. 'Process could not be started [' . $err . ']'
  268. );
  269. }
  270. $this->_in = &$pipes[0];
  271. $this->_out = &$pipes[1];
  272. }
  273. private function _getReadConnectionDescription()
  274. {
  275. switch ($this->_params['type']) {
  276. case self::TYPE_PROCESS:
  277. return 'Process ' . $this->_params['command'];
  278. break;
  279. case self::TYPE_SOCKET:
  280. default:
  281. $host = $this->_params['host'];
  282. if (!empty($this->_params['protocol'])) {
  283. $host = $this->_params['protocol'] . '://' . $host;
  284. }
  285. $host .= ':' . $this->_params['port'];
  286. return $host;
  287. break;
  288. }
  289. }
  290. }