Save to local Google Datastore with PHP - php

The following code inserts an entity into the remote Google Datastore:
require_once('google-api-php-client/src/Google_Client.php');
require_once('google-api-php-client/src/contrib/Google_DatastoreService.php');
$client = new Google_Client();
$client -> setApplicationName("myApp");
$serviceAccount = 'myServiceAccount#developer.gserviceaccount.com';
$key = file_get_contents('super/secret/encryptedKey-privatekey.p12');
$client -> setAssertionCredentials(new Google_AssertionCredentials(
$serviceAccount,
array('https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/datastore'), $key));
$datastore = new Google_DatastoreService($client);
$path = new Google_KeyPathElement();
$path -> setName('testName');
$path -> setKind('testKind');
$key = new Google_Key();
$key -> setPath(array($path));
$entities = new Google_Entity();
$entities -> setKey($key);
$mutation = new Google_Mutation();
$mutation -> setInsert(array($entities));
$blindWrite = new Google_BlindWriteRequest();
$blindWrite -> setMutation($mutation);
$datastore -> datasets -> blindWrite('myApp', $blindWrite);
Now this is not really ideal for local development, so I changed the 'basePath' in google-api-php-client/src/config.php from
'basePath' => 'https://www.googleapis.com',
to
'basePath' => 'http://localhost:53290',
which is my API server according to the app launcher log.
Unfortunately, this does not work and any requests to the local API server result in the following error:
Fatal error: Uncaught exception 'Google_ServiceException' with message 'Error calling POST http://localhost:53290/datastore/v1beta1/datasets/myApp/blindWrite: (400) HTTP requires CRLF terminators' in ***\google-api-php-client\src\io\Google_REST.php:66
However, accessing http://localhost:53290 works and returns:
{app_id: dev~myApp, rtok: '0'}
Does anybody know what's causing this error? The request is exactly the same and I know that the local datastore is working in other languages.

Caveat: I have not developed in PHP on GAE, only in python and java.
According to this answer the PHP runtime currently cannot access the GAE-datastore; instead it uses Google Cloud Datastore which is accessed differently. (Just wanted to clarify this, since you tagged your question with gae-datastore)
AFIAK, the GAE development server does not support Google Cloud Datastore (which you are using via Google_DatastoreService.php). In order to simulate Google Cloud Datastore locally you will need to run the Google Cloud Datastore development server. -- However, if you can even use this depends on whether the PHP client uses their protocal buffer or their JSON API. Only the former is supported. See note on that page. So you might be stuck at this point.
Assuming you can use the local devserver:
I don't know what basepath in google-api-php/client/src/config.php is referring to and if changing it is the way to go when you are running the Google Cloud Datastore local devserver. The docs for the devserver state that you should modify the environment variables DATASTORE_HOST and DATASTORE_DATASET.
(BTW: I believe the API server entry in your app launcher log refers to Google Cloud Endpoints which aren't related to your problem.)

This is the easiest workaround if someone wants to use a different Cloud Datastore for development and production using PHP:
Create two applications:
myApp
myApp-dev
Activate the Datastore API for both applications. I was a little surprised but you can access a datastore from any application as long as you have the correct service-account-id and private key.
Implement a simple switch:
const DATASTORE_APP_NAME_PRODUCTION = 'myApp';
const DATASTORE_SERVICE_ACCOUNT_NAME_PRODUCTION =
'production-service-account-id#developer.gserviceaccount.com';
const DATASTORE_APP_NAME_DEVELOPMENT = 'myApp-dev';
const DATASTORE_SERVICE_ACCOUNT_NAME_DEVELOPMENT =
'dev-service-account-id#developer.gserviceaccount.com';
if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'],
'Google App Engine') !== false) {
$runMode = 'PRODUCTION';
} else {
$runMode = 'DEVELOPMENT';
}
Then do something like this when you want access the Cloud Datastore in your application:
$serviceAccount = constant('DATASTORE_SERVICE_ACCOUNT_NAME_'.$runMode);
$appName = constant('DATASTORE_APP_NAME_'.$runMode);
$key = file_get_contents('secret/path/'.$runMode.'-privatekey.p12');
$client -> setAssertionCredentials(
new Google_AssertionCredentials($serviceAccount,
array('https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/datastore'), $key));

I have recently created a library that can handle this: https://github.com/pwhelan/datachore. The actual magic is in: https://github.com/pwhelan/datachore/blob/master/src/Datastore/GoogleRemoteApi.php.
The code works just as well once it is deployed.

Related

GCE - Switch ON and OFF a VM from API request

I'm figuring out if there is a way to switch ON and OFF an instance on Google Compute Engine directly by API (hosted on app engine with PHP).
I've found this documentation:
https://cloud.google.com/compute/docs/reference/rest/v1/instances/start
But can't understand if this documentation is what really i need or not :/
EDIT:
$client = new Google_Client();
$client->setApplicationName('Google-ComputeSample/0.1');
$client->useApplicationDefaultCredentials();
$client->addScope('https://www.googleapis.com/auth/cloud-platform');
$service = new Google_Service_Compute($client);
// Project ID for this request.
$project = 'my-project';
// The name of the zone for this request.
$zone = 'europe-west3-c';
// Name of the instance resource to start.
$instance = 'name-instance';
$response = $service->instances->start($project, $zone, $instance);
print_r($response)
Get this error:
Uncaught exception 'DomainException' with message 'Could not load the default credentials. Browse to https://developers.google.com/accounts/docs/application-default-credentials for more information'
I'm trying to run this code from localhost, i think this is the problem.
If i run this code from an app engine inside my project, i suppose it will work.
But the google-php-client folder for the APIs has > 10000 files inside, so I can't push it on an app engine versione and try it :/
The document that you cite is correct for what you want to achieve, so using that API call you will start a VM instance and with the method instances.stop you will stop them. The examples for PHP are in the same document, to start [1] and to stop [2]. I hope this information helps.

How to create a credential (for google sheets) on GCE with php code?

I put my php code in GCE and wanna to modify google sheets.
Google told me that i don't have to apply a extra credential by using GCP>API because there's a strategy called Application Default Credentials (ADC) will find application's credentials.
I first check the environment variable "GOOGLE_APPLICATION_CREDENTIALS" in GCE server but it's empty.
Then i follow this tutorial https://cloud.google.com/docs/authentication/production?hl=zh_TW#auth-cloud-implicit-php and install this:
composer require google/cloud-storage
I tried the code under and got some error.
namespace Google\Cloud\Samples\Auth;
// Imports GCECredentials and the Cloud Storage client library.
use Google\Auth\Credentials\GCECredentials;
use Google\Cloud\Storage\StorageClient;
function auth_cloud_explicit_compute_engine($projectId)
{
$gceCredentials = new GCECredentials();
$config = [
'projectId' => $projectId,
'credentialsFetcher' => $gceCredentials,
];
$storage = new StorageClient($config);
# Make an authenticated API request (listing storage buckets)
foreach ($storage->buckets() as $bucket) {
printf('Bucket: %s' . PHP_EOL, $bucket->name());
}
}
PHP Fatal error: Uncaught Error: Class 'GCECredentials' not found in /var/www/html/google_sheets/t2.php:5
More question:
Will this code create a json file as credential for me to access google sheets?
$gceCredentials = new GCECredentials();
Or where can i find the service account key??
Please tell me what should i do, thanks a lot.

firebase storage and upload from php

I have a php application and from this i need upload images to google firebase storage. I had seen snippets that write to and read from realtime database but couldnt find any code that upload from php to firebase storage.
Any help will be much appreciated.
Tismon Varghese
You can get started by using their official documentation at
The storage documentation and An easier to use SDK within a Framework
You can explore the two for other information. So to get started on how I did mine. I was working on a laravel project though.
You have to install this package composer require kreait/firebase-php
Then also read the setup steps at Package Setup
$storage = app('firebase.storage'); // This is an instance of Google\Cloud\Storage\StorageClient from kreait/firebase-php library
$defaultBucket = $storage->getBucket();
$image = $request->file('image');
$name = (string) Str::uuid().".".$image->getClientOriginalExtension(); // use Illuminate\Support\Str;
$pathName = $image->getPathName();
$file = fopen($pathName, 'r');
$object = $defaultBucket->upload($file, [
'name' => $name,
'predefinedAcl' => 'publicRead'
]);
$image_url = 'https://storage.googleapis.com/'.env('FIREBASE_PROJECT_ID').'.appspot.com/'.$name;
I hope this helps.
We recommend using the Google API Client PHP library for this, as Firebase Storage is backed by Google Cloud Storage. Firebase Storage doesn't provide a PHP client for front end code though.
From the GCS PHP example code:
// composer autoloading
require_once __DIR__ . '/vendor/autoload.php';
// grab the first argument
if (empty($argv[1])) {
die("usage: php listBuckets [project_id]\n");
}
$projectId = $argv[1];
// Authenticate your API Client
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(Google_Service_Storage::DEVSTORAGE_FULL_CONTROL);
$storage = new Google_Service_Storage($client);
/**
* Google Cloud Storage API request to retrieve the list of buckets in your project.
*/
$buckets = $storage->buckets->listBuckets($projectId);
foreach ($buckets['items'] as $bucket) {
printf("%s\n", $bucket->getName());
}

Setup google-api-php-client to comunicate with custom google app engine API endpoint

I'm trying to configure the google-api-php-client library in my project.
I've already created a custom google app engine project that consists in a cloud endpoint. The project is called 'set-core', the service is called 'vrp API', version 'v1' and the method vrp.vrp.getSolution().
Now in my PHP code i'm following this example:
https://developers.google.com/api-client-library/php/start/get_started#building-and-calling-a-service
The problem is that in this example there's no mention how to connect to any custom service, outside Google's ones.
My PHP code is:
$client = new Google_Client();
$client->setApplicationName("set-core");
$client->setDeveloperKey("AIzaSyByd8cRJNGYC4szFLbr3**************");
$client->isAppEngine(true);
$service = new Google_Service_Appengine_Service($client);
$results = $service->vrp->vrp.vrp.getSolution($stringVehicles, $stringServices, $stringDepot);
Unfortunately, on the last line, PHP warns me:
Notice: Trying to get property of non-object (I assume it's $service).
The problem is that I don't really know how to set up all the client's params and which Service type use.
You are going to want to create an authorized HTTP client and then request your API endpoint directly with it. The AppEngine service classes you're manipulating above are not meant for this use case. Something like this should work:
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$httpClient = $client->authorize();
$response = $httpClient->request('GET', 'https://myapp.appspot.com/vrp/getSolution');
The $httpClient class is an instance of GuzzleHttp\Client, but with your Google authentication already added to it. See the documentation for making a request with Guzzle.
I hope this helps!

Google AppEngine + PHP + Google Cloud Datastore: receiving Unauthorized

I have a PHP application running at Google App Engine and I want to use the App Engine's datastore in it.
I am using the google-api-php-client, and at the Google Cloud Console I've enabled the Google Cloud Datastore API, and registered a new app, downloading the private certificate.
For the authentication, I'm using the following code (xxxx has the real values):
const SERVICE_ACCOUNT_NAME = 'xxxx#developer.gserviceaccount.com';
const KEY_FILE = 'secure/privatekey.p12';
$client = new Google_Client();
$key = file_get_contents ( KEY_FILE );
$client->setAssertionCredentials (
new Google_AssertionCredentials (
SERVICE_ACCOUNT_NAME,
array (
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/datastore'
),
$key
)
);
$service = new Google_DatastoreService ( $client );
$datasets = $service->datasets;
Whichever operation I use in $datasets, like $datasets->lookup, I receive an exception stating that the operation is Unauthorized:
Uncaught exception 'Google_ServiceException' with message 'Error calling POST https://www.googleapis.com/datastore/v1beta1/datasets/<my-appengine-id>/lookup: (403) Unauthorized.'
What might be wrong?
I believe you are hitting the following limitation: service account authorization doesn't work with domain-restricted App Engine application.
So you can either comment on the issue to get your application whitelisted, keep in mind that it can allow account outside of your domain to auth with your application using OAuth depending on how your application is built.

Categories