FriendsOfCake / cakephp-upload

CakePHP: Handle file uploading sans ridiculous automagic
https://cakephp-upload.readthedocs.io/
MIT License
551 stars 255 forks source link

Uploading multiple files. Error Invalid data type, must be an array or \ArrayAccess instance. #496

Closed VazLang closed 5 years ago

VazLang commented 5 years ago

Hello everyone i just started out using cakephp and php in general. First thank you Jose Gonzalez for the Plugin it really did help me a lot, while figuring out how to upload pictures.

Multiple file upload works for me when only choosing two pictures, once i extend that to 3 or 4 i get this error message: Invalid data type, must be an array or \ArrayAccess instance.

Here is the part of the Table I am working on. Thanks in advance for your help.

 public function initialize(array $config)
    {
        $this->setPrimaryKey('id');
        $this->belongsToMany('Tags');
        $this->addBehavior('Timestamp');

        $this->addBehavior('Josegonzalez/Upload.Upload', [
            //works with two
            'photolg',
            //stops working with 3rd and 4th
            //'photomd',
            //'photosm',
            'photo' => [
                'fields' => [
                    'dir' => 'photo_dir',
                ],
                'nameCallback' => function ($table, $entity, $data, $field, $settings) {
                    return strtolower($data['name']);
                },
                'transformer' =>  function ($table, $entity, $data, $field, $settings) {
                    $extension = pathinfo($data['name'], PATHINFO_EXTENSION);

                    // Store the thumbnail in a temporary file
                    $tmp = tempnam(sys_get_temp_dir(), 'upload') . '.' . $extension;

                    // Use the Imagine library to DO THE THING
                    $size = new \Imagine\Image\Box(100, 100);
                    $mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
                    $imagine = new \Imagine\Gd\Imagine();

                    // Save that modified file to our temp file
                    $imagine->open($data['tmp_name'])
                        ->thumbnail($size, $mode)
                        ->save($tmp);

                    // Now return the original *and* the thumbnail
                    return [
                        $data['tmp_name'] => $data['name'],
                        $tmp => 'thumbnail-' . $data['name'],
                    ];
                },
                'deleteCallback' => function ($path, $entity, $field, $settings) {
                    // When deleting the entity, both the original and the thumbnail will be removed
                    // when keepFilesOnDelete is set to false
                    return [
                        $path . $entity->{$field},
                        $path . 'thumbnail-' . $entity->{$field}
                    ];
                },
                'keepFilesOnDelete' => false
            ]
        ]);
    }
raul338 commented 5 years ago

That error may happen when the post size / file size is larger than configured. You may have to tweak your php ini

post_max_size=20M
upload_max_filesize=20M
VazLang commented 5 years ago

Thanks for the suggestion. But it did not work even with those changes. I changed php.ini to post_max_size=20M upload_max_filesize=20M And even though the total upload size is 500kb i still get an error message.

davidyell commented 5 years ago

There are few things which I'd like to see for this issue.

  1. What is the exact error message you get. It should include a file and line number. As this might be due to a callback you have. Invalid data type sounds to me like a PHP 7 type error.
  2. Can you show us the php you are using to generate your form. As it might be the way you are sending your request data which is why you can't implement more than 2 uploads
VazLang commented 5 years ago

@davidyell Thank you for the Reply. Here is the Error massage I receive. bildschirmfoto 2018-10-18 um 10 54 48

And here is the Form i create with the upload buttons.

<div class="container">
    <?= $this->Form->create($article, ['type' => 'file']); ?>
        <?php echo $this->Form->control('user_id', ['type' => 'hidden']); ?>

        <fieldset>
            <legend>Edit Article</legend>

            <div class="form-group">
                <?= $this->Form->control(('title'), ['class'=> 'form-control']) ?>
            </div>

            <div class="form-group">
                <?= $this->Form->control(('body'), ['class'=> 'form-control']) ?>
            </div>

            <div class="form-group">
                <?= $this->Form->control(('tag_string'), ['class'=> 'form-control']) ?>
            </div>

            <div class="form-group">
                <?= $this->Form->input('photo', ['type'=>'file']); ?>
            </div>

            <!--Not Possible to add Picture 3 and 4-->
            <div class="form-group">
                <?= $this->Form->input('photosm', ['type'=>'file']); ?>
            </div>

            <div class="form-group">
                <?= $this->Form->input('photomd', ['type'=>'file']); ?>
            </div>

            <!-- Possible to add 2. Picture-->
            <div class="form-group">
                <?= $this->Form->input('photolg', ['type'=>'file']); ?>
            </div>

            <!--<div class="form-group">
                <label for="exampleInputFile">File input</label>
                <input type="file" class="form-control-file" id="exampleInputFile" aria-describedby="fileHelp">
                <small id="fileHelp" class="form-text text-muted">Choose the pictures you want to upload.</small>
            </div>-->

            <?= $this->Form->button(__('Save Article'), ['class'=> 'btn btn-primary']) ?>
        </fieldset>
    <?= $this->Form->end() ?>
</div>
davidyell commented 5 years ago

So I think the problem is that your upload fields have no configuration.

'photolg',

This is essentially 0 => 'photolg' which means you're passing a string of photolog whereas the behaviour is expecting must be an array or \ArrayAccess instance.

So I believe the solution is to include the configuration for each upload field. So that the field is a string and the settings is an array.

VazLang commented 5 years ago

@davidyell You are a magician, it now works like a charm. Thank you so much. The Table now looks like this:

```

public function initialize(array $config) { $this->setPrimaryKey('id'); $this->belongsToMany('Tags'); $this->addBehavior('Timestamp');

    $this->addBehavior('Josegonzalez/Upload.Upload', [

        'photolg'=> [
            'fields' => [
                'dir' => 'photolg_dir',
            ],
            'nameCallback' => function ($table, $entity, $data, $field, $settings) {
                return strtolower($data['name']);
            },
            'transformer' =>  function ($table, $entity, $data, $field, $settings) {
                $extension = pathinfo($data['name'], PATHINFO_EXTENSION);

                // Store the thumbnail in a temporary file
                $tmp = tempnam(sys_get_temp_dir(), 'upload') . '.' . $extension;

                // Use the Imagine library to DO THE THING
                $size = new \Imagine\Image\Box(100, 100);
                $mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
                $imagine = new \Imagine\Gd\Imagine();

                // Save that modified file to our temp file
                $imagine->open($data['tmp_name'])
                    ->thumbnail($size, $mode)
                    ->save($tmp);

                // Now return the original *and* the thumbnail
                return [
                    $data['tmp_name'] => $data['name'],
                    $tmp => 'thumbnail-' . $data['name'],
                ];
            },
            'deleteCallback' => function ($path, $entity, $field, $settings) {
                // When deleting the entity, both the original and the thumbnail will be removed
                // when keepFilesOnDelete is set to false
                return [
                    $path . $entity->{$field},
                    $path . 'thumbnail-' . $entity->{$field}
                ];
            },
            'keepFilesOnDelete' => false
        ],

        'photomd'=> [
            'fields' => [
                'dir' => 'photomd_dir',
            ],
            'nameCallback' => function ($table, $entity, $data, $field, $settings) {
                return strtolower($data['name']);
            },
            'transformer' =>  function ($table, $entity, $data, $field, $settings) {
                $extension = pathinfo($data['name'], PATHINFO_EXTENSION);

                // Store the thumbnail in a temporary file
                $tmp = tempnam(sys_get_temp_dir(), 'upload') . '.' . $extension;

                // Use the Imagine library to DO THE THING
                $size = new \Imagine\Image\Box(100, 100);
                $mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
                $imagine = new \Imagine\Gd\Imagine();

                // Save that modified file to our temp file
                $imagine->open($data['tmp_name'])
                    ->thumbnail($size, $mode)
                    ->save($tmp);

                // Now return the original *and* the thumbnail
                return [
                    $data['tmp_name'] => $data['name'],
                    $tmp => 'thumbnail-' . $data['name'],
                ];
            },
            'deleteCallback' => function ($path, $entity, $field, $settings) {
                // When deleting the entity, both the original and the thumbnail will be removed
                // when keepFilesOnDelete is set to false
                return [
                    $path . $entity->{$field},
                    $path . 'thumbnail-' . $entity->{$field}
                ];
            },
            'keepFilesOnDelete' => false
        ],

        'photosm'=> [
            'fields' => [
                'dir' => 'photosm_dir',
            ],
            'nameCallback' => function ($table, $entity, $data, $field, $settings) {
                return strtolower($data['name']);
            },
            'transformer' =>  function ($table, $entity, $data, $field, $settings) {
                $extension = pathinfo($data['name'], PATHINFO_EXTENSION);

                // Store the thumbnail in a temporary file
                $tmp = tempnam(sys_get_temp_dir(), 'upload') . '.' . $extension;

                // Use the Imagine library to DO THE THING
                $size = new \Imagine\Image\Box(100, 100);
                $mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
                $imagine = new \Imagine\Gd\Imagine();

                // Save that modified file to our temp file
                $imagine->open($data['tmp_name'])
                    ->thumbnail($size, $mode)
                    ->save($tmp);

                // Now return the original *and* the thumbnail
                return [
                    $data['tmp_name'] => $data['name'],
                    $tmp => 'thumbnail-' . $data['name'],
                ];
            },
            'deleteCallback' => function ($path, $entity, $field, $settings) {
                // When deleting the entity, both the original and the thumbnail will be removed
                // when keepFilesOnDelete is set to false
                return [
                    $path . $entity->{$field},
                    $path . 'thumbnail-' . $entity->{$field}
                ];
            },
            'keepFilesOnDelete' => false
        ],

        'photo' => [
            'fields' => [
                'dir' => 'photo_dir',
            ],
            'nameCallback' => function ($table, $entity, $data, $field, $settings) {
                return strtolower($data['name']);
            },
            'transformer' =>  function ($table, $entity, $data, $field, $settings) {
                $extension = pathinfo($data['name'], PATHINFO_EXTENSION);

                // Store the thumbnail in a temporary file
                $tmp = tempnam(sys_get_temp_dir(), 'upload') . '.' . $extension;

                // Use the Imagine library to DO THE THING
                $size = new \Imagine\Image\Box(100, 100);
                $mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
                $imagine = new \Imagine\Gd\Imagine();

                // Save that modified file to our temp file
                $imagine->open($data['tmp_name'])
                    ->thumbnail($size, $mode)
                    ->save($tmp);

                // Now return the original *and* the thumbnail
                return [
                    $data['tmp_name'] => $data['name'],
                    $tmp => 'thumbnail-' . $data['name'],
                ];
            },
            'deleteCallback' => function ($path, $entity, $field, $settings) {
                // When deleting the entity, both the original and the thumbnail will be removed
                // when keepFilesOnDelete is set to false
                return [
                    $path . $entity->{$field},
                    $path . 'thumbnail-' . $entity->{$field}
                ];
            },
            'keepFilesOnDelete' => false
        ]
    ]);
}
davidyell commented 5 years ago

Glad you've got it sorted 👍