HttpClient.php 11 KB

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