/framework/vendor/swift/lib/classes/Swift/Transport/StreamBuffer.php

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