This commit is contained in:
2020-05-16 13:43:36 -04:00
parent 4d782855f0
commit 4288365815
413 changed files with 424972 additions and 5 deletions
+78
View File
@@ -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();
}
}
+78
View File
@@ -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
View File
@@ -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;
?>
+13 -2
View File
@@ -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";
}
}
+1 -1
View File
@@ -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'),
]
);
}
}
File diff suppressed because it is too large Load Diff
+100
View File
@@ -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]);
}
}
}
+20
View File
@@ -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
{
}
+253
View File
@@ -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;
}
}
+182
View File
@@ -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
View File
@@ -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;
}
}
+56
View File
@@ -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
{
}
+281
View File
@@ -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;
}
}
+21
View File
@@ -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>
+11
View File
@@ -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. */
+130
View File
@@ -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"
}
+130
View File
@@ -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"
}
+130
View File
@@ -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"
}
+130
View File
@@ -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.
+1
View File
@@ -0,0 +1 @@
/home/uploads/