Dialogflow and PHP newbie here.
I have created and implemented a mini button-based chatbot using Dialogflow ES PHP client library in one of my client's WordPress site.
Everything worked as expected in my local environment, but when I pushed my codes to the staging site, I got a 500 (Internal Server Error) in my DevTool. The Dialogflow console still got my initial intent from staging and responded accordingly with logs without any error, however.
This is the error shown in my server error.log
PHP Fatal error:
Uncaught Google\ApiCore\ApiException: {
"message": "Input text not set.",
"code": 3,
"status": "INVALID_ARGUMENT",
"details": []
}
thrown in /var/www/my-staging-domain.com/public/vendor/google/gax/src/ApiException.php on line 267, referer: https://my-staging-domain.com/
AJAX call frontend JS file
async function sendDataToDialogflow(text, sessionID) {
let result;
try {
result = await $.ajax({
url: /dialogflow.php,
type: "POST",
data: {
query: text,
lang: "en",
sessionId: sessionID,
},
success: function(res, status, xhr) {
setDialogflowResponse(res);
},
error: function(error) {
console.warn(error);
}
});
return result;
} catch (error) {
console.log(error);
}
}
My backend dialogflow.php file setting
<?php
namespace Google\Cloud\Samples\Dialogflow;
namespace Google\Protobuf;
use Google\Cloud\Dialogflow\V2\SessionsClient;
use Google\Cloud\Dialogflow\V2\TextInput;
use Google\Cloud\Dialogflow\V2\QueryInput;
use Google\Cloud\Dialogflow\V2\Context;
require $_SERVER['DOCUMENT_ROOT']. '/vendor/autoload.php';
if (isset($_POST) && isset($_POST["query"])) {
$query = $_POST["query"];
$lang = $_POST["lang"];
$sessionId = $_POST["sessionId"];
if (isset($_POST['query'])) {
detect_intent_texts($projectId,$query,$sessionId);
}
}
function detect_intent_texts($projectId, $text, $sessionId, $context = '', $parameters = '', $languageCode = 'en-US')
{
// -------------- new session --------------
$credential = array('credentials' => $_SERVER['DOCUMENT_ROOT'].'/client-secret.json');
$sessionsClient = new SessionsClient($credential);
$session = $sessionsClient->sessionName($projectId, $sessionId ?: uniqid());
//printf('Session path: %s' . PHP_EOL, $session);
// -------------- create text input --------------
$textInput = new TextInput();
$textInput->setText($text);
$textInput->setLanguageCode($languageCode);
if($context !== '') {
// -------------- create context struct --------------
$contextStruct = new Struct();
$contextStruct->setFields($context['parameters']);
// -------------- create context input --------------
$contextInput = new Context();
$contextInput->setLifespanCount($context['lifespan']);
$contextInput->setName($context['name']);
$contextInput->setParameters($contextStruct);
}
if($parameters !== '') {
$paramStruct = new Struct();
$paramStruct->setFields($parameters['parameters']);
}
// -------------- create query input --------------
$queryInput = new QueryInput();
$queryInput->setText($textInput);
// -------------- get response and relevant info --------------
$response = ($parameters ? $sessionsClient->detectIntent($session, $queryInput) : $sessionsClient->detectIntent($session, $queryInput));
$responseId = $response->getResponseId();
$queryResult = $response->getQueryResult();
$fields = $queryResult->getParameters()->getFields();
$jsonString = $queryResult->serializeToJsonString();
$queryText = $queryResult->getQueryText();
$intent = $queryResult->getIntent();
$displayName = $intent->getDisplayName();
$confidence = $queryResult->getIntentDetectionConfidence();
$fulfillmentText = $queryResult->getFulfillmentText();
$fulfillmentMessages = json_decode($queryResult->getFulfillmentMessages()[0]->serializeToJsonString(), true);
function get_field_value($field)
{
$kind = $field->getKind();
if ($kind == "string_value")
return $field->getStringValue();
else if ($kind == "number_value")
return $field->getNumberValue();
else if ($kind == "bool_value")
return $field->getBoolValue();
else if ($kind == "null_value")
return $field->getNullValue();
else if ($kind == "list_value") {
$list_values = $field->getListValue()->getValues();
$values = [];
foreach($list_values as $list_value)
$values[] = get_field_value($list_value);
return $values;
}
else if ($kind == "struct_value")
return $field->getStructValue();
}
$parameters = [];
foreach($fields as $key => $field) {
$parameters[$key] = get_field_value($field);
}
$returnResponse = array(
'responseId' => $responseId,
'fulfillmentText' => $fulfillmentText,
'fulfillmentMessages' => $fulfillmentMessages,
'queryText' => $queryText,
'parameters' => json_decode($jsonString)->parameters
);
echo json_encode($returnResponse);
$sessionsClient->close();
}
composer.json
{
"require": {
"google/cloud-dialogflow": "^0.29.0",
"google/protobuf": "^3.21",
"protobuf-php/protobuf": "^0.1.3",
"ext-bcmath": "*"
}
}
Any insights on this issue would be much appreciated!
I've updated staging from http to https, but this didn't fix the issue.
I've read through all the documents/questions on stackoverflow I could find, but in vain.
Related
so i have a login form where in iwant to show a error message if the account is not exsisting or the inputed account is incorrect. but the error message using snackbar is not showing.
here is my code for vue js.
const Login = Vue.component('login-view', {
data () {
return {
validate: {
login: false,
forgot: false
},
loading: {
login: false
},
form: {
email: null,
password: null
},
showPassword: false
}
},
computed: {
passField () {
var type = null
if (this.showPassword) {
type = 'text'
} else {
type = 'password'
}
return type
}
},
methods: {
signIn () {
if (this.$refs.login.validate()) {
this.loading.login = true
axios.post('./sql/login.php', this.form)
.then((res) => {
const data = res.data
console.log(data)
if(data) {
sessionStorage.setItem('uid', data.uid)
sessionStorage.setItem('displayName', data.displayName)
sessionStorage.setItem('email', data.email)
sessionStorage.setItem('type', data.type)
if (data.type === 'customer') { router.push('/'); location.reload() }
else if (data.type === 'seller') { router.push('/seller') }
}
this.loading.login = false
})/* Catching the error and displaying it in the console. */
.catch((error) => { console.log(error); this.$emit('snackbar', "incorrect"); this.loading.login = false })
}
}
},
here is my code for php
<?php
require_once("connection.php");
// Used to recognize JSON data posted by Axios.js
$data = json_decode(file_get_contents("php://input"), true);
//Check if the account exists
$sql = $handler->prepare("SELECT * FROM accounts WHERE email = ?");
$sql->execute(array($data['email']));
$count = $sql->rowCount();
// If account exists, its data will be fetched.
if($count === 1) {
$info = $sql->fetch(PDO::FETCH_OBJ);
$verified = password_verify($data['password'], $info->password);
// Checks if password entered matches the hashed password in account's data.
if ($verified) {
// Encodes initial account information as a JSON and sends it back.
$accountData = new \stdClass();
$accountData->uid = $info->uid;
$accountData->displayName = $info->fname . ' ' . $info->lname;
$accountData->email = $info->email;
$accountData->type = $info->type;
header("HTTP/1.1 200 OK");
/* Encoding the account data as a JSON and sending it back to the client. */
die(json_encode($accountData));
} else {
console_log(json_encode(array('message' => 'ERROR', 'code' => 2000)));
$error = 'Wrong email or password. Please try again.';
header('HTTP/1.1 500 Internal Server');
header('Content-Type: application/json; charset=UTF-8');
/* Sending a JSON object back to the client. */
die(json_encode(array('message' => 'ERROR', 'code' => 2000)));
}
die();
}
else {
$error = 'Account does not exists under this email. Please try again.';
}
die();
function console_log($output, $with_script_tags = true) {
$js_code = 'console.log(' . json_encode($output, JSON_HEX_TAG) .
');';
if ($with_script_tags) {
$js_code = '<script>' . $js_code . '</script>';
}
echo $js_code;
}
?>
here is the link to the website that i built. https://www.tailorshopthesis.online/tailorshop%20twofish/shop/#/sign-in
i hope some of you guys will help me. thanks
I've got this code to run and fetch images from my drive. But i'm running into a problem every time I run this code.
function listF() {
$result = array();
$tok = array();
$nextPageToken = NULL;
do {
try {
$parameters = array();
if ($nextPageToken) {
$parameters['pageToken'] = $nextPageToken;
$parameters['q'] = "mimeType='image/jpeg' or mimeType='image/png'";
}
$files = $this->service->files->listFiles($parameters);
$tok[] = $nextPageToken;
$result = array_merge($tok, $result, $files->getFiles());
$nextPageToken = $files->getNextPageToken();
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
$nextPageToken = NULL;
}
} while ($nextPageToken);
return $result;
}
I'm getting this error:
An error occurred: {
"error": {
"errors": [
{
"domain": "global",
"reason": "invalid",
"message": "Invalid Value",
"locationType": "parameter",
"location": "pageToken"
}
],
"code": 400,
"message": "Invalid Value"
}
}
It doesn't really seem illegitimate to me. Perhaps you might able to find the bug. Thanks
I'll answer your nextPageToken problem using Javascript, just take note of the logic.
I have two listFile() functions which are identical. One executes at initial load, after loading the page, it shows the first 10 of my 100 files. The other executes each time a button is clicked.
First function to display the inital 10 files.
//take note of this variable
var nextToken ;
function listFiles() {
gapi.client.drive.files.list({
'pageSize': 10,
'fields': "*"
}).then(function(response) {
//assign the nextPageToken to a variable to be used later
nextToken = response.result.nextPageToken;
// do whatever you like here, like display first 10 files in web page
// . . .
});
}
Second function:
This function is triggered by click of a button named "Next Page" which displays the succeeding files from 11 to N.
function gotoNextPage(event) {
gapi.client.drive.files.list({
'pageSize': 10,
'fields': "*",
'pageToken': nextToken
}).then(function(response) {
//assign new nextPageToken to make sure new files are displayed
nextToken = response.result.nextPageToken;
//display batch of file results in the web page
//. . .
});
}
It appears that the nextPageToken will be ruled invalid unless you include the exact same query field (q) in the subsequent requests that was included in the initial request.
var files = []
var nextToken;
gapi.client.drive.files.list({
'q': "mimeType='image/jpeg' or mimeType='image/png'",
'pageSize': 10,
'fields': 'nextPageToken, files(id, name)'
}).then(function(response) {
nextToken = response.result.nextPageToken;
files.push(...response.result.files)
while (nextToken) {
gapi.client.drive.files.list({
'nextPage': nextToken,
'q': "mimeType='image/jpeg' or mimeType='image/png'",
'pageSize': 10,
'fields': 'nextPageToken, files(id, name)'
}).then(function(response) {
nextToken = response.result.nextPageToken;
files.push(...response.result.files)
})
}
});
A V3 tested solution. This will handle large sets (greater then 1000) by handling pagination:
function GetFiles()
{
$options =
[
'pageSize' => 1000,
'supportsAllDrives' => true,
'fields' => "files(id, mimeType, name), nextPageToken"
];
$files = [];
$pageToken = null;
do
{
try
{
if ($pageToken !== null)
{
$options['pageToken'] = $pageToken;
}
$response = $this->service->files->listFiles($options);
$files = array_merge($files, $response->files);
$pageToken = $response->getNextPageToken();
}
catch (Exception $exception)
{
$message = $exception->getMessage();
echo "Error: $message\r\n";
$pageToken = null;
}
} while ($pageToken !== null);
return $files;
}
The Google Drive V3 PHP API is not as copiously documented as V2.
I found no simple PHP examples utilizing pageToken for the V3 API, so I am providing this one:
$parameters = array();
$parameters['q'] = "mimeType='image/jpeg' or mimeType='image/png'";
$parameters['fields'] = "files(id,name), nextPageToken";
$parameters['pageSize'] = 100;
$files = $google_drive_service->files->listFiles($parameters);
/* initially, we're not passing a pageToken, but we need a placeholder value */
$pageToken = 'go';
while ($pageToken != null) {
if (count($files->getFiles()) == 0) {
echo "No files found.\n";
}
else {
foreach ($files->getFiles() as $file) {
echo "name: '".$file->getName()."' ID: '".$file->getId()."'\n";
}
}
/* important step number one - get the next page token (if any) */
$pageToken = $files->getNextPageToken();
/* important step number two - append the next page token to your query */
$parameters['pageToken'] = $pageToken;
$files = $google_drive_service->files->listFiles($parameters);
}
I want to create an API using Slim for my android application. The API is very simple, i just want to save in my database data for an article. My code is shown below
<?php
error_reporting(-1);
ini_set('display_errors', 'On');
require_once '../include/DbHandler.php';
require '.././libs/Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
/**
* Verifying required params posted or not
*/
function verifyRequiredParams($required_fields) {
$error = false;
$error_fields = "";
$request_params = array();
$request_params = $_REQUEST;
if ($_SERVER['REQUEST_METHOD'] == 'PUT') {
$app = \Slim\Slim::getInstance();
parse_str($app->request()->getBody(), $request_params);
}
foreach ($required_fields as $field) {
if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) {
$error = true;
$error_fields .= $field . ', ';
}
}
if ($error) {
$response = array();
$app = \Slim\Slim::getInstance();
$response["error"] = true;
$response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty';
echoRespnse(400, $response);
$app->stop();
}
}
/**
* Echoing json response to client
* #param String $status_code Http response code
* #param Int $response Json response
*/
function echoRespnse($status_code, $response) {
$app = \Slim\Slim::getInstance();
$app->status($status_code);
$app->contentType('application/json');
echo json_encode($response);
}
/**
* Creating new task in db
* method POST
* params - name
* url - /articles/
*
* {"error": false,
"message": "Task created successfully",
"task_id": 1}
*/
$app->post('/articles', 'authenticate', function() use ($app) {
//verifyRequiredParams(array('article'));
$response = array();
$article_image = $app->request->post('article_image');
$article_video = $app->request->post('article_video');
$article_title = $app->request->post('article_title');
$article_main_body = $app->request->post('article_main_body');
$article_tags = $app->request->post('article_tags');
$db = new DbHandler();
// creating new article
$article_id = $db->createTask($article_image,$article_video,$article_title,$article_main_body,$article_tags);
if ($article_id != NULL) {
$response["error"] = false;
$response["message"] = "Article created successfully";
$response["article_id"] = $article_id;
} else {
$response["error"] = true;
$response["message"] = "Failed to create article. Please try again";
}
echoRespnse(201, $response);
});
/**
* Listing all articles
* method GET
* url /articles
* {
"error": false,
"tasks": [
{
"id": 1,
"task": "Complete REST article by Sunday",
"status": 0,
"createdAt": "2014-01-08 23:35:45"
},
{
"id": 2,
"task": "Book bus tickets!",
"status": 0,
"createdAt": "2014-01-08 23:56:52"
}
]
}
*/
$app->get('/articles', 'authenticate', function() {
$response = array();
$db = new DbHandler();
$result = $db->getAllTasks();
$response["error"] = false;
$response["articles"] = array();
// looping through result and preparing articles array
while ($article = $result->fetch_assoc()) {
$tmp = array();
$tmp["id"] = $task["id"];
$tmp["article_image"] = $article["article_image"];
$tmp["article_video"] = $article["article_video"];
$tmp["article_title"] = $article["article_title"];
$tmp["article_main_body"] = $article["article_main_body"];
$tmp["article_tags"] = $article["article_tags"];
$tmp["created_at"] = $article["created_at"];
array_push($response["articles"], $tmp);
}
echoRespnse(200, $response);
});
/**
* Listing single task of particual user
* method GET
* url /articles/:id
* Will return 404 if the task doesn't belongs to user
*
* {
"error": false,
"id": 2,
"task": "Book bus tickets!",
"status": 0,
"createdAt": "2014-01-08 23:56:52"
}
*/
$app->get('/articles/:id', 'authenticate', function($article_id) {
$response = array();
$db = new DbHandler();
// fetch article
$result = $db->getArticle($article_id);
if ($result != NULL) {
$response["error"] = false;
$response["id"] = $result["id"];
$response["article_image"] = $result["article_image"];
$response["article_video"] = $result["article_video"];
$response["article_title"] = $result["article_title"];
$response["article_main_body"] = $result["article_main_body"];
$response["article_tags"] = $result["article_tags"];
$response["created_at"] = $result["created_at"];
echoRespnse(200, $response);
} else {
$response["error"] = true;
$response["message"] = "The requested resource doesn't exists";
echoRespnse(404, $response);
}
});
$app->run();
?>
The above, is my index.php while my .htaccess is the below
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ %{ENV:BASE}index.php [QSA,L]
The structure of my project is
include
|
-Config.php
-DbConnect.php
-DbHandler.php
libs
|
-Slim
v1
|
-.htaccess
-index.php
I have uploaded my project in an Ubuntu Droplet i created in DigitalOcean, however when i run my project i get the exception below
Uncaught exception 'InvalidArgumentException' All Route middleware must be callable'
Is there anything i should change in my servers config docs?
Slim is trying to call a function that doesn't exist.
In every route definition you have a second parameter with the value 'authenticate' (for example in your $app->post('/articles', 'authenticate', function() use ($app) {});
You have to define the authenticate function somewhere before:
function authenticate() {
echo "My authenticate logic!";
}
Take a look to the documentation.
I have this function that connects to an external API:
function ICUK_Request($url, $method = 'GET', $body = NULL) {
$client = new IcukApiClient();
$client->username = "user";
$client->key = "pass";
$client->encryption = "SHA-512";
$req = new IcukApiRequest();
$req->url = $url;
$req->method = $method;
if(!is_null($body)) {
$req->body = $body;
}
$res = $client->send($req);
if ($res->success) {
$obj = json_decode($res->response);
}
else {
throw new Exception('There was an error contacting the API.');
}
return $obj;
}
the API docs are telling me to send the POST request like this:
POST /domain/registration/new/
{
"domain_name": "domain.co.uk",
"hosting_type": "NONE",
"registration_length": 1,
"auto_renew": false,
"domain_lock": false,
"whois_privacy": false,
"contact_registrant_id": 1
}
so i tried this:
$arr = array(
"domain_name" => "domain.co.uk",
"hosting_type" => "NONE",
"registration_length" => 1,
"auto_renew" => false,
"domain_lock" => false,
"whois_privacy" => false,
"contact_registrant_id" => 1
);
ICUK_Request("/domain/registration/new", "POST", $arr);
but thats giving me a response in the API Logs saying:
{
"exception_message": "Internal API exception occured",
"exception_type": "InternalApiException"
}
im not sure if this would be anything generic and if anyone can help on how to POST the data?
Send it as json:
$values = json_encode($arr);
ICUK_Request("/domain/registration/new", "POST", $values);
I need to implement MinecraftQuery's class (https://github.com/xPaw/PHP-Minecraft-Query/blob/master/MinecraftQuery.class.php)
So far I have the PHP side working.
This resides in HomeController.
public function mcQuery($ip, $port)
{
$Query = new MinecraftQuery();
try
{
$host = $this->getHost($ip, $port);
$Query->Connect( $host["ip"], $host["port"] );
return $Query;
}
catch( MinecraftQueryException $e )
{
return false;
}
}
public function getHost($address, $port)
{
$result = dns_get_record("_minecraft._tcp.$address", DNS_SRV);
if ($result) {
$priority = 0;
$valid = 0;
foreach ($result as $v) {
$type = $v['type'];
$pri = $v['pri'];
$targetPort = $v['port'];
$target = $v['target'];
if ($type=="SRV") {
if ($valid==0 || $pri <= $priority) {
$address = $target;
$port = $targetPort;
$priority = $pri;
$valid = 1;
}
}
}
} else {
$address = gethostbyname($address.'.');
if(filter_var($address, FILTER_VALIDATE_IP) != $address) {
throw new \Exception("Not a valid ip address: " . $address . "\n");
}
}
return [ 'ip' => $address, 'port' => $port ];
}
}
This works - by itself anyways, but the next problem is actually returning the response to the route so I can use it via javascript
This is all I have...
Route::get('/servers', function(){
$ip = Input::get('ip');
$port = Input::get('port');
$home = App::make('HomeController');
$info = $home->mcQuery($ip, $port);
return $info
});
This returns an error, though. When I visit http://mysite.dev/servers?ip=lorem.someip.com&port=25564
I get...
The Response content must be a string or object implementing __toString(), "object" given.
However, doing a dd($info) instead returns...
object(MinecraftQuery)#130 (3) {
["Socket":"MinecraftQuery":private]=>
resource(48) of type (Unknown)
["Players":"MinecraftQuery":private]=>
NULL
["Info":"MinecraftQuery":private]=>
array(10) {
["HostName"]=>
string(37) "Some Name!"
["GameType"]=>
string(3) "SMP"
["Version"]=>
string(5) "1.7.9"
// ...
}
}
I've never seen an array with :private before and Im assuming that is apart of the problem. But this is the object I am trying to return.
Oh, and for the last bit, this is how I'm trying to get this data..
serversObj.each(function(index, el) {
// serverObj is like 4 divs
var serverIp = $(this).data('ip');
var serverPort = $(this).data('port');
var serverStatus = $(this).find('.status');
$.ajax({
url: '/servers',
type: 'GET',
data: {ip: serverIp, port: serverPort},
})
.done(function(data) {
console.log("success: \n" + data);
})
.fail(function(ex) {
console.log(ex);
return false;
});
});
But of course returns a 500 server error unless I do dd() in the route instead.
So how can I get the correct data to return?
You may try this:
return Response::json($info->GetInfo());
In the done method try:
done(function(data) {
var object = $.parseJSON(data);
console.log(object);
})
Looking at the class, it seems that you want the GetInfo() method. This example should work:
$Query = new MinecraftQuery();
$host = $this->getHost($ip, $port);
$Query->Connect( $host["ip"], $host["port"] );
var_dump($Query->GetInfo());