Saat mengunggah project Laravel ke shared hosting atau cPanel, terkadang pengguna tidak mendapatkan akses SSH atau Terminal. Akibatnya, beberapa perintah penting Laravel tidak bisa dijalankan secara langsung, seperti:
php artisan storage:link
php artisan config:clear
php artisan cache:clear
php artisan config:cache
php artisan key:generate
Sebagai alternatif, kita dapat membuat file PHP sementara yang menjalankan perintah Artisan melalui browser. Kita juga dapat membuat symbolic link secara manual menggunakan fungsi symlink() dari PHP.
Artikel ini membahas cara:
-
Membuat symbolic link folder storage secara manual.
-
Menjalankan perintah Artisan Laravel melalui browser.
-
Menghapus symbolic link atau folder
public/storageyang lama. -
Membuat ulang storage link Laravel.
-
Menghindari risiko keamanan ketika menjalankan script melalui browser.
Mengapa Laravel Membutuhkan Storage Link?
Secara default, file publik Laravel disimpan di:
storage/app/public
Namun folder tersebut tidak dapat diakses langsung dari browser. Agar file dapat dibuka melalui URL, Laravel membuat symbolic link dari:
public/storage
menuju:
storage/app/public
Dengan demikian, file yang disimpan menggunakan disk public dapat diakses melalui URL seperti:
https://domainsaya.com/storage/nama-file.jpg
Perintah standar Laravel untuk membuat link tersebut adalah:
php artisan storage:link
Jika hosting tidak menyediakan SSH atau Terminal, kita dapat membuat link tersebut menggunakan file PHP.
Struktur Folder Project
Pada contoh ini, struktur folder hosting adalah:
/home/username/domainsaya.com/
├── laravelapp/
│ ├── app/
│ ├── bootstrap/
│ ├── config/
│ ├── public/
│ ├── storage/
│ ├── vendor/
│ └── artisan
│
└── artisan-run.php
Folder project Laravel berada di:
/home/username/domainsaya.com/laravelapp
Pastikan document root domain sudah diarahkan ke folder:
/home/username/domainsaya.com/laravelapp/public
Pengaturan document root biasanya dapat dilakukan melalui menu Domains di cPanel.
Metode 1: Membuat Symbolic Link secara Manual
Buat file PHP sementara, misalnya:
storage-link.php
Letakkan file tersebut di folder yang dapat dibuka melalui browser.
Gunakan kode berikut:
<?php
declare(strict_types=1);
$target = '/home/username/domainsaya.com/laravelapp/storage/app/public';
$link = '/home/username/domainsaya.com/laravelapp/public/storage';
header('Content-Type: text/plain; charset=UTF-8');
echo "Target: {$target}\n";
echo "Link: {$link}\n\n";
if (!is_dir($target)) {
exit(
"GAGAL: Folder target tidak ditemukan.\n" .
"Periksa kembali lokasi storage/app/public.\n"
);
}
if (is_link($link)) {
exit(
"Symbolic link storage sudah tersedia.\n" .
"Mengarah ke: " . readlink($link) . "\n"
);
}
if (file_exists($link)) {
exit(
"GAGAL: Sudah ada folder atau file pada lokasi berikut:\n" .
"{$link}\n\n" .
"Hapus atau ubah nama folder storage tersebut terlebih dahulu."
);
}
if (!function_exists('symlink')) {
exit(
"GAGAL: Fungsi symlink() tidak tersedia.\n" .
"Kemungkinan fungsi tersebut dinonaktifkan oleh penyedia hosting."
);
}
if (symlink($target, $link)) {
echo "BERHASIL membuat symbolic link:\n\n";
echo "{$link}\n";
echo "-> {$target}\n";
} else {
$error = error_get_last();
echo "GAGAL membuat symbolic link.\n";
if ($error !== null) {
echo "Error: {$error['message']}\n";
}
echo "\nKemungkinan pembuatan symbolic link diblokir oleh hosting.";
}
Penjelasan Variabel Target dan Link
Variabel $target merupakan folder asli tempat file publik Laravel disimpan:
$target = '/home/username/domainsaya.com/laravelapp/storage/app/public';
Variabel $link adalah lokasi symbolic link yang akan dibuat:
$link = '/home/username/domainsaya.com/laravelapp/public/storage';
Hasil akhirnya adalah:
laravelapp/public/storage
->
laravelapp/storage/app/public
Jangan menggunakan folder root domain sebagai nilai $link, seperti:
$link = '/home/username/domainsaya.com/';
Folder tersebut sudah tersedia sehingga file_exists() pasti menghasilkan nilai true. Selain itu, symbolic link harus memiliki nama tujuan, yaitu storage.
Menjalankan Script Storage Link
Setelah file diunggah, buka melalui browser:
https://domainsaya.com/storage-link.php
Jika berhasil, hasilnya kurang lebih seperti berikut:
BERHASIL membuat symbolic link:
/home/username/project/public/storage
->
/home/username/project/storage/app/public
Kemudian lakukan pengujian dengan membuka file yang berada di dalam storage/app/public.
Contoh:
https://domainsaya.com/storage/contoh.jpg
Metode 2: Menjalankan Artisan Laravel Melalui Browser
Selain membuat symbolic link secara manual, kita juga dapat memanggil Laravel Console Kernel agar perintah Artisan dapat dijalankan melalui PHP.
Buat file:
artisan-run.php
Letakkan di folder satu tingkat di atas project Laravel atau sesuaikan nilai $projectPath.
Gunakan kode berikut:
<?php
declare(strict_types=1);
ob_start();
use Illuminate\Contracts\Console\Kernel;
$projectPath = __DIR__ . '/laravelapp';
require $projectPath . '/vendor/autoload.php';
$app = require_once $projectPath . '/bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$publicStorage = $projectPath . '/public/storage';
/**
* Menghapus file, symbolic link, atau folder beserta seluruh isinya.
*/
function removeStoragePath(string $path): bool
{
if (is_link($path) || is_file($path)) {
return unlink($path);
}
if (!is_dir($path)) {
return true;
}
$items = scandir($path);
if ($items === false) {
return false;
}
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$itemPath = $path . DIRECTORY_SEPARATOR . $item;
if (is_link($itemPath) || is_file($itemPath)) {
if (!unlink($itemPath)) {
return false;
}
continue;
}
if (is_dir($itemPath) && !removeStoragePath($itemPath)) {
return false;
}
}
return rmdir($path);
}
$output = [];
$output[] = 'Project Laravel: ' . $projectPath;
$output[] = 'Public storage: ' . $publicStorage;
$output[] = '';
try {
/*
|--------------------------------------------------------------------------
| Hapus public/storage lama
|--------------------------------------------------------------------------
*/
if (is_link($publicStorage)) {
if (!unlink($publicStorage)) {
throw new RuntimeException(
'Gagal menghapus symbolic link storage lama.'
);
}
$output[] = 'Symbolic link storage lama berhasil dihapus.';
} elseif (is_dir($publicStorage)) {
if (!removeStoragePath($publicStorage)) {
throw new RuntimeException(
'Gagal menghapus folder public/storage lama.'
);
}
$output[] = 'Folder public/storage lama berhasil dihapus.';
} elseif (file_exists($publicStorage)) {
if (!unlink($publicStorage)) {
throw new RuntimeException(
'Gagal menghapus file public/storage lama.'
);
}
$output[] = 'File public/storage lama berhasil dihapus.';
} else {
$output[] = 'Public storage lama tidak ditemukan.';
}
$output[] = '';
/*
|--------------------------------------------------------------------------
| Jalankan perintah Artisan
|--------------------------------------------------------------------------
*/
$commands = [
'config:clear',
'storage:link',
'cache:clear',
'config:cache',
];
foreach ($commands as $command) {
$output[] = 'Menjalankan: php artisan ' . $command;
try {
$exitCode = $kernel->call($command);
$commandOutput = trim($kernel->output());
if ($commandOutput !== '') {
$output[] = $commandOutput;
}
$output[] = 'Exit code: ' . $exitCode;
} catch (Throwable $exception) {
$output[] = 'ERROR: ' . $exception->getMessage();
}
$output[] = '';
}
} catch (Throwable $exception) {
$output[] = 'ERROR UTAMA: ' . $exception->getMessage();
}
ob_clean();
header('Content-Type: text/plain; charset=UTF-8');
echo implode(PHP_EOL, $output);
Perintah Artisan yang Dijalankan
Script tersebut menjalankan beberapa perintah berikut.
Menghapus Cache Konfigurasi
php artisan config:clear
Perintah ini menghapus cache konfigurasi Laravel agar perubahan pada file .env dapat dibaca ulang.
Membuat Storage Link
php artisan storage:link
Perintah ini membuat symbolic link:
public/storage
->
storage/app/public
Menghapus Cache Aplikasi
php artisan cache:clear
Perintah ini menghapus cache aplikasi Laravel.
Membuat Ulang Cache Konfigurasi
php artisan config:cache
Perintah ini menyimpan konfigurasi Laravel dalam bentuk cache agar aplikasi berjalan lebih efisien pada lingkungan production.
Cara Menggunakan Artisan Runner
1. Periksa Lokasi Project
Pastikan baris berikut sesuai dengan nama folder project Laravel:
$projectPath = __DIR__ . '/laravelapp';
Jika nama folder Laravel adalah aplikasi, ubah menjadi:
$projectPath = __DIR__ . '/aplikasi';
2. Upload File ke Hosting
Upload artisan-run.php ke folder yang sama dengan folder project.
Contoh:
/home/username/domainsaya.com/artisan-run.php
/home/username/domainsaya.com/laravelapp/
3. Buka melalui Browser
Buka URL file tersebut:
https://domainsaya.com/artisan-run.php
Script akan:
-
Memeriksa lokasi project.
-
Menghapus
public/storagelama. -
Menjalankan
config:clear. -
Menjalankan
storage:link. -
Menjalankan
cache:clear. -
Menjalankan
config:cache. -
Menampilkan hasil setiap perintah.
4. Periksa Exit Code
Apabila berhasil, biasanya setiap perintah akan menampilkan:
Exit code: 0
Exit code 0 menunjukkan bahwa perintah berhasil dijalankan.
Cara Membuat APP_KEY Tanpa SSH
Untuk instalasi Laravel baru yang belum memiliki APP_KEY, tambahkan perintah berikut ke dalam array $commands:
'key:generate --force',
Contohnya:
$commands = [
'key:generate --force',
'config:clear',
'storage:link',
'cache:clear',
'config:cache',
];
Namun perintah tersebut hanya boleh dijalankan untuk instalasi baru.
Setelah APP_KEY berhasil dibuat, segera hapus perintah:
'key:generate --force',
Jangan menjalankan key:generate --force berulang kali pada aplikasi yang sudah aktif.
Mengganti APP_KEY dapat menyebabkan:
-
Session pengguna tidak dapat dibaca.
-
Cookie terenkripsi menjadi tidak valid.
-
Data terenkripsi Laravel tidak dapat dibuka.
-
Pengguna otomatis logout.
-
Fitur reset password atau token tertentu bermasalah.
-
Data yang disimpan menggunakan
Crypttidak dapat dipulihkan menggunakan key baru.
Mengatur APP_URL Laravel
Buka file .env, lalu atur APP_URL sesuai domain aplikasi:
APP_URL=https://domainsaya.com
Pastikan tidak menggunakan slash tambahan di akhir URL:
APP_URL=https://domainsaya.com/
Walaupun sebagian besar konfigurasi tetap berjalan, format yang lebih konsisten adalah:
APP_URL=https://domainsaya.com
Setelah mengubah .env, jalankan:
php artisan config:clear
php artisan config:cache
Mengatasi Error Cache Database
Pada beberapa project Laravel, perintah berikut dapat menampilkan error database:
php artisan cache:clear
Hal ini biasanya terjadi karena cache menggunakan driver database, tetapi tabel cache belum tersedia atau koneksi database belum benar.
Periksa konfigurasi .env:
CACHE_STORE=file
SESSION_DRIVER=file
Pada project Laravel versi lama, konfigurasi cache mungkin menggunakan:
CACHE_DRIVER=file
SESSION_DRIVER=file
Kemudian jalankan ulang:
php artisan config:clear
php artisan cache:clear
php artisan config:cache
Jika project memang menggunakan database sebagai tempat penyimpanan cache, pastikan tabel cache sudah dibuat:
php artisan cache:table
php artisan migrate
Karena artikel ini membahas hosting tanpa SSH, perintah tersebut juga dapat dimasukkan sementara ke dalam array $commands.
Contoh:
$commands = [
'config:clear',
'cache:table',
'migrate --force',
'cache:clear',
'config:cache',
];
Jalankan migrasi hanya jika sudah memahami perubahan database yang akan dilakukan.
Error Symbolic Link Sudah Tersedia
Jika muncul pesan:
The [public/storage] link already exists
berarti sudah terdapat file, folder, atau symbolic link di:
public/storage
Script Artisan Runner di atas akan mencoba menghapus lokasi tersebut sebelum menjalankan:
php artisan storage:link
Jika ingin menghapus symbolic link secara manual melalui PHP, gunakan:
<?php
$storagePath = __DIR__ . '/laravelapp/public/storage';
if (is_link($storagePath)) {
if (unlink($storagePath)) {
echo 'Symbolic link berhasil dihapus.';
} else {
echo 'Symbolic link gagal dihapus.';
}
} else {
echo 'Lokasi tersebut bukan symbolic link.';
}
Jangan menghapus folder berikut:
storage/app/public
Folder tersebut adalah lokasi asli file upload Laravel.
Yang boleh dihapus untuk dibuat ulang adalah:
public/storage
Error Fungsi symlink Dinonaktifkan
Jika muncul pesan seperti:
Call to undefined function symlink()
atau:
symlink() has been disabled for security reasons
kemungkinan penyedia hosting menonaktifkan fungsi symlink().
Beberapa solusi yang dapat dilakukan:
-
Gunakan menu Terminal cPanel jika tersedia.
-
Hubungi penyedia hosting dan minta dibuatkan symbolic link.
-
Minta penyedia hosting mengaktifkan fungsi
symlink(). -
Gunakan perintah Artisan melalui Laravel Console Kernel.
-
Ubah konfigurasi penyimpanan apabila hosting benar-benar tidak mendukung symbolic link.
Pada shared hosting tertentu, symbolic link juga dapat dibatasi menggunakan konfigurasi open_basedir.
Error Cannot Modify Header Information
Error berikut dapat muncul ketika Laravel mencoba mengirim header setelah script lebih dahulu mencetak output:
Cannot modify header information - headers already sent
Karena itu, script Artisan Runner menggunakan:
ob_start();
Kemudian sebelum mencetak hasil akhir, buffer dibersihkan menggunakan:
ob_clean();
Pastikan tidak ada:
-
Spasi sebelum
<?php. -
Teks HTML sebelum kode PHP.
-
Tanda backtick Markdown.
-
Penutup kode seperti tiga tanda backtick.
-
Karakter tersembunyi sebelum tag PHP.
-
Lebih dari satu tag
<?phpyang tidak diperlukan.
Keamanan dan Disclaimer
Script pada artikel ini menjalankan perintah Laravel melalui URL publik. Oleh karena itu, penggunaannya memiliki risiko keamanan apabila file dibiarkan berada di hosting.
Setelah perintah berhasil dijalankan, segera hapus file berikut:
artisan-run.php
storage-link.php
Jangan membiarkan file tersebut dapat diakses oleh orang lain.
Orang yang mengetahui URL file dapat menjalankan ulang perintah dan berpotensi:
-
Menghapus symbolic link storage.
-
Menghapus folder
public/storage. -
Menghapus cache aplikasi.
-
Mengubah konfigurasi aplikasi.
-
Mengganti
APP_KEYapabila perintah tersebut masih tersedia. -
Menyebabkan aplikasi mengalami error atau downtime.
Sebelum menjalankan script, lakukan backup terhadap:
-
File
.env. -
Database aplikasi.
-
Folder
storage/app/public. -
Konfigurasi domain.
-
Folder project Laravel.
Kode dalam artikel ini harus disesuaikan dengan struktur folder masing-masing hosting. Jangan menyalin path contoh tanpa memeriksa lokasi project melalui File Manager cPanel.
Penulis tidak bertanggung jawab atas kehilangan file, kerusakan aplikasi, perubahan data, error konfigurasi, atau gangguan layanan akibat kesalahan penggunaan script.
Rekomendasi Penggunaan yang Lebih Aman
Tambahkan token rahasia agar file tidak dapat dijalankan sembarang orang.
Contoh:
<?php
declare(strict_types=1);
$secretToken = 'ganti-dengan-token-rahasia-yang-panjang';
$providedToken = $_GET['token'] ?? '';
if (!hash_equals($secretToken, $providedToken)) {
http_response_code(403);
exit('Akses ditolak.');
}
Kemudian buka file menggunakan URL:
https://domainsaya.com/artisan-run.php?token=ganti-dengan-token-rahasia-yang-panjang
Walaupun sudah menggunakan token, file tetap harus segera dihapus setelah selesai digunakan.
Kesimpulan
Pada hosting cPanel tanpa SSH, perintah Artisan Laravel tetap dapat dijalankan dengan memanggil Console Kernel melalui file PHP sementara.
Untuk membuat file upload Laravel dapat diakses dari browser, pastikan symbolic link berikut tersedia:
public/storage
->
storage/app/public
Gunakan file storage-link.php apabila hanya ingin membuat symbolic link. Gunakan artisan-run.php apabila ingin menjalankan beberapa perintah Artisan sekaligus.
Hal terpenting yang harus diperhatikan adalah:
-
Sesuaikan path project dengan struktur hosting.
-
Jangan menghapus
storage/app/public. -
Hanya hapus
public/storageketika ingin membuat ulang link. -
Jangan menjalankan
key:generate --forcepada aplikasi aktif. -
Backup aplikasi sebelum menjalankan script.
-
Hapus seluruh file runner setelah proses selesai.