Currently I doing a project by using hitbox.tv api plug in to my website. I would like to update my video title during when I'm broadcasting live stream. I using guzzle 6 to send http request to api end point, the following is my code
myGuzzle.php
<?php
namespace myGuzzle;
require __DIR__.'/../vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
class myGuzzle{
public $params;
public $method;
public $endpoint;
public $body;
public $status;
public $errorJson;
function response($params=[],$method,$endpoint) {
$this->params = $params;
$this->method = $method;
$this->endpoint = $endpoint;
$client = new Client();
try{
$response = $client->request($this->method, $this->endpoint,['json' => $this->params]);
$this->body = $response->getBody();
$this->status = $response->getStatusCode();
}
catch(ClientException $e){
$this->body = $e->getMessage();
$this->status = $e->getCode();
$this->errorJson = $e->getResponse()->getBody();
}
}
function getStatus(){
return $this->status;
}
function getBody(){
return $this->body;
}
function getErrorJson(){
return $this->errorJson;
}
}
updateLiveMedia.php
namespace models;
use myGuzzle\myGuzzle;
class updateLiveMedia {
protected $username;
protected $access_token;
public $media_user_name;
public $media_id;
public $media_category_id;
public $media_live_delay;
public $media_hidden;
public $media_recording;
public $media_mature;
public $media_hosted_name;
public $media_countries = [];
public $media_status;
public $media_description;
function __construct($username,$acessToken) {
$this->username = $username;
$this->access_token = $acessToken;
$this->media_countries = ["EN"];
$this->media_category_id = '0';
$this->media_recording = "1";
$this->media_mature ='0';
$this->media_user_name = $this->username;
$this->media_hosted_name = "on";
$this->media_live_delay='2';
$this->media_hidden = '0';
}
/*
* Parameters function(title,descritption) or
* Parameters function(title,description,countries).
*/
function update($opts=[]){
if(is_array($opts)){
foreach($opts as $key=>$value){
$this->$key = $value;
}
}
$myGuzzle = new myGuzzle;
$uri = "https://api.hitbox.tv/media/live/".$this->username."?authToken=".$this->access_token;
$params = ["livestream"=>[
[
"media_user_name"=>$this->username,
"media_id"=>$this->media_id,
"media_category_id"=>$this->media_category_id,
"media_live_delay"=>$this->media_live_delay,
"media_hidden"=>$this->media_hidden,
"media_recording"=>$this->media_recording,
"media_mature"=>$this->media_mature,
"media_hosted_name"=>$this->media_hosted_name,
"media_countries"=> $this->media_countries,
"media_status"=>$this->media_status,
"media_description"=>$this->media_description,
]
]];
$myGuzzle->response($params,"PUT",$uri);
return $myGuzzle->getBody();
if($myGuzzle->getStatus() == 200){
return true;
}
return false;
}
}
run update() return the following result
{"success":true,"error":false,"message":"host_mode_enabled"}
According the documentation provided by hitbox.tv (http://developers.hitbox.tv/#update-live-media) should return something like the following
{
"livestream": [
{
"media_user_name": "masta",
"media_id": "1",
"media_category_id": "447",
"media_live_delay": "0",
"media_hidden": "0",
"media_recording": "1",
"media_mature": "0",
"media_countries": [
"EN"
],
"media_status": "This is a stream title!",
"media_description_md": null
}
]
}
The API documentation for update-live-media describes the response to be expected only when the hosting flag is not being modified.
The other cases would return different types of answers:
When host mode is being enabled
{"success":true,"error":false,"message":"host_mode_enabled"}
When host mode is being disabled
{"success":true,"error":false,"message":"host_mode_disabled"}
And an error would also return something different than the documentation, for example:
If the authToken/media_id is invalid or there is insufficient permissions
{"success":true,"error":false,"message":"auth_required_token"} or
{"success":true,"error":false,"message":"auth_required"}
When you are updating the hosting mode, you won't be updating any other information (title). Just try to leave out media_hosted_name from your query, and watch how description and titles get updated. Users (and chat bots) then can see the updated information.
Let me know if you still are having any trouble with the API. I would need a specific example and could help you further.
Related
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.
BotMan Version: 2.1
PHP Version:7.3
Messaging Service(s):
Cache Driver: SymfonyCache
Description:
I trying to have conversation. In every next method I lost data from conversation properties, that was saved in properties before!
class GetAlertDataConversation extends AppConversation
{
public $bot;
public $alertTitle;
public $alertDescription;
public $alertLatitude;
public $alertLongitude;
public $alertAuthorId;
public $alertAuthorName;
public function __construct($bot)
{
$this->bot = $bot;
}
private function askTitle()
{
$this->ask('Что случилось? (кратко)', function (Answer $answer) {
$this->alertTitle = $this->askSomethingWithLettersCounting($answer->getText(), 'Слишком коротко!', 'askDescription');
\Yii::warning($this->alertTitle);
});
}
public function askDescription()
{
$this->ask('Расскажи подробней!', function (Answer $answer) {
$this->alertDescription = $this->askSomethingWithLettersCounting($answer->getText(), 'Слишком коротко!', 'askLocation');
\Yii::warning($this->alertTitle);
});
}
private function askLocation()
{
\Yii::warning($this->alertTitle);
$this->askForLocation('Локация?', function (Location $location) {
// $location is a Location object with the latitude / longitude.
$this->alertLatitude = $location->getLatitude();
$this->alertLongitude = $location->getLongitude();
$this->endConversation();
return true;
});
}
private function endConversation()
{
\Yii::warning($this->alertTitle);
$alertId = $this->saveAlertData();
if ($alertId)
$this->say("Событие номер {$alertId} зарегистрировано!");
else
$this->say("Ошибка при сохранении события, обратитесь к администратору!");
}
private function saveAlertData()
{
$user = $this->bot->getUser();
$this->alertAuthorId = $user->getId();
$this->alertAuthorName = $user->getFirstName() . ' ' . $user->getLastName();
$alert = new Alert();
\Yii::warning($this->alertTitle);
$alert->name = $this->alertTitle;
$alert->description = $this->alertDescription;
$alert->latitude = $this->alertLatitude;
$alert->longitude = $this->alertLongitude;
$alert->author_id = $this->alertAuthorId;
$alert->author_name = $this->alertAuthorName;
$alert->chat_link = '';
$alert->additional = '';
if ($alert->validate()) {
$alert->save();
return $alert->id;
} else {
\Yii::warning($alert->errors);
\Yii::warning($alert);
return false;
}
}
}
There is user's text answer in the first \Yii::warning($this->alertTitle); in the askTitle() function.
But all other \Yii::warning($this->alertTitle); returns NULL!!!!
As the result, saving of Alert object not working!
Please, help me. Some ideas?
I think, that it can be by some caching + serialise problem.
I was trying to change cache method to Redis. Same result.
Problem was in this function call and caching:
$this->askSomethingWithLettersCounting($answer->getText(), 'Слишком коротко!', 'askDescription');
If you will read other conversation botman issues in github, you wil see, that most of issues in conversation cache and serialise.
Not any PHP code of conversation can be cached right.
In this case, not direct call of functions askDescription() and askLocation() broken conversation caching.
I fixed that by removing askSomethingWithLettersCounting() function.
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.
I tried to find out gotowebinar api in php but didn't get it. So, I have tried to write a simple class which can be useful. It does authentication which is same for gotowebinar, gotomeeting and rest. It fetches the upcoming webinar, all webinars, single webinar information, registrants fields and also create registrant. Now you all can enhance it as you want. Any suggestion would be much appericiated.
help.txt
1) First change the GOTO_WEBINAR_API_KEY in
gotoWebinarClass.php to your appication key.
2) Then change the
REDIRECT_URL_AFTER_AUTHENTICATION in
authorize.php. It is a url where one should be redirected after
authentication.
3) Execute authorize.php.
4) After you autheticate,
it would take you to
REDIRECT_URL_AFTER_AUTHENTICATION with "code" in the query
string.
5) Copy that code and execute the authorize.php again with ?
code='your_code' in the query string.
6) If everything goes fine, we will get the token and we will set into session and be redirected to get-all-webinars.php
which fetches user's all webinars.
This class is not complete, I have laid down the basic
foundation, now you can keep on adding the other functions. Any
suggestion from your side would be much appriciated. Thanks.
gotoWebinarClass.php
<?php
define('GOTO_WEBINAR_API_KEY','your gotowebinar application key');
class OAuth_En{
protected $_accessToken;
protected $_userId;
protected $_organizerKey;
protected $_refreshToken;
protected $_expiresIn;
public function getAccessToken(){
return $this->_accessToken;
}
public function setAccessToken($token){
$this->_accessToken = $token;
}
public function getUserId(){
return $this->_userId;
}
public function setUserId($id){
$this->_userId = $id;
}
public function getOrganizerKey(){
return $this->_organizerKey;
}
public function setOrganizerKey($key){
$this->_organizerKey = $key;
}
public function getRefreshToken(){
return $this->_refreshToken;
}
public function setRefreshToken($token){
$this->_refreshToken = $token;
}
public function getExpiresIn(){
return $this->_expiresIn;
}
public function setExpiresIn($expiresIn){
$this->_expiresIn = $expiresIn;
}
}
class OAuth_Db{
function getToken(){
}
}
class OAuth{
protected $_redirectUrl;
protected $_OAuthEnObj;
protected $_curlHeader = array();
protected $_apiResponse;
protected $_apiError;
protected $_apiErrorCode;
protected $_apiRequestUrl;
protected $_apiResponseKey;
protected $_accessTokenUrl;
protected $_webinarId;
protected $_registrantInfo = array();
protected $_apiRequestType;
protected $_apiPostData;
public function __construct(OAuth_En $oAuthEn){
$this->_OAuthEnObj = $oAuthEn;
}
public function getOAuthEntityClone(){
return clone $this->_OAuthEnObj;
}
public function getWebinarId(){
return $this->_webinarId;
}
public function setWebinarId($id){
$id = (int)$id;
$this->_webinarId = empty($id) ? 0 : $id;
}
public function setApiErrorCode($code){
$this->_apiErrorCode = $code;
}
public function getApiErrorCode(){
return $this->_apiErrorCode;
}
public function getApiAuthorizationUrl(){
return 'https://api.citrixonline.com/oauth/authorize?client_id='.GOTO_WEBINAR_API_KEY.'&redirect_uri='.$this->getRedirectUrl();
}
public function getApiKey(){
return GOTO_WEBINAR_API_KEY;
}
public function getApiRequestUrl(){
return $this->_apiRequestUrl;
}
public function setApiRequestUrl($url){
$this->_apiRequestUrl = $url;
}
public function setRedirectUrl($url){
$this->_redirectUrl = urlencode($url);
}
public function getRedirectUrl(){
return $this->_redirectUrl;
}
public function setCurlHeader($header){
$this->_curlHeader = $header;
}
public function getCurlHeader(){
return $this->_curlHeader;
}
public function setApiResponseKey($key){
$this->_apiResponseKey = $key;
}
public function getApiResponseKey(){
return $this->_apiResponseKey;
}
public function setRegistrantInfo($arrInfo){
$this->_registrantInfo = $arrInfo;
}
public function getRegistrantInfo(){
return $this->_registrantInfo;
}
public function authorizeUsingResponseKey($responseKey){
$this->setApiResponseKey($responseKey);
$this->setApiTokenUsingResponseKey();
}
protected function setAccessTokenUrl(){
$url = 'https://api.citrixonline.com/oauth/access_token?grant_type=authorization_code&code={responseKey}&client_id={api_key}';
$url = str_replace('{api_key}', $this->getApiKey(), $url);
$url = str_replace('{responseKey}', $this->getApiResponseKey(), $url);
$this->_accessTokenUrl = $url;
}
protected function getAccessTokenUrl(){
return $this->_accessTokenUrl;
}
protected function resetApiError(){
$this->_apiError = '';
}
public function setApiTokenUsingResponseKey(){
//set the access token url
$this->setAccessTokenUrl();
//set the url where api should go for request
$this->setApiRequestUrl($this->getAccessTokenUrl());
//make request
$this->makeApiRequest();
if($this->hasApiError()){
echo $this->getApiError();
}else{
//if api does not have any error set the token
echo $this->getResponseData();
$responseData = json_decode($this->getResponseData());
$this->_OAuthEnObj->setAccessToken($responseData->access_token);
$this->_OAuthEnObj->setOrganizerKey($responseData->organizer_key);
$this->_OAuthEnObj->setRefreshToken($responseData->refresh_token);
$this->_OAuthEnObj->setExpiresIn($responseData->expires_in);
}
}
function hasApiError(){
return $this->getApiError() ? 1 : 0;
}
function getApiError(){
return $this->_apiError;
}
function setApiError($errors){
return $this->_apiError = $errors;
}
function getApiRequestType(){
return $this->_apiRequestType;
}
function setApiRequestType($type){
return $this->_apiRequestType = $type;
}
function getResponseData(){
return $this->_apiResponse;
}
function setApiPostData($data){
return $this->_apiPostData = $data;
}
function getApiPostData(){
return $this->_apiPostData;
}
function makeApiRequest(){
$header = array();
$this->getApiRequestUrl();
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_URL, $this->getApiRequestUrl());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if($this->getApiRequestType()=='POST'){
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->getApiPostData());
}
if($this->getCurlHeader()){
$headers = $this->getCurlHeader();
}else{
$headers = array(
"HTTP/1.1",
"Content-type: application/json",
"Accept: application/json",
"Authorization: OAuth oauth_token=".$this->_OAuthEnObj->getAccessToken()
);
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = curl_exec($ch);
$validResponseCodes = array(200,201,409);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->resetApiError();
if (curl_errno($ch)) {
$this->setApiError(array(curl_error($ch)));
} elseif(!in_array($responseCode, $validResponseCodes)){
if($this->isJsonString($data)){
$data = json_decode($data);
}
$this->setApiError($data);
$this->setApiErrorCode($responseCode);
}else {
$this->_apiResponse = $data;
$_SESSION['gotoApiResponse'] = $this->getResponseData();
curl_close($ch);
}
}
function isAuthorizationRequiredAgain(){
$arrAuthorizationRequiredCodes = array(400,401,403,500);
$isAuthRequired = 0;
$error = $this->getApiError();
$responseCode = $this->getApiErrorCode();
//we might have to add more exception in this condition
if(in_array($responseCode, $arrAuthorizationRequiredCodes)){
if($responseCode==400 && is_object($error)){ //because for 400 error sometime one needs to authenticate again
foreach($error as $single){
$pos = strpos($single,'Authorization');
if($pos!==false){
$isAuthRequired = 1;
}
}
}else{
$isAuthRequired = 1;
}
}
return $isAuthRequired;
}
function getWebinars(){
$url = 'https://api.citrixonline.com/G2W/rest/organizers/'.$this->_OAuthEnObj->getOrganizerKey().'/webinars';
$this->setApiRequestUrl($url);
$this->setApiRequestType('GET');
$this->makeApiRequest();
if($this->hasApiError()){
return null;
}
$webinars = json_decode($this->getResponseData());
return $webinars;
}
function getWebinar(){
if(!$this->getWebinarId()){
$this->setApiError(array('Webinar id not provided'));
return null;
}
$this->setApiRequestType('GET');
$url = 'https://api.citrixonline.com/G2W/rest/organizers/'.$this->_OAuthEnObj->getOrganizerKey().'/webinars/'.$this->getWebinarId();
$this->setApiRequestUrl($url);
$this->makeApiRequest();
if($this->hasApiError()){
return null;
}
$webinar = json_decode($this->getResponseData());
return $webinar;
}
function getUpcomingWebinars(){
$url = 'https://api.citrixonline.com/G2W/rest/organizers/'.$this->_OAuthEnObj->getOrganizerKey().'/upcomingWebinars';
$this->setApiRequestUrl($url);
$this->setApiRequestType('GET');
$this->makeApiRequest();
if($this->hasApiError()){
return null;
}
$webinars = json_decode($this->getResponseData());
return $webinars;
}
function createRegistrant(){
if(!$this->getWebinarId()){
$this->setApiError(array('Webinar id not provided'));
return null;
}
if(!$this->getRegistrantInfo()){
$this->setApiError(array('Registrant info not provided'));
return null;
}
$this->setApiRequestType('POST');
$this->setApiPostData(json_encode($this->getRegistrantInfo()));
$url = 'https://api.citrixonline.com/G2W/rest/organizers/'.$this->_OAuthEnObj->getOrganizerKey().'/webinars/'.$this->getWebinarId().'/registrants';
$this->setApiRequestUrl($url);
$this->makeApiRequest();
if($this->hasApiError()){
return null;
}
$webinar = json_decode($this->getResponseData());
return $webinar;
}
function getWebinarRegistrantsFields(){
if(!$this->getWebinarId()){
$this->setApiError(array('Webinar id not provided'));
return null;
}
$url = 'https://api.citrixonline.com/G2W/rest/organizers/'.$this->_OAuthEnObj->getOrganizerKey().'/webinars/'.$this->getWebinarId().'/registrants/fields';
$this->setApiRequestUrl($url);
$this->setApiRequestType('GET');
$this->makeApiRequest();
if($this->hasApiError()){
return null;
}
$registrantFields = json_decode($this->getResponseData());
return $registrantFields;
}
function isJsonString($string){
$isJson = 0;
$decodedString = json_decode($string);
if(is_array($decodedString) || is_object($decodedString))
$isJson = 1;
return $isJson;
}
}
Authorize.php
<?php
include_once "gotoWebinarClass.php";
define('REDIRECT_URL_AFTER_AUTHENTICATION','http://url where we want to redirect'); //this is the url where your get token code would be written.
session_start();
$obj = new OAuth_En();
$oauth = new OAuth($obj);
if(!isset($_GET['code'])){
goForAuthorization();
}else{ //when user authenticates and redirect back to application redirect url, get the token
$oauth->authorizeUsingResponseKey($_GET['code']);
if(!$oauth->hasApiError()){
$objOAuthEn = $oauth->getOAuthEntityClone();
$_SESSION['oauthEn'] = serialize($objOAuthEn);
header('Location: get-all-webinars.php');
}
}
//this function has been used for getting the key using which we can get the access token and organizer key
function goForAuthorization(){
global $oauth;
$oauth->setRedirectUrl(REDIRECT_URL_AFTER_AUTHENTICATION);
$url = $oauth->getApiAuthorizationUrl();
header('Location: '.$url);
}
get-all-webinars.php
<?php
include_once "gotoWebinarClass.php";
session_start();
$obj = unserialize($_SESSION['oauthEn']);
/*
this can be used to fetch the stored access token key and organizer key from database and use it without asking the authetication from user again
$obj = new OAuth_En();
$obj->setAccessToken('token');
$obj->setOrganizerKey('organizer key');
*/
$oauth = new OAuth($obj);
$webinars = $oauth->getWebinars();
echo '<pre>';
if(!$oauth->hasApiError()){
print_r($webinars);
}else{
print_r($oauth->getApiError());
}
exit;
/*$webinars = $oauth->getUpcomingWebinars();
if(!$oauth->hasApiError()){
print_r($webinars);
}else{
print_r($oauth->getApiError());
}
exit;
$registrantInfo = array(
"firstName"=>"ashish",
"lastName"=>"mehta",
"email"=>"test#test.com",
);
$oauth->setWebinarId(525120321);
$oauth->setRegistrantInfo($registrantInfo);
$res = $oauth->createRegistrant();
echo $oauth->getApiErrorCode();
if(!$oauth->hasApiError()){
print_r($res);
}else{
echo 'error';
print_r($oauth->getApiError());
}
exit;
$oauth->setWebinarId(525120321);
$webinar = $oauth->getWebinar();
if(!$oauth->hasApiError()){
print_r($webinar);
}else{
print_r($oauth->getApiError());
echo $oauth->getApiErrorCode();
}
*/
Suggestion #1: AMAZING CLASS! :)
Suggestion #2: Because I didn't really have to do any actual "work" to implement your class, I had some trouble with submitting custom question responses when creating a registrant.
This is because if you use custom fields, you need to add an additional parameter to the header:
Accept: application/vnd.citrix.g2wapi-v1.1+json
Other than that this class is MONEY IN THE BANK! Thanks for this you saved me a TON of time (and only had to focus on one problem instead of 30).
I've been trying this class and it is really helpful and great. :)
The only problem I am encountering is that when it redirects to GotoWebinar, it would first ask me to enter my username and password before it returns the Array containing the upcoming webinars.
Is there a way to auto-login to GotoWebinar by using POST or any other code so that I won't have to manually enter the username and password? Here is my current code for the authorize.php.
I tried the Direct Login, https://developer.citrixonline.com/page/direct-login. However, it would return the information of my user account. But it would not redirect to the page that will generate the webinars.
Thanks a lot!
I am developing a Facebook app in Zend Framework. In startAction() I am getting the following error:
The URL http://apps.facebook.com/rails_across_europe/turn/move-trains-auto is not valid.
I have included the code for startAction() below. I have also included the code for moveTrainsAutoAction (these are all TurnController actions) I can't find anything wrong with my _redirect() in startAction(). I am using the same redirect in other actions and they execute flawlessly. Would you please review my code and let me know if you find a problem? I appreciate it! Thanks.
public function startAction() {
require_once 'Train.php';
$trainModel = new Train();
$config = Zend_Registry::get('config');
require_once 'Zend/Session/Namespace.php';
$userNamespace = new Zend_Session_Namespace('User');
$trainData = $trainModel->getTrain($userNamespace->gamePlayerId);
switch($trainData['type']) {
case 'STANDARD':
default:
$unitMovement = $config->train->standard->unit_movement;
break;
case 'FAST FREIGHT':
$unitMovement = $config->train->fast_freight->unit_movement;
break;
case 'SUPER FREIGHT':
$unitMovement = $config->train->superfreight->unit_movement;
break;
case 'HEAVY FREIGHT':
$unitMovement = $config->train->heavy_freight->unit_movement;
break;
}
$trainRow = array('track_units_remaining' => $unitMovement);
$where = $trainModel->getAdapter()->quoteInto('id = ?', $trainData['id']);
$trainModel->update($trainRow, $where);
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto');
}
.
.
.
public function moveTrainsAutoAction() {
$log = Zend_Registry::get('log');
$log->debug('moveTrainsAutoAction');
require_once 'Train.php';
$trainModel = new Train();
$userNamespace = new Zend_Session_Namespace('User');
$gameNamespace = new Zend_Session_Namespace('Game');
$trainData = $trainModel->getTrain($userNamespace->gamePlayerId);
$trainRow = $this->_helper->moveTrain($trainData['dest_city_id']);
if(count($trainRow) > 0) {
if($trainRow['status'] == 'ARRIVED') {
// Pass id for last city user selected so we can return user to previous map scroll postion
$this->_redirect($config->url->absolute->fb->canvas . '/turn/unload-cargo?city_id='.$gameNamespace->endTrackCity);
} else if($trainRow['track_units_remaining'] > 0) {
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto');
} else { /* Turn has ended */
$this->_redirect($config->url->absolute->fb->canvas . '/turn/end');
}
}
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto-error'); //-set-destination-error');
}
As #Jani Hartikainen points out in his comment, there is really no need to URL-encode underscores. Try to redirect with literal underscores and see if that works, since I believe redirect makes some url encoding of its own.
Not really related to your question, but in my opinion you should refactor your code a bit to get rid of the switch-case statements (or at least localize them to a single point):
controllers/TrainController.php
[...]
public function startAction() {
require_once 'Train.php';
$trainTable = new DbTable_Train();
$config = Zend_Registry::get('config');
require_once 'Zend/Session/Namespace.php';
$userNamespace = new Zend_Session_Namespace('User');
$train = $trainTable->getTrain($userNamespace->gamePlayerId);
// Add additional operations in your getTrain-method to create subclasses
// for the train
$trainTable->trackStart($train);
$this->_redirect(
$config->url->absolute->fb->canvas . '/turn/move-trains-auto'
);
}
[...]
models/dbTable/Train.php
class DbTable_Train extends Zend_Db_Table_Abstract
{
protected $_tableName = 'Train';
[...]
/**
*
*
* #return Train|false The train of $playerId, or false if the player
* does not yet have a train
*/
public function getTrain($playerId)
{
// Fetch train row
$row = [..];
return $this->trainFromDbRow($row);
}
private function trainFromDbRow(Zend_Db_Table_Row $row)
{
$data = $row->toArray();
$trainType = 'Train_Standard';
switch($row->type) {
case 'FAST FREIGHT':
$trainType = 'Train_Freight_Fast';
break;
case 'SUPER FREIGHT':
$trainType = 'Train_Freight_Super';
break;
case 'HEAVY FREIGHT':
$trainType = 'Train_Freight_Heavy';
break;
}
return new $trainType($data);
}
public function trackStart(Train $train)
{
// Since we have subclasses here, polymorphism will ensure that we
// get the correct speed etc without having to worry about the different
// types of trains.
$trainRow = array('track_units_remaining' => $train->getSpeed());
$where = $trainModel->getAdapter()->quoteInto('id = ?', $train->getId());
$this->update($trainRow, $where);
}
[...]
/models/Train.php
abstract class Train
{
public function __construct(array $data)
{
$this->setValues($data);
}
/**
* Sets multiple values on the model by calling the
* corresponding setter instead of setting the fields
* directly. This allows validation logic etc
* to be contained in the setter-methods.
*/
public function setValues(array $data)
{
foreach($data as $field => $value)
{
$methodName = 'set' . ucfirst($field);
if(method_exists($methodName, $this))
{
$this->$methodName($value);
}
}
}
/**
* Get the id of the train. The id uniquely
* identifies the train.
* #return int
*/
public final function getId ()
{
return $this->id;
}
/**
* #return int The speed of the train / turn
*/
public abstract function getSpeed ();
[..] //More common methods for trains
}
/models/Train/Standard.php
class Train_Standard extends Train
{
public function getSpeed ()
{
return 3;
}
[...]
}
/models/Train/Freight/Super.php
class Train_Freight_Super extends Train
{
public function getSpeed ()
{
return 1;
}
public function getCapacity ()
{
return A_VALUE_MUCH_LARGER_THAN_STANDARD;
}
[...]
}
By default, this will send an HTTP 302 Redirect. Since it is writing headers, if any output is written to the HTTP output, the program will stop sending headers. Try looking at the requests and response inside Firebug.
In other case, try using non default options to the _redirect() method. For example, you can try:
$ropts = { 'exit' => true, 'prependBase' => false };
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto', $ropts);
There is another interesting option for the _redirect() method, the code option, you can send for example a HTTP 301 Moved Permanently code.
$ropts = { 'exit' => true, 'prependBase' => false, 'code' => 301 };
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto', $ropts);
I think I may have found the answer. It appears that Facebook does not play nice with redirect, so it is neccessary to use Facebook's 'fb:redirect' FBML. This appears to work:
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
echo '<fb:redirect url="' . $config->url->absolute->fb->canvas . '/turn/move-trains-auto"/>';