I try to validate file, befor upload, but I doing something wrong.
This is my file in form type:
->add('file', 'file', array(
'constraints' => [
new File([
'maxSize' => '5M',
'mimeTypes' => [
'image/*'
],
'mimeTypesMessage' => 'Only images allowed!'
])
],
'multiple' => 'multiple',
'data_class' => null,
'required' => false,
'mapped' => false,
'attr' => array(
'maxSize' => '1024k',
'accept' => 'image/*',
)
))
If I select .txt, .php, ... to upload, so it's normally uploaded, without errors.
How to make it work?
Thanks
EDIT:
My Upload Function:
private function uploadImg($files)
{
$path = array();
foreach ($files as $file) {
$extension = $file->guessExtension();
if (!$extension) {
$extension = 'bin';
}
$randomName = 'image' . date('Y-m-d-H-i-s') . uniqid() . '.' . $extension;
$file->move('uploads/images/', $randomName);
$path[] = $randomName;
}
return $path;
}
and in controller:
$ads->setPath(implode(',', $this->uploadImg($form['file']->getData())));
Related
I'm working on this project and at first it has a single file upload that works perfectly fine, but had to change to multiple file upload and now I just can't make it work!
Getting an "Headers aready sent" error:
Deprecated (16384): Accessing `here` as a property will be removed in 4.0.0. Use request->getAttribute("here") instead. - /home1/thecyb80/seibo.the-cyberpunk.com/src/Controller/AppController.php, line: 92
You can disable deprecation warnings by setting `Error.errorLevel` to `E_ALL & ~E_USER_DEPRECATED` in your config/app.php. [CORE/src/Core/functions.php, line 311]
Warning (512): Unable to emit headers. Headers sent in file=/home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php line=856 [CORE/src/Http/ResponseEmitter.php, line 51]
Warning (2): Cannot modify header information - headers already sent by (output started at /home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php:856) [CORE/src/Http/ResponseEmitter.php, line 152]
Warning (2): Cannot modify header information - headers already sent by (output started at /home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php:856) [CORE/src/Http/ResponseEmitter.php, line 185]
Warning (2): Cannot modify header information - headers already sent by (output started at /home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php:856) [CORE/src/Http/ResponseEmitter.php, line 185]
Here's my code: add.ctp
<?= $this->Form->create($atividade, ['type' => 'file']) ?>
[...]
<div class="form-group m-0">
<label class="btn btn-light p-3 rounded border d-flex align-items-center justify-content-center flex-column" style="cursor: pointer; min-height: 350px;">
<strong class="d-block">Selecione o(s) arquivo(s) da atividade. Você pode enviar até 10 arquivos.</strong>
<span class="exercicio-nome d-flex aling-items-center justify-content-center w-100 mt-3"></span>
<?= $this->Form->file('arquivos[]', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
</label>
</div>
Validation founded in AtividadesTable.php (that's the only occurrence of the field):
$validator
->scalar('arquivos')
->maxLength('arquivos', 255)
->allowEmptyString('arquivos')
->allowEmptyFile('arquivos');
I've tried several solutions, that I've found over the internet, but none helped me. I'm using CakePHP 3.8.11 over PHP 7.2.31.
Here'se my composer.json modules installed (don't know if it can help):
"require": {
"php": ">=5.6",
"cakephp/cakephp": "3.8.*",
"cakephp/migrations": "^2.0.0",
"cakephp/plugin-installer": "^1.0",
"mobiledetect/mobiledetectlib": "2.*"
}
Since I can't go over this step, I'm assuming that for now, my Controller is irrelevant. What can I do?
Edit: 06/04 (asked by Salines)
Multiple file upload (uploaded 4 files)
Using
<?= $this->Form->file('arquivos[]', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
(Page just refreshs)
Single file upload
Using
<?= $this->Form->file('arquivos[]', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
(Page just refreshs)
Multiple file upload (uploaded 4 files)
Using
<?= $this->Form->file('arquivos', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
/src/Controller/AtividadesController.php (line 159)
[
'nome' => 'Atividade teste',
'status' => '1',
'users' => [
'_ids' => [
(int) 0 => '306'
]
],
'turmas' => [
'_ids' => [
(int) 0 => '17'
]
],
'materias' => [
'_ids' => [
(int) 0 => '45'
]
],
'descricao' => '<p>Teste</p>
',
'comeca_dia' => [
'year' => '2020',
'month' => '06',
'day' => '04'
],
'termina_dia' => [
'year' => '2020',
'month' => '06',
'day' => '04'
],
'video' => '',
'aviso_do_professor' => 'Teste',
'arquivos' => [
'tmp_name' => '/tmp/phpafKkWr',
'error' => (int) 0,
'name' => 'imagem_sobre.png',
'type' => 'image/png',
'size' => (int) 600995
]
]
Multiple file upload (uploaded 4 files)
Using
<?= $this->Form->file('arquivos. ', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
(Page just refreshs)
AtividadesController
I'll show my AtividadesController.php (add method):
/**
* Add method
*
* #return \Cake\Http\Response|null Redirects on successful add, renders view otherwise.
*/
public function add($nivelId = null)
{
$atividade = $this->Atividades->newEntity();
if ($this->request->is('post')) {
// Edit - StackOverflow
debug($this->getRequest()->getData()); exit;
$atividade = $this->Atividades->patchEntity($atividade, $this->request->getData());
die(debug($_FILES));
// Salvando os arquivos
if (!empty($_FILES['arquivos']['name'])) {
$file = $_FILES['arquivos'];
$arquivoName = $file['name'];
$userId = $this->Auth->user('id');
$ext = substr(strtolower(strrchr($arquivoName, '.')), 1);
$arr_ext = array('zip', 'rar', 'pdf', 'doc', 'docx', 'ppt', 'pptx');
if (in_array($ext, $arr_ext)) {
$imgHashed = md5($arquivoName) . time() . '.' . $ext;
$fileDir = WWW_ROOT . 'files/' . $userId;
if (!is_dir($fileDir)) {
mkdir($fileDir);
}
#move_uploaded_file($file['tmp_name'], $fileDir . '/' . $imgHashed);
$atividade['arquivos'] = $imgHashed;
$atividade['arquivo_nome'] = $arquivoName;
} else {
$this->Flash->error(__("Só aceitamos imagens dos tipos 'zip', 'rar', 'pdf', 'doc', 'docx', 'ppt' ou 'pptx'."));
return $this->redirect(['action' => 'add']);
}
}
if ($this->Atividades->save($atividade)) {
$this->Flash->success(__('A atividade foi salva.'));
return $this->redirect(['action' => 'index', $this->Auth->user('id')]);
}
$this->Flash->error(__('A atividade não pode ser salva. Por favor, tente novamente.'));
}
$arquivos = $this->Atividades->Arquivos->find('list');
$materias = $this->Atividades->Materias->find('list');
if ($nivelId) {
$turmas = $this->Atividades->Turmas->find('list')->matching('Nivels', function($q) use ($nivelId) {
return $q
->select()
->where(['Nivels.id' => $nivelId]);
});
} else {
$turmas = $this->Atividades->Turmas->find('list');
}
$users = $this->Atividades->Users->find('list')->where(['tipo' => 'professor']);
$this->set(compact('atividade', 'arquivos', 'materias', 'turmas', 'users'));
}
Am I missing something? Some CakePHP component, maybe? Some PHP extension?
I have written a module with form api which can upload image with dynamic file name. I want to upload that file with auto compression. I cannot understand how will I achieve this. How can I implement this in submit callback.
Below my code:
function MYMODULE_registration_form() {
$form['name'] = array(
'#title'=> t('Name'),
'#type' => 'textfield',
'#required' => TRUE,
'#size' => 40,
'#attributes' => array('placeholder' => t('Enter your name'),),
);
$form['personal_info']['upload_pic'] = array(
'#title' => t('Upload Photo'),
'#type' => 'file',
'#description' => t('Upload a file, allowed extensions: jpg, jpeg, png, gif, bmp'),
);
$form['submit'] = array(
'#value' => t('Submit'),
'#type' => 'submit',
);
$form['#attributes']['enctype'] = 'multipart/form-data';
return $form;
}
function MYMODULE_registration_form_submit($form, $form_state) {
$name = $form_state['values']['name'];
$count = 1;
$original_username = $name;
while (user_load_by_name($name)) {
$name = $original_username . $count++;
}
$validators = array(
'file_validate_extensions' => array('png gif jpg jpeg bmp')
);
$uploadCheck = file_save_upload('upload_pic', $validators);
if($uploadCheck) {
$parts = pathinfo($uploadCheck->filename);
$imagename = str_replace(' ', '_',$original_username.'_'. $count . '.'. $parts['extension']);
$target = "public://attorneys/".$imagename;
file_move($uploadCheck, $target, FILE_EXISTS_REPLACE);
$picture_fid = $uploadCheck->fid;
}
}
After a lot of R&D I have come to this conclusion and it is working fine:
Implement gulp package and install image optimisation plugin.
Take ref from this url : https://www.tutorialspoint.com/gulp/gulp_optimizing_images.htm
my requirement is to upload files to specific folders. How can I achieve this by using form api.
How can I modify below code such that upload_location should be dynamic. Uploaded file should save into the Folder name provided by the user.
#submit element is not calling custom_document_submit function.
$form['folder_name'] = array(
'#type' => 'textfield',
'#title' => t('Folder Name'),
);
$form['document'] = array(
'#type' => 'managed_file',
'#upload_validators' => array('file_validate_extensions' => array('xml')),
'#upload_location' => 'public://',
'#submit' => array('custom_document_submit'),
);
function custom_document_submit($form, &$form_state){
$destination = $form_state['values']['folder_name'];
$validators = array();
$file = file_save_upload('document', $validators, 'public://'.$destination);
}
The #submit property cannot be declare on a managed_file form object...
Instead, you have to add or to modify a submit action on your form (or button).
$form['#submit'][] = 'custom_document_submit';
If you don't want to modify the submit method of your form, you can also simply add a validator (with the #validate property), witch will modify the '#upload_location' property of your document depending on the folder_name value.
Both, #submit and #validate properties have to be added to the form itself.
<?php
define('IMPORT_DIRECTORY_PATH', 'public://import');
$form['folder_name'] = array(
'#type' => 'textfield',
'#title' => t('Folder Name'),
);
form['document'] = array(
'#title' => t('Upload .xml'),
'#type' => 'managed_file',
'#upload_validators' => array(
'file_validate_extensions' => array('xml'),
),
'#process' => array('import_document_element_process'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Upload'),
'#submit' => array('custom_document_submit'),
);
function custom_document_submit($form, &$form_state){
// Validate extensions.
$validators = array(
'file_validate_extensions' => array('xml'),
);
$file = file_save_upload('document', $validators, FALSE, FILE_EXISTS_RENAME);
// If the file passed validation.
if ($file) {
// Rename uploaded file to prevent cache from remembering name file.
$directory = SCHEDULES_IMPORT_DIRECTORY_PATH;
if (file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
$uri = $directory . '/xml_' . $file->uid . '_' . $file->timestamp . '.xml';
if ($file = file_move($file, $uri)) {
$form_state['values']['document'] = $file;
}
else {
form_set_error('document', t('The file could not be uploaded.'));
}
}
else {
form_set_error('document', t('The directory is not writable.'));
}
}
else {
form_set_error('document', t('The file extension is not correct.'));
}
// dpm($form_state['values']['document']);
// var_dump( $form_state['values']['document']);
}
/**
* Removing the upload button in managed files.
*/
function import_document_element_process($element, &$form_state, $form) {
$element = file_managed_file_process($element, $form_state, $form);
$element['upload_button']['#access'] = FALSE;
return $element;
}
I need to create the upload process where the user can upload multiple files at once, using the file field with html5 multiple attr. Name of the file must be saved in the associated model.
I can run successfully upload one file and save the file name in the photos table, across the field:
echo $this->Form->file('photos.name');
But if I want to enable upload more photos with
echo $this->Form->input('title'); // post title
echo $this->Form->input('maintext'); // post main text,
... etc
echo $this->Form->file('photos[].name',['multiple'=>true]);
I get into the problem, and try to understand where I make mistakes, but without success.
PostsController:
public function add()
{
$post = $this->Posts->newEntity();
if ($this->request->is('post')) {
$post = $this->Posts->patchEntity($post, $this->request->data);
if ($this->Posts->save($post)) {
$this->Flash->success(__('The post has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The post could not be saved. Please, try again.'));
}
}
$this->set(compact('post'));
$this->set('_serialize', ['post']);
}
PostsTable:
$this->addBehavior('Upload');
$this->hasMany('Photos', [
'foreignKey' => 'post_id'
]);
UploadBehavior
All standard callbacks where I currently perform debug $data / $entity, but only in beforeMarshal i use:
$data = Hash::get($data,'name');
debug($data);
// debug output
[
'name' => 'HPIM3869.JPG',
'type' => 'image/jpeg',
'tmp_name' => 'C:\xampp\tmp\phpF02D.tmp',
'error' => (int) 0,
'size' => (int) 1295448
],
...
In beforeSave and afterSave
My form is OK, the data properly come in before Marshal method, if I upload 3 files, I also see the same number of debug outputs, but in beforSave and afterSave debug only show the first file like this:
debug($entity);
object(App\Model\Entity\Photos) {
'name' => [
'name' => 'HPIM3435.JPG',
'type' => 'image/jpeg',
'tmp_name' => 'C:\xampp\tmp\php5839.tmp',
'error' => (int) 0,
'size' => (int) 1517410
],
'post_id' => (int) 469,
'created' => object(Cake\I18n\Time) {
'time' => '2015-10-07T09:22:44+0200',
'timezone' => 'Europe/Berlin',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-10-07T09:22:44+0200',
'timezone' => 'Europe/Berlin',
'fixedNowTime' => false
},
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'name' => true,
'post_id' => true,
'created' => true,
'modified' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Photos'
}
Edit:
In the purpose of the test, I create such a form:
echo $this->Form->input('name',['value'=>'zzz']);
echo $this->Form->input('photos.0.name',['value'=>'zzz']);
echo $this->Form->input('photos.1.name',['value'=>'hhh']);
echo $this->Form->input('photos.2.name',['value'=>'fff']);
Also it only be saved the first result.
I need help to understand how to save multiple form data. Where I go wrong?
I think your field should be like this
echo $this->Form->file('photos.name.',['multiple'=>true]); //note dot notation at end of name. It will generate input name as array
I have a cakedc search plugin with cakephp 3.0 working fine, but would like to have more advanced search filters like:
city = 'Los Angeles';
city != 'Los Angeles';
city LIKE '%Angeles%';
city LIKE 'Los%';
city NOT LIKE '%Angeles%';
city NOT LIKE 'Los%';
etc...
So i'm looking to add 2 dropdown select and 1 text input to achieve this.
'city' would be in a dropdown of db fields.
=, !=, like %?%, like %?, not like ?% conditions would be a dropdown
'los angeles' search value would be typed in.
Figured out, might not be perfect but seems to work fine:
View:
<?php echo $this->Form->input('dbfield', ['label' => 'Field', 'options' => ['' => '', 'region' => 'Region', 'city' => 'City', 'keyword' => 'Keyword']]); ?>
<?php echo $this->Form->input('dbconditions', [
'label' => 'Condition',
'options' => [
'' => '',
'contains' => 'contains',
'doesnotcontain' => 'does not contain',
'beginswith' => 'begins with',
'endswith' => 'ends with',
'isequalto' => 'is equal to',
'isnotequalto' => 'is not equal to',
],
]); ?>
<?php echo $this->Form->input('dbvalue', ['label' => 'Value', 'class' => 'form-control input-sm']); ?>
Model
public $filterArgs = [
'dbfield' => [
'type' => 'finder',
'finder' => 'conds0',
],
'dbconditions' => [
'type' => 'finder',
'finder' => 'conds0',
],
'dbvalue' => [
'type' => 'finder',
'finder' => 'conds',
],
];
public function findConds0(Query $query, $options = []) {
}
public function findConds(Query $query, $options = []) {
if($options['data']['dbconditions'] == 'contains') {
$conditions = [
$options['data']['dbfield'] . ' LIKE' => '%' . $options['data']['dbvalue'] . '%',
];
}
if($options['data']['dbconditions'] == 'doesnotcontain') {
$conditions = [
$options['data']['dbfield'] . ' NOT LIKE' => '%' . $options['data']['dbvalue'] . '%',
];
}
if($options['data']['dbconditions'] == 'beginswith') {
$conditions = [
$options['data']['dbfield'] . ' LIKE' => $options['data']['dbvalue'] . '%',
];
}
if($options['data']['dbconditions'] == 'endswith') {
$conditions = [
$options['data']['dbfield'] . ' LIKE' => '%' . $options['data']['dbvalue'],
];
}
if($options['data']['dbconditions'] == 'isequalto') {
$conditions = [
$options['data']['dbfield'] => $options['data']['dbvalue'],
];
}
if($options['data']['dbconditions'] == 'isnotequalto') {
$conditions = [
$options['data']['dbfield'] . ' != ' => $options['data']['dbvalue'],
];
}
return $query->where($conditions);
}
I clean the code, only beacuse look a big code.
In other way, why you include an empty option in the Condition select input? not look better with a default search condition?
Saludos