Writing to a config file dynamically using PHP - config

Implementing a SAAS (multi-tenant) app, I have a situation where an app would need to connect to different databases based on the user who wants to login. The databases are for separate institutions. Let's say MANAGER-A for institution-A, MANAGER-B for institution-B, want to login into their various institutions.
The process I'm implementing is this: There are 3 databases involved: DEFAULT-DB, INSTITUTION-A-DB, INSTITUTION-B-DB. The DEFAULT-DB contains all the login and database credentials of each user. This means that before MANAGER-A can login to his app, what happens is that, first, he will be logged in into the DEFAULT-DB, if successful, his details would be fetched and logged and set as the parameter of the config.php file. This means that connection will be dynamic based on the params fetched and passed by the DEFAULT-DB. My questions are these:
How do I write these params dynamically to the config.php file?
Secondly, I'm open to experts advise if my implementation is not the best.
Config.php file
<?php
unset($CFG);
global $CFG;
$CFG = new stdClass();
$CFG->dbtype = 'mysqli';
$CFG->dblibrary = 'native';
$CFG->dbhost = 'localhost';
$CFG->dbname = 'mydb';
$CFG->dbuser = 'root';
$CFG->dbpass = '';
$CFG->prefix = 'my_';
$CFG->dboptions = array (
'dbpersist' => 0,
'dbport' => '',
'dbsocket' => '1',
'dbcollation' => 'utf8mb4_unicode_ci',
);
$CFG->wwwroot = 'http://localhost:8888/myapp';
$CFG->dataroot = '/Applications/MAMP/data/myapp_data';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
require_once(dirname(__FILE__) . '/lib/setup.php');
This is Moodle. I have tried IOMAD, it is a great app but does not address my need.

That is a bad solution, IMHO. When you rewrite the configuration file, what happens when the next request comes in that loads that file? They will load the wrong configuration.
I would create two additional configuration files: config_inst_a.php and config_inst_b.php. Then set a session variable when the user logs in that contains the settings file name to load. You can then redefine the database information variables in the additional settings files. If the session variable has a filename in it, load that file AFTER the default config and the database connection values will be replaced.
Added sample code:
Really, really brief:
// Log in user here, and get info about what user company..
$session_start();
$_SESSION['User_ConfigFile'] = 'settings'.$userCompany.'.php';
// More code, or page redirect, or whatever, but the below goes on every page AFTER the default DB is included:
$session_start();
require_once($_SESSION['User_ConfigFile']);

If it helps somebody, my solution, not in production yet, but for now it works like a charm.
if ($_SERVER['SERVER_NAME'] == 'institutionA.mydomain.com') {
$CFG->dbname = 'institutionA'; // database name, eg moodle
$CFG->dbuser = 'user_institutionA'; // your database username
$CFG->wwwroot = 'https://institutionA.mydomain.com';
$CFG->dataroot = 'dataroot_institutionA';
//
$CFG->some_custom_data = 'my_institutiona_data';
} else
if ($_SERVER['SERVER_NAME'] == 'institutionB.mydomain.com') {
$CFG->dbname = 'institutionB'; // database name, eg moodle
$CFG->dbuser = 'user_institutionB'; // your database username
$CFG->wwwroot = 'https://institutionB.mydomain.com';
$CFG->dataroot = 'dataroot_institutionB';
//
$CFG->some_custom_data = 'my_institutionB_data';
} else {
...... anything you need in this case
}

Related

Can't handle HTTP multiple attribute values in Perl

I'm facing with a really strange issue. I interfaced a SAML authentication with OTRS which is an ITSM written in Perl and the Identity Provider sends the attributes as follow :
LoginName : dev-znuny02
mail : test2#company.dev
Profile : company.autre.idp.v2()
Profile : company.autre.mcf.sp(dev)
givenName : MyName
sn : Test2
I handle these with a module called Mod_Auth_Mellon and as you can see the attribute Profile is multivaluated. In short I retrieve all of these values with the following snippet :
sub new {
my ( $Type, %Param ) = #_;
# allocate new hash for object
my $Self = {};
bless( $Self, $Type );
$Self->{ConfigObject} = $Kernel::OM->Get('Kernel::Config');
$Self->{UserObject} = Kernel::System::User->new( %{$Self} );
# Handle header's attributes
$Self->{loginName} = 'MELLON_LoginName';
$Self->{eMail} = 'MELLON_mail';
$Self->{Profile_0} = 'MELLON_Profile_0';
$Self->{Profile_1} = 'MELLON_Profile_1';
$Self->{gName} = 'MELLON_givenName';
$Self->{sName} = 'MELLON_sn';
return $Self;
}
sub Auth {
my ( $Self, %Param ) = #_;
# get params
my $lname = $ENV{$Self->{loginName}};
my $email = $ENV{$Self->{eMail}};
my $profile0 = $ENV{$Self->{Profile_0}};
my $profile1 = $ENV{$Self->{Profile_1}};
my $gname = $ENV{$Self->{gName}};
my $sname = $ENV{$Self->{sName}};
...
}
I can handle all the values of the attributes except the attribute Profile. When I take a look to the documentation, they said :
If an attribute has multiple values, then they will be stored as MELLON_<name>_0, MELLON_<name>_1, MELLON_<name>_2
To be sure, I activated the diagnostics of the Mellon module and indeed I receive the information correctly :
...
MELLON_LoginName : dev_znuny02
MELLON_LoginName_0 : dev_znuny02
MELLON_mail : test2#company.dev
MELLON_mail_0 : test2#company.dev
MELLON_Profile : company.autre.idp.v2()
MELLON_Profile_0 : company.autre.idp.v2()
MELLON_Profile_1 : company.autre.mcf.sp(dev)
...
When I try to manipulate the MELLON_Profile_0 or MELLON_Profile_1 attributes in the Perl script, the variable assigned to it seems empty. Do you have any idea on what can be the issue here ?
Any help is welcome ! Thanks a lot guys
PS : I have no control on the Identity Provider so I can't edit the attributes sent
I didn't managed to make it work but I found a workaround to prevent users who don't have the Profile attribute value from logging into the application:
MellonCond Profile company.autre.mcf.sp(dev)
according the documentation :
You can also utilize SAML attributes to control whether Mellon authentication succeeds (a form of authorization). So even though the IdP may have successfully authenticated the user you can apply additional constraints via the MellonCond directive. The basic idea is that each MellonCond directive specifies one condition that either evaluates to True or False.

Xero Oauth2 Node Examples

I am doing some expermenting with the xero API, however i cant seem to get past the Connect to Xero returning an error
"Sorry, something went wrong
Go back and try again.
If the issue continues, check out our Status Page."
I have setup my App in the xero dev center
I have tried these 2 repos
https://github.com/XeroAPI/xero-node-oauth2-app
https://github.com/XeroAPI/node-oauth2-example
Both yeld the same result just an error page, no information in console/dev tools
Any help would be amazing as im completely stuck with this
So that looks like the error you get when either API keys and/or callback urls are not setup correctly.
Have you swapped in all your api keys & callback urls to the .env (environment) files?
Create a .env file in the root of your project & replace the 3 variables
Create an .env file in the root of your project using touch .env or edit the sample prefix off sample.env and change out with your /myapps credentials of the app you just made.
CLIENT_ID=...
CLIENT_SECRET=...
REDIRECT_URI=...
Here is the library that is used successfully with ouath2.0 tokenization. The token is expired in 30 mints. After that, we need to refresh the token with old token objects.
First set up an app in developer.xero.com.
Add Company Name and Redirect URL while creating the app.
Setup environment configuration in your file.
X_CLIENT_ID=CD43E78278ED4BE68F35F155C3E708F7
X_CLIENT_SECRET=IuP5TrE70JoyYiezMRM2KwvcHFYoLy3qRbD3NFlOkYLN0Asy
X_REDIRECT_URL=https://baseredirecturl.com/xero/default/redirect
Step-1: Here is the code for creating a token and refresh token.
public function actionConnectXero()
{
$session = Yii::$app->session;
$request = Yii::$app->request;
if (empty($request->get('code'))) {
// If we don't have an authorization code then get one
$authUrl = $this->provider->getAuthorizationUrl([
'scope' => 'offline_access openid email profile accounting.settings accounting.transactions accounting.contacts accounting.reports.read projects accounting.journals.read'
]);
//offline_access openid email profile accounting.settings accounting.transactions accounting.contacts accounting.reports.read projects accounting.journals.read
$session->set('oauth2state', $this->provider->getState());
$this->redirect($authUrl);
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($request->get('state')) || ($request->get('state') !== $session->get('oauth2state'))) {
$session->remove('oauth2state');
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $this->provider->getAccessToken('authorization_code', [
'code' => $request->get('code')
]);
$session->set('access_token', $token);
//If you added the openid/profile scopes you can access the authorizing user's identity.
$identity = $this->provider->getResourceOwner($token);
echo "<pre>";
print_r($identity);
//Get the tenants that this user is authorized to access
$tenants = $this->provider->getTenants($token);
print_r($tenants);
$session->set('tenantId', $tenants[0]->tenantId);
exit;
}
}
Step-2: Redirect to URL.
public function actionRedirectXero()
{
$request = Yii::$app->request;
$codeStr = explode("?", $request->getUrl());
$token = $this->provider->getAccessToken('authorization_code', [
'code' => $request->get('code')
]);
$tenants = $this->provider->getTenants($token);
$exits = XeroConfigs::find()->where(['created_by' => Yii::$app->user->identity->id])->one();
$xeroConf = $exits ? XeroConfigs::findOne($exits->id) : new XeroConfigs();
$xeroConf->access_token = $token;
$xeroConf->refresh_token = $token->getRefreshToken();
$xeroConf->expiry = $token->getExpires();
$xeroConf->tenant_id = isset($tenants[0]) ? $tenants[0]->id : 0;
$xeroConf->token_object = serialize($token);
$xeroConf->created_by = Yii::$app->user->identity->id;
$xeroConf->save();
$this->redirect('/xero/default/get-xero-data?'.$codeStr[1]);
}
Step-3: Get data from xero. I just save and get contacts. for more examples, you can check the package documentation.
public function actionGetXeroData(){
$configs = XeroConfigs::find()->where(['created_by' => Yii::$app->user->identity->id])->one();
if($configs->expiry < time()){
$newAccessToken = $this->provider->getAccessToken('refresh_token', [
'grant_type' => 'refresh_token',
'refresh_token' => $configs->refresh_token
]);
$tenants = $this->provider->getTenants($newAccessToken);
$xeroConf = XeroConfigs::findOne($configs->id);
$xeroConf->access_token = $newAccessToken;
$xeroConf->refresh_token = $newAccessToken->getRefreshToken();
$xeroConf->expiry = $newAccessToken->getExpires();
$xeroConf->tenant_id = isset($tenants[0]) ? $tenants[0]->id : 0;;
$xeroConf->token_object = serialize($newAccessToken);;
$xeroConf->updated_at = Carbon::now()->toDateTimeString();
$xeroConf->created_by = Yii::$app->user->identity->id;
$xeroConf->save();
$configs = XeroConfigs::find()->where(['created_by' => Yii::$app->user->identity->id])->one();
}
$tokenObj = unserialize($configs->token_object);
$tenants = $this->provider->getTenants($tokenObj);
$xero = new \XeroPHP\Application($tokenObj, $tenants[0]->tenantId);
$contact = new Contact($xero);
$contact->setName('Hassan Raza')
->setAccountNumber('0245541574185741')
->setContactID('852986')
->setGUID('52552548-5585-8715-8888-871222554154')
->setBankAccountDetail('0245541574185741')
->setTaxNumber('55545352')
->setContactStatus('ACTIVE')
->setSkypeUserName('hassan_raza2010')
->setTrackingCategoryName('Manager')
->setFirstName('Hassan')
->setLastName('Raza')
->setEmailAddress('hassan#xero.com');
$response = $contact->save();
dd($response->getResponseBody());

Paypal Php Sdk - NotifyUrl is not a fully qualified URL Error

I have this code
$product_info = array();
if(isset($cms['site']['url_data']['product_id'])){
$product_info = $cms['class']['product']->get($cms['site']['url_data']['product_id']);
}
if(!isset($product_info['id'])){
/*
echo 'No product info.';
exit();
*/
header_url(SITE_URL.'?subpage=user_subscription#xl_xr_page_my%20account');
}
$fee = $product_info['yearly_price_end'] / 100 * $product_info['fee'];
$yearly_price_end = $product_info['yearly_price_end'] + $fee;
$fee = ($product_info['setup_price_end'] / 100) * $product_info['fee'];
$setup_price_end = $product_info['setup_price_end'] + $fee;
if(isset($_SESSION['discountcode_amount'])){
$setup_price_end = $setup_price_end - $_SESSION['discountcode_amount'];
unset($_SESSION['discountcode_amount']);
}
$error = false;
$plan_id = '';
$approvalUrl = '';
$ReturnUrl = SITE_URL.'payment/?payment_type=paypal&payment_page=process_agreement';
$CancelUrl = SITE_URL.'payment/?payment_type=paypal&payment_page=cancel_agreement';
$now = $cms['date'];
$now->modify('+5 minutes');
$apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential(
$cms['options']['plugin_paypal_clientid'], // ClientID
$cms['options']['plugin_paypal_clientsecret'] // ClientSecret
)
);
use PayPal\Api\ChargeModel;
use PayPal\Api\Currency;
use PayPal\Api\MerchantPreferences;
use PayPal\Api\PaymentDefinition;
use PayPal\Api\Plan;
use PayPal\Api\Patch;
use PayPal\Api\PatchRequest;
use PayPal\Common\PayPalModel;
use PayPal\Api\Agreement;
use PayPal\Api\Payer;
use PayPal\Api\ShippingAddress;
// Create a new instance of Plan object
$plan = new Plan();
// # Basic Information
// Fill up the basic information that is required for the plan
$plan->setName($product_info['name'])
->setDescription($product_info['desc_text'])
->setType('fixed');
// # Payment definitions for this billing plan.
$paymentDefinition = new PaymentDefinition();
// The possible values for such setters are mentioned in the setter method documentation.
// Just open the class file. e.g. lib/PayPal/Api/PaymentDefinition.php and look for setFrequency method.
// You should be able to see the acceptable values in the comments.
$setFrequency = 'Year';
//$setFrequency = 'Day';
$paymentDefinition->setName('Regular Payments')
->setType('REGULAR')
->setFrequency($setFrequency)
->setFrequencyInterval("1")
->setCycles("999")
->setAmount(new Currency(array('value' => $yearly_price_end, 'currency' => $cms['session']['client']['currency']['iso_code'])));
// Charge Models
$chargeModel = new ChargeModel();
$chargeModel->setType('SHIPPING')
->setAmount(new Currency(array('value' => 0, 'currency' => $cms['session']['client']['currency']['iso_code'])));
$paymentDefinition->setChargeModels(array($chargeModel));
$merchantPreferences = new MerchantPreferences();
// ReturnURL and CancelURL are not required and used when creating billing agreement with payment_method as "credit_card".
// However, it is generally a good idea to set these values, in case you plan to create billing agreements which accepts "paypal" as payment_method.
// This will keep your plan compatible with both the possible scenarios on how it is being used in agreement.
$merchantPreferences->setReturnUrl($ReturnUrl)
->setCancelUrl($CancelUrl)
->setAutoBillAmount("yes")
->setInitialFailAmountAction("CONTINUE")
->setMaxFailAttempts("0")
->setSetupFee(new Currency(array('value' => $setup_price_end, 'currency' => $cms['session']['client']['currency']['iso_code'])));
$plan->setPaymentDefinitions(array($paymentDefinition));
$plan->setMerchantPreferences($merchantPreferences);
// ### Create Plan
try {
$output = $plan->create($apiContext);
} catch (Exception $ex){
die($ex);
}
echo $output->getId().'<br />';
echo $output.'<br />';
Been working with paypal php sdk for some days now and my code stop working.
So i went back to basic and i am still getting the same damn error.
I am trying to create a plan for subscription but getting the following error:
"NotifyUrl is not a fully qualified URL"
I have no idea how to fix this as i dont use NotfifyUrl in my code?
Could be really nice if anyone had an idea how to fix this problem :)
Thanks
PayPal did a update to their API last night which has caused problem within their SDK.
They are sending back null values in their responses.
I MUST stress the error is not on sending the request to PayPal, but on processing their response.
BUG Report : https://github.com/paypal/PayPal-PHP-SDK/issues/1151
Pull Request : https://github.com/paypal/PayPal-PHP-SDK/pull/1152
Hope this helps, but their current SDK is throwing exceptions.
Use below simple fix.
Replace below function in vendor\paypal\rest-api-sdk-php\lib\PayPal\Api\MerchantPreferences.php
public function setNotifyUrl($notify_url)
{
if(!empty($notify_url)){
UrlValidator::validate($notify_url, "NotifyUrl");
}
$this->notify_url = $notify_url;
return $this;
}
If you get the same error for return_url/cancel_url, add the if condition as above.
Note: This is not a permanent solution, you can use this until getting the update from PayPal.
From the GitHub repo for the PayPal PHP SDK, I see that the error you mentioned is thrown when MerchantPreferences is not given a valid NotifyUrl. I see you're setting the CancelUrl and ReturnUrl, but not the NotifyUrl. You may simply need to set that as well, i.e.:
$NotifyUrl = (some url goes here)
$obj->setNotifyUrl($NotifyUrl);
Reason behind it!
error comes from.
vendor\paypal\rest-api-sdk-php\lib\PayPal\Validation\UrlValidator.php
line.
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
throw new \InvalidArgumentException("$urlName is not a fully qualified URL");
}
FILTER_VALIDATE_URL: according to this php function.
INVALID URL: "http://cat_n.domain.net.in/"; // IT CONTAIN _ UNDERSCORE.
VALID URL: "http://cat-n.domain.net.in/"; it separated with - dash
here you can dump your url.
vendor\paypal\rest-api-sdk-php\lib\PayPal\Validation\UrlValidator.php
public static function validate($url, $urlName = null)
{
var_dump($url);
}
And then check this here: https://www.w3schools.com/PHP/phptryit.asp?filename=tryphp_func_validate_url
you can check here what character will reason for invalid.

Yii + Zend gdata. Youtube upload

I want to upload videos with next way:
I just upload file to server (as usual)
My server-side Yii-application takes that video and uploads it on Youtube from a special account on youTube
What do i have:
My YouTube (google) account name and email. "name" or "name#gmail.com"
My password
A developer Key, which I found in Google's "Product Dashboard"
A name of the application, which names 'myapp':
Product Dashboard: myapp
So, I read some docs in google and decided that best way for me is to use ClientLogin auth type, because I have only one account to use and I have all necessary data. I found an example for ZendFramework's GData and I imported it into my Yii application.
I specially simplified the code just to upload one single video from /upload directory to test that it works. I expect to find a video in my YT account uploaded. Of course there is no video and here I am :-) Complete code of the action is below:
Yii::import('application.vendors.*');
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_YouTube');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
$yt_user = 'myYTname';
$yt_pass = 'myYTpass';
$yt_source = 'myapp';
$yt_api_key = 'veryVERYlongKEYhere';
$authenticationURL= 'https://www.google.com/accounts/ClientLogin';
$httpClient = Zend_Gdata_ClientLogin::getHttpClient(
$username = $yt_user,
$password = $yt_pass,
$service = 'youtube',
$client = null,
$source = $yt_source,
$loginToken = null,
$loginCaptcha = null,
$authenticationURL
);
$yt = new Zend_Gdata_YouTube($httpClient, $yt_source, null, $yt_api_key);
$myVideoEntry = new Zend_Gdata_YouTube_VideoEntry();
$filesource = $yt->newMediaFileSource(Yii::getpathOfAlias('webroot').'/upload/videos/video.mp4');
$filesource->setContentType('video/mp4');
$filesource->setSlug('video.mp4');
$myVideoEntry->setMediaSource($filesource);
$myVideoEntry->setVideoTitle('My Test Movie');
$myVideoEntry->setVideoDescription('My Test Movie description');
$myVideoEntry->setVideoCategory('Autos');
$myVideoEntry->SetVideoTags('cars, funny');
$myVideoEntry->setVideoDeveloperTags(array('mydevtag', 'anotherdevtag'));
$uploadUrl = "http://uploads.gdata.youtube.com/feeds/api/users/{$yt_user}/uploads";
try {
$newEntry = $yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry');
} catch (Zend_Gdata_App_HttpException $httpException) {
echo $httpException->getRawResponseBody();
} catch (Zend_Gdata_App_Exception $e) {
echo $e->getMessage();
}
As you can see, there is a lot of default code from the official example. But it doesn't work. Noone echo shows me information. But when I deleted try-catch, I got an error:
Zend_Gdata_App_HttpException
Read timed out after 10 seconds
So, this problem is solved by myself :)
First of all: don't try to upload from localhost!
Then in my case I got an error, that I didn't say my dev-key! So, if you got the same error, try to change this:
$newEntry = $yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry');
by adding the 4th parameter - extra headers:
$yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry', array(
'X-GData-Key' => 'key=yourBIGbigBIGdeveloperKEYhere'
));
Good luck and have fun with youtube API!

Setting Sharepoint File Field Attributes

In out SP site, we have a library with files. These are files associated with a user. We now cstomized the user's profiles to accept a list of files. And now, to this list of files in the user's profile, we would like to add a reference to the file so that the user doesn't have to upload again.
Current Library:
/personal/my/User Files/[filename]
So, I was wondering how to do this? The data looks like this in the new User Files field (JSON):
{
[
{
"Id":"1",
"Title":"Test",
"Url":"\/personal\/my\/User+Files\/testfile.doc"
}
]
}
I have a csv file that I iterate over. The csv file contains the user name:filename pairs.
The Id value has to be gotten from the SP instance libarary at that location for that file.
Powershell code:
$upAttribute = "UserFiles"
$profile_info = Import-Csv profiles.csv
foreach ($row in $profile_info) {
$userId = $row.user # User ID
$fullAdAccount = $adAccount += $userId
#Check to see if user profile exists
if ($profileManager.UserExists($fullAdAccount))
{
$up = $profileManager.GetUserProfile($fullAdAccount)
$upAttributeValue += $row.filename # Filename
# CODE ??????
$up.Commit()
}
}
That is the all the data that I have.
Thanks for any and all help.
Eric
You will first need to add the custom property to the User Profile like so:
http://www.paulgrimley.com/2011/02/adding-custom-user-profile-property-to.html
Then this should help you out:
http://get-spscripts.com/2010/07/modify-single-value-user-profile.html
#Get user profile and change the value
$up = $profileManager.GetUserProfile($adAccount)
$up[$upAttribute].Value = $upAttributeValue
$up.Commit()