How set ApplicationDefaultCredentials in Google Translate api php? - php

I'm trying to set Google Translation API on my server.
But code returns error "Could not construct ApplicationDefaultCredentials"
$translationClient = new Google\Cloud\Translate\V3\TranslationServiceClient();
putenv('GOOGLE_APPLICATION_CREDENTIALS="/path/to/credetials.json"');
$content = ['one', 'two', 'three'];
$targetLanguage = 'es';
$response = $translationClient->translateText(
$content,
$targetLanguage,
TranslationServiceClient::locationName('[ProjectID]', 'global')
);
$res = '';
foreach ($response->getTranslations() as $key => $translation) {
$separator = $key === 2
? '!'
: ', ';
$res .= $translation->getTranslatedText() . $separator;
}
} catch(\Exception $e) {
$res = $e->getMessage();
}
die(json_encode($res));
I've already spend a lot of time to setting it but with no result.
Please, help me

You can pass the credentials in a config variable and then initialize the client.
<?php
require __DIR__ . '/vendor/autoload.php';
use Google\Cloud\Translate\V2\TranslateClient;
/** Uncomment and populate these variables in your code */
$config = ['credentials' => 'key.json'];
$text = "The text to translate.";
$targetLanguage = "ja";
$translate = new TranslateClient($config);
$result = $translate->translate($text, [
"target" => $targetLanguage,
]);
print("Source language: $result[source]\n");
print("Translation: $result[text]\n");
?>
Source language: en
Translation: 翻訳するテキスト

Php putenv https://www.php.net/manual/en/function.putenv.php
Andrey this worked for me on Windows 10 Pro. Wampserver 3.2.0. Php 7.4.4. It definitely has a problem with Windows backslashes. Forwardslashes and avoiding double quotes and single quotes together has helped to bump the compiler along.
$file = trim("C:/users/boss/onedrive/desktop/google.json",'"');
putenv("GOOGLE_APPLICATION_CREDENTIALS=$file");

Related

How to show return values fom a PHP XML-RPC call?

I can't seem to find any code to display returned values from the call.
I am running the xml-lib from the software vendor at the following link
https://support.sippysoft.com/support/solutions/articles/3000013653-xml-rpc-api-sign-up-html-page-fresh-version-
<?php
include 'xmlrpc/xmlrpc.inc';
function listAccounts()
{
//$params = array(new xmlrpcval(array("i_account"=> new xmlrpcval('14719', "string")), 'struct'));
$msg = new xmlrpcmsg('listAccounts');
/* replace here URL and credentials to access to the API */
$cli = new xmlrpc_client('https://DOMAINHERE/xmlapi/xmlapi');
$cli->setSSLVerifyPeer(false);
$cli->setSSLVerifyHost(false);
$cli->setCredentials('USERNAME', 'PASSWORD', CURLAUTH_DIGEST);
$r = $cli->send($msg, 20);
if ($r->faultCode()) {
error_log("Fault. Code: " . $r->faultCode() . ", Reason: " . $r->faultString());
print_r ($r->faultString());
return false;
}
else
{
return $r->value();
// I need something here to write returned values to normal PHP variable
}
}
Ok thanks to the comment from halfer.
I managed to get the issue and digging through the code in the library I found a function that does the trick.
Thanks a million for your pointer it really helped.
I am new to php and xml and the learning curve is quite tall but thanks.
for someone else reference maybe in the future here is the corrected code with the last 2 lines that does the magic for me.
<?php
include 'xmlrpc/xmlrpc.inc';
// $params = array(new xmlrpcval(array("offset"=> new xmlrpcval("1", "int")
// ,"i_customer"=> new xmlrpcval("321", "int")
// ), 'struct'));
$params = array(new xmlrpcval(array("i_customer"=> new xmlrpcval("321", "int")
), 'struct'));
$msg = new xmlrpcmsg('listAccounts', $params);
/* replace here URL and credentials to access to the API */
$cli = new xmlrpc_client('DOMAIN');
$cli->setSSLVerifyPeer(false);
$cli->setdebug(0);
$r = $cli->send($msg, 20); /* 20 seconds timeout */
if ($r->faultCode()) {
error_log("Fault. Code: " . $r->faultCode() . ", Reason: " . $r->faultString());
echo $r->faultString();
}
// now lets decode the xml response..
$values=php_xmlrpc_decode($r->value());
var_dump ($values['accounts'][0][username]);
?>

How to use optional parameters in Google Photos API?

I am working on project in php with Google Photos API. i have an issue, if i pass optional parameters like pageSize, it doesn't work still get all images.
$optParams = array(
'pageSize' => 1,
);
$response = $photosLibraryClient->listMediaItems($optParams);
foreach ($response->iterateAllElements() as $item) {
$id = $item->getId();
$description = $item->getDescription();
$mimeType = $item->getMimeType();
$productUrl = $item->getProductUrl();
$filename = $item->getFilename();
echo '<br>';
echo $filename;
}
I'm not a 100% sure of this, but it seems the iterateAllElements literally iterates over all elements available in the account, ignoring your specified pageSize (even the default pageSize) by requesting everything from the API without any boundaries.
You can iterate over the returned pages replacing iterateAllElements with iteratePages, but it also doesn't seems to work properly without a albumId, the API returns an irregular page sizing, like the example below:
$optParams = array(
'pageSize' => 5 // Changed
);
$response = $photosLibraryClient->searchMediaItems($optParams); // Changed the method
foreach ($response->iteratePages() as $key => $page) {
echo "Page #{$key}<br>";
foreach ($page as $item) {
$id = $item->getId();
$description = $item->getDescription();
$mimeType = $item->getMimeType();
$productUrl = $item->getProductUrl();
$filename = $item->getFilename();
echo '<br>';
echo $filename;
}
}
if the search or list were called without providing a albumId, the example above would return something like this:
[
[{...},{...},{...}],
[{...},{...},{...},{...},{...}],
[{...}],
[],
[{...},{...},{...},{...},{...}],
[]
]
If you find a good solution for this specific problem, please let me know.
Ps.: Their API behavior and it's documentation are very weird and confusing.

evernote api: example of php code to retrieve the text of a note

I look for an example of PHP code to retrieve the text of a note on the Evernote server.
So far, I only found trivial examples listing the notebooks, and helping to get authenticated. But all the references are for Java and not for PHP, and nothing lists the notes self.
I understand I have to use the function findNotesMetaData but I don't understand what to specify as fourth argument.
I need some help to get further. I don't know enough Java to understand the equivalent statement in PHP. Thanks in advance.
Pierre
You can't get note contents with findNotesMetaData. Here's simple code snippet for getting notes (also refer to the sample on github to know how to get token with OAuth).
use EDAM\NoteStore\NoteFilter;
use Evernote\Client;
$client = new Client(array(
'token' => $accessToken,
'sandbox' => true
));
$filter = new NoteFilter();
$filter->words = "Evernote";
$notes = $client->getNoteStore()->findNotes($filter, 0, 10);
You can see more details about searching notes here.
On github there is PHP Evernote API SDK
https://github.com/evernote/evernote-sdk-php
Not PHP, but the perl answer for this is as follows:
use strict;
use Net::Evernote::Simple;
my $evernote = Net::Evernote::Simple->new(
# Obtain a developer token from Evernote and put it here
dev_token => 'YOUR DEV TOKEN HERE',
);
warn "Evernote API version out of date!\n" if( ! $evernote->version_check() ); # check if our client API version still works
my $note_store = $evernote->note_store() or die "getting notestore failed: $#";
my $notebooks = $note_store->listNotebooks( $evernote->dev_token() ) or die "oops:$!"; # retrieve all of our notebooks. See https://dev.evernote.com/doc/reference/ for other things you can do.
for my $notebook ( #$notebooks ) {
print "evernote->note_store->listNotebooks: " . $notebook->guid() . "\t" . $notebook->name(), "\n";
$arg{'guid'}=$notebook->guid() if($notebook->name() eq 'Some Notebook Name');
}
my $tags = $note_store->listTags( $evernote->dev_token() ) or die "oops:$!";
for my $s ( #$tags ) {
print "evernote->note_store->listTags: " . $s->guid() . "\t" . $s->name(), "\n";
}
use Data::Dumper; print Data::Dumper->Dump([ $notebooks ],['$notebooks']);
my $srch = Net::Evernote::Simple::EDAMNoteStore::NoteFilter->new() or die "oops:$!";
$srch->notebookGuid( $arg{'guid'} ) or warn "hmm: $!";
# $srch->inactive( 1 ); # set this to go through the trash
print Data::Dumper->Dump([ $srch ],['$srch']);
my $res=Net::Evernote::Simple::EDAMNoteStore::NotesMetadataResultSpec->new();
# $authenticationToken, $filter, $offset, $maxNotes, $resultSpec);
my $sr = $note_store->findNotesMetadata( $evernote->dev_token(), $srch, 0, 99999, $res) or die "oops:$!";
print Data::Dumper->Dump([ $res ],['$res']);
print Data::Dumper->Dump([ $sr ],['$sr']);
#($authenticationToken, $guid, $withContent, $withResourcesData, $withResourcesRecognition, $withResourcesAlternateData);
my $note = $note_store->getNote( $evernote->dev_token(), 'some_note_GUID_here', 1, 1, 1, 1) or die "oops:$!";
print Data::Dumper->Dump([ $note ],['$note']);
my $tags = $note_store->listTags( $evernote->dev_token() ) or die "oops:$!";
print Data::Dumper->Dump([ $tags ],['$tags']);

PHP multipart form data PUT request?

I'm writing a RESTful API. I'm having trouble with uploading images using the different verbs.
Consider:
I have an object which can be created/modified/deleted/viewed via a post/put/delete/get request to a URL. The request is multi part form when there is a file to upload, or application/xml when there's just text to process.
To handle the image uploads which are associated with the object I am doing something like:
if(isset($_FILES['userfile'])) {
$data = $this->image_model->upload_image();
if($data['error']){
$this->response(array('error' => $error['error']));
}
$xml_data = (array)simplexml_load_string( urldecode($_POST['xml']) );
$object = (array)$xml_data['object'];
} else {
$object = $this->body('object');
}
The major problem here is when trying to handle a put request, obviously $_POST doesn't contain the put data (as far as I can tell!).
For reference this is how I'm building the requests:
curl -F userfile=#./image.png -F xml="<xml><object>stuff to edit</object></xml>"
http://example.com/object -X PUT
Does anyone have any ideas how I can access the xml variable in my PUT request?
First of all, $_FILES is not populated when handling PUT requests. It is only populated by PHP when handling POST requests.
You need to parse it manually. That goes for "regular" fields as well:
// Fetch content and determine boundary
$raw_data = file_get_contents('php://input');
$boundary = substr($raw_data, 0, strpos($raw_data, "\r\n"));
// Fetch each part
$parts = array_slice(explode($boundary, $raw_data), 1);
$data = array();
foreach ($parts as $part) {
// If this is the last part, break
if ($part == "--\r\n") break;
// Separate content from headers
$part = ltrim($part, "\r\n");
list($raw_headers, $body) = explode("\r\n\r\n", $part, 2);
// Parse the headers list
$raw_headers = explode("\r\n", $raw_headers);
$headers = array();
foreach ($raw_headers as $header) {
list($name, $value) = explode(':', $header);
$headers[strtolower($name)] = ltrim($value, ' ');
}
// Parse the Content-Disposition to get the field name, etc.
if (isset($headers['content-disposition'])) {
$filename = null;
preg_match(
'/^(.+); *name="([^"]+)"(; *filename="([^"]+)")?/',
$headers['content-disposition'],
$matches
);
list(, $type, $name) = $matches;
isset($matches[4]) and $filename = $matches[4];
// handle your fields here
switch ($name) {
// this is a file upload
case 'userfile':
file_put_contents($filename, $body);
break;
// default for all other files is to populate $data
default:
$data[$name] = substr($body, 0, strlen($body) - 2);
break;
}
}
}
At each iteration, the $data array will be populated with your parameters, and the $headers array will be populated with the headers for each part (e.g.: Content-Type, etc.), and $filename will contain the original filename, if supplied in the request and is applicable to the field.
Take note the above will only work for multipart content types. Make sure to check the request Content-Type header before using the above to parse the body.
Please don't delete this again, it's helpful to a majority of people coming here! All previous answers were partial answers that don't cover the solution as a majority of people asking this question would want.
This takes what has been said above and additionally handles multiple file uploads and places them in $_FILES as someone would expect. To get this to work, you have to add 'Script PUT /put.php' to your Virtual Host for the project per Documentation. I also suspect I'll have to setup a cron to cleanup any '.tmp' files.
private function _parsePut( )
{
global $_PUT;
/* PUT data comes in on the stdin stream */
$putdata = fopen("php://input", "r");
/* Open a file for writing */
// $fp = fopen("myputfile.ext", "w");
$raw_data = '';
/* Read the data 1 KB at a time
and write to the file */
while ($chunk = fread($putdata, 1024))
$raw_data .= $chunk;
/* Close the streams */
fclose($putdata);
// Fetch content and determine boundary
$boundary = substr($raw_data, 0, strpos($raw_data, "\r\n"));
if(empty($boundary)){
parse_str($raw_data,$data);
$GLOBALS[ '_PUT' ] = $data;
return;
}
// Fetch each part
$parts = array_slice(explode($boundary, $raw_data), 1);
$data = array();
foreach ($parts as $part) {
// If this is the last part, break
if ($part == "--\r\n") break;
// Separate content from headers
$part = ltrim($part, "\r\n");
list($raw_headers, $body) = explode("\r\n\r\n", $part, 2);
// Parse the headers list
$raw_headers = explode("\r\n", $raw_headers);
$headers = array();
foreach ($raw_headers as $header) {
list($name, $value) = explode(':', $header);
$headers[strtolower($name)] = ltrim($value, ' ');
}
// Parse the Content-Disposition to get the field name, etc.
if (isset($headers['content-disposition'])) {
$filename = null;
$tmp_name = null;
preg_match(
'/^(.+); *name="([^"]+)"(; *filename="([^"]+)")?/',
$headers['content-disposition'],
$matches
);
list(, $type, $name) = $matches;
//Parse File
if( isset($matches[4]) )
{
//if labeled the same as previous, skip
if( isset( $_FILES[ $matches[ 2 ] ] ) )
{
continue;
}
//get filename
$filename = $matches[4];
//get tmp name
$filename_parts = pathinfo( $filename );
$tmp_name = tempnam( ini_get('upload_tmp_dir'), $filename_parts['filename']);
//populate $_FILES with information, size may be off in multibyte situation
$_FILES[ $matches[ 2 ] ] = array(
'error'=>0,
'name'=>$filename,
'tmp_name'=>$tmp_name,
'size'=>strlen( $body ),
'type'=>$value
);
//place in temporary directory
file_put_contents($tmp_name, $body);
}
//Parse Field
else
{
$data[$name] = substr($body, 0, strlen($body) - 2);
}
}
}
$GLOBALS[ '_PUT' ] = $data;
return;
}
For whom using Apiato (Laravel) framework:
create new Middleware like file below, then declair this file in your laravel kernel file within the protected $middlewareGroups variable (inside web or api, whatever you want) like this:
protected $middlewareGroups = [
'web' => [],
'api' => [HandlePutFormData::class],
];
<?php
namespace App\Ship\Middlewares\Http;
use Closure;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* #author Quang Pham
*/
class HandlePutFormData
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->method() == 'POST' or $request->method() == 'GET') {
return $next($request);
}
if (preg_match('/multipart\/form-data/', $request->headers->get('Content-Type')) or
preg_match('/multipart\/form-data/', $request->headers->get('content-type'))) {
$parameters = $this->decode();
$request->merge($parameters['inputs']);
$request->files->add($parameters['files']);
}
return $next($request);
}
public function decode()
{
$files = [];
$data = [];
// Fetch content and determine boundary
$rawData = file_get_contents('php://input');
$boundary = substr($rawData, 0, strpos($rawData, "\r\n"));
// Fetch and process each part
$parts = $rawData ? array_slice(explode($boundary, $rawData), 1) : [];
foreach ($parts as $part) {
// If this is the last part, break
if ($part == "--\r\n") {
break;
}
// Separate content from headers
$part = ltrim($part, "\r\n");
list($rawHeaders, $content) = explode("\r\n\r\n", $part, 2);
$content = substr($content, 0, strlen($content) - 2);
// Parse the headers list
$rawHeaders = explode("\r\n", $rawHeaders);
$headers = array();
foreach ($rawHeaders as $header) {
list($name, $value) = explode(':', $header);
$headers[strtolower($name)] = ltrim($value, ' ');
}
// Parse the Content-Disposition to get the field name, etc.
if (isset($headers['content-disposition'])) {
$filename = null;
preg_match(
'/^form-data; *name="([^"]+)"(; *filename="([^"]+)")?/',
$headers['content-disposition'],
$matches
);
$fieldName = $matches[1];
$fileName = (isset($matches[3]) ? $matches[3] : null);
// If we have a file, save it. Otherwise, save the data.
if ($fileName !== null) {
$localFileName = tempnam(sys_get_temp_dir(), 'sfy');
file_put_contents($localFileName, $content);
$files = $this->transformData($files, $fieldName, [
'name' => $fileName,
'type' => $headers['content-type'],
'tmp_name' => $localFileName,
'error' => 0,
'size' => filesize($localFileName)
]);
// register a shutdown function to cleanup the temporary file
register_shutdown_function(function () use ($localFileName) {
unlink($localFileName);
});
} else {
$data = $this->transformData($data, $fieldName, $content);
}
}
}
$fields = new ParameterBag($data);
return ["inputs" => $fields->all(), "files" => $files];
}
private function transformData($data, $name, $value)
{
$isArray = strpos($name, '[]');
if ($isArray && (($isArray + 2) == strlen($name))) {
$name = str_replace('[]', '', $name);
$data[$name][]= $value;
} else {
$data[$name] = $value;
}
return $data;
}
}
Pls note: Those codes above not all mine, some from above comment, some modified by me.
Quoting netcoder reply : "Take note the above will only work for multipart content types"
To work with any content type I have added the following lines to Mr. netcoder's solution :
// Fetch content and determine boundary
$raw_data = file_get_contents('php://input');
$boundary = substr($raw_data, 0, strpos($raw_data, "\r\n"));
/*...... My edit --------- */
if(empty($boundary)){
parse_str($raw_data,$data);
return $data;
}
/* ........... My edit ends ......... */
// Fetch each part
$parts = array_slice(explode($boundary, $raw_data), 1);
$data = array();
............
...............
I've been trying to figure out how to work with this issue without having to break RESTful convention and boy howdie, what a rabbit hole, let me tell you.
I'm adding this anywhere I can find in the hope that it will help somebody out in the future.
I've just lost a day of development firstly figuring out that this was an issue, then figuring out where the issue lay.
As mentioned, this isn't a symfony (or laravel, or any other framework) issue, it's a limitation of PHP.
After trawling through a good few RFCs for php core, the core development team seem somewhat resistant to implementing anything to do with modernising the handling of HTTP requests. The issue was first reported in 2011, it doesn't look any closer to having a native solution.
That said, I managed to find this PECL extension called Always Populate Form Data. I'm not really very familiar with pecl, and couldn't seem to get it working using pear. but I'm using CentOS and Remi PHP which has a yum package.
I ran yum install php-pecl-apfd and it literally fixed the issue straight away (well I had to restart my docker containers but that was a given).
I believe there are other packages in various flavours of linux and I'm sure anybody with more knowledge of pear/pecl/general php extensions could get it running on windows or mac with no issue.
I know this article is old.
But unfortunately, PHP still does not pay attention to form-data other than the Post method.
Thanks to friends (#netcoder, #greendot, #pham-quang) who suggested solutions above.
Using those solutions I wrote a library for this purpose:
composer require alireaza/php-form-data
You can also use composer require alireaza/laravel-form-data in Laravel.

Max CDN purge through API

I am trying to purge a file through the MaxCDN API but it's not working. Here's the code I'm using. The print_r doesn't return any result.
function purge() {
date_default_timezone_set('America/Los_Angeles');
$date = date('c');
$apiid = 'myapiid';
$apikey = 'myapi';
$auth_key = hash('sha256', $date.':'.$apikey.':purge');
$url = 'http://softsailor.alexdumitru.netdna-cdn.com/wp-content/themes/ss3/includes/sprite.jpg';
if (!class_exists('IXR_Client')) {
require_once (ABSPATH . WPINC . '/class-IXR.php');
}
$client = new IXR_Client('api.netdna.com','/xmlrpc/cache',80);
$client->timeout = 30;
$client->query('cache.purge', $apiid, $auth_string, $date, $url);
print_r($client->getResponse());
}
I turned debug on and I'm getting the following error
Something went wrong - -32300 : transport error - HTTP status code was not 200
Hey Alex. I work at MaxCDN and here is a code example that I took from our Wiki:
<?php
date_default_timezone_set('America/Los_Angeles');
include("lib/xmlrpc.inc");
$cur = date('c');
$apiKey = 'api-key';
$apiUserId = 'api-user-id';
$namespace = 'cache';
$method = 'purge';
$authString = hash('sha256', $cur . ':' . $apiKey . ':' . $method);
// this is the url to purge
$url= 'http://static.jdorfman.netdna-cdn.com/static/images/frugal-it-logo.png';
$f=new xmlrpcmsg("$namespace.$method", array(php_xmlrpc_encode($apiUserId),
php_xmlrpc_encode($authString), php_xmlrpc_encode($cur),
php_xmlrpc_encode($url)));
$c=new xmlrpc_client("/xmlrpc/cache", "api.netdna.com", 80,'http11');
$r=&$c->send($f);
print_r($r);
?>
If you have any other questions or concerns feel free to get in contact with me: jdorfman at maxcdn dot com
jdorfman's example dumps the entire raw response but if you are like me you want to get it into data objects using php
Here are some helpful tips:
$r->serialize() to access just the raw XML response
to convert to JSON use this:
$xml = simplexml_load_string($r->serialize());
echo json_encode($xml);

Categories