There are a few ways to deal with large file uploads in PHP. The easiest way is to increase the maximum upload size limit in the PHP configuration file (php.ini) on the server. If you don’t want to modify the server setting in PHP, the Chunk Upload method is one of the best alternatives for large file upload with PHP. In chunk upload, the large file is split into small parts and uploaded in chunks. You can upload large files above 500MB or GB to the server using PHP. This tutorial will show you how to handle large file upload with the chunking feature in PHP.
Normally, the entire file is posted to the server-side for upload. But, if the file is huge (about several gigabytes) in size, the standard upload may fail due to settings in the server’s constraints on uploaded file size. To overcome this issue, we can integrate the chunk upload functionality. The chunk file upload method slices the file into chunks and sends them one by one to the server in PHP.
We will use the Plupload library to split file into chunks on the client-side and post them to the server-side using JavaScript. Plupload is a JavaScript library that handles the chunk upload process on the client-side.
Define HTML elements to select the file, upload button, and file queue.
<!-- File browse input field -->
<div class="form-group">
<label><b>Select File:</b></label>
<input type="file" class="form-control" id="fileInput">
</div>
<!-- List the selected files -->
<div id="fileList"></div>
<!-- Upload button -->
<div class="form-group">
<a id="uploadBtn" href="javascript:;" class="btn btn-success">Upload</a>
</div>
Additionally, we have added a progress bar that indicates the upload progress in a percentage format.
<!-- Progress bar -->
<div class="progress"></div>
First, include the Plupload JS library.
<script src="plupload/js/plupload.full.min.js"></script>
Define Plupload uploader with configuration options using JavaScript.
browse_button
: Element ID of the file browse button.url
: The URL of the server-side script that handles the file upload process.multi_selection
: Set true if you want to allow select multiple files at once.max_file_size
: Maximum file size that is allowed to upload.mime_types
: Type of the files that are allowed to upload.Initialize Plupload uploader with init()
method.
<script>
// Define Plupload uploader with configuration options
var uploader = new plupload.Uploader({
runtimes : 'html5,flash,silverlight,html4',
browse_button : 'fileInput', // you can pass an id...
url : 'upload.php',
flash_swf_url : 'plupload/js/Moxie.swf',
silverlight_xap_url : 'plupload/js/Moxie.xap',
multi_selection: false,
filters : {
max_file_size : '500mb',
mime_types: [
{title : "Image files", extensions : "jpg,jpeg,gif,png"},
{title : "Video files", extensions : "mp4,avi,mpeg,mpg,mov,wmv"},
{title : "Zip files", extensions : "zip"},
{title : "Document files", extensions : "pdf,docx,xlsx"}
]
},
init: {
PostInit: function() {
document.getElementById('fileList').innerHTML = '';
document.getElementById('uploadBtn').onclick = function() {
if (uploader.files.length < 1) {
document.getElementById('statusResponse').innerHTML = '<p style="color:#EA4335;">Please select a file to upload.</p>';
return false;
}else{
uploader.start();
return false;
}
};
},
FilesAdded: function(up, files) {
plupload.each(files, function(file) {
document.getElementById('fileList').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ') <b></b></div>';
});
},
UploadProgress: function(up, file) {
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
document.querySelector(".progress").innerHTML = '<div class="progress-bar" style="width: '+file.percent+'%;">'+file.percent+'%</div>';
},
FileUploaded: function(up, file, result) {
var responseData = result.response.replace('"{', '{').replace('}"', '}');
var objResponse = JSON.parse(responseData);
document.getElementById('statusResponse').innerHTML = '<p style="color:#198754;">' + objResponse.result.message + '</p>';
},
Error: function(up, err) {
document.getElementById('statusResponse').innerHTML = '<p style="color:#EA4335;">Error #' + err.code + ': ' + err.message + '</p>';
}
}
});
// Initialize Plupload uploader
uploader.init();
</script>
This script handles the file uploaded process with chunk functionality.
In the $targetDir
variable, specify the folder name where the uploaded files will be stored.
<?php
// Make sure file is not cached (as it happens for example on iOS devices)
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
// Settings
$targetDir = 'uploads';
$cleanupTargetDir = true; // Remove old files
$maxFileAge = 5 * 3600; // Temp file age in seconds
// Create target dir
if (!file_exists($targetDir)) {
@mkdir($targetDir);
}
// Get a file name
if (isset($_REQUEST["name"])) {
$fileName = $_REQUEST["name"];
} elseif (!empty($_FILES)) {
$fileName = $_FILES["file"]["name"];
} else {
$fileName = uniqid("file_");
}
$filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
// Chunking might be enabled
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;
// Remove old temp files
if ($cleanupTargetDir) {
if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
}
while (($file = readdir($dir)) !== false) {
$tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
// If temp file is current file proceed to the next
if ($tmpfilePath == "{$filePath}.part") {
continue;
}
// Remove temp file if it is older than the max age and is not the current file
if (preg_match('/\.part$/', $file) && (filemtime($tmpfilePath) < time() - $maxFileAge)) {
@unlink($tmpfilePath);
}
}
closedir($dir);
}
// Open temp file
if (!$out = @fopen("{$filePath}.part", $chunks ? "ab" : "wb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
}
if (!empty($_FILES)) {
if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
}
// Read binary input stream and append it to temp file
if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
}
} else {
if (!$in = @fopen("php://input", "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
}
}
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}
@fclose($out);
@fclose($in);
// Check if file has been uploaded
if (!$chunks || $chunk == $chunks - 1) {
// Strip the temp .part suffix off
rename("{$filePath}.part", $filePath);
}
// Return Success JSON-RPC response
die('{"jsonrpc" : "2.0", "result" : {"status": 200, "message": "The file has been uploaded successfully!"}}');
File Upload with Progress Bar using jQuery Ajax and PHP
In most cases, your server does not allow access to the PHP configuration file (php.ini) which lead difficult to allow large files to be uploaded. The chunk file upload can make it possible to upload a large file to the server without any changes in PHP configurations (php.ini). This example script allows you to implement chunk upload functionality to upload large files using PHP. You can allow the user to upload large files to the server in chunks without page refresh using JavaScript and PHP.
Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request
your blog is really helpful. But I need to upload any large file with a chunk on third-party storage like “S3”.
How it is possible with the above code?
Really nice, thanks a lot !!!