353 lines
11 KiB
PHP
353 lines
11 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Zend Framework
|
||
|
*
|
||
|
* LICENSE
|
||
|
*
|
||
|
* This source file is subject to the new BSD license that is bundled
|
||
|
* with this package in the file LICENSE.txt.
|
||
|
* It is also available through the world-wide-web at this URL:
|
||
|
* http://framework.zend.com/license/new-bsd
|
||
|
* If you did not receive a copy of the license and are unable to
|
||
|
* obtain it through the world-wide-web, please send an email
|
||
|
* to license@zend.com so we can send you a copy immediately.
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Gdata
|
||
|
* @subpackage Gdata
|
||
|
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
* @version $Id: HttpClient.php 24593 2012-01-05 20:35:02Z matthew $
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Zend_Http_Client
|
||
|
*/
|
||
|
require_once 'Zend/Http/Client.php';
|
||
|
|
||
|
/**
|
||
|
* Gdata Http Client object.
|
||
|
*
|
||
|
* Class to extend the generic Zend Http Client with the ability to perform
|
||
|
* secure AuthSub requests
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Gdata
|
||
|
* @subpackage Gdata
|
||
|
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
*/
|
||
|
class Zend_Gdata_HttpClient extends Zend_Http_Client
|
||
|
{
|
||
|
|
||
|
/**
|
||
|
* OpenSSL private key resource id
|
||
|
* This key is used for AuthSub authentication. If this value is set,
|
||
|
* it is assuemd that secure AuthSub is desired.
|
||
|
*
|
||
|
* @var resource
|
||
|
*/
|
||
|
private $_authSubPrivateKeyId = null;
|
||
|
|
||
|
/**
|
||
|
* Token for AuthSub authentication.
|
||
|
* If this token is set, AuthSub authentication is used.
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_authSubToken = null;
|
||
|
|
||
|
/**
|
||
|
* Token for ClientLogin authentication.
|
||
|
* If only this token is set, ClientLogin authentication is used.
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_clientLoginToken = null;
|
||
|
|
||
|
/**
|
||
|
* Token for ClientLogin authentication.
|
||
|
* If this token is set, and the AuthSub key is not set,
|
||
|
* ClientLogin authentication is used
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_clientLoginKey = null;
|
||
|
|
||
|
/**
|
||
|
* True if this request is being made with data supplied by
|
||
|
* a stream object instead of a raw encoded string.
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
protected $_streamingRequest = null;
|
||
|
|
||
|
/**
|
||
|
* Sets the PEM formatted private key, as read from a file.
|
||
|
*
|
||
|
* This method reads the file and then calls setAuthSubPrivateKey()
|
||
|
* with the file contents.
|
||
|
*
|
||
|
* @param string $file The location of the file containing the PEM key
|
||
|
* @param string $passphrase The optional private key passphrase
|
||
|
* @param bool $useIncludePath Whether to search the include_path
|
||
|
* for the file
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setAuthSubPrivateKeyFile($file, $passphrase = null,
|
||
|
$useIncludePath = false) {
|
||
|
$fp = @fopen($file, "r", $useIncludePath);
|
||
|
if (!$fp) {
|
||
|
require_once 'Zend/Gdata/App/InvalidArgumentException.php';
|
||
|
throw new Zend_Gdata_App_InvalidArgumentException('Failed to open private key file for AuthSub.');
|
||
|
}
|
||
|
|
||
|
$key = '';
|
||
|
while (!feof($fp)) {
|
||
|
$key .= fread($fp, 8192);
|
||
|
}
|
||
|
$this->setAuthSubPrivateKey($key, $passphrase);
|
||
|
fclose($fp);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the PEM formatted private key to be used for secure AuthSub auth.
|
||
|
*
|
||
|
* In order to call this method, openssl must be enabled in your PHP
|
||
|
* installation. Otherwise, a Zend_Gdata_App_InvalidArgumentException
|
||
|
* will be thrown.
|
||
|
*
|
||
|
* @param string $key The private key
|
||
|
* @param string $passphrase The optional private key passphrase
|
||
|
* @throws Zend_Gdata_App_InvalidArgumentException
|
||
|
* @return Zend_Gdata_HttpClient Provides a fluent interface
|
||
|
*/
|
||
|
public function setAuthSubPrivateKey($key, $passphrase = null) {
|
||
|
if ($key != null && !function_exists('openssl_pkey_get_private')) {
|
||
|
require_once 'Zend/Gdata/App/InvalidArgumentException.php';
|
||
|
throw new Zend_Gdata_App_InvalidArgumentException(
|
||
|
'You cannot enable secure AuthSub if the openssl module ' .
|
||
|
'is not enabled in your PHP installation.');
|
||
|
}
|
||
|
$this->_authSubPrivateKeyId = openssl_pkey_get_private(
|
||
|
$key, $passphrase);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the openssl private key id
|
||
|
*
|
||
|
* @return string The private key
|
||
|
*/
|
||
|
public function getAuthSubPrivateKeyId() {
|
||
|
return $this->_authSubPrivateKeyId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the AuthSub token used for authentication
|
||
|
*
|
||
|
* @return string The token
|
||
|
*/
|
||
|
public function getAuthSubToken() {
|
||
|
return $this->_authSubToken;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the AuthSub token used for authentication
|
||
|
*
|
||
|
* @param string $token The token
|
||
|
* @return Zend_Gdata_HttpClient Provides a fluent interface
|
||
|
*/
|
||
|
public function setAuthSubToken($token) {
|
||
|
$this->_authSubToken = $token;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the ClientLogin token used for authentication
|
||
|
*
|
||
|
* @return string The token
|
||
|
*/
|
||
|
public function getClientLoginToken() {
|
||
|
return $this->_clientLoginToken;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the ClientLogin token used for authentication
|
||
|
*
|
||
|
* @param string $token The token
|
||
|
* @return Zend_Gdata_HttpClient Provides a fluent interface
|
||
|
*/
|
||
|
public function setClientLoginToken($token) {
|
||
|
$this->_clientLoginToken = $token;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Filters the HTTP requests being sent to add the Authorization header.
|
||
|
*
|
||
|
* If both AuthSub and ClientLogin tokens are set,
|
||
|
* AuthSub takes precedence. If an AuthSub key is set, then
|
||
|
* secure AuthSub authentication is used, and the request is signed.
|
||
|
* Requests must be signed only with the private key corresponding to the
|
||
|
* public key registered with Google. If an AuthSub key is set, but
|
||
|
* openssl support is not enabled in the PHP installation, an exception is
|
||
|
* thrown.
|
||
|
*
|
||
|
* @param string $method The HTTP method
|
||
|
* @param string $url The URL
|
||
|
* @param array $headers An associate array of headers to be
|
||
|
* sent with the request or null
|
||
|
* @param string $body The body of the request or null
|
||
|
* @param string $contentType The MIME content type of the body or null
|
||
|
* @throws Zend_Gdata_App_Exception if there was a signing failure
|
||
|
* @return array The processed values in an associative array,
|
||
|
* using the same names as the params
|
||
|
*/
|
||
|
public function filterHttpRequest($method, $url, $headers = array(), $body = null, $contentType = null) {
|
||
|
if ($this->getAuthSubToken() != null) {
|
||
|
// AuthSub authentication
|
||
|
if ($this->getAuthSubPrivateKeyId() != null) {
|
||
|
// secure AuthSub
|
||
|
$time = time();
|
||
|
$nonce = mt_rand(0, 999999999);
|
||
|
$dataToSign = $method . ' ' . $url . ' ' . $time . ' ' . $nonce;
|
||
|
|
||
|
// compute signature
|
||
|
$pKeyId = $this->getAuthSubPrivateKeyId();
|
||
|
$signSuccess = openssl_sign($dataToSign, $signature, $pKeyId,
|
||
|
OPENSSL_ALGO_SHA1);
|
||
|
if (!$signSuccess) {
|
||
|
require_once 'Zend/Gdata/App/Exception.php';
|
||
|
throw new Zend_Gdata_App_Exception(
|
||
|
'openssl_signing failure - returned false');
|
||
|
}
|
||
|
// encode signature
|
||
|
$encodedSignature = base64_encode($signature);
|
||
|
|
||
|
// final header
|
||
|
$headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '" ' .
|
||
|
'data="' . $dataToSign . '" ' .
|
||
|
'sig="' . $encodedSignature . '" ' .
|
||
|
'sigalg="rsa-sha1"';
|
||
|
} else {
|
||
|
// AuthSub without secure tokens
|
||
|
$headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '"';
|
||
|
}
|
||
|
} elseif ($this->getClientLoginToken() != null) {
|
||
|
$headers['authorization'] = 'GoogleLogin auth=' . $this->getClientLoginToken();
|
||
|
}
|
||
|
return array('method' => $method, 'url' => $url, 'body' => $body, 'headers' => $headers, 'contentType' => $contentType);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method for filtering the HTTP response, though no filtering is
|
||
|
* currently done.
|
||
|
*
|
||
|
* @param Zend_Http_Response $response The response object to filter
|
||
|
* @return Zend_Http_Response The filterd response object
|
||
|
*/
|
||
|
public function filterHttpResponse($response) {
|
||
|
return $response;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the current connection adapter
|
||
|
*
|
||
|
* @return Zend_Http_Client_Adapter_Interface|string $adapter
|
||
|
*/
|
||
|
public function getAdapter()
|
||
|
{
|
||
|
return $this->adapter;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load the connection adapter
|
||
|
*
|
||
|
* @param Zend_Http_Client_Adapter_Interface $adapter
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setAdapter($adapter)
|
||
|
{
|
||
|
if ($adapter == null) {
|
||
|
$this->adapter = $adapter;
|
||
|
} else {
|
||
|
parent::setAdapter($adapter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the streamingRequest variable which controls whether we are
|
||
|
* sending the raw (already encoded) POST data from a stream source.
|
||
|
*
|
||
|
* @param boolean $value The value to set.
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setStreamingRequest($value)
|
||
|
{
|
||
|
$this->_streamingRequest = $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check whether the client is set to perform streaming requests.
|
||
|
*
|
||
|
* @return boolean True if yes, false otherwise.
|
||
|
*/
|
||
|
public function getStreamingRequest()
|
||
|
{
|
||
|
if ($this->_streamingRequest()) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Prepare the request body (for POST and PUT requests)
|
||
|
*
|
||
|
* @return string
|
||
|
* @throws Zend_Http_Client_Exception
|
||
|
*/
|
||
|
protected function _prepareBody()
|
||
|
{
|
||
|
if($this->_streamingRequest) {
|
||
|
$this->setHeaders(self::CONTENT_LENGTH,
|
||
|
$this->raw_post_data->getTotalSize());
|
||
|
return $this->raw_post_data;
|
||
|
}
|
||
|
else {
|
||
|
return parent::_prepareBody();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear all custom parameters we set.
|
||
|
*
|
||
|
* @return Zend_Http_Client
|
||
|
*/
|
||
|
public function resetParameters($clearAll = false)
|
||
|
{
|
||
|
$this->_streamingRequest = false;
|
||
|
|
||
|
return parent::resetParameters($clearAll);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the raw (already encoded) POST data from a stream source.
|
||
|
*
|
||
|
* This is used to support POSTing from open file handles without
|
||
|
* caching the entire body into memory. It is a wrapper around
|
||
|
* Zend_Http_Client::setRawData().
|
||
|
*
|
||
|
* @param string $data The request data
|
||
|
* @param string $enctype The encoding type
|
||
|
* @return Zend_Http_Client
|
||
|
*/
|
||
|
public function setRawDataStream($data, $enctype = null)
|
||
|
{
|
||
|
$this->_streamingRequest = true;
|
||
|
return $this->setRawData($data, $enctype);
|
||
|
}
|
||
|
|
||
|
}
|