PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Mage/HTTP/Client/Socket.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 537 lines | 260 code | 63 blank | 214 comment | 32 complexity | 7a889fed729d92eba849d6fdfa32d7d6 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Connect
  23. * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Class to work with HTTP protocol using sockets
  28. *
  29. * @category Mage
  30. * @package Mage_Connect
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_HTTP_Client_Socket
  34. implements Mage_HTTP_IClient
  35. {
  36. /**
  37. * Hostname
  38. * @var string
  39. */
  40. private $_host = 'localhost';
  41. /**
  42. * Port
  43. * @var int
  44. */
  45. private $_port = 80;
  46. /**
  47. * Stream resource
  48. * @var object
  49. */
  50. private $_sock = null;
  51. /**
  52. * Request headers
  53. * @var array
  54. */
  55. private $_headers = array();
  56. /**
  57. * Fields for POST method - hash
  58. * @var array
  59. */
  60. private $_postFields = array();
  61. /**
  62. * Request cookies
  63. * @var array
  64. */
  65. private $_cookies = array();
  66. /**
  67. * Response headers
  68. * @var array
  69. */
  70. private $_responseHeaders = array();
  71. /**
  72. * Response body
  73. * @var string
  74. */
  75. private $_responseBody = '';
  76. /**
  77. * Response status
  78. * @var int
  79. */
  80. private $_responseStatus = 0;
  81. /**
  82. * Request timeout
  83. * @var int
  84. */
  85. private $_timeout = 300;
  86. /**
  87. * TODO
  88. * @var int
  89. */
  90. private $_redirectCount = 0;
  91. /**
  92. * Set request timeout, msec
  93. *
  94. * @param int $value
  95. */
  96. public function setTimeout($value)
  97. {
  98. $this->_timeout = (int) $value;
  99. }
  100. /**
  101. * Constructor
  102. * @param string $host
  103. * @param int $port
  104. */
  105. public function __construct($host = null, $port = 80)
  106. {
  107. if($host) {
  108. $this->connect($host, (int) $port);
  109. }
  110. }
  111. /**
  112. * Set connection params
  113. *
  114. * @param string $host
  115. * @param int $port
  116. */
  117. public function connect($host, $port = 80)
  118. {
  119. $this->_host = $host;
  120. $this->_port = (int) $port;
  121. }
  122. /**
  123. * Disconnect
  124. */
  125. public function disconnect()
  126. {
  127. @fclose($this->_sock);
  128. }
  129. /**
  130. * Set headers from hash
  131. * @param array $headers
  132. */
  133. public function setHeaders($headers)
  134. {
  135. $this->_headers = $headers;
  136. }
  137. /**
  138. * Add header
  139. *
  140. * @param $name name, ex. "Location"
  141. * @param $value value ex. "http://google.com"
  142. */
  143. public function addHeader($name, $value)
  144. {
  145. $this->_headers[$name] = $value;
  146. }
  147. /**
  148. * Remove specified header
  149. *
  150. * @param string $name
  151. */
  152. public function removeHeader($name)
  153. {
  154. unset($this->_headers[$name]);
  155. }
  156. /**
  157. * Authorization: Basic header
  158. * Login credentials support
  159. *
  160. * @param string $login username
  161. * @param string $pass password
  162. */
  163. public function setCredentials($login, $pass)
  164. {
  165. $val= base64_encode( "$login:$pass" );
  166. $this->addHeader( "Authorization", "Basic $val" );
  167. }
  168. /**
  169. * Add cookie
  170. *
  171. * @param string $name
  172. * @param string $value
  173. */
  174. public function addCookie($name, $value)
  175. {
  176. $this->_cookies[$name] = $value;
  177. }
  178. /**
  179. * Remove cookie
  180. *
  181. * @param string $name
  182. */
  183. public function removeCookie($name)
  184. {
  185. unset($this->_cookies[$name]);
  186. }
  187. /**
  188. * Set cookies array
  189. *
  190. * @param array $cookies
  191. */
  192. public function setCookies($cookies)
  193. {
  194. $this->_cookies = $cookies;
  195. }
  196. /**
  197. * Clear cookies
  198. */
  199. public function removeCookies()
  200. {
  201. $this->setCookies(array());
  202. }
  203. /**
  204. * Make GET request
  205. *
  206. * @param string $uri full uri path
  207. */
  208. public function get($uri)
  209. {
  210. $this->makeRequest("GET",$this->parseUrl($uri));
  211. }
  212. /**
  213. * Set host, port from full url
  214. * and return relative url
  215. *
  216. * @param string $uri ex. http://google.com/index.php?a=b
  217. * @return string ex. /index.php?a=b
  218. */
  219. protected function parseUrl($uri)
  220. {
  221. $parts = parse_url($uri);
  222. if(!empty($parts['user']) && !empty($parts['pass'])) {
  223. $this->setCredentials($parts['user'], $parts['pass']);
  224. }
  225. if(!empty($parts['port'])) {
  226. $this->_port = (int) $parts['port'];
  227. }
  228. if(!empty($parts['host'])) {
  229. $this->_host = $parts['host'];
  230. } else {
  231. throw new InvalidArgumentException("Uri doesn't contain host part");
  232. }
  233. if(!empty($parts['path'])) {
  234. $requestUri = $parts['path'];
  235. } else {
  236. throw new InvalidArgumentException("Uri doesn't contain path part");
  237. }
  238. if(!empty($parts['query'])) {
  239. $requestUri .= "?".$parts['query'];
  240. }
  241. return $requestUri;
  242. }
  243. /**
  244. * Make POST request
  245. */
  246. public function post($uri, $params)
  247. {
  248. $this->makeRequest("POST", $this->parseUrl($uri), $params);
  249. }
  250. /**
  251. * Get response headers
  252. *
  253. * @return array
  254. */
  255. public function getHeaders()
  256. {
  257. return $this->_responseHeaders;
  258. }
  259. /**
  260. * Get response body
  261. *
  262. * @return string
  263. */
  264. public function getBody()
  265. {
  266. return $this->_responseBody;
  267. }
  268. /**
  269. * Get cookies response hash
  270. *
  271. * @return array
  272. */
  273. public function getCookies()
  274. {
  275. if(empty($this->_responseHeaders['Set-Cookie'])) {
  276. return array();
  277. }
  278. $out = array();
  279. foreach( $this->_responseHeaders['Set-Cookie'] as $row) {
  280. $values = explode("; ", $row);
  281. $c = count($values);
  282. if(!$c) {
  283. continue;
  284. }
  285. list($key, $val) = explode("=", $values[0]);
  286. if(is_null($val)) {
  287. continue;
  288. }
  289. $out[trim($key)] = trim($val);
  290. }
  291. return $out;
  292. }
  293. /**
  294. * Get cookies array with details
  295. * (domain, expire time etc)
  296. * @return array
  297. */
  298. public function getCookiesFull()
  299. {
  300. if(empty($this->_responseHeaders['Set-Cookie'])) {
  301. return array();
  302. }
  303. $out = array();
  304. foreach( $this->_responseHeaders['Set-Cookie'] as $row) {
  305. $values = explode("; ", $row);
  306. $c = count($values);
  307. if(!$c) {
  308. continue;
  309. }
  310. list($key, $val) = explode("=", $values[0]);
  311. if(is_null($val)) {
  312. continue;
  313. }
  314. $out[trim($key)] = array('value'=>trim($val));
  315. array_shift($values);
  316. $c--;
  317. if(!$c) {
  318. continue;
  319. }
  320. for($i = 0; $i<$c; $i++) {
  321. list($subkey, $val) = explode("=", $values[$i]);
  322. $out[trim($key)][trim($subkey)] = trim($val);
  323. }
  324. }
  325. return $out;
  326. }
  327. /**
  328. * Process response headers
  329. */
  330. protected function processResponseHeaders()
  331. {
  332. $crlf = "\r\n";
  333. $this->_responseHeaders = array();
  334. while (!feof($this->_sock)) {
  335. $line = fgets($this->_sock, 1024);
  336. if($line === $crlf) {
  337. return;
  338. }
  339. $name = $value = '';
  340. $out = explode(": ", trim($line), 2);
  341. if(count($out) == 2) {
  342. $name = $out[0];
  343. $value = $out[1];
  344. }
  345. if(!empty($value)) {
  346. if($name == "Set-Cookie") {
  347. if(!isset($this->_responseHeaders[$name])) {
  348. $this->_responseHeaders[$name] = array();
  349. }
  350. $this->_responseHeaders[$name][] = $value;
  351. } else {
  352. $this->_responseHeaders[$name] = $value;
  353. }
  354. }
  355. }
  356. }
  357. /**
  358. * Process response body
  359. */
  360. protected function processResponseBody()
  361. {
  362. $this->_responseBody = '';
  363. while (!feof($this->_sock)) {
  364. $this->_responseBody .= @fread($this->_sock, 1024);
  365. }
  366. }
  367. /**
  368. * Process response
  369. */
  370. protected function processResponse()
  371. {
  372. $response = '';
  373. $responseLine = trim(fgets($this->_sock, 1024));
  374. $line = explode(" ", $responseLine, 3);
  375. if(count($line) != 3) {
  376. return $this->doError("Invalid response line returned from server: ".$responseLine);
  377. }
  378. $this->_responseStatus = intval($line[1]);
  379. $this->processResponseHeaders();
  380. $this->processRedirect();
  381. $this->processResponseBody();
  382. }
  383. /**
  384. * Process redirect
  385. */
  386. protected function processRedirect()
  387. {
  388. // TODO: implement redircets support
  389. }
  390. /**
  391. * Get response status code
  392. * @see lib/Mage/HTTP/Mage_HTTP_Client#getStatus()
  393. */
  394. public function getStatus()
  395. {
  396. return $this->_responseStatus;
  397. }
  398. /**
  399. * Make request
  400. * @param string $method
  401. * @param string $uri
  402. * @param array $params
  403. * @return null
  404. */
  405. protected function makeRequest($method, $uri, $params = array())
  406. {
  407. $errno = $errstr = '';
  408. $this->_sock = @fsockopen($this->_host, $this->_port, $errno, $errstr, $this->_timeout);
  409. if(!$this->_sock) {
  410. return $this->doError(sprintf("[errno: %d] %s", $errno, $errstr));
  411. }
  412. $crlf = "\r\n";
  413. $isPost = $method == "POST";
  414. $appendHeaders = array();
  415. $paramsStr = false;
  416. if($isPost && count($params)) {
  417. $paramsStr = http_build_query($params);
  418. $appendHeaders['Content-type'] = 'application/x-www-form-urlencoded';
  419. $appendHeaders['Content-length'] = strlen($paramsStr);
  420. }
  421. $out = "{$method} {$uri} HTTP/1.1{$crlf}";
  422. $out .= $this->headersToString($appendHeaders);
  423. $out .= $crlf;
  424. if($paramsStr) {
  425. $out .= $paramsStr.$crlf;
  426. }
  427. fwrite($this->_sock, $out);
  428. $this->processResponse();
  429. }
  430. /**
  431. * Throw error excpetion
  432. * @param $string
  433. * @throws Exception
  434. */
  435. public function doError($string)
  436. {
  437. throw new Exception($string);
  438. }
  439. /**
  440. * Convert headers hash to string
  441. * @param $delimiter
  442. * @param $append
  443. * @return string
  444. */
  445. protected function headersToString($append = array())
  446. {
  447. $headers = array();
  448. $headers["Host"] = $this->_host;
  449. $headers['Connection'] = "close";
  450. $headers = array_merge($headers, $this->_headers, $append);
  451. $str = array();
  452. foreach ($headers as $k=>$v) {
  453. $str []= "$k: $v\r\n";
  454. }
  455. return implode($str);
  456. }
  457. /**
  458. * TODO
  459. */
  460. public function setOptions($arr)
  461. {
  462. // Stub
  463. }
  464. /**
  465. * TODO
  466. */
  467. public function setOption($name, $value)
  468. {
  469. // Stub
  470. }
  471. }