Laravel 5 Dotenv for specific subdomain - laravel

I have a few subdomain in my laravel 5 application, each sub domain have a specific configuration, like mail, nocaptcha, etc.
how to set .env file to work with my-specific subdomain ?

Yes, you can use separate .env files for each subdomain so if you use env variables in your config it will work without great modifications.
Create bootstrap/env.php file with the following content:
<?php
$app->detectEnvironment(function () use ($app) {
if (!isset($_SERVER['HTTP_HOST'])) {
Dotenv::load($app['path.base'], $app->environmentFile());
}
$pos = mb_strpos($_SERVER['HTTP_HOST'], '.');
$prefix = '';
if ($pos) {
$prefix = mb_substr($_SERVER['HTTP_HOST'], 0, $pos);
}
$file = '.' . $prefix . '.env';
if (!file_exists($app['path.base'] . '/' . $file)) {
$file = '.env';
}
Dotenv::load($app['path.base'], $file);
});
Now modify bootstrap/app.php to load your custom env.php file. Just add:
require('env.php');
after
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
Now you can create separate env files for each domains for example if you use testing.app, abc.testing.app and def.testing.app you can have .env file for main domain (and for all subdomains that don't have custom env files) and .abc.env and .def.env files for custom env variables your your subdomains.

The best solution I found is to use .htaccess plus env variables.
In .htaccess add these lines:
<If "%{HTTP_HOST} == 'sub.domain'">
SetEnv APP_DOMAIN sub
</If>
In bootstrap/app.php add after the app initialisation:
//own env directory for separate env files
$app->useEnvironmentPath( realpath(__DIR__ . '/../env/') );
//separate files for each domain (see htaccess)
$app->loadEnvironmentFrom( getenv('APP_DOMAIN') . '.env' );
Create a new directory called "env" in your Laravel root and add your config files as:
"sub1.env",
"sub2.env" ..etc
(Of course you can keep it in your root as is currently, but for many subdomains it's better to move into a directory => looks much cleaner => everyone's happy! :) )

You can’t. Each subdomain will be running in the same environment.
If you want per-subdomain configuration then your best bet is to either create a configuration file in the config directory with each subdomain’s settings, or use a database approach.

I had the same issue, Based on #Marcin's answer I built this one (Works with laravel 5.2.X)
I added in the bootstrap/app.php
if (isset($_SERVER['HTTP_HOST'])) {
$hostArray = explode('.', $_SERVER['HTTP_HOST']);
//if the address is a subdomain and exist the .xxx.env file
$envFile = sprintf('.%s.env', $hostArray[0]);
if (count($hostArray) > 2 && file_exists(sprintf('%s/%s', $app['path.base'], $envFile))) {
$app->loadEnvironmentFrom($envFile);
}
}
after
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
I hope that helps someone
Greetings

Related

Cannot get value from config in Lumen

I want to change the timezone in lumen, but I cannot get the value from config, it always give the default value UTC.
I've tried everything I know, to the point changing the default value to what I wanted. But still the timezone wont change
AppServiceProvider
public function register()
{
//set local timezone
date_default_timezone_set(config('app.timezone'));
//set local date name
setLocale(LC_TIME, $this->app->getLocale());
URL::forceRootUrl(Config::get('app.url'));
}
Bootstrap.app
(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
dirname(__DIR__)
))->bootstrap();
date_default_timezone_set(env('APP_TIMEZONE', 'Asia/Jakarta'));
$app->configure('app');
Config.app
'timezone' => env("APP_TIMEZONE", "Asia/Jakarta"),
.env
APP_TIMEZONE="Asia/Jakarta"
APP_LOCALE="id"
Also if I make a variable inside config.app such as:
'tes_var' => 'Test'
And using it like this:
\Log::info(config('app.tes_var'));
The result in Log is null, I can't get the value from tes_var.
I don't have any idea what's wrong here, if it's in Laravel maybe this is happened because cached config, but there's no cached config in Lumen. Maybe I miss some configuration here?
Thanks
First, you should create the config/ directory in your project root folder.
Then create a new file app.php under the config directory i.e. config/app.php
Now add whatever config values you want to access later in your application in the config/app.php file.
So, instead of creating a config.php file you should make a config directory and can create multiple config files under the config directory.
So final code will be like this:
config/app.php will have:
<?PHP
return [
'test_var' => 'Test'
];
Can access it anywhere like this:
config('app.tes_var');
Although Lumen bootstrap/app.php has already loaded the app.php config file (can check here: https://github.com/laravel/lumen/blob/9.x/bootstrap/app.php)
If not loaded in your case, you can add the below line in bootstrap/app.php file:
$app->configure('app');
Hope it will help you.
In order to use the env file while caching the configs, you need to create a env.php inside the config folder. Then, load all env variables and read as "env.VARIABLE_FROM_ENV". Example env.php:
<?php
use Dotenv\Dotenv;
$envVariables = [];
$loaded = Dotenv::createArrayBacked(base_path())->load();
foreach ($loaded as $key => $value) {
$envVariables[$key] = $value;
}
return $envVariables;
then read in your code:
$value = config('env.VARIABLE_FROM_ENV', 'DEFAULT_VALUE_IF_YOU_WANT');

How to change public folder to public_html in laravel 8?

I wanna deploy my application on shared hosting on Cpanel where the primary document root has public_html but Laravel project public
You have to follow 2 steps to change your application's public folder to public_html then your can deploy it or anything you can do :)
Edit \App\Providers\AppServiceProvider register() method & add this code .
// set the public path to this directory
$this->app->bind('path.public', function() {
return base_path().'/public_html';
});
Open server.php you can see this code
if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
return false;
}
require_once __DIR__.'/public/index.php';
Just Replace it with :
if ($uri !== '/' && file_exists(__DIR__.'/public_html'.$uri)) {
return false;
}
require_once __DIR__.'/public_html/index.php';
Then serve your application with php artisan serve, you also can deploy it on your Cpanel shared hosting where primary document root public_html
You can rename your public directory to whatever you want and tell Laravel to use the current directory path as the public path. Just navigate to the index.php inside the public folder (or whatever you renamed it to) and add the following code after the $app definition:
$app = require_once __DIR__.'/../bootstrap/app.php';
/* *** Add this code: *** */
$app->bind('path.public', function() {
return __DIR__;
});
/* ********************** */
there, idk if you have same problem like me, my cases is i using shared hosting, and i deploy it in my main domain. i place all my files in the root, my problem is the storage:link keep between public, not public_html (because its default by the hosting) so what i need to do i changhe the link using this code :
Before :
'links' => [
public_path('storage') => storage_path('app/public'),
],
After :
'links' => [
app()->basePath('public_html/storage') => storage_path('app/public'),
],
I hope it can help few people :)
Just Rename the "public" folder to "public_html" and it will work.
No changes are required in the code. Tested in Laravel 8.
my two cents :) What helped to me was:
Open LaravelService/vendor/laravel/framework/src/Illuminate/Foundation/Application.php and change publicPath() method to return public_html.
public function publicPath()
{
return $this->basePath.DIRECTORY_SEPARATOR.'public_html';
}
Then if you are using webpack also change the output folder:
const output = 'public_html';
mix.ts('resources/js/web/App.ts', output + '/js/web').setPublicPath(output).react();
This helped to me. Only issue is that it is probably not recommended to change Application.php as it is part of Laravel framework and after updating it, it will be probably erased so you have to put it back.

Are laravel's routes safeguarding enough against file traversal attacks?

Route::get('/transaction/{name}', 'TransactionController#download');
public function download($name){
$path = storage_path('app/something/') . $name . '.xml';
return response()->download($path);
}
The user shall using this action only be able to download .xml files in app/something.
Is it possible to to download data outside of the specified app/something folder.
Laravel doesn't protect against traversal attacks - the router will return any value with your code example, meaning that someone could get access to your filesystem!
You an use PHP's basename() to sanitise $name by removing any path references from the string:
Route::get('/transaction/{name}', 'TransactionController#download');
public function download($name){
$path = storage_path('app/something/') . basename($name, '.xml') . '.xml';
return response()->download($path);
}
As far as i know Laravel will compile your path to:
#^/transaction/(?P<name>[^/]++)$#s
So simple / will not not work..
You could use more sophisticated backslash - but it depends on server..
At the end - Remember not to trust all user input.. No matter does it goes through routing or received directly..
Updated answer
As you can see below, it's definitely possible to do malicious stuff within Laravel routes. Given your function setup, the chance of someone doing something you don't want is small, because he/she can only alter the $name variable.
You can still write some extra code like this (found on viblo.asia):
$basepath = '/foo/bar/baz/'; // Path to xml file
$realBase = realpath($basepath);
$userpath = $basepath . $_GET['path'];
$realUserPath = realpath($userpath);
if ($realUserPath === false || strpos($realUserPath, $realBase) !== 0) {
//Directory Traversal!
} else {
//Good path!
}
To prevent users from accessing files they aren't allowed to.
Old, but relevant answer
Just tried this in Homestead:
Route::get(
'/',
function () {
dump(exec('ls ' . storage_path() . '/../../../'));
}
);
And that prints the corresponding folder just fine:
So I'd say that it's definitely possible to do stuff outside of the specified folder. Try this for yourself for example:
Route::get(
'/',
function () {
for ($i = 0; $i < 10; $i++) {
$path = str_repeat('/..', $i);
dump(exec('ls ' . storage_path() . $path));
}
}
);
And see your folders appear on screen when you hit the / route.

Can't write image data to path in laravel

I am having the same error as this guy is :
Another thread
basically the error i have is uploading the image to the specific path, my code is as follows :
public function postCreate() {
$validator = Validator::make(Input::all() , Product::$rules);
if ($validator->passes()) {
$product = new Product;
$product->category_id = Input::get('category_id');
$product->title = Input::get('title');
$product->description = Input::get('description');
$product->price = Input::get('price');
$image = Input::file('image');
$filename = date('Y-m-d-H:i:s')."-".$image->getClientOriginalName();
Image::make($image->getRealPath())->resize(468, 249)->save('public/img/products'.$filename);
$product->image = 'public/img/products'.$filename;
$product->save();
return Redirect::to('admin/products/index')
->with('message' , 'Product created');
}
return Redirect::to('admin/products/index')->with('message' , 'something went wrong')
->withErrors($validator)->withInput();
}
I was just trying to follow a tutorial on laravel e-commerce web application.
I guess the problem is that i don't have write permisson in my directory , how do i add write permission in my directory. I.E. the public folder, I googled a few places , but i don't understand what is it that i have to edit ?
I.E the htaccesss file or can i make write changes on the cmd ? also how do i check what weather a directory is write protected .
PS. i am using windows . i am attaching a screenshot of the error .
Thank you.
You might want to change the dateformat since windows doesn't allow colons in filenames:
$filename = date('Y-m-d-H:i:s')."-".$image->getClientOriginalName();
And you also might want to add a trailing slash to your path so it doesn't concatenate the filename to the folder path:
Image::make($image->getRealPath())->resize(468, 249)->save('public/img/products'.$filename);
Generally this error occurs when you do not yet have the directory that will store the image inside the public directory. Sometimes it can be a permission issue.
Does you img directory exists in your public directory?
To fix this, follow the steps:
Use this snippet:
$relPath = 'img/'; //your path inside public directory
if (!file_exists(public_path($relPath))) { //Verify if the directory exists
mkdir(public_path($relPath), 666, true); //create it if do not exists
}
Or manually create the img directory in public
2.Then you can save your image:
Image::make($image)->resize(468, 249)->save(public_path('img/products'.$filename)); //save you image
$product->image = 'img/products'.$filename; //note
$product->save();
**NOTE: We do not need to specify the public directory in the path because we are using a relative path. The img directory will be created inside public directory.
Along with this, you need to make sure the folder path exists and which has right permissions set.
$relPath = 'img/product/';
if (!file_exists(public_path($relPath))) {
mkdir(public_path($relPath), 777, true);
}
Where $relPath is the path relative to public directory.
This requirement is however windows specific. In linux, folder directory will be created if it does not exist.
I also recommend all of you to check if $path exists. Like Jose Seie use native PHP check, I recommend you to thought about build-in helpers.
This can be achieved with File Facade helper:
File::exists($imagePath) or File::makeDirectory($imagePath, 777, true);
Advice you to use Laravel built-in functions, classes & helpers to improve the performance of your application!
well , i made the correction that john suggested and then made the following corrections :
I replaced the below code :
Image::make($image->getRealPath())->resize(468, 249)->save('public/img/products'.$filename);
with :
$path = public_path('img/products/'.$filename);
Image::make($image->getRealPath())->resize(468, 249)->save($path);
problem solved , i don't know why public_path works , but never mind .

CodeIgniter - Delete file, pathing issue

I have 3 folders in my root, "application", "system", and "uploads". In application/controllers/mycontroller.php I have this line of code.
delete_files("../../uploads/$file_name");
The file does not get deleted and I have tried a number of pathing options like ../ and ../../../ any ideas? Thanks.
Use the FCPATH constant provided to you by CodeIgniter for this.
unlink(FCPATH . '/uploads/' . $filename);
base_url() generates HTTP urls, and cannot be used to generate filesystem paths. This is why you must use one of the CI path constants. They are defined in the front controller file (index.php).
The three ones you would use are:
FCPATH - path to front controller, usually index.php
APPPATH - path to application folder
BASEPATH - path to system folder.
$file_name is a variable. You should concatenate it to your own string in order to execute the function:
delete_files("../../uploads/" . $file_name);
EDIT:
Make sure that this sentence:
echo base_url("uploads/" . $file_name);
Is echoing a valid path. If the answer is YES, try this:
$this->load->helper("url");
delete_files(base_url("uploads/" . $file_name));
Supposing that your "uploads" folder is in your root directory.
EDIT 2:
Using unlink function:
$this->load->helper("url");
unlink(base_url("uploads/" . $file_name));
Try this one.. this just a very simple solution to your problem..
If you notice CI has there on defining of base_path to your directory e.g. in the upload library's config:
$imagePath = './picture/Temporary Profile Picture/';
$config['upload_path'] = $imagePath;
$config['allowed_types'] = 'gif|jpg|jpeg|png';
$this->load->library('upload', $config);
if you notice the upload_path is './picture/Temporary Profile Picture/'
so if you want to delete a file from a directory all you have to do is use unlink() function.
unlink($imagePath . $file_name);
or
#unlink($imagePath . $file_name);
Enjoy..^^
This code was working for me. Try this in your Model or Controller. Change the file path according to yours.
file path -->> project_name/assets/uploads/file_name.jpg
public function delete_file()
{
$file = 'file_name.jpg';
$path = './assets/uploads/'.$file;
unlink($path);
}
You should try this code:
$imagepath = $config['upload_path'];
unlink($imagepath . $images);
or
delete_files($imagepath . $images);
public function deleteContent($id)
{
$this->db->where('Filename',$id);
$this->db->delete('tableName',array('Filename'=>$id));
if (unlink("upload/folderName/".$id))
{
redirect($_SERVER['HTTP_REFERER']);
}
}

Resources