I have an input which accepts multiple files:
<input id="propertyImages" type="file" name="submission_img[]" multiple accept=".jpg, .jpeg, .png, .gif"/>
I then POST this data to a PHP file via JS/Ajax:
//Compiling the data which will be POSTed using AJAX. Note that the input above with id of propertyImages is not part of the form with id accommodationForm and is therefore appended to the formData.
var form = $("#accommodationForm")[0];
var formData = new FormData(form);
var propertyImages = document.getElementById("propertyImages");
for(var i=0; i<propertyImages.files.length; i++){
formData.append('propImages[]', propertyImages.files[i]);
}
//Printing to console the formData entries to confirm the formData data:
for (var d of formData.entries()) {
console.log(d);
}
//The partial code for the ajax call:
$.ajax({
url: "includes/handlers/ajax_submit_accommodation.php",
method: "POST",
data: formData,
...
The PHP code to which the data is POSTed:
$errorstatus = 0; //Used as an error flag
$maximagesize = 10485760; // Max file size allowed = 10MB
$acceptableimage = array( //The allowed mime types
'image/jpeg',
'image/jpg',
'image/png',
);
$submission_images_array = array();
$output = ""; //Used for debugging purposes
for($x=0; $x<30; $x++){ //30 is the upper limit for the amount of images POSTed
if($_FILES['propImages']['size'][$x] != 0){
if( $_FILES['propImages']['size'][$x] >= $maximagesize || (!in_array($_FILES['propImages']['type'][$x], $acceptableimage))) {
$errorstatus = 1;
} else {
$submission_img = $_FILES['propImages']['name'][$x];
$submission_img = pathinfo($submission_img, PATHINFO_FILENAME);
$submission_img = $submission_img.'-'.$user_id.'-'.rand().'.jpeg';
array_push($submission_images_array, $submission_img);
$submission_img_tmp = $_FILES['propImages']['tmp_name'][$x];
compressImage($submission_img_tmp, '../../submitted_media/accommodation/'.$submission_img, 50);
$output .= "$x:"." ".$submission_img."\n";
}
} else {
$output .= "$x: Empty image\n";
$submission_img = "";
array_push($submission_images_array, $submission_img);
}
}
file_put_contents('../../filenames.txt', $output ); // DEBUG
I want the user to attach a maximum of 30 images. I have made sure that the front end and back end check for this. The issue I am having is that I can attach 30 images - the debugging confirms this via the printing to console of the formData...i.e. the formData contains all the image data. However, when I look at the filenames.txt which I logged in the PHP it only contains the first 20 file names, while the last 10 entries is logged as "Empty image" (as I instructed in the code if the image size is 0).
Notes:
I have made sure (using other JS code) that propertyImages.files.length in the for loop cannot be greater than 30 and that when I attach 30 images, that the length is indeed 30.
I have made sure that max_input_vars in the PHP.ini file is not the issue.
The image sizes of the last 10 files are NOT 0. This has been confirmed by the logging of formData
Have a look at the max_file_uploads directive:
max_file_uploads integer
The maximum number of files allowed to be uploaded simultaneously.
As shown in the table in the "File Uploads" section, it defaults to 20:
Name Default Changeable Changelog
...
max_file_uploads 20 PHP_INI_SYSTEM Available since PHP 5.2.12.
You'll need to update that value your php.ini.
Also check you don't exceed post_max_size or
upload_max_filesize.
Related
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 have a form that contains article information and images that I submit using the DropZone library.
I have no problem with this library and it works very well, but when the submitted form had an error and I receive this error message on the client side via Ajax, the user fixes the problems and sends the form again, but unfortunately the form is not sent and no file is left. Not selected
While the files are available in the preview and are sent to the server only once.
What should I do to solve this problem?
Please enter simple codes.
Thanks
successmultiple function
myDropzone.on("successmultiple", function(file,serverResponse) {
/* None of the uploaded files are available in Drop Zone here anymore,
** and I had to delete the files so the user could choose again,
** which would not be a good user experience.
** Exactly what code should I write here so that there is no need to
** re-select files from the user's system?
*/
myDropzone.removeFile(file);
if(serverResponse.status)
{
// Success:: In this case, I have no problem
alert("Article saved successfully. Redirecting to the Articles page ...");
window.location.href = serverResponse.redirectedTo;
}
else
{
// Display errors received from the server to the user
alert("Please enter your name and resubmit the form.");
}
});
I think a possible solution is if you pass the event to your successhandler and prevent it from its default bahaviour.
Like so:
function successHandler(event){
event.preventDefault();
}
This should prevent it refreshing the page and loosing the file in the input.
Otherwise I would just save the file to a variable.
I found the answers to my questions myself and i will put it below for you too.
This code is written for Laravel blade file :
<script>
$("document").ready(()=>{
var path = "{{ $path }}";
var file = new File([path], "{{ $attach->file_name }}", {type: "{{ $attach->mime_type }}", lastModified: {{ $attach->updated_at}}})
file['status'] = "queued";
file['status'] = "queued";
file['previewElement'] = "div.dz-preview.dz-image-preview";
file['previewTemplate'] = "div.dz-preview.dz-image-preview";
file['_removeLink'] = "a.dz-remove";
file['webkitRelativePath'] = "";
file['width'] = 500;
file['height'] = 500;
file['accepted'] = true;
file['dataURL'] = path;
file['upload'] = {
bytesSent: 0 ,
filename: "{{ $attach->file_name }}" ,
progress: 0 ,
total: {{ $attach->file_size }} ,
uuid: "{{ md5($attach->id) }}" ,
};
myDropzone.emit("addedfile", file , path);
myDropzone.emit("thumbnail", file , path);
// myDropzone.emit("complete", itemInfo);
// myDropzone.options.maxFiles = myDropzone.options.maxFiles - 1;
myDropzone.files.push(file);
console.log(file);
});
</script>
I want to ask that how can I get the size of data I am passing as a client to the server.As while developing an application, I am unable to get the whole data on server side.My POST limit size at the server side is 6M as in php.ini file.
I have asked a similar question earlier(How to parse large data via POST query), but didn't get a prompt answer.
Thanks
Try this:
$data_size = (int) $_SERVER['CONTENT_LENGTH'];
Please use this function on submit form
<button onclick="store()" type="button">form submit</button>
function store(){
var totalsize = 0; // total post data size
$('form').find('input[type=file]').each(function() { // for all files in form
totalsize += this.files[0].size;
});
totalsize=totalsize+($("form").not("[type='file']").serialize().length);
if (totalsize > (6 * 1048576)) { // > 6MB
// this will exceed post_max_size PHP setting, now handle...
alert('this will exceed post_max_size PHP setting')
} else if ($('form').find('input[type=file]').length >= 10) { // max_file_upload_limit = 10;
// if file upload is more than 10
alert('upload is more than 10 files')
}else{
you are free upload data successfully
}
}
This is a tangent from the question here:
Returning value to Javascript from PHP called from XMLHttpRequest
I am adding an "image upload" button to my AjaxChat. I am using an XMLHttpRequest to send the image to the server, where I run a PHP script to move it to my images folder. Below is the Javascript function in charge of opening the XMLHttpRequest connection and sending the file:
function uploadImage() {
var form = document.getElementById('fileSelectForm');
var photo = document.getElementById('photo');
var uploadButton = document.getElementById('imageUploadButton');
form.onsubmit = function(event) {
event.preventDefault();
// Update button text
uploadButton.innerHTML = 'Uploading...';
//Get selected files from input
var files = photo.files;
// Create a new FormData object
var formData = new FormData();
// Loop through selected files
for (var i = 0; files.length > i; i++) {
var file = files[i];
// Check file type; only images are allowed
if (!file.type.match('image/*')) {
continue;
}
// Add file to request
formData.append('photo', file, file.name);
}
// Set up request
var xhr = new XMLHttpRequest();
// Open connection
xhr.open('POST', 'sites/all/modules/ajaxchat/upload.php', true);
// Set up handler for when request finishes
xhr.onload = function () {
if (xhr.status === 200) {
//File(s) uploaded
uploadButton.innerHTML = 'Upload';
var result = xhr.responseText;
ajaxChat.insertText('\n\[img\]http:\/\/www.mysite.com\/images' + result + '\[\/img\]');
ajaxChat.sendMessage();
} else {
alert('An error occurred!');
}
form.reset();
};
// Send data
xhr.send(formData);
}
}
Here is upload.php:
<?php
$valid_file = true;
if($_FILES['photo']['name']) {
//if no errors...
if(!$_FILES['photo']['error']) {
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['tmp_name']); //rename file
if($_FILES['photo']['size'] > (1024000)) { //can't be larger than 1 MB
$valid_file = false;
}
//if the file has passed the test
if($valid_file) {
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], '/var/www/html/images'.$new_file_name);
$message = $new_file_name;
exit("$message");
}
}
}
?>
I currently have the multiple image upload disabled, so the "Loop through selected files" only executes once.
The upload worked for a little bit on my PC, but then I tried uploading an image from my phone. When I did so, the entire server (and my browser) crashed, presumably due to an infinite loop somewhere. Every time I close my browser and log back in, or restart the server, or restart my computer, it hangs and eventually crashes again (on my PC or on my phone). I have been unable to find the script that is causing the issue. I get the feeling it's right under my nose. Does anyone see the problem? If you need the HTML form code then I can provide that, but I don't think it's necessary.
We are taking over a site that is using Angular js for a form for data and multi-file upload (up to 4 files).
We are posting to a .php file. I have been able to separate and capture the field data - but can only seem to 'see' one file. If I upload multiple files I 'see' only the last one added to the form.
Can someone please help me to get the files using PHP?
Form HTML (for files):
<ul class="attachments">
<li ng-repeat="attachment in attachments" class="attachment">
{{attachment.name}}
<i class="btn-submit-att-x-hover-off"></i>
</li>
</ul>
<button type="button" class="attachments-button btn btn-default" ngf-select ngf-change="onFileSelect($files)" ngf-multiple="true" ng-if="attachments.length < 4">
<i class="btn-submit-attch"></i>Upload Attachments
</button>
Angular JS Code - for the files as I see:
$scope.attachments = [];
//onFileSelect adds file attachments to the $scope up to the
//configured maximum value.
$scope.onFileSelect = function ($files) {
var MAX_ATTACHMENTS = 4;
for(var i=0; i < $files.length; i++){
if($scope.attachments.length >= MAX_ATTACHMENTS){
break;
}
$scope.attachments.push($files[i]);
}
};
$scope.removeAttachment = function (attachment) {
var index = $scope.attachments.indexOf(attachment);
if (index > -1) {
$scope.attachments.splice(index, 1);
}
};
//POST form data
$scope.upload = Upload.upload({
url: 'forms/pressrelease.html',
method: 'POST',
data: $scope.model,
file: $scope.attachments,
fileFormDataName: "files"
})
.success(function (data, status, headers, config) {
alertSuccess("Your press release has been submitted successfully!");
$scope.showSuccess = true;
}
The only PHP code we've used that has given us anything back - but again - only 1, or the last file name is:
if(isset($_FILES['files'])){
$files = $_FILES['files'];
$sentfilename = $_FILES['files']['name'];
$email_body .= "I see files: $sentfilename<br />";
$tmpsentfile = $_FILES['files']['tmp_name'];
$i=0;
$getfile = $files[0];
$sentfilename = $getfile;
$sentfilesize = $_FILES['files']['size'];
$errormessage = $_FILES['files']['error'];
$email_body .= "I see files: $sentfilename<br />";
}
If anyone one can show us the PHP code we need to use to capture these uploaded files.
Thanks
Create a names array and post the dynamic file names:
var names = []
foreach file:
names.push(files[i].name)
in upload:
method: 'POST',
data: $scope.model,
file: $scope.attachments,
fileFormDataName: names