HttpClient.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  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@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Gdata
  17. * @subpackage Gdata
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /**
  23. * Zend_Http_Client
  24. */
  25. require_once 'Zend/Http/Client.php';
  26. /** @see Zend_Crypt_Math */
  27. require_once 'Zend/Crypt/Math.php';
  28. /**
  29. * Gdata Http Client object.
  30. *
  31. * Class to extend the generic Zend Http Client with the ability to perform
  32. * secure AuthSub requests
  33. *
  34. * @category Zend
  35. * @package Zend_Gdata
  36. * @subpackage Gdata
  37. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class Zend_Gdata_HttpClient extends Zend_Http_Client
  41. {
  42. /**
  43. * OpenSSL private key resource id
  44. * This key is used for AuthSub authentication. If this value is set,
  45. * it is assuemd that secure AuthSub is desired.
  46. *
  47. * @var resource
  48. */
  49. private $_authSubPrivateKeyId = null;
  50. /**
  51. * Token for AuthSub authentication.
  52. * If this token is set, AuthSub authentication is used.
  53. *
  54. * @var string
  55. */
  56. private $_authSubToken = null;
  57. /**
  58. * Token for ClientLogin authentication.
  59. * If only this token is set, ClientLogin authentication is used.
  60. *
  61. * @var string
  62. */
  63. private $_clientLoginToken = null;
  64. /**
  65. * Token for ClientLogin authentication.
  66. * If this token is set, and the AuthSub key is not set,
  67. * ClientLogin authentication is used
  68. *
  69. * @var string
  70. */
  71. private $_clientLoginKey = null;
  72. /**
  73. * True if this request is being made with data supplied by
  74. * a stream object instead of a raw encoded string.
  75. *
  76. * @var bool
  77. */
  78. protected $_streamingRequest = null;
  79. /**
  80. * Sets the PEM formatted private key, as read from a file.
  81. *
  82. * This method reads the file and then calls setAuthSubPrivateKey()
  83. * with the file contents.
  84. *
  85. * @param string $file The location of the file containing the PEM key
  86. * @param string $passphrase The optional private key passphrase
  87. * @param bool $useIncludePath Whether to search the include_path
  88. * for the file
  89. * @return void
  90. */
  91. public function setAuthSubPrivateKeyFile($file, $passphrase = null,
  92. $useIncludePath = false) {
  93. $fp = @fopen($file, "r", $useIncludePath);
  94. if (!$fp) {
  95. require_once 'Zend/Gdata/App/InvalidArgumentException.php';
  96. throw new Zend_Gdata_App_InvalidArgumentException('Failed to open private key file for AuthSub.');
  97. }
  98. $key = '';
  99. while (!feof($fp)) {
  100. $key .= fread($fp, 8192);
  101. }
  102. $this->setAuthSubPrivateKey($key, $passphrase);
  103. fclose($fp);
  104. }
  105. /**
  106. * Sets the PEM formatted private key to be used for secure AuthSub auth.
  107. *
  108. * In order to call this method, openssl must be enabled in your PHP
  109. * installation. Otherwise, a Zend_Gdata_App_InvalidArgumentException
  110. * will be thrown.
  111. *
  112. * @param string $key The private key
  113. * @param string $passphrase The optional private key passphrase
  114. * @throws Zend_Gdata_App_InvalidArgumentException
  115. * @return Zend_Gdata_HttpClient Provides a fluent interface
  116. */
  117. public function setAuthSubPrivateKey($key, $passphrase = null) {
  118. if ($key != null && !function_exists('openssl_pkey_get_private')) {
  119. require_once 'Zend/Gdata/App/InvalidArgumentException.php';
  120. throw new Zend_Gdata_App_InvalidArgumentException(
  121. 'You cannot enable secure AuthSub if the openssl module ' .
  122. 'is not enabled in your PHP installation.');
  123. }
  124. $this->_authSubPrivateKeyId = openssl_pkey_get_private(
  125. $key, $passphrase);
  126. return $this;
  127. }
  128. /**
  129. * Gets the openssl private key id
  130. *
  131. * @return string The private key
  132. */
  133. public function getAuthSubPrivateKeyId() {
  134. return $this->_authSubPrivateKeyId;
  135. }
  136. /**
  137. * Gets the AuthSub token used for authentication
  138. *
  139. * @return string The token
  140. */
  141. public function getAuthSubToken() {
  142. return $this->_authSubToken;
  143. }
  144. /**
  145. * Sets the AuthSub token used for authentication
  146. *
  147. * @param string $token The token
  148. * @return Zend_Gdata_HttpClient Provides a fluent interface
  149. */
  150. public function setAuthSubToken($token) {
  151. $this->_authSubToken = $token;
  152. return $this;
  153. }
  154. /**
  155. * Gets the ClientLogin token used for authentication
  156. *
  157. * @return string The token
  158. */
  159. public function getClientLoginToken() {
  160. return $this->_clientLoginToken;
  161. }
  162. /**
  163. * Sets the ClientLogin token used for authentication
  164. *
  165. * @param string $token The token
  166. * @return Zend_Gdata_HttpClient Provides a fluent interface
  167. */
  168. public function setClientLoginToken($token) {
  169. $this->_clientLoginToken = $token;
  170. return $this;
  171. }
  172. /**
  173. * Filters the HTTP requests being sent to add the Authorization header.
  174. *
  175. * If both AuthSub and ClientLogin tokens are set,
  176. * AuthSub takes precedence. If an AuthSub key is set, then
  177. * secure AuthSub authentication is used, and the request is signed.
  178. * Requests must be signed only with the private key corresponding to the
  179. * public key registered with Google. If an AuthSub key is set, but
  180. * openssl support is not enabled in the PHP installation, an exception is
  181. * thrown.
  182. *
  183. * @param string $method The HTTP method
  184. * @param string $url The URL
  185. * @param array $headers An associate array of headers to be
  186. * sent with the request or null
  187. * @param string $body The body of the request or null
  188. * @param string $contentType The MIME content type of the body or null
  189. * @throws Zend_Gdata_App_Exception if there was a signing failure
  190. * @return array The processed values in an associative array,
  191. * using the same names as the params
  192. */
  193. public function filterHttpRequest($method, $url, $headers = array(), $body = null, $contentType = null) {
  194. if ($this->getAuthSubToken() != null) {
  195. // AuthSub authentication
  196. if ($this->getAuthSubPrivateKeyId() != null) {
  197. // secure AuthSub
  198. $time = time();
  199. $nonce = Zend_Crypt_Math::randInteger(0, 999999999);
  200. $dataToSign = $method . ' ' . $url . ' ' . $time . ' ' . $nonce;
  201. // compute signature
  202. $pKeyId = $this->getAuthSubPrivateKeyId();
  203. $signSuccess = openssl_sign($dataToSign, $signature, $pKeyId,
  204. OPENSSL_ALGO_SHA1);
  205. if (!$signSuccess) {
  206. require_once 'Zend/Gdata/App/Exception.php';
  207. throw new Zend_Gdata_App_Exception(
  208. 'openssl_signing failure - returned false');
  209. }
  210. // encode signature
  211. $encodedSignature = base64_encode($signature);
  212. // final header
  213. $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '" ' .
  214. 'data="' . $dataToSign . '" ' .
  215. 'sig="' . $encodedSignature . '" ' .
  216. 'sigalg="rsa-sha1"';
  217. } else {
  218. // AuthSub without secure tokens
  219. $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '"';
  220. }
  221. } elseif ($this->getClientLoginToken() != null) {
  222. $headers['authorization'] = 'GoogleLogin auth=' . $this->getClientLoginToken();
  223. }
  224. return array('method' => $method, 'url' => $url, 'body' => $body, 'headers' => $headers, 'contentType' => $contentType);
  225. }
  226. /**
  227. * Method for filtering the HTTP response, though no filtering is
  228. * currently done.
  229. *
  230. * @param Zend_Http_Response $response The response object to filter
  231. * @return Zend_Http_Response The filterd response object
  232. */
  233. public function filterHttpResponse($response) {
  234. return $response;
  235. }
  236. /**
  237. * Return the current connection adapter
  238. *
  239. * @return Zend_Http_Client_Adapter_Interface|string $adapter
  240. */
  241. public function getAdapter()
  242. {
  243. return $this->adapter;
  244. }
  245. /**
  246. * Load the connection adapter
  247. *
  248. * @param Zend_Http_Client_Adapter_Interface $adapter
  249. * @return void
  250. */
  251. public function setAdapter($adapter)
  252. {
  253. if ($adapter == null) {
  254. $this->adapter = $adapter;
  255. } else {
  256. parent::setAdapter($adapter);
  257. }
  258. }
  259. /**
  260. * Set the streamingRequest variable which controls whether we are
  261. * sending the raw (already encoded) POST data from a stream source.
  262. *
  263. * @param boolean $value The value to set.
  264. * @return void
  265. */
  266. public function setStreamingRequest($value)
  267. {
  268. $this->_streamingRequest = $value;
  269. }
  270. /**
  271. * Check whether the client is set to perform streaming requests.
  272. *
  273. * @return boolean True if yes, false otherwise.
  274. */
  275. public function getStreamingRequest()
  276. {
  277. if ($this->_streamingRequest()) {
  278. return true;
  279. } else {
  280. return false;
  281. }
  282. }
  283. /**
  284. * Prepare the request body (for POST and PUT requests)
  285. *
  286. * @return string
  287. * @throws Zend_Http_Client_Exception
  288. */
  289. protected function _prepareBody()
  290. {
  291. if($this->_streamingRequest) {
  292. $this->setHeaders(self::CONTENT_LENGTH,
  293. $this->raw_post_data->getTotalSize());
  294. return $this->raw_post_data;
  295. }
  296. else {
  297. return parent::_prepareBody();
  298. }
  299. }
  300. /**
  301. * Clear all custom parameters we set.
  302. *
  303. * @return Zend_Http_Client
  304. */
  305. public function resetParameters($clearAll = false)
  306. {
  307. $this->_streamingRequest = false;
  308. return parent::resetParameters($clearAll);
  309. }
  310. /**
  311. * Set the raw (already encoded) POST data from a stream source.
  312. *
  313. * This is used to support POSTing from open file handles without
  314. * caching the entire body into memory. It is a wrapper around
  315. * Zend_Http_Client::setRawData().
  316. *
  317. * @param string $data The request data
  318. * @param string $enctype The encoding type
  319. * @return Zend_Http_Client
  320. */
  321. public function setRawDataStream($data, $enctype = null)
  322. {
  323. $this->_streamingRequest = true;
  324. return $this->setRawData($data, $enctype);
  325. }
  326. }