view files outside the resources dir in laravel 5.0 - laravel-5

I have a view,in which I would like to store it outside the current resources/views.
Currently we access it like so
public function sideBarItems(){
return view('ApplicationCreator.sideBarItems.blade.php');
}
but what if I want to access the view from outside resources/views? If my folder tree looks like this.
+newFolder
-foo.blade.php
+resouces
-views
-ApplicationCreator
-sideBarItems.blade.php
how should I access the foo.blade.php

Look in the view config file (config/view.php).
Add your directory in the 'paths' array, as follows:
'paths' => [
realpath(base_path('resources/views')),
realpath(base_path('newFolder')),
],

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');

Laravel Route Controller issue

I am trying to add a new route to my application and can't seem to get it to work. I keep getting a 404 error. It looks like the physical path is looking at the wrong directory. Currently looking at D:\Web\FormMapper\blog\public\forms but should be looking at D:\Web\FormMapper\blog\resources\view\layout\pages\forms.blade.php
My request URL:
http://localhost/FormMapper/ /works fine
http://localhost/FormMapper/forms /doesn't work
http://localhost/FormMapper/forms.php /No input file specified.
my FormsController:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class FormsController extends Controller
{
public function index()
{
return view('layouts.pages.forms');
}
}
My web.php:
Route::get('/', function () {
return view('layouts/pages/login');
});
Route::get('/forms', 'FormsController#index');
My folder structure looks like this:
My config/view.php
return [
'paths' => [
resource_path('views'),
],
'compiled' => env(
'VIEW_COMPILED_PATH',
realpath(storage_path('framework/views'))
),
];
you must use dot for this. In your controller change to this:
return view('layouts.pages.forms');
If your route only needs to return a view, you may use the Route::view method. Like the redirect method, this method provides a simple shortcut so that you do not have to define a full route or controller. The view method accepts a URI as its first argument and a view name as its second argument. In addition, you may provide an array of data to pass to the view as an optional third argument:
Route::view('/', 'layouts.pages.login');
Route::view('/forms', 'layouts.pages.forms', ['foo' => 'bar']);
Check docs
After tracking digging deeper I determined that the issue was that IIS requires URL rewrite rules in place for Laravel to work properly. The index.php and '/' route would work b/c it was the default page but any other pages wouldn't. To test this I used the
php artisan serve
approach to it. and everything worked properly. Unfortunately I am unable to do this in production so I needed to get it to work with IIS.

Dynamic route url change is not reflecting in laravel package

I am creating a package which gives a config file to customize the route url which it will add, I can see config file values in the controller, but same config('app_settings.url') is coming as null in
pakacge/src/routes/web.php
Route::get(config('app_settings.url'), 'SomeController')
my tests are also giving 404 and app_settings config change is not getting picked by route.
function it_can_change_route_url_by_config() {
// this should be default url
$this->get('settings')
->assertStatus(200);
// change the route url
config()->set('app_settings.url', '/app_settings');
$this->get('app_settings')
->assertStatus(200);
$this->get('settings')
->assertStatus(400);
}
app_setting.php
return [
'url' => 'settings',
'middleware' => []
];
It works when I use this package, but tests fail.
Please help How I can give the option to change the route url from config.
To be honest I think it's impossible to make such test. I've tried using some "hacky" solutions but also failed.
The problem is, when you start such test, all routes are already loaded, so changing value in config doesn't affect current routes.
EDIT
As alternative solution, to make it a bit testable, in config I would use:
<?php
return [
'url' => env('APP_SETTING_URL', 'settings'),
'middleware' => []
];
Then in phpunit.xml you can set:
<env name="APP_SETTING_URL" value="dummy-url"/>
As you see I set here completely dummy url to make sure this custom url will be later used and then test could look like this:
/** #test */
function it_works_fine_with_custom_url()
{
$this->get('dummy-url')
->assertStatus(200);
$this->get('settings')
->assertStatus(404);
}
Probably it doesn't test everything but it's hard to believe that someone would use dummy-url in routing, and using custom env in phpunit.xml give you some sort of confidence only custom url is working fine;

I can't find the implementation for Storage Facade in laravel

I'm new with laravel and I'm working in fileststem on laravel
(I want to do usual fileststem process like -make dir - copy - put -delete -ect)
I'm using laravel "Storage" Facade
but when i type
i referenced the class above like this in my code
use Illuminate\Support\Facades\Storage;
for example below :
if (file_exists(public_path($oldImage))) {
Storage::delete($oldImage);
}
nothing happens ,and when i refer to the class code i found this :
namespace Illuminate\Support\Facades;
/**
* #see \Illuminate\Filesystem\FilesystemManager
*/
class Storage extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'filesystem';
}
}
so where is the implementation and if you have alternative way to deal with
filesystem process rather than "Storage" facade ??
Storage is a facade and accesses the class Filesystem located here: vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php
As you can see in the official filesystem documentation the code snippets use Storage.
UPDATE:
You should add use Storage; to be able to use the Storage facade.
I recommend reading the Laravel 8.X docs to get an initial heads up: https://laravel.com/docs/8.x/filesystem
NOTE: Before you get too carried away, make sure you understand the difference between local and public.
For starters, you should make your first goal to upload a file and acquire the UploadedFile type.
You can access a single file via something like $request->file('name'), or an array of images via something like:
// $request->input('images')
foreach ($images as $image) {
\Log::debug($image->getClientOriginalName());
}
If your file upload can be single and/or multiple, I recommend going with the array approach because a single file wrapped in an array allows you to use the same syntax for single and multi uploads (ie: that foreach loop works fine with one image, no extra code).
Here's an example:
use Illuminate\Support\Facades\Storage;
$slug = 'davids-sandwich-photos';
foreach ($images as $image) {
Storage::putFileAs(
'images' .'/'. $slug,
$image,
$image->getClientOriginalName()
);
}
Storage::putFileAs() can take 3 parameters: directory, content, filename. You can see above in the code that I interpolated a mix of static and derived directory name. You could do something like 'images' .'/'. $slug .'/'. Auth::user()->id to save the file in /images/davids-sandwich-photos/11.
Then, check in your repo directory: /storage/app/ and look for the images directory.
You can manually delete the folders while testing to get your bearings straight.
That should be enough to get most people started.
To avoid using the Storage facade, you can use:
foreach ($images as $image) {
$image->storeAs(
'examples' .'/'. $slug,
$image->getClientOriginalName(),
'public'
);
}
--
Check out config/filesystems.php under the disks section if you want to start manipulating the drivers, but I'm not a DB admin expert here.
I also saved this along my journey: https://medium.com/#shafiya.ariff23/how-to-store-uploaded-images-in-public-folder-in-laravel-5-8-and-display-them-on-shared-hosting-e31c7f37a737. You might need that if you get stuck with something like symlinking.
<img
v-for="image in example.images"
:key="image.filename"
:src="`/storage/examples/${example.slug}/${image.filename}`"
>
NOTE: The important part with Vue JS is to use <img src="/storage/examples/slug/filename.jpg"> if your file is located in your repository as /storage/app/public/examples/slug/filename.jpg Pay close attention to every character.
The public_path function returns the fully qualified path to the public directory ie public directory inside the laravel application. When using Storage, the path is set to the storage/app directory.
if (file_exists(public_path($oldImage))) {
//public_path($oldImage) will check for file in public directory
Storage::delete($oldImage); //Will delete file in storage/app directory
}
The modified code should be
if(Storage::has($oldImage)){
Storage::delete($oldImage);
}

How to protect image from public view in Laravel 5?

I have installed Laravel 5.0 and have made Authentication. Everything is working just fine.
My web site is only open for Authenticated members. The content inside is protected to Authenticated members only, but the images inside the site is not protected for public view.
Any one writes the image URL directly can see the image, even if the person is not logged in to the system.
http://www.somedomainname.net/images/users/userImage.jpg
My Question: is it possible to protect images (the above URL example) from public view, in other Word if a URL of the image send to any person, the individual must be member and login to be able to see the image.
Is that possible and how?
It is possible to protect images from public view in Laravel 5.x folder.
Create images folder under storage folder (I have chosen storage folder because it has write permission already that I can use when I upload images to it) in Laravel like storage/app/images.
Move the images you want to protect from public folder to the new created images folder. You could also chose other location to create images folder but not inside the public folder, but with in Laravel folder structure but still a logical location example not inside controller folder. Next you need to create a route and image controller.
Create Route
Route::get('images/users/{user_id}/{slug}', [
'as' => 'images.show',
'uses' => 'ImagesController#show',
'middleware' => 'auth',
]);
The route will forward all image request access to Authentication page if person is not logged in.
Create ImagesController
class ImagesController extends Controller {
public function show($user_id, $slug)
{
$storagePath = storage_path('app/images/users/' . $user_id . '/' . $slug);
return Image::make($storagePath)->response();
}
}
EDIT (NOTE)
For those who use Laravel 5.2 and newer. Laravel introduces new and better way to serve files that has less overhead (This way does not regenerate the file as mentioned in the answer):
File Responses
The file method can be used to display a file, such as an image or
PDF, directly in the user's browser instead of initiating a download.
This method accepts the path to the file as its first argument and an
array of headers as its second argument:
return response()->file($pathToFile);
return response()->file($pathToFile, $headers);
You can modify your storage path and file/folder structure as you wish to fit your requirement, this is just to demonstrate how I did it and how it works.
You can also added condition to show the images only for specific members in the controller.
It is also possible to hash the file name with file name, time stamp and other variables in addition.
Addition: some asked if this method can be used as alternative to public folder upload, YES it is possible but it is not recommended practice as explained in this answer. So the same method can be also used to upload images in storage path even if you do not intend to protect them, just follow the same process but remove 'middleware' => 'auth',. That way you won't give 777 permission in your public folder and still have a safe uploading environment. The same mentioned answer also explain how to use this method with out authentication in case some one would use it or giving alternative solution as well.
In a previous project I protected the uploads by doing the following:
Created Storage Disk:
config/filesystems.php
'myDisk' => [
'driver' => 'local',
'root' => storage_path('app/uploads'),
'url' => env('APP_URL') . '/storage',
'visibility' => 'private',
],
This will upload the files to \storage\app\uploads\ which is not available to public viewing.
To save files on your controller:
Storage::disk('myDisk')->put('/ANY FOLDER NAME/' . $file, $data);
In order for users to view the files and to protect the uploads from unauthorized access. First check if the file exist on the disk:
public function returnFile($file)
{
//This method will look for the file and get it from drive
$path = storage_path('app/uploads/ANY FOLDER NAME/' . $file);
try {
$file = File::get($path);
$type = File::mimeType($path);
$response = Response::make($file, 200);
$response->header("Content-Type", $type);
return $response;
} catch (FileNotFoundException $exception) {
abort(404);
}
}
Serve the file if the user have the right access:
public function licenceFileShow($file)
{
/**
*Make sure the #param $file has a dot
* Then check if the user has Admin Role. If true serve else
*/
if (strpos($file, '.') !== false) {
if (Auth::user()->hasAnyRole(['Admin'])) {
/** Serve the file for the Admin*/
return $this->returnFile($file);
} else {
/**Logic to check if the request is from file owner**/
return $this->returnFile($file);
}
} else {
//Invalid file name given
return redirect()->route('home');
}
}
Finally on Web.php routes:
Route::get('uploads/user-files/{filename}', 'MiscController#licenceFileShow');
I haven't actually tried this but I found Nginx auth_request module that allows you to check the authentication from Laravel, but still send the file using Nginx.
It sends an internal request to given url and checks the http code for success (2xx) or failure (4xx) and on success, lets the user download the file.
Edit: Another option is something I've tried and it seemed to work fine. You can use X-Accel-Redirect -header to serve the file from Nginx. The request goes through PHP, but instead of sending the whole file through, it just sends the file location to Nginx which then serves it to the client.
if I am understanding you it's like !
Route::post('/download/{id}', function(Request $request , $id){
{
if(\Auth::user()->id == $id) {
return \Storage::download($request->f);
}
else {
\Session::flash('error' , 'Access deny');
return back();
}
}
})->name('download')->middleware('auth:owner,admin,web');
Every file inside the public folder is accessible in the browser. Anyone easily gets that file if they find out the file name and storage path.
So better option is to store the file outside the public folder eg: /storage/app/private
Now do following steps:
create a route (eg: private/{file_name})
Route::get('/private/{file_name}', [App\Http\Controllers\FileController::class, 'view'])->middleware(['auth'])->name('view.file');
create a function in a controller that returns a file path. to create a controller run the command php artisan make:controller FileController
and paste the view function in FileController
public function view($file)
{
$filePath = "notes/{$file}";
if(Storage::exists($filePath)){
return Storage::response($filePath);
}
abort(404);
}
then, paste use Illuminate\Support\Facades\Storage; in FileController for Storage
And don't forget to assign middleware (in route or controller) as your requirement(eg: auth)
And now, only those who have access to that middleware can access that file through a route name called view.file

Resources