php - seleccionar - subir un archivo en trozos usando html5
subir archivos php mysql (5)
Estoy tratando de cargar un archivo en trozos usando la API de archivos de html5 y luego volver a montarlo en el lado del servidor en PHP. Estoy subiendo un video, pero cuando fusiono los archivos en el lado del servidor, el tamaño ha aumentado y se está convirtiendo en un archivo no válido. Tenga en cuenta que el siguiente código html5 solo funciona en el navegador Chrome. Probado en Chrome 9 ya que utiliza la función de división del archivo API. ¿Puede alguien guiarme en esto? Gracias
Fuente PHP
<?php
$target_path = "uploads/";
$tmp_name = $_FILES[''fileToUpload''][''tmp_name''];
$size = $_FILES[''fileToUpload''][''size''];
$name = $_FILES[''fileToUpload''][''name''];
$target_file = $target_path . basename($name);
$complete = "complete.mov";
$com = fopen("uploads/".$complete, "ab");
error_log($target_path);
// Open temp file
$out = fopen($target_file, "wb");
if ( $out ) {
// Read binary input stream and append it to temp file
$in = fopen($tmp_name, "rb");
if ( $in ) {
while ( $buff = fread( $in, 1048576 ) ) {
fwrite($out, $buff);
fwrite($com, $buff);
}
}
fclose($in);
fclose($out);
}
fclose($com);
?>
Fuente HTML
<!DOCTYPE html>
<html>
<head>
<title>Upload Files using XMLHttpRequest</title>
<script type="text/javascript">
window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
function sendRequest() {
var blob = document.getElementById(''fileToUpload'').files[0];
const BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while( start < SIZE ) {
var chunk = blob.slice(start, end);
uploadFile(chunk);
start = end;
end = start + BYTES_PER_CHUNK;
}
}
function fileSelected() {
var file = document.getElementById(''fileToUpload'').files[0];
if (file) {
var fileSize = 0;
if (file.size > 1024 * 1024)
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + ''MB'';
else
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + ''KB'';
document.getElementById(''fileName'').innerHTML = ''Name: '' + file.name;
document.getElementById(''fileSize'').innerHTML = ''Size: '' + fileSize;
document.getElementById(''fileType'').innerHTML = ''Type: '' + file.type;
}
}
function uploadFile(blobFile) {
//var file = document.getElementById(''fileToUpload'').files[0];
var fd = new FormData();
fd.append("fileToUpload", blobFile);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
xhr.open("POST", "upload.php");
xhr.onload = function(e) {
alert("loaded!");
};
xhr.send(fd);
//alert("oen over");
}
function uploadProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
document.getElementById(''progressNumber'').innerHTML = percentComplete.toString() + ''%'';
}
else {
document.getElementById(''progressNumber'').innerHTML = ''unable to compute'';
}
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert(evt.target.responseText);
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
xhr.abort();
xhr = null;
//alert("The upload has been canceled by the user or the browser dropped the connection.");
}
</script>
</head>
<body>
<form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
<div class="row">
<label for="fileToUpload">Select a File to Upload</label><br />
<input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
<input type="button" value="cancel" onClick="uploadCanceled();"/>
</div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
<input type="button" onclick="sendRequest();" value="Upload" />
</div>
<div id="progressNumber"></div>
</form>
</body>
</html>
Hola he comprobado tu archivo php. Le agregué un código de seguridad. Y cambió el nombre de archivo atribuido y borró la creación del archivo dubbel. Aquí está.
<?php
session_start();
if ($_SESSION[''newsession''] == false and $_SESSION[''TypeUser''] == ''Admin'' ){
$target_path = "../uploads/";
$tmp_name = $_FILES[''fileToUpload''][''tmp_name''];
$size = $_FILES[''fileToUpload''][''size''];
$name = $_FILES[''fileToUpload''][''name''];
$name2 = $_GET[''filename''];
$target_file = $target_path.$name;
$complete =$target_path.$name2;
$com = fopen($complete, "ab");
error_log($target_path);
// Open temp file
//$out = fopen($target_file, "wb");
//if ( $out ) {
// Read binary input stream and append it to temp file
$in = fopen($tmp_name, "rb");
if ( $in ) {
while ( $buff = fread( $in, 1048576 ) ) {
// fwrite($out, $buff);
fwrite($com, $buff);
}
}
fclose($in);
//}
//fclose($out);
fclose($com);
}else{
echo''you are not logged in.'';
}
?>
Para la parte html cambié la forma en que se cargan los archivos de varias partes. Puse el tema en una lista y uno por uno lo subí. Aquí está el código.
<script type="text/javascript" >
function uploadchange() {
var input = document.getElementById("file");
var ul = document.getElementById("uploadlist");
while (ul.hasChildNodes()) {
ul.removeChild(ul.firstChild);
}
for (var i = 0; i < input.files.length; i++) {
var li = document.createElement("li");
thefilesize = input.files[i].fileSize||input.files[i].size;
if (thefilesize > 1024 * 1024){
thefilesize = (Math.round(thefilesize * 100 / (1024 * 1024)) / 100).toString() + ''MB'';
}else{
thefilesize = (Math.round(thefilesize * 100 / 1024) / 100).toString() + ''KB'';
}
li.innerHTML = input.files[i].name + " " + thefilesize ;
ul.appendChild(li);
}
if(!ul.hasChildNodes()) {
var li = document.createElement("li");
li.innerHTML = ''No Files Selected'';
ul.appendChild(li);
}
sendRequest();
}
window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
function sendRequest() {
var blob = document.getElementById(''file'').files[0];
var BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
var SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
window.uploadcounter=0;
window.uploadfilearray = [];
document.getElementById(''progressNumber'').innerHTML = "Upload: 0 % ";
while( start < SIZE ) {
var chunk = blob.slice(start, end);
window.uploadfilearray[window.uploadcounter]=chunk;
window.uploadcounter=window.uploadcounter+1;
start = end;
end = start + BYTES_PER_CHUNK;
}
window.uploadcounter=0;
uploadFile(window.uploadfilearray[window.uploadcounter],document.getElementById(''file'').files[0].name);
}
function fileSelected() {
var file = document.getElementById(''fileToUpload'').files[0];
if (file) {
var fileSize = 0;
if (file.size > 1024 * 1024)
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + ''MB'';
else
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + ''KB'';
document.getElementById(''fileName'').innerHTML = ''Name: '' + file.name;
document.getElementById(''fileSize'').innerHTML = ''Size: '' + fileSize;
document.getElementById(''fileType'').innerHTML = ''Type: '' + file.type;
}
}
function uploadFile(blobFile,filename) {
var fd = new FormData();
fd.append("fileToUpload", blobFile);
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
xhr.open("POST", "./system/upload2.php?filename="+filename);
xhr.onload = function(e) {
window.uploadcounter=window.uploadcounter+1;
if (window.uploadfilearray.length > window.uploadcounter ){
uploadFile(window.uploadfilearray[window.uploadcounter],document.getElementById(''file'').files[0].name);
var percentloaded2 = parseInt((window.uploadcounter/window.uploadfilearray.length)*100);
document.getElementById(''progressNumber'').innerHTML = ''Upload: ''+percentloaded2+'' % '';
}else{
document.getElementById(''progressNumber'').innerHTML = "File uploaded";
loadXMLDoc(''./system/loaddir.php?url=''+ window.currentuploaddir);
}
};
xhr.send(fd);
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
if (evt.target.responseText != ""){
alert(evt.target.responseText);
}
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
xhr.abort();
xhr = null;
//alert("The upload has been canceled by the user or the browser dropped the connection.");
}
</script>
<LINK HREF="./system/link.css" REL="stylesheet" TYPE="text/css">
</head>
<body>
<div id="fileselector">
<div id="containerback">
</div>
<div id="dirlijst">
</div>
<div id="container">
<h1>Upload file</h1>
<br />
<form name="form1" onSubmit="return uploadFile();" method="post" action="<?php echo $_SERVER[''PHP_SELF'']; ?>" enctype="multipart/form-data">
<div id="progressNumber"></div>
<input type="file" id="file" multiple name="uploads[]" style="visibility:hidden" onChange="uploadchange();">
<a href="#" onClick="document.getElementById(''file'').click();return false"><img src="system/iconfilemanager/upload.png" alt="upload file"></a>
<div id="uploadlist">
</div>
</form>
</div>
Intenté resolver este problema y encontré las siguientes cosas, que espero que sean de utilidad para usted:
1) La función JS que está utilizando para cortar el archivo está en desuso. Estoy ejecutando Chrome v14 y la consola no lo reconoció. Tuve que cambiarlo a esto antes de poder hacer algo:
var chunk = blob.webkitSlice(start, end);
2) Experimenté con archivos mucho más pequeños (aproximadamente 10 MB), pero tuve problemas similares: mi video siempre se corrompió después de subirlo. Cuando comparé el original y la "copia", noté una cosa peculiar: parecía que las partes del archivo se habían mezclado: todo estaba allí pero en el orden incorrecto.
Sospecho que un problema que sufre su programa actual es no tomar medidas para asegurarse de que los archivos se ensamblan en el orden correcto. Creo que lo que está sucediendo es que su JS está ejecutando uploadFile varias veces, sin esperar a que terminen las cargas anteriores, y el servidor intenta ensamblar los archivos en el orden en que se reciben, pero no es el mismo orden en que se envían los archivos. .
Pude demostrarlo haciendo que su código funcionara (algo modificado, pirateado como una prueba de concepto), asignando a cada archivo un número de secuencia a medida que se recibía, y luego, después de que todas las partes se recibieran, se reunieron en orden. Después de hacer eso, pude reproducir mi archivo de video, después de haberlo subido.
Creo que vas a tener que tomar una medida similar. Reciba todos los fragmentos de archivos y luego reúnalos, o al menos asegúrese de tomar las medidas necesarias para ensamblarlos en orden. No estoy seguro de por qué sus archivos crecerían en tamaño (observé este fenómeno desde el principio), por lo que sospecho que es simplemente un efecto secundario extraño ya que de lo contrario no se sincronizarían los fragmentos de archivos.
Una de las dificultades que tendrá inmediatamente es que el objeto Blob en Javasacript no admite el cambio o la configuración del nombre del archivo, por lo que no puede darle al archivo un identificador único de esa manera. Lo que hice, como un simple trabajo alrededor, fue lo siguiente:
var i = 1;
while( start < SIZE ) {
var chunk = blob.webkitSlice(start, end);
uploadFile(chunk, i);
i++;
start = end;
end = start + BYTES_PER_CHUNK;
}
function uploadFile(blobFile, part) {
....
xhr.open("POST", "test.php?num=" + part);
....
}
Como probablemente pueda adivinar en el lado del servidor, en ese momento, uso esa variable GET para asignar un identificador, y la uso como base para cualquier otro procesamiento que deba realizarse en el servidor.
De todos modos, esto no aborda directamente el problema del aumento del tamaño del archivo, por lo que solo espero que esto le ayude; Tengo curiosidad por ver qué más descubres!
La función Slice acepta el segundo parámetro como longitud. Donde como mozSlice acepta segundo parámetro como final
Según la documentación de PHP, fread toma la longitud en bytes, no en bits. ¿Intentaste con 1000000 en lugar de 1048576?
Respuesta actualizada
En chrome ==> Slice Function acepta el segundo parámetro como longitud.
En FF ==> Slice Function acepta el segundo parámetro como final.
muestras de código
fileorblob.slice(startingPosition, length) //for chrome
fileorblob.slice(startingPosition, end)//for FF
webkitslice and mozslice
están en desuso, en su lugar usa "slice()"
nativo.
BlobBuilder
también desaprobó el uso de Blob constructor
.
Recursos:
http://updates.html5rocks.com/2012/06/Don-t-Build-Blobs-Construct-Them