fix
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
include '../backend.php';
|
||||
|
||||
|
||||
define('COREGRADE_ACCOUNT_TESTEMAIL', 11001);
|
||||
define('COREGRADE_ACCOUNT_PENDING', 11010);
|
||||
define('COREGRADE_VERIFY_PENDING_LINK', 11015);
|
||||
define('COREGRADE_ACCOUNT_CREATEACC', 11020);
|
||||
define('COREGRADE_ACCOUNT_LOGIN', 11025);
|
||||
define('COREGRADE_ACCOUNT_ADDCARD', 11027);
|
||||
define('COREGRADE_ACCOUNT_ADDPAGECARD', 11029);
|
||||
global $coregrade;
|
||||
|
||||
$data = [];
|
||||
$data["action"] = COREGRADE_ACCOUNT_PENDING;
|
||||
$data['firstname'] = 'Olu';
|
||||
$data['lastname'] = 'Amey';
|
||||
$data['username'] = "ses66181+" . rand(100, 999) . "@gmail.com";
|
||||
//$data['username'] = "tokunbo.lawal1+".rand(1999,9999)."@gmail.com";
|
||||
$data['password'] = "12345678";
|
||||
$data['email'] = $data['username'];
|
||||
|
||||
$out = array();
|
||||
$ret = $coregrade->coregrade_api($data, $out);
|
||||
|
||||
//print_r($out)
|
||||
|
||||
/*
|
||||
if (true == $valid_entry) {
|
||||
if ($data['username'] != '' && $data['password'] != '') {
|
||||
$out = [];
|
||||
$this->coregrade_webapi(COREGRADE_ACCOUNT_PENDING, $data, $out);
|
||||
|
||||
|
||||
|
||||
|
||||
define('EMAIL_PENDING',1);
|
||||
define('EMAIL_SENT' ,5);
|
||||
|
||||
$db_host = $coregrade->cfgReadChar('database.host');
|
||||
$db_name = $coregrade->cfgReadChar('database.name');
|
||||
$db_user = $coregrade->cfgReadChar('database.user');
|
||||
$db_pass = $coregrade->cfgReadChar('database.pass');
|
||||
$db_port = $coregrade->cfgReadLong('database.port');
|
||||
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
|
||||
$conn = pg_connect($connstr);
|
||||
|
||||
define("FLOAT_SYSTEM_EMAIL_NOTIFICATION", 92027);
|
||||
|
||||
function Fextension_call($in, &$out) {
|
||||
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
|
||||
global $coregrade;
|
||||
|
||||
$ret = $out["retval"];
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
$coregrade = new coregrade_api_oameye\coregrade();
|
||||
|
||||
$USER = $_SERVER['SCRIPT_FILENAME'];
|
||||
$USER = str_replace('/home', '', $USER);
|
||||
$USER = strtok($USER, '/');
|
||||
if ($USER=='opt') $USER = 'root';
|
||||
// Load API class
|
||||
|
||||
|
||||
$coregrade_class = 'coregrade_api_' . $USER . '\\coregrade';
|
||||
if (!is_object($coregrade)) {
|
||||
$coregrade = new $coregrade_class();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
include '../backend.php';
|
||||
|
||||
|
||||
define('COREGRADE_ACCOUNT_TESTEMAIL', 11001);
|
||||
define('COREGRADE_ACCOUNT_PENDING', 11010);
|
||||
define('COREGRADE_VERIFY_PENDING_LINK', 11015);
|
||||
define('COREGRADE_ACCOUNT_CREATEACC', 11020);
|
||||
define('COREGRADE_ACCOUNT_LOGIN', 11025);
|
||||
define('COREGRADE_ACCOUNT_ADDCARD', 11027);
|
||||
define('COREGRADE_ACCOUNT_ADDPAGECARD', 11029);
|
||||
global $coregrade;
|
||||
|
||||
$data = [];
|
||||
$data["action"] = COREGRADE_ACCOUNT_PENDING;
|
||||
$data['firstname'] = 'Olu';
|
||||
$data['lastname'] = 'Amey';
|
||||
$data['username'] = "ses66181+" . rand(100, 999) . "@gmail.com";
|
||||
//$data['username'] = "tokunbo.lawal1+".rand(1999,9999)."@gmail.com";
|
||||
$data['password'] = "12345678";
|
||||
$data['email'] = $data['username'];
|
||||
|
||||
$out = array();
|
||||
$ret = $coregrade->coregrade_api($data, $out);
|
||||
|
||||
//print_r($out)
|
||||
|
||||
/*
|
||||
if (true == $valid_entry) {
|
||||
if ($data['username'] != '' && $data['password'] != '') {
|
||||
$out = [];
|
||||
$this->coregrade_webapi(COREGRADE_ACCOUNT_PENDING, $data, $out);
|
||||
|
||||
|
||||
|
||||
|
||||
define('EMAIL_PENDING',1);
|
||||
define('EMAIL_SENT' ,5);
|
||||
|
||||
$db_host = $coregrade->cfgReadChar('database.host');
|
||||
$db_name = $coregrade->cfgReadChar('database.name');
|
||||
$db_user = $coregrade->cfgReadChar('database.user');
|
||||
$db_pass = $coregrade->cfgReadChar('database.pass');
|
||||
$db_port = $coregrade->cfgReadLong('database.port');
|
||||
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
|
||||
$conn = pg_connect($connstr);
|
||||
|
||||
define("FLOAT_SYSTEM_EMAIL_NOTIFICATION", 92027);
|
||||
|
||||
function Fextension_call($in, &$out) {
|
||||
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
|
||||
global $coregrade;
|
||||
|
||||
$ret = $out["retval"];
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
$coregrade = new coregrade_api_oameye\coregrade();
|
||||
|
||||
$USER = $_SERVER['SCRIPT_FILENAME'];
|
||||
$USER = str_replace('/home', '', $USER);
|
||||
$USER = strtok($USER, '/');
|
||||
if ($USER=='opt') $USER = 'root';
|
||||
// Load API class
|
||||
|
||||
|
||||
$coregrade_class = 'coregrade_api_' . $USER . '\\coregrade';
|
||||
if (!is_object($coregrade)) {
|
||||
$coregrade = new $coregrade_class();
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
//index.php
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>How to Upload a File using Dropzone.js with PHP</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/dropzone.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/dropzone.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<br />
|
||||
<h3 align="center">How to Upload a File using Dropzone.js with PHP</h3>
|
||||
<br />
|
||||
|
||||
<form action="upload.php" class="dropzone" id="dropzoneFrom">
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
</form>
|
||||
<br />
|
||||
<br />
|
||||
<div align="center">
|
||||
<button type="button" class="btn btn-info" id="submit-all">Upload</button>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<div id="preview"></div>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script>
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
Dropzone.options.dropzoneFrom = {
|
||||
autoProcessQueue: false,
|
||||
acceptedFiles:".png,.jpg,.gif,.bmp,.jpeg",
|
||||
init: function(){
|
||||
var submitButton = document.querySelector('#submit-all');
|
||||
myDropzone = this;
|
||||
submitButton.addEventListener("click", function(){
|
||||
myDropzone.processQueue();
|
||||
});
|
||||
this.on("complete", function(){
|
||||
if(this.getQueuedFiles().length == 0 && this.getUploadingFiles().length == 0)
|
||||
{
|
||||
var _this = this;
|
||||
_this.removeAllFiles();
|
||||
}
|
||||
list_image();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
list_image();
|
||||
|
||||
function list_image()
|
||||
{
|
||||
$.ajax({
|
||||
url:"upload.php",
|
||||
success:function(data){
|
||||
$('#preview').html(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '.remove_image', function(){
|
||||
var name = $(this).attr('id');
|
||||
$.ajax({
|
||||
url:"upload.php",
|
||||
method:"POST",
|
||||
data:{name:name},
|
||||
success:function(data)
|
||||
{
|
||||
list_image();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
upload.php
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
//upload.php
|
||||
|
||||
$folder_name = 'upload/';
|
||||
|
||||
if(!empty($_FILES))
|
||||
{
|
||||
$temp_file = $_FILES['file']['tmp_name'];
|
||||
$location = $folder_name . $_FILES['file']['name'];
|
||||
move_uploaded_file($temp_file, $location);
|
||||
}
|
||||
|
||||
if(isset($_POST["name"]))
|
||||
{
|
||||
$filename = $folder_name.$_POST["name"];
|
||||
unlink($filename);
|
||||
}
|
||||
|
||||
$result = array();
|
||||
|
||||
$files = scandir('upload');
|
||||
|
||||
$output = '<div class="row">';
|
||||
|
||||
if(false !== $files)
|
||||
{
|
||||
foreach($files as $file)
|
||||
{
|
||||
if('.' != $file && '..' != $file)
|
||||
{
|
||||
$output .= '
|
||||
<div class="col-md-2">
|
||||
<img src="'.$folder_name.$file.'" class="img-thumbnail" width="175" height="175" style="height:175px;" />
|
||||
<button type="button" class="btn btn-link remove_image" id="'.$file.'">Remove</button>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
}
|
||||
$output .= '</div>';
|
||||
echo $output;
|
||||
|
||||
?>
|
||||
@@ -18,8 +18,7 @@ class Home extends Start_Controller {
|
||||
|
||||
$data = [];
|
||||
$this->viewHomePages("view_howitworks", $data);
|
||||
// $this->load->view('auth/view_howitworks', $data);
|
||||
|
||||
// $this->load->view('auth/view_howitworks', $data);
|
||||
}
|
||||
|
||||
public function privacy() {
|
||||
@@ -55,4 +54,16 @@ class Home extends Start_Controller {
|
||||
$this->load->view('auth/view_foot');
|
||||
}
|
||||
|
||||
public function school() {
|
||||
echo "Here School";
|
||||
}
|
||||
|
||||
public function myhome() {
|
||||
echo "Here MyHome";
|
||||
}
|
||||
|
||||
public function cp() {
|
||||
echo "Here CP";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -542,7 +542,7 @@ class Member extends Member_Controller {
|
||||
$this->db->query($q);
|
||||
echo "Room Added";
|
||||
} else {
|
||||
echo "All fields ar required";
|
||||
echo "All fields are required";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Revoke
|
||||
{
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(ClientInterface $http = null)
|
||||
{
|
||||
$this->http = $http;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
|
||||
* token, if a token isn't provided.
|
||||
*
|
||||
* @param string|array $token The token (access token or a refresh token) that should be revoked.
|
||||
* @return boolean Returns True if the revocation was successful, otherwise False.
|
||||
*/
|
||||
public function revokeToken($token)
|
||||
{
|
||||
if (is_array($token)) {
|
||||
if (isset($token['refresh_token'])) {
|
||||
$token = $token['refresh_token'];
|
||||
} else {
|
||||
$token = $token['access_token'];
|
||||
}
|
||||
}
|
||||
|
||||
$body = Psr7\stream_for(http_build_query(array('token' => $token)));
|
||||
$request = new Request(
|
||||
'POST',
|
||||
Google_Client::OAUTH2_REVOKE_URI,
|
||||
[
|
||||
'Cache-Control' => 'no-store',
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
],
|
||||
$body
|
||||
);
|
||||
|
||||
$httpHandler = HttpHandlerFactory::build($this->http);
|
||||
|
||||
$response = $httpHandler($request);
|
||||
|
||||
return $response->getStatusCode() == 200;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Firebase\JWT\ExpiredException as ExpiredExceptionV3;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Google\Auth\Cache\MemoryCacheItemPool;
|
||||
use Stash\Driver\FileSystem;
|
||||
use Stash\Pool;
|
||||
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Verify
|
||||
{
|
||||
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
|
||||
const OAUTH2_ISSUER = 'accounts.google.com';
|
||||
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
|
||||
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* @var Psr\Cache\CacheItemPoolInterface cache class
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(
|
||||
ClientInterface $http = null,
|
||||
CacheItemPoolInterface $cache = null,
|
||||
$jwt = null
|
||||
) {
|
||||
if (null === $http) {
|
||||
$http = new Client();
|
||||
}
|
||||
|
||||
if (null === $cache) {
|
||||
$cache = new MemoryCacheItemPool;
|
||||
}
|
||||
|
||||
$this->http = $http;
|
||||
$this->cache = $cache;
|
||||
$this->jwt = $jwt ?: $this->getJwtService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies an id token and returns the authenticated apiLoginTicket.
|
||||
* Throws an exception if the id token is not valid.
|
||||
* The audience parameter can be used to control which id tokens are
|
||||
* accepted. By default, the id token must have been issued to this OAuth2 client.
|
||||
*
|
||||
* @param $audience
|
||||
* @return array the token payload, if successful
|
||||
*/
|
||||
public function verifyIdToken($idToken, $audience = null)
|
||||
{
|
||||
if (empty($idToken)) {
|
||||
throw new LogicException('id_token cannot be null');
|
||||
}
|
||||
|
||||
// set phpseclib constants if applicable
|
||||
$this->setPhpsecConstants();
|
||||
|
||||
// Check signature
|
||||
$certs = $this->getFederatedSignOnCerts();
|
||||
foreach ($certs as $cert) {
|
||||
$bigIntClass = $this->getBigIntClass();
|
||||
$rsaClass = $this->getRsaClass();
|
||||
$modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
|
||||
$exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
|
||||
|
||||
$rsa = new $rsaClass();
|
||||
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
|
||||
|
||||
try {
|
||||
$payload = $this->jwt->decode(
|
||||
$idToken,
|
||||
$rsa->getPublicKey(),
|
||||
array('RS256')
|
||||
);
|
||||
|
||||
if (property_exists($payload, 'aud')) {
|
||||
if ($audience && $payload->aud != $audience) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// support HTTP and HTTPS issuers
|
||||
// @see https://developers.google.com/identity/sign-in/web/backend-auth
|
||||
$issuers = array(self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS);
|
||||
if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (array) $payload;
|
||||
} catch (ExpiredException $e) {
|
||||
return false;
|
||||
} catch (ExpiredExceptionV3 $e) {
|
||||
return false;
|
||||
} catch (SignatureInvalidException $e) {
|
||||
// continue
|
||||
} catch (DomainException $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getCache()
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and cache a certificates file.
|
||||
*
|
||||
* @param $url string location
|
||||
* @throws Google_Exception
|
||||
* @return array certificates
|
||||
*/
|
||||
private function retrieveCertsFromLocation($url)
|
||||
{
|
||||
// If we're retrieving a local file, just grab it.
|
||||
if (0 !== strpos($url, 'http')) {
|
||||
if (!$file = file_get_contents($url)) {
|
||||
throw new Google_Exception(
|
||||
"Failed to retrieve verification certificates: '" .
|
||||
$url . "'."
|
||||
);
|
||||
}
|
||||
|
||||
return json_decode($file, true);
|
||||
}
|
||||
|
||||
$response = $this->http->get($url);
|
||||
|
||||
if ($response->getStatusCode() == 200) {
|
||||
return json_decode((string) $response->getBody(), true);
|
||||
}
|
||||
throw new Google_Exception(
|
||||
sprintf(
|
||||
'Failed to retrieve verification certificates: "%s".',
|
||||
$response->getBody()->getContents()
|
||||
),
|
||||
$response->getStatusCode()
|
||||
);
|
||||
}
|
||||
|
||||
// Gets federated sign-on certificates to use for verifying identity tokens.
|
||||
// Returns certs as array structure, where keys are key ids, and values
|
||||
// are PEM encoded certificates.
|
||||
private function getFederatedSignOnCerts()
|
||||
{
|
||||
$certs = null;
|
||||
if ($cache = $this->getCache()) {
|
||||
$cacheItem = $cache->getItem('federated_signon_certs_v3');
|
||||
$certs = $cacheItem->get();
|
||||
}
|
||||
|
||||
|
||||
if (!$certs) {
|
||||
$certs = $this->retrieveCertsFromLocation(
|
||||
self::FEDERATED_SIGNON_CERT_URL
|
||||
);
|
||||
|
||||
if ($cache) {
|
||||
$cacheItem->expiresAt(new DateTime('+1 hour'));
|
||||
$cacheItem->set($certs);
|
||||
$cache->save($cacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($certs['keys'])) {
|
||||
throw new InvalidArgumentException(
|
||||
'federated sign-on certs expects "keys" to be set'
|
||||
);
|
||||
}
|
||||
|
||||
return $certs['keys'];
|
||||
}
|
||||
|
||||
private function getJwtService()
|
||||
{
|
||||
$jwtClass = 'JWT';
|
||||
if (class_exists('\Firebase\JWT\JWT')) {
|
||||
$jwtClass = 'Firebase\JWT\JWT';
|
||||
}
|
||||
|
||||
if (property_exists($jwtClass, 'leeway') && $jwtClass::$leeway < 1) {
|
||||
// Ensures JWT leeway is at least 1
|
||||
// @see https://github.com/google/google-api-php-client/issues/827
|
||||
$jwtClass::$leeway = 1;
|
||||
}
|
||||
|
||||
return new $jwtClass;
|
||||
}
|
||||
|
||||
private function getRsaClass()
|
||||
{
|
||||
if (class_exists('phpseclib\Crypt\RSA')) {
|
||||
return 'phpseclib\Crypt\RSA';
|
||||
}
|
||||
|
||||
return 'Crypt_RSA';
|
||||
}
|
||||
|
||||
private function getBigIntClass()
|
||||
{
|
||||
if (class_exists('phpseclib\Math\BigInteger')) {
|
||||
return 'phpseclib\Math\BigInteger';
|
||||
}
|
||||
|
||||
return 'Math_BigInteger';
|
||||
}
|
||||
|
||||
private function getOpenSslConstant()
|
||||
{
|
||||
if (class_exists('phpseclib\Crypt\RSA')) {
|
||||
return 'phpseclib\Crypt\RSA::MODE_OPENSSL';
|
||||
}
|
||||
|
||||
if (class_exists('Crypt_RSA')) {
|
||||
return 'CRYPT_RSA_MODE_OPENSSL';
|
||||
}
|
||||
|
||||
throw new \Exception('Cannot find RSA class');
|
||||
}
|
||||
|
||||
/**
|
||||
* phpseclib calls "phpinfo" by default, which requires special
|
||||
* whitelisting in the AppEngine VM environment. This function
|
||||
* sets constants to bypass the need for phpseclib to check phpinfo
|
||||
*
|
||||
* @see phpseclib/Math/BigInteger
|
||||
* @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
|
||||
*/
|
||||
private function setPhpsecConstants()
|
||||
{
|
||||
if (filter_var(getenv('GAE_VM'), FILTER_VALIDATE_BOOLEAN)) {
|
||||
if (!defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
||||
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
||||
}
|
||||
if (!defined('CRYPT_RSA_MODE')) {
|
||||
define('CRYPT_RSA_MODE', constant($this->getOpenSslConstant()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
|
||||
class Google_AuthHandler_AuthHandlerFactory
|
||||
{
|
||||
/**
|
||||
* Builds out a default http handler for the installed version of guzzle.
|
||||
*
|
||||
* @return Google_AuthHandler_Guzzle5AuthHandler|Google_AuthHandler_Guzzle6AuthHandler
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function build($cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$version = ClientInterface::VERSION;
|
||||
|
||||
switch ($version[0]) {
|
||||
case '5':
|
||||
return new Google_AuthHandler_Guzzle5AuthHandler($cache, $cacheConfig);
|
||||
case '6':
|
||||
return new Google_AuthHandler_Guzzle6AuthHandler($cache, $cacheConfig);
|
||||
default:
|
||||
throw new Exception('Version not supported');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
use Google\Auth\CredentialsLoader;
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use Google\Auth\FetchAuthTokenCache;
|
||||
use Google\Auth\Subscriber\AuthTokenSubscriber;
|
||||
use Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
|
||||
use Google\Auth\Subscriber\SimpleSubscriber;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle5AuthHandler
|
||||
{
|
||||
protected $cache;
|
||||
protected $cacheConfig;
|
||||
|
||||
public function __construct(CacheItemPoolInterface $cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheConfig = $cacheConfig;
|
||||
}
|
||||
|
||||
public function attachCredentials(
|
||||
ClientInterface $http,
|
||||
CredentialsLoader $credentials,
|
||||
callable $tokenCallback = null
|
||||
) {
|
||||
// use the provided cache
|
||||
if ($this->cache) {
|
||||
$credentials = new FetchAuthTokenCache(
|
||||
$credentials,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
}
|
||||
// if we end up needing to make an HTTP request to retrieve credentials, we
|
||||
// can use our existing one, but we need to throw exceptions so the error
|
||||
// bubbles up.
|
||||
$authHttp = $this->createAuthHttp($http);
|
||||
$authHttpHandler = HttpHandlerFactory::build($authHttp);
|
||||
$subscriber = new AuthTokenSubscriber(
|
||||
$credentials,
|
||||
$authHttpHandler,
|
||||
$tokenCallback
|
||||
);
|
||||
|
||||
$http->setDefaultOption('auth', 'google_auth');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachToken(ClientInterface $http, array $token, array $scopes)
|
||||
{
|
||||
$tokenFunc = function ($scopes) use ($token) {
|
||||
return $token['access_token'];
|
||||
};
|
||||
|
||||
$subscriber = new ScopedAccessTokenSubscriber(
|
||||
$tokenFunc,
|
||||
$scopes,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
|
||||
$http->setDefaultOption('auth', 'scoped');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachKey(ClientInterface $http, $key)
|
||||
{
|
||||
$subscriber = new SimpleSubscriber(['key' => $key]);
|
||||
|
||||
$http->setDefaultOption('auth', 'simple');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
private function createAuthHttp(ClientInterface $http)
|
||||
{
|
||||
return new Client(
|
||||
[
|
||||
'base_url' => $http->getBaseUrl(),
|
||||
'defaults' => [
|
||||
'exceptions' => true,
|
||||
'verify' => $http->getDefaultOption('verify'),
|
||||
'proxy' => $http->getDefaultOption('proxy'),
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
use Google\Auth\CredentialsLoader;
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use Google\Auth\FetchAuthTokenCache;
|
||||
use Google\Auth\Middleware\AuthTokenMiddleware;
|
||||
use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
|
||||
use Google\Auth\Middleware\SimpleMiddleware;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle6AuthHandler
|
||||
{
|
||||
protected $cache;
|
||||
protected $cacheConfig;
|
||||
|
||||
public function __construct(CacheItemPoolInterface $cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheConfig = $cacheConfig;
|
||||
}
|
||||
|
||||
public function attachCredentials(
|
||||
ClientInterface $http,
|
||||
CredentialsLoader $credentials,
|
||||
callable $tokenCallback = null
|
||||
) {
|
||||
// use the provided cache
|
||||
if ($this->cache) {
|
||||
$credentials = new FetchAuthTokenCache(
|
||||
$credentials,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
}
|
||||
// if we end up needing to make an HTTP request to retrieve credentials, we
|
||||
// can use our existing one, but we need to throw exceptions so the error
|
||||
// bubbles up.
|
||||
$authHttp = $this->createAuthHttp($http);
|
||||
$authHttpHandler = HttpHandlerFactory::build($authHttp);
|
||||
$middleware = new AuthTokenMiddleware(
|
||||
$credentials,
|
||||
$authHttpHandler,
|
||||
$tokenCallback
|
||||
);
|
||||
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'google_auth';
|
||||
$http = new Client($config);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachToken(ClientInterface $http, array $token, array $scopes)
|
||||
{
|
||||
$tokenFunc = function ($scopes) use ($token) {
|
||||
return $token['access_token'];
|
||||
};
|
||||
|
||||
$middleware = new ScopedAccessTokenMiddleware(
|
||||
$tokenFunc,
|
||||
$scopes,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'scoped';
|
||||
$http = new Client($config);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachKey(ClientInterface $http, $key)
|
||||
{
|
||||
$middleware = new SimpleMiddleware(['key' => $key]);
|
||||
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'simple';
|
||||
$http = new Client($config);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
private function createAuthHttp(ClientInterface $http)
|
||||
{
|
||||
return new Client(
|
||||
[
|
||||
'base_uri' => $http->getConfig('base_uri'),
|
||||
'exceptions' => true,
|
||||
'verify' => $http->getConfig('verify'),
|
||||
'proxy' => $http->getConfig('proxy'),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
+1185
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
if (!class_exists('Google_Client')) {
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension to the regular Google_Model that automatically
|
||||
* exposes the items array for iteration, so you can just
|
||||
* iterate over the object rather than a reference inside.
|
||||
*/
|
||||
class Google_Collection extends Google_Model implements Iterator, Countable
|
||||
{
|
||||
protected $collection_key = 'items';
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
if (isset($this->{$this->collection_key})
|
||||
&& is_array($this->{$this->collection_key})) {
|
||||
reset($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
$this->coerceType($this->key());
|
||||
if (is_array($this->{$this->collection_key})) {
|
||||
return current($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
if (isset($this->{$this->collection_key})
|
||||
&& is_array($this->{$this->collection_key})) {
|
||||
return key($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
return next($this->{$this->collection_key});
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
$key = $this->key();
|
||||
return $key !== null && $key !== false;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
if (!isset($this->{$this->collection_key})) {
|
||||
return 0;
|
||||
}
|
||||
return count($this->{$this->collection_key});
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetExists($offset);
|
||||
}
|
||||
return isset($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetGet($offset);
|
||||
}
|
||||
$this->coerceType($offset);
|
||||
return $this->{$this->collection_key}[$offset];
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetSet($offset, $value);
|
||||
}
|
||||
$this->{$this->collection_key}[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetUnset($offset);
|
||||
}
|
||||
unset($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
|
||||
private function coerceType($offset)
|
||||
{
|
||||
$keyType = $this->keyType($this->collection_key);
|
||||
if ($keyType && !is_object($this->{$this->collection_key}[$offset])) {
|
||||
$this->{$this->collection_key}[$offset] =
|
||||
new $keyType($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Exception extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Class to handle batched requests to the Google API service.
|
||||
*
|
||||
* Note that calls to `Google_Http_Batch::execute()` do not clear the queued
|
||||
* requests. To start a new batch, be sure to create a new instance of this
|
||||
* class.
|
||||
*/
|
||||
class Google_Http_Batch
|
||||
{
|
||||
const BATCH_PATH = 'batch';
|
||||
|
||||
private static $CONNECTION_ESTABLISHED_HEADERS = array(
|
||||
"HTTP/1.0 200 Connection established\r\n\r\n",
|
||||
"HTTP/1.1 200 Connection established\r\n\r\n",
|
||||
);
|
||||
|
||||
/** @var string Multipart Boundary. */
|
||||
private $boundary;
|
||||
|
||||
/** @var array service requests to be executed. */
|
||||
private $requests = array();
|
||||
|
||||
/** @var Google_Client */
|
||||
private $client;
|
||||
|
||||
private $rootUrl;
|
||||
|
||||
private $batchPath;
|
||||
|
||||
public function __construct(
|
||||
Google_Client $client,
|
||||
$boundary = false,
|
||||
$rootUrl = null,
|
||||
$batchPath = null
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->boundary = $boundary ?: mt_rand();
|
||||
$this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
|
||||
$this->batchPath = $batchPath ?: self::BATCH_PATH;
|
||||
}
|
||||
|
||||
public function add(RequestInterface $request, $key = false)
|
||||
{
|
||||
if (false == $key) {
|
||||
$key = mt_rand();
|
||||
}
|
||||
|
||||
$this->requests[$key] = $request;
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$body = '';
|
||||
$classes = array();
|
||||
$batchHttpTemplate = <<<EOF
|
||||
--%s
|
||||
Content-Type: application/http
|
||||
Content-Transfer-Encoding: binary
|
||||
MIME-Version: 1.0
|
||||
Content-ID: %s
|
||||
|
||||
%s
|
||||
%s%s
|
||||
|
||||
|
||||
EOF;
|
||||
|
||||
/** @var Google_Http_Request $req */
|
||||
foreach ($this->requests as $key => $request) {
|
||||
$firstLine = sprintf(
|
||||
'%s %s HTTP/%s',
|
||||
$request->getMethod(),
|
||||
$request->getRequestTarget(),
|
||||
$request->getProtocolVersion()
|
||||
);
|
||||
|
||||
$content = (string) $request->getBody();
|
||||
|
||||
$headers = '';
|
||||
foreach ($request->getHeaders() as $name => $values) {
|
||||
$headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
|
||||
}
|
||||
|
||||
$body .= sprintf(
|
||||
$batchHttpTemplate,
|
||||
$this->boundary,
|
||||
$key,
|
||||
$firstLine,
|
||||
$headers,
|
||||
$content ? "\n".$content : ''
|
||||
);
|
||||
|
||||
$classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
|
||||
}
|
||||
|
||||
$body .= "--{$this->boundary}--";
|
||||
$body = trim($body);
|
||||
$url = $this->rootUrl . '/' . $this->batchPath;
|
||||
$headers = array(
|
||||
'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary),
|
||||
'Content-Length' => strlen($body),
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
'POST',
|
||||
$url,
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
|
||||
$response = $this->client->execute($request);
|
||||
|
||||
return $this->parseResponse($response, $classes);
|
||||
}
|
||||
|
||||
public function parseResponse(ResponseInterface $response, $classes = array())
|
||||
{
|
||||
$contentType = $response->getHeaderLine('content-type');
|
||||
$contentType = explode(';', $contentType);
|
||||
$boundary = false;
|
||||
foreach ($contentType as $part) {
|
||||
$part = explode('=', $part, 2);
|
||||
if (isset($part[0]) && 'boundary' == trim($part[0])) {
|
||||
$boundary = $part[1];
|
||||
}
|
||||
}
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
if (!empty($body)) {
|
||||
$body = str_replace("--$boundary--", "--$boundary", $body);
|
||||
$parts = explode("--$boundary", $body);
|
||||
$responses = array();
|
||||
$requests = array_values($this->requests);
|
||||
|
||||
foreach ($parts as $i => $part) {
|
||||
$part = trim($part);
|
||||
if (!empty($part)) {
|
||||
list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
|
||||
$headers = $this->parseRawHeaders($rawHeaders);
|
||||
|
||||
$status = substr($part, 0, strpos($part, "\n"));
|
||||
$status = explode(" ", $status);
|
||||
$status = $status[1];
|
||||
|
||||
list($partHeaders, $partBody) = $this->parseHttpResponse($part, false);
|
||||
$response = new Response(
|
||||
$status,
|
||||
$partHeaders,
|
||||
Psr7\stream_for($partBody)
|
||||
);
|
||||
|
||||
// Need content id.
|
||||
$key = $headers['content-id'];
|
||||
|
||||
try {
|
||||
$response = Google_Http_REST::decodeHttpResponse($response, $requests[$i-1]);
|
||||
} catch (Google_Service_Exception $e) {
|
||||
// Store the exception as the response, so successful responses
|
||||
// can be processed.
|
||||
$response = $e;
|
||||
}
|
||||
|
||||
$responses[$key] = $response;
|
||||
}
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function parseRawHeaders($rawHeaders)
|
||||
{
|
||||
$headers = array();
|
||||
$responseHeaderLines = explode("\r\n", $rawHeaders);
|
||||
foreach ($responseHeaderLines as $headerLine) {
|
||||
if ($headerLine && strpos($headerLine, ':') !== false) {
|
||||
list($header, $value) = explode(': ', $headerLine, 2);
|
||||
$header = strtolower($header);
|
||||
if (isset($headers[$header])) {
|
||||
$headers[$header] .= "\n" . $value;
|
||||
} else {
|
||||
$headers[$header] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the IO lib and also the batch processing.
|
||||
*
|
||||
* @param $respData
|
||||
* @param $headerSize
|
||||
* @return array
|
||||
*/
|
||||
private function parseHttpResponse($respData, $headerSize)
|
||||
{
|
||||
// check proxy header
|
||||
foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
|
||||
if (stripos($respData, $established_header) !== false) {
|
||||
// existed, remove it
|
||||
$respData = str_ireplace($established_header, '', $respData);
|
||||
// Subtract the proxy header size unless the cURL bug prior to 7.30.0
|
||||
// is present which prevented the proxy header size from being taken into
|
||||
// account.
|
||||
// @TODO look into this
|
||||
// if (!$this->needsQuirk()) {
|
||||
// $headerSize -= strlen($established_header);
|
||||
// }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($headerSize) {
|
||||
$responseBody = substr($respData, $headerSize);
|
||||
$responseHeaders = substr($respData, 0, $headerSize);
|
||||
} else {
|
||||
$responseSegments = explode("\r\n\r\n", $respData, 2);
|
||||
$responseHeaders = $responseSegments[0];
|
||||
$responseBody = isset($responseSegments[1]) ? $responseSegments[1] :
|
||||
null;
|
||||
}
|
||||
|
||||
$responseHeaders = $this->parseRawHeaders($responseHeaders);
|
||||
|
||||
return array($responseHeaders, $responseBody);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Manage large file uploads, which may be media but can be any type
|
||||
* of sizable data.
|
||||
*/
|
||||
class Google_Http_MediaFileUpload
|
||||
{
|
||||
const UPLOAD_MEDIA_TYPE = 'media';
|
||||
const UPLOAD_MULTIPART_TYPE = 'multipart';
|
||||
const UPLOAD_RESUMABLE_TYPE = 'resumable';
|
||||
|
||||
/** @var string $mimeType */
|
||||
private $mimeType;
|
||||
|
||||
/** @var string $data */
|
||||
private $data;
|
||||
|
||||
/** @var bool $resumable */
|
||||
private $resumable;
|
||||
|
||||
/** @var int $chunkSize */
|
||||
private $chunkSize;
|
||||
|
||||
/** @var int $size */
|
||||
private $size;
|
||||
|
||||
/** @var string $resumeUri */
|
||||
private $resumeUri;
|
||||
|
||||
/** @var int $progress */
|
||||
private $progress;
|
||||
|
||||
/** @var Google_Client */
|
||||
private $client;
|
||||
|
||||
/** @var Psr\Http\Message\RequestInterface */
|
||||
private $request;
|
||||
|
||||
/** @var string */
|
||||
private $boundary;
|
||||
|
||||
/**
|
||||
* Result code from last HTTP call
|
||||
* @var int
|
||||
*/
|
||||
private $httpResultCode;
|
||||
|
||||
/**
|
||||
* @param Google_Client $client
|
||||
* @param RequestInterface $request
|
||||
* @param string $mimeType
|
||||
* @param string $data The bytes you want to upload.
|
||||
* @param bool $resumable
|
||||
* @param bool $chunkSize File will be uploaded in chunks of this many bytes.
|
||||
* only used if resumable=True
|
||||
*/
|
||||
public function __construct(
|
||||
Google_Client $client,
|
||||
RequestInterface $request,
|
||||
$mimeType,
|
||||
$data,
|
||||
$resumable = false,
|
||||
$chunkSize = false
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->request = $request;
|
||||
$this->mimeType = $mimeType;
|
||||
$this->data = $data;
|
||||
$this->resumable = $resumable;
|
||||
$this->chunkSize = $chunkSize;
|
||||
$this->progress = 0;
|
||||
|
||||
$this->process();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the file that is being uploaded.
|
||||
* @param $size - int file size in bytes
|
||||
*/
|
||||
public function setFileSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the progress on the upload
|
||||
* @return int progress in bytes uploaded.
|
||||
*/
|
||||
public function getProgress()
|
||||
{
|
||||
return $this->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the next part of the file to upload.
|
||||
* @param [$chunk] the next set of bytes to send. If false will used $data passed
|
||||
* at construct time.
|
||||
*/
|
||||
public function nextChunk($chunk = false)
|
||||
{
|
||||
$resumeUri = $this->getResumeUri();
|
||||
|
||||
if (false == $chunk) {
|
||||
$chunk = substr($this->data, $this->progress, $this->chunkSize);
|
||||
}
|
||||
|
||||
$lastBytePos = $this->progress + strlen($chunk) - 1;
|
||||
$headers = array(
|
||||
'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
|
||||
'content-length' => strlen($chunk),
|
||||
'expect' => '',
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
'PUT',
|
||||
$resumeUri,
|
||||
$headers,
|
||||
Psr7\stream_for($chunk)
|
||||
);
|
||||
|
||||
return $this->makePutRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP result code from the last call made.
|
||||
* @return int code
|
||||
*/
|
||||
public function getHttpResultCode()
|
||||
{
|
||||
return $this->httpResultCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a PUT-Request to google drive and parses the response,
|
||||
* setting the appropiate variables from the response()
|
||||
*
|
||||
* @param Google_Http_Request $httpRequest the Reuqest which will be send
|
||||
*
|
||||
* @return false|mixed false when the upload is unfinished or the decoded http response
|
||||
*
|
||||
*/
|
||||
private function makePutRequest(RequestInterface $request)
|
||||
{
|
||||
$response = $this->client->execute($request);
|
||||
$this->httpResultCode = $response->getStatusCode();
|
||||
|
||||
if (308 == $this->httpResultCode) {
|
||||
// Track the amount uploaded.
|
||||
$range = $response->getHeaderLine('range');
|
||||
if ($range) {
|
||||
$range_array = explode('-', $range);
|
||||
$this->progress = $range_array[1] + 1;
|
||||
}
|
||||
|
||||
// Allow for changing upload URLs.
|
||||
$location = $response->getHeaderLine('location');
|
||||
if ($location) {
|
||||
$this->resumeUri = $location;
|
||||
}
|
||||
|
||||
// No problems, but upload not complete.
|
||||
return false;
|
||||
}
|
||||
|
||||
return Google_Http_REST::decodeHttpResponse($response, $this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a previously unfinished upload
|
||||
* @param $resumeUri the resume-URI of the unfinished, resumable upload.
|
||||
*/
|
||||
public function resume($resumeUri)
|
||||
{
|
||||
$this->resumeUri = $resumeUri;
|
||||
$headers = array(
|
||||
'content-range' => "bytes */$this->size",
|
||||
'content-length' => 0,
|
||||
);
|
||||
$httpRequest = new Request(
|
||||
'PUT',
|
||||
$this->resumeUri,
|
||||
$headers
|
||||
);
|
||||
|
||||
return $this->makePutRequest($httpRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Psr\Http\Message\RequestInterface $request
|
||||
* @visible for testing
|
||||
*/
|
||||
private function process()
|
||||
{
|
||||
$this->transformToUploadUrl();
|
||||
$request = $this->request;
|
||||
|
||||
$postBody = '';
|
||||
$contentType = false;
|
||||
|
||||
$meta = (string) $request->getBody();
|
||||
$meta = is_string($meta) ? json_decode($meta, true) : $meta;
|
||||
|
||||
$uploadType = $this->getUploadType($meta);
|
||||
$request = $request->withUri(
|
||||
Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType)
|
||||
);
|
||||
|
||||
$mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
|
||||
|
||||
if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = is_string($meta) ? $meta : json_encode($meta);
|
||||
} else if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = $this->data;
|
||||
} else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
|
||||
// This is a multipart/related upload.
|
||||
$boundary = $this->boundary ?: mt_rand();
|
||||
$boundary = str_replace('"', '', $boundary);
|
||||
$contentType = 'multipart/related; boundary=' . $boundary;
|
||||
$related = "--$boundary\r\n";
|
||||
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
|
||||
$related .= "\r\n" . json_encode($meta) . "\r\n";
|
||||
$related .= "--$boundary\r\n";
|
||||
$related .= "Content-Type: $mimeType\r\n";
|
||||
$related .= "Content-Transfer-Encoding: base64\r\n";
|
||||
$related .= "\r\n" . base64_encode($this->data) . "\r\n";
|
||||
$related .= "--$boundary--";
|
||||
$postBody = $related;
|
||||
}
|
||||
|
||||
$request = $request->withBody(Psr7\stream_for($postBody));
|
||||
|
||||
if (isset($contentType) && $contentType) {
|
||||
$request = $request->withHeader('content-type', $contentType);
|
||||
}
|
||||
|
||||
return $this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid upload types:
|
||||
* - resumable (UPLOAD_RESUMABLE_TYPE)
|
||||
* - media (UPLOAD_MEDIA_TYPE)
|
||||
* - multipart (UPLOAD_MULTIPART_TYPE)
|
||||
* @param $meta
|
||||
* @return string
|
||||
* @visible for testing
|
||||
*/
|
||||
public function getUploadType($meta)
|
||||
{
|
||||
if ($this->resumable) {
|
||||
return self::UPLOAD_RESUMABLE_TYPE;
|
||||
}
|
||||
|
||||
if (false == $meta && $this->data) {
|
||||
return self::UPLOAD_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
return self::UPLOAD_MULTIPART_TYPE;
|
||||
}
|
||||
|
||||
public function getResumeUri()
|
||||
{
|
||||
if (null === $this->resumeUri) {
|
||||
$this->resumeUri = $this->fetchResumeUri();
|
||||
}
|
||||
|
||||
return $this->resumeUri;
|
||||
}
|
||||
|
||||
private function fetchResumeUri()
|
||||
{
|
||||
$body = $this->request->getBody();
|
||||
if ($body) {
|
||||
$headers = array(
|
||||
'content-type' => 'application/json; charset=UTF-8',
|
||||
'content-length' => $body->getSize(),
|
||||
'x-upload-content-type' => $this->mimeType,
|
||||
'x-upload-content-length' => $this->size,
|
||||
'expect' => '',
|
||||
);
|
||||
foreach ($headers as $key => $value) {
|
||||
$this->request = $this->request->withHeader($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->client->execute($this->request, false);
|
||||
$location = $response->getHeaderLine('location');
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
if (200 == $code && true == $location) {
|
||||
return $location;
|
||||
}
|
||||
|
||||
$message = $code;
|
||||
$body = json_decode((string) $this->request->getBody(), true);
|
||||
if (isset($body['error']['errors'])) {
|
||||
$message .= ': ';
|
||||
foreach ($body['error']['errors'] as $error) {
|
||||
$message .= "{$error['domain']}, {$error['message']};";
|
||||
}
|
||||
$message = rtrim($message, ';');
|
||||
}
|
||||
|
||||
$error = "Failed to start the resumable upload (HTTP {$message})";
|
||||
$this->client->getLogger()->error($error);
|
||||
|
||||
throw new Google_Exception($error);
|
||||
}
|
||||
|
||||
private function transformToUploadUrl()
|
||||
{
|
||||
$parts = parse_url((string) $this->request->getUri());
|
||||
if (!isset($parts['path'])) {
|
||||
$parts['path'] = '';
|
||||
}
|
||||
$parts['path'] = '/upload' . $parts['path'];
|
||||
$uri = Uri::fromParts($parts);
|
||||
$this->request = $this->request->withUri($uri);
|
||||
}
|
||||
|
||||
public function setChunkSize($chunkSize)
|
||||
{
|
||||
$this->chunkSize = $chunkSize;
|
||||
}
|
||||
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This class implements the RESTful transport of apiServiceRequest()'s
|
||||
*/
|
||||
class Google_Http_REST
|
||||
{
|
||||
/**
|
||||
* Executes a Psr\Http\Message\RequestInterface and (if applicable) automatically retries
|
||||
* when errors occur.
|
||||
*
|
||||
* @param Google_Client $client
|
||||
* @param Psr\Http\Message\RequestInterface $req
|
||||
* @return array decoded result
|
||||
* @throws Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function execute(
|
||||
ClientInterface $client,
|
||||
RequestInterface $request,
|
||||
$expectedClass = null,
|
||||
$config = array(),
|
||||
$retryMap = null
|
||||
) {
|
||||
$runner = new Google_Task_Runner(
|
||||
$config,
|
||||
sprintf('%s %s', $request->getMethod(), (string) $request->getUri()),
|
||||
array(get_class(), 'doExecute'),
|
||||
array($client, $request, $expectedClass)
|
||||
);
|
||||
|
||||
if (null !== $retryMap) {
|
||||
$runner->setRetryMap($retryMap);
|
||||
}
|
||||
|
||||
return $runner->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a Psr\Http\Message\RequestInterface
|
||||
*
|
||||
* @param Google_Client $client
|
||||
* @param Psr\Http\Message\RequestInterface $request
|
||||
* @return array decoded result
|
||||
* @throws Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
|
||||
{
|
||||
try {
|
||||
$httpHandler = HttpHandlerFactory::build($client);
|
||||
$response = $httpHandler($request);
|
||||
} catch (RequestException $e) {
|
||||
// if Guzzle throws an exception, catch it and handle the response
|
||||
if (!$e->hasResponse()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$response = $e->getResponse();
|
||||
// specific checking for Guzzle 5: convert to PSR7 response
|
||||
if ($response instanceof \GuzzleHttp\Message\ResponseInterface) {
|
||||
$response = new Response(
|
||||
$response->getStatusCode(),
|
||||
$response->getHeaders() ?: [],
|
||||
$response->getBody(),
|
||||
$response->getProtocolVersion(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return self::decodeHttpResponse($response, $request, $expectedClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an HTTP Response.
|
||||
* @static
|
||||
* @throws Google_Service_Exception
|
||||
* @param Psr\Http\Message\RequestInterface $response The http response to be decoded.
|
||||
* @param Psr\Http\Message\ResponseInterface $response
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function decodeHttpResponse(
|
||||
ResponseInterface $response,
|
||||
RequestInterface $request = null,
|
||||
$expectedClass = null
|
||||
) {
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
// retry strategy
|
||||
if (intVal($code) >= 400) {
|
||||
// if we errored out, it should be safe to grab the response body
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
// Check if we received errors, and add those to the Exception for convenience
|
||||
throw new Google_Service_Exception($body, $code, null, self::getResponseErrors($body));
|
||||
}
|
||||
|
||||
// Ensure we only pull the entire body into memory if the request is not
|
||||
// of media type
|
||||
$body = self::decodeBody($response, $request);
|
||||
|
||||
if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
|
||||
$json = json_decode($body, true);
|
||||
|
||||
return new $expectedClass($json);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
|
||||
{
|
||||
if (self::isAltMedia($request)) {
|
||||
// don't decode the body, it's probably a really long string
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $response->getBody();
|
||||
}
|
||||
|
||||
private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
|
||||
{
|
||||
// "false" is used to explicitly prevent an expected class from being returned
|
||||
if (false === $expectedClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if we don't have a request, we just use what's passed in
|
||||
if (null === $request) {
|
||||
return $expectedClass;
|
||||
}
|
||||
|
||||
// return what we have in the request header if one was not supplied
|
||||
return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
|
||||
}
|
||||
|
||||
private static function getResponseErrors($body)
|
||||
{
|
||||
$json = json_decode($body, true);
|
||||
|
||||
if (isset($json['error']['errors'])) {
|
||||
return $json['error']['errors'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function isAltMedia(RequestInterface $request = null)
|
||||
{
|
||||
if ($request && $qs = $request->getUri()->getQuery()) {
|
||||
parse_str($qs, $query);
|
||||
if (isset($query['alt']) && $query['alt'] == 'media') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines attributes, valid values, and usage which is generated
|
||||
* from a given json schema.
|
||||
* http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
|
||||
*
|
||||
*/
|
||||
class Google_Model implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* If you need to specify a NULL JSON value, use Google_Model::NULL_VALUE
|
||||
* instead - it will be replaced when converting to JSON with a real null.
|
||||
*/
|
||||
const NULL_VALUE = "{}gapi-php-null";
|
||||
protected $internal_gapi_mappings = array();
|
||||
protected $modelData = array();
|
||||
protected $processed = array();
|
||||
|
||||
/**
|
||||
* Polymorphic - accepts a variable number of arguments dependent
|
||||
* on the type of the model subclass.
|
||||
*/
|
||||
final public function __construct()
|
||||
{
|
||||
if (func_num_args() == 1 && is_array(func_get_arg(0))) {
|
||||
// Initialize the model with the array's contents.
|
||||
$array = func_get_arg(0);
|
||||
$this->mapTypes($array);
|
||||
}
|
||||
$this->gapiInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter that handles passthrough access to the data array, and lazy object creation.
|
||||
* @param string $key Property name.
|
||||
* @return mixed The value if any, or null.
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
$keyType = $this->keyType($key);
|
||||
$keyDataType = $this->dataType($key);
|
||||
if ($keyType && !isset($this->processed[$key])) {
|
||||
if (isset($this->modelData[$key])) {
|
||||
$val = $this->modelData[$key];
|
||||
} elseif ($keyDataType == 'array' || $keyDataType == 'map') {
|
||||
$val = array();
|
||||
} else {
|
||||
$val = null;
|
||||
}
|
||||
|
||||
if ($this->isAssociativeArray($val)) {
|
||||
if ($keyDataType && 'map' == $keyDataType) {
|
||||
foreach ($val as $arrayKey => $arrayItem) {
|
||||
$this->modelData[$key][$arrayKey] =
|
||||
new $keyType($arrayItem);
|
||||
}
|
||||
} else {
|
||||
$this->modelData[$key] = new $keyType($val);
|
||||
}
|
||||
} else if (is_array($val)) {
|
||||
$arrayObject = array();
|
||||
foreach ($val as $arrayIndex => $arrayItem) {
|
||||
$arrayObject[$arrayIndex] = new $keyType($arrayItem);
|
||||
}
|
||||
$this->modelData[$key] = $arrayObject;
|
||||
}
|
||||
$this->processed[$key] = true;
|
||||
}
|
||||
|
||||
return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this object's properties from an array.
|
||||
*
|
||||
* @param array $array Used to seed this object's properties.
|
||||
* @return void
|
||||
*/
|
||||
protected function mapTypes($array)
|
||||
{
|
||||
// Hard initialise simple types, lazy load more complex ones.
|
||||
foreach ($array as $key => $val) {
|
||||
if ($keyType = $this->keyType($key)) {
|
||||
$dataType = $this->dataType($key);
|
||||
if ($dataType == 'array' || $dataType == 'map') {
|
||||
$this->$key = array();
|
||||
foreach ($val as $itemKey => $itemVal) {
|
||||
if ($itemVal instanceof $keyType) {
|
||||
$this->{$key}[$itemKey] = $itemVal;
|
||||
} else {
|
||||
$this->{$key}[$itemKey] = new $keyType($itemVal);
|
||||
}
|
||||
}
|
||||
} elseif ($val instanceof $keyType) {
|
||||
$this->$key = $val;
|
||||
} else {
|
||||
$this->$key = new $keyType($val);
|
||||
}
|
||||
unset($array[$key]);
|
||||
} elseif (property_exists($this, $key)) {
|
||||
$this->$key = $val;
|
||||
unset($array[$key]);
|
||||
} elseif (property_exists($this, $camelKey = $this->camelCase($key))) {
|
||||
// This checks if property exists as camelCase, leaving it in array as snake_case
|
||||
// in case of backwards compatibility issues.
|
||||
$this->$camelKey = $val;
|
||||
}
|
||||
}
|
||||
$this->modelData = $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blank initialiser to be used in subclasses to do post-construction initialisation - this
|
||||
* avoids the need for subclasses to have to implement the variadics handling in their
|
||||
* constructors.
|
||||
*/
|
||||
protected function gapiInit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simplified object suitable for straightforward
|
||||
* conversion to JSON. This is relatively expensive
|
||||
* due to the usage of reflection, but shouldn't be called
|
||||
* a whole lot, and is the most straightforward way to filter.
|
||||
*/
|
||||
public function toSimpleObject()
|
||||
{
|
||||
$object = new stdClass();
|
||||
|
||||
// Process all other data.
|
||||
foreach ($this->modelData as $key => $val) {
|
||||
$result = $this->getSimpleValue($val);
|
||||
if ($result !== null) {
|
||||
$object->$key = $this->nullPlaceholderCheck($result);
|
||||
}
|
||||
}
|
||||
|
||||
// Process all public properties.
|
||||
$reflect = new ReflectionObject($this);
|
||||
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
|
||||
foreach ($props as $member) {
|
||||
$name = $member->getName();
|
||||
$result = $this->getSimpleValue($this->$name);
|
||||
if ($result !== null) {
|
||||
$name = $this->getMappedName($name);
|
||||
$object->$name = $this->nullPlaceholderCheck($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle different types of values, primarily
|
||||
* other objects and map and array data types.
|
||||
*/
|
||||
private function getSimpleValue($value)
|
||||
{
|
||||
if ($value instanceof Google_Model) {
|
||||
return $value->toSimpleObject();
|
||||
} else if (is_array($value)) {
|
||||
$return = array();
|
||||
foreach ($value as $key => $a_value) {
|
||||
$a_value = $this->getSimpleValue($a_value);
|
||||
if ($a_value !== null) {
|
||||
$key = $this->getMappedName($key);
|
||||
$return[$key] = $this->nullPlaceholderCheck($a_value);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the value is the null placeholder and return true null.
|
||||
*/
|
||||
private function nullPlaceholderCheck($value)
|
||||
{
|
||||
if ($value === self::NULL_VALUE) {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is an internal name mapping, use that.
|
||||
*/
|
||||
private function getMappedName($key)
|
||||
{
|
||||
if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
|
||||
$key = $this->internal_gapi_mappings[$key];
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if the array is associative.
|
||||
* @param array $array
|
||||
* @return bool True if the array is associative.
|
||||
*/
|
||||
protected function isAssociativeArray($array)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return false;
|
||||
}
|
||||
$keys = array_keys($array);
|
||||
foreach ($keys as $key) {
|
||||
if (is_string($key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if $obj is an array.
|
||||
* @throws Google_Exception Thrown if $obj isn't an array.
|
||||
* @param array $obj Items that should be validated.
|
||||
* @param string $method Method expecting an array as an argument.
|
||||
*/
|
||||
public function assertIsArray($obj, $method)
|
||||
{
|
||||
if ($obj && !is_array($obj)) {
|
||||
throw new Google_Exception(
|
||||
"Incorrect parameter type passed to $method(). Expected an array."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->$offset) || isset($this->modelData[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->$offset) ?
|
||||
$this->$offset :
|
||||
$this->__get($offset);
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (property_exists($this, $offset)) {
|
||||
$this->$offset = $value;
|
||||
} else {
|
||||
$this->modelData[$offset] = $value;
|
||||
$this->processed[$offset] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->modelData[$offset]);
|
||||
}
|
||||
|
||||
protected function keyType($key)
|
||||
{
|
||||
$keyType = $key . "Type";
|
||||
|
||||
// ensure keyType is a valid class
|
||||
if (property_exists($this, $keyType) && class_exists($this->$keyType)) {
|
||||
return $this->$keyType;
|
||||
}
|
||||
}
|
||||
|
||||
protected function dataType($key)
|
||||
{
|
||||
$dataType = $key . "DataType";
|
||||
|
||||
if (property_exists($this, $dataType)) {
|
||||
return $this->$dataType;
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset($key)
|
||||
{
|
||||
return isset($this->modelData[$key]);
|
||||
}
|
||||
|
||||
public function __unset($key)
|
||||
{
|
||||
unset($this->modelData[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to camelCase
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
private function camelCase($value)
|
||||
{
|
||||
$value = ucwords(str_replace(array('-', '_'), ' ', $value));
|
||||
$value = str_replace(' ', '', $value);
|
||||
$value[0] = strtolower($value[0]);
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Service
|
||||
{
|
||||
public $batchPath;
|
||||
public $rootUrl;
|
||||
public $version;
|
||||
public $servicePath;
|
||||
public $availableScopes;
|
||||
public $resource;
|
||||
private $client;
|
||||
|
||||
public function __construct(Google_Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated Google_Client class.
|
||||
* @return Google_Client
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HTTP Batch handler for this service
|
||||
*
|
||||
* @return Google_Http_Batch
|
||||
*/
|
||||
public function createBatch()
|
||||
{
|
||||
return new Google_Http_Batch(
|
||||
$this->client,
|
||||
false,
|
||||
$this->rootUrl,
|
||||
$this->batchPath
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Service_Exception extends Google_Exception
|
||||
{
|
||||
/**
|
||||
* Optional list of errors returned in a JSON body of an HTTP error response.
|
||||
*/
|
||||
protected $errors = array();
|
||||
|
||||
/**
|
||||
* Override default constructor to add the ability to set $errors and a retry
|
||||
* map.
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Exception|null $previous
|
||||
* @param [{string, string}] errors List of errors returned in an HTTP
|
||||
* response. Defaults to [].
|
||||
* @param array|null $retryMap Map of errors with retry counts.
|
||||
*/
|
||||
public function __construct(
|
||||
$message,
|
||||
$code = 0,
|
||||
Exception $previous = null,
|
||||
$errors = array()
|
||||
) {
|
||||
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
} else {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
$this->errors = $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* An example of the possible errors returned.
|
||||
*
|
||||
* {
|
||||
* "domain": "global",
|
||||
* "reason": "authError",
|
||||
* "message": "Invalid Credentials",
|
||||
* "locationType": "header",
|
||||
* "location": "Authorization",
|
||||
* }
|
||||
*
|
||||
* @return [{string, string}] List of errors return in an HTTP response or [].
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Google API Client Services
|
||||
|
||||
Google API Client Service classes have been moved to the
|
||||
[google-api-php-client-services](https://github.com/google/google-api-php-client-services)
|
||||
repository.
|
||||
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
/**
|
||||
* Implements the actual methods/resources of the discovered Google API using magic function
|
||||
* calling overloading (__call()), which on call will see if the method name (plus.activities.list)
|
||||
* is available in this service, and if so construct an apiHttpRequest representing it.
|
||||
*
|
||||
*/
|
||||
class Google_Service_Resource
|
||||
{
|
||||
// Valid query parameters that work, but don't appear in discovery.
|
||||
private $stackParameters = array(
|
||||
'alt' => array('type' => 'string', 'location' => 'query'),
|
||||
'fields' => array('type' => 'string', 'location' => 'query'),
|
||||
'trace' => array('type' => 'string', 'location' => 'query'),
|
||||
'userIp' => array('type' => 'string', 'location' => 'query'),
|
||||
'quotaUser' => array('type' => 'string', 'location' => 'query'),
|
||||
'data' => array('type' => 'string', 'location' => 'body'),
|
||||
'mimeType' => array('type' => 'string', 'location' => 'header'),
|
||||
'uploadType' => array('type' => 'string', 'location' => 'query'),
|
||||
'mediaUpload' => array('type' => 'complex', 'location' => 'query'),
|
||||
'prettyPrint' => array('type' => 'string', 'location' => 'query'),
|
||||
);
|
||||
|
||||
/** @var string $rootUrl */
|
||||
private $rootUrl;
|
||||
|
||||
/** @var Google_Client $client */
|
||||
private $client;
|
||||
|
||||
/** @var string $serviceName */
|
||||
private $serviceName;
|
||||
|
||||
/** @var string $servicePath */
|
||||
private $servicePath;
|
||||
|
||||
/** @var string $resourceName */
|
||||
private $resourceName;
|
||||
|
||||
/** @var array $methods */
|
||||
private $methods;
|
||||
|
||||
public function __construct($service, $serviceName, $resourceName, $resource)
|
||||
{
|
||||
$this->rootUrl = $service->rootUrl;
|
||||
$this->client = $service->getClient();
|
||||
$this->servicePath = $service->servicePath;
|
||||
$this->serviceName = $serviceName;
|
||||
$this->resourceName = $resourceName;
|
||||
$this->methods = is_array($resource) && isset($resource['methods']) ?
|
||||
$resource['methods'] :
|
||||
array($resourceName => $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This function needs simplifying.
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @param $expectedClass - optional, the expected class name
|
||||
* @return Google_Http_Request|expectedClass
|
||||
* @throws Google_Exception
|
||||
*/
|
||||
public function call($name, $arguments, $expectedClass = null)
|
||||
{
|
||||
if (! isset($this->methods[$name])) {
|
||||
$this->client->getLogger()->error(
|
||||
'Service method unknown',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name
|
||||
)
|
||||
);
|
||||
|
||||
throw new Google_Exception(
|
||||
"Unknown function: " .
|
||||
"{$this->serviceName}->{$this->resourceName}->{$name}()"
|
||||
);
|
||||
}
|
||||
$method = $this->methods[$name];
|
||||
$parameters = $arguments[0];
|
||||
|
||||
// postBody is a special case since it's not defined in the discovery
|
||||
// document as parameter, but we abuse the param entry for storing it.
|
||||
$postBody = null;
|
||||
if (isset($parameters['postBody'])) {
|
||||
if ($parameters['postBody'] instanceof Google_Model) {
|
||||
// In the cases the post body is an existing object, we want
|
||||
// to use the smart method to create a simple object for
|
||||
// for JSONification.
|
||||
$parameters['postBody'] = $parameters['postBody']->toSimpleObject();
|
||||
} else if (is_object($parameters['postBody'])) {
|
||||
// If the post body is another kind of object, we will try and
|
||||
// wrangle it into a sensible format.
|
||||
$parameters['postBody'] =
|
||||
$this->convertToArrayAndStripNulls($parameters['postBody']);
|
||||
}
|
||||
$postBody = (array) $parameters['postBody'];
|
||||
unset($parameters['postBody']);
|
||||
}
|
||||
|
||||
// TODO: optParams here probably should have been
|
||||
// handled already - this may well be redundant code.
|
||||
if (isset($parameters['optParams'])) {
|
||||
$optParams = $parameters['optParams'];
|
||||
unset($parameters['optParams']);
|
||||
$parameters = array_merge($parameters, $optParams);
|
||||
}
|
||||
|
||||
if (!isset($method['parameters'])) {
|
||||
$method['parameters'] = array();
|
||||
}
|
||||
|
||||
$method['parameters'] = array_merge(
|
||||
$this->stackParameters,
|
||||
$method['parameters']
|
||||
);
|
||||
|
||||
foreach ($parameters as $key => $val) {
|
||||
if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
|
||||
$this->client->getLogger()->error(
|
||||
'Service parameter unknown',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name,
|
||||
'parameter' => $key
|
||||
)
|
||||
);
|
||||
throw new Google_Exception("($name) unknown parameter: '$key'");
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($method['parameters'] as $paramName => $paramSpec) {
|
||||
if (isset($paramSpec['required']) &&
|
||||
$paramSpec['required'] &&
|
||||
! isset($parameters[$paramName])
|
||||
) {
|
||||
$this->client->getLogger()->error(
|
||||
'Service parameter missing',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name,
|
||||
'parameter' => $paramName
|
||||
)
|
||||
);
|
||||
throw new Google_Exception("($name) missing required param: '$paramName'");
|
||||
}
|
||||
if (isset($parameters[$paramName])) {
|
||||
$value = $parameters[$paramName];
|
||||
$parameters[$paramName] = $paramSpec;
|
||||
$parameters[$paramName]['value'] = $value;
|
||||
unset($parameters[$paramName]['required']);
|
||||
} else {
|
||||
// Ensure we don't pass nulls.
|
||||
unset($parameters[$paramName]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->client->getLogger()->info(
|
||||
'Service Call',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name,
|
||||
'arguments' => $parameters,
|
||||
)
|
||||
);
|
||||
|
||||
// build the service uri
|
||||
$url = $this->createRequestUri(
|
||||
$method['path'],
|
||||
$parameters
|
||||
);
|
||||
|
||||
// NOTE: because we're creating the request by hand,
|
||||
// and because the service has a rootUrl property
|
||||
// the "base_uri" of the Http Client is not accounted for
|
||||
$request = new Request(
|
||||
$method['httpMethod'],
|
||||
$url,
|
||||
['content-type' => 'application/json'],
|
||||
$postBody ? json_encode($postBody) : ''
|
||||
);
|
||||
|
||||
// support uploads
|
||||
if (isset($parameters['data'])) {
|
||||
$mimeType = isset($parameters['mimeType'])
|
||||
? $parameters['mimeType']['value']
|
||||
: 'application/octet-stream';
|
||||
$data = $parameters['data']['value'];
|
||||
$upload = new Google_Http_MediaFileUpload($this->client, $request, $mimeType, $data);
|
||||
|
||||
// pull down the modified request
|
||||
$request = $upload->getRequest();
|
||||
}
|
||||
|
||||
// if this is a media type, we will return the raw response
|
||||
// rather than using an expected class
|
||||
if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
|
||||
$expectedClass = null;
|
||||
}
|
||||
|
||||
// if the client is marked for deferring, rather than
|
||||
// execute the request, return the response
|
||||
if ($this->client->shouldDefer()) {
|
||||
// @TODO find a better way to do this
|
||||
$request = $request
|
||||
->withHeader('X-Php-Expected-Class', $expectedClass);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
return $this->client->execute($request, $expectedClass);
|
||||
}
|
||||
|
||||
protected function convertToArrayAndStripNulls($o)
|
||||
{
|
||||
$o = (array) $o;
|
||||
foreach ($o as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($o[$k]);
|
||||
} elseif (is_object($v) || is_array($v)) {
|
||||
$o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
|
||||
}
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse/expand request parameters and create a fully qualified
|
||||
* request uri.
|
||||
* @static
|
||||
* @param string $restPath
|
||||
* @param array $params
|
||||
* @return string $requestUrl
|
||||
*/
|
||||
public function createRequestUri($restPath, $params)
|
||||
{
|
||||
// Override the default servicePath address if the $restPath use a /
|
||||
if ('/' == substr($restPath, 0, 1)) {
|
||||
$requestUrl = substr($restPath, 1);
|
||||
} else {
|
||||
$requestUrl = $this->servicePath . $restPath;
|
||||
}
|
||||
|
||||
// code for leading slash
|
||||
if ($this->rootUrl) {
|
||||
if ('/' !== substr($this->rootUrl, -1) && '/' !== substr($requestUrl, 0, 1)) {
|
||||
$requestUrl = '/' . $requestUrl;
|
||||
}
|
||||
$requestUrl = $this->rootUrl . $requestUrl;
|
||||
}
|
||||
$uriTemplateVars = array();
|
||||
$queryVars = array();
|
||||
foreach ($params as $paramName => $paramSpec) {
|
||||
if ($paramSpec['type'] == 'boolean') {
|
||||
$paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
|
||||
}
|
||||
if ($paramSpec['location'] == 'path') {
|
||||
$uriTemplateVars[$paramName] = $paramSpec['value'];
|
||||
} else if ($paramSpec['location'] == 'query') {
|
||||
if (is_array($paramSpec['value'])) {
|
||||
foreach ($paramSpec['value'] as $value) {
|
||||
$queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value));
|
||||
}
|
||||
} else {
|
||||
$queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($uriTemplateVars)) {
|
||||
$uriTemplateParser = new Google_Utils_UriTemplate();
|
||||
$requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
|
||||
}
|
||||
|
||||
if (count($queryVars)) {
|
||||
$requestUrl .= '?' . implode('&', $queryVars);
|
||||
}
|
||||
|
||||
return $requestUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Task_Exception extends Google_Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for checking how many times a given task can be retried following
|
||||
* a failure.
|
||||
*/
|
||||
interface Google_Task_Retryable
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A task runner with exponential backoff support.
|
||||
*
|
||||
* @see https://developers.google.com/drive/web/handle-errors#implementing_exponential_backoff
|
||||
*/
|
||||
class Google_Task_Runner
|
||||
{
|
||||
const TASK_RETRY_NEVER = 0;
|
||||
const TASK_RETRY_ONCE = 1;
|
||||
const TASK_RETRY_ALWAYS = -1;
|
||||
|
||||
/**
|
||||
* @var integer $maxDelay The max time (in seconds) to wait before a retry.
|
||||
*/
|
||||
private $maxDelay = 60;
|
||||
/**
|
||||
* @var integer $delay The previous delay from which the next is calculated.
|
||||
*/
|
||||
private $delay = 1;
|
||||
|
||||
/**
|
||||
* @var integer $factor The base number for the exponential back off.
|
||||
*/
|
||||
private $factor = 2;
|
||||
/**
|
||||
* @var float $jitter A random number between -$jitter and $jitter will be
|
||||
* added to $factor on each iteration to allow for a better distribution of
|
||||
* retries.
|
||||
*/
|
||||
private $jitter = 0.5;
|
||||
|
||||
/**
|
||||
* @var integer $attempts The number of attempts that have been tried so far.
|
||||
*/
|
||||
private $attempts = 0;
|
||||
/**
|
||||
* @var integer $maxAttempts The max number of attempts allowed.
|
||||
*/
|
||||
private $maxAttempts = 1;
|
||||
|
||||
/**
|
||||
* @var callable $action The task to run and possibly retry.
|
||||
*/
|
||||
private $action;
|
||||
/**
|
||||
* @var array $arguments The task arguments.
|
||||
*/
|
||||
private $arguments;
|
||||
|
||||
/**
|
||||
* @var array $retryMap Map of errors with retry counts.
|
||||
*/
|
||||
protected $retryMap = [
|
||||
'500' => self::TASK_RETRY_ALWAYS,
|
||||
'503' => self::TASK_RETRY_ALWAYS,
|
||||
'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
|
||||
'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
|
||||
6 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_RESOLVE_HOST
|
||||
7 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_CONNECT
|
||||
28 => self::TASK_RETRY_ALWAYS, // CURLE_OPERATION_TIMEOUTED
|
||||
35 => self::TASK_RETRY_ALWAYS, // CURLE_SSL_CONNECT_ERROR
|
||||
52 => self::TASK_RETRY_ALWAYS // CURLE_GOT_NOTHING
|
||||
];
|
||||
|
||||
/**
|
||||
* Creates a new task runner with exponential backoff support.
|
||||
*
|
||||
* @param array $config The task runner config
|
||||
* @param string $name The name of the current task (used for logging)
|
||||
* @param callable $action The task to run and possibly retry
|
||||
* @param array $arguments The task arguments
|
||||
* @throws Google_Task_Exception when misconfigured
|
||||
*/
|
||||
public function __construct(
|
||||
$config,
|
||||
$name,
|
||||
$action,
|
||||
array $arguments = array()
|
||||
) {
|
||||
if (isset($config['initial_delay'])) {
|
||||
if ($config['initial_delay'] < 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `initial_delay` must not be negative.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->delay = $config['initial_delay'];
|
||||
}
|
||||
|
||||
if (isset($config['max_delay'])) {
|
||||
if ($config['max_delay'] <= 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `max_delay` must be greater than 0.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->maxDelay = $config['max_delay'];
|
||||
}
|
||||
|
||||
if (isset($config['factor'])) {
|
||||
if ($config['factor'] <= 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `factor` must be greater than 0.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->factor = $config['factor'];
|
||||
}
|
||||
|
||||
if (isset($config['jitter'])) {
|
||||
if ($config['jitter'] <= 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `jitter` must be greater than 0.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->jitter = $config['jitter'];
|
||||
}
|
||||
|
||||
if (isset($config['retries'])) {
|
||||
if ($config['retries'] < 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `retries` must not be negative.'
|
||||
);
|
||||
}
|
||||
$this->maxAttempts += $config['retries'];
|
||||
}
|
||||
|
||||
if (!is_callable($action)) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task argument `$action` must be a valid callable.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->action = $action;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a retry can be attempted.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canAttempt()
|
||||
{
|
||||
return $this->attempts < $this->maxAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the task and (if applicable) automatically retries when errors occur.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Google_Task_Retryable on failure when no retries are available.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
while ($this->attempt()) {
|
||||
try {
|
||||
return call_user_func_array($this->action, $this->arguments);
|
||||
} catch (Google_Service_Exception $exception) {
|
||||
$allowedRetries = $this->allowedRetries(
|
||||
$exception->getCode(),
|
||||
$exception->getErrors()
|
||||
);
|
||||
|
||||
if (!$this->canAttempt() || !$allowedRetries) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if ($allowedRetries > 0) {
|
||||
$this->maxAttempts = min(
|
||||
$this->maxAttempts,
|
||||
$this->attempts + $allowedRetries
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task once, if possible. This is useful for bypassing the `run()`
|
||||
* loop.
|
||||
*
|
||||
* NOTE: If this is not the first attempt, this function will sleep in
|
||||
* accordance to the backoff configurations before running the task.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function attempt()
|
||||
{
|
||||
if (!$this->canAttempt()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->attempts > 0) {
|
||||
$this->backOff();
|
||||
}
|
||||
|
||||
$this->attempts++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleeps in accordance to the backoff configurations.
|
||||
*/
|
||||
private function backOff()
|
||||
{
|
||||
$delay = $this->getDelay();
|
||||
|
||||
usleep($delay * 1000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the delay (in seconds) for the current backoff period.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getDelay()
|
||||
{
|
||||
$jitter = $this->getJitter();
|
||||
$factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter);
|
||||
|
||||
return $this->delay = min($this->maxDelay, $this->delay * $factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current jitter (random number between -$this->jitter and
|
||||
* $this->jitter).
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getJitter()
|
||||
{
|
||||
return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times the associated task can be retried.
|
||||
*
|
||||
* NOTE: -1 is returned if the task can be retried indefinitely
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function allowedRetries($code, $errors = array())
|
||||
{
|
||||
if (isset($this->retryMap[$code])) {
|
||||
return $this->retryMap[$code];
|
||||
}
|
||||
|
||||
if (
|
||||
!empty($errors) &&
|
||||
isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])
|
||||
) {
|
||||
return $this->retryMap[$errors[0]['reason']];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function setRetryMap($retryMap)
|
||||
{
|
||||
$this->retryMap = $retryMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of levels 1-3 of the URI Template spec.
|
||||
* @see http://tools.ietf.org/html/rfc6570
|
||||
*/
|
||||
class Google_Utils_UriTemplate
|
||||
{
|
||||
const TYPE_MAP = "1";
|
||||
const TYPE_LIST = "2";
|
||||
const TYPE_SCALAR = "4";
|
||||
|
||||
/**
|
||||
* @var $operators array
|
||||
* These are valid at the start of a template block to
|
||||
* modify the way in which the variables inside are
|
||||
* processed.
|
||||
*/
|
||||
private $operators = array(
|
||||
"+" => "reserved",
|
||||
"/" => "segments",
|
||||
"." => "dotprefix",
|
||||
"#" => "fragment",
|
||||
";" => "semicolon",
|
||||
"?" => "form",
|
||||
"&" => "continuation"
|
||||
);
|
||||
|
||||
/**
|
||||
* @var reserved array
|
||||
* These are the characters which should not be URL encoded in reserved
|
||||
* strings.
|
||||
*/
|
||||
private $reserved = array(
|
||||
"=", ",", "!", "@", "|", ":", "/", "?", "#",
|
||||
"[", "]",'$', "&", "'", "(", ")", "*", "+", ";"
|
||||
);
|
||||
private $reservedEncoded = array(
|
||||
"%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F",
|
||||
"%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29",
|
||||
"%2A", "%2B", "%3B"
|
||||
);
|
||||
|
||||
public function parse($string, array $parameters)
|
||||
{
|
||||
return $this->resolveNextSection($string, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function finds the first matching {...} block and
|
||||
* executes the replacement. It then calls itself to find
|
||||
* subsequent blocks, if any.
|
||||
*/
|
||||
private function resolveNextSection($string, $parameters)
|
||||
{
|
||||
$start = strpos($string, "{");
|
||||
if ($start === false) {
|
||||
return $string;
|
||||
}
|
||||
$end = strpos($string, "}");
|
||||
if ($end === false) {
|
||||
return $string;
|
||||
}
|
||||
$string = $this->replace($string, $start, $end, $parameters);
|
||||
return $this->resolveNextSection($string, $parameters);
|
||||
}
|
||||
|
||||
private function replace($string, $start, $end, $parameters)
|
||||
{
|
||||
// We know a data block will have {} round it, so we can strip that.
|
||||
$data = substr($string, $start + 1, $end - $start - 1);
|
||||
|
||||
// If the first character is one of the reserved operators, it effects
|
||||
// the processing of the stream.
|
||||
if (isset($this->operators[$data[0]])) {
|
||||
$op = $this->operators[$data[0]];
|
||||
$data = substr($data, 1);
|
||||
$prefix = "";
|
||||
$prefix_on_missing = false;
|
||||
|
||||
switch ($op) {
|
||||
case "reserved":
|
||||
// Reserved means certain characters should not be URL encoded
|
||||
$data = $this->replaceVars($data, $parameters, ",", null, true);
|
||||
break;
|
||||
case "fragment":
|
||||
// Comma separated with fragment prefix. Bare values only.
|
||||
$prefix = "#";
|
||||
$prefix_on_missing = true;
|
||||
$data = $this->replaceVars($data, $parameters, ",", null, true);
|
||||
break;
|
||||
case "segments":
|
||||
// Slash separated data. Bare values only.
|
||||
$prefix = "/";
|
||||
$data =$this->replaceVars($data, $parameters, "/");
|
||||
break;
|
||||
case "dotprefix":
|
||||
// Dot separated data. Bare values only.
|
||||
$prefix = ".";
|
||||
$prefix_on_missing = true;
|
||||
$data = $this->replaceVars($data, $parameters, ".");
|
||||
break;
|
||||
case "semicolon":
|
||||
// Semicolon prefixed and separated. Uses the key name
|
||||
$prefix = ";";
|
||||
$data = $this->replaceVars($data, $parameters, ";", "=", false, true, false);
|
||||
break;
|
||||
case "form":
|
||||
// Standard URL format. Uses the key name
|
||||
$prefix = "?";
|
||||
$data = $this->replaceVars($data, $parameters, "&", "=");
|
||||
break;
|
||||
case "continuation":
|
||||
// Standard URL, but with leading ampersand. Uses key name.
|
||||
$prefix = "&";
|
||||
$data = $this->replaceVars($data, $parameters, "&", "=");
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the initial prefix character if data is valid.
|
||||
if ($data || ($data !== false && $prefix_on_missing)) {
|
||||
$data = $prefix . $data;
|
||||
}
|
||||
|
||||
} else {
|
||||
// If no operator we replace with the defaults.
|
||||
$data = $this->replaceVars($data, $parameters);
|
||||
}
|
||||
// This is chops out the {...} and replaces with the new section.
|
||||
return substr($string, 0, $start) . $data . substr($string, $end + 1);
|
||||
}
|
||||
|
||||
private function replaceVars(
|
||||
$section,
|
||||
$parameters,
|
||||
$sep = ",",
|
||||
$combine = null,
|
||||
$reserved = false,
|
||||
$tag_empty = false,
|
||||
$combine_on_empty = true
|
||||
) {
|
||||
if (strpos($section, ",") === false) {
|
||||
// If we only have a single value, we can immediately process.
|
||||
return $this->combine(
|
||||
$section,
|
||||
$parameters,
|
||||
$sep,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
);
|
||||
} else {
|
||||
// If we have multiple values, we need to split and loop over them.
|
||||
// Each is treated individually, then glued together with the
|
||||
// separator character.
|
||||
$vars = explode(",", $section);
|
||||
return $this->combineList(
|
||||
$vars,
|
||||
$sep,
|
||||
$parameters,
|
||||
$combine,
|
||||
$reserved,
|
||||
false, // Never emit empty strings in multi-param replacements
|
||||
$combine_on_empty
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function combine(
|
||||
$key,
|
||||
$parameters,
|
||||
$sep,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
) {
|
||||
$length = false;
|
||||
$explode = false;
|
||||
$skip_final_combine = false;
|
||||
$value = false;
|
||||
|
||||
// Check for length restriction.
|
||||
if (strpos($key, ":") !== false) {
|
||||
list($key, $length) = explode(":", $key);
|
||||
}
|
||||
|
||||
// Check for explode parameter.
|
||||
if ($key[strlen($key) - 1] == "*") {
|
||||
$explode = true;
|
||||
$key = substr($key, 0, -1);
|
||||
$skip_final_combine = true;
|
||||
}
|
||||
|
||||
// Define the list separator.
|
||||
$list_sep = $explode ? $sep : ",";
|
||||
|
||||
if (isset($parameters[$key])) {
|
||||
$data_type = $this->getDataType($parameters[$key]);
|
||||
switch ($data_type) {
|
||||
case self::TYPE_SCALAR:
|
||||
$value = $this->getValue($parameters[$key], $length);
|
||||
break;
|
||||
case self::TYPE_LIST:
|
||||
$values = array();
|
||||
foreach ($parameters[$key] as $pkey => $pvalue) {
|
||||
$pvalue = $this->getValue($pvalue, $length);
|
||||
if ($combine && $explode) {
|
||||
$values[$pkey] = $key . $combine . $pvalue;
|
||||
} else {
|
||||
$values[$pkey] = $pvalue;
|
||||
}
|
||||
}
|
||||
$value = implode($list_sep, $values);
|
||||
if ($value == '') {
|
||||
return '';
|
||||
}
|
||||
break;
|
||||
case self::TYPE_MAP:
|
||||
$values = array();
|
||||
foreach ($parameters[$key] as $pkey => $pvalue) {
|
||||
$pvalue = $this->getValue($pvalue, $length);
|
||||
if ($explode) {
|
||||
$pkey = $this->getValue($pkey, $length);
|
||||
$values[] = $pkey . "=" . $pvalue; // Explode triggers = combine.
|
||||
} else {
|
||||
$values[] = $pkey;
|
||||
$values[] = $pvalue;
|
||||
}
|
||||
}
|
||||
$value = implode($list_sep, $values);
|
||||
if ($value == '') {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if ($tag_empty) {
|
||||
// If we are just indicating empty values with their key name, return that.
|
||||
return $key;
|
||||
} else {
|
||||
// Otherwise we can skip this variable due to not being defined.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($reserved) {
|
||||
$value = str_replace($this->reservedEncoded, $this->reserved, $value);
|
||||
}
|
||||
|
||||
// If we do not need to include the key name, we just return the raw
|
||||
// value.
|
||||
if (!$combine || $skip_final_combine) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Else we combine the key name: foo=bar, if value is not the empty string.
|
||||
return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of a passed in value
|
||||
*/
|
||||
private function getDataType($data)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
reset($data);
|
||||
if (key($data) !== 0) {
|
||||
return self::TYPE_MAP;
|
||||
}
|
||||
return self::TYPE_LIST;
|
||||
}
|
||||
return self::TYPE_SCALAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function that merges multiple combine calls
|
||||
* for multi-key templates.
|
||||
*/
|
||||
private function combineList(
|
||||
$vars,
|
||||
$sep,
|
||||
$parameters,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
) {
|
||||
$ret = array();
|
||||
foreach ($vars as $var) {
|
||||
$response = $this->combine(
|
||||
$var,
|
||||
$parameters,
|
||||
$sep,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
);
|
||||
if ($response === false) {
|
||||
continue;
|
||||
}
|
||||
$ret[] = $response;
|
||||
}
|
||||
return implode($sep, $ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to encode and trim values
|
||||
*/
|
||||
private function getValue($value, $length)
|
||||
{
|
||||
if ($length) {
|
||||
$value = substr($value, 0, $length);
|
||||
}
|
||||
$value = rawurlencode($value);
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* THIS FILE IS FOR BACKWARDS COMPATIBLITY ONLY
|
||||
*
|
||||
* If you were not already including this file in your project, please ignore it
|
||||
*/
|
||||
|
||||
$file = __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$exception = 'This library must be installed via composer or by downloading the full package.';
|
||||
$exception .= ' See the instructions at https://github.com/google/google-api-php-client#installation.';
|
||||
throw new Exception($exception);
|
||||
}
|
||||
|
||||
$error = 'google-api-php-client\'s autoloader was moved to vendor/autoload.php in 2.0.0. This ';
|
||||
$error .= 'redirect will be removed in 2.1. Please adjust your code to use the new location.';
|
||||
trigger_error($error, E_USER_DEPRECATED);
|
||||
|
||||
require_once $file;
|
||||
@@ -13,7 +13,7 @@
|
||||
<ul class="list-group list-group-flush" style="font-size:18px;">
|
||||
<li class="list-group-item">
|
||||
<span class="badge badge-pill bg-primary float-right">4</span>
|
||||
<a href="/member/configure">Add New CoreGrade Card</a>
|
||||
<a href="/member/configure">New Page</a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span class="badge badge-pill bg-info float-right">2</span>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*================================================================================
|
||||
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
|
||||
Version: 2.0
|
||||
Author: PIXINVENT
|
||||
Author URL: http://www.themeforest.net/user/pixinvent
|
||||
================================================================================
|
||||
|
||||
NOTE:
|
||||
------
|
||||
PLACE HERE YOUR OWN SCSS CODES AND IF NEEDED, OVERRIDE THE STYLES FROM THE OTHER STYLESHEETS.
|
||||
WE WILL RELEASE FUTURE UPDATES SO IN ORDER TO NOT OVERWRITE YOUR STYLES IT'S BETTER LIKE THIS. */
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"Dashboard": "Instrumententafel",
|
||||
"Analytics": "Analytics",
|
||||
"eCommerce": "eCommerce",
|
||||
"Apps": "Apps",
|
||||
"UI Elements": "UI Elemente",
|
||||
"Forms & Tables": "Formulare und Tabellen",
|
||||
"Pages": "Seiten",
|
||||
"Charts & Maps": "Karten & Landkarten",
|
||||
"Others": "Andere",
|
||||
"Email": "Email",
|
||||
"Chat": "Plaudern",
|
||||
"Todo": "Machen",
|
||||
"Calender": "Kalander",
|
||||
"Ecommerce": "E-Commerce",
|
||||
"Shop": "Geschäft",
|
||||
"Wish List": "Wunschzettel",
|
||||
"Checkout": "Auschecken",
|
||||
"Starter kit": "Starter-Kit",
|
||||
"1 column": "1 Spalte",
|
||||
"2 columns": "2 Spalten",
|
||||
"Fixed navbar": "Feste Navigationsleiste",
|
||||
"Floating navbar": "Schwimmende Navigationsleiste",
|
||||
"Fixed layout": "Festes Layout",
|
||||
"Static layout": "Statisches Layout",
|
||||
"Dark layout": "Dunkles Layout",
|
||||
"Light layout": "Helles Layout",
|
||||
"Data List": "Datenliste",
|
||||
"List View": "Listenansicht",
|
||||
"Thumb View": "Daumenansicht",
|
||||
"Content": "Inhalt",
|
||||
"Grid": "Gitter",
|
||||
"Typography": "Typografie",
|
||||
"Text Utilities": "Textdienstprogramme",
|
||||
"Syntax Highlighter": "Syntax Textmarker",
|
||||
"Helper Classes": "Hilfsklassen",
|
||||
"Colors": "Farben",
|
||||
"Icons": "Icons",
|
||||
"Feather": "Feder",
|
||||
"Font Awesome": "Guss Ehrfürchtig",
|
||||
"Cards": "Karte",
|
||||
"Basic": "Basic",
|
||||
"Advance": "Voraus",
|
||||
"Statistics": "Statistiken",
|
||||
"Card Actions": "Kartenaktionen",
|
||||
"Table": "Tabelle",
|
||||
"Datatable": "Datentabelle",
|
||||
"Components": "Komponenten",
|
||||
"Alerts": "Warnungen",
|
||||
"Buttons": "Tasten",
|
||||
"Breadcrumbs": "Semmelbrösel",
|
||||
"Carousel": "Karussell",
|
||||
"Collapse": "Zusammenbruch",
|
||||
"Dropdowns": "Dropdowns",
|
||||
"List Group": "Listengruppe",
|
||||
"Modals": "Modals",
|
||||
"Pagination": "Seitennummerierung",
|
||||
"Navs Component": "Navs-Komponente",
|
||||
"Navbar": "Navbar",
|
||||
"Tabs Component": "Registerkarten-Komponente",
|
||||
"Pills Component": "Pillenkomponente",
|
||||
"Tooltips": "Tooltips",
|
||||
"Popovers": "Popovers",
|
||||
"Badges": "Abzeichen",
|
||||
"Pill Badges": "Pillenabzeichen",
|
||||
"Progress": "Fortschritt",
|
||||
"Media Objects": "Medien objekte",
|
||||
"Spinner": "Spinner",
|
||||
"Toasts": "Toast",
|
||||
"Extra Components": "Zusätzliche Komponenten",
|
||||
"Avatar": "Benutzerbild",
|
||||
"Chips": "Chips",
|
||||
"Divider": "Teiler",
|
||||
"Form Elements": "Formularelemente",
|
||||
"Select": "Wählen",
|
||||
"Switch": "Schalter",
|
||||
"Checkbox": "Kontrollkästchen",
|
||||
"Radio": "Radio",
|
||||
"Input": "Eingang",
|
||||
"Input Groups": "Eingabegruppen",
|
||||
"Number Input": "Zahleneingabe",
|
||||
"Textarea": "Textarea",
|
||||
"Date & Time Picker": "Datums- und Uhrzeitauswahl",
|
||||
"Form Layout": "Formularlayout",
|
||||
"Form Wizard": "Formzauberer",
|
||||
"Form Validation": "Formularvalidierung",
|
||||
"Authentication": "Authentifizierung",
|
||||
"Login": "Anmeldung",
|
||||
"Register": "Registrieren",
|
||||
"Forgot Password": "Passwort vergessen",
|
||||
"Reset Password": "Passwort zurücksetzen",
|
||||
"Lock Screen": "Bildschirm sperren",
|
||||
"Coming Soon": "Demnächst",
|
||||
"Error": "Error",
|
||||
"404": "404",
|
||||
"500": "500",
|
||||
"Not Authorized": "Nicht berechtigt",
|
||||
"Maintenance": "Instandhaltung",
|
||||
"Profile": "Profil",
|
||||
"FAQ": "FAQ",
|
||||
"Knowledge Base": "Wissensbasis",
|
||||
"Search": "Suche",
|
||||
"Invoice": "Rechnung",
|
||||
"Charts": "Diagramme",
|
||||
"Apex": "Apex",
|
||||
"Chartjs": "Chartjs",
|
||||
"Echarts": "Echarts",
|
||||
"Google Maps": "Google Maps",
|
||||
"Sweet Alert": "Süßer Alarm",
|
||||
"Toastr": "Toastr",
|
||||
"NoUi Slider": "NoUi Slider",
|
||||
"File Uploader": "Datei-Uploader",
|
||||
"Quill Editor": "Quill Editor",
|
||||
"Drag & Drop": "Ziehen und loslassen",
|
||||
"Tour": "Tour",
|
||||
"Clipboard": "Zwischenablage",
|
||||
"Context Menu": "Kontextmenü",
|
||||
"l18n": "18n",
|
||||
"Menu Levels": "Menüebenen",
|
||||
"Second Level": "zweites Level",
|
||||
"Third Level": "Drittes Level",
|
||||
"Disabled Menu": "Deaktiviertes Menü",
|
||||
"Documentation": "Dokumentation",
|
||||
"Raise Support": "Unterstützung erhöhen",
|
||||
"Miscellaneous": "Sonstiges",
|
||||
"Extensions": "Erweiterungen",
|
||||
"Media Player": "Media Player",
|
||||
"agGrid Table": "agGrid Table",
|
||||
"User Settings": "Benutzereinstellungen"
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"Dashboard": "Dashboard",
|
||||
"Analytics": "Analytics",
|
||||
"eCommerce": "eCommerce",
|
||||
"Apps": "Apps",
|
||||
"UI Elements": "UI Elements",
|
||||
"Forms & Tables": "Forms & Tables",
|
||||
"Pages": "Pages",
|
||||
"Charts & Maps": "Charts & Maps",
|
||||
"Others": "Others",
|
||||
"Email": "Email",
|
||||
"Chat": "Chat",
|
||||
"Todo": "Todo",
|
||||
"Calender": "Calender",
|
||||
"Ecommerce": "Ecommerce",
|
||||
"Shop": "Shop",
|
||||
"Wish List": "Wish List",
|
||||
"Checkout": "Checkout",
|
||||
"Starter kit": "Starter kit",
|
||||
"1 column": "1 column",
|
||||
"2 columns": "2 columns",
|
||||
"Fixed navbar": "Fixed navbar",
|
||||
"Floating navbar": "Floating navbar",
|
||||
"Fixed layout": "Fixed layout",
|
||||
"Static layout": "Static layout",
|
||||
"Dark layout": "Dark layout",
|
||||
"Light layout": "Light layout",
|
||||
"Data List": "Data List",
|
||||
"List View": "List View",
|
||||
"Thumb View": "Thumb View",
|
||||
"Content": "Content",
|
||||
"Grid": "Grid",
|
||||
"Typography": "Typography",
|
||||
"Text Utilities": "Text Utilities",
|
||||
"Syntax Highlighter": "Syntax Highlighter",
|
||||
"Helper Classes": "Helper Classes",
|
||||
"Colors": "Colors",
|
||||
"Icons": "Icons",
|
||||
"Feather": "Feather",
|
||||
"Font Awesome": "Font Awesome",
|
||||
"Cards": "Cards",
|
||||
"Basic": "Basic",
|
||||
"Advance": "Advance",
|
||||
"Statistics": "Statistics",
|
||||
"Card Actions": "Card Actions",
|
||||
"Table": "Table",
|
||||
"Datatable": "Datatable",
|
||||
"Components": "Components",
|
||||
"Alerts": "Alerts",
|
||||
"Buttons": "Buttons",
|
||||
"Breadcrumbs": "Breadcrumbs",
|
||||
"Carousel": "Carousel",
|
||||
"Collapse": "Collapse",
|
||||
"Dropdowns": "Dropdowns",
|
||||
"List Group": "List Group",
|
||||
"Modals": "Modals",
|
||||
"Pagination": "Pagination",
|
||||
"Navs Component": "Navs Component",
|
||||
"Navbar": "Navbar",
|
||||
"Tabs Component": "Tabs Component",
|
||||
"Pills Component": "Pills Component",
|
||||
"Tooltips": "Tooltips",
|
||||
"Popovers": "Popovers",
|
||||
"Badges": "Badges",
|
||||
"Pill Badges": "Pill Badges",
|
||||
"Progress": "Progress",
|
||||
"Media Objects": "Media Objects",
|
||||
"Spinner": "Spinner",
|
||||
"Toasts": "Toasts",
|
||||
"Extra Components": "Extra Components",
|
||||
"Avatar": "Avatar",
|
||||
"Chips": "Chips",
|
||||
"Divider": "Divider",
|
||||
"Form Elements": "Form Elements",
|
||||
"Select": "Select",
|
||||
"Switch": "Switch",
|
||||
"Checkbox": "Checkbox",
|
||||
"Radio": "Radio",
|
||||
"Input": "Input",
|
||||
"Input Groups": "Input Groups",
|
||||
"Number Input": "Number Input",
|
||||
"Textarea": "Textarea",
|
||||
"Date & Time Picker": "Date & Time Picker",
|
||||
"Form Layout": "Form Layout",
|
||||
"Form Wizard": "Form Wizard",
|
||||
"Form Validation": "Form Validation",
|
||||
"Authentication": "Authentication",
|
||||
"Login": "Login",
|
||||
"Register": "Register",
|
||||
"Forgot Password": "Forgot Password",
|
||||
"Reset Password": "Reset Password",
|
||||
"Lock Screen": "Lock Screen",
|
||||
"Coming Soon": "Coming Soon",
|
||||
"Error": "Error",
|
||||
"404": "404",
|
||||
"500": "500",
|
||||
"Not Authorized": "Not Authorized",
|
||||
"Maintenance": "Maintenance",
|
||||
"Profile": "Profile",
|
||||
"FAQ": "FAQ",
|
||||
"Knowledge Base": "Knowledge Base",
|
||||
"Search": "Search",
|
||||
"Invoice": "Invoice",
|
||||
"Charts": "Charts",
|
||||
"Apex": "Apex",
|
||||
"Chartjs": "Chartjs",
|
||||
"Echarts": "Echarts",
|
||||
"Google Maps": "Google Maps",
|
||||
"Sweet Alert": "Sweet Alert",
|
||||
"Toastr": "Toastr",
|
||||
"NoUi Slider": "NoUi Slider",
|
||||
"File Uploader": "File Uploader",
|
||||
"Quill Editor": "Quill Editor",
|
||||
"Drag & Drop": "Drag & Drop",
|
||||
"Tour": "Tour",
|
||||
"Clipboard": "Clipboard",
|
||||
"Context Menu": "Context Menu",
|
||||
"l18n": "l18n",
|
||||
"Menu Levels": "Menu Levels",
|
||||
"Second Level": "Second Level",
|
||||
"Third Level": "Third Level",
|
||||
"Disabled Menu": "Disabled Menu",
|
||||
"Documentation": "Documentation",
|
||||
"Raise Support": "Raise Support",
|
||||
"Miscellaneous": "Miscellaneous",
|
||||
"Extensions": "Extensions",
|
||||
"Media Player": "Media Player",
|
||||
"agGrid Table": "agGrid Table",
|
||||
"User Settings": "User Settings"
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"Dashboard": "Tableau de bord",
|
||||
"Analytics": "Analytique",
|
||||
"eCommerce": "commerce électronique",
|
||||
"Apps": "Apps",
|
||||
"UI Elements": "Éléments d'interface utilisateur",
|
||||
"Forms & Tables": "Formulaires et tableaux",
|
||||
"Pages": "Des pages",
|
||||
"Charts & Maps": "Graphiques et cartes",
|
||||
"Others": "Autres",
|
||||
"Email": "Email",
|
||||
"Chat": "Bavarder",
|
||||
"Todo": "Faire",
|
||||
"Calender": "Calandre",
|
||||
"Ecommerce": "Commerce électronique",
|
||||
"Shop": "Boutique",
|
||||
"Wish List": "Liste de souhaits",
|
||||
"Checkout": "Check-out",
|
||||
"Starter kit": "Kit de démarrage",
|
||||
"1 column": "1 colonne",
|
||||
"2 columns": "2 colonnes",
|
||||
"Fixed navbar": "Barre de navigation fixe",
|
||||
"Floating navbar": "Barre de navigation flottante",
|
||||
"Fixed layout": "Mise en page fixe",
|
||||
"Static layout": "Disposition statique",
|
||||
"Dark layout": "Mise en page sombre",
|
||||
"Light layout": "Mise en lumière",
|
||||
"Data List": "Liste de données",
|
||||
"List View": "Voir la liste",
|
||||
"Thumb View": "Thumb View",
|
||||
"Content": "Contenu",
|
||||
"Grid": "la grille",
|
||||
"Typography": "Typographie",
|
||||
"Text Utilities": "Utilitaires de texte",
|
||||
"Syntax Highlighter": "Surligneur de syntaxe",
|
||||
"Helper Classes": "Classes d'assistance",
|
||||
"Colors": "Couleurs",
|
||||
"Icons": "Les icônes",
|
||||
"Feather": "Plume",
|
||||
"Font Awesome": "Police géniale",
|
||||
"Cards": "Carte",
|
||||
"Basic": "De base",
|
||||
"Advance": "Avance",
|
||||
"Statistics": "Statistiques",
|
||||
"Card Actions": "Actions de carte",
|
||||
"Table": "Table",
|
||||
"Datatable": "Datatable",
|
||||
"Components": "Composants",
|
||||
"Alerts": "Les alertes",
|
||||
"Buttons": "Boutons",
|
||||
"Breadcrumbs": "Chapelure",
|
||||
"Carousel": "Carrousel",
|
||||
"Collapse": "Effondrer",
|
||||
"Dropdowns": "Des listes déroulantes",
|
||||
"List Group": "Groupe de liste",
|
||||
"Modals": "Modaux",
|
||||
"Pagination": "Pagination",
|
||||
"Navs Component": "Composante navs",
|
||||
"Navbar": "Barre de navigation",
|
||||
"Tabs Component": "Composant Onglets",
|
||||
"Pills Component": "Composant pilules",
|
||||
"Tooltips": "Info-bulles",
|
||||
"Popovers": "popovers",
|
||||
"Badges": "Insignes",
|
||||
"Pill Badges": "Insignes de pilule",
|
||||
"Progress": "Le progrès",
|
||||
"Media Objects": "Objets multimédia",
|
||||
"Spinner": "Fileur",
|
||||
"Toasts": "Toasts",
|
||||
"Extra Components": "Composants Extra",
|
||||
"Avatar": "Avatar",
|
||||
"Chips": "chips",
|
||||
"Divider": "Diviseur",
|
||||
"Form Elements": "Éléments de formulaire",
|
||||
"Select": "Sélectionner",
|
||||
"Switch": "Commutateur",
|
||||
"Checkbox": "Case à cocher",
|
||||
"Radio": "Radio",
|
||||
"Input": "Contribution",
|
||||
"Input Groups": "Groupes d'entrées",
|
||||
"Number Input": "Nombre d'entrée",
|
||||
"Textarea": "Textarea",
|
||||
"Date & Time Picker": "Sélecteur de date et heure",
|
||||
"Form Layout": "Disposition de formulaire",
|
||||
"Form Wizard": "Assistant de formulaire",
|
||||
"Form Validation": "Validation du formulaire",
|
||||
"Authentication": "Authentification",
|
||||
"Login": "S'identifier",
|
||||
"Register": "registre",
|
||||
"Forgot Password": "Mot de passe oublié",
|
||||
"Reset Password": "réinitialiser le mot de passe",
|
||||
"Lock Screen": "Écran verrouillé",
|
||||
"Coming Soon": "Arrive bientôt",
|
||||
"Error": "Erreur",
|
||||
"404": "404",
|
||||
"500": "500",
|
||||
"Not Authorized": "Pas autorisé",
|
||||
"Maintenance": "Entretien",
|
||||
"Profile": "Profil",
|
||||
"FAQ": "FAQ",
|
||||
"Knowledge Base": "Base de connaissances",
|
||||
"Search": "Chercher",
|
||||
"Invoice": "Facture d'achat",
|
||||
"Charts": "Graphiques",
|
||||
"Apex": "Sommet",
|
||||
"Chartjs": "Chartjs",
|
||||
"Echarts": "Echarts",
|
||||
"Google Maps": "Google Maps",
|
||||
"Sweet Alert": "Douce alerte",
|
||||
"Toastr": "Toastr",
|
||||
"NoUi Slider": "NoUi Slider",
|
||||
"File Uploader": "Chargeur de fichiers",
|
||||
"Quill Editor": "Éditeur de piquants",
|
||||
"Drag & Drop": "Drag & Drop",
|
||||
"Tour": "Tour",
|
||||
"Clipboard": "Presse-papiers",
|
||||
"Context Menu": "Menu contextuel",
|
||||
"l18n": "l18n",
|
||||
"Menu Levels": "Niveaux de menu",
|
||||
"Second Level": "Deuxième niveau",
|
||||
"Third Level": "Troisième niveau",
|
||||
"Disabled Menu": "Menu désactivé",
|
||||
"Documentation": "Documentation",
|
||||
"Raise Support": "Augmenter le soutien",
|
||||
"Miscellaneous": "Divers",
|
||||
"Extensions": "Les extensions",
|
||||
"Media Player": "Lecteur multimédia",
|
||||
"agGrid Table": "agGrid Table",
|
||||
"User Settings": "Paramètres utilisateur"
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"Dashboard": "painel de controle",
|
||||
"Analytics": "Analytics",
|
||||
"eCommerce": "comércio eletrônico",
|
||||
"Apps": "Apps",
|
||||
"UI Elements": "Elementos da interface do usuário",
|
||||
"Forms & Tables": "Formas e tabelas",
|
||||
"Pages": "Páginas",
|
||||
"Charts & Maps": "pronounce Gráficos e Mapas",
|
||||
"Others": "Outras",
|
||||
"Email": "O email",
|
||||
"Chat": "Bate-papo",
|
||||
"Todo": "Façam",
|
||||
"Calender": "Calendário",
|
||||
"Ecommerce": "Comércio eletrônico",
|
||||
"Shop": "fazer compras",
|
||||
"Wish List": "Lista de Desejos",
|
||||
"Checkout": "Confira",
|
||||
"Starter kit": "Kit iniciante",
|
||||
"1 column": "1 coluna",
|
||||
"2 columns": "2 colunas",
|
||||
"Fixed navbar": "Navbar fixa",
|
||||
"Floating navbar": "Navbar flutuante",
|
||||
"Fixed layout": "Layout fixo",
|
||||
"Static layout": "Layout estático",
|
||||
"Dark layout": "Layout escuro",
|
||||
"Light layout": "Layout de luz",
|
||||
"Data List": "Lista de dados",
|
||||
"List View": "Exibição de lista",
|
||||
"Thumb View": "Thumb View",
|
||||
"Content": "Conteúdo",
|
||||
"Grid": "Grade",
|
||||
"Typography": "Tipografia",
|
||||
"Text Utilities": "Utilitários de texto",
|
||||
"Syntax Highlighter": "Marcador de sintaxe",
|
||||
"Helper Classes": "Classes Auxiliares",
|
||||
"Colors": "Cores",
|
||||
"Icons": "Ícones",
|
||||
"Feather": "Pena",
|
||||
"Font Awesome": "Fonte Incrível",
|
||||
"Cards": "Cartão",
|
||||
"Basic": "Basic",
|
||||
"Advance": "Avançar",
|
||||
"Statistics": "Estatisticas",
|
||||
"Card Actions": "Ações do Cartão",
|
||||
"Table": "Mesa",
|
||||
"Datatable": "Tabela de dados",
|
||||
"Components": "Componentes",
|
||||
"Alerts": "Alertas",
|
||||
"Buttons": "Botões",
|
||||
"Breadcrumbs": "Pão ralado",
|
||||
"Carousel": "Carrossel",
|
||||
"Collapse": "Colapso",
|
||||
"Dropdowns": "Dropdowns",
|
||||
"List Group": "Grupo de listas",
|
||||
"Modals": "Modais",
|
||||
"Pagination": "Paginação",
|
||||
"Navs Component": "Componente Navs",
|
||||
"Navbar": "Navbar",
|
||||
"Tabs Component": "Componente de guias",
|
||||
"Pills Component": "Componente de comprimidos",
|
||||
"Tooltips": "Dicas de ferramentas",
|
||||
"Popovers": "Popovers",
|
||||
"Badges": "Distintivos",
|
||||
"Pill Badges": "Emblemas de pílula",
|
||||
"Progress": "Progresso",
|
||||
"Media Objects": "Objetos de Mídia",
|
||||
"Spinner": "Girador",
|
||||
"Toasts": "Torradas",
|
||||
"Extra Components": "Componentes extras",
|
||||
"Avatar": "Avatar",
|
||||
"Chips": "Salgadinhos",
|
||||
"Divider": "Divisor",
|
||||
"Form Elements": "Elementos do formulário",
|
||||
"Select": "Selecione",
|
||||
"Switch": "Interruptor",
|
||||
"Checkbox": "Caixa de seleção",
|
||||
"Radio": "Rádio",
|
||||
"Input": "Entrada",
|
||||
"Input Groups": "Grupos de entrada",
|
||||
"Number Input": "Entrada numérica",
|
||||
"Textarea": "Textarea",
|
||||
"Date & Time Picker": "Selecionador de data e hora",
|
||||
"Form Layout": "Layout de formulário",
|
||||
"Form Wizard": "Assistente de Formulário",
|
||||
"Form Validation": "Validação de Formulário",
|
||||
"Authentication": "Autenticação",
|
||||
"Login": "Entrar",
|
||||
"Register": "registo",
|
||||
"Forgot Password": "Esqueceu a senha",
|
||||
"Reset Password": "Redefinir Senha",
|
||||
"Lock Screen": "Tela de bloqueio",
|
||||
"Coming Soon": "Em breve",
|
||||
"Error": "Erro",
|
||||
"404": "404",
|
||||
"500": "500",
|
||||
"Not Authorized": "Não autorizado",
|
||||
"Maintenance": "Manutenção",
|
||||
"Profile": "Perfil",
|
||||
"FAQ": "Perguntas frequentes",
|
||||
"Knowledge Base": "Base de Conhecimento",
|
||||
"Search": "Procurar",
|
||||
"Invoice": "Fatura",
|
||||
"Charts": "Gráficos",
|
||||
"Apex": "Ápice",
|
||||
"Chartjs": "Chartjs",
|
||||
"Echarts": "Echarts",
|
||||
"Google Maps": "Google Maps",
|
||||
"Sweet Alert": "Alerta doce",
|
||||
"Toastr": "Toastr",
|
||||
"NoUi Slider": "NoUi Slider",
|
||||
"File Uploader": "Uploader de arquivos",
|
||||
"Quill Editor": "Editor de pena",
|
||||
"Drag & Drop": "Arraste e solte",
|
||||
"Tour": "Tour",
|
||||
"Clipboard": "Prancheta",
|
||||
"Context Menu": "Menu contextual",
|
||||
"l18n": "l18n",
|
||||
"Menu Levels": "Níveis de Menu",
|
||||
"Second Level": "Segundo nível",
|
||||
"Third Level": "Terceiro nivel",
|
||||
"Disabled Menu": "Menu desativado",
|
||||
"Documentation": "Documentação",
|
||||
"Raise Support": "Levantar Suporte",
|
||||
"Miscellaneous": "Diversas",
|
||||
"Extensions": "Extensões",
|
||||
"Media Player": "Reprodutor de mídia",
|
||||
"agGrid Table": "agGrid Table",
|
||||
"User Settings": "Configurações do Usuário"
|
||||
}
|
||||
Binary file not shown.
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/uploads/
|
||||
Reference in New Issue
Block a user