0

I'm using AngularJS v1.6.1, Apache 2.4.10 on Debian with PHP 5.6.24 and I'm trying to upload a file to my server using $http POST service. On my php.ini, max file size is set to 8Mo, max post size too, upload file is on, and memory size limit is set to 128Mo.

Form:

<input type="file" accept="application/pdf" id="uploadOT" max-files="1" ng-model="uploadOT" name="uploadOT" valid-file required ng-class="{'md-input-invalid':uploadForm.uploadOT.$error.validFile}" />

Angular directive: (when input content change, get a FileReader object and send file)

myModule.directive('validFile', function() {
    return {
        require:    'ngModel',
        link:       function(scope, elt, attrs, ctrl) {
            ctrl.$setValidity('validFile', elt.val() !== '');
            elt.bind('change', function() {

                var file = document.getElementById('uploadOT').files;
                var reader = new FileReader();
                reader.onload = function(e) {
                    scope.sendFile(reader, scope.id);
                };
                scope.showUploadProgress = true;
                scope.filename = file[0].name;
                reader.readAsBinaryString(file[0]);

                ctrl.$setValidity('validFile', elt.val() !== '');
                scope.$apply(function() {
                    ctrl.$setViewValue(elt.val());
                    ctrl.$render();
                });
            });
        }
    };
});

Inside controller:

$scope.sendFile = function(reader, id) {
    var fd = new FormData();
    fd.append('id', id);
    fd.append('file', reader.result);
    fd.append('MAX_FILE_SIZE', 8 * 1024 * 1024);
    $http.post('api/upload.php', fd, {
        headers:            {'Content-Type' : undefined },
        transformRequest:   angular.identity
    }).then(function() {
        alert('upload success');
    }, function() {
        $scope.showUploadError = true;
        $scope.showUploadProgress = false;
        $scope.postError = 'Une erreur inconnue est survenue !';
    });
};

On server side (file api/upload.php), I print variables $_POST and $_FILES with print_r().

Why is $_FILES always empty, and my file data is in $_POST['file']?

I can create file from $_POST['file'] data with php function file_put_contents() but I cannot make verifications that I can make with $_FILES. Is it really important (security issues)?

If I change my POST Content-Type to multipart/form-data, the same thing happend.

2
  • check the answer in this post: stackoverflow.com/questions/20487212/… Commented Jan 25, 2017 at 15:28
  • @num8er: I'm not using 'ng-file-upload' and cannot use it. Commented Jan 25, 2017 at 15:31

3 Answers 3

0

I presume it's because you forgot to specify the encoding type of your form element.

enctype="multipart/form-data"

So, by default - the browser will assume that the form encoding type is "application/x-www-form-urlencoded" which does not support files in this way. You can still securely send file binary data with the stock encoding method however, this might be where performance and functionality are determining factors to which you choose. I recommend running some tests to confirm which is the fastest. In some cases, the difference will be negligible and will likely be for sake of consistency.

Sign up to request clarification or add additional context in comments.

7 Comments

When I show my headers, the request is with Content-Type multipart/form-data, and the data of the request encoded properly... not application/x-www-form-urlencoded...
Try adding it, and also add method="post" to the element as well. Then vardump $_FILES. Edit: Also, check your php ini to ensure that "file_uploads" is on.
What about "file_uploads" option in your ini?
As I said in my question, file_uploads is 'On'
Ah yes, sorry. Can you show me the entire post form (or at least the inputs)?
|
0

Skip the FileReader API and use the file object directly:

<input type=file files-input ng-model="files" ng-change="upload()" />

The filesInput Directive

angular.module("myApp").directive("filesInput", function() {
  return {
    require: 'ngModel',
    link: function linkFn (scope, elem, attrs, ngModel) {
      elem.on("change", function (e) {
        ngModel.$setViewValue(elem[0].files, "change");
      });
    },
  };
});

The upload() function

 vm.upload = function() {

    //var formData = new $window.FormData();
    //formData.append("file-0", vm.files[0]);

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

    $http.post(url, vm.files[0], config)
    .then(function(response) {
      vm.result = "SUCCESS";
    }).catch(function(response) {
      vm.result = "ERROR "+response.status;
    });
  };

The XHR API send() method can post either a file object or a FormData object. It is more efficient to send the file object directly as the XHR API uses base64 encoding for the FormData object which has a 33% overhead.

The DEMO on PLNKR.

1 Comment

Can you tell me where your variable vm come from? And what if I have other values to send, I suppose that I have to use FormData?
0

To make it works, I had to do these modifications:

Directive:

myModule.directive('validFile', function() {
    return {
        require:    'ngModel',
        link:       function(scope, elt, attrs, ctrl) {
            ctrl.$setValidity('validFile', elt.val() !== '');
            elt.bind('change', function() {

                var file = document.getElementById('uploadOT').files;
                var reader = new FileReader();
                reader.onload = function(e) {
                    scope.sendFile(file[0], scope.OT);  ////CHANGE HERE
                };
                scope.showUploadProgress = true;
                scope.filename = file[0].name;
                reader.readAsArrayBuffer(file[0]);      ////CHANGE HERE

                ctrl.$setValidity('validFile', elt.val() !== '');
                scope.$apply(function() {
                    ctrl.$setViewValue(elt.val());
                    ctrl.$render();
                });
            });
        }
    };
});

Inside Controller

$scope.sendFile = function(file, id) {
        var fd = new FormData();
        fd.append('id', id);
        fd.append('file', file);
        fd.append('MAX_FILE_SIZE', 8 * 1024 * 1024);
        $http({
            method: 'POST',
            url: 'upload.php',
            data: fd,
            headers: {'Content-Type': undefined, 'Process-Data': false},
            transformRequest: angular.identity
        }).then( function() {
            console.log('success');
        }, function() {
            console.log('failure');
        });
    };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.