Pregunta Carga múltiple de archivos HTML desde diferentes carpetas


Tengo un formulario con un campo de carga que permite a los usuarios seleccionar varios archivos. Sin embargo, debo poder permitir que el usuario seleccione el archivo 1 de la carpeta 1, luego vaya y seleccione el archivo 2 de la carpeta 2, y así sucesivamente.

Actualmente, cuando el usuario selecciona el archivo 1 de la carpeta 1 y luego pulsa "Abrir", la ventana de selección se cierra (dejando al usuario en mi formulario). Luego, si el usuario va y selecciona el archivo 2 de la carpeta 2 y pulsa el botón "Abrir", el archivo 1 se elimina, dejando solo el archivo 2.

Básicamente, el usuario no puede seleccionar varios archivos a menos que estén todos en la misma ubicación. ¿Hay alguna manera de hacer que el archivo 1 permanezca seleccionado después de elegir el archivo 2?


5
2017-07-22 13:50


origen


Respuestas:


No, no puedes. Este es un comportamiento definido por los sistemas operativos y puede variar entre ellos. No puedes controlar estas cosas con precisión y siempre temerás lo que sucederá.

Si la cantidad de carpetas que la gente tiene que elegir es bastante pequeña, podría ofrecer múltiples campos de carga.


3
2017-07-22 13:52



¿Qué tal esto?

La solución utiliza HTML, jQuery / Javascript y PHP (para el manejo del lado del servidor de estos datos). La idea es: 1.) Formulario HTML: incluye un botón "explorar" que permite al usuario seleccionar varios archivos (dentro de un directorio). 2.) jQuery: la opción para crear un nuevo botón en el formulario que permite a los usuarios seleccionar múltiples archivos (dentro de un directorio diferente, o incluso el mismo en realidad), con la capacidad de crear nuevos botones "infinitamente". 3.) PHP: como beneficio adicional, pensé en empaquetar bien los datos para el manejo del lado del servidor.

Aquí se muestra el aspecto del formulario HTML (utilicé un icono encontrado para el objeto en el que se puede hacer clic, pero puede reemplazarlo fácilmente con un gráfico de su elección).

<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>" enctype='multipart/form-data'>
    Select files: <br/>
    <input type='file' name='files0[]' id="files0" multiple><br/><br/><br/>
    <span style="font-size: 10pt;">Click "+" for more files
    <i id="more_files" class="general foundicon-plus" style="color: blue;cursor: pointer;"></i></span>
    <br/><br/><br/>
    <input type="submit" name="submit" value="Submit">
</form>

Aquí está el jQuery / Javascript para crear un nuevo botón "explorar" una vez que se activa el evento (¡esto incluso lo coloca después del último botón "navegar"!):

<script type="text/javascript">
//jQuery
$(document).ready(function() {
    $(document).on('click','#more_files', function() {
        var numOfInputs = 1;
        while($('#files'+numOfInputs).length) { numOfInputs++; }//once this loop breaks, numOfInputs is greater than the # of browse buttons

        $("<input type='file' multiple/>")
            .attr("id", "files"+numOfInputs)
            .attr("name", "files"+numOfInputs+"[]")
            .insertAfter("#files"+(numOfInputs-1));

        $("<br/>").insertBefore("#files"+numOfInputs);
    });
});
</script>
<script>
    //vanilla javascript version
    var location = document.getElementById("fileBrowsers");
    var br = document.createElement("BR");
    location.appendChild(br);
    var input = document.createElement("input");
    input.type = "file";
    input.name = "files"+numOfInputs+"[]";
            input.id = "files"+numOfInputs;
            input.multiple = true;

            location.appendChild(input);
</script>

Finalmente, y posiblemente lo más importante, cómo envolver los datos en el servidor en un formato familiar:

<?php
if(isset($_POST['submit']) && !empty($_FILES)) {
    $files = array();
    $files = $_FILES['files0'];
    //var_dump($files);//this array will match the structure of $_FILES['browser']
    //Iterate through each browser button
    $browserIterator = 1;
    while(isset($_FILES['files'.$browserIterator])) {
        //Files have same attribute structure, so grab each attribute and append data for each attribute from each file
        foreach($_FILES['files'.$browserIterator] as $attr => $values) {//get each attribute
            foreach($_FILES['files'.$browserIterator][$attr] as $fileValue) {//get each value from attribute
                $files[$attr][] = $fileValue;//append value
            }
        }
        $browserIterator++;
    }
    //Use $files like you would use $_FILES['browser'] -- It is as though all files came from one browser button!
    $fileIterator = 0;
    while($fileIterator < count($files['name'])) {
        echo $files['name'][$fileIterator]."<br/>";
        $fileIterator++;
    }
}
?>

Nota de actualización: El script jQuery y el Javascript vainilla logran el mismo objetivo. Me encontré con un problema que requería la versión de vanilla. Solo necesitas uno de ellos..


4
2017-07-12 09:18



Otra solución es usar entradas de archivos de la vieja escuela (no múltiples). En este caso, no puede seleccionar varios archivos para cargar, pero puede eliminar cualquier archivo y agregar otro. Inicialmente, solo hay una entrada de archivo en la página, pero cuando selecciona el archivo, se oculta y se reemplaza por el nombre del archivo con el botón de eliminar, y aparece la nueva entrada de archivo.

var fileInput = document.getElementById('fileInput_0');
var filesList =  document.getElementById('fileList');  
var idBase = "fileInput_";
var idCount = 0;

var inputFileOnChange = function() {

	var existingLabel = this.parentNode.getElementsByTagName("LABEL")[0];
	var isLastInput = existingLabel.childNodes.length<=1;

	if(!this.files[0]) {
		if(!isLastInput) {
			this.parentNode.parentNode.removeChild(this.parentNode);
		}
		return;
	}

	var filename = this.files[0].name;

	var deleteButton = document.createElement('span');
	deleteButton.innerHTML = '&times;';
	deleteButton.onclick = function(e) {
		this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
	}
	var filenameCont = document.createElement('span');
	filenameCont.innerHTML = filename;
	existingLabel.innerHTML = "";
	existingLabel.appendChild(filenameCont);
	existingLabel.appendChild(deleteButton);
	
	if(isLastInput) {	
		var newFileInput=document.createElement('input');
		newFileInput.type="file";
		newFileInput.name="file[]";
		newFileInput.id=idBase + (++idCount);
		newFileInput.onchange=inputFileOnChange;
		var newLabel=document.createElement('label');
		newLabel.htmlFor = newFileInput.id;
		newLabel.innerHTML = '+';
		var newDiv=document.createElement('div');
		newDiv.appendChild(newFileInput);
		newDiv.appendChild(newLabel);
		filesList.appendChild(newDiv);
	} 
}

fileInput.onchange=inputFileOnChange;
#fileList > div > label > span:last-child {
	color: red;
	display: inline-block;
	margin-left: 7px;
	cursor: pointer;
}
#fileList input[type=file] {
	display: none;
}
#fileList > div:last-child > label {
	display: inline-block;
	width: 23px;
	height: 23px;
	font: 16px/22px Tahoma;
	color: orange;
	text-align: center;
	border: 2px solid orange;
	border-radius: 50%;
}
<form enctype="multipart/form-data" method="post">
	<div id="fileList">
		<div>
			<input id="fileInput_0" type="file" name="file[]" />
			<label for="fileInput_0">+</label>      
		</div>
	</div>
</form>


0
2017-08-04 01:19