2

I have a JavaScript function which reads an excel file and return me an object ArrayBuffer in document.getElementById("content").value:

  <script type = "text/javascript">
        function readFile(files){
            console.log("DEntro de readFile");
            var reader = new FileReader();
            reader.readAsArrayBuffer(files[0]);
            reader.onload = function(event){
                var arrayBuffer = event.target.result;
                array = new Uint8Array(arrayBuffer);
                binaryString = String.fromCharCode.apply(null, array);
                document.getElementById("fileContent").value = event.target.result;     
            }
        }
  </script>

So, I would like to know, how can I send this object ArrayBuffer to the server and in the server save this ArrayBuffer in an excel file generating the original Excel.

What can I do?

EDIT I: I think I'm doing something wrong, because I create the file, but with strange characters and with only 31 bytes.

JavaScript:

    function readFile(files){
        var reader = new FileReader();
        reader.readAsArrayBuffer(files[0]);
        reader.onload = function(event){
            document.getElementById("fileContent").value = event.target.result;     
        }

    }

Angular JS With this function I send data to the server in a JSON:

 self.uploadFile = function(){
     var data = {
        file    :   document.getElementById("fileContent").value,
     };
     publicDataServices.sendData("http://gnsys.local/publico/test/up", data).then(function(response){
         switch(parseInt(response.result)){
             case 0:
                 console.log("OK!!!");
                 break;
             case 3:    //Error de Sistemas
                 console.log("testControllers.js::uploadFile: Error de sistemas");
                 break;                              
         }
     });
 }

PHP:

    $params = json_decode(file_get_contents('php://input'),true);
    $property = new PropertyReader();
    $fileRoute = $property->getProperty("scripts.ruta.querys");
    $fileName = $fileRoute . "prueba.xls";

    $input = fopen('php://input', 'rb');
    $file = fopen($fileName, 'wb');

    stream_copy_to_stream($input, $file);
    fclose($input);
    fclose($file);

Edit II (it works!):

Angular JS:

 self.uploadFile = function(){
     publicDataServices.sendData("http://gnsys.local/publico/test/up", document.getElementById("file").files[0]).then(function(response){
         switch(parseInt(response.result)){
             case 0:
                 console.log("OK!!!");
                 break;
             case 3:    //Error de Sistemas
                 console.log("testControllers.js::uploadFile: Error de sistemas");
                 break;                              
         }
     });
 }

PHP:

    $property = new PropertyReader();
    $fileRoute = $property->getProperty("scripts.ruta.querys");
    $fileName = $fileRoute . "prueba.xls";

    $input = fopen('php://input', 'rb');
    $file = fopen($fileName, 'wb');

file_get_contents and file_put_contents
        stream_copy_to_stream($input, $file);
        fclose($input);
        fclose($file);

I just only to know how to get the original file name.

Edit III (sending file name): Angular js:

 self.uploadFile = function(){ 
        var promise = $q.defer();
        var headers = {
            "file-name" :   document.getElementById("file").files[0].name
        }
        $http.post("http://gnsys.local/publico/test/up", document.getElementById("file").files[0], {headers:headers})
        .success(function(response, status, headers, config){
            promise.resolve(response);
            console.log("resultado: " + response.result);
        })
        .error(function(data){
            //Error de sistemas
            console.log("Error en sendData: " + data)
        })

        return promise.promise;      
 }

PHP:

    $property = new PropertyReader();
    $fileRoute = $property->getProperty("scripts.ruta.querys");
    $fileName = $fileRoute . "prueba.xls";
    //With this foreach we get all the headers so I can detect which i the right header to get the file name
    foreach (getallheaders() as $name => $value) {
        $log->writeLog(get_class($this) . "::" . __FUNCTION__ . ": name: " . $name . " value: " . $value);
    }

    $input = fopen('php://input', 'rb');
    $file = fopen($fileName, 'wb');

    stream_copy_to_stream($input, $file);
    fclose($input);
    fclose($file);

It works perfectly!

halfer
  • 19,824
  • 17
  • 99
  • 186
José Carlos
  • 2,850
  • 12
  • 59
  • 95
  • 1
    What is purpose of `String.fromCharCode()` call if requirement is to send `ArrayBuffer` to server? See http://stackoverflow.com/questions/37491759/trying-to-pass-todataurl-with-over-524288-bytes-using-input-type-text/37491895#37491895 – guest271314 Feb 21 '17 at 21:22
  • Maybe is not necessary String.fromCharCode(). I'l try to delete that code. Thanks!!! – José Carlos Feb 21 '17 at 21:35
  • 1
    Send `.files[0]` property of `` element to server. `.value` is a string, `C:\\fakepath`. Why do you call `json_decode` at `php`? `publicDataServices.sendData("http://gnsys.local/publico/test/up", document.getElementById("fileContent").files[0])`, at `php` remove first line. – guest271314 Feb 21 '17 at 21:50
  • 1
    `FileReader` is not necessary. `input.onchange = function() { publicDataServices.sendData("http://gnsys.local/publico/test/up", document.getElementById("fileContent").files[0]) }`. Though have not tried `angugularjs`, not sure how the library handles sending `Blob` to server. You could alternatively use `XMLHttpRequest()` or `fetch()` to send `File` object to server. `request.send(document.getElementById("fileContent").files[0])`, or `fetch("path/to/server", {method:"POST", body:document.getElementById("fileContent").files[0]})` – guest271314 Feb 21 '17 at 21:59
  • It works!!! It works!!! I think I'm gonna cry!!! Thank you so much!!! But I've got another question. I need to send the name or get in the server the name of the file. How can I do that? – José Carlos Feb 21 '17 at 21:59
  • You could set the file name at a user defined header, then parse the header at `php`. – guest271314 Feb 21 '17 at 22:01
  • 1
    http://stackoverflow.com/questions/541430/how-do-i-read-any-request-header-in-php, http://stackoverflow.com/questions/2902621/fetching-custom-authorization-header-from-incoming-php-request – guest271314 Feb 21 '17 at 22:08
  • Possible duplicate of [How to correctly attach file to formData before POSTing to server?](http://stackoverflow.com/questions/42031959/how-to-correctly-attach-file-to-formdata-before-posting-to-server) – georgeawg Feb 22 '17 at 00:33

2 Answers2

1

It is not necessary to convert File object to ArrayBuffer. You can POST File object to server and utilize fopen(), "php://input", file_get_contents() at php, see Trying to Pass ToDataURL with over 524288 bytes Using Input Type Text

Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
0

When sending a file blob using the AngularJS $http service, it is important to set the content type header to the primitive value undefined.

var config = { headers: { 'Content-Type': undefined } };

$http.post(url, file[0], config).then(function(response) {
    var data = response.data;
    var status = response.status;
    console.log("status: ", status);
});

Normally the $http service sets the content type header to application/json. By setting the content type header to undefined, the XHR Send Method will set the header to the appropriate value.

georgeawg
  • 48,608
  • 13
  • 72
  • 95