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