/Http/HTTPConnection.php

https://github.com/silasrm/Correios · PHP · 430 lines · 200 code · 66 blank · 164 comment · 58 complexity · 719640b7de2039b97193485831928128 MD5 · raw file

  1. <?php
  2. /**
  3. * @brief Protocolo HTTP
  4. * @details Classes e interfaces relacionadas com o protocolo HTTP
  5. * @package Correios
  6. * @subpackage Correios_Http
  7. */
  8. require_once 'Correios/Http/HTTPAuthenticator.php';
  9. require_once 'Correios/Http/HTTPRequestMethod.php';
  10. require_once 'Correios/Http/CURL.php';
  11. /**
  12. * @author João Batista Neto <neto.joaobatista@imasters.com.br>
  13. * @brief Implementação de um conector HTTP.
  14. */
  15. class Correios_Http_HTTPConnection {
  16. /**
  17. * @brief Porta padrão de uma conexão HTTP não segura.
  18. */
  19. const HTTP_PORT = 80;
  20. /**
  21. * @brief Porta padrão de uma conexão HTTP segura.
  22. */
  23. const HTTPS_PORT = 443;
  24. /**
  25. * @var HTTPAuthenticator
  26. */
  27. protected $httpAuthenticator;
  28. /**
  29. * @var CookieManager
  30. */
  31. protected $cookieManager;
  32. /**
  33. * @var integer
  34. */
  35. protected $connectionTimeout;
  36. /**
  37. * @var string
  38. */
  39. protected $hostname;
  40. /**
  41. * @var boolean
  42. */
  43. protected $initialized = false;
  44. /**
  45. * @var integer
  46. */
  47. protected $port;
  48. /**
  49. * @var string
  50. */
  51. protected $requestBody;
  52. /**
  53. * @var array
  54. */
  55. protected $requestHeader;
  56. /**
  57. * @var array
  58. */
  59. protected $requestParameter;
  60. /**
  61. * @var boolean
  62. */
  63. protected $secure;
  64. /**
  65. * @var integer
  66. */
  67. protected $timeout;
  68. /**
  69. * @var string
  70. */
  71. protected static $userAgent;
  72. /**
  73. * @brief Constroi o objeto de conexão HTTP.
  74. */
  75. public function __construct() {
  76. if ( self::$userAgent == null ) {
  77. $locale = setlocale( LC_ALL , null );
  78. if ( function_exists( 'posix_uname' ) ) {
  79. $uname = posix_uname();
  80. self::$userAgent = sprintf( 'Mozilla/4.0 (compatible; %s; PHP/%s; %s %s; %s)' , PHP_SAPI , PHP_VERSION , $uname[ 'sysname' ] , $uname[ 'machine' ] , $locale );
  81. } else {
  82. self::$userAgent = sprintf( 'Mozilla/4.0 (compatible; %s; PHP/%s; %s; %s)' , PHP_SAPI , PHP_VERSION , PHP_OS , $locale );
  83. }
  84. }
  85. $this->requestHeader = array();
  86. $this->requestParameter = array();
  87. }
  88. /**
  89. * @brief Adiciona um campo de cabeçalho para ser enviado com a
  90. * requisição.
  91. * @param string $name Nome do campo de cabeçalho.
  92. * @param string $value Valor do campo de cabeçalho.
  93. * @param boolean $override Indica se o campo deverá
  94. * ser sobrescrito caso já tenha sido definido.
  95. * @throws InvalidArgumentException Se o nome ou o valor
  96. * do campo não forem valores scalar.
  97. */
  98. public function addHeader( $name , $value , $override = true ) {
  99. if ( is_scalar( $name ) && is_scalar( $value ) ) {
  100. $key = strtolower( $name );
  101. if ( $override === true || !isset( $this->requestHeader[ $key ] ) ) {
  102. $this->requestHeader[ $key ] = array( 'name' => $name , 'value' => $value );
  103. return true;
  104. }
  105. return false;
  106. } else {
  107. throw new InvalidArgumentException( '$name e $value precisam ser strings.' );
  108. }
  109. }
  110. /**
  111. * @brief Fecha a conexão.
  112. * @throws BadMethodCallException Se não houver uma conexão
  113. * inicializada.
  114. */
  115. public function close() {
  116. $this->initialized = false;
  117. }
  118. /**
  119. * @brief Executa a requisição
  120. * @details Executa a requisição HTTP em um caminho utilizando um
  121. * método específico.
  122. * @param string $path Caminho da requisição.
  123. * @param string $method Método da requisição.
  124. * @return HTTPResponse Resposta HTTP.
  125. * @throws BadMethodCallException Se não houver uma conexão
  126. * inicializada ou se o objeto de requisição não for válido.
  127. */
  128. public function execute( $path = '/' , $method = Correios_Http_HTTPRequestMethod::GET ) {
  129. $request = $this->newRequest();
  130. if ( $request instanceof Correios_Http_HTTPRequest ) {
  131. $host = $this->getHost();
  132. $accept = '*/*';
  133. $userAgent = self::$userAgent;
  134. if ( isset( $this->requestHeader[ 'Host' ] ) ) {
  135. $host = $this->requestHeader[ 'host' ][ 'value' ];
  136. unset( $this->requestHeader[ 'host' ] );
  137. }
  138. if ( isset( $this->requestHeader[ 'accept' ] ) ) {
  139. $accept = $this->requestHeader[ 'accept' ][ 'value' ];
  140. unset( $this->requestHeader[ 'accept' ] );
  141. }
  142. if ( isset( $this->requestHeader[ 'user-agent' ] ) ) {
  143. $userAgent = $this->requestHeader[ 'user-agent' ][ 'value' ];
  144. unset( $this->requestHeader[ 'user-agent' ] );
  145. }
  146. $request->addRequestHeader( 'Host' , $host );
  147. $request->addRequestHeader( 'Accept' , $accept );
  148. $request->addRequestHeader( 'User-Agent' , $userAgent );
  149. if ( $this->httpAuthenticator != null ) {
  150. $request->authenticate( $this->httpAuthenticator );
  151. }
  152. foreach ( $this->requestHeader as $header ) {
  153. $request->addRequestHeader( $header[ 'name' ] , $header[ 'value' ] );
  154. }
  155. $cookieManager = $this->getCookieManager();
  156. if ( $cookieManager != null ) {
  157. $cookies = $cookieManager->getCookie( $this->getHostName() , $this->isSecure() , $path );
  158. if ( isset( $this->requestHeader[ 'cookie' ] ) ) {
  159. $buffer = $this->requestHeader[ 'cookie' ][ 'value' ] . '; ' . $cookies;
  160. } else {
  161. $buffer = $cookies;
  162. }
  163. $request->addRequestHeader( 'Cookie' , $buffer );
  164. }
  165. foreach ( $this->requestParameter as $name => $value ) {
  166. $request->setParameter( $name , $value );
  167. }
  168. $request->setRequestBody( $this->requestBody );
  169. if ( $path == null || !is_string( $path ) || empty( $path ) ) {
  170. $path = '/';
  171. } else if ( substr( $path , 0 , 1 ) != '/' ) {
  172. $path = '/' . $path;
  173. }
  174. if ( $this->timeout != null ) {
  175. $request->setTimeout( $this->timeout );
  176. }
  177. if ( $this->connectionTimeout != null ) {
  178. $request->setConnectionTimeout( $this->connectionTimeout );
  179. }
  180. $request->open( $this );
  181. $request->execute( $path , $method );
  182. return $request->getResponse();
  183. } else {
  184. throw new BadMethodCallException( 'Objeto de requisição inválido.' );
  185. }
  186. }
  187. /**
  188. * @brief Recupera o timeout de conexão.
  189. * @return integer
  190. */
  191. public function getConnectionTimeout() {
  192. return $this->connectionTimeout;
  193. }
  194. /**
  195. * @brief Recupera o gerenciador de Cookies.
  196. * @return CookieManager
  197. */
  198. public function getCookieManager() {
  199. return $this->cookieManager;
  200. }
  201. /**
  202. * @brief Recupera o host da conexão.
  203. * @return string
  204. * @throws BadMethodCallException Se a conexão não tiver
  205. * sido inicializada.
  206. */
  207. public function getHost() {
  208. if ( $this->initialized ) {
  209. $hostname = $this->getHostName();
  210. if ( ( $this->secure && $this->port != Correios_Http_HTTPConnection::HTTPS_PORT ) || ( !$this->secure && $this->port != Correios_Http_HTTPConnection::HTTP_PORT ) ) {
  211. return $hostname . ':' . $this->port;
  212. } else {
  213. return $hostname;
  214. }
  215. } else {
  216. throw new BadMethodCallException( 'Conexão não inicializada' );
  217. }
  218. }
  219. /**
  220. * @brief Recupera o nome do host.
  221. * @return string
  222. * @throws BadMethodCallException Se não houver uma conexão
  223. * inicializada.
  224. */
  225. public function getHostName() {
  226. if ( $this->initialized ) {
  227. return $this->hostname;
  228. } else {
  229. throw new BadMethodCallException( 'Conexão não inicializada' );
  230. }
  231. }
  232. /**
  233. * @brief Recupera a porta que será utilizada na conexão.
  234. * @return integer
  235. * @throws BadMethodCallException Se não houver uma conexão
  236. * inicializada.
  237. */
  238. public function getPort() {
  239. if ( $this->initialized ) {
  240. return $this->port;
  241. } else {
  242. throw new BadMethodCallException( 'Conexão não inicializada' );
  243. }
  244. }
  245. /**
  246. * @brief Recupera o timeout.
  247. * @return integer
  248. */
  249. public function getTimeout() {
  250. return $this->timeout;
  251. }
  252. /**
  253. * @brief Recupera a URI que será utilizada na conexão.
  254. * @return string
  255. * @throws BadMethodCallException Se não houver uma conexão
  256. * inicializada.
  257. */
  258. public function getURI() {
  259. if ( $this->initialized ) {
  260. return sprintf( '%s://%s' , $this->isSecure() ? 'https' : 'http' , $this->getHost() );
  261. } else {
  262. throw new BadMethodCallException( 'Conexão não inicializada' );
  263. }
  264. }
  265. /**
  266. * @brief Inicializa a conexão HTTP.
  267. * @param string $hostname Servidor que receberá a requisição.
  268. * @param boolean $secure Indica se a conexão será segura (https).
  269. * @param integer $port Porta da requisição.
  270. * @param integer $connectionTimeout Timeout de conexão em segundos.
  271. * @param integer $timeout Timeout de espera em segundos.
  272. */
  273. public function initialize( $hostname , $secure = false , $port = Correios_Http_HTTPConnection::HTTP_PORT , $connectionTimeout = 0 , $timeout = 0 ) {
  274. if ( $this->initialized ) {
  275. $this->close();
  276. }
  277. $this->initialized = true;
  278. $this->hostname = $hostname;
  279. $this->secure = $secure === true;
  280. if ( func_num_args() == 2 ) {
  281. $this->port = $this->secure ? Correios_Http_HTTPConnection::HTTPS_PORT : Correios_Http_HTTPConnection::HTTP_PORT;
  282. } else {
  283. $this->port = (int) $port;
  284. }
  285. $this->connectionTimeout = (int) $connectionTimeout;
  286. $this->timeout = (int) $timeout;
  287. }
  288. /**
  289. * @brief Verifica se é uma conexão segura.
  290. * @return boolean
  291. */
  292. public function isSecure() {
  293. return $this->secure === true;
  294. }
  295. /**
  296. * @brief Cria uma instância de um objeto de requisição HTTP.
  297. * @return HTTPRequest
  298. */
  299. public function newRequest() {
  300. return new Correios_Http_CURL();
  301. }
  302. /**
  303. * @brief Define um autenticador HTTP.
  304. * @param HTTPAuthenticator $httpAuthenticator
  305. */
  306. public function setAuthenticator( Correios_Http_HTTPAuthenticator $httpAuthenticator ) {
  307. $this->httpAuthenticator = $httpAuthenticator;
  308. }
  309. /**
  310. * @brief Define o timeout de conexão.
  311. * @param integer $connectionTimeout
  312. * @throws InvalidArgumentException Se $connectionTimeout não for um inteiro.
  313. */
  314. public function setConnectionTimeout( $connectionTimeout ) {
  315. if ( is_integer( $connectionTimeout ) ) {
  316. $this->connectionTimeout = $connectionTimeout;
  317. } else {
  318. throw new InvalidArgumentException( '$connectionTimeout precisa ser o tempo em segundos.' );
  319. }
  320. }
  321. /**
  322. * @brief Define um gerenciador de cookies para essa conexão.
  323. * @param CookieManager $cookieManager
  324. */
  325. public function setCookieManager( Correios_Http_CookieManager $cookieManager ) {
  326. $this->cookieManager = $cookieManager;
  327. }
  328. /**
  329. * @brief Define um parâmetro
  330. * @details Define um parâmetro que será enviado com a requisição,
  331. * um parâmetro é um par nome-valor que será enviado como uma
  332. * query string (<b>ex:</b> <i>?name=value</i>).
  333. * @param string $name Nome do parâmetro.
  334. * @param string $value Valor do parâmetro.
  335. * @throws InvalidArgumentException Se o nome ou o valor
  336. * do campo não forem valores scalar.
  337. */
  338. public function setParam( $name , $value = null ) {
  339. if ( is_scalar( $name ) && ( is_scalar( $value ) || is_null( $value ) ) ) {
  340. $this->requestParameter[ $name ] = $value;
  341. } else {
  342. throw new InvalidArgumentException( '$name e $value precisam ser strings.' );
  343. }
  344. }
  345. /**
  346. * @brief Define o corpo da requisição.
  347. * @param string $requestBody
  348. */
  349. public function setRequestBody( $requestBody ) {
  350. $this->requestBody = $requestBody;
  351. }
  352. /**
  353. * @brief Define o timeout.
  354. * @param integer $timeout
  355. * @throws InvalidArgumentException Se $timeout não for um inteiro.
  356. */
  357. public function setTimeout( $timeout ) {
  358. if ( is_integer( $timeout ) ) {
  359. $this->timeout = $timeout;
  360. } else {
  361. throw new InvalidArgumentException( '$timeout precisa ser o tempo em segundos.' );
  362. }
  363. }
  364. }