How to overwrite .env file variables in laravel - php

I am making a custome cms, I want admin users to be able to modify some variable from GUI (Admin seting) like mail variables. So they can easily change some values in the enviroment file by using the provided update form.
I made a custom function in a helper file i created and added the following code to it
function changeEnv($key, $value)
{
$path = base_path('.env');
if (file_exists($path)) {
file_put_contents($path, str_replace(
$key . '=' . env($key), $key . '=' . $value, file_get_contents($path)
));
}
}
Then in my controller I have the following code
public function updateEmail(Request $request)
{
foreach ($request->types as $key => $type) {
// echo $type . "=" . $request[$type];
changeEnv($type, $request[$type]);
}
}
Now when i hit the update button, only viriables with NULL get updated and not completely, I will get something like MAIL_PORT=465null After this they will no longer update unless i changed it manually to null.
My env variables looks like below befor update:
MAIL_MAILER=mail
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello#example.com"
MAIL_FROM_NAME="${APP_NAME}"
And After updating it I will get:
MAIL_MAILER=mail
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=sslnull
MAIL_FROM_ADDRESS="hello#example.com"
MAIL_FROM_NAME="${APP_NAME}"
I will appreciate any help on how to make this work perfectly.

Do not modify the .env directly, because this will cause several troubles (as #apokryfos mentioned in the comment). Troubles include caching and manual changes to this file.
Use the appropriate built-in functions to modify the configuration. To set configuration values at runtime, pass an array to the config function: config([key => value]). See https://laravel.com/docs/9.x/configuration#accessing-configuration-values
Furthermore you may want to consider the following architectures:
Store the configuration in a database table. So you can easily deal with advanced functionality, like user action logging, concurrency control and storing additional informations. Use a service provider that loads the config values from the database table into the Laravel config on boot. Of course this may be an overkill, if your CMS is designed for single or small teams only.
Write your manageable configuration into a custom configuration file, which is placed in the config/ directory and may overwrites all of the other default confiuguration values. The advantage would be that Laravel can deal with it as it is used to be and you benefit from things like caching.
Caching
Always ensure to reset the configuration cache after changing the configuration. You can do this programmatically. See https://laravel.com/docs/9.x/artisan#programmatically-executing-commands
Example:
Artisan::call('cache:clear')

Related

What is best way to create variable in environment file?

In laravel I need to create variable in env file. According to documentation and some relevant threads (got after googling) I need to do add variables in .env file
I have tried following
SANDBOX_PAYPAL_CLIENT_ID=7I3D9
SANDBOX_PAYPAL_CLIENT_SECRET=S2E4C5R6E7T
I am confused that after adding here variable I just need to call then into controller or I need to setup again in somewhere ./config/ directory? What is best practice, can someone guide me about that. I would like to appreciate. Thank you
You should put env variables in .env file, but make sure to only use env() calls in configuration files (the ones under /config) to retrieve their values.
Keep in mind that if you cache the configuration (php artisan config:cache) any env() will return null as Laravel will no longer load .env files.
That's also stated in to the documentation
You can get .env variables using the env() helper function.
Most packages get these values in their conf file to group the configurations.
You can then use the config() helper function to get the value.
However you implement this is up to you.
It depends on how you want to use them. Maybe create a file with name ConfigVariables.php declare all variables of env there.
1) You can have all of them at one place. Centralized control of all env variables at one place.
2) Take care of null checks etc, if config doesn't exit, pass some default value
3) This will help you to have one standard being used for all
4) If you use env directly in the code, you will have to check and take care of the null values (in case if there is no variable in the config)
Just to add a point here, Strings with spaces could be an issue if you do not use ""
You can test it:
Email_Sender_Name=Danyal Sandeelo
echo it as: echo env("Email_Sender_Name");
Email_Sender_Name="Danyal Sandeelo"
echo it as: echo env("Email_Sender_Name");
You can read this one: Laravel 5.2 not reading env file

Update .env value using PHP

I know some of your might think that this will lead to security issue. 🔐 🐞
But ...
I only want to update only 2 specific flags, because sometimes, I want to see the reports, and sometimes, I don't. If I have a way to update those flags -- I can just hook up a route to toggle that functionality - via Apple iPhone Shortcut whenever I want to see reports via EMAIL or SMS.
I've tried
created a route
Route::get('/env/{flag}/{value}','GeneralController#envUpdate');
called it
http://localhost/env/MAIL_REPORT/false
that will trigger this function
public function setEnv($key, $val)
{
$path = base_path('.env');
if (file_exists($path)) {
file_put_contents($path, str_replace(
$key . '=' . env($key), $key . '=' . $val, file_get_contents($path)
));
}
}
public function envUpdate($flag,$value)
{
//dd($flag,$value);
$allow_flags = ["MAIL_REPORT", "SMS_REPORT"];
if (in_array($flag, $allow_flags))
{
setEnv((string)$flag, (string)$value);
return env(env((string)$flag));
}
}
I kept getting true because in my .env does not seem to be updated
MAIL_REPORT=true
I suppose to have MAIL_REPORT=false
Note : I already ran : sudo chmod 777 .env
How would one go about and debug this further?
If you need to change the environment variables I would suggest to just change your .env file and re-cache your config (if in production). Your current implementation might be pretty sensitive for security issues.
If you do want to change your env variables programmatically at run time you can always use the config() helper method.
config(['mailing. reporting' => false]);
This is also documented in the docs.
Edit
So I think you're implementation of the env variables might be a little incorrect. The environment variables itself SHOULD NOT change at run time in your applications. The only place where the env() function should be called is in the config files (found in the config directory). So what you want is to create a new key in your config/mailing.php config file.
'reporting' => env('MAIL_REPORT', false),
Now whenever you need to set this variable to true you can either change the .env file or use the first given example (config(['mailing. reporting' => false]);).
Read more about it in the docs.

How would you skip Laravel Scout if enviroment is not production?

I have an app that I am writing with Laravel. I am still fairly new with the framework and don't understand most of it. I am using Algolia as the search engine with Laravel's Scout. In the models you add use Searchable, a trait, and the records are automatically passed to Algolia, which is cool. I am trying to put a simple statement if (App::environment('local'))" exit scout, just so we are not sending our development data to Algolia. Scout will also throw an exception if I run out of the hacker level of 10,000 records a Algolia.
In your local .env add
SCOUT_DRIVER=null
In production add
SCOUT_DRIVER=algolia
In config/scout.php add
'driver' => env('SCOUT_DRIVER', 'null')
Automatically it will be ignored in local but work in production.
This is just a suggestion. Try to adapt it to your specific context.
On your local environment you can call YourModel::disableSearchSyncing(), which will prevent this model from pushing data to Algolia.
The reverse to this method is YourModel::enableSeachSyncing(), but the search is enabled by default, so usually there is no need to use it.
Per the Laravel 5.3 documentation:
Set the environment the in the .env file:
APP_ENV=local
Determine the current environment:
$environment = App::environment();
Check on $environment and return true:
if (App::environment('local')) {
// The environment is local
}
if (App::environment('local', 'staging')) {
// The environment is either local OR staging...
}
None of above solution works I suggest you to check in your toSearchableArray() method inside your User Model. If you try to set the SCOUT_DRIVER=null in local environment then you will face an error because your application tends to push to Algolia in any environment.
Try to do this instead:
public function toSearchableArray()
{
if (! app()->isLocal()) {
return [
'username' => $this->username,
'age' => (string) $this->age,
// and so on ...
];
}
}

Laravel 4.2 package development on top of Authorize.net SKD - where to put Constant Variables?

I'm developing my first Laravel package in workbench to solve a business need which is to integrate the Authorize.net SDK for our systems billing transactions.
I've got most of my code now working and I can call the SDK functions via my custom facade like so AuthorizeMe::authorizeAndCapture(); My issue is the Authroize.net SDK requires use of defined variables. Their example usage is as follows:
define("AUTHORIZENET_API_LOGIN_ID", "YOURLOGIN");
define("AUTHORIZENET_TRANSACTION_KEY", "YOURKEY");
define("AUTHORIZENET_SANDBOX", true);
$sale = new AuthorizeNetAIM;
$sale->amount = "5.99";
$sale->card_num = '6011000000000012';
$sale->exp_date = '04/15';
$response = $sale->authorizeAndCapture();
if ($response->approved) {
$transaction_id = $response->transaction_id;
}
I would like to 1) store the defined variables in the packages config.php file, 2) I would like to make it so if I do publish the package other users can simply publish the config file to their app/config/packages folder so they can simply put in their unique api info.
I have tried to store the API variables in the config.php array as follows:
return array(
/*
|--------------------------------------------------------------------------
| Define credentials
|--------------------------------------------------------------------------
|
| Your credentials for both live environment and sandbox
|
*/
// Live environment
'LIVE_LOGIN_ID' => 'YOUR ID',
'LIVE_TRANSACTION_KEY' => 'YOUR KEY',
// Sandbox evnironment
'SANDBOX_LOGIN_ID' => 'YOUR SANDBOX ID',
'SANDBOX_TRANSACTION_KEY' => 'YOUR SANDBOX KEY',
/*
|--------------------------------------------------------------------------
| Define environment
|--------------------------------------------------------------------------
|
| Dictates if we're in sandbox mode or live mode
|
*/
'SANDBOX' => true,
);
I don't believe defined variables can be set from within a class so I'm not sure how to use the config file to accomplish my needs.
For example, something like this doesn't seem to work:
class MyClass {
public function __construct($app=null)
{
$this->app = $app ?: app();
}
public function billClient()
{
define("LIVE_LOGIN_ID", $this->app['config']->get('LIVE_LOGIN_ID'));
}
}
Lastly, I don't want to re-write the vendors package to simply work with my implementation as I feel it's important to make sure my package wrapper just sits on top so that it can pull in any future updates.
Store your static data that can change depending on what server your software is running on inside of the environment root-level configuration file. I would suggest doing this also to avoid the possibility of your API keys getting committed into source control (which could potentially be damaging). You can also leverage this to have different configuration values in different environments. Quoting from that linked to manual entry:
For "real" applications, it is advisable to keep all of your sensitive configuration out of your configuration files. Things such as database passwords, Stripe API keys, and encryption keys should be kept out of your configuration files whenever possible
The general practice is to keep these defined in a config file named .env.{environment name}.php which does not get checked in to source control. You can also specify them inside of the virtual host for the site if that works better for you, with e.g. SetEnv directives for Apache.

PHP - Application config file stored as - ini,php,sql,cached,php class,JSON,php array?

I am trying to decide on the best way to store my applications configuration settings. There are so many options.
The majority of applications I have seen have used a simple require and a PHP file that contains variables. There seem to be far more advanced techniques out there.
What have you used?
What is most efficient?
What is most secure?
We use a file called Local.php which is excluded from the SCM system. It contains several constants or global variables. For example:
// Local.php
class Setting
{
const URL = 'http://www.foo.com';
const DB_User = 'websmith';
}
And it can be referred to anywhere simply by:
Setting::URL
If you need the settings to be writable at runtime, I suggest you use public static variables instead.
The best thing you can do is the simplest thing that could possibly work (php variables) and wrap it up in a class. That way you can change the implementation later without changing any client code. Create an interface that the configuration class implements and make the client code use the interface methods. If you later decide to store configuration in a database or JSON or whatever, you can simply swap out the existing implementation with a new one. Make sure your configuration class is testable and write unit tests.
Try to use php-arrays config files using technique described here: http://www.dasprids.de/blog/2009/05/08/writing-powerful-and-easy-config-files-with-php-arrays
This method allows you to write app configuration in this way:
app.config.php
<?php
return array(
'appname' => 'My Application Name',
'database' => array(
'type' => 'mysql',
'host' => 'localhost',
'user' => 'root',
'pass' => 'none',
'db' => 'mydb',
),
);
This method is secure, cache-able by opcode cachers (APC, XCACHE).
How about:
; <?php die('Direct access not allowed ;') ?>
; The above is for security, do not remove
[database]
name = testing
host = localhost
user = root
pass =
[soap]
enableCache = 1
cacheTtl = 30
Save as config.php (or something like that, must have php extention), and then just load it with:
parse_ini_file('config.php', true);
And you could use
array_merge_recursive(parse_ini_file('config-default.php', true), parse_ini_file('config.php', true))
to merge a default config file with a more specific config file.
The point here is that you can use the very readable ini format, but still be able to have your config file in a public directory.
When you open the file with your browser, php will parse it first and give you the result, which will just be "; Direct access not allowed ;". When you parse the file directly as an ini file, the php die statement will be commented out according to the ini syntax (;) so it will not have any effect then.
I find Zend_Config to be a good solution. You can load the configuration from a simple array, from an INI style file, or from an XML document. Whichever you choose, the configuration object is the same, so you can switch storage formats freely. Zend_Config objects can also be merged, depending on your application this may be useful (a server config, then a per site/installation config).
As with most (or all) things in the Zend Framework, you can easily use Zend_Config by itself.
Considering efficiency, I'd say the fastest method would be to use an array, since that requires less (in this case no) string parsing. However, a INI/XML format may be easier for some to maintain. Of course some caching would give you the best of both worlds.
Also, using INI files with Zend_Config allow you to define sections of configurations that inherit from each other. The most common use is a 'development' section that inherits from the 'production' section, then redefines the DB/debugging settings.
As for security, keeping the config file out of the web root is the first step. Making it read only and limiting access could make it more secure; however, depending on your hosting/server configuration you may be limited in what can be done there.
Just an example of how to implement a central XML/Xpath configuration.
class Config {
private static $_singleton;
private $xml;
static function getInstance() {
if(is_null (self::$_singleton) ) {
self::$_singleton = new self;
}
return self::$_singleton;
}
function open($xml_file) {
$this->xml = simplexml_load_file($xml_file);
return $this;
}
public function getConfig($path=null) {
if (!is_object($this->xml)) {
return false;
}
if (!$path) {
return $this->xml;
}
$xml = $this->xml->xpath($path);
if (is_array($xml)) {
if (count($xml) == 1) {
return (string)$xml[0];
}
if (count($xml) == 0) {
return false;
}
}
return $xml;
}
}
Example call
Config::getInstance()
->open('settings.xml')
->getConfig('/settings/module/section/item');
In my view good solution would be ini files.
I don't prefer config file using arrays/variables for storing settings; here is why:
What if a user accidently re-named your setting variable?
What if a variable with similar name is defined elsewhere too by the user?
Variables in config file may be overwritten some where deep in the script or even included files.
and possibly more problems....
I like to use ini file for setting of my php apps. Here is why:
It is section based
It is easier
You can set values by friendly names
You don't have to worry about variables being overwritten because there are no ones.
No conflict of variables of course.
It allows more flexibility in specifying the types of values.
Note: You need to use parse_ini_file function to read ini files.
It is best to do any core configuration in PHP itself, but if you are using a database and don't mind the extra overhead - you may find some flexibility in storing some settings in the database with a single extra query (assuming you organize it properly).
Either way, storing this data in JSON, INI, XL, etc is just another unneeded abstraction that is done way too much nowadays on the web. Your best bet is pure PHP, unless you like the flexibility of some settings being in the database.
The only reason I can think of to not use php vars as others are suggesting is if you need to switch between configurations in a controlled manner, so there data/behavior consistency during the switch. For example, if you're switching databases, then the system could write locked until the switch-over occurs (to prevent ghost-writes, but dirty reads are still possible).
If things like this are a concern, then you could write a special admin page in your app(pref local access only for security) that locks the system temporarily, then reads and deploys all your changes before unlocking.
If you're running a high traffic site where consistency matters, this is something you'll want to consider. If you can deploy during off hours when there is little/no traffic, then php vars or other standard text formats will be fine.
I like the idea of having "namespaces" or some kind of tree
so you can have:
db.default.user
or
db.readonly.user
and so on.
now regarding code what I did was an interface for the config readers: so you can have a memory reader, array reader, db reader, etc.
and a config class that uses those readers and allow you have a config from any kind of source

Categories