mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Migrate RainLoop Webmail to use Facebook Graph API instead of FQL
This commit is contained in:
parent
9fcaf00875
commit
d0dbb26548
120 changed files with 18817 additions and 1746 deletions
|
|
@ -6,19 +6,20 @@
|
||||||
function AdminSocial()
|
function AdminSocial()
|
||||||
{
|
{
|
||||||
var oData = RL.data();
|
var oData = RL.data();
|
||||||
|
|
||||||
this.googleEnable = oData.googleEnable;
|
this.googleEnable = oData.googleEnable;
|
||||||
this.googleClientID = oData.googleClientID;
|
this.googleClientID = oData.googleClientID;
|
||||||
this.googleClientSecret = oData.googleClientSecret;
|
this.googleClientSecret = oData.googleClientSecret;
|
||||||
this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
|
||||||
|
this.facebookSupported = oData.facebookSupported;
|
||||||
this.facebookEnable = oData.facebookEnable;
|
this.facebookEnable = oData.facebookEnable;
|
||||||
this.facebookAppID = oData.facebookAppID;
|
this.facebookAppID = oData.facebookAppID;
|
||||||
this.facebookAppSecret = oData.facebookAppSecret;
|
this.facebookAppSecret = oData.facebookAppSecret;
|
||||||
this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
|
||||||
this.twitterEnable = oData.twitterEnable;
|
this.twitterEnable = oData.twitterEnable;
|
||||||
this.twitterConsumerKey = oData.twitterConsumerKey;
|
this.twitterConsumerKey = oData.twitterConsumerKey;
|
||||||
this.twitterConsumerSecret = oData.twitterConsumerSecret;
|
this.twitterConsumerSecret = oData.twitterConsumerSecret;
|
||||||
|
|
@ -48,21 +49,30 @@ AdminSocial.prototype.onBuild = function ()
|
||||||
;
|
;
|
||||||
|
|
||||||
self.facebookEnable.subscribe(function (bValue) {
|
self.facebookEnable.subscribe(function (bValue) {
|
||||||
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
if (self.facebookSupported())
|
||||||
'FacebookEnable': bValue ? '1' : '0'
|
{
|
||||||
});
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'FacebookEnable': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.facebookAppID.subscribe(function (sValue) {
|
self.facebookAppID.subscribe(function (sValue) {
|
||||||
RL.remote().saveAdminConfig(f1, {
|
if (self.facebookSupported())
|
||||||
'FacebookAppID': Utils.trim(sValue)
|
{
|
||||||
});
|
RL.remote().saveAdminConfig(f1, {
|
||||||
|
'FacebookAppID': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.facebookAppSecret.subscribe(function (sValue) {
|
self.facebookAppSecret.subscribe(function (sValue) {
|
||||||
RL.remote().saveAdminConfig(f2, {
|
if (self.facebookSupported())
|
||||||
'FacebookAppSecret': Utils.trim(sValue)
|
{
|
||||||
});
|
RL.remote().saveAdminConfig(f2, {
|
||||||
|
'FacebookAppSecret': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.twitterEnable.subscribe(function (bValue) {
|
self.twitterEnable.subscribe(function (bValue) {
|
||||||
|
|
@ -82,7 +92,7 @@ AdminSocial.prototype.onBuild = function ()
|
||||||
'TwitterConsumerSecret': Utils.trim(sValue)
|
'TwitterConsumerSecret': Utils.trim(sValue)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
self.googleEnable.subscribe(function (bValue) {
|
self.googleEnable.subscribe(function (bValue) {
|
||||||
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
'GoogleEnable': bValue ? '1' : '0'
|
'GoogleEnable': bValue ? '1' : '0'
|
||||||
|
|
@ -100,7 +110,7 @@ AdminSocial.prototype.onBuild = function ()
|
||||||
'GoogleClientSecret': Utils.trim(sValue)
|
'GoogleClientSecret': Utils.trim(sValue)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
self.dropboxEnable.subscribe(function (bValue) {
|
self.dropboxEnable.subscribe(function (bValue) {
|
||||||
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
'DropboxEnable': bValue ? '1' : '0'
|
'DropboxEnable': bValue ? '1' : '0'
|
||||||
|
|
|
||||||
|
|
@ -777,7 +777,7 @@ Utils.initDataConstructorBySettings = function (oData)
|
||||||
oData.capaThemes = ko.observable(false);
|
oData.capaThemes = ko.observable(false);
|
||||||
oData.allowLanguagesOnSettings = ko.observable(true);
|
oData.allowLanguagesOnSettings = ko.observable(true);
|
||||||
oData.allowLanguagesOnLogin = ko.observable(true);
|
oData.allowLanguagesOnLogin = ko.observable(true);
|
||||||
|
|
||||||
oData.useLocalProxyForExternalImages = ko.observable(false);
|
oData.useLocalProxyForExternalImages = ko.observable(false);
|
||||||
|
|
||||||
oData.desktopNotifications = ko.observable(false);
|
oData.desktopNotifications = ko.observable(false);
|
||||||
|
|
@ -968,6 +968,7 @@ Utils.initDataConstructorBySettings = function (oData)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
oData.facebookSupported = ko.observable(false);
|
||||||
oData.facebookEnable = ko.observable(false);
|
oData.facebookEnable = ko.observable(false);
|
||||||
oData.facebookAppID = ko.observable('');
|
oData.facebookAppID = ko.observable('');
|
||||||
oData.facebookAppSecret = ko.observable('');
|
oData.facebookAppSecret = ko.observable('');
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ AbstractData.prototype.populateDataOnStart = function()
|
||||||
{
|
{
|
||||||
this.layout(mLayout);
|
this.layout(mLayout);
|
||||||
}
|
}
|
||||||
|
this.facebookSupported(!!RL.settingsGet('SupportedFacebookSocial'));
|
||||||
this.facebookEnable(!!RL.settingsGet('AllowFacebookSocial'));
|
this.facebookEnable(!!RL.settingsGet('AllowFacebookSocial'));
|
||||||
this.facebookAppID(RL.settingsGet('FacebookAppID'));
|
this.facebookAppID(RL.settingsGet('FacebookAppID'));
|
||||||
this.facebookAppSecret(RL.settingsGet('FacebookAppSecret'));
|
this.facebookAppSecret(RL.settingsGet('FacebookAppSecret'));
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,14 @@ if (!\defined('RAINLOOP_APP_LIBRARIES_PATH'))
|
||||||
{
|
{
|
||||||
return include RAINLOOP_APP_LIBRARIES_PATH.'RainLoop/'.\str_replace('\\', '/', \substr($sClassName, 9)).'.php';
|
return include RAINLOOP_APP_LIBRARIES_PATH.'RainLoop/'.\str_replace('\\', '/', \substr($sClassName, 9)).'.php';
|
||||||
}
|
}
|
||||||
|
else if (0 === \strpos($sClassName, 'Facebook') && false !== \strpos($sClassName, '\\'))
|
||||||
|
{
|
||||||
|
return include RAINLOOP_APP_LIBRARIES_PATH.'Facebook/'.\str_replace('\\', '/', \substr($sClassName, 9)).'.php';
|
||||||
|
}
|
||||||
|
else if (0 === \strpos($sClassName, 'GuzzleHttp') && false !== \strpos($sClassName, '\\'))
|
||||||
|
{
|
||||||
|
return include RAINLOOP_APP_LIBRARIES_PATH.'GuzzleHttp/'.\str_replace('\\', '/', \substr($sClassName, 11)).'.php';
|
||||||
|
}
|
||||||
else if (0 === \strpos($sClassName, 'Sabre') && false !== \strpos($sClassName, '\\'))
|
else if (0 === \strpos($sClassName, 'Sabre') && false !== \strpos($sClassName, '\\'))
|
||||||
{
|
{
|
||||||
if (!RAINLOOP_MB_SUPPORTED && !defined('RL_MB_FIXED'))
|
if (!RAINLOOP_MB_SUPPORTED && !defined('RL_MB_FIXED'))
|
||||||
|
|
|
||||||
370
rainloop/v/0.0.0/app/libraries/Facebook/Entities/AccessToken.php
Normal file
370
rainloop/v/0.0.0/app/libraries/Facebook/Entities/AccessToken.php
Normal file
|
|
@ -0,0 +1,370 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\Entities;
|
||||||
|
|
||||||
|
use Facebook\FacebookRequest;
|
||||||
|
use Facebook\FacebookRequestException;
|
||||||
|
use Facebook\FacebookSession;
|
||||||
|
use Facebook\GraphSessionInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AccessToken
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class AccessToken
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The access token.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique ID to identify a client.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $machineId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date when token expires.
|
||||||
|
*
|
||||||
|
* @var \DateTime|null
|
||||||
|
*/
|
||||||
|
protected $expiresAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new access token entity.
|
||||||
|
*
|
||||||
|
* @param string $accessToken
|
||||||
|
* @param int $expiresAt
|
||||||
|
* @param string|null machineId
|
||||||
|
*/
|
||||||
|
public function __construct($accessToken, $expiresAt = 0, $machineId = null)
|
||||||
|
{
|
||||||
|
$this->accessToken = $accessToken;
|
||||||
|
if ($expiresAt) {
|
||||||
|
$this->setExpiresAtFromTimeStamp($expiresAt);
|
||||||
|
}
|
||||||
|
$this->machineId = $machineId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for expires_at.
|
||||||
|
*
|
||||||
|
* @param int $timeStamp
|
||||||
|
*/
|
||||||
|
protected function setExpiresAtFromTimeStamp($timeStamp)
|
||||||
|
{
|
||||||
|
$dt = new \DateTime();
|
||||||
|
$dt->setTimestamp($timeStamp);
|
||||||
|
$this->expiresAt = $dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for expiresAt.
|
||||||
|
*
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getExpiresAt()
|
||||||
|
{
|
||||||
|
return $this->expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for machineId.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getMachineId()
|
||||||
|
{
|
||||||
|
return $this->machineId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not this is a long-lived token.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isLongLived()
|
||||||
|
{
|
||||||
|
if ($this->expiresAt) {
|
||||||
|
return $this->expiresAt->getTimestamp() > time() + (60 * 60 * 2);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the validity of the access token.
|
||||||
|
*
|
||||||
|
* @param string|null $appId Application ID to use
|
||||||
|
* @param string|null $appSecret App secret value to use
|
||||||
|
* @param string|null $machineId
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isValid($appId = null, $appSecret = null, $machineId = null)
|
||||||
|
{
|
||||||
|
$accessTokenInfo = $this->getInfo($appId, $appSecret);
|
||||||
|
$machineId = $machineId ?: $this->machineId;
|
||||||
|
return static::validateAccessToken($accessTokenInfo, $appId, $machineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the provided GraphSessionInfo object is valid,
|
||||||
|
* throwing an exception if not. Ensures the appId matches,
|
||||||
|
* that the machineId matches if it's being used,
|
||||||
|
* that the token is valid and has not expired.
|
||||||
|
*
|
||||||
|
* @param GraphSessionInfo $tokenInfo
|
||||||
|
* @param string|null $appId Application ID to use
|
||||||
|
* @param string|null $machineId
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function validateAccessToken(GraphSessionInfo $tokenInfo,
|
||||||
|
$appId = null, $machineId = null)
|
||||||
|
{
|
||||||
|
$targetAppId = FacebookSession::_getTargetAppId($appId);
|
||||||
|
|
||||||
|
$appIdIsValid = $tokenInfo->getAppId() == $targetAppId;
|
||||||
|
$machineIdIsValid = $tokenInfo->getProperty('machine_id') == $machineId;
|
||||||
|
$accessTokenIsValid = $tokenInfo->isValid();
|
||||||
|
|
||||||
|
// Not all access tokens return an expiration. E.g. an app access token.
|
||||||
|
if ($tokenInfo->getExpiresAt() instanceof \DateTime) {
|
||||||
|
$accessTokenIsStillAlive = $tokenInfo->getExpiresAt()->getTimestamp() >= time();
|
||||||
|
} else {
|
||||||
|
$accessTokenIsStillAlive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $appIdIsValid && $machineIdIsValid && $accessTokenIsValid && $accessTokenIsStillAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a valid access token from a code.
|
||||||
|
*
|
||||||
|
* @param string $code
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
* @param string|null $machineId
|
||||||
|
*
|
||||||
|
* @return AccessToken
|
||||||
|
*/
|
||||||
|
public static function getAccessTokenFromCode($code, $appId = null, $appSecret = null, $machineId = null)
|
||||||
|
{
|
||||||
|
$params = array(
|
||||||
|
'code' => $code,
|
||||||
|
'redirect_uri' => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($machineId) {
|
||||||
|
$params['machine_id'] = $machineId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::requestAccessToken($params, $appId, $appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a valid code from an access token.
|
||||||
|
*
|
||||||
|
* @param AccessToken|string $accessToken
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return AccessToken
|
||||||
|
*/
|
||||||
|
public static function getCodeFromAccessToken($accessToken, $appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$accessToken = (string) $accessToken;
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'access_token' => $accessToken,
|
||||||
|
'redirect_uri' => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
return static::requestCode($params, $appId, $appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchanges a short lived access token with a long lived access token.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return AccessToken
|
||||||
|
*/
|
||||||
|
public function extend($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$params = array(
|
||||||
|
'grant_type' => 'fb_exchange_token',
|
||||||
|
'fb_exchange_token' => $this->accessToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
return static::requestAccessToken($params, $appId, $appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request an access token based on a set of params.
|
||||||
|
*
|
||||||
|
* @param array $params
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return AccessToken
|
||||||
|
*
|
||||||
|
* @throws FacebookRequestException
|
||||||
|
*/
|
||||||
|
public static function requestAccessToken(array $params, $appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$response = static::request('/oauth/access_token', $params, $appId, $appSecret);
|
||||||
|
$data = $response->getResponse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO fix this malarkey - getResponse() should always return an object
|
||||||
|
* @see https://github.com/facebook/facebook-php-sdk-v4/issues/36
|
||||||
|
*/
|
||||||
|
if (is_array($data)) {
|
||||||
|
if (isset($data['access_token'])) {
|
||||||
|
$expiresAt = isset($data['expires']) ? time() + $data['expires'] : 0;
|
||||||
|
return new static($data['access_token'], $expiresAt);
|
||||||
|
}
|
||||||
|
} elseif($data instanceof \stdClass) {
|
||||||
|
if (isset($data->access_token)) {
|
||||||
|
$expiresAt = isset($data->expires_in) ? time() + $data->expires_in : 0;
|
||||||
|
$machineId = isset($data->machine_id) ? (string) $data->machine_id : null;
|
||||||
|
return new static((string) $data->access_token, $expiresAt, $machineId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FacebookRequestException::create(
|
||||||
|
$response->getRawResponse(),
|
||||||
|
$data,
|
||||||
|
401
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a code from a long lived access token.
|
||||||
|
*
|
||||||
|
* @param array $params
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws FacebookRequestException
|
||||||
|
*/
|
||||||
|
public static function requestCode(array $params, $appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$response = static::request('/oauth/client_code', $params, $appId, $appSecret);
|
||||||
|
$data = $response->getResponse();
|
||||||
|
|
||||||
|
if (isset($data->code)) {
|
||||||
|
return (string) $data->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FacebookRequestException::create(
|
||||||
|
$response->getRawResponse(),
|
||||||
|
$data,
|
||||||
|
401
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a request to Graph with an app access token.
|
||||||
|
*
|
||||||
|
* @param string $endpoint
|
||||||
|
* @param array $params
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return \Facebook\FacebookResponse
|
||||||
|
*
|
||||||
|
* @throws FacebookRequestException
|
||||||
|
*/
|
||||||
|
protected static function request($endpoint, array $params, $appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$targetAppId = FacebookSession::_getTargetAppId($appId);
|
||||||
|
$targetAppSecret = FacebookSession::_getTargetAppSecret($appSecret);
|
||||||
|
|
||||||
|
if (!isset($params['client_id'])) {
|
||||||
|
$params['client_id'] = $targetAppId;
|
||||||
|
}
|
||||||
|
if (!isset($params['client_secret'])) {
|
||||||
|
$params['client_secret'] = $targetAppSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The response for this endpoint is not JSON, so it must be handled
|
||||||
|
// differently, not as a GraphObject.
|
||||||
|
$request = new FacebookRequest(
|
||||||
|
FacebookSession::newAppSession($targetAppId, $targetAppSecret),
|
||||||
|
'GET',
|
||||||
|
$endpoint,
|
||||||
|
$params
|
||||||
|
);
|
||||||
|
return $request->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get more info about an access token.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return GraphSessionInfo
|
||||||
|
*/
|
||||||
|
public function getInfo($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$params = array('input_token' => $this->accessToken);
|
||||||
|
|
||||||
|
$request = new FacebookRequest(
|
||||||
|
FacebookSession::newAppSession($appId, $appSecret),
|
||||||
|
'GET',
|
||||||
|
'/debug_token',
|
||||||
|
$params
|
||||||
|
);
|
||||||
|
$response = $request->execute()->getGraphObject(GraphSessionInfo::className());
|
||||||
|
|
||||||
|
// Update the data on this token
|
||||||
|
if ($response->getExpiresAt()) {
|
||||||
|
$this->expiresAt = $response->getExpiresAt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the access token as a string.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,386 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\Entities;
|
||||||
|
|
||||||
|
use Facebook\FacebookSDKException;
|
||||||
|
use Facebook\FacebookSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SignedRequest
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class SignedRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $rawSignedRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a new SignedRequest entity.
|
||||||
|
*
|
||||||
|
* @param string|null $rawSignedRequest The raw signed request.
|
||||||
|
* @param string|null $state random string to prevent CSRF.
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*/
|
||||||
|
public function __construct($rawSignedRequest = null, $state = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
if (!$rawSignedRequest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rawSignedRequest = $rawSignedRequest;
|
||||||
|
$this->payload = static::parse($rawSignedRequest, $state, $appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw signed request data.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRawSignedRequest()
|
||||||
|
{
|
||||||
|
return $this->rawSignedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parsed signed request data.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getPayload()
|
||||||
|
{
|
||||||
|
return $this->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a property from the signed request data if available.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed|null $default
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function get($key, $default = null)
|
||||||
|
{
|
||||||
|
if (isset($this->payload[$key])) {
|
||||||
|
return $this->payload[$key];
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns user_id from signed request data if available.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->get('user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for OAuth data in the payload.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function hasOAuthData()
|
||||||
|
{
|
||||||
|
return isset($this->payload['oauth_token']) || isset($this->payload['code']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a signed request from an array of data.
|
||||||
|
*
|
||||||
|
* @param array $payload
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function make(array $payload, $appSecret = null)
|
||||||
|
{
|
||||||
|
$payload['algorithm'] = 'HMAC-SHA256';
|
||||||
|
$payload['issued_at'] = time();
|
||||||
|
$encodedPayload = static::base64UrlEncode(json_encode($payload));
|
||||||
|
|
||||||
|
$hashedSig = static::hashSignature($encodedPayload, $appSecret);
|
||||||
|
$encodedSig = static::base64UrlEncode($hashedSig);
|
||||||
|
|
||||||
|
return $encodedSig.'.'.$encodedPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates and decodes a signed request and returns
|
||||||
|
* the payload as an array.
|
||||||
|
*
|
||||||
|
* @param string $signedRequest
|
||||||
|
* @param string|null $state
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function parse($signedRequest, $state = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
list($encodedSig, $encodedPayload) = static::split($signedRequest);
|
||||||
|
|
||||||
|
// Signature validation
|
||||||
|
$sig = static::decodeSignature($encodedSig);
|
||||||
|
$hashedSig = static::hashSignature($encodedPayload, $appSecret);
|
||||||
|
static::validateSignature($hashedSig, $sig);
|
||||||
|
|
||||||
|
// Payload validation
|
||||||
|
$data = static::decodePayload($encodedPayload);
|
||||||
|
static::validateAlgorithm($data);
|
||||||
|
if ($state) {
|
||||||
|
static::validateCsrf($data, $state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the format of a signed request.
|
||||||
|
*
|
||||||
|
* @param string $signedRequest
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function validateFormat($signedRequest)
|
||||||
|
{
|
||||||
|
if (strpos($signedRequest, '.') !== false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Malformed signed request.', 606
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a raw valid signed request.
|
||||||
|
*
|
||||||
|
* @param string $signedRequest
|
||||||
|
*
|
||||||
|
* @returns array
|
||||||
|
*/
|
||||||
|
public static function split($signedRequest)
|
||||||
|
{
|
||||||
|
static::validateFormat($signedRequest);
|
||||||
|
|
||||||
|
return explode('.', $signedRequest, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the raw signature from a signed request.
|
||||||
|
*
|
||||||
|
* @param string $encodedSig
|
||||||
|
*
|
||||||
|
* @returns string
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function decodeSignature($encodedSig)
|
||||||
|
{
|
||||||
|
$sig = static::base64UrlDecode($encodedSig);
|
||||||
|
|
||||||
|
if ($sig) {
|
||||||
|
return $sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Signed request has malformed encoded signature data.', 607
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the raw payload from a signed request.
|
||||||
|
*
|
||||||
|
* @param string $encodedPayload
|
||||||
|
*
|
||||||
|
* @returns array
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function decodePayload($encodedPayload)
|
||||||
|
{
|
||||||
|
$payload = static::base64UrlDecode($encodedPayload);
|
||||||
|
|
||||||
|
if ($payload) {
|
||||||
|
$payload = json_decode($payload, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($payload)) {
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Signed request has malformed encoded payload data.', 607
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the algorithm used in a signed request.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function validateAlgorithm(array $data)
|
||||||
|
{
|
||||||
|
if (isset($data['algorithm']) && $data['algorithm'] === 'HMAC-SHA256') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Signed request is using the wrong algorithm.', 605
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashes the signature used in a signed request.
|
||||||
|
*
|
||||||
|
* @param string $encodedData
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function hashSignature($encodedData, $appSecret = null)
|
||||||
|
{
|
||||||
|
$hashedSig = hash_hmac(
|
||||||
|
'sha256', $encodedData, FacebookSession::_getTargetAppSecret($appSecret), $raw_output = true
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($hashedSig) {
|
||||||
|
return $hashedSig;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Unable to hash signature from encoded payload data.', 602
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the signature used in a signed request.
|
||||||
|
*
|
||||||
|
* @param string $hashedSig
|
||||||
|
* @param string $sig
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function validateSignature($hashedSig, $sig)
|
||||||
|
{
|
||||||
|
if (mb_strlen($hashedSig) === mb_strlen($sig)) {
|
||||||
|
$validate = 0;
|
||||||
|
for ($i = 0; $i < mb_strlen($sig); $i++) {
|
||||||
|
$validate |= ord($hashedSig[$i]) ^ ord($sig[$i]);
|
||||||
|
}
|
||||||
|
if ($validate === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Signed request has an invalid signature.', 602
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a signed request against CSRF.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @param string $state
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function validateCsrf(array $data, $state)
|
||||||
|
{
|
||||||
|
if (isset($data['state']) && $data['state'] === $state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Signed request did not pass CSRF validation.', 604
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64 decoding which replaces characters:
|
||||||
|
* + instead of -
|
||||||
|
* / instead of _
|
||||||
|
* @link http://en.wikipedia.org/wiki/Base64#URL_applications
|
||||||
|
*
|
||||||
|
* @param string $input base64 url encoded input
|
||||||
|
*
|
||||||
|
* @return string decoded string
|
||||||
|
*/
|
||||||
|
public static function base64UrlDecode($input)
|
||||||
|
{
|
||||||
|
$urlDecodedBase64 = strtr($input, '-_', '+/');
|
||||||
|
static::validateBase64($urlDecodedBase64);
|
||||||
|
return base64_decode($urlDecodedBase64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64 encoding which replaces characters:
|
||||||
|
* + instead of -
|
||||||
|
* / instead of _
|
||||||
|
* @link http://en.wikipedia.org/wiki/Base64#URL_applications
|
||||||
|
*
|
||||||
|
* @param string $input string to encode
|
||||||
|
*
|
||||||
|
* @return string base64 url encoded input
|
||||||
|
*/
|
||||||
|
public static function base64UrlEncode($input)
|
||||||
|
{
|
||||||
|
return strtr(base64_encode($input), '+/', '-_');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a base64 string.
|
||||||
|
*
|
||||||
|
* @param string $input base64 value to validate
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function validateBase64($input)
|
||||||
|
{
|
||||||
|
$pattern = '/^[a-zA-Z0-9\/\r\n+]*={0,2}$/';
|
||||||
|
if (preg_match($pattern, $input)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Signed request contains malformed base64 encoding.', 608
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookAuthorizationException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookAuthorizationException extends FacebookRequestException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookCanvasLoginHelper
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookCanvasLoginHelper extends FacebookSignedRequestFromInputHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the app data value.
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function getAppData()
|
||||||
|
{
|
||||||
|
return $this->signedRequest ? $this->signedRequest->get('app_data') : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw signed request from either GET or POST.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRawSignedRequest()
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* v2.0 apps use GET for Canvas signed requests.
|
||||||
|
*/
|
||||||
|
$rawSignedRequest = $this->getRawSignedRequestFromGet();
|
||||||
|
if ($rawSignedRequest) {
|
||||||
|
return $rawSignedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v1.0 apps use POST for Canvas signed requests, will eventually be
|
||||||
|
* deprecated.
|
||||||
|
*/
|
||||||
|
$rawSignedRequest = $this->getRawSignedRequestFromPost();
|
||||||
|
if ($rawSignedRequest) {
|
||||||
|
return $rawSignedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookClientException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookClientException extends FacebookRequestException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookJavaScriptLoginHelper
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookJavaScriptLoginHelper extends FacebookSignedRequestFromInputHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw signed request from the cookie.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRawSignedRequest()
|
||||||
|
{
|
||||||
|
return $this->getRawSignedRequestFromCookie();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookOtherException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookOtherException extends FacebookRequestException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookPageTabHelper
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookPageTabHelper extends FacebookCanvasLoginHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
protected $pageData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the helper and process available signed request data.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*/
|
||||||
|
public function __construct($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
parent::__construct($appId, $appSecret);
|
||||||
|
|
||||||
|
if (!$this->signedRequest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->pageData = $this->signedRequest->get('page');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value from the page data.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed|null $default
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function getPageData($key, $default = null)
|
||||||
|
{
|
||||||
|
if (isset($this->pageData[$key])) {
|
||||||
|
return $this->pageData[$key];
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the page is liked by the user.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isLiked()
|
||||||
|
{
|
||||||
|
return $this->getPageData('liked') === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the user is an admin.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isAdmin()
|
||||||
|
{
|
||||||
|
return $this->getPageData('admin') === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the page id if available.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getPageId()
|
||||||
|
{
|
||||||
|
return $this->getPageData('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookPermissionException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookPermissionException extends FacebookRequestException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,277 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookRedirectLoginHelper
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookRedirectLoginHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The application id
|
||||||
|
*/
|
||||||
|
private $appId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The application secret
|
||||||
|
*/
|
||||||
|
private $appSecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The redirect URL for the application
|
||||||
|
*/
|
||||||
|
private $redirectUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Prefix to use for session variables
|
||||||
|
*/
|
||||||
|
private $sessionPrefix = 'FBRLH_';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string State token for CSRF validation
|
||||||
|
*/
|
||||||
|
protected $state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean Toggle for PHP session status check
|
||||||
|
*/
|
||||||
|
protected $checkForSessionStatus = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a RedirectLoginHelper for a given appId and redirectUrl.
|
||||||
|
*
|
||||||
|
* @param string $redirectUrl The URL Facebook should redirect users to
|
||||||
|
* after login
|
||||||
|
* @param string $appId The application id
|
||||||
|
* @param string $appSecret The application secret
|
||||||
|
*/
|
||||||
|
public function __construct($redirectUrl, $appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$this->appId = FacebookSession::_getTargetAppId($appId);
|
||||||
|
$this->appSecret = FacebookSession::_getTargetAppSecret($appSecret);
|
||||||
|
$this->redirectUrl = $redirectUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores CSRF state and returns a URL to which the user should be sent to
|
||||||
|
* in order to continue the login process with Facebook. The
|
||||||
|
* provided redirectUrl should invoke the handleRedirect method.
|
||||||
|
*
|
||||||
|
* @param array $scope List of permissions to request during login
|
||||||
|
* @param string $version Optional Graph API version if not default (v2.0)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLoginUrl($scope = array(), $version = null)
|
||||||
|
{
|
||||||
|
$version = ($version ?: FacebookRequest::GRAPH_API_VERSION);
|
||||||
|
$this->state = $this->random(16);
|
||||||
|
$this->storeState($this->state);
|
||||||
|
$params = array(
|
||||||
|
'client_id' => $this->appId,
|
||||||
|
'redirect_uri' => $this->redirectUrl,
|
||||||
|
'state' => $this->state,
|
||||||
|
'sdk' => 'php-sdk-' . FacebookRequest::VERSION,
|
||||||
|
'scope' => implode(',', $scope)
|
||||||
|
);
|
||||||
|
return 'https://www.facebook.com/' . $version . '/dialog/oauth?' .
|
||||||
|
http_build_query($params, null, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL to send the user in order to log out of Facebook.
|
||||||
|
*
|
||||||
|
* @param FacebookSession $session The session that will be logged out
|
||||||
|
* @param string $next The url Facebook should redirect the user to after
|
||||||
|
* a successful logout
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLogoutUrl(FacebookSession $session, $next)
|
||||||
|
{
|
||||||
|
$params = array(
|
||||||
|
'next' => $next,
|
||||||
|
'access_token' => $session->getToken()
|
||||||
|
);
|
||||||
|
return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a response from Facebook, including a CSRF check, and returns a
|
||||||
|
* FacebookSession.
|
||||||
|
*
|
||||||
|
* @return FacebookSession|null
|
||||||
|
*/
|
||||||
|
public function getSessionFromRedirect()
|
||||||
|
{
|
||||||
|
$this->loadState();
|
||||||
|
if ($this->isValidRedirect()) {
|
||||||
|
$params = array(
|
||||||
|
'client_id' => FacebookSession::_getTargetAppId($this->appId),
|
||||||
|
'redirect_uri' => $this->redirectUrl,
|
||||||
|
'client_secret' =>
|
||||||
|
FacebookSession::_getTargetAppSecret($this->appSecret),
|
||||||
|
'code' => $this->getCode()
|
||||||
|
);
|
||||||
|
$response = (new FacebookRequest(
|
||||||
|
FacebookSession::newAppSession($this->appId, $this->appSecret),
|
||||||
|
'GET',
|
||||||
|
'/oauth/access_token',
|
||||||
|
$params
|
||||||
|
))->execute()->getResponse();
|
||||||
|
if (isset($response['access_token'])) {
|
||||||
|
return new FacebookSession($response['access_token']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a redirect has a valid state.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isValidRedirect()
|
||||||
|
{
|
||||||
|
return $this->getCode() && isset($_GET['state'])
|
||||||
|
&& $_GET['state'] == $this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the code.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
protected function getCode()
|
||||||
|
{
|
||||||
|
return isset($_GET['code']) ? $_GET['code'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a state string in session storage for CSRF protection.
|
||||||
|
* Developers should subclass and override this method if they want to store
|
||||||
|
* this state in a different location.
|
||||||
|
*
|
||||||
|
* @param string $state
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
protected function storeState($state)
|
||||||
|
{
|
||||||
|
if ($this->checkForSessionStatus === true
|
||||||
|
&& session_status() !== PHP_SESSION_ACTIVE) {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Session not active, could not store state.', 720
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$_SESSION[$this->sessionPrefix . 'state'] = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a state string from session storage for CSRF validation. May return
|
||||||
|
* null if no object exists. Developers should subclass and override this
|
||||||
|
* method if they want to load the state from a different location.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
protected function loadState()
|
||||||
|
{
|
||||||
|
if ($this->checkForSessionStatus === true
|
||||||
|
&& session_status() !== PHP_SESSION_ACTIVE) {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Session not active, could not load state.', 721
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isset($_SESSION[$this->sessionPrefix . 'state'])) {
|
||||||
|
$this->state = $_SESSION[$this->sessionPrefix . 'state'];
|
||||||
|
return $this->state;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a cryptographically secure pseudrandom number
|
||||||
|
*
|
||||||
|
* @param integer $bytes - number of bytes to return
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*
|
||||||
|
* @todo Support Windows platforms
|
||||||
|
*/
|
||||||
|
public function random($bytes)
|
||||||
|
{
|
||||||
|
if (!is_numeric($bytes)) {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
"random() expects an integer"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($bytes < 1) {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
"random() expects an integer greater than zero"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$buf = '';
|
||||||
|
// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
|
||||||
|
if (is_readable('/dev/urandom')) {
|
||||||
|
$fp = fopen('/dev/urandom', 'rb');
|
||||||
|
if ($fp !== FALSE) {
|
||||||
|
$buf = fread($fp, $bytes);
|
||||||
|
fclose($fp);
|
||||||
|
if($buf !== FALSE) {
|
||||||
|
return bin2hex($buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('mcrypt_create_iv')) {
|
||||||
|
$buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
|
||||||
|
if ($buf !== FALSE) {
|
||||||
|
return bin2hex($buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (strlen($buf) < $bytes) {
|
||||||
|
$buf .= md5(uniqid(mt_rand(), true), true);
|
||||||
|
// We are appending raw binary
|
||||||
|
}
|
||||||
|
return bin2hex(substr($buf, 0, $bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the session_status() check when using $_SESSION
|
||||||
|
*/
|
||||||
|
public function disableSessionStatusCheck()
|
||||||
|
{
|
||||||
|
$this->checkForSessionStatus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
313
rainloop/v/0.0.0/app/libraries/Facebook/FacebookRequest.php
Normal file
313
rainloop/v/0.0.0/app/libraries/Facebook/FacebookRequest.php
Normal file
|
|
@ -0,0 +1,313 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
use Facebook\HttpClients\FacebookHttpable;
|
||||||
|
use Facebook\HttpClients\FacebookCurlHttpClient;
|
||||||
|
use Facebook\HttpClients\FacebookStreamHttpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookRequest
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const string Version number of the Facebook PHP SDK.
|
||||||
|
*/
|
||||||
|
const VERSION = '4.0.9';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const string Default Graph API version for requests
|
||||||
|
*/
|
||||||
|
const GRAPH_API_VERSION = 'v2.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const string Graph API URL
|
||||||
|
*/
|
||||||
|
const BASE_GRAPH_URL = 'https://graph.facebook.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FacebookSession The session used for this request
|
||||||
|
*/
|
||||||
|
private $session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The HTTP method for the request
|
||||||
|
*/
|
||||||
|
private $method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The path for the request
|
||||||
|
*/
|
||||||
|
private $path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The parameters for the request
|
||||||
|
*/
|
||||||
|
private $params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The Graph API version for the request
|
||||||
|
*/
|
||||||
|
private $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string ETag sent with the request
|
||||||
|
*/
|
||||||
|
private $etag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FacebookHttpable HTTP client handler
|
||||||
|
*/
|
||||||
|
private static $httpClientHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The number of calls that have been made to Graph.
|
||||||
|
*/
|
||||||
|
public static $requestCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getSession - Returns the associated FacebookSession.
|
||||||
|
*
|
||||||
|
* @return FacebookSession
|
||||||
|
*/
|
||||||
|
public function getSession()
|
||||||
|
{
|
||||||
|
return $this->session;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPath - Returns the associated path.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPath()
|
||||||
|
{
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getParameters - Returns the associated parameters.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParameters()
|
||||||
|
{
|
||||||
|
return $this->params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getMethod - Returns the associated method.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMethod()
|
||||||
|
{
|
||||||
|
return $this->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getETag - Returns the ETag sent with the request.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getETag()
|
||||||
|
{
|
||||||
|
return $this->etag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setHttpClientHandler - Returns an instance of the HTTP client
|
||||||
|
* handler
|
||||||
|
*
|
||||||
|
* @param \Facebook\HttpClients\FacebookHttpable
|
||||||
|
*/
|
||||||
|
public static function setHttpClientHandler(FacebookHttpable $handler)
|
||||||
|
{
|
||||||
|
static::$httpClientHandler = $handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getHttpClientHandler - Returns an instance of the HTTP client
|
||||||
|
* data handler
|
||||||
|
*
|
||||||
|
* @return FacebookHttpable
|
||||||
|
*/
|
||||||
|
public static function getHttpClientHandler()
|
||||||
|
{
|
||||||
|
if (static::$httpClientHandler) {
|
||||||
|
return static::$httpClientHandler;
|
||||||
|
}
|
||||||
|
return function_exists('curl_init') ? new FacebookCurlHttpClient() : new FacebookStreamHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FacebookRequest - Returns a new request using the given session. optional
|
||||||
|
* parameters hash will be sent with the request. This object is
|
||||||
|
* immutable.
|
||||||
|
*
|
||||||
|
* @param FacebookSession $session
|
||||||
|
* @param string $method
|
||||||
|
* @param string $path
|
||||||
|
* @param array|null $parameters
|
||||||
|
* @param string|null $version
|
||||||
|
* @param string|null $etag
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
FacebookSession $session, $method, $path, $parameters = null, $version = null, $etag = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->session = $session;
|
||||||
|
$this->method = $method;
|
||||||
|
$this->path = $path;
|
||||||
|
if ($version) {
|
||||||
|
$this->version = $version;
|
||||||
|
} else {
|
||||||
|
$this->version = static::GRAPH_API_VERSION;
|
||||||
|
}
|
||||||
|
$this->etag = $etag;
|
||||||
|
|
||||||
|
$params = ($parameters ?: array());
|
||||||
|
if ($session
|
||||||
|
&& !isset($params["access_token"])) {
|
||||||
|
$params["access_token"] = $session->getToken();
|
||||||
|
}
|
||||||
|
if (FacebookSession::useAppSecretProof()
|
||||||
|
&& !isset($params["appsecret_proof"])) {
|
||||||
|
$params["appsecret_proof"] = $this->getAppSecretProof(
|
||||||
|
$params["access_token"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->params = $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base Graph URL.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getRequestURL()
|
||||||
|
{
|
||||||
|
return static::BASE_GRAPH_URL . '/' . $this->version . $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute - Makes the request to Facebook and returns the result.
|
||||||
|
*
|
||||||
|
* @return FacebookResponse
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
* @throws FacebookRequestException
|
||||||
|
*/
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
$url = $this->getRequestURL();
|
||||||
|
$params = $this->getParameters();
|
||||||
|
|
||||||
|
if ($this->method === "GET") {
|
||||||
|
$url = self::appendParamsToUrl($url, $params);
|
||||||
|
$params = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = self::getHttpClientHandler();
|
||||||
|
$connection->addRequestHeader('User-Agent', 'fb-php-' . self::VERSION);
|
||||||
|
$connection->addRequestHeader('Accept-Encoding', '*'); // Support all available encodings.
|
||||||
|
|
||||||
|
// ETag
|
||||||
|
if (isset($this->etag)) {
|
||||||
|
$connection->addRequestHeader('If-None-Match', $this->etag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should throw `FacebookSDKException` exception on HTTP client error.
|
||||||
|
// Don't catch to allow it to bubble up.
|
||||||
|
$result = $connection->send($url, $this->method, $params);
|
||||||
|
|
||||||
|
static::$requestCount++;
|
||||||
|
|
||||||
|
$etagHit = 304 == $connection->getResponseHttpStatusCode();
|
||||||
|
|
||||||
|
$headers = $connection->getResponseHeaders();
|
||||||
|
$etagReceived = isset($headers['ETag']) ? $headers['ETag'] : null;
|
||||||
|
|
||||||
|
$decodedResult = json_decode($result);
|
||||||
|
if ($decodedResult === null) {
|
||||||
|
$out = array();
|
||||||
|
parse_str($result, $out);
|
||||||
|
return new FacebookResponse($this, $out, $result, $etagHit, $etagReceived);
|
||||||
|
}
|
||||||
|
if (isset($decodedResult->error)) {
|
||||||
|
throw FacebookRequestException::create(
|
||||||
|
$result,
|
||||||
|
$decodedResult->error,
|
||||||
|
$connection->getResponseHttpStatusCode()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FacebookResponse($this, $decodedResult, $result, $etagHit, $etagReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and return the appsecret_proof value for an access_token
|
||||||
|
*
|
||||||
|
* @param string $token
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAppSecretProof($token)
|
||||||
|
{
|
||||||
|
return hash_hmac('sha256', $token, FacebookSession::_getTargetAppSecret());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appendParamsToUrl - Gracefully appends params to the URL.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param array $params
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function appendParamsToUrl($url, $params = array())
|
||||||
|
{
|
||||||
|
if (!$params) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($url, '?') === false) {
|
||||||
|
return $url . '?' . http_build_query($params, null, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
list($path, $query_string) = explode('?', $url, 2);
|
||||||
|
parse_str($query_string, $query_array);
|
||||||
|
|
||||||
|
// Favor params from the original URL over $params
|
||||||
|
$params = array_merge($params, $query_array);
|
||||||
|
|
||||||
|
return $path . '?' . http_build_query($params, null, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,222 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookRequestException
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookRequestException extends FacebookSDKException
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int Status code for the response causing the exception
|
||||||
|
*/
|
||||||
|
private $statusCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Raw response
|
||||||
|
*/
|
||||||
|
private $rawResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Decoded response
|
||||||
|
*/
|
||||||
|
private $responseData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FacebookRequestException.
|
||||||
|
*
|
||||||
|
* @param string $rawResponse The raw response from the Graph API
|
||||||
|
* @param array $responseData The decoded response from the Graph API
|
||||||
|
* @param int $statusCode
|
||||||
|
*/
|
||||||
|
public function __construct($rawResponse, $responseData, $statusCode)
|
||||||
|
{
|
||||||
|
$this->rawResponse = $rawResponse;
|
||||||
|
$this->statusCode = $statusCode;
|
||||||
|
$this->responseData = self::convertToArray($responseData);
|
||||||
|
parent::__construct(
|
||||||
|
$this->get('message', 'Unknown Exception'), $this->get('code', -1), null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an error payload from the Graph API and return the appropriate
|
||||||
|
* exception subclass.
|
||||||
|
*
|
||||||
|
* @param string $raw the raw response from the Graph API
|
||||||
|
* @param array $data the decoded response from the Graph API
|
||||||
|
* @param int $statusCode the HTTP response code
|
||||||
|
*
|
||||||
|
* @return FacebookRequestException
|
||||||
|
*/
|
||||||
|
public static function create($raw, $data, $statusCode)
|
||||||
|
{
|
||||||
|
$data = self::convertToArray($data);
|
||||||
|
if (!isset($data['error']['code']) && isset($data['code'])) {
|
||||||
|
$data = array('error' => $data);
|
||||||
|
}
|
||||||
|
$code = (isset($data['error']['code']) ? $data['error']['code'] : null);
|
||||||
|
|
||||||
|
if (isset($data['error']['error_subcode'])) {
|
||||||
|
switch ($data['error']['error_subcode']) {
|
||||||
|
// Other authentication issues
|
||||||
|
case 458:
|
||||||
|
case 459:
|
||||||
|
case 460:
|
||||||
|
case 463:
|
||||||
|
case 464:
|
||||||
|
case 467:
|
||||||
|
return new FacebookAuthorizationException($raw, $data, $statusCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($code) {
|
||||||
|
// Login status or token expired, revoked, or invalid
|
||||||
|
case 100:
|
||||||
|
case 102:
|
||||||
|
case 190:
|
||||||
|
return new FacebookAuthorizationException($raw, $data, $statusCode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Server issue, possible downtime
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return new FacebookServerException($raw, $data, $statusCode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// API Throttling
|
||||||
|
case 4:
|
||||||
|
case 17:
|
||||||
|
case 341:
|
||||||
|
return new FacebookThrottleException($raw, $data, $statusCode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Duplicate Post
|
||||||
|
case 506:
|
||||||
|
return new FacebookClientException($raw, $data, $statusCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Missing Permissions
|
||||||
|
if ($code == 10 || ($code >= 200 && $code <= 299)) {
|
||||||
|
return new FacebookPermissionException($raw, $data, $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth authentication error
|
||||||
|
if (isset($data['error']['type'])
|
||||||
|
and $data['error']['type'] === 'OAuthException') {
|
||||||
|
return new FacebookAuthorizationException($raw, $data, $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All others
|
||||||
|
return new FacebookOtherException($raw, $data, $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks isset and returns that or a default value.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $default
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function get($key, $default = null)
|
||||||
|
{
|
||||||
|
if (isset($this->responseData['error'][$key])) {
|
||||||
|
return $this->responseData['error'][$key];
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP status code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getHttpStatusCode()
|
||||||
|
{
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sub-error code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getSubErrorCode()
|
||||||
|
{
|
||||||
|
return $this->get('error_subcode', -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the error type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getErrorType()
|
||||||
|
{
|
||||||
|
return $this->get('type', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw response used to create the exception.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawResponse()
|
||||||
|
{
|
||||||
|
return $this->rawResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decoded response used to create the exception.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->responseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a stdClass object to an array
|
||||||
|
*
|
||||||
|
* @param mixed $object
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function convertToArray($object)
|
||||||
|
{
|
||||||
|
if ($object instanceof \stdClass) {
|
||||||
|
return get_object_vars($object);
|
||||||
|
}
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
202
rainloop/v/0.0.0/app/libraries/Facebook/FacebookResponse.php
Normal file
202
rainloop/v/0.0.0/app/libraries/Facebook/FacebookResponse.php
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookResponse
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FacebookRequest The request which produced this response
|
||||||
|
*/
|
||||||
|
private $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The decoded response from the Graph API
|
||||||
|
*/
|
||||||
|
private $responseData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The raw response from the Graph API
|
||||||
|
*/
|
||||||
|
private $rawResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool Indicates whether sent ETag matched the one on the FB side
|
||||||
|
*/
|
||||||
|
private $etagHit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string ETag received with the response. `null` in case of ETag hit.
|
||||||
|
*/
|
||||||
|
private $etag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FacebookResponse object for a given request and response.
|
||||||
|
*
|
||||||
|
* @param FacebookRequest $request
|
||||||
|
* @param array $responseData JSON Decoded response data
|
||||||
|
* @param string $rawResponse Raw string response
|
||||||
|
* @param bool $etagHit Indicates whether sent ETag matched the one on the FB side
|
||||||
|
* @param string|null $etag ETag received with the response. `null` in case of ETag hit.
|
||||||
|
*/
|
||||||
|
public function __construct($request, $responseData, $rawResponse, $etagHit = false, $etag = null)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
$this->responseData = $responseData;
|
||||||
|
$this->rawResponse = $rawResponse;
|
||||||
|
$this->etagHit = $etagHit;
|
||||||
|
$this->etag = $etag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the request which produced this response.
|
||||||
|
*
|
||||||
|
* @return FacebookRequest
|
||||||
|
*/
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decoded response data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->responseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw response
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawResponse()
|
||||||
|
{
|
||||||
|
return $this->rawResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if ETag matched the one sent with a request
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isETagHit()
|
||||||
|
{
|
||||||
|
return $this->etagHit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ETag
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getETag()
|
||||||
|
{
|
||||||
|
return $this->etag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result as a GraphObject. If a type is specified, returns the
|
||||||
|
* strongly-typed subclass of GraphObject for the data.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getGraphObject($type = 'Facebook\GraphObject') {
|
||||||
|
return (new GraphObject($this->responseData))->cast($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of GraphObject returned by the request. If a type is
|
||||||
|
* specified, returns the strongly-typed subclass of GraphObject for the data.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getGraphObjectList($type = 'Facebook\GraphObject') {
|
||||||
|
$out = array();
|
||||||
|
$data = $this->responseData->data;
|
||||||
|
for ($i = 0; $i < count($data); $i++) {
|
||||||
|
$out[] = (new GraphObject($data[$i]))->cast($type);
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this response has paginated data, returns the FacebookRequest for the
|
||||||
|
* next page, or null.
|
||||||
|
*
|
||||||
|
* @return FacebookRequest|null
|
||||||
|
*/
|
||||||
|
public function getRequestForNextPage()
|
||||||
|
{
|
||||||
|
return $this->handlePagination('next');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this response has paginated data, returns the FacebookRequest for the
|
||||||
|
* previous page, or null.
|
||||||
|
*
|
||||||
|
* @return FacebookRequest|null
|
||||||
|
*/
|
||||||
|
public function getRequestForPreviousPage()
|
||||||
|
{
|
||||||
|
return $this->handlePagination('previous');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FacebookRequest for the previous or next page, or null.
|
||||||
|
*
|
||||||
|
* @param string $direction
|
||||||
|
*
|
||||||
|
* @return FacebookRequest|null
|
||||||
|
*/
|
||||||
|
private function handlePagination($direction) {
|
||||||
|
if (isset($this->responseData->paging->$direction)) {
|
||||||
|
$url = parse_url($this->responseData->paging->$direction);
|
||||||
|
parse_str($url['query'], $params);
|
||||||
|
|
||||||
|
return new FacebookRequest(
|
||||||
|
$this->request->getSession(),
|
||||||
|
$this->request->getMethod(),
|
||||||
|
$this->request->getPath(),
|
||||||
|
$params
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookSDKException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookSDKException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookServerException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookServerException extends FacebookRequestException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
367
rainloop/v/0.0.0/app/libraries/Facebook/FacebookSession.php
Normal file
367
rainloop/v/0.0.0/app/libraries/Facebook/FacebookSession.php
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
use Facebook\Entities\AccessToken;
|
||||||
|
use Facebook\Entities\SignedRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookSession
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class FacebookSession
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $defaultAppId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $defaultAppSecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AccessToken The AccessToken entity for this connection.
|
||||||
|
*/
|
||||||
|
private $accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var SignedRequest
|
||||||
|
*/
|
||||||
|
private $signedRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private static $useAppSecretProof = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When creating a Session from an access_token, use:
|
||||||
|
* var $session = new FacebookSession($accessToken);
|
||||||
|
* This will validate the token and provide a Session object ready for use.
|
||||||
|
* It will throw a SessionException in case of error.
|
||||||
|
*
|
||||||
|
* @param AccessToken|string $accessToken
|
||||||
|
* @param SignedRequest $signedRequest The SignedRequest entity
|
||||||
|
*/
|
||||||
|
public function __construct($accessToken, SignedRequest $signedRequest = null)
|
||||||
|
{
|
||||||
|
$this->accessToken = $accessToken instanceof AccessToken ? $accessToken : new AccessToken($accessToken);
|
||||||
|
$this->signedRequest = $signedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the access token.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getToken()
|
||||||
|
{
|
||||||
|
return (string) $this->accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the access token entity.
|
||||||
|
*
|
||||||
|
* @return AccessToken
|
||||||
|
*/
|
||||||
|
public function getAccessToken()
|
||||||
|
{
|
||||||
|
return $this->accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the SignedRequest entity.
|
||||||
|
*
|
||||||
|
* @return SignedRequest
|
||||||
|
*/
|
||||||
|
public function getSignedRequest()
|
||||||
|
{
|
||||||
|
return $this->signedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the signed request payload.
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*/
|
||||||
|
public function getSignedRequestData()
|
||||||
|
{
|
||||||
|
return $this->signedRequest ? $this->signedRequest->getPayload() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a property from the signed request data if available.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
*
|
||||||
|
* @return null|mixed
|
||||||
|
*/
|
||||||
|
public function getSignedRequestProperty($key)
|
||||||
|
{
|
||||||
|
return $this->signedRequest ? $this->signedRequest->get($key) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns user_id from signed request data if available.
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->signedRequest ? $this->signedRequest->getUserId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO Remove getSessionInfo() in 4.1: can be accessed from AccessToken directly
|
||||||
|
/**
|
||||||
|
* getSessionInfo - Makes a request to /debug_token with the appropriate
|
||||||
|
* arguments to get debug information about the sessions token.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return GraphSessionInfo
|
||||||
|
*/
|
||||||
|
public function getSessionInfo($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
return $this->accessToken->getInfo($appId, $appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO Remove getLongLivedSession() in 4.1: can be accessed from AccessToken directly
|
||||||
|
/**
|
||||||
|
* getLongLivedSession - Returns a new Facebook session resulting from
|
||||||
|
* extending a short-lived access token. If this session is not
|
||||||
|
* short-lived, returns $this.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return FacebookSession
|
||||||
|
*/
|
||||||
|
public function getLongLivedSession($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$longLivedAccessToken = $this->accessToken->extend($appId, $appSecret);
|
||||||
|
return new static($longLivedAccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO Remove getExchangeToken() in 4.1: can be accessed from AccessToken directly
|
||||||
|
/**
|
||||||
|
* getExchangeToken - Returns an exchange token string which can be sent
|
||||||
|
* back to clients and exchanged for a device-linked access token.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getExchangeToken($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
return AccessToken::getCodeFromAccessToken($this->accessToken, $appId, $appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO Remove validate() in 4.1: can be accessed from AccessToken directly
|
||||||
|
/**
|
||||||
|
* validate - Ensures the current session is valid, throwing an exception if
|
||||||
|
* not. Fetches token info from Facebook.
|
||||||
|
*
|
||||||
|
* @param string|null $appId Application ID to use
|
||||||
|
* @param string|null $appSecret App secret value to use
|
||||||
|
* @param string|null $machineId
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public function validate($appId = null, $appSecret = null, $machineId = null)
|
||||||
|
{
|
||||||
|
if ($this->accessToken->isValid($appId, $appSecret, $machineId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO For v4.1 this should not throw an exception, but just return false.
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Session has expired, or is not valid for this app.', 601
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO Remove validateSessionInfo() in 4.1: can be accessed from AccessToken directly
|
||||||
|
/**
|
||||||
|
* validateTokenInfo - Ensures the provided GraphSessionInfo object is valid,
|
||||||
|
* throwing an exception if not. Ensures the appId matches,
|
||||||
|
* that the token is valid and has not expired.
|
||||||
|
*
|
||||||
|
* @param GraphSessionInfo $tokenInfo
|
||||||
|
* @param string|null $appId Application ID to use
|
||||||
|
* @param string|null $machineId
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function validateSessionInfo(GraphSessionInfo $tokenInfo,
|
||||||
|
$appId = null,
|
||||||
|
$machineId = null)
|
||||||
|
{
|
||||||
|
if (AccessToken::validateAccessToken($tokenInfo, $appId, $machineId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO For v4.1 this should not throw an exception, but just return false.
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Session has expired, or is not valid for this app.', 601
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newSessionFromSignedRequest - Returns a FacebookSession for a
|
||||||
|
* given signed request.
|
||||||
|
*
|
||||||
|
* @param SignedRequest $signedRequest
|
||||||
|
*
|
||||||
|
* @return FacebookSession
|
||||||
|
*/
|
||||||
|
public static function newSessionFromSignedRequest(SignedRequest $signedRequest)
|
||||||
|
{
|
||||||
|
if ($signedRequest->get('code')
|
||||||
|
&& !$signedRequest->get('oauth_token')) {
|
||||||
|
return self::newSessionAfterValidation($signedRequest);
|
||||||
|
}
|
||||||
|
$accessToken = $signedRequest->get('oauth_token');
|
||||||
|
$expiresAt = $signedRequest->get('expires', 0);
|
||||||
|
$accessToken = new AccessToken($accessToken, $expiresAt);
|
||||||
|
return new static($accessToken, $signedRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newSessionAfterValidation - Returns a FacebookSession for a
|
||||||
|
* validated & parsed signed request.
|
||||||
|
*
|
||||||
|
* @param SignedRequest $signedRequest
|
||||||
|
*
|
||||||
|
* @return FacebookSession
|
||||||
|
*/
|
||||||
|
protected static function newSessionAfterValidation(SignedRequest $signedRequest)
|
||||||
|
{
|
||||||
|
$code = $signedRequest->get('code');
|
||||||
|
$accessToken = AccessToken::getAccessTokenFromCode($code);
|
||||||
|
return new static($accessToken, $signedRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newAppSession - Returns a FacebookSession configured with a token for the
|
||||||
|
* application which can be used for publishing and requesting app-level
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* @param string|null $appId Application ID to use
|
||||||
|
* @param string|null $appSecret App secret value to use
|
||||||
|
*
|
||||||
|
* @return FacebookSession
|
||||||
|
*/
|
||||||
|
public static function newAppSession($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$targetAppId = static::_getTargetAppId($appId);
|
||||||
|
$targetAppSecret = static::_getTargetAppSecret($appSecret);
|
||||||
|
return new FacebookSession(
|
||||||
|
$targetAppId . '|' . $targetAppSecret
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setDefaultApplication - Will set the static default appId and appSecret
|
||||||
|
* to be used for API requests.
|
||||||
|
*
|
||||||
|
* @param string $appId Application ID to use by default
|
||||||
|
* @param string $appSecret App secret value to use by default
|
||||||
|
*/
|
||||||
|
public static function setDefaultApplication($appId, $appSecret)
|
||||||
|
{
|
||||||
|
self::$defaultAppId = $appId;
|
||||||
|
self::$defaultAppSecret = $appSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _getTargetAppId - Will return either the provided app Id or the default,
|
||||||
|
* throwing if neither are populated.
|
||||||
|
*
|
||||||
|
* @param string $appId
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function _getTargetAppId($appId = null) {
|
||||||
|
$target = ($appId ?: self::$defaultAppId);
|
||||||
|
if (!$target) {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'You must provide or set a default application id.', 700
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _getTargetAppSecret - Will return either the provided app secret or the
|
||||||
|
* default, throwing if neither are populated.
|
||||||
|
*
|
||||||
|
* @param string $appSecret
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public static function _getTargetAppSecret($appSecret = null) {
|
||||||
|
$target = ($appSecret ?: self::$defaultAppSecret);
|
||||||
|
if (!$target) {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'You must provide or set a default application secret.', 701
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable sending the appsecret_proof with requests.
|
||||||
|
*
|
||||||
|
* @param bool $on
|
||||||
|
*/
|
||||||
|
public static function enableAppSecretProof($on = true)
|
||||||
|
{
|
||||||
|
static::$useAppSecretProof = ($on ? true : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether or not appsecret_proof should be sent with requests.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function useAppSecretProof()
|
||||||
|
{
|
||||||
|
return static::$useAppSecretProof;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
use Facebook\Entities\SignedRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookSignedRequestFromInputHelper
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
abstract class FacebookSignedRequestFromInputHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Facebook\Entities\SignedRequest|null
|
||||||
|
*/
|
||||||
|
protected $signedRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string the app id
|
||||||
|
*/
|
||||||
|
protected $appId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string the app secret
|
||||||
|
*/
|
||||||
|
protected $appSecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Random string to prevent CSRF.
|
||||||
|
*/
|
||||||
|
public $state = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the helper and process available signed request data.
|
||||||
|
*
|
||||||
|
* @param string|null $appId
|
||||||
|
* @param string|null $appSecret
|
||||||
|
*/
|
||||||
|
public function __construct($appId = null, $appSecret = null)
|
||||||
|
{
|
||||||
|
$this->appId = FacebookSession::_getTargetAppId($appId);
|
||||||
|
$this->appSecret = FacebookSession::_getTargetAppSecret($appSecret);
|
||||||
|
|
||||||
|
$this->instantiateSignedRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new SignedRequest entity.
|
||||||
|
*
|
||||||
|
* @param string|null
|
||||||
|
*/
|
||||||
|
public function instantiateSignedRequest($rawSignedRequest = null)
|
||||||
|
{
|
||||||
|
$rawSignedRequest = $rawSignedRequest ?: $this->getRawSignedRequest();
|
||||||
|
|
||||||
|
if (!$rawSignedRequest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->signedRequest = new SignedRequest($rawSignedRequest, $this->state, $this->appSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a FacebookSession from the signed request from input.
|
||||||
|
*
|
||||||
|
* @return FacebookSession|null
|
||||||
|
*/
|
||||||
|
public function getSession()
|
||||||
|
{
|
||||||
|
if ($this->signedRequest && $this->signedRequest->hasOAuthData()) {
|
||||||
|
return FacebookSession::newSessionFromSignedRequest($this->signedRequest);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the SignedRequest entity.
|
||||||
|
*
|
||||||
|
* @return \Facebook\Entities\SignedRequest|null
|
||||||
|
*/
|
||||||
|
public function getSignedRequest()
|
||||||
|
{
|
||||||
|
return $this->signedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the user_id if available.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->signedRequest ? $this->signedRequest->getUserId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw signed request from input.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
abstract public function getRawSignedRequest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw signed request from GET input.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRawSignedRequestFromGet()
|
||||||
|
{
|
||||||
|
if (isset($_GET['signed_request'])) {
|
||||||
|
return $_GET['signed_request'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw signed request from POST input.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRawSignedRequestFromPost()
|
||||||
|
{
|
||||||
|
if (isset($_POST['signed_request'])) {
|
||||||
|
return $_POST['signed_request'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw signed request from cookie set from the Javascript SDK.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRawSignedRequestFromCookie()
|
||||||
|
{
|
||||||
|
if (isset($_COOKIE['fbsr_' . $this->appId])) {
|
||||||
|
return $_COOKIE['fbsr_' . $this->appId];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookThrottleException
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookThrottleException extends FacebookRequestException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
173
rainloop/v/0.0.0/app/libraries/Facebook/GraphAlbum.php
Normal file
173
rainloop/v/0.0.0/app/libraries/Facebook/GraphAlbum.php
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphAlbum
|
||||||
|
* @package Facebook
|
||||||
|
* @author Daniele Grosso <daniele.grosso@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GraphAlbum extends GraphObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the ID for the album.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->getProperty('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the viewer can upload photos to this album.
|
||||||
|
*
|
||||||
|
* @return boolean|null
|
||||||
|
*/
|
||||||
|
public function canUpload()
|
||||||
|
{
|
||||||
|
return $this->getProperty('can_upload');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of photos in this album.
|
||||||
|
*
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function getCount()
|
||||||
|
{
|
||||||
|
return$this->getProperty('count');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID of the album's cover photo.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCoverPhoto()
|
||||||
|
{
|
||||||
|
return$this->getProperty('cover_photo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time the album was initially created.
|
||||||
|
*
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getCreatedTime()
|
||||||
|
{
|
||||||
|
$value = $this->getProperty('created_time');
|
||||||
|
if ($value) {
|
||||||
|
return new \DateTime($value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time the album was updated.
|
||||||
|
*
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getUpdatedTime()
|
||||||
|
{
|
||||||
|
$value = $this->getProperty('updated_time');
|
||||||
|
if ($value) {
|
||||||
|
return new \DateTime($value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of the album.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return$this->getProperty('description');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns profile that created the album.
|
||||||
|
*
|
||||||
|
* @return GraphUser|null
|
||||||
|
*/
|
||||||
|
public function getFrom()
|
||||||
|
{
|
||||||
|
return $this->getProperty('from', GraphUser::className());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a link to this album on Facebook.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getLink()
|
||||||
|
{
|
||||||
|
return$this->getProperty('link');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the textual location of the album.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getLocation()
|
||||||
|
{
|
||||||
|
return$this->getProperty('location');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title of the album.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return$this->getProperty('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the privacy settings for the album.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getPrivacy()
|
||||||
|
{
|
||||||
|
return$this->getProperty('privacy');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the album. enum{profile, mobile, wall, normal, album}
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return$this->getProperty('type');
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: public function getPlace() that should return GraphPage
|
||||||
|
}
|
||||||
105
rainloop/v/0.0.0/app/libraries/Facebook/GraphLocation.php
Normal file
105
rainloop/v/0.0.0/app/libraries/Facebook/GraphLocation.php
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphLocation
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class GraphLocation extends GraphObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the street component of the location
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getStreet()
|
||||||
|
{
|
||||||
|
return $this->getProperty('street');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the city component of the location
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCity()
|
||||||
|
{
|
||||||
|
return $this->getProperty('city');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the state component of the location
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getState()
|
||||||
|
{
|
||||||
|
return $this->getProperty('state');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the country component of the location
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCountry()
|
||||||
|
{
|
||||||
|
return $this->getProperty('country');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the zipcode component of the location
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getZip()
|
||||||
|
{
|
||||||
|
return $this->getProperty('zip');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the latitude component of the location
|
||||||
|
*
|
||||||
|
* @return float|null
|
||||||
|
*/
|
||||||
|
public function getLatitude()
|
||||||
|
{
|
||||||
|
return $this->getProperty('latitude');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the street component of the location
|
||||||
|
*
|
||||||
|
* @return float|null
|
||||||
|
*/
|
||||||
|
public function getLongitude()
|
||||||
|
{
|
||||||
|
return $this->getProperty('longitude');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
167
rainloop/v/0.0.0/app/libraries/Facebook/GraphObject.php
Normal file
167
rainloop/v/0.0.0/app/libraries/Facebook/GraphObject.php
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphObject
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class GraphObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array - Holds the raw associative data for this object
|
||||||
|
*/
|
||||||
|
protected $backingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a GraphObject using the data provided.
|
||||||
|
*
|
||||||
|
* @param array $raw
|
||||||
|
*/
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
if ($raw instanceof \stdClass) {
|
||||||
|
$raw = get_object_vars($raw);
|
||||||
|
}
|
||||||
|
$this->backingData = $raw;
|
||||||
|
|
||||||
|
if (isset($this->backingData['data']) && count($this->backingData) === 1) {
|
||||||
|
$this->backingData = $this->backingData['data'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cast - Return a new instance of a FacebookGraphObject subclass for this
|
||||||
|
* objects underlying data.
|
||||||
|
*
|
||||||
|
* @param string $type The GraphObject subclass to cast to
|
||||||
|
*
|
||||||
|
* @return GraphObject
|
||||||
|
*
|
||||||
|
* @throws FacebookSDKException
|
||||||
|
*/
|
||||||
|
public function cast($type)
|
||||||
|
{
|
||||||
|
if ($this instanceof $type) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if (is_subclass_of($type, GraphObject::className())) {
|
||||||
|
return new $type($this->backingData);
|
||||||
|
} else {
|
||||||
|
throw new FacebookSDKException(
|
||||||
|
'Cannot cast to an object that is not a GraphObject subclass', 620
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* asArray - Return a key-value associative array for the given graph object.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function asArray()
|
||||||
|
{
|
||||||
|
return $this->backingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getProperty - Gets the value of the named property for this graph object,
|
||||||
|
* cast to the appropriate subclass type if provided.
|
||||||
|
*
|
||||||
|
* @param string $name The property to retrieve
|
||||||
|
* @param string $type The subclass of GraphObject, optionally
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getProperty($name, $type = 'Facebook\GraphObject')
|
||||||
|
{
|
||||||
|
if (isset($this->backingData[$name])) {
|
||||||
|
$value = $this->backingData[$name];
|
||||||
|
if (is_scalar($value)) {
|
||||||
|
return $value;
|
||||||
|
} else {
|
||||||
|
return (new GraphObject($value))->cast($type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPropertyAsArray - Get the list value of a named property for this graph
|
||||||
|
* object, where each item has been cast to the appropriate subclass type
|
||||||
|
* if provided.
|
||||||
|
*
|
||||||
|
* Calling this for a property that is not an array, the behavior
|
||||||
|
* is undefined, so don’t do this.
|
||||||
|
*
|
||||||
|
* @param string $name The property to retrieve
|
||||||
|
* @param string $type The subclass of GraphObject, optionally
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPropertyAsArray($name, $type = 'Facebook\GraphObject')
|
||||||
|
{
|
||||||
|
$target = array();
|
||||||
|
if (isset($this->backingData[$name]['data'])) {
|
||||||
|
$target = $this->backingData[$name]['data'];
|
||||||
|
} else if (isset($this->backingData[$name])
|
||||||
|
&& !is_scalar($this->backingData[$name])) {
|
||||||
|
$target = $this->backingData[$name];
|
||||||
|
}
|
||||||
|
$out = array();
|
||||||
|
foreach ($target as $key => $value) {
|
||||||
|
if (is_scalar($value)) {
|
||||||
|
$out[$key] = $value;
|
||||||
|
} else {
|
||||||
|
$out[$key] = (new GraphObject($value))->cast($type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPropertyNames - Returns a list of all properties set on the object.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPropertyNames()
|
||||||
|
{
|
||||||
|
return array_keys($this->backingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string class name of the GraphObject or subclass.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function className()
|
||||||
|
{
|
||||||
|
return get_called_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
64
rainloop/v/0.0.0/app/libraries/Facebook/GraphPage.php
Normal file
64
rainloop/v/0.0.0/app/libraries/Facebook/GraphPage.php
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphPage
|
||||||
|
* @package Facebook
|
||||||
|
* @author Artur Luiz <artur@arturluiz.com.br>
|
||||||
|
*/
|
||||||
|
class GraphPage extends GraphObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID for the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->getProperty('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Category for the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCategory()
|
||||||
|
{
|
||||||
|
return $this->getProperty('category');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Name of the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getProperty('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
115
rainloop/v/0.0.0/app/libraries/Facebook/GraphSessionInfo.php
Normal file
115
rainloop/v/0.0.0/app/libraries/Facebook/GraphSessionInfo.php
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphSessionInfo
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class GraphSessionInfo extends GraphObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the application id the token was issued for.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getAppId()
|
||||||
|
{
|
||||||
|
return $this->getProperty('app_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the application name the token was issued for.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApplication()
|
||||||
|
{
|
||||||
|
return $this->getProperty('application');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date & time that the token expires.
|
||||||
|
*
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getExpiresAt()
|
||||||
|
{
|
||||||
|
$stamp = $this->getProperty('expires_at');
|
||||||
|
if ($stamp) {
|
||||||
|
return (new \DateTime())->setTimestamp($stamp);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the token is valid.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isValid()
|
||||||
|
{
|
||||||
|
return $this->getProperty('is_valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date & time the token was issued at.
|
||||||
|
*
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getIssuedAt()
|
||||||
|
{
|
||||||
|
$stamp = $this->getProperty('issued_at');
|
||||||
|
if ($stamp) {
|
||||||
|
return (new \DateTime())->setTimestamp($stamp);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scope permissions associated with the token.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getScopes()
|
||||||
|
{
|
||||||
|
return $this->getPropertyAsArray('scopes');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the login id of the user associated with the token.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->getProperty('user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
120
rainloop/v/0.0.0/app/libraries/Facebook/GraphUser.php
Normal file
120
rainloop/v/0.0.0/app/libraries/Facebook/GraphUser.php
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphUser
|
||||||
|
* @package Facebook
|
||||||
|
* @author Fosco Marotto <fjm@fb.com>
|
||||||
|
* @author David Poll <depoll@fb.com>
|
||||||
|
*/
|
||||||
|
class GraphUser extends GraphObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID for the user as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->getProperty('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name for the user as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getProperty('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first name for the user as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getFirstName()
|
||||||
|
{
|
||||||
|
return $this->getProperty('first_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the middle name for the user as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getMiddleName()
|
||||||
|
{
|
||||||
|
return $this->getProperty('middle_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last name for the user as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getLastName()
|
||||||
|
{
|
||||||
|
return $this->getProperty('last_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Facebook URL for the user as a string if available.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getLink()
|
||||||
|
{
|
||||||
|
return $this->getProperty('link');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the users birthday, if available.
|
||||||
|
*
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getBirthday()
|
||||||
|
{
|
||||||
|
$value = $this->getProperty('birthday');
|
||||||
|
if ($value) {
|
||||||
|
return new \DateTime($value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current location of the user as a FacebookGraphLocation
|
||||||
|
* if available.
|
||||||
|
*
|
||||||
|
* @return GraphLocation|null
|
||||||
|
*/
|
||||||
|
public function getLocation()
|
||||||
|
{
|
||||||
|
return $this->getProperty('location', GraphLocation::className());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
84
rainloop/v/0.0.0/app/libraries/Facebook/GraphUserPage.php
Normal file
84
rainloop/v/0.0.0/app/libraries/Facebook/GraphUserPage.php
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GraphUserPage
|
||||||
|
* @package Facebook
|
||||||
|
* @author Artur Luiz <artur@arturluiz.com.br>
|
||||||
|
*/
|
||||||
|
class GraphUserPage extends GraphObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID for the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->getProperty('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Category for the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCategory()
|
||||||
|
{
|
||||||
|
return $this->getProperty('category');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Name of the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getProperty('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Access Token used to access the user's page as a string if present.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getAccessToken()
|
||||||
|
{
|
||||||
|
return $this->getProperty('access_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Permissions for the user's page as an array if present.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getPermissions()
|
||||||
|
{
|
||||||
|
return $this->getProperty('perms');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\HttpClients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookCurl
|
||||||
|
* Abstraction for the procedural curl elements so that curl can be mocked
|
||||||
|
* and the implementation can be tested.
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookCurl
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var resource Curl resource instance
|
||||||
|
*/
|
||||||
|
protected $curl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a new curl reference instance
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->curl = curl_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a curl option
|
||||||
|
*
|
||||||
|
* @param $key
|
||||||
|
* @param $value
|
||||||
|
*/
|
||||||
|
public function setopt($key, $value)
|
||||||
|
{
|
||||||
|
curl_setopt($this->curl, $key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an array of options to a curl resource
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function setopt_array(array $options)
|
||||||
|
{
|
||||||
|
curl_setopt_array($this->curl, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a curl request
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function exec()
|
||||||
|
{
|
||||||
|
return curl_exec($this->curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the curl error number
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function errno()
|
||||||
|
{
|
||||||
|
return curl_errno($this->curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the curl error message
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function error()
|
||||||
|
{
|
||||||
|
return curl_error($this->curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get info from a curl reference
|
||||||
|
*
|
||||||
|
* @param $type
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getinfo($type)
|
||||||
|
{
|
||||||
|
return curl_getinfo($this->curl, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently installed curl version
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function version()
|
||||||
|
{
|
||||||
|
return curl_version();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the resource connection to curl
|
||||||
|
*/
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
curl_close($this->curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,323 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\HttpClients;
|
||||||
|
|
||||||
|
use Facebook\FacebookSDKException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookCurlHttpClient
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookCurlHttpClient implements FacebookHttpable
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The headers to be sent with the request
|
||||||
|
*/
|
||||||
|
protected $requestHeaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The headers received from the response
|
||||||
|
*/
|
||||||
|
protected $responseHeaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The HTTP status code returned from the server
|
||||||
|
*/
|
||||||
|
protected $responseHttpStatusCode = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The client error message
|
||||||
|
*/
|
||||||
|
protected $curlErrorMessage = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The curl client error code
|
||||||
|
*/
|
||||||
|
protected $curlErrorCode = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|boolean The raw response from the server
|
||||||
|
*/
|
||||||
|
protected $rawResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FacebookCurl Procedural curl as object
|
||||||
|
*/
|
||||||
|
protected static $facebookCurl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const Curl Version which is unaffected by the proxy header length error.
|
||||||
|
*/
|
||||||
|
const CURL_PROXY_QUIRK_VER = 0x071E00;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const "Connection Established" header text
|
||||||
|
*/
|
||||||
|
const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FacebookCurl|null Procedural curl as object
|
||||||
|
*/
|
||||||
|
public function __construct(FacebookCurl $facebookCurl = null)
|
||||||
|
{
|
||||||
|
self::$facebookCurl = $facebookCurl ?: new FacebookCurl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers we want to send with the request
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function addRequestHeader($key, $value)
|
||||||
|
{
|
||||||
|
$this->requestHeaders[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers returned in the response
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponseHeaders()
|
||||||
|
{
|
||||||
|
return $this->responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTTP status response code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getResponseHttpStatusCode()
|
||||||
|
{
|
||||||
|
return $this->responseHttpStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the server
|
||||||
|
*
|
||||||
|
* @param string $url The endpoint to send the request to
|
||||||
|
* @param string $method The request method
|
||||||
|
* @param array $parameters The key value pairs to be sent in the body
|
||||||
|
*
|
||||||
|
* @return string Raw response from the server
|
||||||
|
*
|
||||||
|
* @throws \Facebook\FacebookSDKException
|
||||||
|
*/
|
||||||
|
public function send($url, $method = 'GET', $parameters = array())
|
||||||
|
{
|
||||||
|
$this->openConnection($url, $method, $parameters);
|
||||||
|
$this->tryToSendRequest();
|
||||||
|
|
||||||
|
// Need to verify the peer
|
||||||
|
if ($this->curlErrorCode == 60 || $this->curlErrorCode == 77) {
|
||||||
|
$this->addBundledCert();
|
||||||
|
$this->tryToSendRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->curlErrorCode) {
|
||||||
|
throw new FacebookSDKException($this->curlErrorMessage, $this->curlErrorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate the raw headers from the raw body
|
||||||
|
list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody();
|
||||||
|
|
||||||
|
$this->responseHeaders = self::headersToArray($rawHeaders);
|
||||||
|
|
||||||
|
$this->closeConnection();
|
||||||
|
|
||||||
|
return $rawBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a new curl connection
|
||||||
|
*
|
||||||
|
* @param string $url The endpoint to send the request to
|
||||||
|
* @param string $method The request method
|
||||||
|
* @param array $parameters The key value pairs to be sent in the body
|
||||||
|
*/
|
||||||
|
public function openConnection($url, $method = 'GET', $parameters = array())
|
||||||
|
{
|
||||||
|
$options = array(
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_CONNECTTIMEOUT => 10,
|
||||||
|
CURLOPT_TIMEOUT => 60,
|
||||||
|
CURLOPT_RETURNTRANSFER => true, // Follow 301 redirects
|
||||||
|
CURLOPT_HEADER => true, // Enable header processing
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($method !== "GET") {
|
||||||
|
$options[CURLOPT_POSTFIELDS] = $parameters;
|
||||||
|
}
|
||||||
|
if ($method === 'DELETE' || $method === 'PUT') {
|
||||||
|
$options[CURLOPT_CUSTOMREQUEST] = $method;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->requestHeaders)) {
|
||||||
|
$options[CURLOPT_HTTPHEADER] = $this->compileRequestHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$facebookCurl->init();
|
||||||
|
self::$facebookCurl->setopt_array($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a bundled cert to the connection
|
||||||
|
*/
|
||||||
|
public function addBundledCert()
|
||||||
|
{
|
||||||
|
self::$facebookCurl->setopt(CURLOPT_CAINFO,
|
||||||
|
dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fb_ca_chain_bundle.crt');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes an existing curl connection
|
||||||
|
*/
|
||||||
|
public function closeConnection()
|
||||||
|
{
|
||||||
|
self::$facebookCurl->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to send the request
|
||||||
|
*/
|
||||||
|
public function tryToSendRequest()
|
||||||
|
{
|
||||||
|
$this->sendRequest();
|
||||||
|
$this->curlErrorMessage = self::$facebookCurl->error();
|
||||||
|
$this->curlErrorCode = self::$facebookCurl->errno();
|
||||||
|
$this->responseHttpStatusCode = self::$facebookCurl->getinfo(CURLINFO_HTTP_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the request and get the raw response from curl
|
||||||
|
*/
|
||||||
|
public function sendRequest()
|
||||||
|
{
|
||||||
|
$this->rawResponse = self::$facebookCurl->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the request headers into a curl-friendly format
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function compileRequestHeaders()
|
||||||
|
{
|
||||||
|
$return = array();
|
||||||
|
|
||||||
|
foreach ($this->requestHeaders as $key => $value) {
|
||||||
|
$return[] = $key . ': ' . $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the headers and the body into a two-part array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function extractResponseHeadersAndBody()
|
||||||
|
{
|
||||||
|
$headerSize = self::getHeaderSize();
|
||||||
|
|
||||||
|
$rawHeaders = mb_substr($this->rawResponse, 0, $headerSize);
|
||||||
|
$rawBody = mb_substr($this->rawResponse, $headerSize);
|
||||||
|
|
||||||
|
return array(trim($rawHeaders), trim($rawBody));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts raw header responses into an array
|
||||||
|
*
|
||||||
|
* @param string $rawHeaders
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function headersToArray($rawHeaders)
|
||||||
|
{
|
||||||
|
$headers = array();
|
||||||
|
|
||||||
|
// Normalize line breaks
|
||||||
|
$rawHeaders = str_replace("\r\n", "\n", $rawHeaders);
|
||||||
|
|
||||||
|
// There will be multiple headers if a 301 was followed
|
||||||
|
// or a proxy was followed, etc
|
||||||
|
$headerCollection = explode("\n\n", trim($rawHeaders));
|
||||||
|
// We just want the last response (at the end)
|
||||||
|
$rawHeader = array_pop($headerCollection);
|
||||||
|
|
||||||
|
$headerComponents = explode("\n", $rawHeader);
|
||||||
|
foreach ($headerComponents as $line) {
|
||||||
|
if (strpos($line, ': ') === false) {
|
||||||
|
$headers['http_code'] = $line;
|
||||||
|
} else {
|
||||||
|
list ($key, $value) = explode(': ', $line);
|
||||||
|
$headers[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return proper header size
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
private function getHeaderSize()
|
||||||
|
{
|
||||||
|
$headerSize = self::$facebookCurl->getinfo(CURLINFO_HEADER_SIZE);
|
||||||
|
// This corrects a Curl bug where header size does not account
|
||||||
|
// for additional Proxy headers.
|
||||||
|
if ( self::needsCurlProxyFix() ) {
|
||||||
|
// Additional way to calculate the request body size.
|
||||||
|
if (preg_match('/Content-Length: (\d+)/', $this->rawResponse, $m)) {
|
||||||
|
$headerSize = mb_strlen($this->rawResponse) - $m[1];
|
||||||
|
} elseif (stripos($this->rawResponse, self::CONNECTION_ESTABLISHED) !== false) {
|
||||||
|
$headerSize += mb_strlen(self::CONNECTION_ESTABLISHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect versions of Curl which report incorrect header lengths when
|
||||||
|
* using Proxies.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private static function needsCurlProxyFix()
|
||||||
|
{
|
||||||
|
$ver = self::$facebookCurl->version();
|
||||||
|
$version = $ver['version_number'];
|
||||||
|
|
||||||
|
return $version < self::CURL_PROXY_QUIRK_VER;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\HttpClients;
|
||||||
|
|
||||||
|
use Facebook\FacebookSDKException;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
class FacebookGuzzleHttpClient implements FacebookHttpable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The headers to be sent with the request
|
||||||
|
*/
|
||||||
|
protected $requestHeaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The headers received from the response
|
||||||
|
*/
|
||||||
|
protected $responseHeaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The HTTP status code returned from the server
|
||||||
|
*/
|
||||||
|
protected $responseHttpStatusCode = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \GuzzleHttp\Client The Guzzle client
|
||||||
|
*/
|
||||||
|
protected static $guzzleClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \GuzzleHttp\Client|null The Guzzle client
|
||||||
|
*/
|
||||||
|
public function __construct(Client $guzzleClient = null)
|
||||||
|
{
|
||||||
|
self::$guzzleClient = $guzzleClient ?: new Client();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers we want to send with the request
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function addRequestHeader($key, $value)
|
||||||
|
{
|
||||||
|
$this->requestHeaders[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers returned in the response
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponseHeaders()
|
||||||
|
{
|
||||||
|
return $this->responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTTP status response code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getResponseHttpStatusCode()
|
||||||
|
{
|
||||||
|
return $this->responseHttpStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the server
|
||||||
|
*
|
||||||
|
* @param string $url The endpoint to send the request to
|
||||||
|
* @param string $method The request method
|
||||||
|
* @param array $parameters The key value pairs to be sent in the body
|
||||||
|
*
|
||||||
|
* @return string Raw response from the server
|
||||||
|
*
|
||||||
|
* @throws \Facebook\FacebookSDKException
|
||||||
|
*/
|
||||||
|
public function send($url, $method = 'GET', $parameters = array())
|
||||||
|
{
|
||||||
|
$options = array();
|
||||||
|
if ($parameters) {
|
||||||
|
$options = array('body' => $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = self::$guzzleClient->createRequest($method, $url, $options);
|
||||||
|
|
||||||
|
foreach($this->requestHeaders as $k => $v) {
|
||||||
|
$request->setHeader($k, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$rawResponse = self::$guzzleClient->send($request);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
if ($e->getPrevious() instanceof AdapterException) {
|
||||||
|
throw new FacebookSDKException($e->getMessage(), $e->getCode());
|
||||||
|
}
|
||||||
|
$rawResponse = $e->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->responseHttpStatusCode = $rawResponse->getStatusCode();
|
||||||
|
$this->responseHeaders = $rawResponse->getHeaders();
|
||||||
|
|
||||||
|
return $rawResponse->getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\HttpClients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface FacebookHttpable
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
interface FacebookHttpable
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers we want to send with the request
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function addRequestHeader($key, $value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers returned in the response
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponseHeaders();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTTP status response code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getResponseHttpStatusCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the server
|
||||||
|
*
|
||||||
|
* @param string $url The endpoint to send the request to
|
||||||
|
* @param string $method The request method
|
||||||
|
* @param array $parameters The key value pairs to be sent in the body
|
||||||
|
*
|
||||||
|
* @return string Raw response from the server
|
||||||
|
*
|
||||||
|
* @throws \Facebook\FacebookSDKException
|
||||||
|
*/
|
||||||
|
public function send($url, $method = 'GET', $parameters = array());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\HttpClients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FacebookStream
|
||||||
|
* Abstraction for the procedural stream elements so that the functions can be
|
||||||
|
* mocked and the implementation can be tested.
|
||||||
|
* @package Facebook
|
||||||
|
*/
|
||||||
|
class FacebookStream
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var resource Context stream resource instance
|
||||||
|
*/
|
||||||
|
protected $stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Response headers from the stream wrapper
|
||||||
|
*/
|
||||||
|
protected $responseHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a new context stream reference instance
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function streamContextCreate(array $options)
|
||||||
|
{
|
||||||
|
$this->stream = stream_context_create($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The response headers from the stream wrapper
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getResponseHeaders()
|
||||||
|
{
|
||||||
|
return $this->responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a stream wrapped request
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function fileGetContents($url)
|
||||||
|
{
|
||||||
|
$rawResponse = file_get_contents($url, false, $this->stream);
|
||||||
|
$this->responseHeaders = $http_response_header;
|
||||||
|
return $rawResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2014 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
|
||||||
|
* use, copy, modify, and distribute this software in source code or binary
|
||||||
|
* form for use in connection with the web services and APIs provided by
|
||||||
|
* Facebook.
|
||||||
|
*
|
||||||
|
* As with any software that integrates with the Facebook platform, your use
|
||||||
|
* of this software is subject to the Facebook Developer Principles and
|
||||||
|
* Policies [http://developers.facebook.com/policy/]. This copyright notice
|
||||||
|
* shall be included in all copies or substantial portions of the software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Facebook\HttpClients;
|
||||||
|
|
||||||
|
use Facebook\FacebookSDKException;
|
||||||
|
|
||||||
|
class FacebookStreamHttpClient implements FacebookHttpable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The headers to be sent with the request
|
||||||
|
*/
|
||||||
|
protected $requestHeaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array The headers received from the response
|
||||||
|
*/
|
||||||
|
protected $responseHeaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The HTTP status code returned from the server
|
||||||
|
*/
|
||||||
|
protected $responseHttpStatusCode = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FacebookStream Procedural stream wrapper as object
|
||||||
|
*/
|
||||||
|
protected static $facebookStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FacebookStream|null Procedural stream wrapper as object
|
||||||
|
*/
|
||||||
|
public function __construct(FacebookStream $facebookStream = null)
|
||||||
|
{
|
||||||
|
self::$facebookStream = $facebookStream ?: new FacebookStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers we want to send with the request
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function addRequestHeader($key, $value)
|
||||||
|
{
|
||||||
|
$this->requestHeaders[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers returned in the response
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponseHeaders()
|
||||||
|
{
|
||||||
|
return $this->responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTTP status response code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getResponseHttpStatusCode()
|
||||||
|
{
|
||||||
|
return $this->responseHttpStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the server
|
||||||
|
*
|
||||||
|
* @param string $url The endpoint to send the request to
|
||||||
|
* @param string $method The request method
|
||||||
|
* @param array $parameters The key value pairs to be sent in the body
|
||||||
|
*
|
||||||
|
* @return string Raw response from the server
|
||||||
|
*
|
||||||
|
* @throws \Facebook\FacebookSDKException
|
||||||
|
*/
|
||||||
|
public function send($url, $method = 'GET', $parameters = array())
|
||||||
|
{
|
||||||
|
$options = array(
|
||||||
|
'http' => array(
|
||||||
|
'method' => $method,
|
||||||
|
'timeout' => 60,
|
||||||
|
'ignore_errors' => true
|
||||||
|
),
|
||||||
|
'ssl' => array(
|
||||||
|
'verify_peer' => true,
|
||||||
|
'cafile' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fb_ca_chain_bundle.crt',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($parameters) {
|
||||||
|
$options['http']['content'] = http_build_query($parameters, null, '&');
|
||||||
|
|
||||||
|
$this->addRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['http']['header'] = $this->compileHeader();
|
||||||
|
|
||||||
|
self::$facebookStream->streamContextCreate($options);
|
||||||
|
$rawResponse = self::$facebookStream->fileGetContents($url);
|
||||||
|
$rawHeaders = self::$facebookStream->getResponseHeaders();
|
||||||
|
|
||||||
|
if ($rawResponse === false || !$rawHeaders) {
|
||||||
|
throw new FacebookSDKException('Stream returned an empty response', 660);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->responseHeaders = self::formatHeadersToArray($rawHeaders);
|
||||||
|
$this->responseHttpStatusCode = self::getStatusCodeFromHeader($this->responseHeaders['http_code']);
|
||||||
|
|
||||||
|
return $rawResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the headers for use in the stream wrapper
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function compileHeader()
|
||||||
|
{
|
||||||
|
$header = [];
|
||||||
|
foreach($this->requestHeaders as $k => $v) {
|
||||||
|
$header[] = $k . ': ' . $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode("\r\n", $header);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts array of headers returned from the wrapper into
|
||||||
|
* something standard
|
||||||
|
*
|
||||||
|
* @param array $rawHeaders
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function formatHeadersToArray(array $rawHeaders)
|
||||||
|
{
|
||||||
|
$headers = array();
|
||||||
|
|
||||||
|
foreach ($rawHeaders as $line) {
|
||||||
|
if (strpos($line, ':') === false) {
|
||||||
|
$headers['http_code'] = $line;
|
||||||
|
} else {
|
||||||
|
list ($key, $value) = explode(': ', $line);
|
||||||
|
$headers[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pulls out the HTTP status code from a response header
|
||||||
|
*
|
||||||
|
* @param string $header
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function getStatusCodeFromHeader($header)
|
||||||
|
{
|
||||||
|
preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $header, $match);
|
||||||
|
return (int) $match[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter interface used to transfer HTTP requests.
|
||||||
|
*
|
||||||
|
* @link http://docs.guzzlephp.org/en/guzzle4/adapters.html for a full
|
||||||
|
* explanation of adapters and their responsibilities.
|
||||||
|
*/
|
||||||
|
interface AdapterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transfers an HTTP request and populates a response
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction Transaction abject to populate
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
public function send(TransactionInterface $transaction);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter\Curl;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides context for a Curl transaction, including active handles,
|
||||||
|
* pending transactions, and whether or not this is a batch or single
|
||||||
|
* transaction.
|
||||||
|
*/
|
||||||
|
class BatchContext
|
||||||
|
{
|
||||||
|
/** @var resource Curl multi resource */
|
||||||
|
private $multi;
|
||||||
|
|
||||||
|
/** @var \SplObjectStorage Map of transactions to curl resources */
|
||||||
|
private $handles;
|
||||||
|
|
||||||
|
/** @var \Iterator Yields pending transactions */
|
||||||
|
private $pending;
|
||||||
|
|
||||||
|
/** @var bool Whether or not to throw transactions */
|
||||||
|
private $throwsExceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resource $multiHandle Initialized curl_multi resource
|
||||||
|
* @param bool $throwsExceptions Whether or not exceptions are thrown
|
||||||
|
* @param \Iterator $pending Iterator yielding pending transactions
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$multiHandle,
|
||||||
|
$throwsExceptions,
|
||||||
|
\Iterator $pending = null
|
||||||
|
) {
|
||||||
|
$this->multi = $multiHandle;
|
||||||
|
$this->handles = new \SplObjectStorage();
|
||||||
|
$this->throwsExceptions = $throwsExceptions;
|
||||||
|
$this->pending = $pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a transaction for a given curl handle
|
||||||
|
*
|
||||||
|
* @param resource $handle Curl handle
|
||||||
|
*
|
||||||
|
* @return TransactionInterface
|
||||||
|
* @throws AdapterException if a transaction is not found
|
||||||
|
*/
|
||||||
|
public function findTransaction($handle)
|
||||||
|
{
|
||||||
|
foreach ($this->handles as $transaction) {
|
||||||
|
if ($this->handles[$transaction] === $handle) {
|
||||||
|
return $transaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AdapterException('No curl handle was found');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there are any remaining pending transactions
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasPending()
|
||||||
|
{
|
||||||
|
return $this->pending && $this->pending->valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop the next transaction from the transaction queue
|
||||||
|
*
|
||||||
|
* @return TransactionInterface|null
|
||||||
|
*/
|
||||||
|
public function nextPending()
|
||||||
|
{
|
||||||
|
if (!$this->hasPending()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current = $this->pending->current();
|
||||||
|
$this->pending->next();
|
||||||
|
|
||||||
|
return $current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the batch is to throw exceptions on error
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function throwsExceptions()
|
||||||
|
{
|
||||||
|
return $this->throwsExceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the curl_multi handle
|
||||||
|
*
|
||||||
|
* @return resource
|
||||||
|
*/
|
||||||
|
public function getMultiHandle()
|
||||||
|
{
|
||||||
|
return $this->multi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a transaction to the multi handle
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction Transaction to add
|
||||||
|
* @param resource $handle Resource to use with the handle
|
||||||
|
*
|
||||||
|
* @throws AdapterException If the handle is already registered
|
||||||
|
*/
|
||||||
|
public function addTransaction(TransactionInterface $transaction, $handle)
|
||||||
|
{
|
||||||
|
if (isset($this->handles[$transaction])) {
|
||||||
|
throw new AdapterException('Transaction already registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = curl_multi_add_handle($this->multi, $handle);
|
||||||
|
if ($code != CURLM_OK) {
|
||||||
|
MultiAdapter::throwMultiError($code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handles[$transaction] = $handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a transaction and associated handle from the context
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction Transaction to remove
|
||||||
|
*
|
||||||
|
* @return array Returns the curl_getinfo array
|
||||||
|
* @throws AdapterException if the transaction is not found
|
||||||
|
*/
|
||||||
|
public function removeTransaction(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
if (!isset($this->handles[$transaction])) {
|
||||||
|
throw new AdapterException('Transaction not registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
$handle = $this->handles[$transaction];
|
||||||
|
|
||||||
|
$code = curl_multi_remove_handle($this->multi, $handle);
|
||||||
|
if ($code != CURLM_OK) {
|
||||||
|
MultiAdapter::throwMultiError($code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = curl_getinfo($handle);
|
||||||
|
curl_close($handle);
|
||||||
|
unset($this->handles[$transaction]);
|
||||||
|
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter\Curl;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\AdapterInterface;
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Event\RequestEvents;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
use GuzzleHttp\Message\MessageFactoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP adapter that uses cURL easy handles as a transport layer.
|
||||||
|
*
|
||||||
|
* Requires PHP 5.5+
|
||||||
|
*
|
||||||
|
* When using the CurlAdapter, custom curl options can be specified as an
|
||||||
|
* associative array of curl option constants mapping to values in the
|
||||||
|
* **curl** key of a request's configuration options.
|
||||||
|
*/
|
||||||
|
class CurlAdapter implements AdapterInterface
|
||||||
|
{
|
||||||
|
/** @var CurlFactory */
|
||||||
|
private $curlFactory;
|
||||||
|
|
||||||
|
/** @var MessageFactoryInterface */
|
||||||
|
private $messageFactory;
|
||||||
|
|
||||||
|
/** @var array Array of curl easy handles */
|
||||||
|
private $handles = [];
|
||||||
|
|
||||||
|
/** @var array Array of owned curl easy handles */
|
||||||
|
private $ownedHandles = [];
|
||||||
|
|
||||||
|
/** @var int Total number of idle handles to keep in cache */
|
||||||
|
private $maxHandles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts an associative array of options:
|
||||||
|
*
|
||||||
|
* - handle_factory: Optional callable factory used to create cURL handles.
|
||||||
|
* The callable is invoked with the following arguments:
|
||||||
|
* TransactionInterface, MessageFactoryInterface, and an optional cURL
|
||||||
|
* handle to modify. The factory method must then return a cURL resource.
|
||||||
|
* - max_handles: Maximum number of idle handles (defaults to 5).
|
||||||
|
*
|
||||||
|
* @param MessageFactoryInterface $messageFactory
|
||||||
|
* @param array $options Array of options to use with the adapter
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
MessageFactoryInterface $messageFactory,
|
||||||
|
array $options = []
|
||||||
|
) {
|
||||||
|
$this->handles = $this->ownedHandles = [];
|
||||||
|
$this->messageFactory = $messageFactory;
|
||||||
|
$this->curlFactory = isset($options['handle_factory'])
|
||||||
|
? $options['handle_factory']
|
||||||
|
: new CurlFactory();
|
||||||
|
$this->maxHandles = isset($options['max_handles'])
|
||||||
|
? $options['max_handles']
|
||||||
|
: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
foreach ($this->handles as $handle) {
|
||||||
|
if (is_resource($handle)) {
|
||||||
|
curl_close($handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
RequestEvents::emitBefore($transaction);
|
||||||
|
if ($response = $transaction->getResponse()) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$factory = $this->curlFactory;
|
||||||
|
$handle = $factory(
|
||||||
|
$transaction,
|
||||||
|
$this->messageFactory,
|
||||||
|
$this->checkoutEasyHandle()
|
||||||
|
);
|
||||||
|
|
||||||
|
curl_exec($handle);
|
||||||
|
$info = curl_getinfo($handle);
|
||||||
|
$info['curl_result'] = curl_errno($handle);
|
||||||
|
|
||||||
|
if ($info['curl_result']) {
|
||||||
|
$this->handleError($transaction, $info, $handle);
|
||||||
|
} else {
|
||||||
|
$this->releaseEasyHandle($handle);
|
||||||
|
RequestEvents::emitComplete($transaction, $info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transaction->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleError(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
$info,
|
||||||
|
$handle
|
||||||
|
) {
|
||||||
|
$error = curl_error($handle);
|
||||||
|
$this->releaseEasyHandle($handle);
|
||||||
|
RequestEvents::emitError(
|
||||||
|
$transaction,
|
||||||
|
new AdapterException("cURL error {$info['curl_result']}: {$error}"),
|
||||||
|
$info
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkoutEasyHandle()
|
||||||
|
{
|
||||||
|
// Find an unused handle in the cache
|
||||||
|
if (false !== ($key = array_search(false, $this->ownedHandles, true))) {
|
||||||
|
$this->ownedHandles[$key] = true;
|
||||||
|
return $this->handles[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new handle
|
||||||
|
$handle = curl_init();
|
||||||
|
$id = (int) $handle;
|
||||||
|
$this->handles[$id] = $handle;
|
||||||
|
$this->ownedHandles[$id] = true;
|
||||||
|
|
||||||
|
return $handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function releaseEasyHandle($handle)
|
||||||
|
{
|
||||||
|
$id = (int) $handle;
|
||||||
|
if (count($this->ownedHandles) > $this->maxHandles) {
|
||||||
|
curl_close($this->handles[$id]);
|
||||||
|
unset($this->handles[$id], $this->ownedHandles[$id]);
|
||||||
|
} else {
|
||||||
|
curl_reset($handle);
|
||||||
|
$this->ownedHandles[$id] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,331 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter\Curl;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Message\MessageFactoryInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Stream;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates curl resources from a request and response object
|
||||||
|
*/
|
||||||
|
class CurlFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a cURL handle based on a transaction.
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction Holds a request and response
|
||||||
|
* @param MessageFactoryInterface $messageFactory Used to create responses
|
||||||
|
* @param null|resource $handle Optionally provide a curl handle to modify
|
||||||
|
*
|
||||||
|
* @return resource Returns a prepared cURL handle
|
||||||
|
* @throws AdapterException when an option cannot be applied
|
||||||
|
*/
|
||||||
|
public function __invoke(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
MessageFactoryInterface $messageFactory,
|
||||||
|
$handle = null
|
||||||
|
) {
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
$mediator = new RequestMediator($transaction, $messageFactory);
|
||||||
|
$options = $this->getDefaultOptions($request, $mediator);
|
||||||
|
$this->applyMethod($request, $options);
|
||||||
|
$this->applyTransferOptions($request, $mediator, $options);
|
||||||
|
$this->applyHeaders($request, $options);
|
||||||
|
unset($options['_headers']);
|
||||||
|
|
||||||
|
// Add adapter options from the request's configuration options
|
||||||
|
if ($config = $request->getConfig()['curl']) {
|
||||||
|
$options = $this->applyCustomCurlOptions($config, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$handle) {
|
||||||
|
$handle = curl_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt_array($handle, $options);
|
||||||
|
|
||||||
|
return $handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultOptions(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator
|
||||||
|
) {
|
||||||
|
$url = $request->getUrl();
|
||||||
|
|
||||||
|
// Strip fragment from URL. See:
|
||||||
|
// https://github.com/guzzle/guzzle/issues/453
|
||||||
|
if (($pos = strpos($url, '#')) !== false) {
|
||||||
|
$url = substr($url, 0, $pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = $request->getConfig();
|
||||||
|
$options = array(
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_CONNECTTIMEOUT => $config['connect_timeout'] ?: 150,
|
||||||
|
CURLOPT_RETURNTRANSFER => false,
|
||||||
|
CURLOPT_HEADER => false,
|
||||||
|
CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'),
|
||||||
|
CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'),
|
||||||
|
CURLOPT_READFUNCTION => array($mediator, 'readRequestBody'),
|
||||||
|
CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0'
|
||||||
|
? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => 1,
|
||||||
|
CURLOPT_SSL_VERIFYHOST => 2,
|
||||||
|
'_headers' => $request->getHeaders()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (defined('CURLOPT_PROTOCOLS')) {
|
||||||
|
// Allow only HTTP and HTTPS protocols
|
||||||
|
$options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CURLOPT_ENCODING if Accept-Encoding header is provided
|
||||||
|
if ($request->hasHeader('Accept-Encoding')) {
|
||||||
|
$options[CURLOPT_ENCODING] = $request->getHeader('Accept-Encoding');
|
||||||
|
// Let cURL set the Accept-Encoding header. Without this change
|
||||||
|
// curl could add a duplicate value.
|
||||||
|
$this->removeHeader('Accept-Encoding', $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyMethod(RequestInterface $request, array &$options)
|
||||||
|
{
|
||||||
|
$method = $request->getMethod();
|
||||||
|
if ($method == 'HEAD') {
|
||||||
|
$options[CURLOPT_NOBODY] = true;
|
||||||
|
unset($options[CURLOPT_WRITEFUNCTION], $options[CURLOPT_READFUNCTION]);
|
||||||
|
} else {
|
||||||
|
$options[CURLOPT_CUSTOMREQUEST] = $method;
|
||||||
|
if (!$request->getBody()) {
|
||||||
|
unset($options[CURLOPT_READFUNCTION]);
|
||||||
|
} else {
|
||||||
|
$this->applyBody($request, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyBody(RequestInterface $request, array &$options)
|
||||||
|
{
|
||||||
|
if ($request->hasHeader('Content-Length')) {
|
||||||
|
$size = (int) $request->getHeader('Content-Length');
|
||||||
|
} else {
|
||||||
|
$size = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->getBody()->seek(0);
|
||||||
|
|
||||||
|
// You can send the body as a string using curl's CURLOPT_POSTFIELDS
|
||||||
|
if (($size !== null && $size < 32768) ||
|
||||||
|
isset($request->getConfig()['curl']['body_as_string'])
|
||||||
|
) {
|
||||||
|
$options[CURLOPT_POSTFIELDS] = $request->getBody()->getContents();
|
||||||
|
// Don't duplicate the Content-Length header
|
||||||
|
$this->removeHeader('Content-Length', $options);
|
||||||
|
$this->removeHeader('Transfer-Encoding', $options);
|
||||||
|
} else {
|
||||||
|
$options[CURLOPT_UPLOAD] = true;
|
||||||
|
// Let cURL handle setting the Content-Length header
|
||||||
|
if ($size !== null) {
|
||||||
|
$options[CURLOPT_INFILESIZE] = $size;
|
||||||
|
$this->removeHeader('Content-Length', $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the Expect header is not present, prevent curl from adding it
|
||||||
|
if (!$request->hasHeader('Expect')) {
|
||||||
|
$options[CURLOPT_HTTPHEADER][] = 'Expect:';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyHeaders(RequestInterface $request, array &$options)
|
||||||
|
{
|
||||||
|
foreach ($options['_headers'] as $name => $values) {
|
||||||
|
$options[CURLOPT_HTTPHEADER][] = $name . ': ' . implode(', ', $values);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the Expect header if one was not set
|
||||||
|
if (!$request->hasHeader('Accept')) {
|
||||||
|
$options[CURLOPT_HTTPHEADER][] = 'Accept:';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyTransferOptions(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
array &$options
|
||||||
|
) {
|
||||||
|
static $methods;
|
||||||
|
if (!$methods) {
|
||||||
|
$methods = array_flip(get_class_methods(__CLASS__));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($request->getConfig()->toArray() as $key => $value) {
|
||||||
|
$method = "add_{$key}";
|
||||||
|
if (isset($methods[$method])) {
|
||||||
|
$this->{$method}($request, $mediator, $options, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_debug(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
if ($value) {
|
||||||
|
$options[CURLOPT_STDERR] = is_resource($value) ? $value : STDOUT;
|
||||||
|
$options[CURLOPT_VERBOSE] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_proxy(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
$options[CURLOPT_PROXY] = $value;
|
||||||
|
} else {
|
||||||
|
$scheme = $request->getScheme();
|
||||||
|
if (isset($value[$scheme])) {
|
||||||
|
$options[CURLOPT_PROXY] = $value[$scheme];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_timeout(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
$options[CURLOPT_TIMEOUT_MS] = $value * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_connect_timeout(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
$options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_verify(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
if ($value === false) {
|
||||||
|
unset($options[CURLOPT_CAINFO]);
|
||||||
|
$options[CURLOPT_SSL_VERIFYHOST] = 0;
|
||||||
|
$options[CURLOPT_SSL_VERIFYPEER] = false;
|
||||||
|
} elseif ($value === true || is_string($value)) {
|
||||||
|
$options[CURLOPT_SSL_VERIFYHOST] = 2;
|
||||||
|
$options[CURLOPT_SSL_VERIFYPEER] = true;
|
||||||
|
if ($value !== true) {
|
||||||
|
if (!file_exists($value)) {
|
||||||
|
throw new AdapterException('SSL certificate authority file'
|
||||||
|
. " not found: {$value}");
|
||||||
|
}
|
||||||
|
$options[CURLOPT_CAINFO] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_cert(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
if (!file_exists($value)) {
|
||||||
|
throw new AdapterException("SSL certificate not found: {$value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$options[CURLOPT_SSLCERT] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_ssl_key(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$options[CURLOPT_SSLKEYPASSWD] = $value[1];
|
||||||
|
$value = $value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($value)) {
|
||||||
|
throw new AdapterException("SSL private key not found: {$value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$options[CURLOPT_SSLKEY] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_save_to(
|
||||||
|
RequestInterface $request,
|
||||||
|
RequestMediator $mediator,
|
||||||
|
&$options,
|
||||||
|
$value
|
||||||
|
) {
|
||||||
|
$mediator->setResponseBody(is_string($value)
|
||||||
|
? Stream\create(fopen($value, 'w'))
|
||||||
|
: Stream\create($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an array of curl options specified in the 'curl' option of a
|
||||||
|
* request's configuration array and maps them to CURLOPT_* options.
|
||||||
|
*
|
||||||
|
* This method is only called when a request has a 'curl' config setting.
|
||||||
|
* Array key strings that start with CURL that have a matching constant
|
||||||
|
* value will be automatically converted to the matching constant.
|
||||||
|
*
|
||||||
|
* @param array $config Configuration array of custom curl option
|
||||||
|
* @param array $options Array of existing curl options
|
||||||
|
*
|
||||||
|
* @return array Returns a new array of curl options
|
||||||
|
*/
|
||||||
|
private function applyCustomCurlOptions(array $config, array $options)
|
||||||
|
{
|
||||||
|
unset($config['body_as_string']);
|
||||||
|
$curlOptions = [];
|
||||||
|
|
||||||
|
// Map curl constant strings to defined values
|
||||||
|
foreach ($config as $key => $value) {
|
||||||
|
if (defined($key) && substr($key, 0, 4) === 'CURL') {
|
||||||
|
$key = constant($key);
|
||||||
|
}
|
||||||
|
$curlOptions[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $curlOptions + $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a header from the options array
|
||||||
|
*
|
||||||
|
* @param string $name Case-insensitive header to remove
|
||||||
|
* @param array $options Array of options to modify
|
||||||
|
*/
|
||||||
|
private function removeHeader($name, array &$options)
|
||||||
|
{
|
||||||
|
foreach (array_keys($options['_headers']) as $key) {
|
||||||
|
if (!strcasecmp($key, $name)) {
|
||||||
|
unset($options['_headers'][$key]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter\Curl;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\AdapterInterface;
|
||||||
|
use GuzzleHttp\Adapter\ParallelAdapterInterface;
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Event\RequestEvents;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use GuzzleHttp\Message\MessageFactoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP adapter that uses cURL multi as a transport layer
|
||||||
|
*
|
||||||
|
* When using the CurlAdapter, custom curl options can be specified as an
|
||||||
|
* associative array of curl option constants mapping to values in the
|
||||||
|
* **curl** key of a request's configuration options.
|
||||||
|
*
|
||||||
|
* In addition to being able to supply configuration options via the curl
|
||||||
|
* request config, you can also specify the select_timeout variable using the
|
||||||
|
* `GUZZLE_CURL_SELECT_TIMEOUT` environment variable.
|
||||||
|
*/
|
||||||
|
class MultiAdapter implements AdapterInterface, ParallelAdapterInterface
|
||||||
|
{
|
||||||
|
const ERROR_STR = 'See http://curl.haxx.se/libcurl/c/libcurl-errors.html for an explanation of cURL errors';
|
||||||
|
const ENV_SELECT_TIMEOUT = 'GUZZLE_CURL_SELECT_TIMEOUT';
|
||||||
|
|
||||||
|
/** @var CurlFactory */
|
||||||
|
private $curlFactory;
|
||||||
|
|
||||||
|
/** @var MessageFactoryInterface */
|
||||||
|
private $messageFactory;
|
||||||
|
|
||||||
|
/** @var array Array of curl multi handles */
|
||||||
|
private $multiHandles = [];
|
||||||
|
|
||||||
|
/** @var array Array of curl multi handles */
|
||||||
|
private $multiOwned = [];
|
||||||
|
|
||||||
|
/** @var double */
|
||||||
|
private $selectTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts an associative array of options:
|
||||||
|
*
|
||||||
|
* - handle_factory: Optional callable factory used to create cURL handles.
|
||||||
|
* The callable is invoked with the following arguments:
|
||||||
|
* TransactionInterface, MessageFactoryInterface, and an optional cURL
|
||||||
|
* handle to modify. The factory method must then return a cURL resource.
|
||||||
|
* - select_timeout: Specify a float in seconds to use for a
|
||||||
|
* curl_multi_select timeout.
|
||||||
|
*
|
||||||
|
* @param MessageFactoryInterface $messageFactory
|
||||||
|
* @param array $options Array of options to use with the adapter:
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
MessageFactoryInterface $messageFactory,
|
||||||
|
array $options = []
|
||||||
|
) {
|
||||||
|
$this->messageFactory = $messageFactory;
|
||||||
|
$this->curlFactory = isset($options['handle_factory'])
|
||||||
|
? $options['handle_factory']
|
||||||
|
: new CurlFactory();
|
||||||
|
|
||||||
|
if (isset($options['select_timeout'])) {
|
||||||
|
$this->selectTimeout = $options['select_timeout'];
|
||||||
|
} elseif (isset($_SERVER[self::ENV_SELECT_TIMEOUT])) {
|
||||||
|
$this->selectTimeout = $_SERVER[self::ENV_SELECT_TIMEOUT];
|
||||||
|
} else {
|
||||||
|
$this->selectTimeout = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
foreach ($this->multiHandles as $handle) {
|
||||||
|
if (is_resource($handle)) {
|
||||||
|
curl_multi_close($handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an exception for a cURL multi response
|
||||||
|
*
|
||||||
|
* @param int $code Curl response code
|
||||||
|
* @throws AdapterException
|
||||||
|
*/
|
||||||
|
public static function throwMultiError($code)
|
||||||
|
{
|
||||||
|
$buffer = function_exists('curl_multi_strerror')
|
||||||
|
? curl_multi_strerror($code)
|
||||||
|
: self::ERROR_STR;
|
||||||
|
|
||||||
|
throw new AdapterException(sprintf('cURL error %s: %s', $code, $buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
$context = new BatchContext($this->checkoutMultiHandle(), true);
|
||||||
|
$this->addHandle($transaction, $context);
|
||||||
|
$this->perform($context);
|
||||||
|
|
||||||
|
return $transaction->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendAll(\Iterator $transactions, $parallel)
|
||||||
|
{
|
||||||
|
$context = new BatchContext(
|
||||||
|
$this->checkoutMultiHandle(),
|
||||||
|
false,
|
||||||
|
$transactions
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (new \LimitIterator($transactions, 0, $parallel) as $trans) {
|
||||||
|
$this->addHandle($trans, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->perform($context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function perform(BatchContext $context)
|
||||||
|
{
|
||||||
|
// The first curl_multi_select often times out no matter what, but is
|
||||||
|
// usually required for fast transfers.
|
||||||
|
$active = false;
|
||||||
|
$multi = $context->getMultiHandle();
|
||||||
|
|
||||||
|
do {
|
||||||
|
while (($mrc = curl_multi_exec($multi, $active)) == CURLM_CALL_MULTI_PERFORM);
|
||||||
|
if ($mrc != CURLM_OK && $mrc != CURLM_CALL_MULTI_PERFORM) {
|
||||||
|
self::throwMultiError($mrc);
|
||||||
|
}
|
||||||
|
// Need to check if there are pending transactions before processing
|
||||||
|
// them so that we don't bail from the loop too early.
|
||||||
|
$pending = $context->hasPending();
|
||||||
|
$this->processMessages($context);
|
||||||
|
if ($active && curl_multi_select($multi, $this->selectTimeout) === -1) {
|
||||||
|
// Perform a usleep if a select returns -1.
|
||||||
|
// See: https://bugs.php.net/bug.php?id=61141
|
||||||
|
usleep(250);
|
||||||
|
}
|
||||||
|
} while ($active || $pending);
|
||||||
|
|
||||||
|
$this->releaseMultiHandle($multi);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processMessages(BatchContext $context)
|
||||||
|
{
|
||||||
|
$multi = $context->getMultiHandle();
|
||||||
|
|
||||||
|
while ($done = curl_multi_info_read($multi)) {
|
||||||
|
$transaction = $context->findTransaction($done['handle']);
|
||||||
|
$this->processResponse($transaction, $done, $context);
|
||||||
|
// Add the next transaction if there are more in the queue
|
||||||
|
if ($next = $context->nextPending()) {
|
||||||
|
$this->addHandle($next, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processResponse(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
array $curl,
|
||||||
|
BatchContext $context
|
||||||
|
) {
|
||||||
|
$info = $context->removeTransaction($transaction);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!$this->isCurlException($transaction, $curl, $context, $info)) {
|
||||||
|
RequestEvents::emitComplete($transaction, $info);
|
||||||
|
}
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
$this->throwException($e, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addHandle(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
BatchContext $context
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
RequestEvents::emitBefore($transaction);
|
||||||
|
// Only transfer if the request was not intercepted
|
||||||
|
if (!$transaction->getResponse()) {
|
||||||
|
$factory = $this->curlFactory;
|
||||||
|
$context->addTransaction(
|
||||||
|
$transaction,
|
||||||
|
$factory($transaction, $this->messageFactory)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
$this->throwException($e, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isCurlException(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
array $curl,
|
||||||
|
BatchContext $context,
|
||||||
|
array $info
|
||||||
|
) {
|
||||||
|
if (CURLM_OK == $curl['result'] ||
|
||||||
|
CURLM_CALL_MULTI_PERFORM == $curl['result']
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
try {
|
||||||
|
// Send curl stats along if they are available
|
||||||
|
$stats = ['curl_result' => $curl['result']] + $info;
|
||||||
|
RequestEvents::emitError(
|
||||||
|
$transaction,
|
||||||
|
new RequestException(
|
||||||
|
sprintf(
|
||||||
|
'[curl] (#%s) %s [url] %s',
|
||||||
|
$curl['result'],
|
||||||
|
function_exists('curl_strerror')
|
||||||
|
? curl_strerror($curl['result'])
|
||||||
|
: self::ERROR_STR,
|
||||||
|
$request->getUrl()
|
||||||
|
),
|
||||||
|
$request
|
||||||
|
),
|
||||||
|
$stats
|
||||||
|
);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
$this->throwException($e, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function throwException(RequestException $e, BatchContext $context)
|
||||||
|
{
|
||||||
|
if ($context->throwsExceptions()) {
|
||||||
|
$this->releaseMultiHandle($context->getMultiHandle());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a curl_multi handle from the cache or creates a new one
|
||||||
|
*
|
||||||
|
* @return resource
|
||||||
|
*/
|
||||||
|
private function checkoutMultiHandle()
|
||||||
|
{
|
||||||
|
// Find an unused handle in the cache
|
||||||
|
$key = array_search(false, $this->multiOwned, true);
|
||||||
|
if (false !== $key) {
|
||||||
|
$this->multiOwned[$key] = true;
|
||||||
|
return $this->multiHandles[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new handle
|
||||||
|
$handle = curl_multi_init();
|
||||||
|
$id = (int) $handle;
|
||||||
|
$this->multiHandles[$id] = $handle;
|
||||||
|
$this->multiOwned[$id] = true;
|
||||||
|
|
||||||
|
return $handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases a curl_multi handle back into the cache and removes excess cache
|
||||||
|
*
|
||||||
|
* @param resource $handle Curl multi handle to remove
|
||||||
|
*/
|
||||||
|
private function releaseMultiHandle($handle)
|
||||||
|
{
|
||||||
|
$id = (int) $handle;
|
||||||
|
|
||||||
|
if (count($this->multiHandles) <= 3) {
|
||||||
|
$this->multiOwned[$id] = false;
|
||||||
|
} else {
|
||||||
|
// Prune excessive handles
|
||||||
|
curl_multi_close($this->multiHandles[$id]);
|
||||||
|
unset($this->multiHandles[$id], $this->multiOwned[$id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter\Curl;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Event\RequestEvents;
|
||||||
|
use GuzzleHttp\Message\MessageFactoryInterface;
|
||||||
|
use GuzzleHttp\Stream\Stream;
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediator between curl handles and request objects
|
||||||
|
*/
|
||||||
|
class RequestMediator
|
||||||
|
{
|
||||||
|
/** @var TransactionInterface */
|
||||||
|
private $transaction;
|
||||||
|
/** @var MessageFactoryInterface */
|
||||||
|
private $messageFactory;
|
||||||
|
private $statusCode;
|
||||||
|
private $reasonPhrase;
|
||||||
|
private $body;
|
||||||
|
private $protocolVersion;
|
||||||
|
private $headers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionInterface $transaction Transaction to populate
|
||||||
|
* @param MessageFactoryInterface $messageFactory Creates responses
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
MessageFactoryInterface $messageFactory
|
||||||
|
) {
|
||||||
|
$this->transaction = $transaction;
|
||||||
|
$this->messageFactory = $messageFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the body that will hold the response body
|
||||||
|
*
|
||||||
|
* @param StreamInterface $body Response body
|
||||||
|
*/
|
||||||
|
public function setResponseBody(StreamInterface $body = null)
|
||||||
|
{
|
||||||
|
$this->body = $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive a response header from curl
|
||||||
|
*
|
||||||
|
* @param resource $curl Curl handle
|
||||||
|
* @param string $header Received header
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function receiveResponseHeader($curl, $header)
|
||||||
|
{
|
||||||
|
static $normalize = ["\r", "\n"];
|
||||||
|
$length = strlen($header);
|
||||||
|
$header = str_replace($normalize, '', $header);
|
||||||
|
|
||||||
|
if (strpos($header, 'HTTP/') === 0) {
|
||||||
|
$startLine = explode(' ', $header, 3);
|
||||||
|
// Only download the body to a target body when a successful
|
||||||
|
// response is received.
|
||||||
|
if ($startLine[1][0] != '2') {
|
||||||
|
$this->body = null;
|
||||||
|
}
|
||||||
|
$this->statusCode = $startLine[1];
|
||||||
|
$this->reasonPhrase = isset($startLine[2]) ? $startLine[2] : null;
|
||||||
|
$this->protocolVersion = substr($startLine[0], -3);
|
||||||
|
$this->headers = [];
|
||||||
|
} elseif ($pos = strpos($header, ':')) {
|
||||||
|
$this->headers[substr($header, 0, $pos)][] = substr($header, $pos + 1);
|
||||||
|
} elseif ($header == '' && $this->statusCode >= 200) {
|
||||||
|
$response = $this->messageFactory->createResponse(
|
||||||
|
$this->statusCode,
|
||||||
|
$this->headers,
|
||||||
|
$this->body,
|
||||||
|
[
|
||||||
|
'protocol_version' => $this->protocolVersion,
|
||||||
|
'reason_phrase' => $this->reasonPhrase
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$this->headers = $this->body = null;
|
||||||
|
$this->transaction->setResponse($response);
|
||||||
|
// Allows events to react before downloading any of the body
|
||||||
|
RequestEvents::emitHeaders($this->transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data to the response body of a request
|
||||||
|
*
|
||||||
|
* @param resource $curl
|
||||||
|
* @param string $write
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function writeResponseBody($curl, $write)
|
||||||
|
{
|
||||||
|
if (!($response = $this->transaction->getResponse())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a default body on the response if one was not found
|
||||||
|
if (!($body = $response->getBody())) {
|
||||||
|
$body = new Stream(fopen('php://temp', 'r+'));
|
||||||
|
$response->setBody($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $body->write($write);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data from the request body and send it to curl
|
||||||
|
*
|
||||||
|
* @param resource $ch Curl handle
|
||||||
|
* @param resource $fd File descriptor
|
||||||
|
* @param int $length Amount of data to read
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function readRequestBody($ch, $fd, $length)
|
||||||
|
{
|
||||||
|
return (string) $this->transaction->getRequest()->getBody()->read($length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates a regular AdapterInterface object and creates a
|
||||||
|
* ParallelAdapterInterface object that sends multiple HTTP requests serially.
|
||||||
|
*/
|
||||||
|
class FakeParallelAdapter implements ParallelAdapterInterface
|
||||||
|
{
|
||||||
|
/** @var AdapterInterface */
|
||||||
|
private $adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AdapterInterface $adapter Adapter used to send requests
|
||||||
|
*/
|
||||||
|
public function __construct(AdapterInterface $adapter)
|
||||||
|
{
|
||||||
|
$this->adapter = $adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendAll(\Iterator $transactions, $parallel)
|
||||||
|
{
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
try {
|
||||||
|
$this->adapter->send($transaction);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
// no op for batch transaction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\RequestEvents;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter that can be used to associate mock responses with a transaction
|
||||||
|
* while still emulating the event workflow of real adapters.
|
||||||
|
*/
|
||||||
|
class MockAdapter implements AdapterInterface
|
||||||
|
{
|
||||||
|
private $response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ResponseInterface|callable $response Response to serve or function
|
||||||
|
* to invoke that handles a transaction
|
||||||
|
*/
|
||||||
|
public function __construct($response = null)
|
||||||
|
{
|
||||||
|
$this->setResponse($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the response that will be served by the adapter
|
||||||
|
*
|
||||||
|
* @param ResponseInterface|callable $response Response to serve or
|
||||||
|
* function to invoke that handles a transaction
|
||||||
|
*/
|
||||||
|
public function setResponse($response)
|
||||||
|
{
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
RequestEvents::emitBefore($transaction);
|
||||||
|
if (!$transaction->getResponse()) {
|
||||||
|
|
||||||
|
// Read the request body if it is present
|
||||||
|
if ($transaction->getRequest()->getBody()) {
|
||||||
|
$transaction->getRequest()->getBody()->__toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = is_callable($this->response)
|
||||||
|
? call_user_func($this->response, $transaction)
|
||||||
|
: $this->response;
|
||||||
|
if (!$response instanceof ResponseInterface) {
|
||||||
|
throw new \RuntimeException('Invalid mocked response');
|
||||||
|
}
|
||||||
|
|
||||||
|
$transaction->setResponse($response);
|
||||||
|
RequestEvents::emitHeaders($transaction);
|
||||||
|
RequestEvents::emitComplete($transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transaction->getResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter interface used to transfer multiple HTTP requests in parallel.
|
||||||
|
*
|
||||||
|
* Parallel adapters follow the same rules as AdapterInterface except that
|
||||||
|
* RequestExceptions are never thrown in a parallel transfer and parallel
|
||||||
|
* adapters do not return responses.
|
||||||
|
*/
|
||||||
|
interface ParallelAdapterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transfers multiple HTTP requests in parallel.
|
||||||
|
*
|
||||||
|
* RequestExceptions MUST not be thrown from a parallel transfer.
|
||||||
|
*
|
||||||
|
* @param \Iterator $transactions Iterator that yields TransactionInterface
|
||||||
|
* @param int $parallel Max number of requests to send in parallel
|
||||||
|
*/
|
||||||
|
public function sendAll(\Iterator $transactions, $parallel);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,347 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\RequestEvents;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use GuzzleHttp\Message\MessageFactoryInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP adapter that uses PHP's HTTP stream wrapper.
|
||||||
|
*
|
||||||
|
* When using the StreamAdapter, custom stream context options can be specified
|
||||||
|
* using the **stream_context** option in a request's **config** option. The
|
||||||
|
* structure of the "stream_context" option is an associative array where each
|
||||||
|
* key is a transport name and each option is an associative array of options.
|
||||||
|
*/
|
||||||
|
class StreamAdapter implements AdapterInterface
|
||||||
|
{
|
||||||
|
/** @var MessageFactoryInterface */
|
||||||
|
private $messageFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MessageFactoryInterface $messageFactory
|
||||||
|
*/
|
||||||
|
public function __construct(MessageFactoryInterface $messageFactory)
|
||||||
|
{
|
||||||
|
$this->messageFactory = $messageFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
// HTTP/1.1 streams using the PHP stream wrapper require a
|
||||||
|
// Connection: close header. Setting here so that it is added before
|
||||||
|
// emitting the request.before_send event.
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
if ($request->getProtocolVersion() == '1.1' &&
|
||||||
|
!$request->hasHeader('Connection')
|
||||||
|
) {
|
||||||
|
$transaction->getRequest()->setHeader('Connection', 'close');
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestEvents::emitBefore($transaction);
|
||||||
|
if (!$transaction->getResponse()) {
|
||||||
|
$this->createResponse($transaction);
|
||||||
|
RequestEvents::emitComplete($transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transaction->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createResponse(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
$stream = $this->createStream($request, $http_response_header);
|
||||||
|
|
||||||
|
if (!$request->getConfig()['stream']) {
|
||||||
|
$stream = $this->getSaveToBody($request, $stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the response headers of the request
|
||||||
|
$this->createResponseObject($http_response_header, $transaction, $stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drain the steam into the destination stream
|
||||||
|
*/
|
||||||
|
private function getSaveToBody(RequestInterface $request, $stream)
|
||||||
|
{
|
||||||
|
if ($saveTo = $request->getConfig()['save_to']) {
|
||||||
|
// Stream the response into the destination stream
|
||||||
|
$saveTo = is_string($saveTo)
|
||||||
|
? Stream\create(fopen($saveTo, 'r+'))
|
||||||
|
: Stream\create($saveTo);
|
||||||
|
} else {
|
||||||
|
// Stream into the default temp stream
|
||||||
|
$saveTo = Stream\create();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof($stream)) {
|
||||||
|
$saveTo->write(fread($stream, 8096));
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($stream);
|
||||||
|
$saveTo->seek(0);
|
||||||
|
|
||||||
|
return $saveTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createResponseObject(
|
||||||
|
array $headers,
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
$stream
|
||||||
|
) {
|
||||||
|
$parts = explode(' ', array_shift($headers), 3);
|
||||||
|
$options = ['protocol_version' => substr($parts[0], -3)];
|
||||||
|
if (isset($parts[2])) {
|
||||||
|
$options['reason_phrase'] = $parts[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the size on the stream if it was returned in the response
|
||||||
|
$responseHeaders = [];
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
$headerParts = explode(':', $header, 2);
|
||||||
|
$responseHeaders[$headerParts[0]] = isset($headerParts[1])
|
||||||
|
? $headerParts[1]
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->messageFactory->createResponse(
|
||||||
|
$parts[1],
|
||||||
|
$responseHeaders,
|
||||||
|
$stream,
|
||||||
|
$options
|
||||||
|
);
|
||||||
|
|
||||||
|
$transaction->setResponse($response);
|
||||||
|
RequestEvents::emitHeaders($transaction);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a resource and check to ensure it was created successfully
|
||||||
|
*
|
||||||
|
* @param callable $callback Callable that returns stream resource
|
||||||
|
* @param RequestInterface $request Request used when throwing exceptions
|
||||||
|
* @param array $options Options used when throwing exceptions
|
||||||
|
*
|
||||||
|
* @return resource
|
||||||
|
* @throws RequestException on error
|
||||||
|
*/
|
||||||
|
private function createResource(callable $callback, RequestInterface $request, $options)
|
||||||
|
{
|
||||||
|
// Turn off error reporting while we try to initiate the request
|
||||||
|
$level = error_reporting(0);
|
||||||
|
$resource = call_user_func($callback);
|
||||||
|
error_reporting($level);
|
||||||
|
|
||||||
|
// If the resource could not be created, then grab the last error and
|
||||||
|
// throw an exception.
|
||||||
|
if (!is_resource($resource)) {
|
||||||
|
$message = 'Error creating resource. [url] ' . $request->getUrl() . ' ';
|
||||||
|
if (isset($options['http']['proxy'])) {
|
||||||
|
$message .= "[proxy] {$options['http']['proxy']} ";
|
||||||
|
}
|
||||||
|
foreach (error_get_last() as $key => $value) {
|
||||||
|
$message .= "[{$key}] {$value} ";
|
||||||
|
}
|
||||||
|
throw new RequestException(trim($message), $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the stream for the request with the context options.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request being sent
|
||||||
|
* @param mixed $http_response_header Populated by stream wrapper
|
||||||
|
*
|
||||||
|
* @return resource
|
||||||
|
*/
|
||||||
|
private function createStream(
|
||||||
|
RequestInterface $request,
|
||||||
|
&$http_response_header
|
||||||
|
) {
|
||||||
|
static $methods;
|
||||||
|
if (!$methods) {
|
||||||
|
$methods = array_flip(get_class_methods(__CLASS__));
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = [];
|
||||||
|
$options = $this->getDefaultOptions($request);
|
||||||
|
foreach ($request->getConfig()->toArray() as $key => $value) {
|
||||||
|
$method = "add_{$key}";
|
||||||
|
if (isset($methods[$method])) {
|
||||||
|
$this->{$method}($request, $options, $value, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->applyCustomOptions($request, $options);
|
||||||
|
$context = $this->createStreamContext($request, $options, $params);
|
||||||
|
|
||||||
|
return $this->createStreamResource(
|
||||||
|
$request,
|
||||||
|
$options,
|
||||||
|
$context,
|
||||||
|
$http_response_header
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDefaultOptions(RequestInterface $request)
|
||||||
|
{
|
||||||
|
$headers = '';
|
||||||
|
foreach ($request->getHeaders() as $name => $values) {
|
||||||
|
$headers .= $name . ': ' . implode(', ', $values) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'http' => [
|
||||||
|
'method' => $request->getMethod(),
|
||||||
|
'header' => trim($headers),
|
||||||
|
'protocol_version' => $request->getProtocolVersion(),
|
||||||
|
'ignore_errors' => true,
|
||||||
|
'follow_location' => 0,
|
||||||
|
'content' => (string) $request->getBody()
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_proxy(RequestInterface $request, &$options, $value, &$params)
|
||||||
|
{
|
||||||
|
if (!is_array($value)) {
|
||||||
|
$options['http']['proxy'] = $value;
|
||||||
|
$options['http']['request_fulluri'] = true;
|
||||||
|
} else {
|
||||||
|
$scheme = $request->getScheme();
|
||||||
|
if (isset($value[$scheme])) {
|
||||||
|
$options['http']['proxy'] = $value[$scheme];
|
||||||
|
$options['http']['request_fulluri'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_timeout(RequestInterface $request, &$options, $value, &$params)
|
||||||
|
{
|
||||||
|
$options['http']['timeout'] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_verify(RequestInterface $request, &$options, $value, &$params)
|
||||||
|
{
|
||||||
|
if ($value === true || is_string($value)) {
|
||||||
|
$options['http']['verify_peer'] = true;
|
||||||
|
if ($value !== true) {
|
||||||
|
if (!file_exists($value)) {
|
||||||
|
throw new \RuntimeException("SSL certificate authority file not found: {$value}");
|
||||||
|
}
|
||||||
|
$options['http']['allow_self_signed'] = true;
|
||||||
|
$options['http']['cafile'] = $value;
|
||||||
|
}
|
||||||
|
} elseif ($value === false) {
|
||||||
|
$options['http']['verify_peer'] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_cert(RequestInterface $request, &$options, $value, &$params)
|
||||||
|
{
|
||||||
|
if (is_array($value)) {
|
||||||
|
$options['http']['passphrase'] = $value[1];
|
||||||
|
$value = $value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($value)) {
|
||||||
|
throw new \RuntimeException("SSL certificate not found: {$value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['http']['local_cert'] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_debug(RequestInterface $request, &$options, $value, &$params)
|
||||||
|
{
|
||||||
|
static $map = [
|
||||||
|
STREAM_NOTIFY_CONNECT => 'CONNECT',
|
||||||
|
STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
|
||||||
|
STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
|
||||||
|
STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
|
||||||
|
STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
|
||||||
|
STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
|
||||||
|
STREAM_NOTIFY_PROGRESS => 'PROGRESS',
|
||||||
|
STREAM_NOTIFY_FAILURE => 'FAILURE',
|
||||||
|
STREAM_NOTIFY_COMPLETED => 'COMPLETED',
|
||||||
|
STREAM_NOTIFY_RESOLVE => 'RESOLVE'
|
||||||
|
];
|
||||||
|
|
||||||
|
static $args = ['severity', 'message', 'message_code',
|
||||||
|
'bytes_transferred', 'bytes_max'];
|
||||||
|
|
||||||
|
if (!is_resource($value)) {
|
||||||
|
$value = fopen('php://output', 'w');
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['notification'] = function () use ($request, $value, $map, $args) {
|
||||||
|
$passed = func_get_args();
|
||||||
|
$code = array_shift($passed);
|
||||||
|
fprintf($value, '<%s> [%s] ', $request->getUrl(), $map[$code]);
|
||||||
|
foreach (array_filter($passed) as $i => $v) {
|
||||||
|
fwrite($value, $args[$i] . ': "' . $v . '" ');
|
||||||
|
}
|
||||||
|
fwrite($value, "\n");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyCustomOptions(
|
||||||
|
RequestInterface $request,
|
||||||
|
array &$options
|
||||||
|
) {
|
||||||
|
// Overwrite any generated options with custom options
|
||||||
|
if ($custom = $request->getConfig()['stream_context']) {
|
||||||
|
if (!is_array($custom)) {
|
||||||
|
throw new AdapterException('stream_context must be an array');
|
||||||
|
}
|
||||||
|
$options = array_replace_recursive($options, $custom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createStreamContext(
|
||||||
|
RequestInterface $request,
|
||||||
|
array $options,
|
||||||
|
array $params
|
||||||
|
) {
|
||||||
|
return $this->createResource(function () use (
|
||||||
|
$request,
|
||||||
|
$options,
|
||||||
|
$params
|
||||||
|
) {
|
||||||
|
return stream_context_create($options, $params);
|
||||||
|
}, $request, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createStreamResource(
|
||||||
|
RequestInterface $request,
|
||||||
|
array $options,
|
||||||
|
$context,
|
||||||
|
&$http_response_header
|
||||||
|
) {
|
||||||
|
$url = $request->getUrl();
|
||||||
|
// Add automatic gzip decompression
|
||||||
|
if (strpos($request->getHeader('Accept-Encoding'), 'gzip') !== false) {
|
||||||
|
$url = 'compress.zlib://' . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createResource(function () use (
|
||||||
|
$url,
|
||||||
|
&$http_response_header,
|
||||||
|
$context
|
||||||
|
) {
|
||||||
|
if (false === strpos($url, 'http')) {
|
||||||
|
trigger_error("URL is invalid: {$url}", E_USER_WARNING);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fopen($url, 'r', null, $context);
|
||||||
|
}, $request, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends streaming requests to a streaming compatible adapter while sending all
|
||||||
|
* other requests to a default adapter.
|
||||||
|
*
|
||||||
|
* This, for example, could be useful for taking advantage of the performance
|
||||||
|
* benefits of the CurlAdapter while still supporting true streaming through
|
||||||
|
* the StreamAdapter.
|
||||||
|
*/
|
||||||
|
class StreamingProxyAdapter implements AdapterInterface
|
||||||
|
{
|
||||||
|
private $defaultAdapter;
|
||||||
|
private $streamingAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AdapterInterface $defaultAdapter Adapter used for non-streaming responses
|
||||||
|
* @param AdapterInterface $streamingAdapter Adapter used for streaming responses
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
AdapterInterface $defaultAdapter,
|
||||||
|
AdapterInterface $streamingAdapter
|
||||||
|
) {
|
||||||
|
$this->defaultAdapter = $defaultAdapter;
|
||||||
|
$this->streamingAdapter = $streamingAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
return $transaction->getRequest()->getConfig()['stream']
|
||||||
|
? $this->streamingAdapter->send($transaction)
|
||||||
|
: $this->defaultAdapter->send($transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\ClientInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class Transaction implements TransactionInterface
|
||||||
|
{
|
||||||
|
/** @var ClientInterface */
|
||||||
|
private $client;
|
||||||
|
/** @var RequestInterface */
|
||||||
|
private $request;
|
||||||
|
/** @var ResponseInterface */
|
||||||
|
private $response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ClientInterface $client Client that is used to send the requests
|
||||||
|
* @param RequestInterface $request
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
ClientInterface $client,
|
||||||
|
RequestInterface $request
|
||||||
|
) {
|
||||||
|
$this->client = $client;
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setResponse(ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClient()
|
||||||
|
{
|
||||||
|
return $this->client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\ClientInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a transactions that consists of a request, response, and client
|
||||||
|
*/
|
||||||
|
interface TransactionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return RequestInterface
|
||||||
|
*/
|
||||||
|
public function getRequest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
public function getResponse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a response on the transaction
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response Response to set
|
||||||
|
*/
|
||||||
|
public function setResponse(ResponseInterface $response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ClientInterface
|
||||||
|
*/
|
||||||
|
public function getClient();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Adapter;
|
||||||
|
|
||||||
|
use GuzzleHttp\ClientInterface;
|
||||||
|
use GuzzleHttp\Event\ListenerAttacherTrait;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a sequence of request objects into a transaction.
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class TransactionIterator implements \Iterator
|
||||||
|
{
|
||||||
|
use ListenerAttacherTrait;
|
||||||
|
|
||||||
|
/** @var \Iterator */
|
||||||
|
private $source;
|
||||||
|
|
||||||
|
/** @var ClientInterface */
|
||||||
|
private $client;
|
||||||
|
|
||||||
|
/** @var array Listeners to attach to each request */
|
||||||
|
private $eventListeners = [];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
$source,
|
||||||
|
ClientInterface $client,
|
||||||
|
array $options
|
||||||
|
) {
|
||||||
|
$this->client = $client;
|
||||||
|
$this->eventListeners = $this->prepareListeners(
|
||||||
|
$options,
|
||||||
|
['before', 'complete', 'error']
|
||||||
|
);
|
||||||
|
if ($source instanceof \Iterator) {
|
||||||
|
$this->source = $source;
|
||||||
|
} elseif (is_array($source)) {
|
||||||
|
$this->source = new \ArrayIterator($source);
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Expected an Iterator or array');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
$request = $this->source->current();
|
||||||
|
if (!$request instanceof RequestInterface) {
|
||||||
|
throw new \RuntimeException('All must implement RequestInterface');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->attachListeners($request, $this->eventListeners);
|
||||||
|
|
||||||
|
return new Transaction($this->client, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->source->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key()
|
||||||
|
{
|
||||||
|
return $this->source->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return $this->source->valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind() {}
|
||||||
|
}
|
||||||
364
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Client.php
Normal file
364
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Client.php
Normal file
|
|
@ -0,0 +1,364 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\Curl\MultiAdapter;
|
||||||
|
use GuzzleHttp\Event\HasEmitterTrait;
|
||||||
|
use GuzzleHttp\Adapter\FakeParallelAdapter;
|
||||||
|
use GuzzleHttp\Adapter\ParallelAdapterInterface;
|
||||||
|
use GuzzleHttp\Adapter\AdapterInterface;
|
||||||
|
use GuzzleHttp\Adapter\StreamAdapter;
|
||||||
|
use GuzzleHttp\Adapter\StreamingProxyAdapter;
|
||||||
|
use GuzzleHttp\Adapter\Curl\CurlAdapter;
|
||||||
|
use GuzzleHttp\Adapter\Transaction;
|
||||||
|
use GuzzleHttp\Adapter\TransactionIterator;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use GuzzleHttp\Message\MessageFactory;
|
||||||
|
use GuzzleHttp\Message\MessageFactoryInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP client
|
||||||
|
*/
|
||||||
|
class Client implements ClientInterface
|
||||||
|
{
|
||||||
|
use HasEmitterTrait;
|
||||||
|
|
||||||
|
const DEFAULT_CONCURRENCY = 25;
|
||||||
|
|
||||||
|
/** @var MessageFactoryInterface Request factory used by the client */
|
||||||
|
private $messageFactory;
|
||||||
|
|
||||||
|
/** @var AdapterInterface */
|
||||||
|
private $adapter;
|
||||||
|
|
||||||
|
/** @var ParallelAdapterInterface */
|
||||||
|
private $parallelAdapter;
|
||||||
|
|
||||||
|
/** @var Url Base URL of the client */
|
||||||
|
private $baseUrl;
|
||||||
|
|
||||||
|
/** @var array Default request options */
|
||||||
|
private $defaults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clients accept an array of constructor parameters.
|
||||||
|
*
|
||||||
|
* Here's an example of creating a client using an URI template for the
|
||||||
|
* client's base_url and an array of default request options to apply
|
||||||
|
* to each request:
|
||||||
|
*
|
||||||
|
* $client = new Client([
|
||||||
|
* 'base_url' => [
|
||||||
|
* 'http://www.foo.com/{version}/',
|
||||||
|
* ['version' => '123']
|
||||||
|
* ],
|
||||||
|
* 'defaults' => [
|
||||||
|
* 'timeout' => 10,
|
||||||
|
* 'allow_redirects' => false,
|
||||||
|
* 'proxy' => '192.168.16.1:10'
|
||||||
|
* ]
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* @param array $config Client configuration settings
|
||||||
|
* - base_url: Base URL of the client that is merged into relative URLs.
|
||||||
|
* Can be a string or an array that contains a URI template followed
|
||||||
|
* by an associative array of expansion variables to inject into the
|
||||||
|
* URI template.
|
||||||
|
* - adapter: Adapter used to transfer requests
|
||||||
|
* - parallel_adapter: Adapter used to transfer requests in parallel
|
||||||
|
* - message_factory: Factory used to create request and response object
|
||||||
|
* - defaults: Default request options to apply to each request
|
||||||
|
* - emitter: Event emitter used for request events
|
||||||
|
*/
|
||||||
|
public function __construct(array $config = [])
|
||||||
|
{
|
||||||
|
$this->configureBaseUrl($config);
|
||||||
|
$this->configureDefaults($config);
|
||||||
|
$this->configureAdapter($config);
|
||||||
|
if (isset($config['emitter'])) {
|
||||||
|
$this->emitter = $config['emitter'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default User-Agent string to use with Guzzle
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getDefaultUserAgent()
|
||||||
|
{
|
||||||
|
static $defaultAgent = '';
|
||||||
|
if (!$defaultAgent) {
|
||||||
|
$defaultAgent = 'Guzzle/' . self::VERSION;
|
||||||
|
if (extension_loaded('curl')) {
|
||||||
|
$defaultAgent .= ' curl/' . curl_version()['version'];
|
||||||
|
}
|
||||||
|
$defaultAgent .= ' PHP/' . PHP_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $defaultAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($name, $arguments)
|
||||||
|
{
|
||||||
|
return \GuzzleHttp\deprecation_proxy(
|
||||||
|
$this,
|
||||||
|
$name,
|
||||||
|
$arguments,
|
||||||
|
['getEventDispatcher' => 'getEmitter']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultOption($keyOrPath = null)
|
||||||
|
{
|
||||||
|
return $keyOrPath === null
|
||||||
|
? $this->defaults
|
||||||
|
: \GuzzleHttp\get_path($this->defaults, $keyOrPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDefaultOption($keyOrPath, $value)
|
||||||
|
{
|
||||||
|
\GuzzleHttp\set_path($this->defaults, $keyOrPath, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseUrl()
|
||||||
|
{
|
||||||
|
return (string) $this->baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createRequest($method, $url = null, array $options = [])
|
||||||
|
{
|
||||||
|
// Merge in default options
|
||||||
|
$options = array_replace_recursive($this->defaults, $options);
|
||||||
|
|
||||||
|
// Use a clone of the client's emitter
|
||||||
|
$options['config']['emitter'] = clone $this->getEmitter();
|
||||||
|
|
||||||
|
$request = $this->messageFactory->createRequest(
|
||||||
|
$method,
|
||||||
|
$url ? (string) $this->buildUrl($url) : (string) $this->baseUrl,
|
||||||
|
$options
|
||||||
|
);
|
||||||
|
|
||||||
|
return $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($url = null, $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('GET', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function head($url = null, array $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('HEAD', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($url = null, array $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('DELETE', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function put($url = null, array $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('PUT', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function patch($url = null, array $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('PATCH', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post($url = null, array $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('POST', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function options($url = null, array $options = [])
|
||||||
|
{
|
||||||
|
return $this->send($this->createRequest('OPTIONS', $url, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(RequestInterface $request)
|
||||||
|
{
|
||||||
|
$transaction = new Transaction($this, $request);
|
||||||
|
try {
|
||||||
|
if ($response = $this->adapter->send($transaction)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
throw new \LogicException('No response was associated with the transaction');
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
throw $e;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Wrap exceptions in a RequestException to adhere to the interface
|
||||||
|
throw new RequestException($e->getMessage(), $request, null, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendAll($requests, array $options = [])
|
||||||
|
{
|
||||||
|
if (!($requests instanceof TransactionIterator)) {
|
||||||
|
$requests = new TransactionIterator($requests, $this, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parallelAdapter->sendAll(
|
||||||
|
$requests,
|
||||||
|
isset($options['parallel'])
|
||||||
|
? $options['parallel']
|
||||||
|
: self::DEFAULT_CONCURRENCY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of default options to apply to the client
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getDefaultOptions()
|
||||||
|
{
|
||||||
|
$settings = [
|
||||||
|
'allow_redirects' => true,
|
||||||
|
'exceptions' => true,
|
||||||
|
'verify' => __DIR__ . '/cacert.pem'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Use the bundled cacert if it is a regular file, or set to true if
|
||||||
|
// using a phar file (because curL and the stream wrapper can't read
|
||||||
|
// cacerts from the phar stream wrapper). Favor the ini setting over
|
||||||
|
// the system's cacert.
|
||||||
|
if (substr(__FILE__, 0, 7) == 'phar://') {
|
||||||
|
$settings['verify'] = ini_get('openssl.cafile') ?: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
|
||||||
|
if (isset($_SERVER['HTTP_PROXY'])) {
|
||||||
|
$settings['proxy']['http'] = $_SERVER['HTTP_PROXY'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_SERVER['HTTPS_PROXY'])) {
|
||||||
|
$settings['proxy']['https'] = $_SERVER['HTTPS_PROXY'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a URI template and inherit from the base URL if it's relative
|
||||||
|
*
|
||||||
|
* @param string|array $url URL or URI template to expand
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function buildUrl($url)
|
||||||
|
{
|
||||||
|
if (!is_array($url)) {
|
||||||
|
if (strpos($url, '://')) {
|
||||||
|
return (string) $url;
|
||||||
|
}
|
||||||
|
return (string) $this->baseUrl->combine($url);
|
||||||
|
} elseif (strpos($url[0], '://')) {
|
||||||
|
return \GuzzleHttp\uri_template($url[0], $url[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $this->baseUrl->combine(
|
||||||
|
\GuzzleHttp\uri_template($url[0], $url[1])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a default parallel adapter to use based on the environment
|
||||||
|
*
|
||||||
|
* @return ParallelAdapterInterface
|
||||||
|
*/
|
||||||
|
private function getDefaultParallelAdapter()
|
||||||
|
{
|
||||||
|
return extension_loaded('curl')
|
||||||
|
? new MultiAdapter($this->messageFactory)
|
||||||
|
: new FakeParallelAdapter($this->adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a default adapter to use based on the environment
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
private function getDefaultAdapter()
|
||||||
|
{
|
||||||
|
if (extension_loaded('curl')) {
|
||||||
|
$this->parallelAdapter = new MultiAdapter($this->messageFactory);
|
||||||
|
$this->adapter = function_exists('curl_reset')
|
||||||
|
? new CurlAdapter($this->messageFactory)
|
||||||
|
: $this->parallelAdapter;
|
||||||
|
if (ini_get('allow_url_fopen')) {
|
||||||
|
$this->adapter = new StreamingProxyAdapter(
|
||||||
|
$this->adapter,
|
||||||
|
new StreamAdapter($this->messageFactory)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (ini_get('allow_url_fopen')) {
|
||||||
|
$this->adapter = new StreamAdapter($this->messageFactory);
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException('Guzzle requires cURL, the '
|
||||||
|
. 'allow_url_fopen ini setting, or a custom HTTP adapter.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function configureBaseUrl(&$config)
|
||||||
|
{
|
||||||
|
if (!isset($config['base_url'])) {
|
||||||
|
$this->baseUrl = new Url('', '');
|
||||||
|
} elseif (is_array($config['base_url'])) {
|
||||||
|
$this->baseUrl = Url::fromString(
|
||||||
|
\GuzzleHttp\uri_template(
|
||||||
|
$config['base_url'][0],
|
||||||
|
$config['base_url'][1]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$config['base_url'] = (string) $this->baseUrl;
|
||||||
|
} else {
|
||||||
|
$this->baseUrl = Url::fromString($config['base_url']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function configureDefaults($config)
|
||||||
|
{
|
||||||
|
if (!isset($config['defaults'])) {
|
||||||
|
$this->defaults = $this->getDefaultOptions();
|
||||||
|
} else {
|
||||||
|
$this->defaults = array_replace(
|
||||||
|
$this->getDefaultOptions(),
|
||||||
|
$config['defaults']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the default user-agent header
|
||||||
|
if (!isset($this->defaults['headers'])) {
|
||||||
|
$this->defaults['headers'] = [
|
||||||
|
'User-Agent' => static::getDefaultUserAgent()
|
||||||
|
];
|
||||||
|
} elseif (!isset(array_change_key_case($this->defaults['headers'])['user-agent'])) {
|
||||||
|
// Add the User-Agent header if one was not already set
|
||||||
|
$this->defaults['headers']['User-Agent'] = static::getDefaultUserAgent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function configureAdapter(&$config)
|
||||||
|
{
|
||||||
|
if (isset($config['message_factory'])) {
|
||||||
|
$this->messageFactory = $config['message_factory'];
|
||||||
|
} else {
|
||||||
|
$this->messageFactory = new MessageFactory();
|
||||||
|
}
|
||||||
|
if (isset($config['adapter'])) {
|
||||||
|
$this->adapter = $config['adapter'];
|
||||||
|
} else {
|
||||||
|
$this->getDefaultAdapter();
|
||||||
|
}
|
||||||
|
// If no parallel adapter was explicitly provided and one was not
|
||||||
|
// defaulted when creating the default adapter, then create one now.
|
||||||
|
if (isset($config['parallel_adapter'])) {
|
||||||
|
$this->parallelAdapter = $config['parallel_adapter'];
|
||||||
|
} elseif (!$this->parallelAdapter) {
|
||||||
|
$this->parallelAdapter = $this->getDefaultParallelAdapter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
179
rainloop/v/0.0.0/app/libraries/GuzzleHttp/ClientInterface.php
Normal file
179
rainloop/v/0.0.0/app/libraries/GuzzleHttp/ClientInterface.php
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\HasEmitterInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use GuzzleHttp\Exception\AdapterException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client interface for sending HTTP requests
|
||||||
|
*/
|
||||||
|
interface ClientInterface extends HasEmitterInterface
|
||||||
|
{
|
||||||
|
const VERSION = '4.1.2';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a new {@see RequestInterface} object.
|
||||||
|
*
|
||||||
|
* Use an absolute path to override the base path of the client, or a
|
||||||
|
* relative path to append to the base path of the client. The URL can
|
||||||
|
* contain the query string as well. Use an array to provide a URL
|
||||||
|
* template and additional variables to use in the URL template expansion.
|
||||||
|
*
|
||||||
|
* @param string $method HTTP method
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return RequestInterface
|
||||||
|
*/
|
||||||
|
public function createRequest($method, $url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a GET request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function get($url = null, $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a HEAD request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function head($url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a DELETE request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function delete($url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a PUT request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function put($url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a PATCH request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function patch($url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a POST request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function post($url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an OPTIONS request
|
||||||
|
*
|
||||||
|
* @param string|array|Url $url URL or URI template
|
||||||
|
* @param array $options Array of request options to apply.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function options($url = null, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a single request
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request to send
|
||||||
|
*
|
||||||
|
* @return \GuzzleHttp\Message\ResponseInterface
|
||||||
|
* @throws \LogicException When the adapter does not populate a response
|
||||||
|
* @throws RequestException When an error is encountered
|
||||||
|
*/
|
||||||
|
public function send(RequestInterface $request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends multiple requests in parallel.
|
||||||
|
*
|
||||||
|
* Exceptions are not thrown for failed requests. Callers are expected to
|
||||||
|
* register an "error" option to handle request errors OR directly register
|
||||||
|
* an event handler for the "error" event of a request's
|
||||||
|
* event emitter.
|
||||||
|
*
|
||||||
|
* The option values for 'before', 'after', and 'error' can be a callable,
|
||||||
|
* an associative array containing event data, or an array of event data
|
||||||
|
* arrays. Event data arrays contain the following keys:
|
||||||
|
*
|
||||||
|
* - fn: callable to invoke that receives the event
|
||||||
|
* - priority: Optional event priority (defaults to 0)
|
||||||
|
* - once: Set to true so that the event is removed after it is triggered
|
||||||
|
*
|
||||||
|
* @param array|\Iterator $requests Requests to send in parallel
|
||||||
|
* @param array $options Associative array of options
|
||||||
|
* - parallel: (int) Maximum number of requests to send in parallel
|
||||||
|
* - before: (callable|array) Receives a BeforeEvent
|
||||||
|
* - after: (callable|array) Receives a CompleteEvent
|
||||||
|
* - error: (callable|array) Receives a ErrorEvent
|
||||||
|
*
|
||||||
|
* @throws AdapterException When an error occurs in the HTTP adapter.
|
||||||
|
*/
|
||||||
|
public function sendAll($requests, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get default request options of the client.
|
||||||
|
*
|
||||||
|
* @param string|null $keyOrPath The Path to a particular default request
|
||||||
|
* option to retrieve or pass null to retrieve all default request
|
||||||
|
* options. The syntax uses "/" to denote a path through nested PHP
|
||||||
|
* arrays. For example, "headers/content-type".
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getDefaultOption($keyOrPath = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a default request option on the client so that any request created
|
||||||
|
* by the client will use the provided default value unless overridden
|
||||||
|
* explicitly when creating a request.
|
||||||
|
*
|
||||||
|
* @param string|null $keyOrPath The Path to a particular configuration
|
||||||
|
* value to set. The syntax uses a path notation that allows you to
|
||||||
|
* specify nested configuration values (e.g., 'headers/content-type').
|
||||||
|
* @param mixed $value Default request option value to set
|
||||||
|
*/
|
||||||
|
public function setDefaultOption($keyOrPath, $value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the base URL of the client.
|
||||||
|
*
|
||||||
|
* @return string Returns the base URL if present
|
||||||
|
*/
|
||||||
|
public function getBaseUrl();
|
||||||
|
}
|
||||||
265
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Collection.php
Normal file
265
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Collection.php
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key value pair collection object
|
||||||
|
*/
|
||||||
|
class Collection implements
|
||||||
|
\ArrayAccess,
|
||||||
|
\IteratorAggregate,
|
||||||
|
\Countable,
|
||||||
|
ToArrayInterface
|
||||||
|
{
|
||||||
|
use HasDataTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data Associative array of data to set
|
||||||
|
*/
|
||||||
|
public function __construct(array $data = [])
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new collection from an array, validate the keys, and add default
|
||||||
|
* values where missing
|
||||||
|
*
|
||||||
|
* @param array $config Configuration values to apply.
|
||||||
|
* @param array $defaults Default parameters
|
||||||
|
* @param array $required Required parameter names
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
* @throws \InvalidArgumentException if a parameter is missing
|
||||||
|
*/
|
||||||
|
public static function fromConfig(
|
||||||
|
array $config = [],
|
||||||
|
array $defaults = [],
|
||||||
|
array $required = []
|
||||||
|
) {
|
||||||
|
$data = $config + $defaults;
|
||||||
|
|
||||||
|
if ($missing = array_diff($required, array_keys($data))) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'Config is missing the following keys: ' .
|
||||||
|
implode(', ', $missing));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all key value pairs
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function clear()
|
||||||
|
{
|
||||||
|
$this->data = [];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific key value.
|
||||||
|
*
|
||||||
|
* @param string $key Key to retrieve.
|
||||||
|
*
|
||||||
|
* @return mixed|null Value of the key or NULL
|
||||||
|
*/
|
||||||
|
public function get($key)
|
||||||
|
{
|
||||||
|
return isset($this->data[$key]) ? $this->data[$key] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a key value pair
|
||||||
|
*
|
||||||
|
* @param string $key Key to set
|
||||||
|
* @param mixed $value Value to set
|
||||||
|
*
|
||||||
|
* @return Collection Returns a reference to the object
|
||||||
|
*/
|
||||||
|
public function set($key, $value)
|
||||||
|
{
|
||||||
|
$this->data[$key] = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a value to a key. If a key of the same name has already been added,
|
||||||
|
* the key value will be converted into an array and the new value will be
|
||||||
|
* pushed to the end of the array.
|
||||||
|
*
|
||||||
|
* @param string $key Key to add
|
||||||
|
* @param mixed $value Value to add to the key
|
||||||
|
*
|
||||||
|
* @return Collection Returns a reference to the object.
|
||||||
|
*/
|
||||||
|
public function add($key, $value)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($key, $this->data)) {
|
||||||
|
$this->data[$key] = $value;
|
||||||
|
} elseif (is_array($this->data[$key])) {
|
||||||
|
$this->data[$key][] = $value;
|
||||||
|
} else {
|
||||||
|
$this->data[$key] = array($this->data[$key], $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific key value pair
|
||||||
|
*
|
||||||
|
* @param string $key A key to remove
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function remove($key)
|
||||||
|
{
|
||||||
|
unset($this->data[$key]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all keys in the collection
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getKeys()
|
||||||
|
{
|
||||||
|
return array_keys($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the specified key is present.
|
||||||
|
*
|
||||||
|
* @param string $key The key for which to check the existence.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasKey($key)
|
||||||
|
{
|
||||||
|
return array_key_exists($key, $this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any keys contains a certain value
|
||||||
|
*
|
||||||
|
* @param string $value Value to search for
|
||||||
|
*
|
||||||
|
* @return mixed Returns the key if the value was found FALSE if the value
|
||||||
|
* was not found.
|
||||||
|
*/
|
||||||
|
public function hasValue($value)
|
||||||
|
{
|
||||||
|
return array_search($value, $this->data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the data of the object with the value of an array
|
||||||
|
*
|
||||||
|
* @param array $data Associative array of data
|
||||||
|
*
|
||||||
|
* @return Collection Returns a reference to the object
|
||||||
|
*/
|
||||||
|
public function replace(array $data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add and merge in a Collection or array of key value pair data.
|
||||||
|
*
|
||||||
|
* @param Collection|array $data Associative array of key value pair data
|
||||||
|
*
|
||||||
|
* @return Collection Returns a reference to the object.
|
||||||
|
*/
|
||||||
|
public function merge($data)
|
||||||
|
{
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$this->add($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Over write key value pairs in this collection with all of the data from
|
||||||
|
* an array or collection.
|
||||||
|
*
|
||||||
|
* @param array|\Traversable $data Values to override over this config
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function overwriteWith($data)
|
||||||
|
{
|
||||||
|
if (is_array($data)) {
|
||||||
|
$this->data = $data + $this->data;
|
||||||
|
} elseif ($data instanceof Collection) {
|
||||||
|
$this->data = $data->toArray() + $this->data;
|
||||||
|
} else {
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$this->data[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Collection containing all the elements of the collection after
|
||||||
|
* applying the callback function to each one.
|
||||||
|
*
|
||||||
|
* The callable should accept three arguments:
|
||||||
|
* - (string) $key
|
||||||
|
* - (string) $value
|
||||||
|
* - (array) $context
|
||||||
|
*
|
||||||
|
* The callable must return a the altered or unaltered value.
|
||||||
|
*
|
||||||
|
* @param callable $closure Map function to apply
|
||||||
|
* @param array $context Context to pass to the callable
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function map(callable $closure, array $context = [])
|
||||||
|
{
|
||||||
|
$collection = new static();
|
||||||
|
foreach ($this as $key => $value) {
|
||||||
|
$collection[$key] = $closure($key, $value, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over each key value pair in the collection passing them to the
|
||||||
|
* callable. If the callable returns true, the current value from input is
|
||||||
|
* returned into the result Collection.
|
||||||
|
*
|
||||||
|
* The callable must accept two arguments:
|
||||||
|
* - (string) $key
|
||||||
|
* - (string) $value
|
||||||
|
*
|
||||||
|
* @param callable $closure Evaluation function
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function filter(callable $closure)
|
||||||
|
{
|
||||||
|
$collection = new static();
|
||||||
|
foreach ($this->data as $key => $value) {
|
||||||
|
if ($closure($key, $value)) {
|
||||||
|
$collection[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
}
|
||||||
249
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Cookie/CookieJar.php
Normal file
249
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Cookie/CookieJar.php
Normal file
|
|
@ -0,0 +1,249 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Cookie;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
use GuzzleHttp\ToArrayInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie jar that stores cookies an an array
|
||||||
|
*/
|
||||||
|
class CookieJar implements CookieJarInterface, ToArrayInterface
|
||||||
|
{
|
||||||
|
/** @var SetCookie[] Loaded cookie data */
|
||||||
|
private $cookies = [];
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $strictMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $strictMode Set to true to throw exceptions when invalid
|
||||||
|
* cookies are added to the cookie jar.
|
||||||
|
* @param array $cookieArray Array of SetCookie objects or a hash of arrays
|
||||||
|
* that can be used with the SetCookie constructor
|
||||||
|
*/
|
||||||
|
public function __construct($strictMode = false, $cookieArray = [])
|
||||||
|
{
|
||||||
|
$this->strictMode = $strictMode;
|
||||||
|
|
||||||
|
foreach ($cookieArray as $cookie) {
|
||||||
|
if (!($cookieArray instanceof SetCookie)) {
|
||||||
|
$cookie = new SetCookie($cookie);
|
||||||
|
}
|
||||||
|
$this->setCookie($cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Cookie jar from an associative array and domain.
|
||||||
|
*
|
||||||
|
* @param array $cookies Cookies to create the jar from
|
||||||
|
* @param string $domain Domain to set the cookies to
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function fromArray(array $cookies, $domain)
|
||||||
|
{
|
||||||
|
$cookieJar = new self();
|
||||||
|
foreach ($cookies as $name => $value) {
|
||||||
|
$cookieJar->setCookie(new SetCookie([
|
||||||
|
'Domain' => $domain,
|
||||||
|
'Name' => $name,
|
||||||
|
'Value' => $value,
|
||||||
|
'Discard' => true
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cookieJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quote the cookie value if it is not already quoted and it contains
|
||||||
|
* problematic characters.
|
||||||
|
*
|
||||||
|
* @param string $value Value that may or may not need to be quoted
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getCookieValue($value)
|
||||||
|
{
|
||||||
|
if (substr($value, 0, 1) !== '"' &&
|
||||||
|
substr($value, -1, 1) !== '"' &&
|
||||||
|
strpbrk($value, ';,')
|
||||||
|
) {
|
||||||
|
$value = '"' . $value . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return array_map(function (SetCookie $cookie) {
|
||||||
|
return $cookie->toArray();
|
||||||
|
}, $this->getIterator()->getArrayCopy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear($domain = null, $path = null, $name = null)
|
||||||
|
{
|
||||||
|
if (!$domain) {
|
||||||
|
$this->cookies = [];
|
||||||
|
return;
|
||||||
|
} elseif (!$path) {
|
||||||
|
$this->cookies = array_filter(
|
||||||
|
$this->cookies,
|
||||||
|
function (SetCookie $cookie) use ($path, $domain) {
|
||||||
|
return !$cookie->matchesDomain($domain);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} elseif (!$name) {
|
||||||
|
$this->cookies = array_filter(
|
||||||
|
$this->cookies,
|
||||||
|
function (SetCookie $cookie) use ($path, $domain) {
|
||||||
|
return !($cookie->matchesPath($path) &&
|
||||||
|
$cookie->matchesDomain($domain));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->cookies = array_filter(
|
||||||
|
$this->cookies,
|
||||||
|
function (SetCookie $cookie) use ($path, $domain, $name) {
|
||||||
|
return !($cookie->getName() == $name &&
|
||||||
|
$cookie->matchesPath($path) &&
|
||||||
|
$cookie->matchesDomain($domain));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearSessionCookies()
|
||||||
|
{
|
||||||
|
$this->cookies = array_filter(
|
||||||
|
$this->cookies,
|
||||||
|
function (SetCookie $cookie) {
|
||||||
|
return !$cookie->getDiscard() && $cookie->getExpires();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCookie(SetCookie $cookie)
|
||||||
|
{
|
||||||
|
// Only allow cookies with set and valid domain, name, value
|
||||||
|
$result = $cookie->validate();
|
||||||
|
if ($result !== true) {
|
||||||
|
if ($this->strictMode) {
|
||||||
|
throw new \RuntimeException('Invalid cookie: ' . $result);
|
||||||
|
} else {
|
||||||
|
$this->removeCookieIfEmpty($cookie);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve conflicts with previously set cookies
|
||||||
|
foreach ($this->cookies as $i => $c) {
|
||||||
|
|
||||||
|
// Two cookies are identical, when their path, and domain are
|
||||||
|
// identical.
|
||||||
|
if ($c->getPath() != $cookie->getPath() ||
|
||||||
|
$c->getDomain() != $cookie->getDomain() ||
|
||||||
|
$c->getName() != $cookie->getName()
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The previously set cookie is a discard cookie and this one is
|
||||||
|
// not so allow the new cookie to be set
|
||||||
|
if (!$cookie->getDiscard() && $c->getDiscard()) {
|
||||||
|
unset($this->cookies[$i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the new cookie's expiration is further into the future, then
|
||||||
|
// replace the old cookie
|
||||||
|
if ($cookie->getExpires() > $c->getExpires()) {
|
||||||
|
unset($this->cookies[$i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the value has changed, we better change it
|
||||||
|
if ($cookie->getValue() !== $c->getValue()) {
|
||||||
|
unset($this->cookies[$i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The cookie exists, so no need to continue
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cookies[] = $cookie;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return count($this->cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIterator()
|
||||||
|
{
|
||||||
|
return new \ArrayIterator(array_values($this->cookies));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extractCookies(
|
||||||
|
RequestInterface $request,
|
||||||
|
ResponseInterface $response
|
||||||
|
) {
|
||||||
|
if ($cookieHeader = $response->getHeader('Set-Cookie', true)) {
|
||||||
|
foreach ($cookieHeader as $cookie) {
|
||||||
|
$sc = SetCookie::fromString($cookie);
|
||||||
|
if (!$sc->getDomain()) {
|
||||||
|
$sc->setDomain($request->getHost());
|
||||||
|
}
|
||||||
|
$this->setCookie($sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCookieHeader(RequestInterface $request)
|
||||||
|
{
|
||||||
|
$values = [];
|
||||||
|
$scheme = $request->getScheme();
|
||||||
|
$host = $request->getHost();
|
||||||
|
$path = $request->getPath();
|
||||||
|
|
||||||
|
foreach ($this->cookies as $cookie) {
|
||||||
|
if ($cookie->matchesPath($path) &&
|
||||||
|
$cookie->matchesDomain($host) &&
|
||||||
|
!$cookie->isExpired() &&
|
||||||
|
(!$cookie->getSecure() || $scheme == 'https')
|
||||||
|
) {
|
||||||
|
$values[] = $cookie->getName() . '='
|
||||||
|
. self::getCookieValue($cookie->getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($values) {
|
||||||
|
$request->setHeader('Cookie', implode(';', $values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a cookie already exists and the server asks to set it again with a
|
||||||
|
* null value, the cookie must be deleted.
|
||||||
|
*
|
||||||
|
* @param SetCookie $cookie
|
||||||
|
*/
|
||||||
|
private function removeCookieIfEmpty(SetCookie $cookie)
|
||||||
|
{
|
||||||
|
$cookieValue = $cookie->getValue();
|
||||||
|
if ($cookieValue === null || $cookieValue === '') {
|
||||||
|
$this->clear(
|
||||||
|
$cookie->getDomain(),
|
||||||
|
$cookie->getPath(),
|
||||||
|
$cookie->getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Cookie;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores HTTP cookies.
|
||||||
|
*
|
||||||
|
* It extracts cookies from HTTP requests, and returns them in HTTP responses.
|
||||||
|
* CookieJarInterface instances automatically expire contained cookies when
|
||||||
|
* necessary. Subclasses are also responsible for storing and retrieving
|
||||||
|
* cookies from a file, database, etc.
|
||||||
|
*
|
||||||
|
* @link http://docs.python.org/2/library/cookielib.html Inspiration
|
||||||
|
*/
|
||||||
|
interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Add a Cookie header to a request.
|
||||||
|
*
|
||||||
|
* If no matching cookies are found in the cookie jar, then no Cookie
|
||||||
|
* header is added to the request.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request object to update
|
||||||
|
*/
|
||||||
|
public function addCookieHeader(RequestInterface $request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract cookies from an HTTP response and store them in the CookieJar.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request that was sent
|
||||||
|
* @param ResponseInterface $response Response that was received
|
||||||
|
*/
|
||||||
|
public function extractCookies(
|
||||||
|
RequestInterface $request,
|
||||||
|
ResponseInterface $response
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cookie in the cookie jar.
|
||||||
|
*
|
||||||
|
* @param SetCookie $cookie Cookie to set.
|
||||||
|
*
|
||||||
|
* @return bool Returns true on success or false on failure
|
||||||
|
*/
|
||||||
|
public function setCookie(SetCookie $cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove cookies currently held in the cookie jar.
|
||||||
|
*
|
||||||
|
* Invoking this method without arguments will empty the whole cookie jar.
|
||||||
|
* If given a $domain argument only cookies belonging to that domain will
|
||||||
|
* be removed. If given a $domain and $path argument, cookies belonging to
|
||||||
|
* the specified path within that domain are removed. If given all three
|
||||||
|
* arguments, then the cookie with the specified name, path and domain is
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* @param string $domain Clears cookies matching a domain
|
||||||
|
* @param string $path Clears cookies matching a domain and path
|
||||||
|
* @param string $name Clears cookies matching a domain, path, and name
|
||||||
|
*
|
||||||
|
* @return CookieJarInterface
|
||||||
|
*/
|
||||||
|
public function clear($domain = null, $path = null, $name = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard all sessions cookies.
|
||||||
|
*
|
||||||
|
* Removes cookies that don't have an expire field or a have a discard
|
||||||
|
* field set to true. To be called when the user agent shuts down according
|
||||||
|
* to RFC 2965.
|
||||||
|
*/
|
||||||
|
public function clearSessionCookies();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Cookie;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists non-session cookies using a JSON formatted file
|
||||||
|
*/
|
||||||
|
class FileCookieJar extends CookieJar
|
||||||
|
{
|
||||||
|
/** @var string filename */
|
||||||
|
private $filename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new FileCookieJar object
|
||||||
|
*
|
||||||
|
* @param string $cookieFile File to store the cookie data
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException if the file cannot be found or created
|
||||||
|
*/
|
||||||
|
public function __construct($cookieFile)
|
||||||
|
{
|
||||||
|
$this->filename = $cookieFile;
|
||||||
|
|
||||||
|
if (file_exists($cookieFile)) {
|
||||||
|
$this->load($cookieFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the file when shutting down
|
||||||
|
*/
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
$this->save($this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the cookies to a file.
|
||||||
|
*
|
||||||
|
* @param string $filename File to save
|
||||||
|
* @throws \RuntimeException if the file cannot be found or created
|
||||||
|
*/
|
||||||
|
public function save($filename)
|
||||||
|
{
|
||||||
|
$json = [];
|
||||||
|
foreach ($this as $cookie) {
|
||||||
|
if ($cookie->getExpires() && !$cookie->getDiscard()) {
|
||||||
|
$json[] = $cookie->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === file_put_contents($filename, json_encode($json))) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
throw new \RuntimeException("Unable to save file {$filename}");
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load cookies from a JSON formatted file.
|
||||||
|
*
|
||||||
|
* Old cookies are kept unless overwritten by newly loaded ones.
|
||||||
|
*
|
||||||
|
* @param string $filename Cookie file to load.
|
||||||
|
* @throws \RuntimeException if the file cannot be loaded.
|
||||||
|
*/
|
||||||
|
public function load($filename)
|
||||||
|
{
|
||||||
|
$json = file_get_contents($filename);
|
||||||
|
if (false === $json) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
throw new \RuntimeException("Unable to load file {$filename}");
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = \GuzzleHttp\json_decode($json, true);
|
||||||
|
if (is_array($data)) {
|
||||||
|
foreach (\GuzzleHttp\json_decode($json, true) as $cookie) {
|
||||||
|
$this->setCookie(new SetCookie($cookie));
|
||||||
|
}
|
||||||
|
} elseif (strlen($data)) {
|
||||||
|
throw new \RuntimeException("Invalid cookie file: {$filename}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Cookie;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists cookies in the client session
|
||||||
|
*/
|
||||||
|
class SessionCookieJar extends CookieJar
|
||||||
|
{
|
||||||
|
/** @var string session key */
|
||||||
|
private $sessionKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SessionCookieJar object
|
||||||
|
*
|
||||||
|
* @param string $sessionKey Session key name to store the cookie data in session
|
||||||
|
*/
|
||||||
|
public function __construct($sessionKey)
|
||||||
|
{
|
||||||
|
$this->sessionKey = $sessionKey;
|
||||||
|
$this->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves cookies to session when shutting down
|
||||||
|
*/
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save cookies to the client session
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$json = [];
|
||||||
|
foreach ($this as $cookie) {
|
||||||
|
if ($cookie->getExpires() && !$cookie->getDiscard()) {
|
||||||
|
$json[] = $cookie->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION[$this->sessionKey] = json_encode($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the contents of the client session into the data array
|
||||||
|
*/
|
||||||
|
protected function load()
|
||||||
|
{
|
||||||
|
$cookieJar = isset($_SESSION[$this->sessionKey])
|
||||||
|
? $_SESSION[$this->sessionKey]
|
||||||
|
: null;
|
||||||
|
|
||||||
|
$data = \GuzzleHttp\json_decode($cookieJar, true);
|
||||||
|
if (is_array($data)) {
|
||||||
|
foreach ($data as $cookie) {
|
||||||
|
$this->setCookie(new SetCookie($cookie));
|
||||||
|
}
|
||||||
|
} elseif (strlen($data)) {
|
||||||
|
throw new \RuntimeException("Invalid cookie data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
410
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Cookie/SetCookie.php
Normal file
410
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Cookie/SetCookie.php
Normal file
|
|
@ -0,0 +1,410 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Cookie;
|
||||||
|
|
||||||
|
use GuzzleHttp\ToArrayInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set-Cookie object
|
||||||
|
*/
|
||||||
|
class SetCookie implements ToArrayInterface
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
private static $defaults = [
|
||||||
|
'Name' => null,
|
||||||
|
'Value' => null,
|
||||||
|
'Domain' => null,
|
||||||
|
'Path' => '/',
|
||||||
|
'Max-Age' => null,
|
||||||
|
'Expires' => null,
|
||||||
|
'Secure' => false,
|
||||||
|
'Discard' => false,
|
||||||
|
'HttpOnly' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array Cookie data */
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SetCookie object from a string
|
||||||
|
*
|
||||||
|
* @param string $cookie Set-Cookie header string
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function fromString($cookie)
|
||||||
|
{
|
||||||
|
// Create the default return array
|
||||||
|
$data = self::$defaults;
|
||||||
|
// Explode the cookie string using a series of semicolons
|
||||||
|
$pieces = array_filter(array_map('trim', explode(';', $cookie)));
|
||||||
|
// The name of the cookie (first kvp) must include an equal sign.
|
||||||
|
if (empty($pieces) || !strpos($pieces[0], '=')) {
|
||||||
|
return new self($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the cookie pieces into the parsed data array
|
||||||
|
foreach ($pieces as $part) {
|
||||||
|
|
||||||
|
$cookieParts = explode('=', $part, 2);
|
||||||
|
$key = trim($cookieParts[0]);
|
||||||
|
$value = isset($cookieParts[1])
|
||||||
|
? trim($cookieParts[1], " \n\r\t\0\x0B\"")
|
||||||
|
: true;
|
||||||
|
|
||||||
|
// Only check for non-cookies when cookies have been found
|
||||||
|
if (empty($data['Name'])) {
|
||||||
|
$data['Name'] = $key;
|
||||||
|
$data['Value'] = $value;
|
||||||
|
} else {
|
||||||
|
foreach (array_keys(self::$defaults) as $search) {
|
||||||
|
if (!strcasecmp($search, $key)) {
|
||||||
|
$data[$search] = $value;
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data Array of cookie data provided by a Cookie parser
|
||||||
|
*/
|
||||||
|
public function __construct(array $data = [])
|
||||||
|
{
|
||||||
|
$this->data = array_replace(self::$defaults, $data);
|
||||||
|
// Extract the Expires value and turn it into a UNIX timestamp if needed
|
||||||
|
if (!$this->getExpires() && $this->getMaxAge()) {
|
||||||
|
// Calculate the Expires date
|
||||||
|
$this->setExpires(time() + $this->getMaxAge());
|
||||||
|
} elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
|
||||||
|
$this->setExpires($this->getExpires());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
|
||||||
|
foreach ($this->data as $k => $v) {
|
||||||
|
if ($k != 'Name' && $k != 'Value'&& $v !== null && $v !== false) {
|
||||||
|
if ($k == 'Expires') {
|
||||||
|
$str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
|
||||||
|
} else {
|
||||||
|
$str .= ($v === true ? $k : "{$k}={$v}") . '; ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtrim($str, '; ');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cookie name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->data['Name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cookie name
|
||||||
|
*
|
||||||
|
* @param string $name Cookie name
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->data['Name'] = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cookie value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
return $this->data['Value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cookie value
|
||||||
|
*
|
||||||
|
* @param string $value Cookie value
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setValue($value)
|
||||||
|
{
|
||||||
|
$this->data['Value'] = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the domain
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getDomain()
|
||||||
|
{
|
||||||
|
return $this->data['Domain'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the domain of the cookie
|
||||||
|
*
|
||||||
|
* @param string $domain
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setDomain($domain)
|
||||||
|
{
|
||||||
|
$this->data['Domain'] = $domain;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPath()
|
||||||
|
{
|
||||||
|
return $this->data['Path'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path of the cookie
|
||||||
|
*
|
||||||
|
* @param string $path Path of the cookie
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setPath($path)
|
||||||
|
{
|
||||||
|
$this->data['Path'] = $path;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum lifetime of the cookie in seconds
|
||||||
|
*
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function getMaxAge()
|
||||||
|
{
|
||||||
|
return $this->data['Max-Age'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the max-age of the cookie
|
||||||
|
*
|
||||||
|
* @param int $maxAge Max age of the cookie in seconds
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setMaxAge($maxAge)
|
||||||
|
{
|
||||||
|
$this->data['Max-Age'] = $maxAge;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UNIX timestamp when the cookie Expires
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getExpires()
|
||||||
|
{
|
||||||
|
return $this->data['Expires'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the unix timestamp for which the cookie will expire
|
||||||
|
*
|
||||||
|
* @param int $timestamp Unix timestamp
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setExpires($timestamp)
|
||||||
|
{
|
||||||
|
$this->data['Expires'] = is_numeric($timestamp)
|
||||||
|
? (int) $timestamp
|
||||||
|
: strtotime($timestamp);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether or not this is a secure cookie
|
||||||
|
*
|
||||||
|
* @return null|bool
|
||||||
|
*/
|
||||||
|
public function getSecure()
|
||||||
|
{
|
||||||
|
return $this->data['Secure'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not the cookie is secure
|
||||||
|
*
|
||||||
|
* @param bool $secure Set to true or false if secure
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setSecure($secure)
|
||||||
|
{
|
||||||
|
$this->data['Secure'] = $secure;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether or not this is a session cookie
|
||||||
|
*
|
||||||
|
* @return null|bool
|
||||||
|
*/
|
||||||
|
public function getDiscard()
|
||||||
|
{
|
||||||
|
return $this->data['Discard'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not this is a session cookie
|
||||||
|
*
|
||||||
|
* @param bool $discard Set to true or false if this is a session cookie
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setDiscard($discard)
|
||||||
|
{
|
||||||
|
$this->data['Discard'] = $discard;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether or not this is an HTTP only cookie
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getHttpOnly()
|
||||||
|
{
|
||||||
|
return $this->data['HttpOnly'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not this is an HTTP only cookie
|
||||||
|
*
|
||||||
|
* @param bool $httpOnly Set to true or false if this is HTTP only
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setHttpOnly($httpOnly)
|
||||||
|
{
|
||||||
|
$this->data['HttpOnly'] = $httpOnly;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the cookie matches a path value
|
||||||
|
*
|
||||||
|
* @param string $path Path to check against
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function matchesPath($path)
|
||||||
|
{
|
||||||
|
return !$this->getPath() || 0 === stripos($path, $this->getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the cookie matches a domain value
|
||||||
|
*
|
||||||
|
* @param string $domain Domain to check against
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function matchesDomain($domain)
|
||||||
|
{
|
||||||
|
// Remove the leading '.' as per spec in RFC 6265.
|
||||||
|
// http://tools.ietf.org/html/rfc6265#section-5.2.3
|
||||||
|
$cookieDomain = ltrim($this->getDomain(), '.');
|
||||||
|
|
||||||
|
// Domain not set or exact match.
|
||||||
|
if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matching the subdomain according to RFC 6265.
|
||||||
|
// http://tools.ietf.org/html/rfc6265#section-5.1.3
|
||||||
|
if (filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the cookie is expired
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isExpired()
|
||||||
|
{
|
||||||
|
return $this->getExpires() && time() > $this->getExpires();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the cookie is valid according to RFC 6265
|
||||||
|
*
|
||||||
|
* @return bool|string Returns true if valid or an error message if invalid
|
||||||
|
*/
|
||||||
|
public function validate()
|
||||||
|
{
|
||||||
|
// Names must not be empty, but can be 0
|
||||||
|
$name = $this->getName();
|
||||||
|
if (empty($name) && !is_numeric($name)) {
|
||||||
|
return 'The cookie name must not be empty';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any of the invalid characters are present in the cookie name
|
||||||
|
if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
|
||||||
|
return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value must not be empty, but can be 0
|
||||||
|
$value = $this->getValue();
|
||||||
|
if (empty($value) && !is_numeric($value)) {
|
||||||
|
return 'The cookie value must not be empty';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domains must not be empty, but can be 0
|
||||||
|
// A "0" is not a valid internet domain, but may be used as server name
|
||||||
|
// in a private network.
|
||||||
|
$domain = $this->getDomain();
|
||||||
|
if (empty($domain) && !is_numeric($domain)) {
|
||||||
|
return 'The cookie domain must not be empty';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic event class that can be extended.
|
||||||
|
*/
|
||||||
|
abstract class AbstractEvent implements EventInterface
|
||||||
|
{
|
||||||
|
private $propagationStopped = false;
|
||||||
|
|
||||||
|
public function isPropagationStopped()
|
||||||
|
{
|
||||||
|
return $this->propagationStopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopPropagation()
|
||||||
|
{
|
||||||
|
$this->propagationStopped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\ClientInterface;
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
|
||||||
|
abstract class AbstractRequestEvent extends AbstractEvent
|
||||||
|
{
|
||||||
|
/** @var TransactionInterface */
|
||||||
|
private $transaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionInterface $transaction
|
||||||
|
*/
|
||||||
|
public function __construct(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
$this->transaction = $transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the client associated with the event
|
||||||
|
*
|
||||||
|
* @return ClientInterface
|
||||||
|
*/
|
||||||
|
public function getClient()
|
||||||
|
{
|
||||||
|
return $this->transaction->getClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request object
|
||||||
|
*
|
||||||
|
* @return RequestInterface
|
||||||
|
*/
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
return $this->transaction->getRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TransactionInterface
|
||||||
|
*/
|
||||||
|
protected function getTransaction()
|
||||||
|
{
|
||||||
|
return $this->transaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event that contains transaction statistics (time over the wire, lookup time,
|
||||||
|
* etc.).
|
||||||
|
*
|
||||||
|
* Adapters that create this event SHOULD add, at a minimum, the 'total_time'
|
||||||
|
* transfer statistic that measures the amount of time, in seconds, taken to
|
||||||
|
* complete a transfer for the current request/response cycle. Each event
|
||||||
|
* pertains to a single request/response transaction, NOT the entire
|
||||||
|
* transaction (e.g. redirects).
|
||||||
|
*
|
||||||
|
* Adapters that add transaction statistics SHOULD follow the same string
|
||||||
|
* attribute names that are provided by cURL listed at
|
||||||
|
* http://php.net/manual/en/function.curl-getinfo.php. However, not all
|
||||||
|
* adapters will have access to the advanced statistics provided by cURL. The
|
||||||
|
* most useful transfer statistics are as follows:
|
||||||
|
*
|
||||||
|
* - total_time: Total transaction time in seconds for last transfer
|
||||||
|
* - namelookup_time: Time in seconds until name resolving was complete
|
||||||
|
* - connect_time: Time in seconds it took to establish the connection
|
||||||
|
* - pretransfer_time: Time in seconds from start until just before file
|
||||||
|
* transfer begins.
|
||||||
|
* - starttransfer_time: Time in seconds until the first byte is about to be
|
||||||
|
* transferred.
|
||||||
|
* - speed_download: Average download speed
|
||||||
|
* - speed_upload: Average upload speed
|
||||||
|
*/
|
||||||
|
abstract class AbstractTransferEvent extends AbstractRequestEvent
|
||||||
|
{
|
||||||
|
private $transferInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionInterface $transaction Transaction
|
||||||
|
* @param array $transferInfo Transfer statistics
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
$transferInfo = []
|
||||||
|
) {
|
||||||
|
parent::__construct($transaction);
|
||||||
|
$this->transferInfo = $transferInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all transfer information as an associative array if no $name
|
||||||
|
* argument is supplied, or gets a specific transfer statistic if
|
||||||
|
* a $name attribute is supplied (e.g., 'total_time').
|
||||||
|
*
|
||||||
|
* @param string $name Name of the transfer stat to retrieve
|
||||||
|
*
|
||||||
|
* @return mixed|null|array
|
||||||
|
*/
|
||||||
|
public function getTransferInfo($name = null)
|
||||||
|
{
|
||||||
|
if (!$name) {
|
||||||
|
return $this->transferInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($this->transferInfo[$name])
|
||||||
|
? $this->transferInfo[$name]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response
|
||||||
|
*
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
abstract public function getResponse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercept the request and associate a response
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response Response to set
|
||||||
|
*/
|
||||||
|
abstract public function intercept(ResponseInterface $response);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event object emitted before a request is sent.
|
||||||
|
*
|
||||||
|
* You may change the Response associated with the request using the
|
||||||
|
* intercept() method of the event.
|
||||||
|
*/
|
||||||
|
class BeforeEvent extends AbstractRequestEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Intercept the request and associate a response
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response Response to set
|
||||||
|
*/
|
||||||
|
public function intercept(ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->getTransaction()->setResponse($response);
|
||||||
|
$this->stopPropagation();
|
||||||
|
RequestEvents::emitComplete($this->getTransaction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event object emitted after a request has been completed.
|
||||||
|
*
|
||||||
|
* You may change the Response associated with the request using the
|
||||||
|
* intercept() method of the event.
|
||||||
|
*/
|
||||||
|
class CompleteEvent extends AbstractTransferEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Intercept the request and associate a response
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response Response to set
|
||||||
|
*/
|
||||||
|
public function intercept(ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->stopPropagation();
|
||||||
|
$this->getTransaction()->setResponse($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response of the request
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->getTransaction()->getResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
147
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Event/Emitter.php
Normal file
147
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Event/Emitter.php
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guzzle event emitter.
|
||||||
|
*
|
||||||
|
* Some of this class is based on the Symfony EventDispatcher component, which
|
||||||
|
* ships with the following license:
|
||||||
|
*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*
|
||||||
|
* @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
|
||||||
|
*/
|
||||||
|
class Emitter implements EmitterInterface
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
private $listeners = [];
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $sorted = [];
|
||||||
|
|
||||||
|
public function on($eventName, callable $listener, $priority = 0)
|
||||||
|
{
|
||||||
|
if ($priority === 'first') {
|
||||||
|
$priority = isset($this->listeners[$eventName])
|
||||||
|
? max(array_keys($this->listeners[$eventName])) + 1
|
||||||
|
: 1;
|
||||||
|
} elseif ($priority === 'last') {
|
||||||
|
$priority = isset($this->listeners[$eventName])
|
||||||
|
? min(array_keys($this->listeners[$eventName])) - 1
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->listeners[$eventName][$priority][] = $listener;
|
||||||
|
unset($this->sorted[$eventName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function once($eventName, callable $listener, $priority = 0)
|
||||||
|
{
|
||||||
|
$onceListener = function (
|
||||||
|
EventInterface $event,
|
||||||
|
$eventName
|
||||||
|
) use (&$onceListener, $eventName, $listener, $priority) {
|
||||||
|
$this->removeListener($eventName, $onceListener);
|
||||||
|
$listener($event, $eventName, $this);
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->on($eventName, $onceListener, $priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeListener($eventName, callable $listener)
|
||||||
|
{
|
||||||
|
if (!isset($this->listeners[$eventName])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->listeners[$eventName] as $priority => $listeners) {
|
||||||
|
if (false !== ($key = array_search($listener, $listeners, true))) {
|
||||||
|
unset(
|
||||||
|
$this->listeners[$eventName][$priority][$key],
|
||||||
|
$this->sorted[$eventName]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listeners($eventName = null)
|
||||||
|
{
|
||||||
|
// Return all events in a sorted priority order
|
||||||
|
if ($eventName === null) {
|
||||||
|
foreach (array_keys($this->listeners) as $eventName) {
|
||||||
|
if (!isset($this->sorted[$eventName])) {
|
||||||
|
$this->listeners($eventName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the listeners for a specific event, sorted in priority order
|
||||||
|
if (!isset($this->sorted[$eventName])) {
|
||||||
|
if (!isset($this->listeners[$eventName])) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
krsort($this->listeners[$eventName]);
|
||||||
|
$this->sorted[$eventName] = call_user_func_array(
|
||||||
|
'array_merge',
|
||||||
|
$this->listeners[$eventName]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sorted[$eventName];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emit($eventName, EventInterface $event)
|
||||||
|
{
|
||||||
|
if (isset($this->listeners[$eventName])) {
|
||||||
|
foreach ($this->listeners($eventName) as $listener) {
|
||||||
|
$listener($event, $eventName);
|
||||||
|
if ($event->isPropagationStopped()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attach(SubscriberInterface $subscriber)
|
||||||
|
{
|
||||||
|
foreach ($subscriber->getEvents() as $eventName => $listener) {
|
||||||
|
$this->on(
|
||||||
|
$eventName,
|
||||||
|
array($subscriber, $listener[0]),
|
||||||
|
isset($listener[1]) ? $listener[1] : 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detach(SubscriberInterface $subscriber)
|
||||||
|
{
|
||||||
|
foreach ($subscriber->getEvents() as $eventName => $listener) {
|
||||||
|
$this->removeListener($eventName, array($subscriber, $listener[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($name, $arguments)
|
||||||
|
{
|
||||||
|
return \GuzzleHttp\deprecation_proxy(
|
||||||
|
$this,
|
||||||
|
$name,
|
||||||
|
$arguments,
|
||||||
|
[
|
||||||
|
'addSubscriber' => 'attach',
|
||||||
|
'removeSubscriber' => 'detach',
|
||||||
|
'addListener' => 'on',
|
||||||
|
'dispatch' => 'emit'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guzzle event emitter.
|
||||||
|
*/
|
||||||
|
interface EmitterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Binds a listener to a specific event.
|
||||||
|
*
|
||||||
|
* @param string $eventName Name of the event to bind to.
|
||||||
|
* @param callable $listener Listener to invoke when triggered.
|
||||||
|
* @param int|string $priority The higher this value, the earlier an event
|
||||||
|
* listener will be triggered in the chain (defaults to 0). You can
|
||||||
|
* pass "first" or "last" to dynamically specify the event priority
|
||||||
|
* based on the current event priorities associated with the given
|
||||||
|
* event name in the emitter. Use "first" to set the priority to the
|
||||||
|
* current highest priority plus one. Use "last" to set the priority to
|
||||||
|
* the current lowest event priority minus one.
|
||||||
|
*/
|
||||||
|
public function on($eventName, callable $listener, $priority = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a listener to a specific event. After the listener is triggered
|
||||||
|
* once, it is removed as a listener.
|
||||||
|
*
|
||||||
|
* @param string $eventName Name of the event to bind to.
|
||||||
|
* @param callable $listener Listener to invoke when triggered.
|
||||||
|
* @param int $priority The higher this value, the earlier an event
|
||||||
|
* listener will be triggered in the chain (defaults to 0)
|
||||||
|
*/
|
||||||
|
public function once($eventName, callable $listener, $priority = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an event listener from the specified event.
|
||||||
|
*
|
||||||
|
* @param string $eventName The event to remove a listener from
|
||||||
|
* @param callable $listener The listener to remove
|
||||||
|
*/
|
||||||
|
public function removeListener($eventName, callable $listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the listeners of a specific event or all listeners if no event is
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* @param string $eventName The name of the event. Pass null (the default)
|
||||||
|
* to retrieve all listeners.
|
||||||
|
*
|
||||||
|
* @return array The event listeners for the specified event, or all event
|
||||||
|
* listeners by event name. The format of the array when retrieving a
|
||||||
|
* specific event list is an array of callables. The format of the array
|
||||||
|
* when retrieving all listeners is an associative array of arrays of
|
||||||
|
* callables.
|
||||||
|
*/
|
||||||
|
public function listeners($eventName = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event to all registered listeners.
|
||||||
|
*
|
||||||
|
* Each event that is bound to the emitted eventName receives a
|
||||||
|
* EventInterface, the name of the event, and the event emitter.
|
||||||
|
*
|
||||||
|
* @param string $eventName The name of the event to dispatch.
|
||||||
|
* @param EventInterface $event The event to pass to the event handlers/listeners.
|
||||||
|
*
|
||||||
|
* @return EventInterface Returns the provided event object
|
||||||
|
*/
|
||||||
|
public function emit($eventName, EventInterface $event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches an event subscriber.
|
||||||
|
*
|
||||||
|
* The subscriber is asked for all the events it is interested in and added
|
||||||
|
* as an event listener for each event.
|
||||||
|
*
|
||||||
|
* @param SubscriberInterface $subscriber Subscriber to attach.
|
||||||
|
*/
|
||||||
|
public function attach(SubscriberInterface $subscriber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches an event subscriber.
|
||||||
|
*
|
||||||
|
* @param SubscriberInterface $subscriber Subscriber to detach.
|
||||||
|
*/
|
||||||
|
public function detach(SubscriberInterface $subscriber);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event object emitted after a request has been sent and an error was
|
||||||
|
* encountered.
|
||||||
|
*
|
||||||
|
* You may intercept the exception and inject a response into the event to
|
||||||
|
* rescue the request.
|
||||||
|
*/
|
||||||
|
class ErrorEvent extends AbstractTransferEvent
|
||||||
|
{
|
||||||
|
private $exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionInterface $transaction Transaction that contains the request
|
||||||
|
* @param RequestException $e Exception encountered
|
||||||
|
* @param array $transferStats Array of transfer statistics
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
RequestException $e,
|
||||||
|
$transferStats = []
|
||||||
|
) {
|
||||||
|
parent::__construct($transaction, $transferStats);
|
||||||
|
$this->exception = $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercept the exception and inject a response
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response Response to set
|
||||||
|
*/
|
||||||
|
public function intercept(ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->stopPropagation();
|
||||||
|
$this->getTransaction()->setResponse($response);
|
||||||
|
RequestEvents::emitComplete($this->getTransaction());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the exception that was encountered
|
||||||
|
*
|
||||||
|
* @return RequestException
|
||||||
|
*/
|
||||||
|
public function getException()
|
||||||
|
{
|
||||||
|
return $this->exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response the was received (if any)
|
||||||
|
*
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->getException()->getResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base event interface used when dispatching events to listeners using an
|
||||||
|
* event emitter.
|
||||||
|
*/
|
||||||
|
interface EventInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns whether or not stopPropagation was called on the event.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @see Event::stopPropagation
|
||||||
|
*/
|
||||||
|
public function isPropagationStopped();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the propagation of the event, preventing subsequent listeners
|
||||||
|
* registered to the same event from being invoked.
|
||||||
|
*/
|
||||||
|
public function stopPropagation();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds an event emitter
|
||||||
|
*/
|
||||||
|
interface HasEmitterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the event emitter of the object
|
||||||
|
*
|
||||||
|
* @return EmitterInterface
|
||||||
|
*/
|
||||||
|
public function getEmitter();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait that implements the methods of HasEmitterInterface
|
||||||
|
*/
|
||||||
|
trait HasEmitterTrait
|
||||||
|
{
|
||||||
|
/** @var EmitterInterface */
|
||||||
|
private $emitter;
|
||||||
|
|
||||||
|
public function getEmitter()
|
||||||
|
{
|
||||||
|
if (!$this->emitter) {
|
||||||
|
$this->emitter = new Emitter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->emitter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event object emitted after the response headers of a request have been
|
||||||
|
* received.
|
||||||
|
*
|
||||||
|
* You may intercept the exception and inject a response into the event to
|
||||||
|
* rescue the request.
|
||||||
|
*/
|
||||||
|
class HeadersEvent extends AbstractRequestEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param TransactionInterface $transaction Transaction that contains the
|
||||||
|
* request and response.
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
public function __construct(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
parent::__construct($transaction);
|
||||||
|
if (!$transaction->getResponse()) {
|
||||||
|
throw new \RuntimeException('A response must be present');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response the was received
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->getTransaction()->getResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait that provides methods for extract event listeners specified in an array
|
||||||
|
* and attaching them to an emitter owned by the object or one of its direct
|
||||||
|
* dependencies.
|
||||||
|
*/
|
||||||
|
trait ListenerAttacherTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Attaches event listeners and properly sets their priorities and whether
|
||||||
|
* or not they are are only executed once.
|
||||||
|
*
|
||||||
|
* @param HasEmitterInterface $object Object that has the event emitter.
|
||||||
|
* @param array $listeners Array of hashes representing event
|
||||||
|
* event listeners. Each item contains
|
||||||
|
* "name", "fn", "priority", & "once".
|
||||||
|
*/
|
||||||
|
private function attachListeners(HasEmitterInterface $object, array $listeners)
|
||||||
|
{
|
||||||
|
$emitter = $object->getEmitter();
|
||||||
|
foreach ($listeners as $el) {
|
||||||
|
if ($el['once']) {
|
||||||
|
$emitter->once($el['name'], $el['fn'], $el['priority']);
|
||||||
|
} else {
|
||||||
|
$emitter->on($el['name'], $el['fn'], $el['priority']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the allowed events from the provided array, and ignores anything
|
||||||
|
* else in the array. The event listener must be specified as a callable or
|
||||||
|
* as an array of event listener data ("name", "fn", "priority", "once").
|
||||||
|
*
|
||||||
|
* @param array $source Array containing callables or hashes of data to be
|
||||||
|
* prepared as event listeners.
|
||||||
|
* @param array $events Names of events to look for in the provided $source
|
||||||
|
* array. Other keys are ignored.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function prepareListeners(array $source, array $events)
|
||||||
|
{
|
||||||
|
$listeners = [];
|
||||||
|
foreach ($events as $name) {
|
||||||
|
if (isset($source[$name])) {
|
||||||
|
$this->buildListener($name, $source[$name], $listeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a complete event listener definition from the provided array of
|
||||||
|
* listener data. Also works recursively if more than one listeners are
|
||||||
|
* contained in the provided array.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the event the listener is for.
|
||||||
|
* @param array|callable $data Event listener data to prepare.
|
||||||
|
* @param array $listeners Array of listeners, passed by reference.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException if the event data is malformed.
|
||||||
|
*/
|
||||||
|
private function buildListener($name, $data, &$listeners)
|
||||||
|
{
|
||||||
|
static $defaults = ['priority' => 0, 'once' => false];
|
||||||
|
|
||||||
|
// If a callable is provided, normalize it to the array format.
|
||||||
|
if (is_callable($data)) {
|
||||||
|
$data = ['fn' => $data];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the listener and add it to the array, recursively.
|
||||||
|
if (isset($data['fn'])) {
|
||||||
|
$data['name'] = $name;
|
||||||
|
$listeners[] = $data + $defaults;
|
||||||
|
} elseif (is_array($data)) {
|
||||||
|
foreach ($data as $listenerData) {
|
||||||
|
$this->buildListener($name, $listenerData, $listeners);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Each event listener must be a '
|
||||||
|
. 'callable or an associative array containing a "fn" key.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
use GuzzleHttp\Adapter\TransactionInterface;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains methods used to manage the request event lifecycle.
|
||||||
|
*/
|
||||||
|
final class RequestEvents
|
||||||
|
{
|
||||||
|
// Generic event priorities
|
||||||
|
const EARLY = 10000;
|
||||||
|
const LATE = -10000;
|
||||||
|
|
||||||
|
// "before" priorities
|
||||||
|
const PREPARE_REQUEST = -100;
|
||||||
|
const SIGN_REQUEST = -10000;
|
||||||
|
|
||||||
|
// "complete" and "error" response priorities
|
||||||
|
const VERIFY_RESPONSE = 100;
|
||||||
|
const REDIRECT_RESPONSE = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits the before send event for a request and emits an error
|
||||||
|
* event if an error is encountered during the before send.
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction
|
||||||
|
*
|
||||||
|
* @throws RequestException
|
||||||
|
*/
|
||||||
|
public static function emitBefore(TransactionInterface $transaction) {
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
try {
|
||||||
|
$request->getEmitter()->emit(
|
||||||
|
'before',
|
||||||
|
new BeforeEvent($transaction)
|
||||||
|
);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
// When a RequestException has been emitted through emitError, the
|
||||||
|
// exception is marked as "emitted". This means that the exception
|
||||||
|
// had a chance to be rescued but was not. In this case, this method
|
||||||
|
// must not emit the error again, but rather throw the exception.
|
||||||
|
// This prevents RequestExceptions encountered during the before
|
||||||
|
// event from being emitted to listeners twice.
|
||||||
|
if ($e->emittedError()) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
self::emitError($transaction, $e);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::emitError($transaction, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits the complete event for a request and emits an error
|
||||||
|
* event if an error is encountered during the after send.
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction Transaction to emit for
|
||||||
|
* @param array $stats Transfer stats
|
||||||
|
*
|
||||||
|
* @throws RequestException
|
||||||
|
*/
|
||||||
|
public static function emitComplete(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
array $stats = []
|
||||||
|
) {
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
$transaction->getResponse()->setEffectiveUrl($request->getUrl());
|
||||||
|
try {
|
||||||
|
$request->getEmitter()->emit(
|
||||||
|
'complete',
|
||||||
|
new CompleteEvent($transaction, $stats)
|
||||||
|
);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
self::emitError($transaction, $e, $stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits the headers event for a request.
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction Transaction to emit for
|
||||||
|
*/
|
||||||
|
public static function emitHeaders(TransactionInterface $transaction)
|
||||||
|
{
|
||||||
|
$transaction->getRequest()->getEmitter()->emit(
|
||||||
|
'headers',
|
||||||
|
new HeadersEvent($transaction)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an error event for a request and accounts for the propagation
|
||||||
|
* of an error event being stopped to prevent the exception from being
|
||||||
|
* thrown.
|
||||||
|
*
|
||||||
|
* @param TransactionInterface $transaction
|
||||||
|
* @param \Exception $e
|
||||||
|
* @param array $stats
|
||||||
|
*
|
||||||
|
* @throws \GuzzleHttp\Exception\RequestException
|
||||||
|
*/
|
||||||
|
public static function emitError(
|
||||||
|
TransactionInterface $transaction,
|
||||||
|
\Exception $e,
|
||||||
|
array $stats = []
|
||||||
|
) {
|
||||||
|
$request = $transaction->getRequest();
|
||||||
|
|
||||||
|
// Convert non-request exception to a wrapped exception
|
||||||
|
if (!($e instanceof RequestException)) {
|
||||||
|
$e = new RequestException($e->getMessage(), $request, null, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the exception as having been emitted for an error event. This
|
||||||
|
// works in tandem with the emitBefore method to prevent the error
|
||||||
|
// event from being triggered twice for the same exception.
|
||||||
|
$e->emittedError(true);
|
||||||
|
|
||||||
|
// Dispatch an event and allow interception
|
||||||
|
if (!$request->getEmitter()->emit(
|
||||||
|
'error',
|
||||||
|
new ErrorEvent($transaction, $e, $stats)
|
||||||
|
)->isPropagationStopped()) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an array of event options into a formatted array of valid event
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @param array $options Event array to convert
|
||||||
|
* @param array $events Event names to convert in the options array.
|
||||||
|
* @param mixed $handler Event handler to utilize
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \InvalidArgumentException if the event config is invalid
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function convertEventArray(
|
||||||
|
array $options,
|
||||||
|
array $events,
|
||||||
|
$handler
|
||||||
|
) {
|
||||||
|
foreach ($events as $name) {
|
||||||
|
if (!isset($options[$name])) {
|
||||||
|
$options[$name] = $handler;
|
||||||
|
} elseif (is_callable($options[$name])) {
|
||||||
|
$options[$name] = [['fn' => $options[$name]], $handler];
|
||||||
|
} elseif (is_array($options[$name])) {
|
||||||
|
$options[$name][] = $handler;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Invalid event format');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SubscriberInterface provides an array of events to an
|
||||||
|
* EventEmitterInterface when it is registered. The emitter then binds the
|
||||||
|
* listeners specified by the EventSubscriber.
|
||||||
|
*
|
||||||
|
* This interface is based on the SubscriberInterface of the Symfony.
|
||||||
|
* @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
|
||||||
|
*/
|
||||||
|
interface SubscriberInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns an array of event names this subscriber wants to listen to.
|
||||||
|
*
|
||||||
|
* The returned array keys MUST map to an event name. Each array value
|
||||||
|
* MUST be an array in which the first element is the name of a function
|
||||||
|
* on the EventSubscriber. The second element in the array is optional, and
|
||||||
|
* if specified, designates the event priority.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* - ['eventName' => ['methodName']]
|
||||||
|
* - ['eventName' => ['methodName', $priority]]
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getEvents();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
class AdapterException extends TransferException {}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception when an HTTP error occurs (4xx or 5xx error)
|
||||||
|
*/
|
||||||
|
class BadResponseException extends RequestException {}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception when a client error is encountered (4xx codes)
|
||||||
|
*/
|
||||||
|
class ClientException extends BadResponseException {}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
class CouldNotRewindStreamException extends RequestException {}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception when a client is unable to parse the response body as XML or JSON
|
||||||
|
*/
|
||||||
|
class ParseException extends TransferException
|
||||||
|
{
|
||||||
|
/** @var ResponseInterface */
|
||||||
|
private $response;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
$message = '',
|
||||||
|
ResponseInterface $response = null,
|
||||||
|
\Exception $previous = null
|
||||||
|
) {
|
||||||
|
parent::__construct($message, 0, $previous);
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the associated response
|
||||||
|
*
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Request exception
|
||||||
|
*/
|
||||||
|
class RequestException extends TransferException
|
||||||
|
{
|
||||||
|
/** @var bool */
|
||||||
|
private $emittedErrorEvent = false;
|
||||||
|
|
||||||
|
/** @var RequestInterface */
|
||||||
|
private $request;
|
||||||
|
|
||||||
|
/** @var ResponseInterface */
|
||||||
|
private $response;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
$message = '',
|
||||||
|
RequestInterface $request,
|
||||||
|
ResponseInterface $response = null,
|
||||||
|
\Exception $previous = null
|
||||||
|
) {
|
||||||
|
$code = $response ? $response->getStatusCode() : 0;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
$this->request = $request;
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to create a new exception with a normalized error message
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request
|
||||||
|
* @param ResponseInterface $response Response received
|
||||||
|
* @param \Exception $previous Previous exception
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function create(
|
||||||
|
RequestInterface $request,
|
||||||
|
ResponseInterface $response = null,
|
||||||
|
\Exception $previous = null
|
||||||
|
) {
|
||||||
|
if (!$response) {
|
||||||
|
return new self('Error completing request', $request, null, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
$level = $response->getStatusCode()[0];
|
||||||
|
if ($level == '4') {
|
||||||
|
$label = 'Client error response';
|
||||||
|
$className = __NAMESPACE__ . '\\ClientException';
|
||||||
|
} elseif ($level == '5') {
|
||||||
|
$label = 'Server error response';
|
||||||
|
$className = __NAMESPACE__ . '\\ServerException';
|
||||||
|
} else {
|
||||||
|
$label = 'Unsuccessful response';
|
||||||
|
$className = __CLASS__;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $label . ' [url] ' . $request->getUrl()
|
||||||
|
. ' [status code] ' . $response->getStatusCode()
|
||||||
|
. ' [reason phrase] ' . $response->getReasonPhrase();
|
||||||
|
|
||||||
|
return new $className($message, $request, $response, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request that caused the exception
|
||||||
|
*
|
||||||
|
* @return RequestInterface
|
||||||
|
*/
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the associated response
|
||||||
|
*
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a response was received
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasResponse()
|
||||||
|
{
|
||||||
|
return $this->response !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check or set if the exception was emitted in an error event.
|
||||||
|
*
|
||||||
|
* This value is used in the RequestEvents::emitBefore() method to check
|
||||||
|
* to see if an exception has already been emitted in an error event.
|
||||||
|
*
|
||||||
|
* @param bool|null Set to true to set the exception as having emitted an
|
||||||
|
* error. Leave null to retrieve the current setting.
|
||||||
|
*
|
||||||
|
* @return null|bool
|
||||||
|
* @throws \InvalidArgumentException if you attempt to set the value to false
|
||||||
|
*/
|
||||||
|
public function emittedError($value = null)
|
||||||
|
{
|
||||||
|
if ($value === null) {
|
||||||
|
return $this->emittedErrorEvent;
|
||||||
|
} elseif ($value === true) {
|
||||||
|
return $this->emittedErrorEvent = true;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('You cannot set the emitted '
|
||||||
|
. 'error value to false.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception when a server error is encountered (5xx codes)
|
||||||
|
*/
|
||||||
|
class ServerException extends BadResponseException {}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
class TooManyRedirectsException extends RequestException {}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Exception;
|
||||||
|
|
||||||
|
class TransferException extends \RuntimeException {}
|
||||||
76
rainloop/v/0.0.0/app/libraries/GuzzleHttp/HasDataTrait.php
Normal file
76
rainloop/v/0.0.0/app/libraries/GuzzleHttp/HasDataTrait.php
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait implementing ToArrayInterface, \ArrayAccess, \Countable,
|
||||||
|
* \IteratorAggregate, and some path style methods.
|
||||||
|
*/
|
||||||
|
trait HasDataTrait
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
protected $data = [];
|
||||||
|
|
||||||
|
public function getIterator()
|
||||||
|
{
|
||||||
|
return new \ArrayIterator($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet($offset)
|
||||||
|
{
|
||||||
|
return isset($this->data[$offset]) ? $this->data[$offset] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetSet($offset, $value)
|
||||||
|
{
|
||||||
|
$this->data[$offset] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetExists($offset)
|
||||||
|
{
|
||||||
|
return isset($this->data[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetUnset($offset)
|
||||||
|
{
|
||||||
|
unset($this->data[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return count($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from the collection using a path syntax to retrieve nested
|
||||||
|
* data.
|
||||||
|
*
|
||||||
|
* @param string $path Path to traverse and retrieve a value from
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function getPath($path)
|
||||||
|
{
|
||||||
|
return \GuzzleHttp\get_path($this->data, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a value into a nested array key. Keys will be created as needed to
|
||||||
|
* set the value.
|
||||||
|
*
|
||||||
|
* @param string $path Path to set
|
||||||
|
* @param mixed $value Value to set at the key
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException when trying to setPath using a nested path
|
||||||
|
* that travels through a scalar value
|
||||||
|
*/
|
||||||
|
public function setPath($path, $value)
|
||||||
|
{
|
||||||
|
\GuzzleHttp\set_path($this->data, $path, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,237 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
abstract class AbstractMessage implements MessageInterface
|
||||||
|
{
|
||||||
|
/** @var array HTTP header collection */
|
||||||
|
private $headers = [];
|
||||||
|
|
||||||
|
/** @var array mapping a lowercase header name to its name over the wire */
|
||||||
|
private $headerNames = [];
|
||||||
|
|
||||||
|
/** @var StreamInterface Message body */
|
||||||
|
private $body;
|
||||||
|
|
||||||
|
/** @var string HTTP protocol version of the message */
|
||||||
|
private $protocolVersion = '1.1';
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$result = $this->getStartLine();
|
||||||
|
foreach ($this->getHeaders() as $name => $values) {
|
||||||
|
$result .= "\r\n{$name}: " . implode(', ', $values);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result . "\r\n\r\n" . $this->body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProtocolVersion()
|
||||||
|
{
|
||||||
|
return $this->protocolVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBody()
|
||||||
|
{
|
||||||
|
return $this->body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBody(StreamInterface $body = null)
|
||||||
|
{
|
||||||
|
if ($body === null) {
|
||||||
|
// Setting a null body will remove the body of the request
|
||||||
|
$this->removeHeader('Content-Length')
|
||||||
|
->removeHeader('Transfer-Encoding');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->body = $body;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addHeader($header, $value)
|
||||||
|
{
|
||||||
|
static $valid = ['string' => true, 'integer' => true,
|
||||||
|
'double' => true, 'array' => true];
|
||||||
|
|
||||||
|
$type = gettype($value);
|
||||||
|
if (!isset($valid[$type])) {
|
||||||
|
throw new \InvalidArgumentException('Invalid header value');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type == 'array') {
|
||||||
|
$current = array_merge($this->getHeader($header, true), $value);
|
||||||
|
} else {
|
||||||
|
$current = $this->getHeader($header, true);
|
||||||
|
$current[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->setHeader($header, $current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addHeaders(array $headers)
|
||||||
|
{
|
||||||
|
foreach ($headers as $name => $header) {
|
||||||
|
$this->addHeader($name, $header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeader($header, $asArray = false)
|
||||||
|
{
|
||||||
|
$name = strtolower($header);
|
||||||
|
|
||||||
|
if (!isset($this->headers[$name])) {
|
||||||
|
return $asArray ? [] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $asArray
|
||||||
|
? $this->headers[$name]
|
||||||
|
: implode(', ', $this->headers[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaders()
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
foreach ($this->headers as $name => $values) {
|
||||||
|
$headers[$this->headerNames[$name]] = $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeader($header, $value)
|
||||||
|
{
|
||||||
|
$header = trim($header);
|
||||||
|
$name = strtolower($header);
|
||||||
|
$this->headerNames[$name] = $header;
|
||||||
|
|
||||||
|
switch (gettype($value)) {
|
||||||
|
case 'string':
|
||||||
|
$this->headers[$name] = [trim($value)];
|
||||||
|
break;
|
||||||
|
case 'integer':
|
||||||
|
case 'double':
|
||||||
|
$this->headers[$name] = [(string) $value];
|
||||||
|
break;
|
||||||
|
case 'array':
|
||||||
|
foreach ($value as &$v) {
|
||||||
|
$v = trim($v);
|
||||||
|
}
|
||||||
|
$this->headers[$name] = $value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid header value '
|
||||||
|
. 'provided: ' . var_export($value, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeaders(array $headers)
|
||||||
|
{
|
||||||
|
$this->headers = $this->headerNames = [];
|
||||||
|
foreach ($headers as $key => $value) {
|
||||||
|
$this->setHeader($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasHeader($header)
|
||||||
|
{
|
||||||
|
return isset($this->headers[strtolower($header)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeHeader($header)
|
||||||
|
{
|
||||||
|
$name = strtolower($header);
|
||||||
|
unset($this->headers[$name], $this->headerNames[$name]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an array of header values containing ";" separated data into an
|
||||||
|
* array of associative arrays representing the header key value pair
|
||||||
|
* data of the header. When a parameter does not contain a value, but just
|
||||||
|
* contains a key, this function will inject a key with a '' string value.
|
||||||
|
*
|
||||||
|
* @param MessageInterface $message That contains the header
|
||||||
|
* @param string $header Header to retrieve from the message
|
||||||
|
*
|
||||||
|
* @return array Returns the parsed header values.
|
||||||
|
*/
|
||||||
|
public static function parseHeader(MessageInterface $message, $header)
|
||||||
|
{
|
||||||
|
static $trimmed = "\"' \n\t\r";
|
||||||
|
$params = $matches = [];
|
||||||
|
|
||||||
|
foreach (self::normalizeHeader($message, $header) as $val) {
|
||||||
|
$part = [];
|
||||||
|
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
|
||||||
|
if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
|
||||||
|
$m = $matches[0];
|
||||||
|
if (isset($m[1])) {
|
||||||
|
$part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
|
||||||
|
} else {
|
||||||
|
$part[] = trim($m[0], $trimmed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($part) {
|
||||||
|
$params[] = $part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an array of header values that may contain comma separated
|
||||||
|
* headers into an array of headers with no comma separated values.
|
||||||
|
*
|
||||||
|
* @param MessageInterface $message That contains the header
|
||||||
|
* @param string $header Header to retrieve from the message
|
||||||
|
*
|
||||||
|
* @return array Returns the normalized header field values.
|
||||||
|
*/
|
||||||
|
public static function normalizeHeader(MessageInterface $message, $header)
|
||||||
|
{
|
||||||
|
$h = $message->getHeader($header, true);
|
||||||
|
for ($i = 0, $total = count($h); $i < $total; $i++) {
|
||||||
|
if (strpos($h[$i], ',') === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
|
||||||
|
$h[] = trim($v);
|
||||||
|
}
|
||||||
|
unset($h[$i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the start line of a message.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract protected function getStartLine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts and modifies the options provided to the message in the
|
||||||
|
* constructor.
|
||||||
|
*
|
||||||
|
* Can be overridden in subclasses as necessary.
|
||||||
|
*
|
||||||
|
* @param array $options Options array passed by reference.
|
||||||
|
*/
|
||||||
|
protected function handleOptions(array &$options)
|
||||||
|
{
|
||||||
|
if (isset($options['protocol_version'])) {
|
||||||
|
$this->protocolVersion = $options['protocol_version'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,345 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\ListenerAttacherTrait;
|
||||||
|
use GuzzleHttp\Post\PostFileInterface;
|
||||||
|
use GuzzleHttp\Subscriber\Cookie;
|
||||||
|
use GuzzleHttp\Cookie\CookieJar;
|
||||||
|
use GuzzleHttp\Cookie\CookieJarInterface;
|
||||||
|
use GuzzleHttp\Subscriber\HttpError;
|
||||||
|
use GuzzleHttp\Post\PostBody;
|
||||||
|
use GuzzleHttp\Post\PostFile;
|
||||||
|
use GuzzleHttp\Subscriber\Redirect;
|
||||||
|
use GuzzleHttp\Stream;
|
||||||
|
use GuzzleHttp\Query;
|
||||||
|
use GuzzleHttp\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default HTTP request factory used to create Request and Response objects.
|
||||||
|
*/
|
||||||
|
class MessageFactory implements MessageFactoryInterface
|
||||||
|
{
|
||||||
|
use ListenerAttacherTrait;
|
||||||
|
|
||||||
|
/** @var HttpError */
|
||||||
|
private $errorPlugin;
|
||||||
|
|
||||||
|
/** @var Redirect */
|
||||||
|
private $redirectPlugin;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected static $classMethods = [];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->errorPlugin = new HttpError();
|
||||||
|
$this->redirectPlugin = new Redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createResponse(
|
||||||
|
$statusCode,
|
||||||
|
array $headers = [],
|
||||||
|
$body = null,
|
||||||
|
array $options = []
|
||||||
|
) {
|
||||||
|
if (null !== $body) {
|
||||||
|
$body = Stream\create($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response($statusCode, $headers, $body, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createRequest($method, $url, array $options = [])
|
||||||
|
{
|
||||||
|
// Handle the request protocol version option that needs to be
|
||||||
|
// specified in the request constructor.
|
||||||
|
if (isset($options['version'])) {
|
||||||
|
$options['config']['protocol_version'] = $options['version'];
|
||||||
|
unset($options['version']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = new Request($method, $url, [], null,
|
||||||
|
isset($options['config']) ? $options['config'] : []);
|
||||||
|
|
||||||
|
unset($options['config']);
|
||||||
|
|
||||||
|
// Use a POST body by default
|
||||||
|
if ($method == 'POST' &&
|
||||||
|
!isset($options['body']) &&
|
||||||
|
!isset($options['json'])
|
||||||
|
) {
|
||||||
|
$options['body'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options) {
|
||||||
|
$this->applyOptions($request, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a request or response object from an HTTP message string
|
||||||
|
*
|
||||||
|
* @param string $message Message to parse
|
||||||
|
*
|
||||||
|
* @return RequestInterface|ResponseInterface
|
||||||
|
* @throws \InvalidArgumentException if unable to parse a message
|
||||||
|
*/
|
||||||
|
public function fromMessage($message)
|
||||||
|
{
|
||||||
|
static $parser;
|
||||||
|
if (!$parser) {
|
||||||
|
$parser = new MessageParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a response
|
||||||
|
if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
|
||||||
|
$data = $parser->parseResponse($message);
|
||||||
|
return $this->createResponse(
|
||||||
|
$data['code'],
|
||||||
|
$data['headers'],
|
||||||
|
$data['body'] === '' ? null : $data['body'],
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a request
|
||||||
|
if (!($data = ($parser->parseRequest($message)))) {
|
||||||
|
throw new \InvalidArgumentException('Unable to parse request');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createRequest(
|
||||||
|
$data['method'],
|
||||||
|
Url::buildUrl($data['request_url']),
|
||||||
|
[
|
||||||
|
'headers' => $data['headers'],
|
||||||
|
'body' => $data['body'] === '' ? null : $data['body'],
|
||||||
|
'config' => [
|
||||||
|
'protocol_version' => $data['protocol_version']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply POST fields and files to a request to attempt to give an accurate
|
||||||
|
* representation.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request to update
|
||||||
|
* @param array $body Body to apply
|
||||||
|
*/
|
||||||
|
protected function addPostData(RequestInterface $request, array $body)
|
||||||
|
{
|
||||||
|
static $fields = ['string' => true, 'array' => true, 'NULL' => true,
|
||||||
|
'boolean' => true, 'double' => true, 'integer' => true];
|
||||||
|
|
||||||
|
$post = new PostBody();
|
||||||
|
foreach ($body as $key => $value) {
|
||||||
|
if (isset($fields[gettype($value)])) {
|
||||||
|
$post->setField($key, $value);
|
||||||
|
} elseif ($value instanceof PostFileInterface) {
|
||||||
|
$post->addFile($value);
|
||||||
|
} else {
|
||||||
|
$post->addFile(new PostFile($key, $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->setBody($post);
|
||||||
|
$post->applyRequestHeaders($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyOptions(
|
||||||
|
RequestInterface $request,
|
||||||
|
array $options = []
|
||||||
|
) {
|
||||||
|
// Values specified in the config map are passed to request options
|
||||||
|
static $configMap = ['connect_timeout' => 1, 'timeout' => 1,
|
||||||
|
'verify' => 1, 'ssl_key' => 1, 'cert' => 1, 'proxy' => 1,
|
||||||
|
'debug' => 1, 'save_to' => 1, 'stream' => 1, 'expect' => 1];
|
||||||
|
|
||||||
|
// Take the class of the instance, not the parent
|
||||||
|
$selfClass = get_class($this);
|
||||||
|
|
||||||
|
// Check if we already took it's class methods and had them saved
|
||||||
|
if (!isset(self::$classMethods[$selfClass])) {
|
||||||
|
self::$classMethods[$selfClass] = array_flip(get_class_methods($this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take class methods of this particular instance
|
||||||
|
$methods = self::$classMethods[$selfClass];
|
||||||
|
|
||||||
|
// Iterate over each key value pair and attempt to apply a config using
|
||||||
|
// double dispatch.
|
||||||
|
$config = $request->getConfig();
|
||||||
|
foreach ($options as $key => $value) {
|
||||||
|
$method = "add_{$key}";
|
||||||
|
if (isset($methods[$method])) {
|
||||||
|
$this->{$method}($request, $value);
|
||||||
|
} elseif (isset($configMap[$key])) {
|
||||||
|
$config[$key] = $value;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException("No method is configured "
|
||||||
|
. "to handle the {$key} config key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_body(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if ($value !== null) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$this->addPostData($request, $value);
|
||||||
|
} else {
|
||||||
|
$request->setBody(Stream\create($value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_allow_redirects(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
static $defaultRedirect = [
|
||||||
|
'max' => 5,
|
||||||
|
'strict' => false,
|
||||||
|
'referer' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($value === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value === true) {
|
||||||
|
$value = $defaultRedirect;
|
||||||
|
} elseif (!isset($value['max'])) {
|
||||||
|
throw new \InvalidArgumentException('allow_redirects must be '
|
||||||
|
. 'true, false, or an array that contains the \'max\' key');
|
||||||
|
} else {
|
||||||
|
// Merge the default settings with the provided settings
|
||||||
|
$value += $defaultRedirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->getConfig()['redirect'] = $value;
|
||||||
|
$request->getEmitter()->attach($this->redirectPlugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_exceptions(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if ($value === true) {
|
||||||
|
$request->getEmitter()->attach($this->errorPlugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_auth(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if (!$value) {
|
||||||
|
return;
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
$authType = isset($value[2]) ? strtolower($value[2]) : 'basic';
|
||||||
|
} else {
|
||||||
|
$authType = strtolower($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->getConfig()->set('auth', $value);
|
||||||
|
|
||||||
|
if ($authType == 'basic') {
|
||||||
|
$request->setHeader(
|
||||||
|
'Authorization',
|
||||||
|
'Basic ' . base64_encode("$value[0]:$value[1]")
|
||||||
|
);
|
||||||
|
} elseif ($authType == 'digest') {
|
||||||
|
// Currently only implemented by the cURL adapter.
|
||||||
|
// @todo: Need an event listener solution that does not rely on cURL
|
||||||
|
$config = $request->getConfig();
|
||||||
|
$config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
||||||
|
$config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_query(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if ($value instanceof Query) {
|
||||||
|
$original = $request->getQuery();
|
||||||
|
// Do not overwrite existing query string variables by overwriting
|
||||||
|
// the object with the query string data passed in the URL
|
||||||
|
$request->setQuery($value->overwriteWith($original->toArray()));
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
// Do not overwrite existing query string variables
|
||||||
|
$query = $request->getQuery();
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if (!isset($query[$k])) {
|
||||||
|
$query[$k] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('query value must be an array '
|
||||||
|
. 'or Query object');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_headers(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new \InvalidArgumentException('header value must be an array');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not overwrite existing headers
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if (!$request->hasHeader($k)) {
|
||||||
|
$request->setHeader($k, $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_cookies(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if ($value === true) {
|
||||||
|
static $cookie = null;
|
||||||
|
if (!$cookie) {
|
||||||
|
$cookie = new Cookie();
|
||||||
|
}
|
||||||
|
$request->getEmitter()->attach($cookie);
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
$request->getEmitter()->attach(
|
||||||
|
new Cookie(CookieJar::fromArray($value, $request->getHost()))
|
||||||
|
);
|
||||||
|
} elseif ($value instanceof CookieJarInterface) {
|
||||||
|
$request->getEmitter()->attach(new Cookie($value));
|
||||||
|
} elseif ($value !== false) {
|
||||||
|
throw new \InvalidArgumentException('cookies must be an array, '
|
||||||
|
. 'true, or a CookieJarInterface object');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_events(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new \InvalidArgumentException('events value must be an array');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->attachListeners($request, $this->prepareListeners($value,
|
||||||
|
['before', 'complete', 'error', 'headers']
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_subscribers(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new \InvalidArgumentException('subscribers must be an array');
|
||||||
|
}
|
||||||
|
|
||||||
|
$emitter = $request->getEmitter();
|
||||||
|
foreach ($value as $subscribers) {
|
||||||
|
$emitter->attach($subscribers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function add_json(RequestInterface $request, $value)
|
||||||
|
{
|
||||||
|
if (!$request->hasHeader('Content-Type')) {
|
||||||
|
$request->setHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->setBody(Stream\create(json_encode($value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request and response factory
|
||||||
|
*/
|
||||||
|
interface MessageFactoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a response
|
||||||
|
*
|
||||||
|
* @param string $statusCode HTTP status code
|
||||||
|
* @param array $headers Response headers
|
||||||
|
* @param mixed $body Response body
|
||||||
|
* @param array $options Response options
|
||||||
|
* - protocol_version: HTTP protocol version
|
||||||
|
* - header_factory: Factory used to create headers
|
||||||
|
* - And any other options used by a concrete message implementation
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
public function createResponse(
|
||||||
|
$statusCode,
|
||||||
|
array $headers = [],
|
||||||
|
$body = null,
|
||||||
|
array $options = []
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new request based on the HTTP method.
|
||||||
|
*
|
||||||
|
* This method accepts an associative array of request options. Below is a
|
||||||
|
* brief description of each parameter. See
|
||||||
|
* http://docs.guzzlephp.org/clients.html#request-options for a much more
|
||||||
|
* in-depth description of each parameter.
|
||||||
|
*
|
||||||
|
* - headers: Associative array of headers to add to the request
|
||||||
|
* - body: string|resource|array|StreamInterface request body to send
|
||||||
|
* - json: mixed Uploads JSON encoded data using an application/json Content-Type header.
|
||||||
|
* - query: Associative array of query string values to add to the request
|
||||||
|
* - auth: array|string HTTP auth settings (user, pass[, type="basic"])
|
||||||
|
* - version: The HTTP protocol version to use with the request
|
||||||
|
* - cookies: true|false|CookieJarInterface To enable or disable cookies
|
||||||
|
* - allow_redirects: true|false|array Controls HTTP redirects
|
||||||
|
* - save_to: string|resource|StreamInterface Where the response is saved
|
||||||
|
* - events: Associative array of event names to callables or arrays
|
||||||
|
* - subscribers: Array of event subscribers to add to the request
|
||||||
|
* - exceptions: Specifies whether or not exceptions are thrown for HTTP protocol errors
|
||||||
|
* - timeout: Timeout of the request in seconds. Use 0 to wait indefinitely
|
||||||
|
* - connect_timeout: Number of seconds to wait while trying to connect. (0 to wait indefinitely)
|
||||||
|
* - verify: SSL validation. True/False or the path to a PEM file
|
||||||
|
* - cert: Path a SSL cert or array of (path, pwd)
|
||||||
|
* - ssl_key: Path to a private SSL key or array of (path, pwd)
|
||||||
|
* - proxy: Specify an HTTP proxy or hash of protocols to proxies
|
||||||
|
* - debug: Set to true or a resource to view adapter specific debug info
|
||||||
|
* - stream: Set to true to stream a response body rather than download it all up front
|
||||||
|
* - expect: true/false/integer Controls the "Expect: 100-Continue" header
|
||||||
|
* - config: Associative array of request config collection options
|
||||||
|
*
|
||||||
|
* @param string $method HTTP method (GET, POST, PUT, etc.)
|
||||||
|
* @param string|Url $url HTTP URL to connect to
|
||||||
|
* @param array $options Array of options to apply to the request
|
||||||
|
*
|
||||||
|
* @return RequestInterface
|
||||||
|
* @link http://docs.guzzlephp.org/clients.html#request-options
|
||||||
|
*/
|
||||||
|
public function createRequest($method, $url, array $options = []);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request and response message interface
|
||||||
|
*/
|
||||||
|
interface MessageInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get a string representation of the message
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HTTP protocol version of the message
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getProtocolVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the body of the message.
|
||||||
|
*
|
||||||
|
* The body MUST be a StreamInterface object. Setting the body to null MUST
|
||||||
|
* remove the existing body.
|
||||||
|
*
|
||||||
|
* @param StreamInterface|null $body Body.
|
||||||
|
*
|
||||||
|
* @return self Returns the message.
|
||||||
|
*/
|
||||||
|
public function setBody(StreamInterface $body = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the body of the message
|
||||||
|
*
|
||||||
|
* @return StreamInterface|null
|
||||||
|
*/
|
||||||
|
public function getBody();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all message headers.
|
||||||
|
*
|
||||||
|
* The keys represent the header name as it will be sent over the wire, and
|
||||||
|
* each value is an array of strings associated with the header.
|
||||||
|
*
|
||||||
|
* // Represent the headers as a string
|
||||||
|
* foreach ($message->getHeaders() as $name => $values) {
|
||||||
|
* echo $name . ": " . implode(", ", $values);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @return array Returns an associative array of the message's headers.
|
||||||
|
*/
|
||||||
|
public function getHeaders();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a header by the given case-insensitive name.
|
||||||
|
*
|
||||||
|
* By default, this method returns all of the header values of the given
|
||||||
|
* case-insensitive header name as a string concatenated together using
|
||||||
|
* a comma. Because some header should not be concatenated together using a
|
||||||
|
* comma, this method provides a Boolean argument that can be used to
|
||||||
|
* retrieve the associated header values as an array of strings.
|
||||||
|
*
|
||||||
|
* @param string $header Case-insensitive header name.
|
||||||
|
* @param bool $asArray Set to true to retrieve the header value as an
|
||||||
|
* array of strings.
|
||||||
|
*
|
||||||
|
* @return array|string
|
||||||
|
*/
|
||||||
|
public function getHeader($header, $asArray = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a header exists by the given case-insensitive name.
|
||||||
|
*
|
||||||
|
* @param string $header Case-insensitive header name.
|
||||||
|
*
|
||||||
|
* @return bool Returns true if any header names match the given header
|
||||||
|
* name using a case-insensitive string comparison. Returns false if
|
||||||
|
* no matching header name is found in the message.
|
||||||
|
*/
|
||||||
|
public function hasHeader($header);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific header by case-insensitive name.
|
||||||
|
*
|
||||||
|
* @param string $header Case-insensitive header name.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function removeHeader($header);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a header value to any existing values associated with the
|
||||||
|
* given header name.
|
||||||
|
*
|
||||||
|
* @param string $header Header name to add
|
||||||
|
* @param string $value Value of the header
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function addHeader($header, $value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges in an associative array of headers.
|
||||||
|
*
|
||||||
|
* Each array key MUST be a string representing the case-insensitive name
|
||||||
|
* of a header. Each value MUST be either a string or an array of strings.
|
||||||
|
* For each value, the value is appended to any existing header of the same
|
||||||
|
* name, or, if a header does not already exist by the given name, then the
|
||||||
|
* header is added.
|
||||||
|
*
|
||||||
|
* @param array $headers Associative array of headers to add to the message
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function addHeaders(array $headers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a header, replacing any existing values of any headers with the
|
||||||
|
* same case-insensitive name.
|
||||||
|
*
|
||||||
|
* The header values MUST be a string or an array of strings.
|
||||||
|
*
|
||||||
|
* @param string $header Header name
|
||||||
|
* @param string|array $value Header value(s)
|
||||||
|
*
|
||||||
|
* @return self Returns the message.
|
||||||
|
*/
|
||||||
|
public function setHeader($header, $value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets headers, replacing any headers that have already been set on the
|
||||||
|
* message.
|
||||||
|
*
|
||||||
|
* The array keys MUST be a string. The array values must be either a
|
||||||
|
* string or an array of strings.
|
||||||
|
*
|
||||||
|
* @param array $headers Headers to set.
|
||||||
|
*
|
||||||
|
* @return self Returns the message.
|
||||||
|
*/
|
||||||
|
public function setHeaders(array $headers);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request and response parser used by Guzzle
|
||||||
|
*/
|
||||||
|
class MessageParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parse an HTTP request message into an associative array of parts.
|
||||||
|
*
|
||||||
|
* @param string $message HTTP request to parse
|
||||||
|
*
|
||||||
|
* @return array|bool Returns false if the message is invalid
|
||||||
|
*/
|
||||||
|
public function parseRequest($message)
|
||||||
|
{
|
||||||
|
if (!($parts = $this->parseMessage($message))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the protocol and protocol version
|
||||||
|
if (isset($parts['start_line'][2])) {
|
||||||
|
$startParts = explode('/', $parts['start_line'][2]);
|
||||||
|
$protocol = strtoupper($startParts[0]);
|
||||||
|
$version = isset($startParts[1]) ? $startParts[1] : '1.1';
|
||||||
|
} else {
|
||||||
|
$protocol = 'HTTP';
|
||||||
|
$version = '1.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsed = [
|
||||||
|
'method' => strtoupper($parts['start_line'][0]),
|
||||||
|
'protocol' => $protocol,
|
||||||
|
'protocol_version' => $version,
|
||||||
|
'headers' => $parts['headers'],
|
||||||
|
'body' => $parts['body']
|
||||||
|
];
|
||||||
|
|
||||||
|
$parsed['request_url'] = $this->getUrlPartsFromMessage(
|
||||||
|
(isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);
|
||||||
|
|
||||||
|
return $parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an HTTP response message into an associative array of parts.
|
||||||
|
*
|
||||||
|
* @param string $message HTTP response to parse
|
||||||
|
*
|
||||||
|
* @return array|bool Returns false if the message is invalid
|
||||||
|
*/
|
||||||
|
public function parseResponse($message)
|
||||||
|
{
|
||||||
|
if (!($parts = $this->parseMessage($message))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($protocol, $version) = explode('/', trim($parts['start_line'][0]));
|
||||||
|
|
||||||
|
return [
|
||||||
|
'protocol' => $protocol,
|
||||||
|
'protocol_version' => $version,
|
||||||
|
'code' => $parts['start_line'][1],
|
||||||
|
'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
|
||||||
|
'headers' => $parts['headers'],
|
||||||
|
'body' => $parts['body']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a message into parts
|
||||||
|
*
|
||||||
|
* @param string $message Message to parse
|
||||||
|
*
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
private function parseMessage($message)
|
||||||
|
{
|
||||||
|
if (!$message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$startLine = null;
|
||||||
|
$headers = [];
|
||||||
|
$body = '';
|
||||||
|
|
||||||
|
// Iterate over each line in the message, accounting for line endings
|
||||||
|
$lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
|
||||||
|
|
||||||
|
$line = $lines[$i];
|
||||||
|
|
||||||
|
// If two line breaks were encountered, then this is the end of body
|
||||||
|
if (empty($line)) {
|
||||||
|
if ($i < $totalLines - 1) {
|
||||||
|
$body = implode('', array_slice($lines, $i + 2));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse message headers
|
||||||
|
if (!$startLine) {
|
||||||
|
$startLine = explode(' ', $line, 3);
|
||||||
|
} elseif (strpos($line, ':')) {
|
||||||
|
$parts = explode(':', $line, 2);
|
||||||
|
$key = trim($parts[0]);
|
||||||
|
$value = isset($parts[1]) ? trim($parts[1]) : '';
|
||||||
|
if (!isset($headers[$key])) {
|
||||||
|
$headers[$key] = $value;
|
||||||
|
} elseif (!is_array($headers[$key])) {
|
||||||
|
$headers[$key] = [$headers[$key], $value];
|
||||||
|
} else {
|
||||||
|
$headers[$key][] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'start_line' => $startLine,
|
||||||
|
'headers' => $headers,
|
||||||
|
'body' => $body
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create URL parts from HTTP message parts
|
||||||
|
*
|
||||||
|
* @param string $requestUrl Associated URL
|
||||||
|
* @param array $parts HTTP message parts
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getUrlPartsFromMessage($requestUrl, array $parts)
|
||||||
|
{
|
||||||
|
// Parse the URL information from the message
|
||||||
|
$urlParts = ['path' => $requestUrl, 'scheme' => 'http'];
|
||||||
|
|
||||||
|
// Check for the Host header
|
||||||
|
if (isset($parts['headers']['Host'])) {
|
||||||
|
$urlParts['host'] = $parts['headers']['Host'];
|
||||||
|
} elseif (isset($parts['headers']['host'])) {
|
||||||
|
$urlParts['host'] = $parts['headers']['host'];
|
||||||
|
} else {
|
||||||
|
$urlParts['host'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === strpos($urlParts['host'], ':')) {
|
||||||
|
$urlParts['port'] = '';
|
||||||
|
} else {
|
||||||
|
$hostParts = explode(':', $urlParts['host']);
|
||||||
|
$urlParts['host'] = trim($hostParts[0]);
|
||||||
|
$urlParts['port'] = (int) trim($hostParts[1]);
|
||||||
|
if ($urlParts['port'] == 443) {
|
||||||
|
$urlParts['scheme'] = 'https';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a query is present
|
||||||
|
$path = $urlParts['path'];
|
||||||
|
$qpos = strpos($path, '?');
|
||||||
|
if ($qpos) {
|
||||||
|
$urlParts['query'] = substr($path, $qpos + 1);
|
||||||
|
$urlParts['path'] = substr($path, 0, $qpos);
|
||||||
|
} else {
|
||||||
|
$urlParts['query'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $urlParts;
|
||||||
|
}
|
||||||
|
}
|
||||||
216
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Message/Request.php
Normal file
216
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Message/Request.php
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\HasEmitterTrait;
|
||||||
|
use GuzzleHttp\Collection;
|
||||||
|
use GuzzleHttp\Subscriber\Prepare;
|
||||||
|
use GuzzleHttp\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP request class to send requests
|
||||||
|
*/
|
||||||
|
class Request extends AbstractMessage implements RequestInterface
|
||||||
|
{
|
||||||
|
use HasEmitterTrait;
|
||||||
|
|
||||||
|
/** @var Url HTTP Url */
|
||||||
|
private $url;
|
||||||
|
|
||||||
|
/** @var string HTTP method */
|
||||||
|
private $method;
|
||||||
|
|
||||||
|
/** @var Collection Transfer options */
|
||||||
|
private $transferOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method HTTP method
|
||||||
|
* @param string|Url $url HTTP URL to connect to. The URI scheme,
|
||||||
|
* host header, and URI are parsed from the full URL. If query string
|
||||||
|
* parameters are present they will be parsed as well.
|
||||||
|
* @param array|Collection $headers HTTP headers
|
||||||
|
* @param mixed $body Body to send with the request
|
||||||
|
* @param array $options Array of options to use with the request
|
||||||
|
* - emitter: Event emitter to use with the request
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$method,
|
||||||
|
$url,
|
||||||
|
$headers = [],
|
||||||
|
$body = null,
|
||||||
|
array $options = []
|
||||||
|
) {
|
||||||
|
$this->setUrl($url);
|
||||||
|
$this->method = strtoupper($method);
|
||||||
|
$this->handleOptions($options);
|
||||||
|
$this->transferOptions = new Collection($options);
|
||||||
|
$this->addPrepareEvent();
|
||||||
|
|
||||||
|
if ($body !== null) {
|
||||||
|
$this->setBody($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($headers) {
|
||||||
|
foreach ($headers as $key => $value) {
|
||||||
|
$this->setHeader($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
if ($this->emitter) {
|
||||||
|
$this->emitter = clone $this->emitter;
|
||||||
|
}
|
||||||
|
$this->transferOptions = clone $this->transferOptions;
|
||||||
|
$this->url = clone $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUrl($url)
|
||||||
|
{
|
||||||
|
$this->url = $url instanceof Url ? $url : Url::fromString($url);
|
||||||
|
$this->updateHostHeaderFromUrl();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrl()
|
||||||
|
{
|
||||||
|
return (string) $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setQuery($query)
|
||||||
|
{
|
||||||
|
$this->url->setQuery($query);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuery()
|
||||||
|
{
|
||||||
|
return $this->url->getQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMethod($method)
|
||||||
|
{
|
||||||
|
$this->method = strtoupper($method);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethod()
|
||||||
|
{
|
||||||
|
return $this->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScheme()
|
||||||
|
{
|
||||||
|
return $this->url->getScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setScheme($scheme)
|
||||||
|
{
|
||||||
|
$this->url->setScheme($scheme);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPort()
|
||||||
|
{
|
||||||
|
return $this->url->getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPort($port)
|
||||||
|
{
|
||||||
|
$this->url->setPort($port);
|
||||||
|
$this->updateHostHeaderFromUrl();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHost()
|
||||||
|
{
|
||||||
|
return $this->url->getHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHost($host)
|
||||||
|
{
|
||||||
|
$this->url->setHost($host);
|
||||||
|
$this->updateHostHeaderFromUrl();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPath()
|
||||||
|
{
|
||||||
|
return '/' . ltrim($this->url->getPath(), '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPath($path)
|
||||||
|
{
|
||||||
|
$this->url->setPath($path);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResource()
|
||||||
|
{
|
||||||
|
$resource = $this->getPath();
|
||||||
|
if ($query = (string) $this->url->getQuery()) {
|
||||||
|
$resource .= '?' . $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return $this->transferOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleOptions(array &$options)
|
||||||
|
{
|
||||||
|
parent::handleOptions($options);
|
||||||
|
// Use a custom emitter if one is specified, and remove it from
|
||||||
|
// options that are exposed through getConfig()
|
||||||
|
if (isset($options['emitter'])) {
|
||||||
|
$this->emitter = $options['emitter'];
|
||||||
|
unset($options['emitter']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getStartLine()
|
||||||
|
{
|
||||||
|
return trim($this->method . ' ' . $this->getResource())
|
||||||
|
. ' HTTP/' . $this->getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a subscriber that ensures a request's body is prepared before
|
||||||
|
* sending.
|
||||||
|
*/
|
||||||
|
private function addPrepareEvent()
|
||||||
|
{
|
||||||
|
static $subscriber;
|
||||||
|
if (!$subscriber) {
|
||||||
|
$subscriber = new Prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getEmitter()->attach($subscriber);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateHostHeaderFromUrl()
|
||||||
|
{
|
||||||
|
$port = $this->url->getPort();
|
||||||
|
$scheme = $this->url->getScheme();
|
||||||
|
if ($host = $this->url->getHost()) {
|
||||||
|
if (($port == 80 && $scheme == 'http') ||
|
||||||
|
($port == 443 && $scheme == 'https')
|
||||||
|
) {
|
||||||
|
$this->setHeader('Host', $host);
|
||||||
|
} else {
|
||||||
|
$this->setHeader('Host', "{$host}:{$port}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\HasEmitterInterface;
|
||||||
|
use GuzzleHttp\Query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic HTTP request interface
|
||||||
|
*/
|
||||||
|
interface RequestInterface extends MessageInterface, HasEmitterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sets the request URL.
|
||||||
|
*
|
||||||
|
* The URL MUST be a string, or an object that implements the
|
||||||
|
* `__toString()` method.
|
||||||
|
*
|
||||||
|
* @param string $url Request URL.
|
||||||
|
*
|
||||||
|
* @return self Reference to the request.
|
||||||
|
* @throws \InvalidArgumentException If the URL is invalid.
|
||||||
|
*/
|
||||||
|
public function setUrl($url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the request URL as a string.
|
||||||
|
*
|
||||||
|
* @return string Returns the URL as a string.
|
||||||
|
*/
|
||||||
|
public function getUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the resource part of the the request, including the path, query
|
||||||
|
* string, and fragment.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getResource();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the collection of key value pairs that will be used as the query
|
||||||
|
* string in the request.
|
||||||
|
*
|
||||||
|
* @return Query
|
||||||
|
*/
|
||||||
|
public function getQuery();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the query string used by the request
|
||||||
|
*
|
||||||
|
* @param array|Query $query Query to set
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setQuery($query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HTTP method of the request.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMethod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the HTTP method of the request.
|
||||||
|
*
|
||||||
|
* @param string $method HTTP method
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setMethod($method);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URI scheme of the request (http, https, etc.).
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getScheme();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the URI scheme of the request (http, https, etc.).
|
||||||
|
*
|
||||||
|
* @param string $scheme Scheme to set
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setScheme($scheme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the port scheme of the request (e.g., 80, 443, etc.).
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getPort();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the port of the request.
|
||||||
|
*
|
||||||
|
* Setting a port modifies the Host header of a request as necessary.
|
||||||
|
*
|
||||||
|
* @param int $port Port to set
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setPort($port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the host of the request.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getHost();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the host of the request including an optional port.
|
||||||
|
*
|
||||||
|
* Including a port in the host argument will explicitly change the port of
|
||||||
|
* the request. If no port is found, the default port of the current
|
||||||
|
* request scheme will be utilized.
|
||||||
|
*
|
||||||
|
* @param string $host Host to set (e.g. www.yahoo.com, www.yahoo.com:80)
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setHost($host);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path of the request (e.g. '/', '/index.html').
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path of the request (e.g. '/', '/index.html').
|
||||||
|
*
|
||||||
|
* @param string|array $path Path to set or array of segments to implode
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setPath($path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request's configuration options.
|
||||||
|
*
|
||||||
|
* @return \GuzzleHttp\Collection
|
||||||
|
*/
|
||||||
|
public function getConfig();
|
||||||
|
}
|
||||||
202
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Message/Response.php
Normal file
202
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Message/Response.php
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
use GuzzleHttp\Exception\ParseException;
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guzzle HTTP response object
|
||||||
|
*/
|
||||||
|
class Response extends AbstractMessage implements ResponseInterface
|
||||||
|
{
|
||||||
|
/** @var array Mapping of status codes to reason phrases */
|
||||||
|
private static $statusTexts = array(
|
||||||
|
100 => 'Continue',
|
||||||
|
101 => 'Switching Protocols',
|
||||||
|
102 => 'Processing',
|
||||||
|
200 => 'OK',
|
||||||
|
201 => 'Created',
|
||||||
|
202 => 'Accepted',
|
||||||
|
203 => 'Non-Authoritative Information',
|
||||||
|
204 => 'No Content',
|
||||||
|
205 => 'Reset Content',
|
||||||
|
206 => 'Partial Content',
|
||||||
|
207 => 'Multi-Status',
|
||||||
|
208 => 'Already Reported',
|
||||||
|
226 => 'IM Used',
|
||||||
|
300 => 'Multiple Choices',
|
||||||
|
301 => 'Moved Permanently',
|
||||||
|
302 => 'Found',
|
||||||
|
303 => 'See Other',
|
||||||
|
304 => 'Not Modified',
|
||||||
|
305 => 'Use Proxy',
|
||||||
|
307 => 'Temporary Redirect',
|
||||||
|
308 => 'Permanent Redirect',
|
||||||
|
400 => 'Bad Request',
|
||||||
|
401 => 'Unauthorized',
|
||||||
|
402 => 'Payment Required',
|
||||||
|
403 => 'Forbidden',
|
||||||
|
404 => 'Not Found',
|
||||||
|
405 => 'Method Not Allowed',
|
||||||
|
406 => 'Not Acceptable',
|
||||||
|
407 => 'Proxy Authentication Required',
|
||||||
|
408 => 'Request Timeout',
|
||||||
|
409 => 'Conflict',
|
||||||
|
410 => 'Gone',
|
||||||
|
411 => 'Length Required',
|
||||||
|
412 => 'Precondition Failed',
|
||||||
|
413 => 'Request Entity Too Large',
|
||||||
|
414 => 'Request-URI Too Long',
|
||||||
|
415 => 'Unsupported Media Type',
|
||||||
|
416 => 'Requested Range Not Satisfiable',
|
||||||
|
417 => 'Expectation Failed',
|
||||||
|
422 => 'Unprocessable Entity',
|
||||||
|
423 => 'Locked',
|
||||||
|
424 => 'Failed Dependency',
|
||||||
|
425 => 'Reserved for WebDAV advanced collections expired proposal',
|
||||||
|
426 => 'Upgrade required',
|
||||||
|
428 => 'Precondition Required',
|
||||||
|
429 => 'Too Many Requests',
|
||||||
|
431 => 'Request Header Fields Too Large',
|
||||||
|
500 => 'Internal Server Error',
|
||||||
|
501 => 'Not Implemented',
|
||||||
|
502 => 'Bad Gateway',
|
||||||
|
503 => 'Service Unavailable',
|
||||||
|
504 => 'Gateway Timeout',
|
||||||
|
505 => 'HTTP Version Not Supported',
|
||||||
|
506 => 'Variant Also Negotiates (Experimental)',
|
||||||
|
507 => 'Insufficient Storage',
|
||||||
|
508 => 'Loop Detected',
|
||||||
|
510 => 'Not Extended',
|
||||||
|
511 => 'Network Authentication Required',
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var string The reason phrase of the response (human readable code) */
|
||||||
|
private $reasonPhrase;
|
||||||
|
|
||||||
|
/** @var string The status code of the response */
|
||||||
|
private $statusCode;
|
||||||
|
|
||||||
|
/** @var string The effective URL that returned this response */
|
||||||
|
private $effectiveUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $statusCode The response status code (e.g. 200)
|
||||||
|
* @param array $headers The response headers
|
||||||
|
* @param StreamInterface $body The body of the response
|
||||||
|
* @param array $options Response message options
|
||||||
|
* - reason_phrase: Set a custom reason phrase
|
||||||
|
* - protocol_version: Set a custom protocol version
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$statusCode,
|
||||||
|
array $headers = [],
|
||||||
|
StreamInterface $body = null,
|
||||||
|
array $options = []
|
||||||
|
) {
|
||||||
|
$this->statusCode = (string) $statusCode;
|
||||||
|
$this->handleOptions($options);
|
||||||
|
|
||||||
|
// Assume a reason phrase if one was not applied as an option
|
||||||
|
if (!$this->reasonPhrase &&
|
||||||
|
isset(self::$statusTexts[$this->statusCode])
|
||||||
|
) {
|
||||||
|
$this->reasonPhrase = self::$statusTexts[$this->statusCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($headers) {
|
||||||
|
$this->setHeaders($headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($body) {
|
||||||
|
$this->setBody($body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusCode()
|
||||||
|
{
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getReasonPhrase()
|
||||||
|
{
|
||||||
|
return $this->reasonPhrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function json(array $config = [])
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return \GuzzleHttp\json_decode(
|
||||||
|
(string) $this->getBody(),
|
||||||
|
isset($config['object']) ? !$config['object'] : true,
|
||||||
|
512,
|
||||||
|
isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0
|
||||||
|
);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
throw new ParseException(
|
||||||
|
$e->getMessage(),
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function xml(array $config = [])
|
||||||
|
{
|
||||||
|
$disableEntities = libxml_disable_entity_loader(true);
|
||||||
|
$internalErrors = libxml_use_internal_errors(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Allow XML to be retrieved even if there is no response body
|
||||||
|
$xml = new \SimpleXMLElement(
|
||||||
|
(string) $this->getBody() ?: '<root />',
|
||||||
|
LIBXML_NONET,
|
||||||
|
isset($config['ns']) ? $config['ns'] : '',
|
||||||
|
isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false
|
||||||
|
);
|
||||||
|
libxml_disable_entity_loader($disableEntities);
|
||||||
|
libxml_use_internal_errors($internalErrors);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
libxml_disable_entity_loader($disableEntities);
|
||||||
|
libxml_use_internal_errors($internalErrors);
|
||||||
|
throw new ParseException(
|
||||||
|
'Unable to parse response body into XML: ' . $e->getMessage(),
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEffectiveUrl()
|
||||||
|
{
|
||||||
|
return $this->effectiveUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEffectiveUrl($url)
|
||||||
|
{
|
||||||
|
$this->effectiveUrl = $url;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts and modifies the options provided to the response in the
|
||||||
|
* constructor.
|
||||||
|
*
|
||||||
|
* @param array $options Options array passed by reference.
|
||||||
|
*/
|
||||||
|
protected function handleOptions(array &$options = [])
|
||||||
|
{
|
||||||
|
parent::handleOptions($options);
|
||||||
|
if (isset($options['reason_phrase'])) {
|
||||||
|
$this->reasonPhrase = $options['reason_phrase'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getStartLine()
|
||||||
|
{
|
||||||
|
return 'HTTP/' . $this->getProtocolVersion()
|
||||||
|
. " {$this->statusCode} {$this->reasonPhrase}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an HTTP response message.
|
||||||
|
*/
|
||||||
|
interface ResponseInterface extends MessageInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the response status code (e.g. "200", "404", etc.)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getStatusCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response reason phrase- a human readable version of the numeric
|
||||||
|
* status code
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getReasonPhrase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the effective URL that resulted in this response (e.g. the last
|
||||||
|
* redirect URL).
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEffectiveUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the effective URL that resulted in this response (e.g. the last
|
||||||
|
* redirect URL).
|
||||||
|
*
|
||||||
|
* @param string $url Effective URL
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setEffectiveUrl($url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the JSON response body and return the JSON decoded data.
|
||||||
|
*
|
||||||
|
* @param array $config Associative array of configuration settings used
|
||||||
|
* to control how the JSON data is parsed. Concrete implementations MAY
|
||||||
|
* add further configuration settings as needed, but they MUST implement
|
||||||
|
* functionality for the following options:
|
||||||
|
*
|
||||||
|
* - object: Set to true to parse JSON objects as PHP objects rather
|
||||||
|
* than associative arrays. Defaults to false.
|
||||||
|
* - big_int_strings: When set to true, large integers are converted to
|
||||||
|
* strings rather than floats. Defaults to false.
|
||||||
|
*
|
||||||
|
* Implementations are free to add further configuration settings as
|
||||||
|
* needed.
|
||||||
|
*
|
||||||
|
* @return mixed Returns the JSON decoded data based on the provided
|
||||||
|
* parse settings.
|
||||||
|
* @throws \RuntimeException if the response body is not in JSON format
|
||||||
|
*/
|
||||||
|
public function json(array $config = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the XML response body and return a \SimpleXMLElement.
|
||||||
|
*
|
||||||
|
* In order to prevent XXE attacks, this method disables loading external
|
||||||
|
* entities. If you rely on external entities, then you must parse the
|
||||||
|
* XML response manually by accessing the response body directly.
|
||||||
|
*
|
||||||
|
* @param array $config Associative array of configuration settings used
|
||||||
|
* to control how the XML is parsed. Concrete implementations MAY add
|
||||||
|
* further configuration settings as needed, but they MUST implement
|
||||||
|
* functionality for the following options:
|
||||||
|
*
|
||||||
|
* - ns: Set to a string to represent the namespace prefix or URI
|
||||||
|
* - ns_is_prefix: Set to true to specify that the NS is a prefix rather
|
||||||
|
* than a URI (defaults to false).
|
||||||
|
*
|
||||||
|
* @return \SimpleXMLElement
|
||||||
|
* @throws \RuntimeException if the response body is not in XML format
|
||||||
|
* @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html
|
||||||
|
*/
|
||||||
|
public function xml(array $config = []);
|
||||||
|
}
|
||||||
964
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Mimetypes.php
Normal file
964
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Mimetypes.php
Normal file
|
|
@ -0,0 +1,964 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides mappings of file extensions to mimetypes
|
||||||
|
* @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
|
||||||
|
*/
|
||||||
|
class Mimetypes
|
||||||
|
{
|
||||||
|
/** @var self */
|
||||||
|
protected static $instance;
|
||||||
|
|
||||||
|
/** @var array Mapping of extension to mimetype */
|
||||||
|
protected $mimetypes = array(
|
||||||
|
'3dml' => 'text/vnd.in3d.3dml',
|
||||||
|
'3g2' => 'video/3gpp2',
|
||||||
|
'3gp' => 'video/3gpp',
|
||||||
|
'7z' => 'application/x-7z-compressed',
|
||||||
|
'aab' => 'application/x-authorware-bin',
|
||||||
|
'aac' => 'audio/x-aac',
|
||||||
|
'aam' => 'application/x-authorware-map',
|
||||||
|
'aas' => 'application/x-authorware-seg',
|
||||||
|
'abw' => 'application/x-abiword',
|
||||||
|
'ac' => 'application/pkix-attr-cert',
|
||||||
|
'acc' => 'application/vnd.americandynamics.acc',
|
||||||
|
'ace' => 'application/x-ace-compressed',
|
||||||
|
'acu' => 'application/vnd.acucobol',
|
||||||
|
'acutc' => 'application/vnd.acucorp',
|
||||||
|
'adp' => 'audio/adpcm',
|
||||||
|
'aep' => 'application/vnd.audiograph',
|
||||||
|
'afm' => 'application/x-font-type1',
|
||||||
|
'afp' => 'application/vnd.ibm.modcap',
|
||||||
|
'ahead' => 'application/vnd.ahead.space',
|
||||||
|
'ai' => 'application/postscript',
|
||||||
|
'aif' => 'audio/x-aiff',
|
||||||
|
'aifc' => 'audio/x-aiff',
|
||||||
|
'aiff' => 'audio/x-aiff',
|
||||||
|
'air' => 'application/vnd.adobe.air-application-installer-package+zip',
|
||||||
|
'ait' => 'application/vnd.dvb.ait',
|
||||||
|
'ami' => 'application/vnd.amiga.ami',
|
||||||
|
'apk' => 'application/vnd.android.package-archive',
|
||||||
|
'application' => 'application/x-ms-application',
|
||||||
|
'apr' => 'application/vnd.lotus-approach',
|
||||||
|
'asa' => 'text/plain',
|
||||||
|
'asax' => 'application/octet-stream',
|
||||||
|
'asc' => 'application/pgp-signature',
|
||||||
|
'ascx' => 'text/plain',
|
||||||
|
'asf' => 'video/x-ms-asf',
|
||||||
|
'ashx' => 'text/plain',
|
||||||
|
'asm' => 'text/x-asm',
|
||||||
|
'asmx' => 'text/plain',
|
||||||
|
'aso' => 'application/vnd.accpac.simply.aso',
|
||||||
|
'asp' => 'text/plain',
|
||||||
|
'aspx' => 'text/plain',
|
||||||
|
'asx' => 'video/x-ms-asf',
|
||||||
|
'atc' => 'application/vnd.acucorp',
|
||||||
|
'atom' => 'application/atom+xml',
|
||||||
|
'atomcat' => 'application/atomcat+xml',
|
||||||
|
'atomsvc' => 'application/atomsvc+xml',
|
||||||
|
'atx' => 'application/vnd.antix.game-component',
|
||||||
|
'au' => 'audio/basic',
|
||||||
|
'avi' => 'video/x-msvideo',
|
||||||
|
'aw' => 'application/applixware',
|
||||||
|
'axd' => 'text/plain',
|
||||||
|
'azf' => 'application/vnd.airzip.filesecure.azf',
|
||||||
|
'azs' => 'application/vnd.airzip.filesecure.azs',
|
||||||
|
'azw' => 'application/vnd.amazon.ebook',
|
||||||
|
'bat' => 'application/x-msdownload',
|
||||||
|
'bcpio' => 'application/x-bcpio',
|
||||||
|
'bdf' => 'application/x-font-bdf',
|
||||||
|
'bdm' => 'application/vnd.syncml.dm+wbxml',
|
||||||
|
'bed' => 'application/vnd.realvnc.bed',
|
||||||
|
'bh2' => 'application/vnd.fujitsu.oasysprs',
|
||||||
|
'bin' => 'application/octet-stream',
|
||||||
|
'bmi' => 'application/vnd.bmi',
|
||||||
|
'bmp' => 'image/bmp',
|
||||||
|
'book' => 'application/vnd.framemaker',
|
||||||
|
'box' => 'application/vnd.previewsystems.box',
|
||||||
|
'boz' => 'application/x-bzip2',
|
||||||
|
'bpk' => 'application/octet-stream',
|
||||||
|
'btif' => 'image/prs.btif',
|
||||||
|
'bz' => 'application/x-bzip',
|
||||||
|
'bz2' => 'application/x-bzip2',
|
||||||
|
'c' => 'text/x-c',
|
||||||
|
'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
|
||||||
|
'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
|
||||||
|
'c4d' => 'application/vnd.clonk.c4group',
|
||||||
|
'c4f' => 'application/vnd.clonk.c4group',
|
||||||
|
'c4g' => 'application/vnd.clonk.c4group',
|
||||||
|
'c4p' => 'application/vnd.clonk.c4group',
|
||||||
|
'c4u' => 'application/vnd.clonk.c4group',
|
||||||
|
'cab' => 'application/vnd.ms-cab-compressed',
|
||||||
|
'car' => 'application/vnd.curl.car',
|
||||||
|
'cat' => 'application/vnd.ms-pki.seccat',
|
||||||
|
'cc' => 'text/x-c',
|
||||||
|
'cct' => 'application/x-director',
|
||||||
|
'ccxml' => 'application/ccxml+xml',
|
||||||
|
'cdbcmsg' => 'application/vnd.contact.cmsg',
|
||||||
|
'cdf' => 'application/x-netcdf',
|
||||||
|
'cdkey' => 'application/vnd.mediastation.cdkey',
|
||||||
|
'cdmia' => 'application/cdmi-capability',
|
||||||
|
'cdmic' => 'application/cdmi-container',
|
||||||
|
'cdmid' => 'application/cdmi-domain',
|
||||||
|
'cdmio' => 'application/cdmi-object',
|
||||||
|
'cdmiq' => 'application/cdmi-queue',
|
||||||
|
'cdx' => 'chemical/x-cdx',
|
||||||
|
'cdxml' => 'application/vnd.chemdraw+xml',
|
||||||
|
'cdy' => 'application/vnd.cinderella',
|
||||||
|
'cer' => 'application/pkix-cert',
|
||||||
|
'cfc' => 'application/x-coldfusion',
|
||||||
|
'cfm' => 'application/x-coldfusion',
|
||||||
|
'cgm' => 'image/cgm',
|
||||||
|
'chat' => 'application/x-chat',
|
||||||
|
'chm' => 'application/vnd.ms-htmlhelp',
|
||||||
|
'chrt' => 'application/vnd.kde.kchart',
|
||||||
|
'cif' => 'chemical/x-cif',
|
||||||
|
'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
|
||||||
|
'cil' => 'application/vnd.ms-artgalry',
|
||||||
|
'cla' => 'application/vnd.claymore',
|
||||||
|
'class' => 'application/java-vm',
|
||||||
|
'clkk' => 'application/vnd.crick.clicker.keyboard',
|
||||||
|
'clkp' => 'application/vnd.crick.clicker.palette',
|
||||||
|
'clkt' => 'application/vnd.crick.clicker.template',
|
||||||
|
'clkw' => 'application/vnd.crick.clicker.wordbank',
|
||||||
|
'clkx' => 'application/vnd.crick.clicker',
|
||||||
|
'clp' => 'application/x-msclip',
|
||||||
|
'cmc' => 'application/vnd.cosmocaller',
|
||||||
|
'cmdf' => 'chemical/x-cmdf',
|
||||||
|
'cml' => 'chemical/x-cml',
|
||||||
|
'cmp' => 'application/vnd.yellowriver-custom-menu',
|
||||||
|
'cmx' => 'image/x-cmx',
|
||||||
|
'cod' => 'application/vnd.rim.cod',
|
||||||
|
'com' => 'application/x-msdownload',
|
||||||
|
'conf' => 'text/plain',
|
||||||
|
'cpio' => 'application/x-cpio',
|
||||||
|
'cpp' => 'text/x-c',
|
||||||
|
'cpt' => 'application/mac-compactpro',
|
||||||
|
'crd' => 'application/x-mscardfile',
|
||||||
|
'crl' => 'application/pkix-crl',
|
||||||
|
'crt' => 'application/x-x509-ca-cert',
|
||||||
|
'cryptonote' => 'application/vnd.rig.cryptonote',
|
||||||
|
'cs' => 'text/plain',
|
||||||
|
'csh' => 'application/x-csh',
|
||||||
|
'csml' => 'chemical/x-csml',
|
||||||
|
'csp' => 'application/vnd.commonspace',
|
||||||
|
'css' => 'text/css',
|
||||||
|
'cst' => 'application/x-director',
|
||||||
|
'csv' => 'text/csv',
|
||||||
|
'cu' => 'application/cu-seeme',
|
||||||
|
'curl' => 'text/vnd.curl',
|
||||||
|
'cww' => 'application/prs.cww',
|
||||||
|
'cxt' => 'application/x-director',
|
||||||
|
'cxx' => 'text/x-c',
|
||||||
|
'dae' => 'model/vnd.collada+xml',
|
||||||
|
'daf' => 'application/vnd.mobius.daf',
|
||||||
|
'dataless' => 'application/vnd.fdsn.seed',
|
||||||
|
'davmount' => 'application/davmount+xml',
|
||||||
|
'dcr' => 'application/x-director',
|
||||||
|
'dcurl' => 'text/vnd.curl.dcurl',
|
||||||
|
'dd2' => 'application/vnd.oma.dd2+xml',
|
||||||
|
'ddd' => 'application/vnd.fujixerox.ddd',
|
||||||
|
'deb' => 'application/x-debian-package',
|
||||||
|
'def' => 'text/plain',
|
||||||
|
'deploy' => 'application/octet-stream',
|
||||||
|
'der' => 'application/x-x509-ca-cert',
|
||||||
|
'dfac' => 'application/vnd.dreamfactory',
|
||||||
|
'dic' => 'text/x-c',
|
||||||
|
'dir' => 'application/x-director',
|
||||||
|
'dis' => 'application/vnd.mobius.dis',
|
||||||
|
'dist' => 'application/octet-stream',
|
||||||
|
'distz' => 'application/octet-stream',
|
||||||
|
'djv' => 'image/vnd.djvu',
|
||||||
|
'djvu' => 'image/vnd.djvu',
|
||||||
|
'dll' => 'application/x-msdownload',
|
||||||
|
'dmg' => 'application/octet-stream',
|
||||||
|
'dms' => 'application/octet-stream',
|
||||||
|
'dna' => 'application/vnd.dna',
|
||||||
|
'doc' => 'application/msword',
|
||||||
|
'docm' => 'application/vnd.ms-word.document.macroenabled.12',
|
||||||
|
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'dot' => 'application/msword',
|
||||||
|
'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
|
||||||
|
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||||
|
'dp' => 'application/vnd.osgi.dp',
|
||||||
|
'dpg' => 'application/vnd.dpgraph',
|
||||||
|
'dra' => 'audio/vnd.dra',
|
||||||
|
'dsc' => 'text/prs.lines.tag',
|
||||||
|
'dssc' => 'application/dssc+der',
|
||||||
|
'dtb' => 'application/x-dtbook+xml',
|
||||||
|
'dtd' => 'application/xml-dtd',
|
||||||
|
'dts' => 'audio/vnd.dts',
|
||||||
|
'dtshd' => 'audio/vnd.dts.hd',
|
||||||
|
'dump' => 'application/octet-stream',
|
||||||
|
'dvi' => 'application/x-dvi',
|
||||||
|
'dwf' => 'model/vnd.dwf',
|
||||||
|
'dwg' => 'image/vnd.dwg',
|
||||||
|
'dxf' => 'image/vnd.dxf',
|
||||||
|
'dxp' => 'application/vnd.spotfire.dxp',
|
||||||
|
'dxr' => 'application/x-director',
|
||||||
|
'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
|
||||||
|
'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
|
||||||
|
'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
|
||||||
|
'ecma' => 'application/ecmascript',
|
||||||
|
'edm' => 'application/vnd.novadigm.edm',
|
||||||
|
'edx' => 'application/vnd.novadigm.edx',
|
||||||
|
'efif' => 'application/vnd.picsel',
|
||||||
|
'ei6' => 'application/vnd.pg.osasli',
|
||||||
|
'elc' => 'application/octet-stream',
|
||||||
|
'eml' => 'message/rfc822',
|
||||||
|
'emma' => 'application/emma+xml',
|
||||||
|
'eol' => 'audio/vnd.digital-winds',
|
||||||
|
'eot' => 'application/vnd.ms-fontobject',
|
||||||
|
'eps' => 'application/postscript',
|
||||||
|
'epub' => 'application/epub+zip',
|
||||||
|
'es3' => 'application/vnd.eszigno3+xml',
|
||||||
|
'esf' => 'application/vnd.epson.esf',
|
||||||
|
'et3' => 'application/vnd.eszigno3+xml',
|
||||||
|
'etx' => 'text/x-setext',
|
||||||
|
'exe' => 'application/x-msdownload',
|
||||||
|
'exi' => 'application/exi',
|
||||||
|
'ext' => 'application/vnd.novadigm.ext',
|
||||||
|
'ez' => 'application/andrew-inset',
|
||||||
|
'ez2' => 'application/vnd.ezpix-album',
|
||||||
|
'ez3' => 'application/vnd.ezpix-package',
|
||||||
|
'f' => 'text/x-fortran',
|
||||||
|
'f4v' => 'video/x-f4v',
|
||||||
|
'f77' => 'text/x-fortran',
|
||||||
|
'f90' => 'text/x-fortran',
|
||||||
|
'fbs' => 'image/vnd.fastbidsheet',
|
||||||
|
'fcs' => 'application/vnd.isac.fcs',
|
||||||
|
'fdf' => 'application/vnd.fdf',
|
||||||
|
'fe_launch' => 'application/vnd.denovo.fcselayout-link',
|
||||||
|
'fg5' => 'application/vnd.fujitsu.oasysgp',
|
||||||
|
'fgd' => 'application/x-director',
|
||||||
|
'fh' => 'image/x-freehand',
|
||||||
|
'fh4' => 'image/x-freehand',
|
||||||
|
'fh5' => 'image/x-freehand',
|
||||||
|
'fh7' => 'image/x-freehand',
|
||||||
|
'fhc' => 'image/x-freehand',
|
||||||
|
'fig' => 'application/x-xfig',
|
||||||
|
'fli' => 'video/x-fli',
|
||||||
|
'flo' => 'application/vnd.micrografx.flo',
|
||||||
|
'flv' => 'video/x-flv',
|
||||||
|
'flw' => 'application/vnd.kde.kivio',
|
||||||
|
'flx' => 'text/vnd.fmi.flexstor',
|
||||||
|
'fly' => 'text/vnd.fly',
|
||||||
|
'fm' => 'application/vnd.framemaker',
|
||||||
|
'fnc' => 'application/vnd.frogans.fnc',
|
||||||
|
'for' => 'text/x-fortran',
|
||||||
|
'fpx' => 'image/vnd.fpx',
|
||||||
|
'frame' => 'application/vnd.framemaker',
|
||||||
|
'fsc' => 'application/vnd.fsc.weblaunch',
|
||||||
|
'fst' => 'image/vnd.fst',
|
||||||
|
'ftc' => 'application/vnd.fluxtime.clip',
|
||||||
|
'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
|
||||||
|
'fvt' => 'video/vnd.fvt',
|
||||||
|
'fxp' => 'application/vnd.adobe.fxp',
|
||||||
|
'fxpl' => 'application/vnd.adobe.fxp',
|
||||||
|
'fzs' => 'application/vnd.fuzzysheet',
|
||||||
|
'g2w' => 'application/vnd.geoplan',
|
||||||
|
'g3' => 'image/g3fax',
|
||||||
|
'g3w' => 'application/vnd.geospace',
|
||||||
|
'gac' => 'application/vnd.groove-account',
|
||||||
|
'gdl' => 'model/vnd.gdl',
|
||||||
|
'geo' => 'application/vnd.dynageo',
|
||||||
|
'gex' => 'application/vnd.geometry-explorer',
|
||||||
|
'ggb' => 'application/vnd.geogebra.file',
|
||||||
|
'ggt' => 'application/vnd.geogebra.tool',
|
||||||
|
'ghf' => 'application/vnd.groove-help',
|
||||||
|
'gif' => 'image/gif',
|
||||||
|
'gim' => 'application/vnd.groove-identity-message',
|
||||||
|
'gmx' => 'application/vnd.gmx',
|
||||||
|
'gnumeric' => 'application/x-gnumeric',
|
||||||
|
'gph' => 'application/vnd.flographit',
|
||||||
|
'gqf' => 'application/vnd.grafeq',
|
||||||
|
'gqs' => 'application/vnd.grafeq',
|
||||||
|
'gram' => 'application/srgs',
|
||||||
|
'gre' => 'application/vnd.geometry-explorer',
|
||||||
|
'grv' => 'application/vnd.groove-injector',
|
||||||
|
'grxml' => 'application/srgs+xml',
|
||||||
|
'gsf' => 'application/x-font-ghostscript',
|
||||||
|
'gtar' => 'application/x-gtar',
|
||||||
|
'gtm' => 'application/vnd.groove-tool-message',
|
||||||
|
'gtw' => 'model/vnd.gtw',
|
||||||
|
'gv' => 'text/vnd.graphviz',
|
||||||
|
'gxt' => 'application/vnd.geonext',
|
||||||
|
'h' => 'text/x-c',
|
||||||
|
'h261' => 'video/h261',
|
||||||
|
'h263' => 'video/h263',
|
||||||
|
'h264' => 'video/h264',
|
||||||
|
'hal' => 'application/vnd.hal+xml',
|
||||||
|
'hbci' => 'application/vnd.hbci',
|
||||||
|
'hdf' => 'application/x-hdf',
|
||||||
|
'hh' => 'text/x-c',
|
||||||
|
'hlp' => 'application/winhlp',
|
||||||
|
'hpgl' => 'application/vnd.hp-hpgl',
|
||||||
|
'hpid' => 'application/vnd.hp-hpid',
|
||||||
|
'hps' => 'application/vnd.hp-hps',
|
||||||
|
'hqx' => 'application/mac-binhex40',
|
||||||
|
'hta' => 'application/octet-stream',
|
||||||
|
'htc' => 'text/html',
|
||||||
|
'htke' => 'application/vnd.kenameaapp',
|
||||||
|
'htm' => 'text/html',
|
||||||
|
'html' => 'text/html',
|
||||||
|
'hvd' => 'application/vnd.yamaha.hv-dic',
|
||||||
|
'hvp' => 'application/vnd.yamaha.hv-voice',
|
||||||
|
'hvs' => 'application/vnd.yamaha.hv-script',
|
||||||
|
'i2g' => 'application/vnd.intergeo',
|
||||||
|
'icc' => 'application/vnd.iccprofile',
|
||||||
|
'ice' => 'x-conference/x-cooltalk',
|
||||||
|
'icm' => 'application/vnd.iccprofile',
|
||||||
|
'ico' => 'image/x-icon',
|
||||||
|
'ics' => 'text/calendar',
|
||||||
|
'ief' => 'image/ief',
|
||||||
|
'ifb' => 'text/calendar',
|
||||||
|
'ifm' => 'application/vnd.shana.informed.formdata',
|
||||||
|
'iges' => 'model/iges',
|
||||||
|
'igl' => 'application/vnd.igloader',
|
||||||
|
'igm' => 'application/vnd.insors.igm',
|
||||||
|
'igs' => 'model/iges',
|
||||||
|
'igx' => 'application/vnd.micrografx.igx',
|
||||||
|
'iif' => 'application/vnd.shana.informed.interchange',
|
||||||
|
'imp' => 'application/vnd.accpac.simply.imp',
|
||||||
|
'ims' => 'application/vnd.ms-ims',
|
||||||
|
'in' => 'text/plain',
|
||||||
|
'ini' => 'text/plain',
|
||||||
|
'ipfix' => 'application/ipfix',
|
||||||
|
'ipk' => 'application/vnd.shana.informed.package',
|
||||||
|
'irm' => 'application/vnd.ibm.rights-management',
|
||||||
|
'irp' => 'application/vnd.irepository.package+xml',
|
||||||
|
'iso' => 'application/octet-stream',
|
||||||
|
'itp' => 'application/vnd.shana.informed.formtemplate',
|
||||||
|
'ivp' => 'application/vnd.immervision-ivp',
|
||||||
|
'ivu' => 'application/vnd.immervision-ivu',
|
||||||
|
'jad' => 'text/vnd.sun.j2me.app-descriptor',
|
||||||
|
'jam' => 'application/vnd.jam',
|
||||||
|
'jar' => 'application/java-archive',
|
||||||
|
'java' => 'text/x-java-source',
|
||||||
|
'jisp' => 'application/vnd.jisp',
|
||||||
|
'jlt' => 'application/vnd.hp-jlyt',
|
||||||
|
'jnlp' => 'application/x-java-jnlp-file',
|
||||||
|
'joda' => 'application/vnd.joost.joda-archive',
|
||||||
|
'jpe' => 'image/jpeg',
|
||||||
|
'jpeg' => 'image/jpeg',
|
||||||
|
'jpg' => 'image/jpeg',
|
||||||
|
'jpgm' => 'video/jpm',
|
||||||
|
'jpgv' => 'video/jpeg',
|
||||||
|
'jpm' => 'video/jpm',
|
||||||
|
'js' => 'text/javascript',
|
||||||
|
'json' => 'application/json',
|
||||||
|
'kar' => 'audio/midi',
|
||||||
|
'karbon' => 'application/vnd.kde.karbon',
|
||||||
|
'kfo' => 'application/vnd.kde.kformula',
|
||||||
|
'kia' => 'application/vnd.kidspiration',
|
||||||
|
'kml' => 'application/vnd.google-earth.kml+xml',
|
||||||
|
'kmz' => 'application/vnd.google-earth.kmz',
|
||||||
|
'kne' => 'application/vnd.kinar',
|
||||||
|
'knp' => 'application/vnd.kinar',
|
||||||
|
'kon' => 'application/vnd.kde.kontour',
|
||||||
|
'kpr' => 'application/vnd.kde.kpresenter',
|
||||||
|
'kpt' => 'application/vnd.kde.kpresenter',
|
||||||
|
'ksp' => 'application/vnd.kde.kspread',
|
||||||
|
'ktr' => 'application/vnd.kahootz',
|
||||||
|
'ktx' => 'image/ktx',
|
||||||
|
'ktz' => 'application/vnd.kahootz',
|
||||||
|
'kwd' => 'application/vnd.kde.kword',
|
||||||
|
'kwt' => 'application/vnd.kde.kword',
|
||||||
|
'lasxml' => 'application/vnd.las.las+xml',
|
||||||
|
'latex' => 'application/x-latex',
|
||||||
|
'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
|
||||||
|
'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
|
||||||
|
'les' => 'application/vnd.hhe.lesson-player',
|
||||||
|
'lha' => 'application/octet-stream',
|
||||||
|
'link66' => 'application/vnd.route66.link66+xml',
|
||||||
|
'list' => 'text/plain',
|
||||||
|
'list3820' => 'application/vnd.ibm.modcap',
|
||||||
|
'listafp' => 'application/vnd.ibm.modcap',
|
||||||
|
'log' => 'text/plain',
|
||||||
|
'lostxml' => 'application/lost+xml',
|
||||||
|
'lrf' => 'application/octet-stream',
|
||||||
|
'lrm' => 'application/vnd.ms-lrm',
|
||||||
|
'ltf' => 'application/vnd.frogans.ltf',
|
||||||
|
'lvp' => 'audio/vnd.lucent.voice',
|
||||||
|
'lwp' => 'application/vnd.lotus-wordpro',
|
||||||
|
'lzh' => 'application/octet-stream',
|
||||||
|
'm13' => 'application/x-msmediaview',
|
||||||
|
'm14' => 'application/x-msmediaview',
|
||||||
|
'm1v' => 'video/mpeg',
|
||||||
|
'm21' => 'application/mp21',
|
||||||
|
'm2a' => 'audio/mpeg',
|
||||||
|
'm2v' => 'video/mpeg',
|
||||||
|
'm3a' => 'audio/mpeg',
|
||||||
|
'm3u' => 'audio/x-mpegurl',
|
||||||
|
'm3u8' => 'application/vnd.apple.mpegurl',
|
||||||
|
'm4a' => 'audio/mp4',
|
||||||
|
'm4u' => 'video/vnd.mpegurl',
|
||||||
|
'm4v' => 'video/mp4',
|
||||||
|
'ma' => 'application/mathematica',
|
||||||
|
'mads' => 'application/mads+xml',
|
||||||
|
'mag' => 'application/vnd.ecowin.chart',
|
||||||
|
'maker' => 'application/vnd.framemaker',
|
||||||
|
'man' => 'text/troff',
|
||||||
|
'mathml' => 'application/mathml+xml',
|
||||||
|
'mb' => 'application/mathematica',
|
||||||
|
'mbk' => 'application/vnd.mobius.mbk',
|
||||||
|
'mbox' => 'application/mbox',
|
||||||
|
'mc1' => 'application/vnd.medcalcdata',
|
||||||
|
'mcd' => 'application/vnd.mcd',
|
||||||
|
'mcurl' => 'text/vnd.curl.mcurl',
|
||||||
|
'mdb' => 'application/x-msaccess',
|
||||||
|
'mdi' => 'image/vnd.ms-modi',
|
||||||
|
'me' => 'text/troff',
|
||||||
|
'mesh' => 'model/mesh',
|
||||||
|
'meta4' => 'application/metalink4+xml',
|
||||||
|
'mets' => 'application/mets+xml',
|
||||||
|
'mfm' => 'application/vnd.mfmp',
|
||||||
|
'mgp' => 'application/vnd.osgeo.mapguide.package',
|
||||||
|
'mgz' => 'application/vnd.proteus.magazine',
|
||||||
|
'mid' => 'audio/midi',
|
||||||
|
'midi' => 'audio/midi',
|
||||||
|
'mif' => 'application/vnd.mif',
|
||||||
|
'mime' => 'message/rfc822',
|
||||||
|
'mj2' => 'video/mj2',
|
||||||
|
'mjp2' => 'video/mj2',
|
||||||
|
'mlp' => 'application/vnd.dolby.mlp',
|
||||||
|
'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
|
||||||
|
'mmf' => 'application/vnd.smaf',
|
||||||
|
'mmr' => 'image/vnd.fujixerox.edmics-mmr',
|
||||||
|
'mny' => 'application/x-msmoney',
|
||||||
|
'mobi' => 'application/x-mobipocket-ebook',
|
||||||
|
'mods' => 'application/mods+xml',
|
||||||
|
'mov' => 'video/quicktime',
|
||||||
|
'movie' => 'video/x-sgi-movie',
|
||||||
|
'mp2' => 'audio/mpeg',
|
||||||
|
'mp21' => 'application/mp21',
|
||||||
|
'mp2a' => 'audio/mpeg',
|
||||||
|
'mp3' => 'audio/mpeg',
|
||||||
|
'mp4' => 'video/mp4',
|
||||||
|
'mp4a' => 'audio/mp4',
|
||||||
|
'mp4s' => 'application/mp4',
|
||||||
|
'mp4v' => 'video/mp4',
|
||||||
|
'mpc' => 'application/vnd.mophun.certificate',
|
||||||
|
'mpe' => 'video/mpeg',
|
||||||
|
'mpeg' => 'video/mpeg',
|
||||||
|
'mpg' => 'video/mpeg',
|
||||||
|
'mpg4' => 'video/mp4',
|
||||||
|
'mpga' => 'audio/mpeg',
|
||||||
|
'mpkg' => 'application/vnd.apple.installer+xml',
|
||||||
|
'mpm' => 'application/vnd.blueice.multipass',
|
||||||
|
'mpn' => 'application/vnd.mophun.application',
|
||||||
|
'mpp' => 'application/vnd.ms-project',
|
||||||
|
'mpt' => 'application/vnd.ms-project',
|
||||||
|
'mpy' => 'application/vnd.ibm.minipay',
|
||||||
|
'mqy' => 'application/vnd.mobius.mqy',
|
||||||
|
'mrc' => 'application/marc',
|
||||||
|
'mrcx' => 'application/marcxml+xml',
|
||||||
|
'ms' => 'text/troff',
|
||||||
|
'mscml' => 'application/mediaservercontrol+xml',
|
||||||
|
'mseed' => 'application/vnd.fdsn.mseed',
|
||||||
|
'mseq' => 'application/vnd.mseq',
|
||||||
|
'msf' => 'application/vnd.epson.msf',
|
||||||
|
'msh' => 'model/mesh',
|
||||||
|
'msi' => 'application/x-msdownload',
|
||||||
|
'msl' => 'application/vnd.mobius.msl',
|
||||||
|
'msty' => 'application/vnd.muvee.style',
|
||||||
|
'mts' => 'model/vnd.mts',
|
||||||
|
'mus' => 'application/vnd.musician',
|
||||||
|
'musicxml' => 'application/vnd.recordare.musicxml+xml',
|
||||||
|
'mvb' => 'application/x-msmediaview',
|
||||||
|
'mwf' => 'application/vnd.mfer',
|
||||||
|
'mxf' => 'application/mxf',
|
||||||
|
'mxl' => 'application/vnd.recordare.musicxml',
|
||||||
|
'mxml' => 'application/xv+xml',
|
||||||
|
'mxs' => 'application/vnd.triscape.mxs',
|
||||||
|
'mxu' => 'video/vnd.mpegurl',
|
||||||
|
'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
|
||||||
|
'n3' => 'text/n3',
|
||||||
|
'nb' => 'application/mathematica',
|
||||||
|
'nbp' => 'application/vnd.wolfram.player',
|
||||||
|
'nc' => 'application/x-netcdf',
|
||||||
|
'ncx' => 'application/x-dtbncx+xml',
|
||||||
|
'ngdat' => 'application/vnd.nokia.n-gage.data',
|
||||||
|
'nlu' => 'application/vnd.neurolanguage.nlu',
|
||||||
|
'nml' => 'application/vnd.enliven',
|
||||||
|
'nnd' => 'application/vnd.noblenet-directory',
|
||||||
|
'nns' => 'application/vnd.noblenet-sealer',
|
||||||
|
'nnw' => 'application/vnd.noblenet-web',
|
||||||
|
'npx' => 'image/vnd.net-fpx',
|
||||||
|
'nsf' => 'application/vnd.lotus-notes',
|
||||||
|
'oa2' => 'application/vnd.fujitsu.oasys2',
|
||||||
|
'oa3' => 'application/vnd.fujitsu.oasys3',
|
||||||
|
'oas' => 'application/vnd.fujitsu.oasys',
|
||||||
|
'obd' => 'application/x-msbinder',
|
||||||
|
'oda' => 'application/oda',
|
||||||
|
'odb' => 'application/vnd.oasis.opendocument.database',
|
||||||
|
'odc' => 'application/vnd.oasis.opendocument.chart',
|
||||||
|
'odf' => 'application/vnd.oasis.opendocument.formula',
|
||||||
|
'odft' => 'application/vnd.oasis.opendocument.formula-template',
|
||||||
|
'odg' => 'application/vnd.oasis.opendocument.graphics',
|
||||||
|
'odi' => 'application/vnd.oasis.opendocument.image',
|
||||||
|
'odm' => 'application/vnd.oasis.opendocument.text-master',
|
||||||
|
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||||
|
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||||
|
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||||
|
'oga' => 'audio/ogg',
|
||||||
|
'ogg' => 'audio/ogg',
|
||||||
|
'ogv' => 'video/ogg',
|
||||||
|
'ogx' => 'application/ogg',
|
||||||
|
'onepkg' => 'application/onenote',
|
||||||
|
'onetmp' => 'application/onenote',
|
||||||
|
'onetoc' => 'application/onenote',
|
||||||
|
'onetoc2' => 'application/onenote',
|
||||||
|
'opf' => 'application/oebps-package+xml',
|
||||||
|
'oprc' => 'application/vnd.palm',
|
||||||
|
'org' => 'application/vnd.lotus-organizer',
|
||||||
|
'osf' => 'application/vnd.yamaha.openscoreformat',
|
||||||
|
'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
|
||||||
|
'otc' => 'application/vnd.oasis.opendocument.chart-template',
|
||||||
|
'otf' => 'application/x-font-otf',
|
||||||
|
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
|
||||||
|
'oth' => 'application/vnd.oasis.opendocument.text-web',
|
||||||
|
'oti' => 'application/vnd.oasis.opendocument.image-template',
|
||||||
|
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
|
||||||
|
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||||
|
'ott' => 'application/vnd.oasis.opendocument.text-template',
|
||||||
|
'oxt' => 'application/vnd.openofficeorg.extension',
|
||||||
|
'p' => 'text/x-pascal',
|
||||||
|
'p10' => 'application/pkcs10',
|
||||||
|
'p12' => 'application/x-pkcs12',
|
||||||
|
'p7b' => 'application/x-pkcs7-certificates',
|
||||||
|
'p7c' => 'application/pkcs7-mime',
|
||||||
|
'p7m' => 'application/pkcs7-mime',
|
||||||
|
'p7r' => 'application/x-pkcs7-certreqresp',
|
||||||
|
'p7s' => 'application/pkcs7-signature',
|
||||||
|
'p8' => 'application/pkcs8',
|
||||||
|
'pas' => 'text/x-pascal',
|
||||||
|
'paw' => 'application/vnd.pawaafile',
|
||||||
|
'pbd' => 'application/vnd.powerbuilder6',
|
||||||
|
'pbm' => 'image/x-portable-bitmap',
|
||||||
|
'pcf' => 'application/x-font-pcf',
|
||||||
|
'pcl' => 'application/vnd.hp-pcl',
|
||||||
|
'pclxl' => 'application/vnd.hp-pclxl',
|
||||||
|
'pct' => 'image/x-pict',
|
||||||
|
'pcurl' => 'application/vnd.curl.pcurl',
|
||||||
|
'pcx' => 'image/x-pcx',
|
||||||
|
'pdb' => 'application/vnd.palm',
|
||||||
|
'pdf' => 'application/pdf',
|
||||||
|
'pfa' => 'application/x-font-type1',
|
||||||
|
'pfb' => 'application/x-font-type1',
|
||||||
|
'pfm' => 'application/x-font-type1',
|
||||||
|
'pfr' => 'application/font-tdpfr',
|
||||||
|
'pfx' => 'application/x-pkcs12',
|
||||||
|
'pgm' => 'image/x-portable-graymap',
|
||||||
|
'pgn' => 'application/x-chess-pgn',
|
||||||
|
'pgp' => 'application/pgp-encrypted',
|
||||||
|
'php' => 'text/x-php',
|
||||||
|
'phps' => 'application/x-httpd-phps',
|
||||||
|
'pic' => 'image/x-pict',
|
||||||
|
'pkg' => 'application/octet-stream',
|
||||||
|
'pki' => 'application/pkixcmp',
|
||||||
|
'pkipath' => 'application/pkix-pkipath',
|
||||||
|
'plb' => 'application/vnd.3gpp.pic-bw-large',
|
||||||
|
'plc' => 'application/vnd.mobius.plc',
|
||||||
|
'plf' => 'application/vnd.pocketlearn',
|
||||||
|
'pls' => 'application/pls+xml',
|
||||||
|
'pml' => 'application/vnd.ctc-posml',
|
||||||
|
'png' => 'image/png',
|
||||||
|
'pnm' => 'image/x-portable-anymap',
|
||||||
|
'portpkg' => 'application/vnd.macports.portpkg',
|
||||||
|
'pot' => 'application/vnd.ms-powerpoint',
|
||||||
|
'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
|
||||||
|
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||||
|
'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
|
||||||
|
'ppd' => 'application/vnd.cups-ppd',
|
||||||
|
'ppm' => 'image/x-portable-pixmap',
|
||||||
|
'pps' => 'application/vnd.ms-powerpoint',
|
||||||
|
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
|
||||||
|
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||||
|
'ppt' => 'application/vnd.ms-powerpoint',
|
||||||
|
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
|
||||||
|
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
'pqa' => 'application/vnd.palm',
|
||||||
|
'prc' => 'application/x-mobipocket-ebook',
|
||||||
|
'pre' => 'application/vnd.lotus-freelance',
|
||||||
|
'prf' => 'application/pics-rules',
|
||||||
|
'ps' => 'application/postscript',
|
||||||
|
'psb' => 'application/vnd.3gpp.pic-bw-small',
|
||||||
|
'psd' => 'image/vnd.adobe.photoshop',
|
||||||
|
'psf' => 'application/x-font-linux-psf',
|
||||||
|
'pskcxml' => 'application/pskc+xml',
|
||||||
|
'ptid' => 'application/vnd.pvi.ptid1',
|
||||||
|
'pub' => 'application/x-mspublisher',
|
||||||
|
'pvb' => 'application/vnd.3gpp.pic-bw-var',
|
||||||
|
'pwn' => 'application/vnd.3m.post-it-notes',
|
||||||
|
'pya' => 'audio/vnd.ms-playready.media.pya',
|
||||||
|
'pyv' => 'video/vnd.ms-playready.media.pyv',
|
||||||
|
'qam' => 'application/vnd.epson.quickanime',
|
||||||
|
'qbo' => 'application/vnd.intu.qbo',
|
||||||
|
'qfx' => 'application/vnd.intu.qfx',
|
||||||
|
'qps' => 'application/vnd.publishare-delta-tree',
|
||||||
|
'qt' => 'video/quicktime',
|
||||||
|
'qwd' => 'application/vnd.quark.quarkxpress',
|
||||||
|
'qwt' => 'application/vnd.quark.quarkxpress',
|
||||||
|
'qxb' => 'application/vnd.quark.quarkxpress',
|
||||||
|
'qxd' => 'application/vnd.quark.quarkxpress',
|
||||||
|
'qxl' => 'application/vnd.quark.quarkxpress',
|
||||||
|
'qxt' => 'application/vnd.quark.quarkxpress',
|
||||||
|
'ra' => 'audio/x-pn-realaudio',
|
||||||
|
'ram' => 'audio/x-pn-realaudio',
|
||||||
|
'rar' => 'application/x-rar-compressed',
|
||||||
|
'ras' => 'image/x-cmu-raster',
|
||||||
|
'rb' => 'text/plain',
|
||||||
|
'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
|
||||||
|
'rdf' => 'application/rdf+xml',
|
||||||
|
'rdz' => 'application/vnd.data-vision.rdz',
|
||||||
|
'rep' => 'application/vnd.businessobjects',
|
||||||
|
'res' => 'application/x-dtbresource+xml',
|
||||||
|
'resx' => 'text/xml',
|
||||||
|
'rgb' => 'image/x-rgb',
|
||||||
|
'rif' => 'application/reginfo+xml',
|
||||||
|
'rip' => 'audio/vnd.rip',
|
||||||
|
'rl' => 'application/resource-lists+xml',
|
||||||
|
'rlc' => 'image/vnd.fujixerox.edmics-rlc',
|
||||||
|
'rld' => 'application/resource-lists-diff+xml',
|
||||||
|
'rm' => 'application/vnd.rn-realmedia',
|
||||||
|
'rmi' => 'audio/midi',
|
||||||
|
'rmp' => 'audio/x-pn-realaudio-plugin',
|
||||||
|
'rms' => 'application/vnd.jcp.javame.midlet-rms',
|
||||||
|
'rnc' => 'application/relax-ng-compact-syntax',
|
||||||
|
'roff' => 'text/troff',
|
||||||
|
'rp9' => 'application/vnd.cloanto.rp9',
|
||||||
|
'rpss' => 'application/vnd.nokia.radio-presets',
|
||||||
|
'rpst' => 'application/vnd.nokia.radio-preset',
|
||||||
|
'rq' => 'application/sparql-query',
|
||||||
|
'rs' => 'application/rls-services+xml',
|
||||||
|
'rsd' => 'application/rsd+xml',
|
||||||
|
'rss' => 'application/rss+xml',
|
||||||
|
'rtf' => 'application/rtf',
|
||||||
|
'rtx' => 'text/richtext',
|
||||||
|
's' => 'text/x-asm',
|
||||||
|
'saf' => 'application/vnd.yamaha.smaf-audio',
|
||||||
|
'sbml' => 'application/sbml+xml',
|
||||||
|
'sc' => 'application/vnd.ibm.secure-container',
|
||||||
|
'scd' => 'application/x-msschedule',
|
||||||
|
'scm' => 'application/vnd.lotus-screencam',
|
||||||
|
'scq' => 'application/scvp-cv-request',
|
||||||
|
'scs' => 'application/scvp-cv-response',
|
||||||
|
'scurl' => 'text/vnd.curl.scurl',
|
||||||
|
'sda' => 'application/vnd.stardivision.draw',
|
||||||
|
'sdc' => 'application/vnd.stardivision.calc',
|
||||||
|
'sdd' => 'application/vnd.stardivision.impress',
|
||||||
|
'sdkd' => 'application/vnd.solent.sdkm+xml',
|
||||||
|
'sdkm' => 'application/vnd.solent.sdkm+xml',
|
||||||
|
'sdp' => 'application/sdp',
|
||||||
|
'sdw' => 'application/vnd.stardivision.writer',
|
||||||
|
'see' => 'application/vnd.seemail',
|
||||||
|
'seed' => 'application/vnd.fdsn.seed',
|
||||||
|
'sema' => 'application/vnd.sema',
|
||||||
|
'semd' => 'application/vnd.semd',
|
||||||
|
'semf' => 'application/vnd.semf',
|
||||||
|
'ser' => 'application/java-serialized-object',
|
||||||
|
'setpay' => 'application/set-payment-initiation',
|
||||||
|
'setreg' => 'application/set-registration-initiation',
|
||||||
|
'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
|
||||||
|
'sfs' => 'application/vnd.spotfire.sfs',
|
||||||
|
'sgl' => 'application/vnd.stardivision.writer-global',
|
||||||
|
'sgm' => 'text/sgml',
|
||||||
|
'sgml' => 'text/sgml',
|
||||||
|
'sh' => 'application/x-sh',
|
||||||
|
'shar' => 'application/x-shar',
|
||||||
|
'shf' => 'application/shf+xml',
|
||||||
|
'sig' => 'application/pgp-signature',
|
||||||
|
'silo' => 'model/mesh',
|
||||||
|
'sis' => 'application/vnd.symbian.install',
|
||||||
|
'sisx' => 'application/vnd.symbian.install',
|
||||||
|
'sit' => 'application/x-stuffit',
|
||||||
|
'sitx' => 'application/x-stuffitx',
|
||||||
|
'skd' => 'application/vnd.koan',
|
||||||
|
'skm' => 'application/vnd.koan',
|
||||||
|
'skp' => 'application/vnd.koan',
|
||||||
|
'skt' => 'application/vnd.koan',
|
||||||
|
'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
|
||||||
|
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
|
||||||
|
'slt' => 'application/vnd.epson.salt',
|
||||||
|
'sm' => 'application/vnd.stepmania.stepchart',
|
||||||
|
'smf' => 'application/vnd.stardivision.math',
|
||||||
|
'smi' => 'application/smil+xml',
|
||||||
|
'smil' => 'application/smil+xml',
|
||||||
|
'snd' => 'audio/basic',
|
||||||
|
'snf' => 'application/x-font-snf',
|
||||||
|
'so' => 'application/octet-stream',
|
||||||
|
'spc' => 'application/x-pkcs7-certificates',
|
||||||
|
'spf' => 'application/vnd.yamaha.smaf-phrase',
|
||||||
|
'spl' => 'application/x-futuresplash',
|
||||||
|
'spot' => 'text/vnd.in3d.spot',
|
||||||
|
'spp' => 'application/scvp-vp-response',
|
||||||
|
'spq' => 'application/scvp-vp-request',
|
||||||
|
'spx' => 'audio/ogg',
|
||||||
|
'src' => 'application/x-wais-source',
|
||||||
|
'sru' => 'application/sru+xml',
|
||||||
|
'srx' => 'application/sparql-results+xml',
|
||||||
|
'sse' => 'application/vnd.kodak-descriptor',
|
||||||
|
'ssf' => 'application/vnd.epson.ssf',
|
||||||
|
'ssml' => 'application/ssml+xml',
|
||||||
|
'st' => 'application/vnd.sailingtracker.track',
|
||||||
|
'stc' => 'application/vnd.sun.xml.calc.template',
|
||||||
|
'std' => 'application/vnd.sun.xml.draw.template',
|
||||||
|
'stf' => 'application/vnd.wt.stf',
|
||||||
|
'sti' => 'application/vnd.sun.xml.impress.template',
|
||||||
|
'stk' => 'application/hyperstudio',
|
||||||
|
'stl' => 'application/vnd.ms-pki.stl',
|
||||||
|
'str' => 'application/vnd.pg.format',
|
||||||
|
'stw' => 'application/vnd.sun.xml.writer.template',
|
||||||
|
'sub' => 'image/vnd.dvb.subtitle',
|
||||||
|
'sus' => 'application/vnd.sus-calendar',
|
||||||
|
'susp' => 'application/vnd.sus-calendar',
|
||||||
|
'sv4cpio' => 'application/x-sv4cpio',
|
||||||
|
'sv4crc' => 'application/x-sv4crc',
|
||||||
|
'svc' => 'application/vnd.dvb.service',
|
||||||
|
'svd' => 'application/vnd.svd',
|
||||||
|
'svg' => 'image/svg+xml',
|
||||||
|
'svgz' => 'image/svg+xml',
|
||||||
|
'swa' => 'application/x-director',
|
||||||
|
'swf' => 'application/x-shockwave-flash',
|
||||||
|
'swi' => 'application/vnd.aristanetworks.swi',
|
||||||
|
'sxc' => 'application/vnd.sun.xml.calc',
|
||||||
|
'sxd' => 'application/vnd.sun.xml.draw',
|
||||||
|
'sxg' => 'application/vnd.sun.xml.writer.global',
|
||||||
|
'sxi' => 'application/vnd.sun.xml.impress',
|
||||||
|
'sxm' => 'application/vnd.sun.xml.math',
|
||||||
|
'sxw' => 'application/vnd.sun.xml.writer',
|
||||||
|
't' => 'text/troff',
|
||||||
|
'tao' => 'application/vnd.tao.intent-module-archive',
|
||||||
|
'tar' => 'application/x-tar',
|
||||||
|
'tcap' => 'application/vnd.3gpp2.tcap',
|
||||||
|
'tcl' => 'application/x-tcl',
|
||||||
|
'teacher' => 'application/vnd.smart.teacher',
|
||||||
|
'tei' => 'application/tei+xml',
|
||||||
|
'teicorpus' => 'application/tei+xml',
|
||||||
|
'tex' => 'application/x-tex',
|
||||||
|
'texi' => 'application/x-texinfo',
|
||||||
|
'texinfo' => 'application/x-texinfo',
|
||||||
|
'text' => 'text/plain',
|
||||||
|
'tfi' => 'application/thraud+xml',
|
||||||
|
'tfm' => 'application/x-tex-tfm',
|
||||||
|
'thmx' => 'application/vnd.ms-officetheme',
|
||||||
|
'tif' => 'image/tiff',
|
||||||
|
'tiff' => 'image/tiff',
|
||||||
|
'tmo' => 'application/vnd.tmobile-livetv',
|
||||||
|
'torrent' => 'application/x-bittorrent',
|
||||||
|
'tpl' => 'application/vnd.groove-tool-template',
|
||||||
|
'tpt' => 'application/vnd.trid.tpt',
|
||||||
|
'tr' => 'text/troff',
|
||||||
|
'tra' => 'application/vnd.trueapp',
|
||||||
|
'trm' => 'application/x-msterminal',
|
||||||
|
'tsd' => 'application/timestamped-data',
|
||||||
|
'tsv' => 'text/tab-separated-values',
|
||||||
|
'ttc' => 'application/x-font-ttf',
|
||||||
|
'ttf' => 'application/x-font-ttf',
|
||||||
|
'ttl' => 'text/turtle',
|
||||||
|
'twd' => 'application/vnd.simtech-mindmapper',
|
||||||
|
'twds' => 'application/vnd.simtech-mindmapper',
|
||||||
|
'txd' => 'application/vnd.genomatix.tuxedo',
|
||||||
|
'txf' => 'application/vnd.mobius.txf',
|
||||||
|
'txt' => 'text/plain',
|
||||||
|
'u32' => 'application/x-authorware-bin',
|
||||||
|
'udeb' => 'application/x-debian-package',
|
||||||
|
'ufd' => 'application/vnd.ufdl',
|
||||||
|
'ufdl' => 'application/vnd.ufdl',
|
||||||
|
'umj' => 'application/vnd.umajin',
|
||||||
|
'unityweb' => 'application/vnd.unity',
|
||||||
|
'uoml' => 'application/vnd.uoml+xml',
|
||||||
|
'uri' => 'text/uri-list',
|
||||||
|
'uris' => 'text/uri-list',
|
||||||
|
'urls' => 'text/uri-list',
|
||||||
|
'ustar' => 'application/x-ustar',
|
||||||
|
'utz' => 'application/vnd.uiq.theme',
|
||||||
|
'uu' => 'text/x-uuencode',
|
||||||
|
'uva' => 'audio/vnd.dece.audio',
|
||||||
|
'uvd' => 'application/vnd.dece.data',
|
||||||
|
'uvf' => 'application/vnd.dece.data',
|
||||||
|
'uvg' => 'image/vnd.dece.graphic',
|
||||||
|
'uvh' => 'video/vnd.dece.hd',
|
||||||
|
'uvi' => 'image/vnd.dece.graphic',
|
||||||
|
'uvm' => 'video/vnd.dece.mobile',
|
||||||
|
'uvp' => 'video/vnd.dece.pd',
|
||||||
|
'uvs' => 'video/vnd.dece.sd',
|
||||||
|
'uvt' => 'application/vnd.dece.ttml+xml',
|
||||||
|
'uvu' => 'video/vnd.uvvu.mp4',
|
||||||
|
'uvv' => 'video/vnd.dece.video',
|
||||||
|
'uvva' => 'audio/vnd.dece.audio',
|
||||||
|
'uvvd' => 'application/vnd.dece.data',
|
||||||
|
'uvvf' => 'application/vnd.dece.data',
|
||||||
|
'uvvg' => 'image/vnd.dece.graphic',
|
||||||
|
'uvvh' => 'video/vnd.dece.hd',
|
||||||
|
'uvvi' => 'image/vnd.dece.graphic',
|
||||||
|
'uvvm' => 'video/vnd.dece.mobile',
|
||||||
|
'uvvp' => 'video/vnd.dece.pd',
|
||||||
|
'uvvs' => 'video/vnd.dece.sd',
|
||||||
|
'uvvt' => 'application/vnd.dece.ttml+xml',
|
||||||
|
'uvvu' => 'video/vnd.uvvu.mp4',
|
||||||
|
'uvvv' => 'video/vnd.dece.video',
|
||||||
|
'uvvx' => 'application/vnd.dece.unspecified',
|
||||||
|
'uvx' => 'application/vnd.dece.unspecified',
|
||||||
|
'vcd' => 'application/x-cdlink',
|
||||||
|
'vcf' => 'text/x-vcard',
|
||||||
|
'vcg' => 'application/vnd.groove-vcard',
|
||||||
|
'vcs' => 'text/x-vcalendar',
|
||||||
|
'vcx' => 'application/vnd.vcx',
|
||||||
|
'vis' => 'application/vnd.visionary',
|
||||||
|
'viv' => 'video/vnd.vivo',
|
||||||
|
'vor' => 'application/vnd.stardivision.writer',
|
||||||
|
'vox' => 'application/x-authorware-bin',
|
||||||
|
'vrml' => 'model/vrml',
|
||||||
|
'vsd' => 'application/vnd.visio',
|
||||||
|
'vsf' => 'application/vnd.vsf',
|
||||||
|
'vss' => 'application/vnd.visio',
|
||||||
|
'vst' => 'application/vnd.visio',
|
||||||
|
'vsw' => 'application/vnd.visio',
|
||||||
|
'vtu' => 'model/vnd.vtu',
|
||||||
|
'vxml' => 'application/voicexml+xml',
|
||||||
|
'w3d' => 'application/x-director',
|
||||||
|
'wad' => 'application/x-doom',
|
||||||
|
'wav' => 'audio/x-wav',
|
||||||
|
'wax' => 'audio/x-ms-wax',
|
||||||
|
'wbmp' => 'image/vnd.wap.wbmp',
|
||||||
|
'wbs' => 'application/vnd.criticaltools.wbs+xml',
|
||||||
|
'wbxml' => 'application/vnd.wap.wbxml',
|
||||||
|
'wcm' => 'application/vnd.ms-works',
|
||||||
|
'wdb' => 'application/vnd.ms-works',
|
||||||
|
'weba' => 'audio/webm',
|
||||||
|
'webm' => 'video/webm',
|
||||||
|
'webp' => 'image/webp',
|
||||||
|
'wg' => 'application/vnd.pmi.widget',
|
||||||
|
'wgt' => 'application/widget',
|
||||||
|
'wks' => 'application/vnd.ms-works',
|
||||||
|
'wm' => 'video/x-ms-wm',
|
||||||
|
'wma' => 'audio/x-ms-wma',
|
||||||
|
'wmd' => 'application/x-ms-wmd',
|
||||||
|
'wmf' => 'application/x-msmetafile',
|
||||||
|
'wml' => 'text/vnd.wap.wml',
|
||||||
|
'wmlc' => 'application/vnd.wap.wmlc',
|
||||||
|
'wmls' => 'text/vnd.wap.wmlscript',
|
||||||
|
'wmlsc' => 'application/vnd.wap.wmlscriptc',
|
||||||
|
'wmv' => 'video/x-ms-wmv',
|
||||||
|
'wmx' => 'video/x-ms-wmx',
|
||||||
|
'wmz' => 'application/x-ms-wmz',
|
||||||
|
'woff' => 'application/x-font-woff',
|
||||||
|
'wpd' => 'application/vnd.wordperfect',
|
||||||
|
'wpl' => 'application/vnd.ms-wpl',
|
||||||
|
'wps' => 'application/vnd.ms-works',
|
||||||
|
'wqd' => 'application/vnd.wqd',
|
||||||
|
'wri' => 'application/x-mswrite',
|
||||||
|
'wrl' => 'model/vrml',
|
||||||
|
'wsdl' => 'application/wsdl+xml',
|
||||||
|
'wspolicy' => 'application/wspolicy+xml',
|
||||||
|
'wtb' => 'application/vnd.webturbo',
|
||||||
|
'wvx' => 'video/x-ms-wvx',
|
||||||
|
'x32' => 'application/x-authorware-bin',
|
||||||
|
'x3d' => 'application/vnd.hzn-3d-crossword',
|
||||||
|
'xap' => 'application/x-silverlight-app',
|
||||||
|
'xar' => 'application/vnd.xara',
|
||||||
|
'xbap' => 'application/x-ms-xbap',
|
||||||
|
'xbd' => 'application/vnd.fujixerox.docuworks.binder',
|
||||||
|
'xbm' => 'image/x-xbitmap',
|
||||||
|
'xdf' => 'application/xcap-diff+xml',
|
||||||
|
'xdm' => 'application/vnd.syncml.dm+xml',
|
||||||
|
'xdp' => 'application/vnd.adobe.xdp+xml',
|
||||||
|
'xdssc' => 'application/dssc+xml',
|
||||||
|
'xdw' => 'application/vnd.fujixerox.docuworks',
|
||||||
|
'xenc' => 'application/xenc+xml',
|
||||||
|
'xer' => 'application/patch-ops-error+xml',
|
||||||
|
'xfdf' => 'application/vnd.adobe.xfdf',
|
||||||
|
'xfdl' => 'application/vnd.xfdl',
|
||||||
|
'xht' => 'application/xhtml+xml',
|
||||||
|
'xhtml' => 'application/xhtml+xml',
|
||||||
|
'xhvml' => 'application/xv+xml',
|
||||||
|
'xif' => 'image/vnd.xiff',
|
||||||
|
'xla' => 'application/vnd.ms-excel',
|
||||||
|
'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
|
||||||
|
'xlc' => 'application/vnd.ms-excel',
|
||||||
|
'xlm' => 'application/vnd.ms-excel',
|
||||||
|
'xls' => 'application/vnd.ms-excel',
|
||||||
|
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
|
||||||
|
'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
|
||||||
|
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'xlt' => 'application/vnd.ms-excel',
|
||||||
|
'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
|
||||||
|
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||||
|
'xlw' => 'application/vnd.ms-excel',
|
||||||
|
'xml' => 'application/xml',
|
||||||
|
'xo' => 'application/vnd.olpc-sugar',
|
||||||
|
'xop' => 'application/xop+xml',
|
||||||
|
'xpi' => 'application/x-xpinstall',
|
||||||
|
'xpm' => 'image/x-xpixmap',
|
||||||
|
'xpr' => 'application/vnd.is-xpr',
|
||||||
|
'xps' => 'application/vnd.ms-xpsdocument',
|
||||||
|
'xpw' => 'application/vnd.intercon.formnet',
|
||||||
|
'xpx' => 'application/vnd.intercon.formnet',
|
||||||
|
'xsl' => 'application/xml',
|
||||||
|
'xslt' => 'application/xslt+xml',
|
||||||
|
'xsm' => 'application/vnd.syncml+xml',
|
||||||
|
'xspf' => 'application/xspf+xml',
|
||||||
|
'xul' => 'application/vnd.mozilla.xul+xml',
|
||||||
|
'xvm' => 'application/xv+xml',
|
||||||
|
'xvml' => 'application/xv+xml',
|
||||||
|
'xwd' => 'image/x-xwindowdump',
|
||||||
|
'xyz' => 'chemical/x-xyz',
|
||||||
|
'yaml' => 'text/yaml',
|
||||||
|
'yang' => 'application/yang',
|
||||||
|
'yin' => 'application/yin+xml',
|
||||||
|
'yml' => 'text/yaml',
|
||||||
|
'zaz' => 'application/vnd.zzazz.deck+xml',
|
||||||
|
'zip' => 'application/zip',
|
||||||
|
'zir' => 'application/vnd.zul',
|
||||||
|
'zirz' => 'application/vnd.zul',
|
||||||
|
'zmm' => 'application/vnd.handheld-entertainment+xml'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a singleton instance of the class
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
public static function getInstance()
|
||||||
|
{
|
||||||
|
if (!self::$instance) {
|
||||||
|
self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a mimetype value from a file extension
|
||||||
|
*
|
||||||
|
* @param string $extension File extension
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function fromExtension($extension)
|
||||||
|
{
|
||||||
|
$extension = strtolower($extension);
|
||||||
|
|
||||||
|
return isset($this->mimetypes[$extension])
|
||||||
|
? $this->mimetypes[$extension]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a mimetype from a filename
|
||||||
|
*
|
||||||
|
* @param string $filename Filename to generate a mimetype from
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function fromFilename($filename)
|
||||||
|
{
|
||||||
|
return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
|
||||||
|
}
|
||||||
|
}
|
||||||
292
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Post/MultipartBody.php
Normal file
292
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Post/MultipartBody.php
Normal file
|
|
@ -0,0 +1,292 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Post;
|
||||||
|
|
||||||
|
use GuzzleHttp\Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream that when read returns bytes for a streaming multipart/form-data body
|
||||||
|
*/
|
||||||
|
class MultipartBody implements Stream\StreamInterface
|
||||||
|
{
|
||||||
|
/** @var Stream\StreamInterface */
|
||||||
|
private $files;
|
||||||
|
private $fields;
|
||||||
|
private $size;
|
||||||
|
private $buffer;
|
||||||
|
private $bufferedHeaders = [];
|
||||||
|
private $pos = 0;
|
||||||
|
private $currentFile = 0;
|
||||||
|
private $currentField = 0;
|
||||||
|
private $sentLast;
|
||||||
|
private $boundary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $fields Associative array of field names to values where
|
||||||
|
* each value is a string.
|
||||||
|
* @param array $files Associative array of PostFileInterface objects
|
||||||
|
* @param string $boundary You can optionally provide a specific boundary
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
array $fields = [],
|
||||||
|
array $files = [],
|
||||||
|
$boundary = null
|
||||||
|
) {
|
||||||
|
$this->boundary = $boundary ?: uniqid();
|
||||||
|
$this->fields = $fields;
|
||||||
|
$this->files = $files;
|
||||||
|
|
||||||
|
// Ensure each file is a PostFileInterface
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
if (!$file instanceof PostFileInterface) {
|
||||||
|
throw new \InvalidArgumentException('All POST fields must '
|
||||||
|
. 'implement PostFieldInterface');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$this->seek(0);
|
||||||
|
|
||||||
|
return $this->getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContents($maxLength = -1)
|
||||||
|
{
|
||||||
|
$buffer = '';
|
||||||
|
|
||||||
|
while (!$this->eof()) {
|
||||||
|
if ($maxLength === -1) {
|
||||||
|
$read = 1048576;
|
||||||
|
} else {
|
||||||
|
$len = strlen($buffer);
|
||||||
|
if ($len == $maxLength) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$read = min(1048576, $maxLength - $len);
|
||||||
|
}
|
||||||
|
$buffer .= $this->read($read);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the boundary
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBoundary()
|
||||||
|
{
|
||||||
|
return $this->boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
$this->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detach()
|
||||||
|
{
|
||||||
|
$this->fields = $this->files = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream has reached an EOF when all of the fields and files have been
|
||||||
|
* read.
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function eof()
|
||||||
|
{
|
||||||
|
return $this->currentField == count($this->fields) &&
|
||||||
|
$this->currentFile == count($this->files);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tell()
|
||||||
|
{
|
||||||
|
return $this->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isReadable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isWritable()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The steam is seekable by default, but all attached files must be
|
||||||
|
* seekable too.
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isSeekable()
|
||||||
|
{
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
if (!$file->getContent()->isSeekable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize()
|
||||||
|
{
|
||||||
|
if ($this->size === null) {
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
// We must be able to ascertain the size of each attached file
|
||||||
|
if (null === ($size = $file->getContent()->getSize())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$this->size += strlen($this->getFileHeaders($file)) + $size;
|
||||||
|
}
|
||||||
|
foreach (array_keys($this->fields) as $key) {
|
||||||
|
$this->size += strlen($this->getFieldString($key));
|
||||||
|
}
|
||||||
|
$this->size += strlen("\r\n--{$this->boundary}--");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read($length)
|
||||||
|
{
|
||||||
|
$content = '';
|
||||||
|
if ($this->buffer && !$this->buffer->eof()) {
|
||||||
|
$content .= $this->buffer->read($length);
|
||||||
|
}
|
||||||
|
if ($delta = $length - strlen($content)) {
|
||||||
|
$content .= $this->readData($delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content === '' && !$this->sentLast) {
|
||||||
|
$this->sentLast = true;
|
||||||
|
$content = "\r\n--{$this->boundary}--";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function seek($offset, $whence = SEEK_SET)
|
||||||
|
{
|
||||||
|
if ($offset != 0 || $whence != SEEK_SET || !$this->isSeekable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
if (!$file->getContent()->seek(0)) {
|
||||||
|
throw new \RuntimeException('Rewind on multipart file failed '
|
||||||
|
. 'even though it shouldn\'t have');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->buffer = $this->sentLast = null;
|
||||||
|
$this->pos = $this->currentField = $this->currentFile = 0;
|
||||||
|
$this->bufferedHeaders = [];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write($string)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No data is in the read buffer, so more needs to be pulled in from fields
|
||||||
|
* and files.
|
||||||
|
*
|
||||||
|
* @param int $length Amount of data to read
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function readData($length)
|
||||||
|
{
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
if ($this->currentField < count($this->fields)) {
|
||||||
|
$result = $this->readField($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result === '' && $this->currentFile < count($this->files)) {
|
||||||
|
$result = $this->readFile($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new stream buffer and inject form-data
|
||||||
|
*
|
||||||
|
* @param int $length Amount of data to read from the stream buffer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function readField($length)
|
||||||
|
{
|
||||||
|
$name = array_keys($this->fields)[++$this->currentField - 1];
|
||||||
|
$this->buffer = Stream\create($this->getFieldString($name));
|
||||||
|
|
||||||
|
return $this->buffer->read($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data from a POST file, fill the read buffer with any overflow
|
||||||
|
*
|
||||||
|
* @param int $length Amount of data to read from the file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function readFile($length)
|
||||||
|
{
|
||||||
|
$current = $this->files[$this->currentFile];
|
||||||
|
|
||||||
|
// Got to the next file and recursively return the read value, or bail
|
||||||
|
// if no more data can be read.
|
||||||
|
if ($current->getContent()->eof()) {
|
||||||
|
return ++$this->currentFile == count($this->files)
|
||||||
|
? ''
|
||||||
|
: $this->readFile($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the start of a file, then send the headers to the read
|
||||||
|
// buffer.
|
||||||
|
if (!isset($this->bufferedHeaders[$this->currentFile])) {
|
||||||
|
$this->buffer = Stream\create($this->getFileHeaders($current));
|
||||||
|
$this->bufferedHeaders[$this->currentFile] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// More data needs to be read to meet the limit, so pull from the file
|
||||||
|
$content = $this->buffer ? $this->buffer->read($length) : '';
|
||||||
|
if (($remaining = $length - strlen($content)) > 0) {
|
||||||
|
$content .= $current->getContent()->read($remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFieldString($key)
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
"--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
|
||||||
|
$this->boundary,
|
||||||
|
$key,
|
||||||
|
$this->fields[$key]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFileHeaders(PostFileInterface $file)
|
||||||
|
{
|
||||||
|
$headers = '';
|
||||||
|
foreach ($file->getHeaders() as $key => $value) {
|
||||||
|
$headers .= "{$key}: {$value}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
282
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Post/PostBody.php
Normal file
282
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Post/PostBody.php
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Post;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Stream;
|
||||||
|
use GuzzleHttp\Query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds POST fields and files and creates a streaming body when read methods
|
||||||
|
* are called on the object.
|
||||||
|
*/
|
||||||
|
class PostBody implements PostBodyInterface
|
||||||
|
{
|
||||||
|
/** @var Stream\StreamInterface */
|
||||||
|
private $body;
|
||||||
|
|
||||||
|
/** @var callable */
|
||||||
|
private $aggregator;
|
||||||
|
|
||||||
|
private $fields = [];
|
||||||
|
|
||||||
|
/** @var PostFileInterface[] */
|
||||||
|
private $files = [];
|
||||||
|
private $forceMultipart = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies request headers to a request based on the POST state
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request to update
|
||||||
|
*/
|
||||||
|
public function applyRequestHeaders(RequestInterface $request)
|
||||||
|
{
|
||||||
|
if ($this->files || $this->forceMultipart) {
|
||||||
|
$request->setHeader(
|
||||||
|
'Content-Type',
|
||||||
|
'multipart/form-data; boundary=' . $this->getBody()->getBoundary()
|
||||||
|
);
|
||||||
|
} elseif ($this->fields) {
|
||||||
|
$request->setHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($size = $this->getSize()) {
|
||||||
|
$request->setHeader('Content-Length', $size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function forceMultipartUpload($force)
|
||||||
|
{
|
||||||
|
$this->forceMultipart = $force;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAggregator(callable $aggregator)
|
||||||
|
{
|
||||||
|
$this->aggregator = $aggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setField($name, $value)
|
||||||
|
{
|
||||||
|
$this->fields[$name] = $value;
|
||||||
|
$this->mutate();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replaceFields(array $fields)
|
||||||
|
{
|
||||||
|
$this->fields = $fields;
|
||||||
|
$this->mutate();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getField($name)
|
||||||
|
{
|
||||||
|
return isset($this->fields[$name]) ? $this->fields[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeField($name)
|
||||||
|
{
|
||||||
|
unset($this->fields[$name]);
|
||||||
|
$this->mutate();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFields($asString = false)
|
||||||
|
{
|
||||||
|
if (!$asString) {
|
||||||
|
return $this->fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) (new Query($this->fields))
|
||||||
|
->setEncodingType(Query::RFC1738)
|
||||||
|
->setAggregator($this->getAggregator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasField($name)
|
||||||
|
{
|
||||||
|
return isset($this->fields[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFile($name)
|
||||||
|
{
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
if ($file->getName() == $name) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFiles()
|
||||||
|
{
|
||||||
|
return $this->files;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFile(PostFileInterface $file)
|
||||||
|
{
|
||||||
|
$this->files[] = $file;
|
||||||
|
$this->mutate();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearFiles()
|
||||||
|
{
|
||||||
|
$this->files = [];
|
||||||
|
$this->mutate();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the numbers of fields + files
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return count($this->files) + count($this->fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return (string) $this->getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContents($maxLength = -1)
|
||||||
|
{
|
||||||
|
return $this->getBody()->getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
return $this->body ? $this->body->close() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detach()
|
||||||
|
{
|
||||||
|
$this->body = null;
|
||||||
|
$this->fields = $this->files = [];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eof()
|
||||||
|
{
|
||||||
|
return $this->getBody()->eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tell()
|
||||||
|
{
|
||||||
|
return $this->body ? $this->body->tell() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSeekable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isReadable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isWritable()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize()
|
||||||
|
{
|
||||||
|
return $this->getBody()->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function seek($offset, $whence = SEEK_SET)
|
||||||
|
{
|
||||||
|
return $this->getBody()->seek($offset, $whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read($length)
|
||||||
|
{
|
||||||
|
return $this->getBody()->read($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write($string)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a stream object that is built from the POST fields and files.
|
||||||
|
*
|
||||||
|
* If one has already been created, the previously created stream will be
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
private function getBody()
|
||||||
|
{
|
||||||
|
if ($this->body) {
|
||||||
|
return $this->body;
|
||||||
|
} elseif ($this->files || $this->forceMultipart) {
|
||||||
|
return $this->body = $this->createMultipart();
|
||||||
|
} elseif ($this->fields) {
|
||||||
|
return $this->body = $this->createUrlEncoded();
|
||||||
|
} else {
|
||||||
|
return $this->body = Stream\create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the aggregator used to join multi-valued field parameters
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
final protected function getAggregator()
|
||||||
|
{
|
||||||
|
if (!$this->aggregator) {
|
||||||
|
$this->aggregator = Query::phpAggregator();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->aggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a multipart/form-data body stream
|
||||||
|
*
|
||||||
|
* @return MultipartBody
|
||||||
|
*/
|
||||||
|
private function createMultipart()
|
||||||
|
{
|
||||||
|
// Flatten the nested query string values using the correct aggregator
|
||||||
|
$query = (string) (new Query($this->fields))
|
||||||
|
->setEncodingType(false)
|
||||||
|
->setAggregator($this->getAggregator());
|
||||||
|
// Convert the flattened query string back into an array
|
||||||
|
$fields = Query::fromString($query)->toArray();
|
||||||
|
|
||||||
|
return new MultipartBody($fields, $this->files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an application/x-www-form-urlencoded stream body
|
||||||
|
*
|
||||||
|
* @return Stream\StreamInterface
|
||||||
|
*/
|
||||||
|
private function createUrlEncoded()
|
||||||
|
{
|
||||||
|
return Stream\create($this->getFields(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get rid of any cached data
|
||||||
|
*/
|
||||||
|
private function mutate()
|
||||||
|
{
|
||||||
|
$this->body = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Post;
|
||||||
|
|
||||||
|
use GuzzleHttp\Message\RequestInterface;
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a POST body that is sent as either a multipart/form-data stream
|
||||||
|
* or application/x-www-urlencoded stream.
|
||||||
|
*/
|
||||||
|
interface PostBodyInterface extends StreamInterface, \Countable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Apply headers to the request appropriate for the current state of the object
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request Request
|
||||||
|
*/
|
||||||
|
public function applyRequestHeaders(RequestInterface $request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific field
|
||||||
|
*
|
||||||
|
* @param string $name Name of the field to set
|
||||||
|
* @param string|array $value Value to set
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setField($name, $value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the aggregation strategy that will be used to turn multi-valued
|
||||||
|
* fields into a string.
|
||||||
|
*
|
||||||
|
* The aggregation function accepts a deeply nested array of query string
|
||||||
|
* values and returns a flattened associative array of key value pairs.
|
||||||
|
*
|
||||||
|
* @param callable $aggregator
|
||||||
|
*/
|
||||||
|
public function setAggregator(callable $aggregator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true to force a multipart upload even if there are no files.
|
||||||
|
*
|
||||||
|
* @param bool $force Set to true to force multipart uploads or false to
|
||||||
|
* remove this flag.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function forceMultipartUpload($force);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace all existing form fields with an array of fields
|
||||||
|
*
|
||||||
|
* @param array $fields Associative array of fields to set
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function replaceFields(array $fields);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific field by name
|
||||||
|
*
|
||||||
|
* @param string $name Name of the POST field to retrieve
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getField($name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a field by name
|
||||||
|
*
|
||||||
|
* @param string $name Name of the field to remove
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function removeField($name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an associative array of names to values or a query string.
|
||||||
|
*
|
||||||
|
* @param bool $asString Set to true to retrieve the fields as a query
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* @return array|string
|
||||||
|
*/
|
||||||
|
public function getFields($asString = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a field is set
|
||||||
|
*
|
||||||
|
* @param string $name Name of the field to set
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasField($name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all of the files
|
||||||
|
*
|
||||||
|
* @return array Returns an array of PostFileInterface objects
|
||||||
|
*/
|
||||||
|
public function getFiles();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a POST file by name.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the POST file to retrieve
|
||||||
|
*
|
||||||
|
* @return PostFileInterface|null
|
||||||
|
*/
|
||||||
|
public function getFile($name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a file to the POST
|
||||||
|
*
|
||||||
|
* @param PostFileInterface $file File to add
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function addFile(PostFileInterface $file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all files from the collection
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function clearFiles();
|
||||||
|
}
|
||||||
138
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Post/PostFile.php
Normal file
138
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Post/PostFile.php
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Post;
|
||||||
|
|
||||||
|
use GuzzleHttp\Mimetypes;
|
||||||
|
use GuzzleHttp\Stream\MetadataStreamInterface;
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post file upload
|
||||||
|
*/
|
||||||
|
class PostFile implements PostFileInterface
|
||||||
|
{
|
||||||
|
private $name;
|
||||||
|
private $filename;
|
||||||
|
private $content;
|
||||||
|
private $headers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param null $name Name of the form field
|
||||||
|
* @param mixed $content Data to send
|
||||||
|
* @param null $filename Filename content-disposition attribute
|
||||||
|
* @param array $headers Array of headers to set on the file
|
||||||
|
* (can override any default headers)
|
||||||
|
* @throws \RuntimeException when filename is not passed or can't be determined
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$name,
|
||||||
|
$content,
|
||||||
|
$filename = null,
|
||||||
|
array $headers = []
|
||||||
|
) {
|
||||||
|
$this->headers = $headers;
|
||||||
|
$this->name = $name;
|
||||||
|
$this->prepareContent($content);
|
||||||
|
$this->prepareFilename($filename);
|
||||||
|
$this->prepareDefaultHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilename()
|
||||||
|
{
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaders()
|
||||||
|
{
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the contents of a POST file.
|
||||||
|
*
|
||||||
|
* @param mixed $content Content of the POST file
|
||||||
|
*/
|
||||||
|
private function prepareContent($content)
|
||||||
|
{
|
||||||
|
$this->content = $content;
|
||||||
|
|
||||||
|
if (!($this->content instanceof StreamInterface)) {
|
||||||
|
$this->content = \GuzzleHttp\Stream\create($this->content);
|
||||||
|
} elseif ($this->content instanceof MultipartBody) {
|
||||||
|
if (!$this->hasHeader('Content-Disposition')) {
|
||||||
|
$disposition = 'form-data; name="' . $this->name .'"';
|
||||||
|
$this->headers['Content-Disposition'] = $disposition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->hasHeader('Content-Type')) {
|
||||||
|
$this->headers['Content-Type'] = sprintf(
|
||||||
|
"multipart/form-data; boundary=%s",
|
||||||
|
$this->content->getBoundary()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a file name to the POST file based on various checks.
|
||||||
|
*
|
||||||
|
* @param string|null $filename Filename to apply (or null to guess)
|
||||||
|
*/
|
||||||
|
private function prepareFilename($filename)
|
||||||
|
{
|
||||||
|
$this->filename = $filename;
|
||||||
|
|
||||||
|
if (!$this->filename &&
|
||||||
|
$this->content instanceof MetadataStreamInterface
|
||||||
|
) {
|
||||||
|
$this->filename = $this->content->getMetadata('uri');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->filename || substr($this->filename, 0, 6) === 'php://') {
|
||||||
|
$this->filename = $this->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies default Content-Disposition and Content-Type headers if needed.
|
||||||
|
*/
|
||||||
|
private function prepareDefaultHeaders()
|
||||||
|
{
|
||||||
|
// Set a default content-disposition header if one was no provided
|
||||||
|
if (!$this->hasHeader('Content-Disposition')) {
|
||||||
|
$this->headers['Content-Disposition'] = sprintf(
|
||||||
|
'form-data; filename="%s"; name="%s"',
|
||||||
|
basename($this->filename),
|
||||||
|
$this->name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a default Content-Type if one was not supplied
|
||||||
|
if (!$this->hasHeader('Content-Type')) {
|
||||||
|
$this->headers['Content-Type'] = Mimetypes::getInstance()
|
||||||
|
->fromFilename($this->filename) ?: 'text/plain';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a specific header exists on the POST file by name.
|
||||||
|
*
|
||||||
|
* @param string $name Case-insensitive header to check
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function hasHeader($name)
|
||||||
|
{
|
||||||
|
return isset(array_change_key_case($this->headers)[strtolower($name)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Post;
|
||||||
|
|
||||||
|
use GuzzleHttp\Stream\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post file upload interface
|
||||||
|
*/
|
||||||
|
interface PostFileInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the name of the form field
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full path to the file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFilename();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content
|
||||||
|
*
|
||||||
|
* @return StreamInterface
|
||||||
|
*/
|
||||||
|
public function getContent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all POST file headers.
|
||||||
|
*
|
||||||
|
* The keys represent the header name as it will be sent over the wire, and
|
||||||
|
* each value is a string.
|
||||||
|
*
|
||||||
|
* @return array Returns an associative array of the file's headers.
|
||||||
|
*/
|
||||||
|
public function getHeaders();
|
||||||
|
}
|
||||||
226
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Query.php
Normal file
226
rainloop/v/0.0.0/app/libraries/GuzzleHttp/Query.php
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages query string variables and can aggregate them into a string
|
||||||
|
*/
|
||||||
|
class Query extends Collection
|
||||||
|
{
|
||||||
|
const RFC3986 = 'RFC3986';
|
||||||
|
const RFC1738 = 'RFC1738';
|
||||||
|
|
||||||
|
/** @var bool URL encode fields and values */
|
||||||
|
private $encoding = self::RFC3986;
|
||||||
|
|
||||||
|
/** @var callable */
|
||||||
|
private $aggregator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a query string into a Query object
|
||||||
|
*
|
||||||
|
* @param string $query Query string to parse
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function fromString($query)
|
||||||
|
{
|
||||||
|
$q = new static();
|
||||||
|
if ($query === '') {
|
||||||
|
return $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
$foundDuplicates = $foundPhpStyle = false;
|
||||||
|
|
||||||
|
foreach (explode('&', $query) as $kvp) {
|
||||||
|
$parts = explode('=', $kvp, 2);
|
||||||
|
$key = rawurldecode($parts[0]);
|
||||||
|
if ($paramIsPhpStyleArray = substr($key, -2) == '[]') {
|
||||||
|
$foundPhpStyle = true;
|
||||||
|
$key = substr($key, 0, -2);
|
||||||
|
}
|
||||||
|
if (isset($parts[1])) {
|
||||||
|
$value = rawurldecode(str_replace('+', '%20', $parts[1]));
|
||||||
|
if (isset($q[$key])) {
|
||||||
|
$q->add($key, $value);
|
||||||
|
$foundDuplicates = true;
|
||||||
|
} elseif ($paramIsPhpStyleArray) {
|
||||||
|
$q[$key] = array($value);
|
||||||
|
} else {
|
||||||
|
$q[$key] = $value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$q->add($key, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the duplicate aggregator if duplicates were found and not using
|
||||||
|
// PHP style arrays.
|
||||||
|
if ($foundDuplicates && !$foundPhpStyle) {
|
||||||
|
$q->setAggregator(self::duplicateAggregator());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the query string parameters to a query string string
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
if (!$this->data) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default aggregator is statically cached
|
||||||
|
static $defaultAggregator;
|
||||||
|
|
||||||
|
if (!$this->aggregator) {
|
||||||
|
if (!$defaultAggregator) {
|
||||||
|
$defaultAggregator = self::phpAggregator();
|
||||||
|
}
|
||||||
|
$this->aggregator = $defaultAggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = '';
|
||||||
|
$aggregator = $this->aggregator;
|
||||||
|
|
||||||
|
foreach ($aggregator($this->data) as $key => $values) {
|
||||||
|
foreach ($values as $value) {
|
||||||
|
if ($result) {
|
||||||
|
$result .= '&';
|
||||||
|
}
|
||||||
|
if ($this->encoding == self::RFC1738) {
|
||||||
|
$result .= urlencode($key);
|
||||||
|
if ($value !== null) {
|
||||||
|
$result .= '=' . urlencode($value);
|
||||||
|
}
|
||||||
|
} elseif ($this->encoding == self::RFC3986) {
|
||||||
|
$result .= rawurlencode($key);
|
||||||
|
if ($value !== null) {
|
||||||
|
$result .= '=' . rawurlencode($value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result .= $key;
|
||||||
|
if ($value !== null) {
|
||||||
|
$result .= '=' . $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls how multi-valued query string parameters are aggregated into a
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* $query->setAggregator($query::duplicateAggregator());
|
||||||
|
*
|
||||||
|
* @param callable $aggregator Callable used to convert a deeply nested
|
||||||
|
* array of query string variables into a flattened array of key value
|
||||||
|
* pairs. The callable accepts an array of query data and returns a
|
||||||
|
* flattened array of key value pairs where each value is an array of
|
||||||
|
* strings.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setAggregator(callable $aggregator)
|
||||||
|
{
|
||||||
|
$this->aggregator = $aggregator;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify how values are URL encoded
|
||||||
|
*
|
||||||
|
* @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setEncodingType($type)
|
||||||
|
{
|
||||||
|
if ($type === false || $type === self::RFC1738 || $type === self::RFC3986) {
|
||||||
|
$this->encoding = $type;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Invalid URL encoding type');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query string aggregator that does not aggregate nested query string
|
||||||
|
* values and allows duplicates in the resulting array.
|
||||||
|
*
|
||||||
|
* Example: http://test.com?q=1&q=2
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
public static function duplicateAggregator()
|
||||||
|
{
|
||||||
|
return function (array $data) {
|
||||||
|
return self::walkQuery($data, '', function ($key, $prefix) {
|
||||||
|
return is_int($key) ? $prefix : "{$prefix}[{$key}]";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregates nested query string variables using the same technique as
|
||||||
|
* ``http_build_query()``.
|
||||||
|
*
|
||||||
|
* @param bool $numericIndices Pass false to not include numeric indices
|
||||||
|
* when multi-values query string parameters are present.
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
public static function phpAggregator($numericIndices = true)
|
||||||
|
{
|
||||||
|
return function (array $data) use ($numericIndices) {
|
||||||
|
return self::walkQuery(
|
||||||
|
$data,
|
||||||
|
'',
|
||||||
|
function ($key, $prefix) use ($numericIndices) {
|
||||||
|
return !$numericIndices && is_int($key)
|
||||||
|
? "{$prefix}[]"
|
||||||
|
: "{$prefix}[{$key}]";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Easily create query aggregation functions by providing a key prefix
|
||||||
|
* function to this query string array walker.
|
||||||
|
*
|
||||||
|
* @param array $query Query string to walk
|
||||||
|
* @param string $keyPrefix Key prefix (start with '')
|
||||||
|
* @param callable $prefixer Function used to create a key prefix
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function walkQuery(array $query, $keyPrefix, callable $prefixer)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach ($query as $key => $value) {
|
||||||
|
if ($keyPrefix) {
|
||||||
|
$key = $prefixer($key, $keyPrefix);
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
$result += self::walkQuery($value, $key, $prefixer);
|
||||||
|
} elseif (isset($result[$key])) {
|
||||||
|
$result[$key][] = $value;
|
||||||
|
} else {
|
||||||
|
$result[$key] = array($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GuzzleHttp\Subscriber;
|
||||||
|
|
||||||
|
use GuzzleHttp\Event\RequestEvents;
|
||||||
|
use GuzzleHttp\Event\SubscriberInterface;
|
||||||
|
use GuzzleHttp\Event\CompleteEvent;
|
||||||
|
use GuzzleHttp\Event\BeforeEvent;
|
||||||
|
use GuzzleHttp\Cookie\CookieJar;
|
||||||
|
use GuzzleHttp\Cookie\CookieJarInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds, extracts, and persists cookies between HTTP requests
|
||||||
|
*/
|
||||||
|
class Cookie implements SubscriberInterface
|
||||||
|
{
|
||||||
|
/** @var CookieJarInterface */
|
||||||
|
private $cookieJar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CookieJarInterface $cookieJar Cookie jar used to hold cookies
|
||||||
|
*/
|
||||||
|
public function __construct(CookieJarInterface $cookieJar = null)
|
||||||
|
{
|
||||||
|
$this->cookieJar = $cookieJar ?: new CookieJar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEvents()
|
||||||
|
{
|
||||||
|
// Fire the cookie plugin complete event before redirecting
|
||||||
|
return [
|
||||||
|
'before' => ['onBefore'],
|
||||||
|
'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cookie cookieJar
|
||||||
|
*
|
||||||
|
* @return CookieJarInterface
|
||||||
|
*/
|
||||||
|
public function getCookieJar()
|
||||||
|
{
|
||||||
|
return $this->cookieJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBefore(BeforeEvent $event)
|
||||||
|
{
|
||||||
|
$this->cookieJar->addCookieHeader($event->getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onComplete(CompleteEvent $event)
|
||||||
|
{
|
||||||
|
$this->cookieJar->extractCookies(
|
||||||
|
$event->getRequest(),
|
||||||
|
$event->getResponse()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue