In Cakephp 3.6 I cannot upload an image through a form

Hello when I try to upload an image through a form, following the steps of:

Creating File Inputs

getdata() of the form returns empty Why does this happen?

Form:

<?= $this->Form->create($imagene, ['enctype' => 'multipart/form-data', 'novalidate', 'id' => 'addimageform', 'class' => 'form addimageform']); ?>
    <?= $this->Form->control('imagen', ['type' => 'file', 'class' => 'imagen-addimage']); ?>
    <div class="centrar-submit">
      <?= $this->Form->button('Subir imagen', ['id' => 'submit', 'class' => 'submit-addimage']); ?>
      <?= $this->Form->button('Omitir', ['id' => 'omitir', 'class' => 'omitir-addimage', 'redirect' => ['controller' => 'administracion', 'action' => 'index']]); ?>
    </div>
    <?= $this->Form->end(); ?>

Controller:

public function add($table, $idTable) {
      $imagene = $this->Imagenes->newEntity();
      if ($this->request->is('post')) {
        $isData = $this->request->getdata();
        debug($this->request->getdata('imagen')); // <---- Is null
        debug($isData); // <---- Is empty
        ...

use getData() instead of getdata() (note the capitalization of the D)

If you’re right, I just changed it, but the problem persists.

maybe it’ll help if you use debug($this->request) to see what’s in the request object.
If it’s not there, then theres something else going wrong as well.

....
[protected] data => []
[protected] uploadedFiles => [] 
[protected] protocol => null 
[protected] requestTarget => null 
[private] deprecatedProperties => [ 
               'data' => [ 
                               'get' => 'getData()', 
                               'set' => 'withData()' 
                              ],
.....

Hello, in the debug($this->request) I don’t see anywhere that returns the image data.

I only see a few alerts through the headers:

[ Warning (512)](javascript:void(0);): Unable to emit headers. Headers sent in file=/srv/www/cake-arbol/vendor/cakephp/cakephp/src/Error/Debugger.php line=952 [ CORE/src/Http/ResponseEmitter.php , line 48 ]

[ Warning (2)](javascript:void(0);): Cannot modify header information - headers already sent by (output started at /srv/www/cake-arbol/vendor/cakephp/cakephp/src/Error/Debugger.php:952) [ CORE/src/Http/ResponseEmitter.php , line 148 ]

[ Warning (2)](javascript:void(0);): Cannot modify header information - headers already sent by (output started at /srv/www/cake-arbol/vendor/cakephp/cakephp/src/Error/Debugger.php:952) [ CORE/src/Http/ResponseEmitter.php , line 177 ]

Those alerts can be ignored.

After more careful inspection, I see that your form controls have no name attribute.
This means that, as a result, there is no data being sent in the post request.
This can be confirmed by opening the network inspector in your browser (often done by hitting CRTL + SHIFT + J and then clicking on network).
Then submit your form like you normally would.
Find your request (most often it’s the top-most when sending a POST request) and click it.
Then check the parameters (or something like it) to see what is being send.
If it’s empty, then I was right for sure.
Else, just keep in mind this trick for later, it’s really helpful to debug similar issues later down the road!

To fix it, something like this should do the trick:

<?= $this->Form->control('imagen', ['name' => 'imagen', 'type' => 'file', 'class' => 'imagen-addimage']); ?>

for simple upload image, install plugin from

https://packagist.org/josegonzalez/cakephp-upload

then installed via composer

composer require josegonzalez/cakephp-upload

then you can read full documentation in

http://josediazgonzalez.com/2015/12/05/uploading-files-and-images/

include tutorial online storage services
-Amazon Web Service
-Windows Azure
-DropBox

Hello I had already tried to put name before, also $this->Form->control() already puts by default name:

Captura

Have you tried using the network inspector?

Yes, but it doesn’t return any parameters, can the problem be ajax? But the inspector console does not return any error.

Ajax file:

if (window.File && window.FileReader && window.FileList && window.Blob) {
	} else {
	        alert('Si esta viendo esto por favor dimelo.');
	}

	$("body").on("change", "#imagen", function(event) {
		var files = event.target.files[0];
		var reader = new FileReader();
		reader.onload = (function(theFile) {
	    	        return function(e) {
		  		$(datos).html('<img class="thumb" src="' + e.target.result + '" title="' + escape(theFile.name) + '"/>');
	    	        };
	   	})(files);
		reader.readAsDataURL(files);
  	 });

	$("body").on("submit", "form", function(event) {
		event.stopPropagation();
	        event.preventDefault();
		var type = "POST";
		var url = $(this, "form").prop("action");
		var cache = false;
		var contentType = 'application/x-www-form-urlencoded';
		var processData = true;

	        if(event.target.files) {
	      	       var data = new FormData(this);
		       contentType = false;
			processData = false;
		}
		else {
		 	var data = $(this).serialize();
		}
		$.ajax({
		url: url,
		data: data,
	        type: type,
		cache: cache,
		contentType: contentType,
	        processData: processData
	})
	.done(function(data) {					
	        $(".section").html(data);
	})
	.fail(function(jqXHR, textStatus, errorThrown) {
		if(jqXHR.status === 0) {
		      alert('Not connect: Verify Network.');
                } else if(jqXHR.status == 404) {
		     alert('Requested page not found [404]');
                } else if(jqXHR.status == 500) {
                     alert('Internal Server Error [500].');
                } else if(textStatus === 'parsererror') {
                    alert('Requested JSON parse failed.');
                } else if(textStatus === 'timeout') {
                   alert('Time out error.');
                } else if(textStatus === 'abort') {
                   alert('Ajax request aborted.');
                } else {
                   alert('Uncaught Error: ' + jqXHR.responseText);
	       }
	})
	.always(function(result) {
	});
  });

Yes, it seems like something is wrong with your data.
By taking a look at your Ajax code you have $("body").on("submit" ... this probably means that the $(this) variable is actually the body tag of the page.

Change it to $("#addimageform") and you should be good.

He does the same thing. But I’ve noticed that it doesn’t get the event.target.files so it doesn’t make a var data = new FormData(this); but if a var data = $(this).serialize(); ignoring the file.

if(event.target.files) {
      	       var data = new FormData(this);
	       contentType = false;
		processData = false;
	}
	else {
	 	var data = $(this).serialize();
	}

After a thousand turns I found the problem:

When he sent the form instead of uploading

/srv/www/cake-arbol/images/edit/178

It changes it to:

/srv/www/cake-arbol/webroot/images/edit/178/index.html

I don’t know why he looks for the view in webroot and puts index.html at the end

Routes:

Router::scope('/imagenes', function($routes) {
   $routes->connect('/index', ['controller' => 'Imagenes', 'action' => 'index']);
   $routes->connect('/view/*', ['controller' => 'Imagenes', 'action' => 'view']);
   $routes->connect('/add/*/*', ['controller' => 'Imagenes', 'action' => 'add']);
   $routes->connect('/edit/*', ['controller' => 'Imagenes', 'action' => 'edit']);
   $routes->connect('/delete/*', ['controller' => 'Imagenes', 'action' => 'delete']);
 });

form:

<?= $this->Form->create($imagene, ['type' => 'post', 'enctype' => 'multipart/form-data']); ?>
<?= $this->Form->Control('imagen', ['type' => 'file']); ?>