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.
Related
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.
I have already work this in php. Here is my working code:
$request = array(
'DomainNames' => $domain_names
);
$response = dreamScapeAPI('DomainCheck', $request);
$available = false;
$alt_domains = array(); // Alternative to user's expected domain names
if (!is_soap_fault($response)) {
// Successfully checked the availability of the domains
if (isset($response->APIResponse->AvailabilityList)) {
$availabilityList = $response->APIResponse->AvailabilityList;
foreach ($availabilityList as $list) {
if ($list->Available){
if ($domain == $list->Item) {
$available = true; // user prefered domain found
}
else {
$alt_domains[] = $list->Item;
}
}
}
}
else {
$error = $response->APIResponse->Errors;
foreach ($error as $e) {
$api_error = $e->Message;
//echo $e->Item . ' - ' . $e->Message . '<br />';
}
}
}
function dreamScapeAPI($method, $data = null) {
$reseller_api_soap_client = "";
$soap_location = 'http://soap.secureapi.com.au/API-2.1';
$wsdl_location = 'http://soap.secureapi.com.au/wsdl/API-2.1.wsdl';
$authenticate = array();
$authenticate['AuthenticateRequest'] = array();
$authenticate['AuthenticateRequest']['ResellerID'] = '**';
$authenticate['AuthenticateRequest']['APIKey'] = '**';
//convert $authenticate to a soap variable
$authenticate['AuthenticateRequest'] = new SoapVar($authenticate['AuthenticateRequest'], SOAP_ENC_OBJECT);
$authenticate = new SoapVar($authenticate, SOAP_ENC_OBJECT);
$header = new SoapHeader($soap_location, 'Authenticate', $authenticate, false);
$reseller_api_soap_client = new SoapClient($wsdl_location, array('soap_version' => SOAP_1_2, 'cache_wsdl' => WSDL_CACHE_NONE));
$reseller_api_soap_client->__setSoapHeaders(array($header));
$prepared_data = $data != null ? array($data) : array();
try {
$response = $reseller_api_soap_client->__soapCall($method, $prepared_data);
} catch (SoapFault $response) { }
return $response;
}
I tried with this : https://github.com/dan-power/node-dreamscape
But domain search can not work properly. Mainly, I want it on nodejs using nodejs dreamscape api but this method is not available on nodejs.
Here is my working demo: click here
I'm trying to rebuild my PHP API with SlimPHP v3 + PDO. The problem is I'm stuck with retrieving attributes passed in POST method. Here is part of my index.php file, I decided just to echo the variable to test if it's working.
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../vendor/autoload.php';
require_once '../includes/UserOperation.php';
require_once '../includes/TweetOperation.php';
$app = new \Slim\App([
'settings' => [
'displayErrorDetails' => true
]
]);
//---UserOperation.php---//
//registering a new user
$app->post('/register', function (Request $request, Response $response) {
if (isTheseParametersAvailable(array('name', 'email', 'password', 'picture_path'))) {
$requestData = $request->getParsedBody();
$name = $request->getParsedBody()['name'];
$email = $requestData['email'];
$password = $requestData['password'];
$picture_path = $requestData['picture_path'];
echo "Hello " .$name;
}
});
//function to check parameters
function isTheseParametersAvailable($required_fields)
{
$error = false;
$error_fields = "";
$request_params = $_REQUEST;
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();
$response["error"] = true;
$response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty';
echo json_encode($response);
return false;
}
return true;
}
$app->run();
The link for my website looks for example like below,but $name variable that I'm trying to echo remains empty.
https://myweblink/register?name=test&email=test#mail.com&password=pass&picture_path=lolololo
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 am using KBariotis module to integrate magento with National Bank of Greece.
I tried everything but it's not working.
At first, it would not recognise the module.
So I changed protected $_formBlockType = 'nbp/form_nbp'; on /model/standard.php to
protected $_formBlockType = 'nbp/form_NBP';
Now it recognises it as a valid payment option.
But on checkout, it redirects me to /checkout/onepage/failure
edit:
In the code model/NBP.php I see that getRedirectUrl() returns false and not what it should. Here is the code
<?php
class KBariotis_NBP_Model_NBP extends Mage_Core_Model_Abstract
{
private $proxyPayEndPoint = null;
private $merchantID = null;
private $merchantSecret = null;
private $newOrderStatus = null;
private $pageSetId = null;
private $enable3dSecure = null;
protected function _Construct()
{
$this->merchantID = Mage::getStoreConfig('payment/nbp/merchant_id');
$this->proxyPayEndPoint = Mage::getStoreConfig('payment/nbp/proxy_pay_endpoint');
$this->merchantSecret = Mage::getStoreConfig('payment/nbp/merchant_confirmation_pwd');
$this->pageSetId = Mage::getStoreConfig('payment/nbp/page_set_id');
$this->newOrderStatus = Mage::getStoreConfig('payment/nbp/order_status');
$this->enable3dSecure = Mage::getStoreConfig('payment/nbp/enable_3d_secure');
}
public function getRedirectUrl()
{
$order = new Mage_Sales_Model_Order();
$orderId = Mage::getSingleton('checkout/session')
->getLastRealOrderId();
$order->loadByIncrementId($orderId);
$orderTotal = $order->getBaseGrandTotal();
$successUrl = Mage::getUrl('nbp/payment/success/');
$request = $this->createXMLRequestPreTransaction($orderId, $orderTotal, $successUrl);
if ($response = $this->makeRequest($request))
return $response->HpsTxn->hps_url . '?HPS_SessionID=' . $response->HpsTxn->session_id;
else
return false;
}
private function createXMLRequestPreTransaction($orderId, $orderTotal, $successUrl)
{
$request = new SimpleXMLElement("<Request></Request>");
$request->addAttribute("version", "2");
$auth = $request->addChild("Authentication");
$auth->addChild("password", $this->merchantSecret);
$auth->addChild("client", $this->merchantID);
$transaction = $request->addChild("Transaction");
$txnDetails = $transaction->addChild("TxnDetails");
$txnDetails
->addChild("merchantreference", $orderId);
if ($this->enable3dSecure) {
$threeDSecure = $txnDetails->addChild("ThreeDSecure");
$browser = $threeDSecure->addChild("Browser");
$browser->addChild("device_category", 0);
$browser->addChild("accept_headers", "*/*");
$browser->addChild("user_agent", "IE/6.0");
$threeDSecure->addChild("purchase_datetime", date('Ymd H:i:s'));
$threeDSecure->addChild("purchase_desc", $orderId);
$threeDSecure->addChild("verify", "yes");
}
$txnDetails
->addChild("amount", $orderTotal)
->addAttribute("currency", "EUR");
$txnDetails
->addChild("capturemethod", "ecomm");
$hpsTxn = $transaction->addChild("HpsTxn");
$hpsTxn
->addChild("method", "setup_full");
$hpsTxn
->addChild("page_set_id", $this->pageSetId);
$hpsTxn
->addChild("return_url", $successUrl);
$hpsTxn
->addChild("expiry_url", Mage::getUrl(''));
$cardTxn = $transaction->addChild('CardTxn');
$cardTxn
->addChild("method", "auth");
return $request;
}
public function queryRefTransaction($ref)
{
$request = $this->createXMLRequestPostTransaction($ref);
if ($response = $this->makeRequest($request))
return $response->merchantreference;
return false;
}
private function createXMLRequestPostTransaction($ref)
{
$request = new SimpleXMLElement("<Request></Request>");
$request->addAttribute("version", "2");
$auth = $request->addChild("Authentication");
$auth->addChild("password", $this->merchantSecret);
$auth->addChild("client", $this->merchantID);
$transaction = $request->addChild("Transaction");
$historicTxn = $transaction->addChild("HistoricTxn");
$historicTxn
->addChild("method", "query");
$historicTxn
->addChild("reference", $ref);
return $request;
}
private function makeRequest($request)
{
$client = new Varien_Http_Client($this->proxyPayEndPoint);
$client->setMethod(Zend_Http_Client::POST);
$client->setRawData($request->asXML());
$response = $client->request();
if (!$response->isSuccessful())
throw new Mage_Payment_Exception('Could not communicate to payment server');
$responseBody = $response->getBody();
$response = simplexml_load_string($responseBody);
$status = intval($response->status);
if ($status != 1 && $status != 7)
Mage::log('Error from the Bank : ' . $responseBody);
if ($status == 7)
Mage::log('Bank refused the payment : ' . $responseBody);
if ($status == 1)
return $response;
return false;
}
public function getNewOrderStatus()
{
return $this->newOrderStatus;
}
}
Although, it's been 4 months since you posted this question I am answering.
Check that your proxyPayEndPoint is the correct valid url.
The page Set ID should be filled. (An id of an existed page that you you are using for validation).
In case you have 3DSecure enabled, you should have the elements correctly filled.
$browser->addChild("device_category", 0);
$headers = apache_request_headers();
$browser->addChild("accept_headers", ($headers['Accept']?(string)$headers['Accept']:"*/*"));
$browser->addChild("user_agent", (string)$_SERVER['HTTP_USER_AGENT']);
You could print the xml request (your_website_url/nbp/payment/redirect/) and see the response and what is probably missing from your structure.