Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

vainway 's avatar

symlink() has been disabled for security reasons

am on a using shared hosting and i can't access my files or uploaded pictures so i used symlink to create my storage folder for my files but its not creating the storage folder and i know also that they can't let me use symlink in public_html so i tried many ways its not working

<?php 

symlink('/home/username/laravelpro/storage/app/public', '/home/username/laravelpro/public/storage');

0 likes
52 replies
bobbybouwmann's avatar

@niyo You should contact your shared hosting provider to enable this functionality.

If they don't do that, the only option is migrating to another server where you're allowed to perform this action.

jlrdw's avatar

Can you display the images okay if they are under public_html. Something like

public_html/site_name/images

Or you could write a simple script to display images.

But yes you could consider changing host if that is the case. Are you trying a free host or is it paid hosting.

I usually have images outside of web anyway. But one site I had to put them like I showed above it was a small Humane Society. But the images were not secure they were for anyone to view anyway.

vainway 's avatar

@jlrdw where i have the issue i when a user upload an image only so i can't view it in my admin panel

but on my website images have no problem, the problem is the images kept in storage folder

vainway 's avatar

@bobbybouwmann i already paid my hosting plan so, i can't change to another hosting company i can't loose my $50 bucks for 4 yrs host

Snapey's avatar

Save them instead in a subfolder of public.

1 like
vainway 's avatar

@snapey i trying to escape the public_html folder cause it can't work there

by the way i save them where am not getting it well

jlrdw's avatar

when a user upload an image only so i can't view it in my admin panel but on my website images have no problem

Wouldn't the admin panel be part of the website?

Aren't they served the same way?

Are they uploaded to the same location? In other words, can you give more detail of how the website has no image problem but the admin panel does have a problem.

But if the host doesn't allow something you want in a host, then @bobbybouwmann solution would be the way to handle it.

vainway 's avatar

@jlrdw may be i give u the link you see the website visit guavahire.com

jlrdw's avatar

Just put code here of where you are having trouble.

Put "website" working code and "admin panel" problem code.

Edit: Why won't @snapey solution work, pretty standard for some shared host. I mentioned I did a humane society like that.

Are these images supposed to be "secure" images?

vainway 's avatar

the problem is to use symlink() that is disabled but on my localhost everything works with no problems

i faced the issue while i hosted my website

the ones that needs to be secured are user uploads that i only see in my admin panel not for other users just admin

jlrdw's avatar

Either make a folder for users and store there.

And write a script, use script requires authorization.

Or use the symfony asset component, I have not tried it myself.

A simple script is like: https://gist.github.com/jimgwhit/90faa6dfbbde72a9901562a5fe4f431e

Sounds like the host won't allow the symlink().

Edit: Also https://symfony.com/doc/current/components/asset.html

https://medium.com/@amycancode/protecting-user-uploads-in-laravel-611b62e6bb0e

meeshal's avatar

@snapey Saving all the resources under public_html is probably not an good idea if your resources are protected or something, let me know what you think.

I think @jlrdw is absolutely right on this, and i am probably expanding on his concept.

@niyo Shared hosting environment does not give you that much freedom to do whatever you want. Symbolic Links are considered not standard or may cause some security issues as experts says.

When I came across this issue first I just wanted it to work, but the fact is;

  1. Laravel is actually more suitable for VPS or system with root or admin access. You can definitely make it work on shared hosting, but there will be some limitations (very few actually), I this laravel offers a way better platform for deploying your apps very easily, check laravel ecosystem in laravel.com

  2. For symbolic links, I would suggest that you write you own logic to generate and use links for all your resources

What you need to do is define a route to specifically download the image/video etc file. You can generate a temporary signed URL to that route in your controller code: https://laravel.com/docs/7.x/urls#signed-urls

Share this URL to the view. Now the browser will load the video from the signed URL. https://laravel.com/docs/7.x/filesystem#downloading-files

Then you may need some kind of restriction on this route, for anyone to access it directly or maybe an middleware which will protect it, if the content you are sharing is protected.

You can learn more on middleware here in laracast.

Thanks

vainway 's avatar

@jlrdw according to that link i think is for helping to displaying images on the site not the created ones by the user

i think on the link above i gave u doesn't have issue for symlink problem the one of my site i gave u

jlrdw's avatar

I just clicked it in your answer, opened fine. Try another browser.

AbdulBazith's avatar

@niyo you are saying that you stored your images in storage folder and used symlink in local system. but u cant do that in shared hosting am i right??

why cant you do like this

in your route

Route::get('/StorageLink', function () {
    Artisan::call('storage:link');
    echo '<script>alert("linked")</script>';
});

Now run your project say for example xyz.com you can do like this xyz.com/StorageLink then it will make a symlink in live..

1 like
vainway 's avatar

steal the same my friend symlink() has been disabled for security reasons

jlrdw's avatar

@niyo you may have to write a custom script to serve the images, and use authorization to access them.

You could (and this is just one way) Store the image names like:

myimage457_179.jpg

Where everything after underscore is the userid (179) here.

Then using some string functions verify that the Auth::user()->id matches 179.

If no match throw an error otherwise display the image.

Again there are other ways as mentioned above.

EDIT: There are ways to have images in user sub folders under public_html and still have them secure, But for better security put them out of web and use a script, just a suggestion.

Here is another technique: https://laravel.io/forum/04-23-2015-securing-filesimages#23498

vainway 's avatar

@jlrdw try to show me how cause am not getting what you saying well

and also every user in my project to post an image must be authenticated and they pass everything according to there user_id

show me this u are saying : and use authorization to access them. You could (and this is just one way) Store the image names like:

vainway 's avatar

@snapey would you please show me how am confused about what you told me earlier

jlrdw's avatar

@niyo

When I upload an image I assign a name to it, like: https://gist.github.com/jimgwhit/0e4929230cd6b7df4b274b0b04312edd

$newname=$filename.$lid.".".$file_ext;
  • Example, a dog named Rover.
  • $lid is current db count +1
  • So rover123.jpg gets entered

To add the user id you could:

  • imagename123_userid.jpg
  • like rover123_478.jpg (478) is user id

Now in a display image script verify the userid matches. I am not saying use this technique, it's just one of many to try.

But try the link I gave first: https://laravel.io/forum/04-23-2015-securing-filesimages#23498

You will want to make a controller named ImageController (or similar) and place your logic there.

And try to open the medium article if you can, it should help you.

vainway 's avatar

@jlrdw look it looks like this when i create a post and how the image are uploaded in my project

public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|min:3',
            'time' => 'required|min:3',
            'description' => 'required|min:10',
            'file' => 'required|file|max:2048'
        ]);

        $upload = $request->file('file');
        $path = $upload->store('public/storage/posts');

        $post = Post::create([
            'name' => $request->name,
            'time' => $request->time,
            'description' => $request->description,
            'file_title' => $upload->getClientOriginalName(),
            'file' => $path,
            'user_id' => Auth::user()->id
        ]);

        return redirect()->route('givePrice', $post->id);
        }

try to give me an example in this way so i can fix it well

jlrdw's avatar

You are trying to serve images correct not upload?

vainway 's avatar

yeah then try to show me in that way i gave u

jlrdw's avatar

Okay I will try to explain: First you can upload the images, is that correct?

If you have an image named:

ace.jpg

The idea is assign a unique name to it, some people might give a unique generated number after the name like.

ace500.jpg

My technique adds the user id to the image:

ace500_125.jpg

So you have image name + however you assign a unique number + _ + userid.

You make a route:

Route::get('image', 'ImageController@displayImage');

You make a controller:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Session;
use App\Helpers\Clnsantize as Cln;
use Illuminate\Support\Facades\Auth;

class ImageController {

    public function displayImage() {

        $basedir = storage_path('app/upload');  // adjust to your needs.
        $imagedir = Request::input('dir');
        $image = Request::input('img');
        $string = $image;
        $str = (int) Cln::getBetween($string, "_", ".");

        If (Auth::id() != $str) {
            exit(0);
        }

        $file = $basedir . '/' . $imagedir . '/' . $image;

        header('Content-Type: image/jpeg');
        ob_clean();

        readfile($file);
        exit(0);
    }

}

And to use

<img src="<?php echo 'http://localhost/laravel70/image?dir=imgdogs&img=' .  $row->dogpic; ?>" alt="" class="image">

I added a string helper to get id:

    public static function getBetween($string, $start = "", $end = ""){
    if (strpos($string, $start)) { // required if $start not exist in $string
        $startCharCount = strpos($string, $start) + strlen($start);
        $firstSubStr = substr($string, $startCharCount, strlen($string));
        $endCharCount = strpos($firstSubStr, $end);
        if ($endCharCount == 0) {
            $endCharCount = strlen($firstSubStr);
        }
        return substr($firstSubStr, 0, $endCharCount);
    } else {
        return '';
    }
}

Now the image will display if the logged in user id matches the image id.

The url is

http://localhost/laravel70/image?dir=imgdogs&img=ace500_125.jpg

The user can right click, view image, download, etc.

Now if another user with id 55 or whatever ...

is logged in, they cannot serve (view) that image. Even if they somehow guess and put:

http://localhost/laravel70/image?dir=imgdogs&img=ace500_125.jpg

in the address bar, they get nothing.

I am not saying to use this, your choice. I also shared two other links that you can look at.

My technique or one of the others, adjust as necessary for admin to also have access to.

Edit: You are just storing image name, what if another user had an image with the same name.

The gist I gave shows one way to get a file name, but use whatever technique you like.

You could just use file name + _ + userid.

But look over https://medium.com/@amycancode/protecting-user-uploads-in-laravel-611b62e6bb0e

and https://laravel.io/forum/04-23-2015-securing-filesimages#23498 also.

If nothing here works for you, you might consider another host as suggested by @bobbybouwmann

Snapey's avatar

sorry guys, I am not getting notifications

@niyo

However you are saving your images, just vary the path to be a place that actually exists and does not rely on a symlink

For all those that chimed in with not secure. blah blah. @niyo has not said that these images need to be private, and if you store images in /storage/app/public and then create a symlink then you might as well have just saved them in the public folder in the first place.

@niyo, show how you save these images and I'll show you how to adapt it

tallaljamshed's avatar

(according to my cpanle view).... go to softwares tab and php version selector and on the top theres 2 options EXTENSION and OPTIONS . in OPTIONS theres a line for disabled_functions.... symlink will be one of them just remove that name and save.... dont know about the security reasons tho. @niyo

vainway 's avatar

@tallaljamshed hey i did what you said but am steal seeing the same error or may be it take some time

i removed symlink in disable_functions but no change

jlrdw's avatar

Above you said in an earlier reply

the ones that needs to be secured are user uploads

So they don't need to be secure or do they?

Meaning if you have a user named Bob with a user id of 125, and Bob uploads one or more images.

Can Bob only view his images (and admin), or can anyone view Bob's images.

Next

Please or to participate in this conversation.