I need help with creating a progress bar for my php upload site. I've got the upload and exctract part sorted but i need help with the progress bar. I'm not sure how to do it. Also, is there a maximum file size for the upload?
HTML
<?php if($message) echo "<p>$message</p>"; ?>
<form enctype="multipart/form-data" method="post" action="">
<label>Choose file (.zip): <input type="file" name="zip_file" /></label>
<br />
<input type="submit" value="Upload" name="submit" value="Upload" />
</form>
PHP
<?php
if($_FILES["zip_file"]["name"]) {
$filename = $_FILES["zip_file"]["name"];
$source = $_FILES["zip_file"]["tmp_name"];
$type = $_FILES["zip_file"]["type"];
$name = explode(".", $filename);
$accepted_types = array(
'application/zip',
'application/x-zip-compressed',
'multipart/x-zip',
'application/x-compressed');
foreach($accepted_types as $mime_type) {
if($mime_type == $type) {
$okay = true;
break;
}
}
$continue = strtolower($name[1]) == 'zip' ? true : false;
if(!$continue) {
$message = "[...] not a .zip file. Please try again.";
}
$target_path = "./".$filename;
if(move_uploaded_file($source, $target_path)) {
$zip = new ZipArchive();
$x = $zip->open($target_path);
if ($x === true) {
$zip->extractTo("./");
$zip->close();
unlink($target_path);
}
$message = "Your .zip file was uploaded and unpacked.";
} else {
$message = "There was a problem with the upload. Please try again.";
}
}
?>
You can make some changes to fit but this works rather well if you want a progress bar. You can add more eventlisteners and make it how you want. I hope this is a good starting point for you.
function uploadFile(){
var file = document.getElementById("zip_file").files[0];
var formdata = new FormData();
formdata.append("zip_file", file);
var ajax = new XMLHttpRequest();
ajax.upload.addEventListener("progress", function(event) { runprogress(event); } , false);
ajax.addEventListener("load", function(event) {uploadcomplete(event); }, false);
//Target your php file.
ajax.open("POST", "upload.php");
ajax.send(formdata);
}
function runprogress(event){
//The progress %, you might want to Math.round(percent)
var percent = (event.loaded / event.total) * 100;
}
function uploadcomplete(event){
//This will = to your php reply.
var AjaxReply=event.target.responseText;
}
As far as I know you would have to use JavaScript to do this. Post your data through an AJAX call and initialize the progress bar. Over time animating it so that the bar "fills up".
Eventually the AJAX call will complete and will send a response back, upon the completion of the call you can finish the animation. This is how I would assume most progress bars work as they typically go up then stop around 99% until the post returns it's "complete status".
In any case, you would have a progress bar, represented by a <div> for example, with a width that would increase as time goes on, or a number would go up etc... and you would animate this using JavaScript and/or jQuery. Hopefully this will get you started in the right direction.
EDIT
Here's a link to a tutorial describing the steps necessary to upload files to the server using AJAX: Uploading Files with AJAX
Related
I am wondering if anyone would be kind enough to assist. This ajax upload works, but it only shows one progress bar and each file loads individually. It shows the progress for the first file and when the first file is uploaded the progress bar resets to zero and then it shows the progress for the next file, and so on until all the files are uploaded.I am unable to get multiple percentage bars working to show the progress for each file as it uploads simultaneously.I would ideally like another progress bar which shows the overall progress of the whole upload but this is not essential.Any assistance you can offer will be greatly appreciated.
HTML
<h2>HTML5 File Upload Progress Bar Tutorial</h2>
<form id="upload_form" enctype="multipart/form-data" method="post">
<input type="file" name="file1" id="file1" multiple>
<input type='submit' name='submit' id="file2" value='Upload' onclick='uploadFile();'/>
<br>
<progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
<h3 id="status"></h3>
<p id="loaded_n_total"></p>
</form>
<script>
function _(el) {
return document.getElementById(el);
}
function uploadFile() {
// assuming there is a file input with the ID `my-input`...
var files = document.getElementById("file1").files;
for (var i = 0; i < files.length; i++)
{
//alert(files[i].name);
//alert(files[i].type);
alert(files[i].name+" | "+files[i].size+" | "+files[i].type);
var formdata = new FormData();
formdata.append("file1", files[i]);
var ajax = new XMLHttpRequest();
ajax.upload.addEventListener("progress", progressHandler, false);
ajax.addEventListener("load", completeHandler, false);
ajax.addEventListener("error", errorHandler, false);
ajax.addEventListener("abort", abortHandler, false);
ajax.open("POST", "file_upload_parser.php");
//use file_upload_parser.php from above url
ajax.send(formdata);
}
}
function progressHandler(event) {
_("loaded_n_total").innerHTML = "Uploaded " + event.loaded + " bytes of " + event.total;
var percent = (event.loaded / event.total) * 100;
_("progressBar").value = Math.round(percent);
_("status").innerHTML = Math.round(percent) + "% uploaded... please wait";
}
function completeHandler(event) {
_("status").innerHTML = event.target.responseText;
_("progressBar").value = 0; //wil clear progress bar after successful upload
}
function errorHandler(event) {
_("status").innerHTML = "Upload Failed";
}
function abortHandler(event) {
_("status").innerHTML = "Upload Aborted";
}
</script>
</body>
</html>
PHP
<?php
/* Get the name of the uploaded file */
$filename = $_FILES['file1']['name'];
/* Choose where to save the uploaded file */
$location = "upload/".$filename;
/* Save the uploaded file to the local filesystem */
if ( move_uploaded_file($_FILES['file1']['tmp_name'], $location) ) {
echo 'Success';
} else {
echo 'Failure';
}
?>
In the progressHandler function you can create new progress bars.
For example:
$('{DIV}').append('<progress id="progressBar-{ID}" value="0" max="100" style="width:300px;"></progress>')
with:
{DIV}: can be a container or anything else
{ID}: is the i element of files.lenght
then you should compare the "event parameter" if it is already created
Try with that
Edit 2 : I notices user can upload unlimited files and can take all disk space, how to prevent that?
Edit: since no one answered this question, is there a source I could read to get my answer???
I have a contact form. There are three inputs. I used a jQuery plugin for uploading files. This plugin adds another form element and uploads files by ajax.
I'm kind of beginner but this code is for a customer and a real job so I want to make sure it's safe!
in my view:
<form action="" method="post" enctype="multipart/form-data" >
<input type="text" name="name" />
<input type="number" name="phone" />
<textarea name="enquiry" rows="10" ></textarea>
<div id="upload-div">
<div id="extraupload">Upload</div>
<input type="hidden" name="count" value="0" id="count"/>
<input type="submit" />
$(document).ready(function()
{
var uploadObj = $("#extraupload").uploadFile({
url:"/uplod_url",
fileName:"file",
onSuccess:function(files,data,xhr,pd)
{
data = jQuery.parseJSON(data);
if(data.status == 'success') {
var count = $('#count').val() * 1 + 1;
for(var i=0; i<data.files.length; i++) {
$('<input type="hidden" name="file_'+count+'" value="'+data.files[i]+'">').insertBefore('#extraupload');
$('#count').val(count);
count++;
}
}
},
});
});
</script>
each successful upload,will add one to input count value
and will append an hidden input with the value of uploaded file name.
In php I check for file type and change file name:
upload_url.php:
if ($_FILES['file']['type']=='image/jpeg' || $_FILES['file']['type']=='image/pjpeg') {
$ext = '.jpg';
}
elseif ($_FILES['file']['type']=='image/png') {
$ext = '.png';
}
elseif ($_FILES['file']['type']=='application/pdf') {
$ext = '.pdf';
}
else {
echo json_encode('Only images and pdf files are allowed!');
die();
}
$fileName = md5(uniqid());
$fileName = $fileName.$ext;
move_uploaded_file($_FILES["file"]["tmp_name"], 'image/tmp'.$fileName);
$result = array('status'=> 'success','files' => $fileName);
echo json_encode($result);
After changing the file's name to a unique hash, I save that in a tmp folder.
then when the main form is submitted this is what happens:
//validation method: if that file exists in tmp folder
if(isset($this->request->post['count']) && is_numeric($this->request->post['count'])) {
for($i=1; $i<=$this->request->post['count']; $i++ ) {
if(isset($this->request->post['file_'.$i])){
if(!file_exists('image/tmp/'.$this->request->post['file_'.$i])){
//throw error
}
} else{
//throw error
}
}
}
// hidden input count can only be integer
if(isset($this->request->post['count']) && !is_numeric($this->request->post['count'])) {
//throw error
}
and then mailing the file and saving file name in database(I did not include database part because I'm kind of sure it's ok)
//by every submition delete files in tmp folder older than 1 day
$oldFiles = glob($tmp_dir."*");
$now = time();
foreach ($oldFiles as $oldFile) {
if (is_file($oldFile)) {
if ($now - filemtime($oldFile) >= 60 * 60 * 24) {
unlink($oldFile);
}
}
}
$mail = new Mail();
//Mail Setting and details deleted
//if there's any file uploaded
if($this->request->post['count'] != 0) {
//unique directory for every form submition
$dir_path = 'image/submitted/'.uniqid();
mkdir($dir_path, 0764, true);
//for all hidden inputs move file from tmp folder to $dir_path
for ($i=1; $i <= $this->request->post['count']; $i++) {
$file = $this->request->post['file_'.$i];
rename('image/tmp'.$file, $dir_path.'/'.$file);
$mail->AddAttachment($dir_path.'/'.$file);
}
}
$mail->send();
now my question is: Is it safe this way? especially when I append hidden inputs with file's name and get the number of uploaded files from hidden input count??
This code already works, but I think this might be a security issue.
Thanks a lot for your patience and sorry for my poor english!
ps: I use opencart
There is the general misconception that in AJAX applications are more secure because it is thought that a user cannot access the server-side script without the rendered user interface (the AJAX based webpage). XML HTTP Request based web applications obscure server-side scripts, and this obscurity gives website developers and owners a false sense of security – obscurity is not security. Since XML HTTP requests function by using the same protocol as all else on the web (HTTP), technically speaking, AJAX-based web applications are vulnerable to the same hacking methodologies as ‘normal’ applications.
I made a little page where you can upload picture it is simple php upload. I want everyone to be able to upload images and view everyone else's uploads on the site. How can I display images after they're uploaded? I want to be able to globally track all uploaded images so that everyone can browse them.
I think I need to use "AJAX upload" to do that and maybe javascript to display image after upload... but how?
I tried this:
function GetFileName(){
var fileInput = document.getElementById('fileToUpload');
var fileName = fileInput.value.split(/(\\|\/)/g).pop();
var img = document.createElement('img');
img.src = 'uploads/' + fileName;
img.setAttribute('width', '100px');
img.setAttribute('height', '100px');
img.alt = fileName;
document.body.appendChild(img);
alert(fileName);
}
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="fileToUpload" id="fileToUpload" class="upload">
<input type="submit" onclick="GetFileName()" value="Upload Image" name="submit" id="submit">
</form>
This is almost work but the image only display few second and then it disappear.
Try some thing like this in Jquery:
$('#upload').on('click', function() {
var img_name = $('#pic').val();
var file_data = $('#pic').prop('files')[0];
var form_data = new FormData();
form_data.append('file', file_data);
$.ajax({
url : 'upload.php', // point to server-side PHP script
dataType : 'text', // what to expect back from the PHP script, if anything
cache : false,
contentType : false,
processData : false,
data : form_data,
type : 'post',
success : function(output){
if(output) // if success
{
$('#img_container').append('<img src="img_path/"'+ img_name +'>'); // It will display the uploaded image
}
}
});
$('#pic').val(''); /* Clear the file container */
});
Html:
<body>
<input id="pic" type="file" name="pic" />
<button id="upload">Upload</button>
<!-- To display image -->
<div id="img_container">
</div>
</body>
I think the key issue to your question here is in how to keep track of all the uploads. This is likely better solved by relying on a persistence store, like a database, to track of all uploaded files on a global level.
For example, when an upload occurs, you can insert a record into an uploads table in your database like so...
// prepare the statement
$stmt = $db->prepare("INSERT INTO uploads (userId, fileName) VALUES(:userId, :fileName)");
if ($_FILES['upload']['error'] == UPLOAD_ERR_OK) { // no errors
// move the file to a permanent location
$tmpName = $_FILES['upload']['tmp_name'];
move_uploaded_file($tmpName, $uploadDir . "/$tmp_name");
$result = $stmt->execute(
[
'userId' => $_SESSION['userId'], // or however you track the user
'fileName' => $_FILES['upload']['tmp_name'],
]
);
if ($result) {
// record added successfully!
} else {
// failed
}
}
Now you can display all uploaded files by looking at the uploads table in your database and display them to users like so...
// prepare the statement
$start = $_GET['start'] ?? 0;
$stmt = $db->prepare("SELECT userId, fileName FROM uploads LIMIT ?,20");
if ($stmt->execute([$start])) {
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($result as $row) {
echo "<img src='$uploadDir/{$row['fileName']}'>";
}
}
Or you could show only those uploads made by a specific user by adding a WHERE userId = ? clause to that query, for example.
I am using the Jquery Form plugging to try and upload a picture to my mysql DBMS. I use the JqueryForm ajaxForm() call to do this. It calls a php file on my server and that script puts the file into the database. I then attempt to get that file out of the database in the same script. I guess the nuts and bolts of how I do it is irrelevant. I really want to know how I would get a picture back from an ajax call using the AjaxForm call from the jqueryForm pluggin. Does anybody have an example of how to do this using that pluggin? I am a little lost...
<script type="text/javascript" src="jquery.form.js"></script>
<script>
$(document).ready(function () {
$('#profilepicbutton').live('change', function () {
$("#preview").html('');
$("#preview").html('<img src="loader.gif" alt="Uploading...."/>');
$("#registerpt3").ajaxForm({
target: '#preview',
success: function (data) {
$("#preview").html('');
$("#preview").append("<img src=" + data + "></img>");
}
}).submit();
});
});
</script>
Now, On the jquery form pluggin site, there is a page in particular that has instructions for file uploads...
http://jquery.malsup.com/form/#file-upload
The example that they give is a little blank...
<textarea>
for (var i=0; i < 10; i++) {
// do some processing
}
</textarea>
Now, what am I supposed to do with that? Why am I looping through some data structure? If you look on there page, you will see they are remarkable brief in their instructions of what to do. Anybody have any tutorials or advice? Thanks.
UPDATE PHP Code
if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST")
{
$name = $_FILES['profilepicinput']['name'];
$size = $_FILES['profilepicinput']['size'];
if(strlen($name))
{
list($txt, $ext) = explode(".", $name);
if(in_array($ext,$valid_formats))
{
if($size<(1024*1024)) // Image size max 1 MB
{
$actual_image_name = time().$session_id.".".$ext;
$tmp = $_FILES['profilepicinput']['tmp_name'];
$fp = fopen($tmp, 'r');
$data = fread($fp, filesize($tmp));
$data = addslashes($data);
fclose($fp);
values('$email', '$tmp')");
if(mysql_query("insert into Personal_Photos (Email, Pics) values('$email', '$data')"))
{
$query="select Pics, MAX(ID) from Personal_Photos where Email='$email'";
$result=mysql_query($query) or die("Error: ".mysql_error());
$row=mysql_fetch_array($result);
$mime = 'image/yourtype';
$base64 = base64_encode($contents);
$uri = "data:$mime;base64,$base64";
header("Content-type: image/jpg");
print($row['Pics']);
}
else
{
die('Invalid query: ' . mysql_error());
echo "failed";
}
}
else
echo "Image file size max 1 MB. Image Size:"+$size;
}
else
echo "Invalid file format..";
}
else
echo "Please select image..! Bull shit".$email;
exit;
}
If I understand your question right, you can create a so called data URI.
In PHP it's quite simple:
$mime = 'image/yourtype';
$base64 = base64_encode($contents);
$uri = "data:$mime;base64,$base64";
And pass this as string in the ajax reponse to be directly entered as you outlined in your question.
Hopefully this helps, I'm not fluent with jqueryform.
I need to take a CSV file from the client's machine and extract the data from it. I cannot save this CSV file, which is crucial (otherwise I would be laughing!). My PHP so far works like a charm:
upload.php
<?php
$file = $_FILES['file'];
if ($file['error'] === UPLOAD_ERR_OK) {
$ext = substr($file["name"], strrpos($file["name"], '.') + 1);
$maxSize = 3000000;
//Check file extension, MIME-type and size limit (3 MB).
if ($ext == "csv") {
if ($file["type"] == "text/csv" ||
$file["type"] == "text/comma-separated-values") {
if ($file["size"] < $maxSize) {
//CSV -> JSON
$fileAsArray = Array();
if (($handle = fopen($file["tmp_name"], "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$fileAsArray[] = $data;
}
fclose($handle);
}
echo json_encode($fileAsArray);
die(json_encode($fileAsArray));
}
else {
echo "File size: ".$file["size"]."bytes<br>Limit: ".$maxSize." (3MB)";
}
}
else {
echo "MIME-type: ".$file["type"]."<br>Required: text/csv";
}
}
else {
echo "File Extension: ".$ext."<br>Required: csv";
}
}
else
die("Cannot upload");
?>
Ignore the echo. It was just so I knew it was actually working. However, I've been using jQuery with this website and can't figure out the code to properly get the form to submit the file and retrieve the JSON data back (fileAsArray) at the same time. Here is my HTML/jquery in index.html:
<script type="text/javascript">
var csvData = {}; //My global variable (two-dimensional JSON array)
$(document).ready(function(){
$("#upload").click(function(){
alert('test');
$.ajax({
type: "POST",
url: "upload.php",
data: "don't know what goes here",
dataType: "json",
success: function (data) {
alert(data); //Tried everything here too. :(
}
});
});
});
and HTML:
<form method="POST" action="upload.php" enctype="multipart/form-data" class="file_upload">
<input id="getFile" type="file" name="file">
<input value="Extract Data" id="upload" type="button">
</form>
I tried type="submit" as well, and a bunch of other things including just a 'form' tag and letting jQuery handle the POST... Thanks. If there is a better way to do this, please let me know :)
(I've been struggling with this for several days now... Having gone through many renditions of the code outlined below, I've stripped it down to its basics.)
If you want to upload CSV data through an Ajax post request, you must read the content of the file and insert it into the data: "don't know what goes here" field. Currently, only HTML5 browsers provides FileReader API that enables JavaScript to read the file, for Internet Explorer you must use a Flash-based solution.
I wrote a jQuery plug-in before that works with HTML5 browsers and jQuery. It would work with jQuery 1.4 - I am not sure about jQuery 1.5.