1: <?php
  2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18: 
 19: 
 20: App::uses('Validation', 'Utility');
 21: 
 22:  23:  24:  25:  26:  27:  28: 
 29: class CakeSocket {
 30: 
 31:  32:  33:  34:  35: 
 36:     public $description = 'Remote DataSource Network Socket Interface';
 37: 
 38:  39:  40:  41:  42: 
 43:     protected $_baseConfig = array(
 44:         'persistent'    => false,
 45:         'host'          => 'localhost',
 46:         'protocol'      => 'tcp',
 47:         'port'          => 80,
 48:         'timeout'       => 30
 49:     );
 50: 
 51:  52:  53:  54:  55: 
 56:     public $config = array();
 57: 
 58:  59:  60:  61:  62: 
 63:     public $connection = null;
 64: 
 65:  66:  67:  68:  69: 
 70:     public $connected = false;
 71: 
 72:  73:  74:  75:  76: 
 77:     public $lastError = array();
 78: 
 79:  80:  81:  82:  83:  84: 
 85:     public function __construct($config = array()) {
 86:         $this->config = array_merge($this->_baseConfig, $config);
 87:         if (!is_numeric($this->config['protocol'])) {
 88:             $this->config['protocol'] = getprotobyname($this->config['protocol']);
 89:         }
 90:     }
 91: 
 92:  93:  94:  95:  96:  97: 
 98:     public function connect() {
 99:         if ($this->connection != null) {
100:             $this->disconnect();
101:         }
102: 
103:         $scheme = null;
104:         if (isset($this->config['request']) && $this->config['request']['uri']['scheme'] == 'https') {
105:             $scheme = 'ssl://';
106:         }
107: 
108:         
109:         if ($this->config['persistent'] == true) {
110:             $this->connection = @pfsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
111:         } else {
112:             $this->connection = @fsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
113:         }
114:         
115: 
116:         if (!empty($errNum) || !empty($errStr)) {
117:             $this->setLastError($errNum, $errStr);
118:             throw new SocketException($errStr, $errNum);
119:         }
120: 
121:         $this->connected = is_resource($this->connection);
122:         if ($this->connected) {
123:             stream_set_timeout($this->connection, $this->config['timeout']);
124:         }
125:         return $this->connected;
126:     }
127: 
128: 129: 130: 131: 132: 
133:     public function host() {
134:         if (Validation::ip($this->config['host'])) {
135:             return gethostbyaddr($this->config['host']);
136:         }
137:         return gethostbyaddr($this->address());
138:     }
139: 
140: 141: 142: 143: 144: 
145:     public function address() {
146:         if (Validation::ip($this->config['host'])) {
147:             return $this->config['host'];
148:         }
149:         return gethostbyname($this->config['host']);
150:     }
151: 
152: 153: 154: 155: 156: 
157:     public function addresses() {
158:         if (Validation::ip($this->config['host'])) {
159:             return array($this->config['host']);
160:         }
161:         return gethostbynamel($this->config['host']);
162:     }
163: 
164: 165: 166: 167: 168: 
169:     public function lastError() {
170:         if (!empty($this->lastError)) {
171:             return $this->lastError['num'] . ': ' . $this->lastError['str'];
172:         }
173:         return null;
174:     }
175: 
176: 177: 178: 179: 180: 181: 182: 
183:     public function setLastError($errNum, $errStr) {
184:         $this->lastError = array('num' => $errNum, 'str' => $errStr);
185:     }
186: 
187: 188: 189: 190: 191: 192: 
193:     public function write($data) {
194:         if (!$this->connected) {
195:             if (!$this->connect()) {
196:                 return false;
197:             }
198:         }
199:         $totalBytes = strlen($data);
200:         for ($written = 0, $rv = 0; $written < $totalBytes; $written += $rv) {
201:             $rv = fwrite($this->connection, substr($data, $written));
202:             if ($rv === false || $rv === 0) {
203:                 return $written;
204:             }
205:         }
206:         return $written;
207:     }
208: 
209: 210: 211: 212: 213: 214: 215: 
216:     public function read($length = 1024) {
217:         if (!$this->connected) {
218:             if (!$this->connect()) {
219:                 return false;
220:             }
221:         }
222: 
223:         if (!feof($this->connection)) {
224:             $buffer = fread($this->connection, $length);
225:             $info = stream_get_meta_data($this->connection);
226:             if ($info['timed_out']) {
227:                 $this->setLastError(E_WARNING, __d('cake_dev', 'Connection timed out'));
228:                 return false;
229:             }
230:             return $buffer;
231:         }
232:         return false;
233:     }
234: 
235: 236: 237: 238: 239: 
240:     public function disconnect() {
241:         if (!is_resource($this->connection)) {
242:             $this->connected = false;
243:             return true;
244:         }
245:         $this->connected = !fclose($this->connection);
246: 
247:         if (!$this->connected) {
248:             $this->connection = null;
249:         }
250:         return !$this->connected;
251:     }
252: 
253: 254: 255: 256: 
257:     public function __destruct() {
258:         $this->disconnect();
259:     }
260: 
261: 262: 263: 264: 265: 266: 
267:     public function reset($state = null) {
268:         if (empty($state)) {
269:             static $initalState = array();
270:             if (empty($initalState)) {
271:                 $initalState = get_class_vars(__CLASS__);
272:             }
273:             $state = $initalState;
274:         }
275: 
276:         foreach ($state as $property => $value) {
277:             $this->{$property} = $value;
278:         }
279:         return true;
280:     }
281: 
282: }
283: