Problem with accessing values in Request Session that I put into - php

I am fairly new to Laravel. This may have an obvious solution but I can't seem to find it so far. Therefore I am asking for help.
Question In Short:
I use Illuminate\Http\Request session ($request->session()) to store some data I get from BigCommerce API. But I can't get them when I need the data.
Context:
I am building a sample app/boilerplate app for BigCommerce platform using Laravel/React. I have built the app using official documentation, semi-official posts released by BigCommerce team and sample codebase provided by them as well.
App works fine with local credentials from a specific store because they are given as environment variables to the app. However I can't read store_hash (which is necessary to fetch data from BigCommerce) and access token. Both I have put in $request->session() object.
I will paste the AppController.php code below, also code is publicly available here:
In the makeBigCommerceAPIRequest method below (as you can see my debugging efforts :)) I can get $this->getAppClientId(), but I can't get anything from $request->session()->get('store_hash') or $request->session()->get('access_token') which returns from $this->getAccessToken($request).
I have tried putting store hash into a global variable, but it didn't work.
From everything I have experienced so far, $request is not working as expected.
Any help appriciated, thanks in advance.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use mysql_xdevapi\Exception;
use Oseintow\Bigcommerce\Bigcommerce;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Bigcommerce\Api\Client as BigcommerceClient;
use Illuminate\Support\Facades\Storage;
use App\Config; //Database Connection
use Bigcommerce\Api\Connection;
class AppController extends Controller
{
protected $bigcommerce;
private $client_id;
private $client_secret;
private $access_token;
private $storehash;
private $redirect_uri;
public function __construct(Bigcommerce $bigcommerce)
{
$this->bigcommerce = $bigcommerce;
$this->client_id = \config('app.clientId');
$this->client_secret = \config('app.clientSecret');
$this->redirect_uri = \config('app.authCallback');
}
public function getAppClientId()
{
if (\config('app.appEnv') === 'local') {
return \config('app.localClientId');
} else {
return \config('app.clientId');
}
}
public function getAppSecret()
{
if (\config('app.appEnv') === 'local') {
return \config('app.localClientSecret');
} else {
return \config('app.clientSecret');
}
}
public function getAccessToken(Request $request)
{
if (\config('app.appEnv') === 'local') {
return \config('app.localAccessToken');
} else {
return $request->session()->get('access_token');
}
}
public function getStoreHash(Request $request)
{
if (\config('app.appEnv') === 'local') {
return \config('app.localStoreHash');
} else {
return $request->session()->get('store_hash');
}
}
public function error(Request $request)
{
$errorMessage = "Internal Application Error";
if ($request->session()->has('error_message')) {
$errorMessage = $request->session()->get('error_message');
}
echo '<h4>An issue has occurred:</h4> <p>' . $errorMessage . '</p> Go back to home';
}
public function load(Request $request)
{
$signedPayload = $request->get('signed_payload');
if (!empty($signedPayload)) {
echo "hello";
$verifiedSignedRequestData = $this->verifySignedRequest($signedPayload);
if ($verifiedSignedRequestData !== null) {
echo "positive return";
$request->session()->put('user_id', $verifiedSignedRequestData['user']['id']);
$request->session()->put('user_email', $verifiedSignedRequestData['user']['email']);
$request->session()->put('owner_id', $verifiedSignedRequestData['owner']['id']);
$request->session()->put('owner_email', $verifiedSignedRequestData['owner']['email']);
$request->session()->put('store_hash', $verifiedSignedRequestData['context']);
echo $request->session()->get('store_hash');
$this->storehash = $verifiedSignedRequestData['context'];
echo ' store hash is at the moment : ' . $this->storehash . ' .....';
} else {
return "The signed request from BigCommerce could not be validated.";
// return redirect()->action([AppController::class, 'error'])->with('error_message', 'The signed request from BigCommerce could not be validated.');
}
} else {
return "The signed request from BigCommerce was empty.";
// return redirect()->action([AppController::class, 'error'])->with('error_message', 'The signed request from BigCommerce was empty.');
}
return redirect(\config('app.appUrl'));
}
public function install(Request $request)
{
// Make sure all required query params have been passed
if (!$request->has('code') || !$request->has('scope') || !$request->has('context')) {
echo 'Not enough information was passed to install this app.';
// return redirect()->action('MainController#error')->with('error_message', 'Not enough information was passed to install this app.');
}
try {
$client = new Client();
$result = $client->request('POST', 'https://login.bigcommerce.com/oauth2/token', [
'json' => [
'client_id' => $this->client_id,
'client_secret' => $this->client_secret,
'redirect_uri' => $this->redirect_uri,
'grant_type' => 'authorization_code',
'code' => $request->input('code'),
'scope' => $request->input('scope'),
'context' => $request->input('context'),
]
]);
$statusCode = $result->getStatusCode();
$data = json_decode($result->getBody(), true);
if ($statusCode == 200) {
$request->session()->put('store_hash', $data['context']);
$request->session()->put('access_token', $data['access_token']);
$request->session()->put('user_id', $data['user']['id']);
$request->session()->put('user_email', $data['user']['email']);
// $configValue = Config::select('*')->where('storehash', $data['context'])->get()->toArray();
// if (count($configValue) != 0) {
// $id = $configValue[0]['id'];
// $configObj = Config::find($id);
// $configObj->access_token = $data['access_token'];
// $configObj->save();
// } else {
// $configObj = new Config;
// $configObj->email = $data['user']['email'];
// $configObj->storehash = $data['context'];
// $configObj->access_token = $data['access_token'];
// $configObj->save();
// }
// If the merchant installed the app via an external link, redirect back to the
// BC installation success page for this app
if ($request->has('external_install')) {
return redirect('https://login.bigcommerce.com/app/' . $this->getAppClientId() . '/install/succeeded');
}
}
return redirect(\config('app.appUrl'));
} catch (RequestException $e) {
$statusCode = $e->getResponse()->getStatusCode();
echo $statusCode;
$errorMessage = "An error occurred.";
if ($e->hasResponse()) {
if ($statusCode != 500) {
echo "some error other than 500";
// $errorMessage = Psr7\str($e->getResponse());
}
}
// If the merchant installed the app via an external link, redirect back to the
// BC installation failure page for this app
if ($request->has('external_install')) {
return redirect('https://login.bigcommerce.com/app/' . $this->getAppClientId() . '/install/failed');
} else {
echo "fail";
// return redirect()->action('MainController#error')->with('error_message', $errorMessage);
}
}
// return view('index');
}
public function verifySignedRequest($signedRequest)
{
list($encodedData, $encodedSignature) = explode('.', $signedRequest, 2);
// decode the data
$signature = base64_decode($encodedSignature);
$jsonStr = base64_decode($encodedData);
echo $jsonStr;
$data = json_decode($jsonStr, true);
// confirm the signature
$expectedSignature = hash_hmac('sha256', $jsonStr, $this->client_secret, $raw = false);
if (!hash_equals($expectedSignature, $signature)) {
error_log('Bad signed request from BigCommerce!');
return null;
}
return $data;
}
public function makeBigCommerceAPIRequest(Request $request, $endpoint)
{
echo ' ...... trying to make an apiRequest now : with storehash : ' . $this->storehash . ' .............';
echo '...........................................';
echo 'other variables at the moment :::: ............... client ID :' . $this->getAppClientId() . '...................... token : ' . $this->getAccessToken($request) . '...............';
$requestConfig = [
'headers' => [
'X-Auth-Client' => $this->getAppClientId(),
'X-Auth-Token' => $this->getAccessToken($request),
'Content-Type' => 'application/json',
]
];
if ($request->method() === 'PUT') {
$requestConfig['body'] = $request->getContent();
}
$client = new Client();
$result = $client->request($request->method(), 'https://api.bigcommerce.com/' . $this->storehash . '/' . $endpoint, $requestConfig);
return $result;
}
public function proxyBigCommerceAPIRequest(Request $request, $endpoint)
{
if (strrpos($endpoint, 'v2') !== false) {
// For v2 endpoints, add a .json to the end of each endpoint, to normalize against the v3 API standards
$endpoint .= '.json';
}
echo ' asadssada ...... trying to make an apiRequest now : with storehash : ' . $this->storehash . ' .............' . $request->session()->get('store_hash') . ' ............ ';
$result = $this->makeBigCommerceAPIRequest($request, $endpoint);
return response($result->getBody(), $result->getStatusCode())->header('Content-Type', 'application/json');
}
}

Thanks for the detailed info. Though it would help to annotate the debug lines with confirmation of what they output, I am making the assumption that you have narrowed the problem down to the session storage and retrieval lines.
$request->session()->put() and get() are the correct ways to access session.
I would therefore suggest investigating Session configuration: https://laravel.com/docs/8.x/session#configuration
If using file-based sessions, confirm that there are no permissions errors, perhaps. Alternatively try and different session storage mechanism.

Related

How to call binance api class in php construtor?

I am trying to call binance api class in construct method in my controller so that I can access that api class instance throught entire controller. Problem lies that I need to pass $key and $secret variables to binance class in order to get that object, but I can not do that in construct method. I tried making config.ini file and calling it with parse_ini_file but that returned error that I can not use that function inside class. Here is my code. Any help is appreciated or if someone has other idea on how to make this work.
controller
<?php
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
require 'vendor/autoload.php';
class BinanceController
{
private $api;
private $key = 'some long string 1';
private $secret = 'some long string 2';
$api = new Binance\API($key,$secret); // SOMEHOW I NEED LIKE THIS!!!
public function __construct()
{
$this->api = new Binance\API($this->key,$this->secret);
}
public function getAllBinancePairs()
{
$exchangeInfo = $this->api->exchangeInfo(); // HERE IS SOURCE OF ERROR!!!
$results = [];
foreach($exchangeInfo['symbols'] as $info) {
$results[] = $info['symbol'];
}
json_response($results);
}
}
index.php
<?php
require 'vendor/autoload.php';
$router = new AltoRouter();
$router->map( 'GET', '/fbinance', function() {
require __DIR__ . '/fbinance.php';
});
$router->map('GET','/get-all-binance-pairs', array('c' => 'BinanceController', 'a' => 'getAllBinancePairs'));
$match = $router->match();
if(!isset($match['target']['c']))
{
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Server Error', true, 404);
}
switch($match['target']['c']) {
case "BinanceController":
include 'controllers/BinanceController.php';
if( $match && is_callable("BinanceController::" . $match['target']['a']) ) {
call_user_func_array("BinanceController::" . $match['target']['a'], $match['params'] );
} else {
// no route was matched
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Server Error', true, 404);
exit;
}
break;
default:
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Server Error', true, 404);
break;
}
If the arguments to the constructor for that API are not public, you can only instantiate it within the constructor of BinanceController like:
class BinanceController
{
private $api;
private $key = 'some long string 1';
private $secret = 'some long string 2';
public function __construct()
{
$this->api = new Binance\API($this->key,$this->secret);
}
}

Load a PHP class multiple times

I've created a class which has multiple private an public functions and an construct function. It's an client to connect to the vCloud API. I want two objects loaded with different initiations of this class. They have to exist in parallel.
$vcloud1 = new vCloud(0, 'system');
$vcloud2 = new vCloud(211, 'org');
When I check the output of $vcloud1 it's loaded with info of $vcloud2. Is this correct, should this happen? Any idea how I can load a class multiple times and isolate both class loads?
This is part of my class, it holds the most important functions. Construct with user and org to login to. If info in the DB exists, then we authenticate with DB info, else we authenticate with system level credentials. So I would like to have two class loads, one with the user level login and one with system level login.
class vCloud {
private $client;
private $session_id;
private $sdk_ver = '7.0';
private $system_user = 'xxxxxxxxxxx';
private $system_password = 'xxxxxxxxxxxxxxxxx';
private $system_host = 'xxxxxxxxxxxxx';
private $org_user;
private $org_password;
private $org_host;
private $base_url;
public function __construct($customerId, $orgName) {
if ($this->vcloud_get_db_info($customerId)) {
$this->base_url = 'https://' . $this->org_host . '/api/';
$this->base_user = $this->org_user . "#" . $orgName;
$this->base_password = $this->org_password;
} else {
$this->base_url = 'https://' . $this->system_host . '/api/';
$this->base_user = $this->system_user;
$this->base_password = $this->system_password;
}
$response = \Httpful\Request::post($this->base_url . 'sessions')
->addHeaders([
'Accept' => 'application/*+xml;version=' . $this->sdk_ver
])
->authenticateWith($this->base_user, $this->base_password)
->send();
$this->client = Httpful\Request::init()
->addHeaders([
'Accept' => 'application/*+xml;version=' . $this->sdk_ver,
'x-vcloud-authorization' => $response->headers['x-vcloud-authorization']
]);
Httpful\Request::ini($this->client);
}
public function __destruct() {
$deleted = $this->vcloud_delete_session();
if (!$deleted) {
echo "vCloud API session could not be deleted. Contact administrator if you see this message.";
}
}
private function vcloud_delete_session() {
if (isset($this->client)) {
$response = $this->client::delete($this->base_url . 'session')->send();
return $response->code == 204;
} else {
return FALSE;
}
}
public function vcloud_get_db_info($customerId) {
global $db_handle;
$result = $db_handle->runQuery("SELECT * from vdc WHERE customer=" . $customerId);
if ($result) {
foreach ($result as $row) {
if ($row['org_host'] != "") {
$this->org_user = $row['org_user'];
$this->org_password = $row['org_password'];
$this->org_host = $row['org_host'];
return true;
} else {
return false;
}
}
} else {
return false;
}
}
public function vcloud_get_admin_orgs() {
$response = $this->client::get($this->base_url . 'query?type=organization&sortAsc=name&pageSize=100')->send();
return $response->body;
}
}
$vcloud1 = new vCloud('user1', 'system');
$vcloud2 = new vCloud('user2', 'org');
This is enough to make two instances which are not related.
I suppose your database is returning the same results.
How about providing a custom equals method to each object that retreives an instance of vCloud?
class vCloud {
//Other definitions
public function equals(vCloud $other){
//Return true if $other is same as this class (has same client_id etc etc)
}
}
So you just need to do as the code says:
$vcloud1 = new vCloud('user1', 'system');
$vcloud2 = new vCloud('user2', 'org');
if($vcloud1.equals($vclous2)){
echo "Entries are the same";
} else {
echo "Entries are NOT the same";
}
Also you may need to have various getter and setter methods into your class definitions. What is needed for you to do is to fill the equals method.

issue is sending sms using php and external class

I want to send sms for registration users.
my sms getway provider using SOAP to connect users to api.
this is how code works:
function sendSMS($mobile, $text){
ini_set("soap.wsdl_cache_enabled", "0");
$value = array('MY USER', 'My pass', 'my sms server number', user mobile number, $text, '1');
$url = 'http://mysmsmprovider.com/WebService/V4/BoxService.asmx?wsdl';
$method = 'SendMessage';
$param = array('Username' => "$value[0]",'Password' => "$value[1]",'Number' => "$value[2]",'Mobile' => array("$value[3]"),'Message' => "$value[4]",'Type' => "$value[5]");
define($security,1);
require_once ("connection.php");
$request = new connection($url,$method,$param);
$message = $request->connect();
$request->__destruct();
unset($value,$url,$method,$param,$request);
if ($message == 'Send Successfully'){
return 1;
}else{
return 0;
}
}
now the connection.php file contents:
<?php
if(!defined($security)){
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
die();
}
class connection{
public $value;
public $method;
public $url;
public $type;
function __construct($url,$method,$value,$type=''){
$this->value = $value;
$this->method = $method;
$this->url = $url;
$this->type = $type;
}
function connect(){
ini_set("soap.wsdl_cache_enabled", "0");
$client = new SoapClient($this->url);
$result = $client->__SoapCall($this->method, array($this->value));
if($this->type == 'object')
return get_object_vars($result);
$merge = $this->method.'Result';
if($result->$merge->string != '')
return $result->$merge->string;
else
return $result->$merge;
}
function __destruct(){
unset($this->value,$this->url,$this->method,$this->type);
}
}
?>
but when i want use function in top i cant! u make request with android and i'm 100% sure that android part is so fine and good.
the problem is php.
i cant send sms using this code in another php class or php file. but i used it before with same codes!
so whats ur suggestion?

Logging SOAP envelope in third party library

I am attempting to add logging for the envelope generated by a third party library. I am modifying the updateMetadataField() method below.
I am creating $client like so:
$client = new UpdateClient($UPDATE_END_POINT, $USER_AUTH_ARRAY);
I have tried both $this->client->__getLastRequest() and $this->__getLastRequest() with the same error as a result.
When the SoapClient is instantiated trace is set to true.
Error is
Fatal error: Call to undefined method UpdateClient::__getLastRequest()
So how do I correctly access the __getLastRequest() method?
$USER_AUTH_ARRAY = array(
'login'=>"foo",
'password'=>"bar",
'exceptions'=>0,
'trace'=>true,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);
class UpdateClient {
private $client;
public function __construct($endpoint, $auth_array) {
$this->client = new SoapClient($endpoint, $auth_array);
}
public function updateMetadataField($uuid, $key, $value) {
$result = $this->client->updateMetadataField(array(
'assetUuid' => $uuid,
'key' => $key,
'value' => $value)
);
if(is_soap_fault($result)) {
return $result;
}
return $result->return . "\n\n" . $this->client->__getLastRequest();
} // updateMetadataField()
} // UpdateClient
UPDATE - adding calling code This code iterates over an array which maps our data to the remote fields.
What I am hoping to do is begin storing the envelope we send to aid in debugging.
$client = new UpdateClient($UPDATE_END_POINT, $USER_AUTH_ARRAY);
foreach ($widen_to_nool_meta_map as $widen => $nool) { // array defined in widen.php
if ($nool != '') {
// handle exceptions
if ($nool == 'asset_created') { // validate as date - note that Widen pulls exif data so we don't need to pass this
if (!strtotime($sa->$nool)) {
continue;
}
} else if ($nool == 'people_in_photo' || $nool == 'allow_sublicensing' || $nool == 'allowed_use_pr_gallery') {
// we store as 0/1 but GUI at Widen wants Yes/No
$sa->$nool = ($sa->$nool == '1') ? 'Yes' : 'No';
} else if ($nool == 'credit_requirements') {
$sa->$nool = $sa->credit_requirements()->label;
}
$result = $client->updateMetadataField($sa->widen_id, $widen, $sa->$nool);
if(is_soap_fault($result)) {
$sync_result = $sync_result . "\n" . $result->getMessage();
} else {
$sync_result = $sync_result . "\n" . print_r($result, 1);
}
} // nool field set
} // foreach mapped field
If you want to access UpdateClient::__getLastRequest() you have to expose that method on the UpdateClient class since the $client is a private variable. The correct way of calling it is $this->client->__getLastRequest().
Take a look at this working example, as you can see I'm consuming a free web service for testing purposes.
<?php
$USER_AUTH_ARRAY = array(
'exceptions'=>0,
'trace'=>true,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);
class TestClient {
private $client;
public function __construct($endpoint, $auth_array) {
$this->client = new SoapClient($endpoint, $auth_array);
}
public function CelsiusToFahrenheit( $celsius ) {
$result = $this->client->CelsiusToFahrenheit(array(
'Celsius' => $celsius
)
);
if(is_soap_fault($result)) {
return $result;
}
return $result;
}
public function __getLastRequest() {
return $this->client->__getLastRequest();
}
}
try
{
$test = new TestClient( "http://www.w3schools.com/webservices/tempconvert.asmx?wsdl", $USER_AUTH_ARRAY);
echo "<pre>";
var_dump($test->CelsiusToFahrenheit( 0 ));
var_dump($test->__getLastRequest());
var_dump($test->CelsiusToFahrenheit( 20 ));
var_dump($test->__getLastRequest());
echo "</pre>";
}
catch (SoapFault $fault)
{
echo $fault->faultcode;
}
?>

jaxl return to function that it's called from

I have library for xmpp transactions used jaxl libraries:
class xmpp{
public function register_user($username, $password){
require_once 'JAXL/jaxl.php';
$this->client = new JAXL(array(
'jid' => 'localhost',
'log_level' => JAXL_ERROR
));
$this->username = $username;
$this->password = $password;
$this->client->require_xep(array(
'0077' // InBand Registration
));
$thisClassObject =& $this;
$this->client->add_cb('on_stream_features', function($stanza) use(&$thisClassObject) {
$thisClassObject->client->xeps['0077']->get_form('localhost');
return array($thisClassObject, 'wait_for_register_form');
});
$this->client->start();
return;
}
public function wait_for_register_response($event, $args) {
if($event == 'end_stream') {
return;
}
else if($event == 'stanza_cb') {
$stanza = $args[0];
if($stanza->name == 'iq') {
if($stanza->attrs['type'] == 'result') {
echo "registration successful".PHP_EOL."shutting down...".PHP_EOL;
$this->client->end_stream();
return 'logged_out';
}
else if($stanza->attrs['type'] == 'error') {
$error = $stanza->exists('error');
echo "registration failed with error code: ".$error->attrs['code']." and type: ".$error->attrs['type'].PHP_EOL;
echo "error text: ".$error->exists('text')->text.PHP_EOL;
echo "shutting down...".PHP_EOL;
$this->client->end_stream();
return "logged_out";
}
}
}
}
public function wait_for_register_form($event, $args) {
$stanza = $args[0];
$query = $stanza->exists('query', NS_INBAND_REGISTER);
if($query) {
$form = array();
$instructions = $query->exists('instructions');
if($instructions) {
echo $instructions->text.PHP_EOL;
}
$this->client->xeps['0077']->set_form($stanza->attrs['from'], array('username' => $this->username, 'password' => $this->password));
return array($this, "wait_for_register_response");
}
else {
$this->client->end_stream();
return "logged_out";
}
}
}
these code are same as register_user.php, but implemented in a class;
i use this class in my code in this way:
$xmppObj = new xmpp();
$xmppObj('user','password');
/*
some more code after this
/*
when it execute , create user successfully but it's print a message ('registration successful ...') and application exited and it doesn't execute "some code after this" after the class function, in the other word it doesn't follow the code...
What can I do for solve this problem, a person can help me that familiar with JAXL library.
Looks like you are pretty much using the same code as found inside examples/register_user.php. Once user registration is successful, script closes XMPPStream as evident from this section of the code:
if($stanza->attrs['type'] == 'result') {
echo "registration successful".PHP_EOL."shutting down...".PHP_EOL;
$this->client->end_stream();
return 'logged_out';
}
You MUST instead call $client->send_end_stream(); and not $client->end_stream();. This will make sure underlying XMPPStream makes proper FSM state transition. Also add a callback for on_disconnect event, inside this callback you can again try to connect back with newly registered XMPP account and it should just work fine.
Note: Kindly checkout latest code from the repository. I made some updates which will allow core JAXLLoop to be re-initialized. If you are interested in details, here is the commit log.

Categories