cake/libs/cake_socket.php

1 <?php
2 /**
3 * Cake Socket connection class.
4 *
5 * PHP versions 4 and 5
6 *
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
9 *
10 * Licensed under The MIT License
11 * Redistributions of files must retain the above copyright notice.
12 *
13 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
14 * @link http://cakephp.org CakePHP(tm) Project
15 * @package cake
16 * @subpackage cake.cake.libs
17 * @since CakePHP(tm) v 1.2.0
18 * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
19 */
20 App::import('Core', 'Validation');
21  
22 /**
23 * Cake network socket connection class.
24 *
25 * Core base class for network communication.
26 *
27 * @package cake
28 * @subpackage cake.cake.libs
29 */
30 class CakeSocket extends Object {
31  
32 /**
33 * Object description
34 *
35 * @var string
36 * @access public
37 */
38 var $description = 'Remote DataSource Network Socket Interface';
39  
40 /**
41 * Base configuration settings for the socket connection
42 *
43 * @var array
44 * @access protected
45 */
46 var $_baseConfig = array(
47 'persistent' => false,
48 'host' => 'localhost',
49 'protocol' => 'tcp',
50 'port' => 80,
51 'timeout' => 30
52 );
53  
54 /**
55 * Configuration settings for the socket connection
56 *
57 * @var array
58 * @access public
59 */
60 var $config = array();
61  
62 /**
63 * Reference to socket connection resource
64 *
65 * @var resource
66 * @access public
67 */
68 var $connection = null;
69  
70 /**
71 * This boolean contains the current state of the CakeSocket class
72 *
73 * @var boolean
74 * @access public
75 */
76 var $connected = false;
77  
78 /**
79 * This variable contains an array with the last error number (num) and string (str)
80 *
81 * @var array
82 * @access public
83 */
84 var $lastError = array();
85  
86 /**
87 * Constructor.
88 *
89 * @param array $config Socket configuration, which will be merged with the base configuration
90 * @see CakeSocket::$_baseConfig
91 */
92 function __construct($config = array()) {
93 parent::__construct();
94  
95 $this->config = array_merge($this->_baseConfig, $config);
96 if (!is_numeric($this->config['protocol'])) {
97 $this->config['protocol'] = getprotobyname($this->config['protocol']);
98 }
99 }
100  
101 /**
102 * Connect the socket to the given host and port.
103 *
104 * @return boolean Success
105 * @access public
106 */
107 function connect() {
108 if ($this->connection != null) {
109 $this->disconnect();
110 }
111  
112 $scheme = null;
113 if (isset($this->config['request']) && $this->config['request']['uri']['scheme'] == 'https') {
114 $scheme = 'ssl://';
115 }
116  
117 if ($this->config['persistent'] == true) {
118 $tmp = null;
119 $this->connection = @pfsockopen($scheme.$this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
120 } else {
121 $this->connection = @fsockopen($scheme.$this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
122 }
123  
124 if (!empty($errNum) || !empty($errStr)) {
125 $this->setLastError($errStr, $errNum);
126 }
127  
128 $this->connected = is_resource($this->connection);
129 if ($this->connected) {
130 stream_set_timeout($this->connection, $this->config['timeout']);
131 }
132 return $this->connected;
133 }
134  
135 /**
136 * Get the host name of the current connection.
137 *
138 * @return string Host name
139 * @access public
140 */
141 function host() {
142 if (Validation::ip($this->config['host'])) {
143 return gethostbyaddr($this->config['host']);
144 } else {
145 return gethostbyaddr($this->address());
146 }
147 }
148  
149 /**
150 * Get the IP address of the current connection.
151 *
152 * @return string IP address
153 * @access public
154 */
155 function address() {
156 if (Validation::ip($this->config['host'])) {
157 return $this->config['host'];
158 } else {
159 return gethostbyname($this->config['host']);
160 }
161 }
162  
163 /**
164 * Get all IP addresses associated with the current connection.
165 *
166 * @return array IP addresses
167 * @access public
168 */
169 function addresses() {
170 if (Validation::ip($this->config['host'])) {
171 return array($this->config['host']);
172 } else {
173 return gethostbynamel($this->config['host']);
174 }
175 }
176  
177 /**
178 * Get the last error as a string.
179 *
180 * @return string Last error
181 * @access public
182 */
183 function lastError() {
184 if (!empty($this->lastError)) {
185 return $this->lastError['num'] . ': ' . $this->lastError['str'];
186 } else {
187 return null;
188 }
189 }
190  
191 /**
192 * Set the last error.
193 *
194 * @param integer $errNum Error code
195 * @param string $errStr Error string
196 * @access public
197 */
198 function setLastError($errNum, $errStr) {
199 $this->lastError = array('num' => $errNum, 'str' => $errStr);
200 }
201  
202 /**
203 * Write data to the socket.
204 *
205 * @param string $data The data to write to the socket
206 * @return boolean Success
207 * @access public
208 */
209 function write($data) {
210 if (!$this->connected) {
211 if (!$this->connect()) {
212 return false;
213 }
214 }
215  
216 return fwrite($this->connection, $data, strlen($data));
217 }
218  
219 /**
220 * Read data from the socket. Returns false if no data is available or no connection could be
221 * established.
222 *
223 * @param integer $length Optional buffer length to read; defaults to 1024
224 * @return mixed Socket data
225 * @access public
226 */
227 function read($length = 1024) {
228 if (!$this->connected) {
229 if (!$this->connect()) {
230 return false;
231 }
232 }
233  
234 if (!feof($this->connection)) {
235 $buffer = fread($this->connection, $length);
236 $info = stream_get_meta_data($this->connection);
237 if ($info['timed_out']) {
238 $this->setLastError(E_WARNING, __('Connection timed out', true));
239 return false;
240 }
241 return $buffer;
242 } else {
243 return false;
244 }
245 }
246  
247 /**
248 * Abort socket operation.
249 *
250 * @return boolean Success
251 * @access public
252 */
253 function abort() {
254 }
255  
256 /**
257 * Disconnect the socket from the current connection.
258 *
259 * @return boolean Success
260 * @access public
261 */
262 function disconnect() {
263 if (!is_resource($this->connection)) {
264 $this->connected = false;
265 return true;
266 }
267 $this->connected = !fclose($this->connection);
268  
269 if (!$this->connected) {
270 $this->connection = null;
271 }
272 return !$this->connected;
273 }
274  
275 /**
276 * Destructor, used to disconnect from current connection.
277 *
278 * @access private
279 */
280 function __destruct() {
281 $this->disconnect();
282 }
283  
284 /**
285 * Resets the state of this Socket instance to it's initial state (before Object::__construct got executed)
286 *
287 * @return boolean True on success
288 * @access public
289 */
290 function reset($state = null) {
291 if (empty($state)) {
292 static $initalState = array();
293 if (empty($initalState)) {
294 $initalState = get_class_vars(__CLASS__);
295 }
296 $state = $initalState;
297 }
298  
299 foreach ($state as $property => $value) {
300 $this->{$property} = $value;
301 }
302 return true;
303 }
304 }
305  
306