Verification: a143cc29221c9be0

Php artisan storage link удалить

Playground Setup

To try the examples provided in this post will require an existing Laravel application or a new one. I will start with a new Laravel project and use the composer to create a new Laravel application.

composer create-project laravel/laravel DemoApp

Above command will generate a new Laravel application in a folder named DemoApp.

Open your command line terminal and move into the DemoApp folder. Now run the below command.

php artisan make:auth

This commmand will scaffold a bootstrap based template layout. Now open the welcome.blade.php file from resources/views folder and replace all markup with the below one.

Laravel Storage Example
@error('file') {{ $message }} @enderror

In this view, we have added a form with an input file field and a submit button to submit the form. The form in this view template is pointing a route named upload, let’s add this route in our routes/web.php file.

Route::post('/upload', '[email protected]')->name('upload');

Next, we will add the upload() method in the HomeController.

public function upload(Request $request)
    // All code examples will go into this method

Next, we need to update the middleware for this controller. Change the __construct() method from this:

 * Create a new controller instance.
 * @return void
public function __construct()

To this:

 * Create a new controller instance.
 * @return void
public function __construct()

That’s all, now we have a form with a controller method where we can test all the examples regarding Laravel Storage. So let’s start.

How Laravel Storage Handles a File

Laravel is one of the fastest-growing frameworks due to its simplicity and flexibility. Therefore there are multiple options available to handle the file uploads and storage formats.

For example, you can use the local storage system where all the files will be stored within the project itself. You can also use the SFTP to transfer files to other servers or you can utilize the Cloud Storage for storing all your files. Laravel provides the Amazon S3 or Google Cloud storage out of the box.

In Laravel, we call all these storage types as disks, think of file storage and label it as a disk in Laravel. If you open the config/filesystems.php file, you will find out all the available disks and their configurations.

In the config/filesystems.php file, you will find out two types of disks named local and public. Laravel by default use the local disk, while you can specify the disk type you want to use when uploading the files.

In the public disk, you will find out that the root of this disk is set to storage/app/public, since the Laravel’s root is in public folder, you have to link the storage/app/public folder to Laravel’s public folder which is placed in the root of your project folder. You can achieve this by running the below artisan command.

php artisan storage:link

File Uploads in Laravel

Since, we have already setup the playground for practicing the file upload, let’s go ahead and write some code to upload files. In the upload() method of HomeController add the below line of code:

public function upload(Request $request)
    $path = $request->file('file')->store('files');


In the above method, we get the file uploaded through the Laravel’s Request object and use the store() method to store uploaded file in the files folder.

Now, if you run the application and upload a file using the form we created in the earlier section, your file will be uploaded and Laravel will dump the file path.

Now, if you go to storage/app folder, you will find a new folder named files and uploaded will be available in this folder.

If you want to give a name to the file you are uploading, you can use storeAs() method like below.

public function upload(Request $request)
    $file = $request->file('file');

    // Generate a file name with extension
    $fileName = 'profile-'.time().'.'.$file->getClientOriginalExtension();

    // Save the file
    $path = $file->storeAs('files', $fileName);


After uploading a new file, you will get something like the following output.


Multiple File Uploads in Laravel

To upload multiple images at once, you have to adjust the file input field in your form. Change the input field from this:

To this:

We have changed the name of this input field from file to files[] and add the multiple attribute in it.

Now, we will store multiple images something like below:

public function upload(Request $request)
    $paths = [];
    $files = $request->file('files');

    foreach ($files as $file)
        // Generate a file name with extension
        $fileName = 'profile-'.time().'.'.$file->getClientOriginalExtension();
        // Save the file
        $paths[] = $file->storeAs('files', $fileName);

In the above method, we simply loop through all the files and save the path in the $paths array.

If you upload now multiple files, you will get something like below output.

array:3 [▼
  0 => "files/profile-1564586818.jpg"
  1 => "files/profile-1564586818.jpg"
  2 => "files/profile-1564586818.jpg"

Validation Rules For Files Upload

For any web application, validation is one of the most important as you have to place some checks if a user is uploading the right file type, within the limit allowed and with correct dimensions if its an image file.

For our file uploads, we can add the validation rules right in our controller or you can use a Laravel Form Request.

public function upload(Request $request)
    $validation = $request->validate([
        'file'  =>  'required|file|image|mimes:jpeg,png,gif,jpg|max:2048'

    $file = $validation['file'];

    // Generate a file name with extension
    $fileName = 'profile-'.time().'.'.$file->getClientOriginalExtension();

    // Save the file
    $path = $file->storeAs('files', $fileName);


In the above method, we added the validation that the uploaded file has to be a file and image with specified extension types and file should not be more than 2MB in size.

Useful Laravel Storage Facade Methods

Laravel Storage facade provides a convenient way to perform actions on the storage disks. For example, if you would like to specify which disk it should use when uploading a file, you do something like below.

Save File to a Specific Disk

Storage::disk('local')->put('filename.txt', 'File content goes here..');

Above code will create a filename.txt file in local storage disk with the content provided.

Get Content of a File

To get the content of a file, you can use get() method.


Checking If a File Exists

To check if a file exist or not, we use the exists() method available, which will return true or false value.

Append to a File

Use the below method of Storage facade to append to a file.

Storage::append('filename.txt', 'Append this text');

Prepend to a File

Use the below method of Storage facade to prepend to a file.

Storage::prepend('filename.txt', 'Append this text');

Download a File

To download a stored file from the storage disk use download() method.


Generating a Public URL

To generate a publicly available link for the file, use below method.


Get Size of a File

To get the size of a file, use the below method.


Delete a File

To delete a file, use delete() method.


Learn More

You can find all the available method with their documentation here.

Working with Directories in Laravel Storage

Laravel Storage facade also provides a simple way to interact with the directories within your storage disks. Here we will look at some of the most common methods of Laravel Storage.

Get Files from a Directory

To get all files from a directory, we can use the files() method on Laravel Storage facade.


If you want to get all files, from subdirectories of a directory, you can use allFiles() method.


Get All Directories within a Directory

To get a list of all directories from a given directory use the directories() method.


Just like files, you can use the allDirectories() method to grab a list of all directories and sub-directories from a given directory.


Create A Directory

Use the makeDirectory() method to create a new directory.


Deleting a Directory

Use the deleteDirectory() method to delete a particular directory.


Using Amazon S3 Cloud Storage

In this section, we will look at how we can upload files on the Amazon S3 storage. Laravel provides the support for Amazon S3 out of the box, but we have to install a dependency package.

Open your terminal and run the below command in the root of your project folder.

composer require league/flysystem-aws-s3-v3 ~1.0

Once composer package installation finish, run the composer dump-autoload.

Now, head to our upload() method we created earlier where we will add the storage logic for our file upload.

To upload the files to Amazon S3, we will use the put() method of the Laravel Storage facade.

Firstly, we will need to create an instance of the S3 using disk() method of the Storage facade. Then we will supply, the relative path to your S3 bucket, the content of the file and the permission of the file.

public function upload(Request $request)
    $validation = $request->validate([
        'file'  =>  'required|file|image|mimes:jpeg,png,gif,jpg|max:2048'

    $file = $validation['file'];

    // Generate a file name with extension
    $fileName = 'profile-'.time().'.'.$file->getClientOriginalExtension();

    // Save the file
    $s3 = Storage::disk('s3');
    $filePath = '/uploads/media/' . $fileName;
    $s3->put($filePath, file_get_contents($file), 'public');


Remember to add the your API credentials in your .env file which you can find in config/filesystems.php file.

's3' => [
    'driver' => 's3',
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'region' => env('AWS_DEFAULT_REGION'),
    'bucket' => env('AWS_BUCKET'),
    'url' => env('AWS_URL'),

Add the above enviornment variables in your .env file to use the Amazon S3 storage.


Laravel обеспечивает мощную абстракцию файловой системы благодаря замечательному пакету Flysystem PHP от Фрэнка де Йонга. Интеграция Laravel с Flysystem содержит простые драйверы для работы с локальными файловыми системами, SFTP и Amazon S3. Более того, удивительно просто переключаться между этими вариантами хранения: как локального, так и производственного серверов – поскольку API остается одинаковым для каждой системы.


Файл конфигурации файловой системы Laravel находится в config/filesystems.php. В этом файле вы можете настроить все «диски» файловой системы. Каждый диск представляет собой определенный драйвер хранилища и место хранения. Примеры конфигураций для каждого поддерживаемого драйвера включены в конфигурационный файл, так что вы можете изменить конфигурацию, отражающую ваши предпочтения хранения и учетные данные.

Драйвер local взаимодействует с файлами, хранящимися локально на сервере, на котором запущено приложение Laravel, в то время как драйвер s3 используется для записи в службу облачного хранилища Amazon S3.

{tip} Вы можете настроить столько дисков, сколько захотите, и даже иметь несколько дисков, использующих один и тот же драйвер.

Локальный драйвер

При использовании драйвера local все операции с файлами выполняются относительно корневого каталога, определенного в файле конфигурации filesystems. По умолчанию это значение задано каталогом storage/app. Следовательно, следующий метод запишет файл в storage/app/example.txt:

use Illuminate\Support\Facades\Storage;

Storage::disk('local')->put('example.txt', 'Contents');

Публичный диск

Диск public, определенный в файле конфигурации filesystems вашего приложения, предназначен для файлов, которые будут общедоступными. По умолчанию публичный диск использует драйвер local и хранит свои файлы в storage/app/public.

Чтобы сделать эти файлы доступными из интернета, вы должны создать символическую ссылку на storage/app/public в public/storage. Использование этого соглашения о папках позволит хранить ваши публичные файлы в одном каталоге, который может быть легко доступен между развертываниями при использовании систем развертывания с нулевым временем простоя, таких как Envoyer.

Чтобы создать символическую ссылку, вы можете использовать команду storage:link Artisan:

php artisan storage:link

После того, как была создана символическая ссылка, вы можете создавать URL-адреса для сохраненных файлов, используя помощник asset:

echo asset('storage/file.txt');

Вы можете настроить дополнительные символические ссылки в файле конфигурации filesystems. Каждая из настроенных ссылок будет создана, когда вы запустите команду storage:link:

'links' => [
    public_path('storage') => storage_path('app/public'),
    public_path('images') => storage_path('app/images'),

Предварительная подготовка драйверов

Пакеты Composer

Перед использованием драйверов S3 или SFTP вам необходимо установить соответствующий пакет с помощью менеджера пакетов Composer:

  • Amazon S3: league/flysystem-aws-s3-v3 ~1.0
  • SFTP: league/flysystem-sftp ~1.0

Кроме того, вы можете установить декоратор CachedAdapter для повышения производительности:

  • CachedAdapter: league/flysystem-cached-adapter ~1.0

Конфигурирование драйвера S3

Информация о конфигурации драйвера S3 находится в вашем файле конфигурации config/filesystems.php. Этот файл содержит пример массива конфигурации для драйвера S3. Вы можете изменить этот массив своей собственной конфигурацией S3 и учетными данными. Для удобства эти переменные среды соответствуют соглашению об именах, используемому в интерфейсе командной строки AWS.

Конфигурирование драйвера FTP

Интеграция Laravel с Flysystem отлично работает с FTP; однако, пример конфигурации по умолчанию не включен в конфигурационный файл config/filesystems.php фреймворка. Если вам нужно настроить файловую систему FTP, вы можете использовать пример конфигурации ниже:

'ftp' => [
    'driver' => 'ftp',
    'host' => '',
    'username' => 'your-username',
    'password' => 'your-password',

    // Optional FTP Settings...
    // 'port' => 21,
    // 'root' => '',
    // 'passive' => true,
    // 'ssl' => true,
    // 'timeout' => 30,

Конфигурирование драйвера SFTP

Интеграция Laravel с Flysystem отлично работает с SFTP; однако, пример конфигурации по умолчанию не включен в конфигурационный файл config/filesystems.php фреймворка. Если вам нужно настроить файловую систему SFTP, вы можете использовать пример конфигурации ниже:

'sftp' => [
    'driver' => 'sftp',
    'host' => '',
    'username' => 'your-username',
    'password' => 'your-password',

    // Settings for SSH key based authentication...
    'privateKey' => '/path/to/privateKey',
    'password' => 'encryption-password',

    // Optional SFTP Settings...
    // 'port' => 22,
    // 'root' => '',
    // 'timeout' => 30,


Чтобы включить кеширование для конкретного диска, вы можете добавить директиву cache в параметры конфигурации этого диска. Параметр cache должен быть массивом параметров кеширования, содержащим имя disk, время expire в секундах и prefix кеша:

's3' => [
    'driver' => 's3',

    // Other Disk Options...

    'cache' => [
        'store' => 'memcached',
        'expire' => 600,
        'prefix' => 'cache-prefix',

Доступ к экземплярам дисков

Фасад Storage используется для взаимодействия с любым из ваших сконфигурированных дисков. Например, вы можете использовать метод put фасада, чтобы сохранить аватар на диске по умолчанию. Если вы вызываете методы фасада Storage без предварительного вызова метода disk, то метод будет проксирован на диск по умолчанию:

use Illuminate\Support\Facades\Storage;

Storage::put('avatars/1', $content);

Если ваше приложение взаимодействует с несколькими дисками, то вы можете использовать метод disk фасада Storage для работы с файлами на указанном диске:

Storage::disk('s3')->put('avatars/1', $content);

Получение файлов

Метод get используется для получения содержимого файла. Необработанное строковое содержимое файла будет возвращено методом. Помните, что все пути к файлам должны быть указаны относительно «корня» диска:

$contents = Storage::get('file.jpg');

Метод exists используется для определения, существует ли файл на диске:

if (Storage::disk('s3')->exists('file.jpg')) {
    // ...

Метод missing используется, чтобы определить, отсутствует ли файл на диске:

if (Storage::disk('s3')->missing('file.jpg')) {
    // ...

Скачивание файлов

Метод download используется для генерации ответа, который заставляет браузер пользователя загружать файл по указанному пути. Метод download принимает имя файла в качестве второго аргумента метода, определяющий имя файла, которое видит пользователь, скачивающий этот файл. Наконец, вы можете передать массив заголовков HTTP в качестве третьего аргумента метода:

return Storage::download('file.jpg');

return Storage::download('file.jpg', $name, $headers);

URL-адреса файлов

Вы можете использовать метод url, чтобы получить URL для указанного файла. Если вы используете драйвер local, он обычно просто добавляет /storage к указанному пути и возвращает относительный URL-адрес файла. Если вы используете драйвер s3, будет возвращен абсолютный внешний URL-адрес:

use Illuminate\Support\Facades\Storage;

$url = Storage::url('file.jpg');

При использовании драйвера local все файлы, которые должны быть общедоступными, должны быть помещены в каталог storage/app/public. Кроме того, вы должны создать символическую ссылку в public/storage, которая указывает на каталог storage/app/public.

{note} При использовании драйвера local возвращаемое значение url не является URL-кодированным. По этой причине мы рекомендуем всегда хранить ваши файлы, используя имена, которые будут создавать допустимые URL-адреса.

Временные URL

Используя метод temporaryUrl, вы можете создавать временные URL-адреса для файлов, хранящихся с помощью драйвера s3. Этот метод принимает путь и экземпляр DateTime, указывающий, когда должен истечь доступ к файлу по URL:

use Illuminate\Support\Facades\Storage;

$url = Storage::temporaryUrl(
    'file.jpg', now()->addMinutes(5)

Если вам нужно указать дополнительные параметры запроса S3, то вы можете передать массив параметров запроса в качестве третьего аргумент методу temporaryUrl:

$url = Storage::temporaryUrl(
        'ResponseContentType' => 'application/octet-stream',
        'ResponseContentDisposition' => 'attachment; filename=file2.jpg',

Настройка хоста URL

Если вы хотите заранее определить хост для URL-адресов, сгенерированных с помощью фасада Storage, то вы можете добавить параметр url в массив конфигурации диска:

'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',

Метаданные файла

Помимо чтения и записи файлов, Laravel также может предоставлять информацию о самих файлах. Например, метод size используется для получения размера файла в байтах:

use Illuminate\Support\Facades\Storage;

$size = Storage::size('file.jpg');

Метод lastModified возвращает временную метку UNIX последнего изменения файла:

$time = Storage::lastModified('file.jpg');

Пути к файлам

Вы можете использовать метод path, чтобы получить путь к указанному файлу. Если вы используете драйвер local, он вернет абсолютный путь к файлу. Если вы используете драйвер s3, этот метод вернет относительный путь к файлу в корзине S3:

use Illuminate\Support\Facades\Storage;

$path = Storage::path('file.jpg');

Хранение файлов

Метод put используется для сохранения содержимого файла на диске. Вы также можете передать resource PHP методу put, который будет использовать поддержку базового потока Flysystem. Помните, что все пути к файлам должны быть указаны относительно «корневого» расположения, настроенного для диска:

use Illuminate\Support\Facades\Storage;

Storage::put('file.jpg', $contents);

Storage::put('file.jpg', $resource);

Автоматическая потоковая передача

Потоковая передача файлов в хранилище позволяет значительно сократить использование памяти. Если вы хотите, чтобы Laravel автоматически управлял потоковой передачей переданного файла в ваше хранилище, вы можете использовать методы putFile или putFileAs. Эти методы принимают экземпляр Illuminate\Http\File или Illuminate\Http\UploadedFile и автоматически передают файл в нужное место:

use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;

// Автоматически генерировать уникальный идентификатор для имени файла ...
$path = Storage::putFile('photos', new File('/path/to/photo'));

// Явно указать имя файла ...
$path = Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');

Следует отметить несколько важных моментов, касающихся метода putFile. Обратите внимание, что мы указали только имя каталога, а не имя файла. По умолчанию метод putFile генерирует уникальный идентификатор, который будет служить именем файла. Расширение файла будет определено путем проверки MIME-типа файла. Путь к файлу будет возвращен методом putFile, так что вы можете сохранить путь, включая сгенерированное имя файла, в вашей базе данных.

Методы putFile и putFileAs также принимают аргумент для определения «видимости» сохраненного файла. Это особенно полезно, если вы храните файл на облачном диске, таком как Amazon S3, и хотите, чтобы файл был общедоступным через сгенерированные URL:

Storage::putFile('photos', new File('/path/to/photo'), 'public');

Добавление информации к файлам

Методы prepend и append позволяют записывать в начало или конец файла, соответственно:

Storage::prepend('file.log', 'Prepended Text');

Storage::append('file.log', 'Appended Text');

Копирование и перемещение файлов

Метод copy используется для копирования существующего файла в новое место на диске, а метод move используется для переименования или перемещения существующего файла в новое место:

Storage::copy('old/file.jpg', 'new/file.jpg');

Storage::move('old/file.jpg', 'new/file.jpg');

Загрузка файлов

В веб-приложениях одним из наиболее распространенных вариантов хранения файлов является хранение загруженных пользователем файлов, таких как фотографии и документы. Laravel упрощает хранение загруженных файлов с помощью метода store экземпляра загружаемого файла. Вызовите метод store, указав путь, по которому вы хотите сохранить загруженный файл:


        return $path;

В этом примере следует отметить несколько важных моментов. Обратите внимание, что мы указали только имя каталога, а не имя файла. По умолчанию метод store генерирует уникальный идентификатор, который будет служить именем файла. Расширение файла будет определено путем проверки MIME-типа файла. Путь к файлу будет возвращен методом store, поэтому вы можете сохранить путь, включая сгенерированное имя файла, в своей базе данных.

Вы также можете вызвать метод putFile фасада Storage, чтобы выполнить ту же операцию сохранения файлов, что и в примере выше:

$path = Storage::putFile('avatars', $request->file('avatar'));

Указание имени файла

Если вы не хотите, чтобы имя файла автоматически присваивалось вашему сохраненному файлу, вы можете использовать метод storeAs, который получает путь, имя файла и (необязательный) диск в качестве аргументов:

$path = $request->file('avatar')->storeAs(
    'avatars', $request->user()->id

Вы также можете использовать метод putFileAs фасада Storage, который будет выполнять ту же операцию сохранения файлов, что и в примере выше:

$path = Storage::putFileAs(
    'avatars', $request->file('avatar'), $request->user()->id

{note} Непечатаемые и недопустимые символы Unicode будут автоматически удалены из путей к файлам. По этой причине, вы по желанию можете очистить пути к файлам перед их передачей в методы хранения файлов Laravel. Пути к файлам нормализуются с помощью метода League\Flysystem\Util::normalizePath.

Указание диска

По умолчанию метод store загружаемого файла будет использовать ваш диск по умолчанию. Если вы хотите указать другой диск, передайте имя диска в качестве второго аргумента методу store:

$path = $request->file('avatar')->store(
    'avatars/'.$request->user()->id, 's3'

Если вы используете метод storeAs, вы можете передать имя диска в качестве третьего аргумента метода:

$path = $request->file('avatar')->storeAs(

Другая информация о загружаемом файле

Если вы хотите получить оригинальное имя загружаемого файла, вы можете сделать это с помощью метода getClientOriginalName:

$name = $request->file('avatar')->getClientOriginalName();

Метод extension используется для получения расширения загружаемого файла:

$extension = $request->file('avatar')->extension();

Видимость файла

В интеграции Laravel Flysystem «видимость» – это абстракция прав доступа к файлам на нескольких платформах. Файлы могут быть объявлены public или private. Когда файл объявляется public, вы указываете, что файл обычно должен быть доступен для других. Например, при использовании драйвера s3 вы можете получить URL-адреса для public файлов.

Вы можете задать видимость при записи файла с помощью метода put:

use Illuminate\Support\Facades\Storage;

Storage::put('file.jpg', $contents, 'public');

Если файл уже был сохранен, его видимость может быть получена и задана с помощью методов getVisibility и setVisibility, соответственно:

$visibility = Storage::getVisibility('file.jpg');

Storage::setVisibility('file.jpg', 'public');

При взаимодействии с загружаемыми файлами, вы можете использовать методы storePublicly и storePubliclyAs для сохранения загружаемого файла с видимостью public:

$path = $request->file('avatar')->storePublicly('avatars', 's3');

$path = $request->file('avatar')->storePubliclyAs(

Локальные файлы и видимость

При использовании драйвера local, видимость public интерпретируется в право доступа 0755 для каталогов и право доступа 0644 для файлов. Вы можете изменить сопоставление прав доступа в файле конфигурации filesystems вашего приложения:

'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
    'permissions' => [
        'file' => [
            'public' => 0664,
            'private' => 0600,
        'dir' => [
            'public' => 0775,
            'private' => 0700,

Удаление файлов

Метод delete принимает имя одного файла или массив имен файлов для удаления:

use Illuminate\Support\Facades\Storage;


Storage::delete(['file.jpg', 'file2.jpg']);

При необходимости вы можете указать диск, с которого следует удалить файл:

use Illuminate\Support\Facades\Storage;



Получение всех файлов каталога

Метод files возвращает массив всех файлов указанного каталога. Если вы хотите получить список всех файлов каталога, включая все подкаталоги, вы можете использовать метод allFiles:

use Illuminate\Support\Facades\Storage;

$files = Storage::files($directory);

$files = Storage::allFiles($directory);

Получение всех каталогов из каталога

Метод directories возвращает массив всех каталогов указанного каталога. Кроме того, вы можете использовать метод allDirectories, чтобы получить список всех каталогов внутри указанного каталога и всех его подкаталогов:

$directories = Storage::directories($directory);

$directories = Storage::allDirectories($directory);

Создание каталога

Метод makeDirectory создаст указанный каталог, включая все необходимые подкаталоги:


Удаление каталога

Наконец, для удаления каталога и всех его файлов можно использовать метод deleteDirectory:



  1. Go to /public directory and run:

    rm storage

  2. Go to Laravel root directory and run:

    php artisan storage:link

Edited on May 1st 2018

This problem comes when laravel project is moved/copied to some other folder.

The storage link is still there thus causing the exception error. public/storage folder exists and points to wrong location and it needs to be deleted with rm storage command.

After that run php artisan storage:link in terminal and it will create the storage link.

This needs to be done EVERY time when laravel is moved/copied/deployed!


This usually happens after moving Laravel app to another directory

The actual storage directory is "/AppName/storage/app/public/"

Laravel creates a symbolic link pointing to actual storage dir "/AppName/public/storage"

Other meaning

"/AppName/public/storage" points to => "/AppName/storage/app/public/"

On changing root app directory to "/AnotherAppName/" symlink will still point to the old path

"/AnotherAppName/public/storage" => "/AppName/storage/app/public/"

my solution is to manually update the symlink using

ln -sfn /AnotherAppName/storage/app/public/ /AnotherAppName/public/storage


I'm face same error when use share hosting and my public directory move to public_html or different directorylike : project directory in root name "project"and public directory in root name "public_html"

when run artisan command by Artisan::call('storage:link'); then face this error.

Solution: 1st need to bind your public directory in app/Providers/AppServiceProvider register method

 $this->app->bind('path.public', function() {
return base_path('../public_html');

Now run the command its working fine