Here is my js, and action
public function postyAction()
{
$this->_helper->viewRenderer->setNoRender(TRUE);
// list of valid extensions, ex. array("jpeg", "xml", "bmp")
$allowedExtensions = array("jpeg","xlsx", "jpg", "gif", "doc", "docx", "xls", "odt", "pdf");
// max file size in bytes
$sizeLimit = 6 * 1024 * 1024;
$f = '../dir/'; //dir to save files
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
$result = $uploader->handleUpload($f);
// to pass data through iframe you will need to encode all html tags
echo htmlspecialchars(json_encode($result), ENT_NOQUOTES);
}
function createUploader(){
var UploadedFileNames = [];
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader-demo1'),
action: '../orders/posty',
sizeLimit: 10000000, //10MB maximo
debug:false,
onComplete: function(id, fileName, responseJson){
var success = responseJson["success"];
if(success == true){
var files = $(".qq-upload-file").toArray();
var UploadedFileNames = [];
for ( var i = 0; i < files.length; i++ ) {
UploadedFileNames.push( files[ i ].innerHTML );
}
$( "#filenem" ).val( UploadedFileNames.join( "#" ) );
}
//$("#filenem").val(fileName);
}
});
}
// in your app create uploader as soon as the DOM is ready
// don't wait for the window to load
window.onload = createUploader;
I wish to get an array of files onComplete(), so that i can insert them into db. my code gets the inner html of the file list but longer file names appear to be dotted hence cant get the real file name. eg . e"myverylongdocume..now.doc" instead of "myverylongdocumentnow.doc" for instance
Related
I'm using a script which resizes images client side before uploading them via Ajax to a PHP file. I am resizing images client side to reduce the power demand on the server. My script works but is taking too long to upload the image and I need help understanding why this is the case. The first part of the file asynchronously resizes the image. The second part encodes the resized image source to dynamically created hidden input and finally, Ajax uploads the dynamically created input value to a PHP file by using a timeout 3-second delay function.
$(document).ready(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
/* Upload Logo Image */
$("#loader-wrapper").hide();
$("#logo_image").change(function(){
$("#ImgText").fadeOut(10, "linear");
$("#loader-wrapper").css('background-image', 'none').fadeIn(200, "linear");
const form = document.querySelector('#user_update_settings');
form.addEventListener('change', async (e) => {
e.preventDefault();
// Get data URI of the selected image
const formData = new FormData(e.currentTarget);
const photoField = formData.get('logo_image');
const dataUri = await dataUriFromFormField(photoField);
// Defines Resized image URL
const imgEl = document.createElement('img');
imgEl.addEventListener('load', () => {
const resizedDataUri = resizeImage(imgEl, 600);
// Deletes Previous Input
var element = document.getElementById('new_logo_image');
if (typeof(element) != 'undefined' && element != null)
{
var elementExists = document.getElementById("new_logo_image");
elementExists.remove();
}
// Creates New Input
var objTo = document.getElementById('LogoInputContainer')
var image_input = document.createElement("input");
image_input.setAttribute("name", "new_logo_image");
image_input.setAttribute("id", "new_logo_image");
image_input.setAttribute("type", "hidden");
image_input.setAttribute("value", resizedDataUri);
objTo.appendChild(image_input);
});
imgEl.src = dataUri;
});
// Resize Script
function dataUriFromFormField (field) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener('load', () => {
resolve(reader.result);
});
reader.readAsDataURL(field);
});
}
function resizeImage(imgEl, wantedWidth) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const aspect = imgEl.width / imgEl.height;
canvas.width = wantedWidth;
canvas.height = wantedWidth / aspect;
ctx.drawImage(imgEl, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL();
}
});
// Image Upload
$("#logo_image").change(function(){
setTimeout(() => {
if(window.File && window.FileReader && window.FileList && window.Blob){
if($(this).val()){
// Checks File Extension
var fileExtension = ['jpeg', 'jpg', 'png', 'gif', 'bmp'];
if ($.inArray($(this).val().split('.').pop().toLowerCase(), fileExtension) == -1) {
alert("Only formats are allowed : "+fileExtension.join(', '));
exit();
}
$.ajax({
url: "/logo_uploader",
type: "POST",
data: new FormData($("#user_update_settings")[0]),
contentType: false,
cache: false,
processData: false,
dataType: 'json',
success:function(response){
if(response.type == 'success'){
$("#loader-wrapper").fadeOut();
$(".logo_image_container").css("background-image", "url("+ response.logo_image +")");
}else{
$("#loader-wrapper").fadeOut();
$("#ImgText").fadein(10, "linear").text("+ response.msg +");
}
}
});
}
} else {
alert("Can't upload! Your browser does not support File API!</div>");
return false;
}
}, 3000);
});
});
Client-side, my logo uploader validates the file type, deletes the previous image [if it exists] decodes the $request->new_logo_image and saves the file in the folder 'logos' and in a SQL database.
// User ID
$user_id = auth()->user()->id;
// Reserved Goods
$user = Users::where('id', $user_id)->first();
// Path
$FilePathDB = FilePathDB::first();
// Path
$file_path = $FilePathDB->public_img_path;
$path = $file_path.$user->logo_image;
// Deletes Previous Logo [If Applicable]
if(file_exists($path)) {
File::delete($path);
}
// Validates Extension
$validatedData = $request->validate([
'logo_image' => 'required|image|mimes:jpg,png,jpeg',
]);
// Generates a Unique New Name
$new_name = 'logos/'.$user_id.trim($user->username).uniqid().'.jpg';
// Uploads request Image if file does not exist
if($request->hasFile('logo_image')) {
$image = $request->new_logo_image; // your base64 encoded
$image = str_replace('data:image/png;base64,', '', $image);
$image = str_replace(' ', '+', $image);
File::put($file_path.$new_name, base64_decode($image));
// Logo Image Variable
$formFields = array(
'logo_image' => $new_name
);
// User ID Update
$users = Users::where('id', $user_id)
->update($formFields);
// If Successful
$response = print json_encode(array(
'type'=> 'success',
'msg' => 'Logo Uploaded Successfully',
'logo_image' => 'storage/'.$new_name,
));
} else {
// If unsuccessful
$response = print json_encode(array(
'type'=> 'failed',
'msg' => 'Ooops, image upload unsuccessful. Please try again!',
));
}
Condensed HTML
<form method="POST" action="/user_update_settings" id="user_update_settings" enctype="multipart/form-data">
<label for="logo_image" class="pointer UploadImgBtn transition">
<input class="DisplayNone" type="file" name="logo_image" id="logo_image" accept="image/*">
<a>Upload Image</a>
</label>
</form>
On average, for a 3MB image, it takes 3 seconds for JS canvas to resize the image and 15-20 seconds to upload the already resized file - now between 40-50KB in size. Knowing the image has been resized, why does it take so long for my code to upload the resized image? Are there any loops I haven't considered running in the background which are consuming the client's resources?
After much thinking, I have just found the solution. When I ran my Ajax script I was submitting the whole form to the server which included both the old and the new image. To reduce the data load, one can either put the hidden input into a new form or else specify the data which is to be sent to the PHP file.
I am working on web page where I want to use drag an drop image upload system with options for remove and sort images before upload.
I would like to ask you about your opinion if this system logic is good.
I do not know if this system will have some troubles in future bcz all systems which I found have different logic.
My logic:
My system is based mainly on JS and images will be UPLOAD to folder AFTER FORM SUBMIT when whole form (other data about user as name, phone, etc) is filled in. Every modification as remove or change order is done by modify object data via JS.
Web sources:
They are based on UPLOAD images immediately AFTER DROP/SELECT IMAGE and upload to server folder via PHP.
DIFFERENCE: My system no need to send data to PHP every time if one of this actions is happened - new image is added, or deleted or order is changed.
I will be very thankful even if you help me find some other problems. Also I hope it can help someone who is building own system.
Here is my code:
JS:
/* DRAG AND DROP IMG UPLOAD */
// preventing page from redirecting
$("html").on("dragover", function(e) {
e.preventDefault();
e.stopPropagation();
});
$("html").on("drop", function(e) { e.preventDefault(); e.stopPropagation(); });
// Drag enter
$('.add-item__upload-area').on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
});
// Drag over
$('.add-item__upload-area').on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
$('.add-item__dropzone').css({border: '2px dashed #111'});
});
$('.add-item__upload-area').on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
$('.add-item__dropzone').css({border: '2px dashed #888'});
});
// Open file browser
$('.add-item__add-photo-btn').click(function() {
$('#input-files').trigger('click'); // execute input type file after click on button
event.preventDefault();
});
// create object to keep img files for modification
var data = {};
// Files added by drop to dropzone area
$('.add-item__upload-area').on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
var totalFiles = e.originalEvent.dataTransfer.files.length;
// fill form by files from input
for (var i = 0; i < totalFiles; i++) {
var file = e.originalEvent.dataTransfer.files[i]; // Get list of the files dropped to area
// fill object for file modifications by img files
data['file_'+i] = file;
// create temp url to img object for creating thumbnail and append img with temp src to thumbnail__wraper div
$('.thumbnail__wrapper').append('<div class="thumbnail" id="file_'+ i +'"><img class="imageThumb" src="' + URL.createObjectURL(file) + '" title="' + file.name + '"/><br/><a class="remove">ZmazaƄ</a></div>');
$('.add-item__add-photo-btn-area').find('p').hide();
}
});
// Files added by selecting in file browser
$('#input-files').on('change', function(){
var totalFiles = $('#input-files')[0].files.length; // get number of uploaded files from input element
// modify ordering of fields inside data object according to order from sortable ui
for (var i = 0; i < totalFiles; i++) {
// By appending [0] to the jQuery object will return the first DOM element. Get <input> element from object.
var file = $('#input-files')[0].files[i]; // Get first file from list of files selected with the <input type="file">
// fill object for file modifications by img files
data['file_'+i] = file;
// create temp url to img object for creating thumbnail and append img with temp src to thumbnail__wraper div
$('.thumbnail__wrapper').append('<div class="thumbnail" id="file_'+ i +'"><img class="imageThumb" src="' + URL.createObjectURL(file) + '" title="' + file.name + '"/><br/><a class="remove">ZmazaƄ</a></div>');
$('.add-item__add-photo-btn-area').find('p').hide();
}
//console.log(data);
//uploadData(formData); // send data via ajax to upload.php
});
// Remove field of data obj after click on remove button
$('.add-item__dropzone').on('click','.remove', function() {
// remove choosen field
delete data[$(this).parent().attr('id')];
$(this).parent('.thumbnail').remove();
//console.log($(this).parent().attr('id'));
//console.log(data);
});
// Make images sortable
$('.thumbnail__wrapper').sortable({
axis: 'x', // axis in which sort is possible
update: function (event, ui) {
// get all ids (item-1, ....) from li elements (setted as sortable) of list in form item[]=1&item[]=2
var reorderList = $(this).sortable('serialize');
//console.log(reorderList);
// fill FormData object by files from data array after order change
var formData = new FormData();
var dataLength = Object.keys(data).length;
//console.log(data);
data = changeOrder(data, reorderList);
//console.log(data);
}
})
// Change order of files inside object data
function changeOrder(obj, order) {
var newObject = {};
// if the g flag is used, all results matching the complete regular expression will be returned, but capturing groups will not.
var matches = order.match(/=/g);
var count = matches.length;
// file[]=1&file[]=0&file[]=2 => ["file[]=1", "file[]=0", "file[]=2"]
var arrayOfOrderValues = order.split('&');
// console.log(arrayOfOrderValues);
for (var i = 0; i < count; i++) {
// get values in appropriate format ["file[]=1", "file[]=0", "file[]=2"] => file_1, file_0, file_2
orderKey = 'file_' + arrayOfOrderValues[i].substring(arrayOfOrderValues[i].lastIndexOf("=") + 1);
// console.log(orderKeyValue);
// check if object contains key(property) as orderKeyValue and then do next step
if(obj.hasOwnProperty(orderKey)) {
// fill value of obj['file_1'] to newObject['file_0'] - ex. in first loop
newObject['file_'+i] = obj[orderKey];
}
}
return newObject;
}
// Sending AJAX request and upload file
function uploadData(formdata){
$.ajax({
url: '_inc/upload.php',
type: 'post',
data: formdata,
contentType: false,
processData: false,
dataType: 'json',
success: function(response){
//addThumbnail(response); // if success - create thumbnail
}
})
}
$('.test').on('submit', function() {
event.preventDefault();
var formData = new FormData(); // Create form
console.log(data);
var count = Object.keys(data).length; // count fields of object
for (var i = 0; i < count; i++) {
formData.append('files[]', data['file_'+i]); // append data to form -> (key, value), file[0] first file from list of files !!! key must have [] for array
}
console.log(count);
uploadData(formData); // send data via ajax to upload.php
})
PHP:
<?php
require($_SERVER['DOCUMENT_ROOT'] . '/bazar/_inc/DBController.php');
// inicialize object
$db_handler = new DBController();
// get total number of files in file list
$total_files = count($_FILES['files']['name']);
// array(5) { ["name"]=> array(2) { [0]=> string(23) "IMG_20190916_105311.jpg" [1]=> string(19) "20180525_115635.jpg" } ["type"]=> array(2) { [0]=> string(10) "image/jpeg" [1]=> string(10) "image/jpeg" } ["tmp_name"]=> array(2) { [0]=> string(28) "/home/gm016900/tmp/phpdU58AU" [1]=> string(28) "/home/gm016900/tmp/phpIqWoaQ" } ["error"]=> array(2) { [0]=> int(0) [1]=> int(0) } ["size"]=> array(2) { [0]=> int(306091) [1]=> int(2315700) } }
// Create array for jQuery information
$return_arr = array();
$images_names = array_filter($_FILES['files']['name']); // filter just values for $key = name
// -> array(2) { [0]=> string(23) "IMG_20190916_105311.jpg" [1]=> string(19) "20180525_115635.jpg" }
//var_dump($images_names);
/* BATCH FILE UPLOAD */
// if $_FILES contains image then do foreach
if ( !empty($images_names) ) {
for($i = 0; $i < $total_files; $i++) {
// Get reference to uploaded image
$image_file = $_FILES["files"];
// Get image name
$image_name = $_FILES["files"]["name"][$i];
// Get file size
$image_size = $_FILES["files"]["size"][$i];
/* BASIC CONTROL */
// Exit if no file uploaded or image name contains unvalid characters /, \\
if ( ( !strpos($image_name, '/') || !strpos($image_name, '\\') ) && isset($image_file) ) {
// define variables if image in correct format is uploaded
$errors = array();
$maxsize = 10485760;
$acceptable = array(
'image/jpeg',
'image/jpg',
'image/gif',
'image/png'
);
} else {
die('No image uploaded.');
}
// Exit if image file is zero bytes or if image size is more then 10 MB
if (getimagesize($image_file["tmp_name"][$i]) <= 0) {
die('Uploaded file has no contents.');
} elseif ($image_size >= $maxsize) {
die('Image is too large. Image must be less than 10 megabytes.');
}
// Determine the type of an image int|false
$image_type = exif_imagetype($image_file["tmp_name"][$i]);
// Exit if is not a valid image file or image has not supported type
if (!$image_type) {
die('Uploaded file is not an image.');
} elseif ( !in_array($image_file["type"][$i], $acceptable) ) {
die('Image has not supported type JPG, PNG, GIF.');
} else {
$src = "default.png";
}
/* CREATE RANDOM IMAGE NAME INSTEDAOF $_FILES['files']['name'] */
// Get file extension based on file type, to prepend a dot we pass true as the second parameter
$image_extension = image_type_to_extension($image_type, true);
// Create a unique image name
$random_image_name = bin2hex(random_bytes(16)) . $image_extension;
/* DEFINE LOCATION */
// 1st create adress with new img random name
$relative_location = "/bazar/assets/img/photos/".$random_image_name;
$absolute_location = dirname(__DIR__, 2).$relative_location;
//var_dump($image_file["tmp_name"][$i]);
//var_dump($absolute_location);
/* MOVE TEMP IMG TO PHOTOS FOLDER */
// 2nd move img with tmp_name to new location under new random name added from 1st step
if (move_uploaded_file($image_file["tmp_name"][$i], $absolute_location)) {
$item_id = 1;
$src = $relative_location;
$query = "INSERT INTO photos (item_id, file_name) VALUES (?, ?)";
$inserted = $db_handler->runQuery( $query, 'is', array($item_id, $src) );
var_dump($inserted);
//$return_arr .= array("name" => $random_image_name,"size" => $image_size, "src"=> $src);
}
}
}
//echo json_encode($return_arr);
Here is code from one Web Source:
$(document).ready(function()
{
$("#drop-area").on('dragenter', function (e){
e.preventDefault();
$(this).css('background', '#BBD5B8');
});
$("#drop-area").on('dragover', function (e){
e.preventDefault();
});
$("#drop-area").on('drop', function (e){
$(this).css('background', '#D8F9D3');
e.preventDefault();
var image = e.originalEvent.dataTransfer.files;
createFormData(image);
});
});
function createFormData(image)
{
var formImage = new FormData();
formImage.append('userImage', image[0]);
uploadFormData(formImage);
}
function uploadFormData(formData)
{
$.ajax({
url: "upload_image.php",
type: "POST",
data: formData,
contentType:false,
cache: false,
processData: false,
success: function(data){
$('#drop-area').html(data);
}});
}
I'm trying to build-in an Image Uplaoder to my CMS for the gallery.
I've done some research and found what I need to build it.
The uploader uses three files. The first one is where to select the images for upload and showing some progress. Connected to this is a js file for resizing the selected images first and upload them afterwards. And last but not least a file to process the images on server via php and for writing data into sql-database.
The good point is: Everything works as it should.
BUT I have a problem with sorting the images. Because they are getting a md5 generated filename, and the uploader handles multiple images at a time, some images that I took for example at the end of a day are showed first and the first pictures of the day are for example anywhere between them.
So here comes my question: Is there a way to keep the orignal filename and name the uploaded image for example anything like "1234md5randomdigits_ORIGINALFILENAME.jpg"?
I've tried a lot of $_FILES and other php parameters, but they were empty...
Here is my upload file for selecting images:
<!DOCTYPE html>
<html>
<head>
<title>multiple.php</title>
<link rel="stylesheet" href="./style.css" />
<head>
<body>
<h1>Upload Images...</h1>
<form>
<input type="file" multiple />
<div class="photos">
</div>
</form>
<script src="./upload.js"></script>
</body>
</html>
Here comes the upload.js file
// Once files have been selected
document.querySelector('form input[type=file]').addEventListener('change', function(event){
// Read files
var files = event.target.files;
// Iterate through files
for (var i = 0; i < files.length; i++) {
// Ensure it's an image
if (files[i].type.match(/image.*/)) {
// Load image
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
// Add elemnt to page
var imageElement = document.createElement('div');
imageElement.classList.add('uploading');
imageElement.innerHTML = '<span class="progress"><span></span></span>';
var progressElement = imageElement.querySelector('span.progress span');
progressElement.style.width = 0;
document.querySelector('form div.photos').appendChild(imageElement);
// Resize image
var canvas = document.createElement('canvas'),
max_size = 1200,
width = image.width,
height = image.height;
if (width > height) {
if (width > max_size) {
height *= max_size / width;
width = max_size;
}
} else {
if (height > max_size) {
width *= max_size / height;
height = max_size;
}
}
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
// Upload image
var xhr = new XMLHttpRequest();
if (xhr.upload) {
// Update progress
xhr.upload.addEventListener('progress', function(event) {
var percent = parseInt(event.loaded / event.total * 100);
progressElement.style.width = percent+'%';
}, false);
// File uploaded / failed
xhr.onreadystatechange = function(event) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
imageElement.classList.remove('uploading');
imageElement.classList.add('uploaded');
imageElement.style.backgroundImage = 'url('+xhr.responseText+')';
console.log('Image uploaded: '+xhr.responseText);
} else {
imageElement.parentNode.removeChild(imageElement);
}
}
}
// Start upload
xhr.open('post', 'process.php', true);
xhr.send(canvas.toDataURL('image/jpeg'));
}
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(files[i]);
}
}
// Clear files
event.target.value = '';
});
And this my "process.php" to process the uploaded data:
<?php
$save_path="/images";
// Generate filename
$filename = md5(mt_rand()).".jpg";
// Read RAW data
$data = file_get_contents("php://input");
// Read string as an image file
$image = file_get_contents("data://".substr($data, 5));
// Save to disk
if ( ! file_put_contents($save_path.$filename, $image)) {
exit();
}
// Clean up memory
unset($data);
unset($image);
//Includes and SQL go after that
// Return file URL
echo $save_path.$filename;
?>
I'd be very happy about some help! :)
In support of my comment above if you send a custom header in the ajax function you can process that server side. I think I got the syntax right for accessing the filename from the files collection
/* ajax: add custom header */
xhr.open('post', 'process.php', true);
xhr.setRequestHeader( 'filename', files[i].name );
xhr.send(canvas.toDataURL('image/jpeg'));
/* php: resort to original md5 name if header failed */
$filename=!empty( $_SERVER['HTTP_FILENAME'] ) ? $_SERVER['HTTP_FILENAME'] : md5(mt_rand()).".jpg";
As I originally forgot to add HTTP_ to the beginning of the custom header ( php ) it initially would not have worked - a simple oversight on my behalf. To correct that I put together a quick demo of using the custom headers idea from end to end, though the code that follows does not entirely emulate your original code with the image processing, canvas, FileReader etc it does show the important aspect of assigning the custom request header and how to process that server-side in php so I hope it will give you an idea how you can implement the original filename feature.
<?php
/*
emulate server side processing of uploaded file -
here it simply sends back the custom headers and
a single POST variable but this would be processing
the image data and saving the file
*/
if( $_SERVER['REQUEST_METHOD']=='POST' ){
ob_clean();
$filename = !empty( $_SERVER['HTTP_FILENAME'] ) ? $_SERVER['HTTP_FILENAME'] : md5( mt_rand() ).".jpg";
$filetype = !empty( $_SERVER['HTTP_FILETYPE'] ) ? $_SERVER['HTTP_FILETYPE'] : 'M.I.A';
$filesize = !empty( $_SERVER['HTTP_FILESIZE'] ) ? $_SERVER['HTTP_FILESIZE'] : 'M.I.A';
$action = !empty( $_POST['action'] ) ? $_POST['action'] : 'M.I.A';
/* send proper content type response header */
header( 'Content-Type: application/json' );
/* add some custom response headers to show how you can pass headers and process them */
header( sprintf( 'Uploaded-Filename: %s', $filename ) );
header( sprintf( 'Uploaded-Filesize: %s', $filesize ) );
header( sprintf( 'Uploaded-Filetype: %s', $filetype ) );
/* send payload back to ajax callback */
exit( json_encode( array(
'filename' => $filename,
'filesize' => $filesize,
'filetype' => $filetype,
'action' => $action
)));
}
?>
<!doctype html>
<html>
<head>
<title>ajax custom headers</title>
<style>
body,body *{
font-family:calibri,verdana,arial;
font-size:0.9rem;
}
</style>
<script>
function bindEvents(){
/* DOM elements */
var oDiv=document.getElementById('results');
var oPre=document.getElementById('headers');
var oBttn=document.getElementById('bttn');
var oFile=document.querySelector('form input[type="file"]');
/* basic callback function to show response */
var callback=function(r,h){
oDiv.innerHTML=r;
oPre.innerHTML=h;
}
oBttn.onclick=function(){
/* as there is only a single file we know the index is zero */
var oCol=oFile.files;
var file=oCol.item(0).name;
var size=oCol.item(0).size;
var type=oCol.item(0).type;
/* ultra basic ajax request with custom request headers */
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if( this.readyState==4 && this.status==200 ){
/*
The callback can take whatever arguments we want - here simply
the response and some headers - could easily process specific
response headers rather than all
*/
callback.call( this, this.response, this.getAllResponseHeaders() );
}
};
xhr.open( 'POST', location.href, true );
xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
/* add custom request headers - original file details */
xhr.setRequestHeader( 'filename', file );
xhr.setRequestHeader( 'filetype', type );
xhr.setRequestHeader( 'filesize', size );
xhr.send( 'action=headers-test' );
}
}
document.addEventListener( 'DOMContentLoaded', bindEvents, false );
</script>
</head>
<body>
<div id='results'></div>
<pre id='headers'></pre>
<form method='post'>
<input type='file' />
<input type='button' id='bttn' value='Send Ajax Request with custom headers' />
</form>
</body>
</html>
Following on from your comment regarding multiple files all sharing the same name hopefully the following might help.
<form method='post'>
<input type='file' multiple=true />
<input type='button' id='bttn' value='Send Ajax Request with custom headers' />
<div class='photos'></div>
</form>
<script>
document.querySelector( 'form input[type="file"]' ).addEventListener( 'change', function( event ){
// Read files
var files = event.target.files;
// Iterate through files
for( var i = 0; i < files.length; i++ ) {
// Ensure it's an image
if ( files[i].type.match( /image.*/ ) ) {
// Load image
var reader = new FileReader();
/*
assign custom properties to the reader
object which will allow you to access
them within callbacks
*/
reader.filename=files[i].name;
reader.filesize=files[i].size;
reader.filetype=files[i].type;
reader.onload = function( readerEvent ) {
/*
assign each new image with the properties from the reader
- these will be available within the ajax function so you
can set the custom headers
*/
var image = new Image();
image.filename=this.filename;
image.filesize=this.filesize;
image.filetype=this.filetype;
image.onload = function( imageEvent ) {
console.log('image onload - - - > > > > > %s -> %s',this.filename,this.filesize);
// Add element to page
var imageElement = document.createElement('div');
imageElement.classList.add('uploading');
imageElement.innerHTML = '<span class="progress"><span></span></span>';
var progressElement = imageElement.querySelector('span.progress span');
progressElement.style.width = 0;
document.querySelector('form div.photos').appendChild( imageElement );
// Resize image
var canvas = document.createElement('canvas'),
max_size = 1200,
width = image.width,
height = image.height;
if ( width > height ) {
if( width > max_size ) {
height *= max_size / width;
width = max_size;
}
} else {
if( height > max_size ) {
width *= max_size / height;
height = max_size;
}
}
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage( image, 0, 0, width, height );
// Upload image
var xhr = new XMLHttpRequest();
if( xhr.upload ) {
xhr.upload.addEventListener('progress', function(event) {
var percent = parseInt( event.loaded / event.total * 100 );
progressElement.style.width = percent+'%';
}, false);
xhr.onreadystatechange = function(event) {
if( xhr.readyState == 4 ) {
if( xhr.status == 200 ) {
imageElement.classList.remove('uploading');
imageElement.classList.add('uploaded');
imageElement.style.backgroundImage = 'url('+xhr.responseText+')';
} else {
imageElement.parentNode.removeChild( imageElement );
}
}
}
xhr.open( 'post', location.href, true ); //'process.php'
xhr.setRequestHeader( 'filename', image.filename );
xhr.setRequestHeader( 'filetype', image.filetype );
xhr.setRequestHeader( 'filesize', image.filesize );
xhr.send( canvas.toDataURL('image/jpeg') );
}
};
image.src = readerEvent.target.result;
};
reader.readAsDataURL( files[i] );
}
}
// Clear files
event.target.value = '';
});
</script>
This is what I use to process potentially any number of upload files if you leave the file name as it is here it will leave it the same as the users file name. Make your form element name an array and it will loop through it uploading all the files. You'll also have to set your form type to multipart. This should be a lot easier to manage than what it looks like you're trying to do though.
$target_dir = "images/";
extract($_POST);
$error=array();
$extension=array("jpg", "gif");
$i=0;
foreach($_FILES["filetoupload"]["tmp_name"] as $key=>$tmp_name) {
$file_name = $_FILES["filetoupload"]["name"][$key];
$ext = strtolower(pathinfo($file_name,PATHINFO_EXTENSION));
$file_tmp=$_FILES["filetoupload"]["tmp_name"][$key];
if(in_array($ext,$extension)) {
if ($_FILES["filetoupload"]["size"][$key] < 5000000) {
if ($_FILES["filetoupload"]["size"][$key] != 0) {
if(!file_exists( $target_dir . $file_name )) {
move_uploaded_file($file_tmp , $target_dir . $file_name );
}
}
}
} else {
array_push($error,"$file_name, ");
}
}
in this example the name attribute of all of the file input fields is name="filetoupload[]"
I need to print all the txt files from a directory inside an HTML using javascript.
i tried to modify a code dealing with photos but I didn't success
How to load all the images from one of my folder into my web page, using Jquery/Javascript
var dir = "D:\Finaltests\test1\new\places";
var fileextension = ".txt";
$.ajax({
//This will retrieve the contents of the folder if the folder is configured as 'browsable'
url: dir,
success: function (data) {
//List all .txt file names in the page
$(data).find("a:contains(" + fileextension + ")").each(function () {
var filename = this.href.replace(window.location.host, "").replace("http://", "");
$("body").append("<input type='file' onload='readText(" + dir + ")>");
});
}
});
You can use <input type="file"> with multiple attribute set, accept attribute set to text/plain; change event ;FileReader, for loop.
var pre = document.querySelector("pre");
document.querySelector("input[type=file]")
.addEventListener("change", function(event) {
var files = event.target.files;
for (var i = 0; i < files.length; i++) {
(function(file) {
var reader = new FileReader();
reader.addEventListener("load", function(e) {
pre.textContent += "\n" + e.target.result;
});
reader.readAsText(file)
}(files[i]))
}
})
<input type="file" accept="text/plain" multiple />
<pre>
</pre>
You can also use webkitdirectory and allowdirs attributes for directory upload at chrome, chromium; at nightly 45+ or firefox 42+ where dom.input.dirpicker preference set to true, see Firefox 42 for developers , Select & Drop Files and/or Folders to be parsed. Note, you can also drop folders from file manager at <input type="file"> element
var pre = document.querySelector("pre");
document.querySelector("input[type=file]")
.addEventListener("change", function(event) {
console.log(event.target.files)
var uploadFile = function(file, path) {
// handle file uploading
console.log(file, path);
var reader = new FileReader();
reader.addEventListener("load", function(e) {
pre.textContent += "\n" + e.target.result;
});
reader.readAsText(file)
};
var iterateFilesAndDirs = function(filesAndDirs, path) {
for (var i = 0; i < filesAndDirs.length; i++) {
if (typeof filesAndDirs[i].getFilesAndDirectories === 'function') {
var path = filesAndDirs[i].path;
// this recursion enables deep traversal of directories
filesAndDirs[i].getFilesAndDirectories()
.then(function(subFilesAndDirs) {
// iterate through files and directories in sub-directory
iterateFilesAndDirs(subFilesAndDirs, path);
});
} else {
uploadFile(filesAndDirs[i], path);
}
}
};
if ("getFilesAndDirectories" in event.target) {
event.target.getFilesAndDirectories()
.then(function(filesAndDirs) {
iterateFilesAndDirs(filesAndDirs, '/');
})
} else {
// do webkit stuff
var files = event.target.files;
for (var i = 0; i < files.length; i++) {
(function(file) {
uploadFile(file)
}(files[i]))
}
}
})
<!DOCTYPE html>
<html>
<head>
<script></script>
</head>
<body>
<input type="file" webkitdirectory allowdirs directory />
<pre>
</pre>
</body>
</html>
plnkr http://plnkr.co/edit/Y1XYd9rLOdKRHw6tb1Sh?p=preview
For ajax requests at chromium, chrome file: protocol local filesystem you can launch with --allow-file-access-from-files flag set, see Jquery load() only working in firefox?.
At firefox you can set security.fileuri.strict_origin_policy to false, see Security.fileuri.strict origin policy.
For a possible $.ajax() approach at chrome, chromium you can try
var path = "/path/to/drectory"; // `D:\`, `file:///`
var files = [];
$.ajax({url:path, dataType:"text html"})
.then((data) => {
// match file names from `html` returned by chrome, chromium
// for directory listing of `D:\Finaltests\test1\new\places`;
// you can alternatively load the "Index of" document and retrieve
// `.textContent` from `<a>` elements within `td` at `table` of
// rendered `html`; note, `RegExp` to match file names
// could probably be improved, does not match space characters in file names
var urls = $.unique(data.match(/\b(\w+|\d+)\.txt\b/g));
return $.when.apply($, $.map(urls, (file) => {
files.push(file);
// `\`, or `/`, depending on filesystem type
return $.ajax({url:path + "/" + file
, dataType:"text html"})
.then((data) => {
// return array of objects having property set to `file` name,
// value set to text within `file`
return {[file]:data}
})
}))
})
.then((...res) => {
console.log(res, files)
})
you can't reach the host filesystem with javascript for security reason.
The best you can do is to make a single ajax call to a server-side script (php for exemple) that will collect all html file and return them to your ajax call.
gethtml.php:
<?php
$output = "";
// your list of folders
$folders = [
'D:\Finaltests\test1\new\places1',
'D:\Finaltests\test1\old\places2',
'D:\Finaltests\test1\whatever\places3'
];
foreach ($folders as $key => $dir) {
if(!is_dir($dir))
continue;
// get all files of the directory
$files = scandir($dir);
foreach ($files as $file) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if(finfo_file($finfo, $file) == 'text/plain')
$output .= file_get_contents($dir . DIRECTORY_SEPARATOR . $file);
}
}
echo $output;
exit;
?>
Ajax call:
$.get('path/to/gethtml.php', function(response){
$('body').html(response);
});
you can change the line of php that check the mime type according to the type of the file you want to get (plain text or text/html or whatever)
Here is what I did to get the file renaming working:
Dropzone.js - How to change file name before uploading to folder
From index.php:
$(document).ready(function() {
Dropzone.autoDiscover = false;
var fileList = new Array;
var i =0;
$("#some-dropzone").dropzone({
addRemoveLinks: true,
init: function() {
// Hack: Add the dropzone class to the element
$(this.element).addClass("dropzone");
this.on("success", function(file, serverFileName) {
fileList[i] = {"serverFileName" : serverFileName, "fileName" : file.name,"fileId" : i };
//console.log(fileList);
i++;
});
this.on("removedfile", function(file) {
var rmvFile = "";
for(f=0;f<fileList.length;f++){
if(fileList[f].fileName == file.name)
{
rmvFile = fileList[f].serverFileName;
}
}
if (rmvFile){
$.ajax({
url: "http://localhost/dropzone/sample/delete_temp_files.php",
type: "POST",
data: { "fileList" : rmvFile }
});
}
});
},
url: "http://localhost/dropzone/sample/upload.php"
});
});
From upload.php:
<?php
$ds = DIRECTORY_SEPARATOR; // Store directory separator (DIRECTORY_SEPARATOR) to a simple variable. This is just a personal preference as we hate to type long variable name.
$storeFolder = 'uploads'; // Declare a variable for destination folder.
if (!empty($_FILES)) {
$tempFile = $_FILES['file']['tmp_name']; // If file is sent to the page, store the file object to a temporary variable.
$targetPath = dirname( __FILE__ ) . $ds. $storeFolder . $ds; // Create the absolute path of the destination folder.
// Adding timestamp with image's name so that files with same name can be uploaded easily.
$date = new DateTime();
$newFileName = $date->getTimestamp().$_FILES['file']['name'];
$targetFile = $targetPath.$newFileName; // Create the absolute path of the uploaded file destination.
move_uploaded_file($tempFile,$targetFile); // Move uploaded file to destination.
echo $newFileName;
}
?>
New file delete_tmp_files.php:
<?php
$ds = DIRECTORY_SEPARATOR; // Store directory separator (DIRECTORY_SEPARATOR) to a simple variable. This is just a personal preference as we hate to type long variable name.
$storeFolder = 'uploads';
$fileList = $_POST['fileList'];
$targetPath = dirname( __FILE__ ) . $ds. $storeFolder . $ds;
if(isset($fileList)){
unlink($targetPath.$fileList);
}
?>
Here I need dropzone to call PHPExcel or sheetJS. I have sheetJS parsing to CSV in a static page using ajax here:
<html>
<head>
<title>AJAX XLS TEST</title>
</head>
<body>
<br/><div id="fileurl"></div>
<pre id="out"></pre>
<br />
<script src="js/iemagic.js"></script>
<script src="js/shim.js"></script>
<script src="js/jszip.js"></script>
<script src="js/xlsx.js"></script>
<script>
function to_csv(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]);
if(csv.length > 0){
result.push("SHEET: " + sheetName);
result.push("");
result.push(csv);
}
});
return result.join("\n");
}
function process_wb(wb) {
var output = to_csv(wb);
if(out.innerText === undefined) out.textContent = output;
else out.innerText = output;
if(typeof console !== 'undefined') console.log("output", new Date());
}
var url = "uploads/fw.xls";
var oReq;
if(window.XMLHttpRequest) oReq = new XMLHttpRequest();
else if(window.ActiveXObject) oReq = new ActiveXObject('MSXML2.XMLHTTP.3.0');
else throw "XHR unavailable for your browser";
document.getElementById('fileurl').innerHTML = 'Download file';
oReq.open("GET", url, true);
if(typeof Uint8Array !== 'undefined') {
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date());
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for(var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var wb = XLSX.read(arr.join(""), {type:"binary"});
process_wb(wb);
};
} else {
oReq.setRequestHeader("Accept-Charset", "x-user-defined");
oReq.onreadystatechange = function() { if(oReq.readyState == 4 && oReq.status == 200) {
var ff = convertResponseBodyToText(oReq.responseBody);
if(typeof console !== 'undefined') console.log("onload", new Date());
var wb = XLSX.read(ff, {type:"binary"});
process_wb(wb);
} };
}
oReq.send();
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>
Question 1: How do I get dropzone to call this ajax csv output? A. There is "queuecomplete" but where to put the quecomplete code (body? head? index.php? Upload.php? Another option would be using PHPexcel (below) but again not sure how to get dropzone to call it after renaming is done:
| Excel To Array
|--------------------------------------------------------------------------
| Helper function to convert excel sheet to key value array
| Input: path to excel file, set wether excel first row are headers
| Dependencies: PHPExcel.php include needed
*/
$filePath = "uploads/fw.xls";
function excelToArray($filePath, $header=true){
//Create excel reader after determining the file type
$inputFileName = $filePath;
/** Identify the type of $inputFileName **/
$inputFileType = PHPExcel_IOFactory::identify($inputFileName);
/** Create a new Reader of the type that has been identified **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Set read type to read cell data onl **/
$objReader->setReadDataOnly(true);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
//Get worksheet and built array with first row as header
$objWorksheet = $objPHPExcel->getActiveSheet();
//excel with first row header, use header as key
if($header){<SNIP>
I really think PHPexcel would be much easier when it comes to culling out specific data from the xls as I only need specific fields to populate the following javascript form, but again, where do I put the PHPexcel script? Do I use queuecomplete to call the file? I think if I use queuecomplete and reference phpexcel_parse.php I could get it going from there but I just can't seem to get dropzone to do something with the file after uploading and renaming is complete. Any help is much appreciated. Thanks!