Skip to content

Fix: upload themes#1620

Open
pandigresik wants to merge 6 commits into
rilis-devfrom
fix/upload_themes
Open

Fix: upload themes#1620
pandigresik wants to merge 6 commits into
rilis-devfrom
fix/upload_themes

Conversation

@pandigresik

@pandigresik pandigresik commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Pull Request: Fix upload themes validation and path issues

Description

Fix multiple issues in theme upload flow: invalid file uploads were not being validated before processing, temporary extraction path used the wrong storage disk, uploaded filename hash did not match the folder inside zip, and scanZipForPhp incorrectly blocked Blade template files. Also updates .gitignore to properly exclude non-default theme directories.

Changes made:

  1. Bug Fix (ThemesController.php): Added $file->isValid() check before processing upload to catch corrupted or failed uploads early and return a specific error message
  2. Bug Fix (ThemeService.php): Fixed storage path from storage_path('framework/themes') to Storage::disk('public')->path('framework/themes') so the temporary zip file is found during extraction
  3. Bug Fix (ThemeService.php): Replaced explode('.', $fileName)[0] folder guessing with recursive findComposerJson() search to handle renamed files from uploadSecure
  4. Bug Fix (ThemeHooksValidator.php): Added .blade.php skip in scanZipForPhp so legitimate Blade template files are not blocked
  5. Config (.gitignore): Uncommented /themes/* rule to ignore non-default theme directories

Reason for change:

  • Upload Validation: Previously, if an uploaded file failed PHP's validation (e.g., exceeded upload_max_filesize), no error was returned to the user, causing a generic failure later
  • Wrong Storage Path: storage_path() returns the default Laravel storage path, but the file was actually stored on the public disk via FileUploadService, so the zip could not be found for extraction
  • Mismatched Folder Name: uploadSecure renames files to {timestamp}_{random}.zip, so deriving folder name from filename produced a non-existent path
  • Blade Files Blocked: scanZipForPhp rejected all .php files including safe .blade.php templates, preventing valid themes from being uploaded
  • Gitignore: Non-default themes like themes/opendk/buen were not excluded from version control

Impact of change:

Better Error Messages: Users now see specific error messages for invalid file uploads and missing composer.json
Reliable Extraction: Zip files are now found and extracted from the correct disk path; folder name auto-detected regardless of uploaded filename
Blade Templates Allowed: Legitimate .blade.php files pass through while dangerous .php files are still blocked
Cleanup: Temporary files are always cleaned up on failure
Version Control: Only the default theme is tracked; other themes are properly ignored

Related Issue

#1619

Steps to Reproduce

Before fix (problem):

  1. Login to admin panel
  2. Go to Themes > Upload Theme
  3. Upload a corrupted zip file or a zip without composer.json
  4. Upload fails silently or returns generic error
  5. ❌ Orphaned files left in storage, no clear error message

After fix (solution):

  1. Login to admin panel
  2. Go to Themes > Upload Theme
  3. Upload a corrupted/invalid zip file
  4. ✅ Clear error message: "Upload file gagal: ..." or "file composer.json tidak ditemukan"
  5. ✅ No orphaned files left behind

Testing on related features:

  • Valid theme upload (with .blade.php files) ✅ Working
  • Upload without file ✅ Returns error
  • Upload invalid/corrupted file ✅ Returns specific error
  • Upload zip without composer.json ✅ Returns specific error, files cleaned up
  • Upload zip renamed by uploadSecure ✅ Folder auto-detected correctly
  • scanZipForPhp blocks dangerous .php but allows .blade.php ✅ Working

Checklist

  • I have complied with script writing rules
  • I have followed pull request review process
  • I have created unit test/integration test to verify the fix
  • Manual testing has been done in development environment
  • No console errors or warnings
  • Code has been reviewed by at least 1 person

Technical Details

Technical Explanation

ThemesController.php (upload method):

  • Added $file->isValid() check after the null check, returning a JSON error with $file->getErrorMessage() if the upload failed during PHP processing

ThemeService.php (installFromZip method):

  • Changed $filePath = storage_path('framework/themes') to $filePath = Storage::disk('public')->path('framework/themes')FileUploadService::uploadSecure() stores files on the public disk, so the path must resolve to the same disk
  • Previously used $folderTheme = explode('.', $fileName)[0] to guess the extracted folder name, but uploadSecure renames the file to {timestamp}_{random}.zip, causing a mismatch. Replaced with new findComposerJson() method that recursively searches for composer.json in the extracted directory using RecursiveDirectoryIterator, making folder detection reliable regardless of uploaded filename

ThemeHooksValidator.php (scanZipForPhp method):

  • Added str_ends_with($filename, '.blade.php') check to skip Blade template files before checking against dangerous extensions. Blade files are safe — they are rendered by Laravel's template engine and cannot execute arbitrary PHP functions like exec, system, eval

.gitignore:

  • Uncommented /themes/* rule so that only !/themes/opendk/default/ is tracked; other themes like themes/opendk/buen are properly ignored

Configuration changes

  • .gitignore: Enabled /themes/* ignore pattern

Dependencies added

No new dependencies

Testing

Manual Testing

  • Upload valid theme zip — success
  • Upload corrupted zip — error message displayed
  • Upload zip without composer.json — error message displayed, no orphaned files
  • Upload without selecting file — error message displayed
  • Regression: existing theme activation and deletion still work

Automated Testing

  • TODO: Add unit test for invalid file upload validation
  • TODO: Add unit test for missing composer.json scenario

Breaking Changes

None

Migration Guide

Not required

References

Video

simplescreenrecorder-2026-07-08_16.36.32.mp4

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

🔄 AI PR Review sedang antri di server...

Proses review akan segera dimulai di background — hasil akan muncul sebagai komentar setelah selesai.
Powered by CrewAI · PR #1620

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant