1.3.1.3. fejezet, File API (FileReader) - file feltöltés részletekben
Beküldte pzoli - 2015, január 10 - 11:28de
Az AJAX push művelettel nagy méretű fájlokat részletekben tölthetünk fel. A böngésző cache túl kicsi egy 100 MiB-es fájl feltöltéséhez a FileReader-el. Emellett félbeszakítható vagy felfüggeszthető a feltöltés.
<!DOCTYPE html> <html lang="hu-HU"> <head> <meta charset="utf-8"> <script src="jquery-2.1.3.js"></script> <style> #progress_bar { margin: 10px 0; padding: 3px; border: 1px solid #000; font-size: 14px; clear: both; opacity: 0; -moz-transition: opacity 1s linear; -o-transition: opacity 1s linear; -webkit-transition: opacity 1s linear; } #progress_bar.loading { opacity: 1.0; } #progress_bar .percent { background-color: #99ccff; height: auto; width: 0; } </style> </head> <body> <input type="file" id="files" name="file" /> <button onclick="abortRead();">Cancel read</button><br/> <button id="commandPost" onclick="savePart(0,'myfile','base64','content');">Post</button> <div id="progress_bar"><div class="percent">0%</div></div> <script> var reader; var progress = document.querySelector('.percent'); var buffsize = 2*1024*1024; var filename; var filetype; function abortRead() { reader.abort(); } function errorHandler(evt) { switch(evt.target.error.code) { case evt.target.error.NOT_FOUND_ERR: alert('File Not Found!'); break; case evt.target.error.NOT_READABLE_ERR: alert('File is not readable'); break; case evt.target.error.ABORT_ERR: break; // noop default: alert('An error occurred reading this file.'); }; } function updateProgress(evt) { // evt is an ProgressEvent. if (evt.lengthComputable) { var percentLoaded = Math.round((evt.loaded / evt.total) * 100); // Increase the progress bar length. if (percentLoaded < 100) { progress.style.width = percentLoaded + '%'; progress.textContent = percentLoaded + '%'; } } } function _arrayBufferToBase64( buffer ) { var binary = ''; var bytes = new Uint8Array( buffer ); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode( bytes[ i ] ); } return window.btoa( binary ); } function savePart(partid,fname,ftype,sliceData) { console.log("partid:"+partid); console.log("filename:"+fname); var base64String = _arrayBufferToBase64(sliceData); $.ajax({ url: "/pushfile.php/", type: "post", async: false, dataType: "text", cache: false, data: { 'contentType' : ftype, 'partno' : partid, 'fname' : fname, 'slice' : base64String }, success: function(data, status) { }, error: function(xhr, desc, err) { console.log(xhr); console.log("Details: " + desc + "\nError:" + err); } }); } function handleFileSelect(evt) { // Reset progress indicator on new file selection. progress.style.width = '0%'; progress.textContent = '0%'; filename = evt.target.files[0].name; filetype = evt.target.files[0].type; var fsize = evt.target.files[0].size; var start = 0; var end = (start + buffsize < fsize ? buffsize : fsize); reader = new FileReader(); reader.onerror = errorHandler; reader.onprogress = updateProgress; reader.onabort = function(e) { alert('File read cancelled'); }; reader.onloadstart = function(e) { document.getElementById('progress_bar').className = 'loading'; }; reader.onload = function(e) { //setTimeout("savePart("+e.target.partno+",'"+filename+"','"+filetype+"','"+e.target.result+"')", 500); savePart(e.target.partno,filename,filetype,e.target.result); }; reader.onloadend = function(e) { if ((start<end) && (end<fsize)) { start = end; end = start + buffsize < fsize ? start + buffsize : fsize; this.partno += 1; reader.readAsArrayBuffer(evt.target.files[0].slice(start,end)); } else { progress.style.width = '100%'; progress.textContent = '100%'; setTimeout("document.getElementById('progress_bar').className='';", 2000); } }; reader.partno = 0; reader.readAsArrayBuffer(evt.target.files[0].slice(start,end)); } document.getElementById('files').addEventListener('change', handleFileSelect, false); </script>
Figyeljünk a buffer méretre, ne legyen nagyobb, mint a szerver által megengedett maximális POST mérete (php.ini - post_max_size). Ha mégis nagyobb buffer méretet alkalmazunk, a php $_POST változóba nem kerül adat (JQuery, php, $_POST, empty), így nincs mit feldolgoznia, leáll a cgi. Ilyenkor az error logban pl. ezt olvashatjuk:
PHP Warning: Unknown: POST Content-Length of 14734420 bytes exceeds the limit of 8388608 bytes in Unknown on line 0
<?php
$fname = mb_convert_encoding($_POST["fname"],"ISO-8859-2","UTF-8");
$partno = $_POST["partno"];
$f = fopen("c:\\temp\\parts\\$fname",($partno == 0 ? "w" :"a"));
fwrite($f, base64_decode($_POST["slice"]));
fclose($f);
?>
Persze a részeket össze kell fűzni, de hogyan, ez már nem a File API leírás része. Jelen kódban a partno változótól függ a file létrehozás, vagy hozzáfűzés.
<?php
$f = fopen("c:\\temp\\parts\\$fname",($partno == 0 ? "w" :"a"));
?>
Hivatkozás az eredeti leírásra: itt
- A hozzászóláshoz be kell jelentkezni