phpcakephpfile-uploadcakephp-4.x

CAKEPHP 4: I cannot upload many files at the same time


Goodnight (or good morning),

I trying to upload multiple files at the same time. I am following the cookbook instructions to build the solution. I always got first file (not and array of files).

Here is my view code...

<?php
/**
 * @var \App\View\AppView $this
 * @var \App\Model\Entity\Upload $upload
 */
?>
<div class="row">
    <aside class="column">
        <div class="side-nav">
            <h4 class="heading"><?= __('Actions') ?></h4>
            <?= $this->Html->link(__('List Uploads'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
        </div>
    </aside>
    <div class="column-responsive column-80">
        <div class="uploads form content">
            <?= $this->Form->create($upload, ['type' => 'file']) ?>
            <fieldset>
                <legend><?= __('Add Upload') ?></legend>
                <?php
                    echo $this->Form->control('name');
                    echo $this->Form->control('document_type_id', ['options' => $documentTypes]);
                    echo $this->Form->control('period_id', ['options' => $periods]);
                    echo $this->Form->control('user_id', ['options' => $users]);
                    echo $this->Form->control('documents', ['type' => 'file',  'label' => __('Choose PDF Files'), 'accept' => 'application/pdf', 'multiple' => 'multiple']);
                ?>
            </fieldset>
            <?= $this->Form->button(__('Submit')) ?>
            <?= $this->Form->end() ?>
        </div>
    </div>
</div>

And here is my controller code...

public function add()
{
    $upload = $this->Uploads->newEmptyEntity();

    if ($this->request->is('post')) {

        $upload = $this->Uploads->patchEntity($upload, $this->request->getData());

        if ($this->Uploads->save($upload)) {

            if (!is_dir($this->Parameters->findByName('document_directory')->first()->toArray()['value'] )) {
                mkdir($this->Parameters->findByName('document_directory')->first()->toArray()['value'], 0776, true);
            }

            $documents = $this->request->getData('documents');

            $this->loadModel('Dockets');
            $dockets = $this->Dockets->findByDocketStateId(1);

            $documents_ok = 0;
            $documents_nok = 0;
            $dockets_without_document = 0;

            foreach($documents as $documents_key => $document_to_save)
            {
                foreach($dockets as $dockets_key => $docket)
                {
                    $contents = file_get_contents($document_to_save);
                    
                    $pattern = str_replace('-', '', $pattern);

                    $pattern = str_replace('', '', $pattern);

                    $pattern = preg_quote($docket->cuit, '/');

                    $pattern = "/^.*$pattern.*\$/m";
                    // search, and store all matching occurences in $matches
                    if(preg_match_all($pattern, $contents, $matches)){

                        $documentsTable = $this->getTableLocator()->get('Documents');
                        $document = $documentsTable->newEmptyEntity();

                        $document->upload_id = $upload->id;

                        $document->document_type_id = $upload->document_type_id;

                        $document->period_id = $upload->period_id;

                        $document->docket_id = $docket->id;

                        $document->user_id = $this->getRequest()->getAttribute('identity')['id'];
                        
                        if ($documentsTable->save($document)) {

                            if (!is_dir($this->Parameters->findByName('document_directory')->first()->toArray()['value'] )) {
                                mkdir($this->Parameters->findByName('document_directory')->first()->toArray()['value'], 0776, true);
                            }

                            $fileobject = $this->request->getData('document');

                            $destination = $this->Parameters->findByName('document_directory')->first()->toArray()['value']  . 'document_' . $document->id . '.pdf';

                            // Existing files with the same name will be replaced.
                            $fileobject->moveTo($destination);
                        }
                        $this->Flash->error(__('The document could not be saved. Please, try again.'));

                        $documents_ok = $documents_ok + 1;

                        unset($dockets[$dockets_key]);

                        unset($documents[$documents_key]);

                        break;
                    }
                }
            }

            if(!empty($documents)){

                //print_r($documents);

                $documents_nok = count($documents);

                unset($documents);
            }

            if(!empty($dockets)){

                $dockets_without_document = count($dockets);

                unset($dockets);

            }

            $message = __('There were processed ') . $documents_ok . __(' documents succesfully. ') . $documents_nok . __(' documents did not math with a docket. And ') . $dockets_without_document . __(' active dockets ddid not not have a document.');

            $this->Flash->success(__('The upload has been saved. ') . $message);

            return $this->redirect(['action' => 'view', $upload->id]);
        }
        $this->Flash->error(__('The upload could not be saved. Please, try again.'));
    }
    $documentTypes = $this->Uploads->DocumentTypes->find('list', ['keyField' => 'id',
                                                                  'valueField' => 'document_type',
                                                                  'limit' => 200]);
    $periods = $this->Uploads->Periods->find('list', ['keyField' => 'id',
                                                      'valueField' => 'period',
                                                      'limit' => 200]);
    $users = $this->Uploads->Users->find('list', ['keyField' => 'id',
                                                  'valueField' => 'full_name',
                                                  'conditions' => ['id' => $this->getRequest()->getAttribute('identity')['id']],
                                                  'limit' => 200]);
    $this->set(compact('upload', 'documentTypes', 'periods', 'users'));
}

Can you help me to understand what I doing wrong?

Thanks,

Gonzalo


Solution

  • When using PHP, multi-file form inputs must have a name with [] appended, otherwise PHP isn't able to parse out multiple entries, they will all have the same name, and PHP will simply use the last occurrence of that name.

    echo $this->Form->control('documents', [
        'type' => 'file',
        'label' => __('Choose PDF Files'),
        'accept' => 'application/pdf',
        'multiple' => 'multiple',
        'name' => 'documents[]',
    ]);
    

    Furthermore the following line:

    $fileobject = $this->request->getData('document');
    

    should probably be more like this, as there a) is no document field and b) even if there were, you most likely wouldn't want to process the same file over and over again:

    $fileobject = $documents[$documents_key];
    

    Also make sure that you have proper validation in place for the uploaded files, even if you don't seem to use the user provided file information, you should still make sure that you've received valid data!