Skip to main content

File Uploads

Core Forms supports file uploads with multi-layered security: extension blocklisting, MIME type validation, double extension detection, filename sanitization, and server-level execution prevention.

Basic Usage

Add a file input to your form HTML:

<p>
    <label for="resume">Upload Resume</label>
    <input type="file" name="resume" id="resume" required />
</p>

Core Forms automatically handles the upload, validation, and storage.

Security Layers

1. Blocked Extensions (30+)

The following extensions are rejected immediately:

php, php3, php4, php5, php7, php8, phtml, phar
exe, bat, cmd, com, msi
sh, bash, csh, ksh, zsh
cgi, pl, py, rb, jsp, asp, aspx
htaccess, htpasswd
svg, shtml, shtm
swf

2. Double Extension Detection

Filenames with dangerous inner extensions are blocked:

file.php.jpg      -> BLOCKED (php in middle)
report.exe.pdf    -> BLOCKED (exe in middle)
photo.png         -> ALLOWED
data.backup.csv   -> ALLOWED (backup is not dangerous)

3. MIME Type Validation

The actual file content is inspected using finfo to detect the real MIME type. If the detected MIME type does not match the file extension, the upload is rejected:

// file.jpg with actual content of a PHP script -> REJECTED
$detected_mime = Uploader::detect_mime_type( $filepath );
if ( ! Uploader::mime_matches_extension( $detected_mime, $extension ) ) {
    return 'file_mime_mismatch';
}

Supported MIME Types

Category Extensions
Images jpg, jpeg, jpe, png, gif, webp, avif, bmp, tif, tiff
Documents pdf, doc, docx, xls, xlsx, ppt, pptx, odt, ods, rtf
Text txt, log, csv
Archives zip, rar, gz, 7z
Audio mp3, wav, ogg, m4a
Video mp4, webm, mov, avi

4. Filename Sanitization

Uploaded filenames are cleaned before storage:

$safe = Uploader::sanitize_filename( $original );
// "My Report (final).pdf"  -> "My-Report-final.pdf"
// "../../etc/passwd"       -> "etcpasswd"
// "<script>hack</script>"  -> "scripthackscript"

Rules applied: - Remove dangerous characters: < > : " / \ | ? * and control characters - Normalize whitespace to hyphens - Collapse multiple hyphens - Trim hyphens from edges - Empty names default to upload

5. Server-Level Protection

An .htaccess file is written to the upload directory to prevent script execution:

# Prevent script execution
<FilesMatch "\.(?:php|phar|phtml|php[0-9]|cgi|pl|py|rb|sh|bash|asp|aspx|jsp)$">
Order allow,deny
Deny from all
</FilesMatch>

An index.php file prevents directory listing.

File Size Limit

Default maximum file size is 8 MB (8,000,000 bytes). Customize with the cf_upload_max_filesize filter:

// Allow up to 25 MB
add_filter( 'cf_upload_max_filesize', function() {
    return 25 * 1024 * 1024; // 25 MB in bytes
} );

Storage Location

Files are stored in:

wp-content/uploads/core-forms/{form-slug}/{id}_{field}_{uniqid}.{ext}

Example: wp-content/uploads/core-forms/contact/42_resume_6612a3b4c5d6e.pdf

Media Library Integration

By default, uploaded files are added to the WordPress Media Library as private attachments. Disable this with:

add_filter( 'cf_upload_add_to_media', '__return_false' );

Submission Data

After upload, the field data in the submission contains:

$submission->data['resume'] = [
    'name'          => '42_resume_6612a3b4c5d6e.pdf',
    'original_name' => 'My-Resume.pdf',
    'url'           => 'https://example.com/wp-content/uploads/core-forms/contact/42_resume_6612a3b4c5d6e.pdf',
    'dir'           => '/var/www/html/wp-content/uploads/core-forms/contact',
    'size'          => 245760,
    'type'          => 'application/pdf',
    'attachment_id' => 567,
];

Error Messages

Custom error messages for file validation failures:

Error Code Default Message
file_too_large Uploaded file is too large.
file_upload_error An upload error occurred. Please try again later.
file_invalid_extension This file type is not allowed.
file_mime_mismatch The uploaded file does not match its extension. Please upload a valid file.

Related