Whatever message this page gives is out now! Go check it out!
<cffile
action = "upload"
allowedExtensions="comma-separated list of file extensions"
destination = "full pathname"
fileField = "form field"
accept = "MIME type|file type"
attributes = "file attribute or list"
mode = "permission"
nameConflict = "behavior"
result = "result name"
strict="true|false"
ContinueOnError = "true|false"
Errors = "variable in which the file upload errors will be stored">Attribute | Req/Opt | Default | Description |
action | Required | Type of file manipulation that the tag performs. | |
| allowedExtensions | Optional | A comma-separated list of file extensions, which will be allowed for upload. For example, .png, .jpg, or, .jpeg. You can use "*" (star) to allow all files, except where you specify the MIME type in the accept attribute. Values specified in the attribute allowedExtensions override the list of blocked extensions in the server or application settings. | |
destination | Required | Pathname of directory in which to upload the file. If not an absolute path (starting with a drive letter and a colon, or a forward or backward slash), it is relative to the ColdFusion temporary directory, which is returned by the GetTempDirectory function. If the destination you specify does not exist, ColdFusion creates a file with the specified destination name. For example, if you specify the destination, C:\XYZ, ColdFusion creates a file XYZ in the C: drive. | |
fileField | Optional | Name of form field used to select the file. Do not use number signs (#) to specify the field name. If omitted, it defaults to the name of the first file field submitted. | |
accept | Optional | Limits the MIME types to accept. It is a comma-delimited list. For example, the following code permits JPEG and Microsoft Word file uploads:"image/jpg,application/msword". When strict="true" If the mime type is specified in the accept attribute, the file does not get uploaded if the extension is blocked in the server or application settings. When strict="false" If you provide a file extension in the attribute accept, the extension overrides the blocked extension list in the server or application settings. The file then gets uploaded. If you provide a MIME type in the attribute accept, and the extension of the file you are trying to upload is blocked in the Administrator/Application-level settings, the file does not get uploaded. For example,
Values specified in the attribute allowedExtensions overrides the list of blocked extensions in the server or application settings. | |
attributes | Optional | Applies to Windows. A comma-delimited list of attributes to set on the file. If omitted, the file's attributes are maintained .Each value must be specified explicitly. For example, if you specify attributes = "readOnly", all other attributes are overwritten.
| |
mode | Optional | Applies only to UNIX and Linux. Permissions. Octal values of chmod command. Assigned to owner , group, and other, respectively, for example:
| |
nameConflict | Optional | Error | Action to take if filename is the same as that of a file in the directory.
|
result | Optional | Lets you specify a name for the variable in which cffile returns the result (or status) parameters. If you do not specify a value for this attribute, cffile uses the prefix cffile . For more information, see Usage. | |
strict | Optional | true | strict="false" If you provide a file extension in the attribute accept, the extension overrides the blocked extension list in the server or application settings. The file then gets uploaded. If you provide a MIME type in the attribute accept, and the extension of the file you are trying to upload is blocked in the Administrator/Application-level settings, the file does not get uploaded. For example,
strict="true" If the mime type is specified in the accept attribute, the file does not get uploaded if the extension is blocked in the server or application settings. For example, if you have blocked file type CFM in the ColdFusion Administrator and specified accept=”text/x-coldfusion” and strict=”true”, and you try uploading a cfm file, the file does not get uploaded. Values specified in the attribute allowedExtensions overrides the list of blocked extensions in the server or application settings. |
| ContinueOnError | Optional | False | By default, when uploading a file fails, the remaining files will not be uploaded. If this value is set to true, file upload continues even after encountering an upload error. A file upload error happens due to the following reasons: 1. Empty file 2. Invalid file type 3. Invalid MIME or extension 4. File already exists In the case of an upload failure, the error details will be stored in the errors attribute. |
| Errors | Optional | cffile .uploadAllErrors | The name of the variable in which the file upload errors will be stored. Errors will be populated in the specified variable name when continueOnError is true .After the file upload is completed, this tag creates an array of structures that contains upload failure information for each upload failure. The upload failure information error structure contains the following fields:
|
Parameter | Description |
attemptedServerFile | Initial name ColdFusion used when attempting to save a file |
clientDirectory | Directory location of the file uploaded from the client's system |
clientFile | Name of the file uploaded from the client's system |
clientFileExt | Extension of the uploaded file on the client system (without a period) |
clientFileName | Name of the uploaded file on the client system (without an extension) |
contentSubType | MIME content subtype of the saved file |
contentType | MIME content type of the saved file |
dateLastAccessed | Date and time the uploaded file was last accessed |
fileExisted | Whether the file existed with the same path (yes or no) |
fileSize | Size of the uploaded file in bytes |
fileWasAppended | Whether ColdFusion appended uploaded file to a file (yes or no) |
fileWasOverwritten | Whether ColdFusion overwrote a file (yes or no) |
fileWasRenamed | Whether uploaded file renamed to avoid a name conflict (yes or no) |
fileWasSaved | Whether ColdFusion saves a file (yes or no) |
oldFileSize | Size of a file that was overwritten in the file upload operation |
serverDirectory | Directory of the file saved on the server |
serverFile | Filename of the file saved on the server |
serverFileExt | Extension of the uploaded file on the server (without a period) |
serverFileName | Name of the uploaded file on the server (without an extension) |
timeCreated | Time the uploaded file was created |
timeLastModified | Date and time of the last modification to the uploaded file |
<!--- Windows Example --->
<!--- Check to see if the Form variable exists. --->
<cfif isDefined("Form.FileContents") >
<!--- If TRUE, upload the file. --->
<cffile action = "upload"
fileField = "FileContents"
destination = "c:\files\upload\"
accept = "text/html"
nameConflict = "MakeUnique">
<cfelse>
<!--- If FALSE, show the Form. --->
<form method="post" action=<cfoutput>#cgi.script_name#</cfoutput>
name="uploadForm" enctype="multipart/form-data">
<input name="FileContents" type="file">
<br>
<input name="submit" type="submit" value="Upload File">
</form>
</cfif><cffile
action="upload"
destination="#expandpath(".")#"
nameconflict="MakeUnique"
accept="image/png, image/gif"
allowedextensions=".png, .gif"
strict="true"
continueonerror="true"
><cfset maxFileSize = 5242880><!--- 5MB in bytes --->
<cfset uploadStatus = {}>
<!--- Check if file was submitted --->
<cfif structKeyExists(form, "employeeDocument")>
<cftry>
<!--- Upload the file --->
<cffile
action="upload"
fileField="employeeDocument"
destination="#expandPath('./uploads/employees/')#"
nameConflict="makeUnique"
accept="application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
result="uploadResult"
mode="644">
<!--- Validate file size after upload --->
<cfif uploadResult.fileSize GT maxFileSize>
<!--- Delete the uploaded file if too large --->
<cfif fileExists("#uploadResult.serverDirectory#/#uploadResult.serverFile#")>
<cffile action="delete" file="#uploadResult.serverDirectory#/#uploadResult.serverFile#">
</cfif>
<cfset uploadStatus.success = false>
<cfset uploadStatus.message = "File size exceeds 5MB limit. Please upload a smaller file.">
<cfelse>
<!--- Process successful upload --->
<cfset uploadStatus.success = true>
<cfset uploadStatus.originalFileName = uploadResult.clientFile>
<cfset uploadStatus.savedFileName = uploadResult.serverFile>
<cfset uploadStatus.fileSize = numberFormat(uploadResult.fileSize / 1024, "0.00")>
<cfset uploadStatus.uploadDate = dateTimeFormat(now(), "yyyy-mm-dd HH:nn:ss")>
<!--- Log to database (simulated) --->
<cfset uploadStatus.message = "Document uploaded successfully">
<!--- If file was renamed due to conflict --->
<cfif uploadResult.fileWasRenamed>
<cfset uploadStatus.warning = "File was renamed to avoid naming conflict">
</cfif>
</cfif>
<cfcatch type="any">
<cfset uploadStatus.success = false>
<cfset uploadStatus.message = "Upload failed: #cfcatch.message#">
</cfcatch>
</cftry>
</cfif>
<!DOCTYPE html>
<html>
<head>
<title>Employee Document Upload</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
.form-container { background: #f5f5f5; padding: 20px; border-radius: 8px; }
.success { background: #d4edda; color: #155724; padding: 15px; border-radius: 5px; margin: 20px 0; }
.error { background: #f8d7da; color: #721c24; padding: 15px; border-radius: 5px; margin: 20px 0; }
.warning { background: #fff3cd; color: #856404; padding: 10px; border-radius: 5px; margin: 10px 0; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input[type="file"] { padding: 10px; width: 100%; box-sizing: border-box; }
button { background: #007bff; color: white; padding: 12px 30px; border: none;
border-radius: 5px; cursor: pointer; font-size: 16px; }
button:hover { background: #0056b3; }
.info-box { background: #e7f3ff; padding: 15px; border-left: 4px solid #007bff; margin-bottom: 20px; }
.detail-row { padding: 5px 0; border-bottom: 1px solid #ddd; }
</style>
</head>
<body>
<h1>📄 Employee Document Upload</h1>
<div class="info-box">
<strong>Accepted Formats:</strong> PDF, DOC, DOCX<br>
<strong>Maximum Size:</strong> 5 MB
</div>
<!--- Display upload status --->
<cfif structKeyExists(uploadStatus, "success")>
<cfif uploadStatus.success>
<div class="success">
<h3>✓ #uploadStatus.message#</h3>
<div class="detail-row"><strong>Original Filename:</strong> #uploadStatus.originalFileName#</div>
<div class="detail-row"><strong>Saved As:</strong> #uploadStatus.savedFileName#</div>
<div class="detail-row"><strong>File Size:</strong> #uploadStatus.fileSize# KB</div>
<div class="detail-row"><strong>Upload Time:</strong> #uploadStatus.uploadDate#</div>
<cfif structKeyExists(uploadStatus, "warning")>
<div class="warning">⚠ #uploadStatus.warning#</div>
</cfif>
</div>
<cfelse>
<div class="error">
<strong>✗ Upload Failed</strong><br>
#uploadStatus.message#
</div>
</cfif>
</cfif>
<div class="form-container">
<h2>Upload Employee Document</h2>
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="employeeDocument">Select Document:</label>
<input type="file" name="employeeDocument" id="employeeDocument" required>
</div>
<div class="form-group">
<button type="submit">Upload Document</button>
</div>
</form>
</div>
<p style="color: #666; font-size: 12px; margin-top: 20px;">
<strong>Note for CFFiddle:</strong> This demonstrates upload validation and status reporting.
Actual file system operations may be restricted in the sandbox environment.
</p>
</body>
</html><cfset maxImageSize = 2097152><!--- 2MB limit for images --->
<cfset userId = randRange(1000, 9999)><!--- Simulated user session --->
<cfset uploadResult = {}>
<cfif structKeyExists(form, "profileImage")>
<cftry>
<!--- Upload with strict security settings --->
<cffile
action="upload"
fileField="profileImage"
destination="#expandPath('./uploads/profiles/')#"
nameConflict="overwrite"
accept="image/jpeg,image/png,image/gif"
allowedExtensions=".jpg,.jpeg,.png,.gif"
strict="true"
result="fileUpload">
<!--- Validate file size after upload --->
<cfif fileUpload.fileSize GT maxImageSize>
<!--- Delete the uploaded file if too large --->
<cfif fileExists("#fileUpload.serverDirectory#/#fileUpload.serverFile#")>
<cffile action="delete" file="#fileUpload.serverDirectory#/#fileUpload.serverFile#">
</cfif>
<cfset uploadResult.status = "error">
<cfset uploadResult.message = "Image size must be under 2MB">
<cfelse>
<!--- Rename file to user-specific name --->
<cfset newFileName = "user_#userId#_profile.#fileUpload.serverFileExt#">
<cffile
action="rename"
source="#fileUpload.serverDirectory#/#fileUpload.serverFile#"
destination="#fileUpload.serverDirectory#/#newFileName#">
<!--- Build success response --->
<cfset uploadResult.status = "success">
<cfset uploadResult.message = "Profile image updated successfully!">
<cfset uploadResult.fileName = newFileName>
<cfset uploadResult.fileSize = numberFormat(fileUpload.fileSize / 1024, "0.00")>
<cfset uploadResult.imageType = fileUpload.contentType>
<cfset uploadResult.originalName = fileUpload.clientFile>
<cfset uploadResult.wasOverwritten = fileUpload.fileWasOverwritten>
</cfif>
<cfcatch type="any">
<cfset uploadResult.status = "error">
<cfif findNoCase("invalid MIME type", cfcatch.message)>
<cfset uploadResult.message = "Invalid file type. Please upload a valid image (JPG, PNG, or GIF)">
<cfelseif findNoCase("extension", cfcatch.message)>
<cfset uploadResult.message = "File extension not allowed. Only .jpg, .png, and .gif files are accepted">
<cfelse>
<cfset uploadResult.message = "Upload error: #cfcatch.message#">
</cfif>
</cfcatch>
</cftry>
</cfif>
<!DOCTYPE html>
<html>
<head>
<title>Profile Image Upload</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh; padding: 20px; }
.container { max-width: 500px; margin: 50px auto; background: white;
border-radius: 15px; box-shadow: 0 10px 40px rgba(0,0,0,0.2); overflow: hidden; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white; padding: 30px; text-align: center; }
.header h1 { font-size: 24px; margin-bottom: 5px; }
.header p { opacity: 0.9; font-size: 14px; }
.content { padding: 30px; }
.profile-preview { text-align: center; margin-bottom: 25px; }
.avatar { width: 120px; height: 120px; border-radius: 50%; border: 4px solid #667eea;
background: #f0f0f0; display: inline-flex; align-items: center;
justify-content: center; font-size: 48px; }
.upload-area { border: 2px dashed #667eea; border-radius: 10px; padding: 30px;
text-align: center; background: #f8f9ff; margin-bottom: 20px; }
.upload-area:hover { background: #f0f3ff; }
input[type="file"] { display: none; }
.file-label { background: #667eea; color: white; padding: 12px 25px;
border-radius: 25px; cursor: pointer; display: inline-block;
transition: all 0.3s; }
.file-label:hover { background: #5568d3; transform: translateY(-2px); }
button { width: 100%; background: #764ba2; color: white; padding: 15px;
border: none; border-radius: 8px; font-size: 16px; cursor: pointer;
font-weight: bold; transition: all 0.3s; }
button:hover { background: #653a8c; transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(118,75,162,0.3); }
.alert { padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.detail { display: flex; justify-content: space-between; padding: 10px 0;
border-bottom: 1px solid #eee; }
.detail:last-child { border-bottom: none; }
.detail strong { color: #667eea; }
.info-text { color: #666; font-size: 13px; text-align: center; margin-top: 15px; }
.badge { display: inline-block; padding: 3px 10px; border-radius: 12px;
font-size: 11px; font-weight: bold; }
.badge-new { background: #28a745; color: white; }
.badge-replaced { background: #ffc107; color: #000; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>👤 Profile Image Upload</h1>
<p>User ID: #userId#</p>
</div>
<div class="content">
<div class="profile-preview">
<div class="avatar">
<cfif structKeyExists(uploadResult, "status") AND uploadResult.status EQ "success">
📸
<cfelse>
👤
</cfif>
</div>
</div>
<!--- Display upload results --->
<cfif structKeyExists(uploadResult, "status")>
<cfif uploadResult.status EQ "success">
<div class="alert alert-success">
<strong>✓ #uploadResult.message#</strong>
<div style="margin-top: 15px;">
<div class="detail">
<span>Saved As:</span>
<strong>#uploadResult.fileName#</strong>
</div>
<div class="detail">
<span>Original Name:</span>
<span>#uploadResult.originalName#</span>
</div>
<div class="detail">
<span>File Size:</span>
<span>#uploadResult.fileSize# KB</span>
</div>
<div class="detail">
<span>Image Type:</span>
<span>#uploadResult.imageType#</span>
</div>
<div class="detail">
<span>Status:</span>
<cfif uploadResult.wasOverwritten>
<span class="badge badge-replaced">REPLACED</span>
<cfelse>
<span class="badge badge-new">NEW</span>
</cfif>
</div>
</div>
</div>
<cfelse>
<div class="alert alert-error">
<strong>✗ Upload Failed</strong><br>
#uploadResult.message#
</div>
</cfif>
</cfif>
<form method="post" enctype="multipart/form-data">
<div class="upload-area">
<p style="margin-bottom: 15px; color: #667eea; font-weight: bold;">
📁 Choose Your Profile Image
</p>
<label for="profileImage" class="file-label">Select Image File</label>
<input type="file" name="profileImage" id="profileImage" accept="image/jpeg,image/png,image/gif" required>
<p class="info-text">JPG, PNG or GIF • Max 2MB</p>
</div>
<button type="submit">🚀 Upload Profile Image</button>
</form>
<p class="info-text" style="margin-top: 20px;">
<strong>Security Features:</strong> MIME type validation, extension whitelist,
size limits enforced
</p>
</div>
</div>
</body>
</html><cfset uploadResults = []>
<cfset batchSummary = {
totalAttempted = 0,
successful = 0,
failed = 0,
totalSize = 0
}>
<cfif structKeyExists(form, "invoiceFile")>
<!--- Handle single or multiple file uploads --->
<cfset fileCount = 1>
<cftry>
<!--- Upload invoice with strict validation --->
<cffile
action="upload"
fileField="invoiceFile"
destination="#expandPath('./uploads/invoices/')#"
nameConflict="makeUnique"
accept="application/pdf"
allowedExtensions=".pdf"
strict="true"
continueOnError="true"
result="uploadData">
<cfset batchSummary.totalAttempted++>
<!--- Check if upload was successful --->
<cfif uploadData.fileWasSaved>
<!--- Generate invoice tracking number --->
<cfset invoiceId = "INV-#dateFormat(now(), 'yyyymmdd')#-#randRange(1000, 9999)#">
<!--- Create audit record --->
<cfset auditRecord = {
status = "success",
invoiceId = invoiceId,
originalFileName = uploadData.clientFile,
savedFileName = uploadData.serverFile,
fileSize = uploadData.fileSize,
uploadTimestamp = now(),
uploadedBy = "system_user",
fileHash = hash(uploadData.serverFile, "MD5"),
wasRenamed = uploadData.fileWasRenamed
}>
<cfset arrayAppend(uploadResults, auditRecord)>
<cfset batchSummary.successful++>
<cfset batchSummary.totalSize += uploadData.fileSize>
<cfelse>
<!--- Handle failed upload --->
<cfset errorRecord = {
status = "failed",
originalFileName = form.invoiceFile,
errorMessage = "File was not saved - validation failed",
timestamp = now()
}>
<cfset arrayAppend(uploadResults, errorRecord)>
<cfset batchSummary.failed++>
</cfif>
<cfcatch type="any">
<!--- Log error but continue processing --->
<cfset batchSummary.totalAttempted++>
<cfset errorRecord = {
status = "error",
originalFileName = "Unknown",
errorMessage = cfcatch.message,
errorDetail = cfcatch.detail,
timestamp = now()
}>
<cfset arrayAppend(uploadResults, errorRecord)>
<cfset batchSummary.failed++>
</cfcatch>
</cftry>
</cfif>
<!DOCTYPE html>
<html>
<head>
<title>Invoice Processing System</title>
<style>
body { font-family: 'Arial', sans-serif; background: #f4f4f4; padding: 20px; }
.container { max-width: 900px; margin: 0 auto; background: white;
border-radius: 10px; box-shadow: 0 0 20px rgba(0,0,0,0.1); }
.header { background: #2c3e50; color: white; padding: 25px; border-radius: 10px 10px 0 0; }
.header h1 { margin: 0; font-size: 28px; }
.header p { margin: 5px 0 0 0; opacity: 0.8; }
.content { padding: 30px; }
.summary-cards { display: grid; grid-template-columns: repeat(3, 1fr);
gap: 15px; margin-bottom: 30px; }
.card { background: #ecf0f1; padding: 20px; border-radius: 8px; text-align: center; }
.card.success { background: #d5f4e6; border-left: 4px solid #27ae60; }
.card.error { background: #fadbd8; border-left: 4px solid #e74c3c; }
.card.info { background: #d6eaf8; border-left: 4px solid #3498db; }
.card h3 { margin: 0 0 10px 0; font-size: 32px; color: #2c3e50; }
.card p { margin: 0; color: #7f8c8d; font-size: 14px; }
.upload-form { background: #f8f9fa; padding: 25px; border-radius: 8px;
border: 2px solid #dee2e6; margin-bottom: 30px; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 8px; font-weight: bold; color: #2c3e50; }
input[type="file"] { padding: 10px; width: 100%; border: 1px solid #ccc;
border-radius: 5px; background: white; }
button { background: #27ae60; color: white; padding: 12px 30px; border: none;
border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold; }
button:hover { background: #229954; }
.audit-trail { margin-top: 30px; }
.audit-trail h2 { color: #2c3e50; margin-bottom: 20px; padding-bottom: 10px;
border-bottom: 2px solid #3498db; }
.audit-record { background: #f8f9fa; padding: 15px; border-radius: 8px;
margin-bottom: 15px; border-left: 4px solid #3498db; }
.audit-record.failed { border-left-color: #e74c3c; background: #fadbd8; }
.audit-detail { display: grid; grid-template-columns: 200px 1fr; gap: 10px;
font-size: 14px; margin-top: 10px; }
.audit-detail strong { color: #2c3e50; }
.status-badge { display: inline-block; padding: 4px 12px; border-radius: 12px;
font-size: 12px; font-weight: bold; text-transform: uppercase; }
.status-badge.success { background: #27ae60; color: white; }
.status-badge.failed { background: #e74c3c; color: white; }
.requirements { background: #fff3cd; padding: 15px; border-radius: 5px;
border-left: 4px solid #ffc107; margin-bottom: 20px; }
.requirements ul { margin: 10px 0; padding-left: 20px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🧾 Invoice Processing System</h1>
<p>Vendor Invoice Upload & Audit Trail Management</p>
</div>
<div class="content">
<!--- Display batch summary if uploads were processed --->
<cfif batchSummary.totalAttempted GT 0>
<div class="summary-cards">
<div class="card info">
<h3>#batchSummary.totalAttempted#</h3>
<p>Total Attempted</p>
</div>
<div class="card success">
<h3>#batchSummary.successful#</h3>
<p>Successfully Processed</p>
</div>
<div class="card error">
<h3>#batchSummary.failed#</h3>
<p>Failed Uploads</p>
</div>
</div>
<cfif batchSummary.successful GT 0>
<div style="background: #d5f4e6; padding: 15px; border-radius: 5px; margin-bottom: 20px;">
<strong>✓ Batch Processing Complete</strong><br>
Total data uploaded: #numberFormat(batchSummary.totalSize / 1024, "0.00")# KB<br>
Processing time: #dateTimeFormat(now(), "HH:nn:ss")#
</div>
</cfif>
</cfif>
<div class="requirements">
<strong>📋 Invoice Upload Requirements:</strong>
<ul>
<li>File Format: PDF only (for OCR processing compatibility)</li>
<li>Strict validation enforced for security compliance</li>
<li>Automatic unique naming to prevent duplicates</li>
<li>Complete audit trail maintained for all uploads</li>
</ul>
</div>
<div class="upload-form">
<h2 style="margin-top: 0; color: #2c3e50;">📤 Upload New Invoice</h2>
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="invoiceFile">Select PDF Invoice:</label>
<input type="file" name="invoiceFile" id="invoiceFile"
accept="application/pdf,.pdf" required>
</div>
<button type="submit">Process Invoice Upload</button>
</form>
</div>
<!--- Display audit trail --->
<cfif arrayLen(uploadResults) GT 0>
<div class="audit-trail">
<h2>📊 Upload Audit Trail</h2>
<cfloop array="#uploadResults#" index="record">
<div class="audit-record <cfif record.status NEQ 'success'>failed</cfif>">
<div>
<span class="status-badge #record.status#">#record.status#</span>
<cfif record.status EQ "success">
<strong style="margin-left: 10px; color: #2c3e50;">
Invoice ID: #record.invoiceId#
</strong>
</cfif>
</div>
<div class="audit-detail">
<cfif record.status EQ "success">
<strong>Original Filename:</strong>
<span>#record.originalFileName#</span>
<strong>Stored As:</strong>
<span>#record.savedFileName#</span>
<strong>File Size:</strong>
<span>#numberFormat(record.fileSize / 1024, "0.00")# KB</span>
<strong>Upload Timestamp:</strong>
<span>#dateTimeFormat(record.uploadTimestamp, "yyyy-mm-dd HH:nn:ss")#</span>
<strong>File Hash (MD5):</strong>
<span style="font-family: monospace; font-size: 11px;">#record.fileHash#</span>
<strong>Uploaded By:</strong>
<span>#record.uploadedBy#</span>
<strong>Filename Modified:</strong>
<span>#yesNoFormat(record.wasRenamed)#</span>
<cfelse>
<strong>Error:</strong>
<span style="color: #e74c3c;">#record.errorMessage#</span>
<strong>Timestamp:</strong>
<span>#dateTimeFormat(record.timestamp, "yyyy-mm-dd HH:nn:ss")#</span>
<cfif structKeyExists(record, "errorDetail")>
<strong>Details:</strong>
<span style="font-size: 12px;">#record.errorDetail#</span>
</cfif>
</cfif>
</div>
</div>
</cfloop>
</div>
</cfif>
<div style="margin-top: 30px; padding: 15px; background: #ecf0f1; border-radius: 5px; font-size: 12px; color: #7f8c8d;">
<strong>Note:</strong> All invoice uploads are logged for compliance and audit purposes.
The continueOnError setting ensures batch processing continues even if individual files fail validation.
</div>
</div>
</div>
</body>
</html><cfset ticketId = "TKT-#dateFormat(now(), 'yyyymmdd')#-#randRange(100, 999)#">
<cfset maxAttachmentSize = 10485760><!--- 10MB --->
<cfset uploadReport = {
ticketId = ticketId,
attachments = [],
errors = []
}>
<cfif structKeyExists(form, "attachment")>
<cftry>
<!--- Upload attachment --->
<cffile
action="upload"
fileField="attachment"
destination="#expandPath('./uploads/tickets/#ticketId#/')#"
nameConflict="makeUnique"
accept="image/jpeg,image/png,image/gif,application/pdf,text/plain,application/zip,application/x-zip-compressed"
allowedExtensions=".jpg,.jpeg,.png,.gif,.pdf,.txt,.log,.zip"
result="fileResult"
mode="644">
<!--- Validate file size after upload --->
<cfif fileResult.fileSize GT maxAttachmentSize>
<!--- Delete the uploaded file if too large --->
<cfif fileExists("#fileResult.serverDirectory#/#fileResult.serverFile#")>
<cffile action="delete" file="#fileResult.serverDirectory#/#fileResult.serverFile#">
</cfif>
<cfset arrayAppend(uploadReport.errors, {
type = "size",
message = "File exceeds 10MB limit",
size = numberFormat(fileResult.fileSize / 1048576, "0.00") & " MB"
})>
<cfelse>
<!--- Build attachment record --->
<cfset attachmentInfo = {
fileName = fileResult.serverFile,
originalName = fileResult.clientFile,
fileSize = fileResult.fileSize,
mimeType = fileResult.contentType,
extension = fileResult.serverFileExt,
uploadedAt = now(),
wasRenamed = fileResult.fileWasRenamed,
status = "uploaded"
}>
<!--- Determine file category --->
<cfswitch expression="#fileResult.contentSubType#">
<cfcase value="jpeg,png,gif">
<cfset attachmentInfo.category = "Screenshot">
<cfset attachmentInfo.icon = "🖼️">
</cfcase>
<cfcase value="pdf">
<cfset attachmentInfo.category = "Document">
<cfset attachmentInfo.icon = "📄">
</cfcase>
<cfcase value="plain">
<cfset attachmentInfo.category = "Log File">
<cfset attachmentInfo.icon = "📝">
</cfcase>
<cfcase value="zip,x-zip-compressed">
<cfset attachmentInfo.category = "Archive">
<cfset attachmentInfo.icon = "📦">
</cfcase>
<cfdefaultcase>
<cfset attachmentInfo.category = "Other">
<cfset attachmentInfo.icon = "📎">
</cfdefaultcase>
</cfswitch>
<cfset arrayAppend(uploadReport.attachments, attachmentInfo)>
</cfif>
<cfcatch type="any">
<cfset arrayAppend(uploadReport.errors, {
type = "upload",
message = cfcatch.message,
detail = cfcatch.detail
})>
</cfcatch>
</cftry>
</cfif>
<!DOCTYPE html>
<html>
<head>
<title>Support Ticket Attachments</title>
<style>
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: #f0f2f5; margin: 0; padding: 20px; }
.container { max-width: 800px; margin: 0 auto; }
.ticket-header { background: white; padding: 25px; border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin-bottom: 20px; }
.ticket-id { font-size: 24px; color: #1c1e21; margin: 0 0 5px 0; }
.ticket-meta { color: #65676b; font-size: 14px; }
.upload-section { background: white; padding: 25px; border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin-bottom: 20px; }
.upload-zone { border: 2px dashed #dadde1; border-radius: 8px; padding: 40px;
text-align: center; background: #f7f8fa; margin-bottom: 20px; }
.upload-zone:hover { border-color: #1877f2; background: #e7f3ff; }
input[type="file"] { display: none; }
.file-label { background: #1877f2; color: white; padding: 12px 24px;
border-radius: 6px; cursor: pointer; display: inline-block;
font-weight: 600; transition: all 0.2s; }
.file-label:hover { background: #166fe5; }
button { background: #42b72a; color: white; padding: 12px 24px; border: none;
border-radius: 6px; font-size: 15px; font-weight: 600; cursor: pointer;
width: 100%; transition: all 0.2s; }
button:hover { background: #36a420; }
.attachments-list { background: white; padding: 25px; border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.attachment-item { display: flex; align-items: center; padding: 15px;
background: #f7f8fa; border-radius: 8px; margin-bottom: 10px;
border-left: 4px solid #1877f2; }
.attachment-icon { font-size: 32px; margin-right: 15px; }
.attachment-info { flex: 1; }
.attachment-name { font-weight: 600; color: #1c1e21; margin-bottom: 5px; }
.attachment-meta { font-size: 13px; color: #65676b; }
.badge { display: inline-block; padding: 3px 8px; border-radius: 4px;
font-size: 11px; font-weight: 600; margin-left: 8px; }
.badge-category { background: #e4e6eb; color: #050505; }
.badge-renamed { background: #fff3cd; color: #856404; }
.alert { padding: 15px; border-radius: 8px; margin-bottom: 15px; }
.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.supported-formats { background: #e7f3ff; padding: 15px; border-radius: 8px;
border-left: 4px solid #1877f2; margin-bottom: 20px; }
.supported-formats h4 { margin: 0 0 10px 0; color: #1877f2; }
.format-grid { display: grid; grid-template-columns: repeat(2, 1fr);
gap: 8px; font-size: 14px; }
.format-item { padding: 8px; background: white; border-radius: 4px; }
</style>
</head>
<body>
<div class="container">
<div class="ticket-header">
<h1 class="ticket-id">🎫 Support Ticket: #ticketId#</h1>
<div class="ticket-meta">
Created: #dateTimeFormat(now(), "mmmm d, yyyy 'at' h:nn tt")# |
Status: <strong>Open</strong>
</div>
</div>
<!--- Display upload results --->
<cfif arrayLen(uploadReport.attachments) GT 0>
<div class="alert alert-success">
<strong>✓ Attachment Uploaded Successfully</strong><br>
Your file has been attached to this support ticket and our team will review it.
</div>
</cfif>
<cfif arrayLen(uploadReport.errors) GT 0>
<div class="alert alert-error">
<strong>✗ Upload Error</strong><br>
<cfloop array="#uploadReport.errors#" index="error">
#error.message#
<cfif structKeyExists(error, "size")>
(File size: #error.size#)
</cfif>
<cfif structKeyExists(error, "detail")>
<br><small>#error.detail#</small>
</cfif>
</cfloop>
</div>
</cfif>
<div class="upload-section">
<h2 style="margin-top: 0; color: #1c1e21;">📎 Add Attachment</h2>
<div class="supported-formats">
<h4>Supported File Types:</h4>
<div class="format-grid">
<div class="format-item">🖼️ Images: JPG, PNG, GIF</div>
<div class="format-item">📄 Documents: PDF</div>
<div class="format-item">📝 Logs: TXT, LOG</div>
<div class="format-item">📦 Archives: ZIP</div>
</div>
<p style="margin: 10px 0 0 0; font-size: 13px; color: #65676b;">
Maximum file size: 10 MB
</p>
</div>
<form method="post" enctype="multipart/form-data">
<div class="upload-zone">
<p style="font-size: 18px; color: #65676b; margin-bottom: 15px;">
Drop a file or click to browse
</p>
<label for="attachment" class="file-label">Choose File</label>
<input type="file" name="attachment" id="attachment"
accept=".jpg,.jpeg,.png,.gif,.pdf,.txt,.log,.zip" required>
</div>
<button type="submit">📤 Upload Attachment</button>
</form>
</div>
<!--- Display attachments list --->
<cfif arrayLen(uploadReport.attachments) GT 0>
<div class="attachments-list">
<h2 style="margin-top: 0; color: #1c1e21;">Attached Files</h2>
<cfloop array="#uploadReport.attachments#" index="attachment">
<div class="attachment-item">
<div class="attachment-icon">#attachment.icon#</div>
<div class="attachment-info">
<div class="attachment-name">
#attachment.originalName#
<span class="badge badge-category">#attachment.category#</span>
<cfif attachment.wasRenamed>
<span class="badge badge-renamed">RENAMED</span>
</cfif>
</div>
<div class="attachment-meta">
<strong>Saved as:</strong> #attachment.fileName# |
<strong>Size:</strong> #numberFormat(attachment.fileSize / 1024, "0.00")# KB |
<strong>Type:</strong> #attachment.mimeType# |
<strong>Uploaded:</strong> #timeFormat(attachment.uploadedAt, "h:nn tt")#
</div>
</div>
</div>
</cfloop>
</div>
</cfif>
<div style="margin-top: 20px; padding: 15px; background: white; border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1); font-size: 13px; color: #65676b;">
<strong>📝 Note:</strong> All attachments are automatically organized by ticket ID
(#ticketId#) and stored securely. Files are scanned for security before being made
available to support staff.
</div>
</div>
</body>
</html>