Yii2 max_size validation issue - validation

This is my action:
public function actionCustom() {
$model = new Custom();
$model->load(\Yii::$app->request->post());
if ($model->validate()) {
// emptying the model's data
$model = new Custom();
var_dump('good');
} else {
var_dump('bad');
}
var_dump($_FILES);
return $this->render('custom', [
'model' => $model
]);
}
And this is my model:
class Custom extends Model
{
public $file;
public function rules()
{
return [
// ['file', 'file', 'extensions' => ['png', 'jpg', 'jpeg', 'gif', 'txt'], 'maxSize' => 1024 * 100]
['file', 'file', 'maxSize' => 1024 * 100],
];
}
}
When I try to upload a file which size exceeds the maxSize rule I set, the client-side validation displays an error and I can't submit the form by clicking on the button and this is all fine, but I can force submitting by typing something like this in the console like how a hacker would do:
document.forms[0].submit()
And I get this output:
C:\wamp64\www3\controllers\SiteController.php:138:string 'good' (length=4)
C:\wamp64\www3\controllers\SiteController.php:143:
array (size=1)
'Custom' =>
array (size=5)
'name' =>
array (size=1)
'file' => string 'tste.txt' (length=8)
'type' =>
array (size=1)
'file' => string 'text/plain' (length=10)
'tmp_name' =>
array (size=1)
'file' => string 'C:\wamp64\tmp\phpDE60.tmp' (length=25)
'error' =>
array (size=1)
'file' => int 0
'size' =>
array (size=1)
'file' => int 818064
string 'good' means that the file has passed the validation, but how?! The size of the file I sent was 818064 and it is bigger than 102400 (1024 * 100) file size limit which I set.
What am I doing wrong?

Have you tried to use yii\web\UploadedFile::getInstance() method mentioned in the official docs example?
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->imageFile = UploadedFile::getInstance($model, 'imageFile');
if ($model->upload()) {
// file is uploaded successfully
return;
}
}
http://www.yiiframework.com/doc-2.0/guide-input-file-upload.html#wiring-up

Related

Laravel array key validation

I have custom request data:
{
"data": {
"checkThisKeyForExists": [
{
"value": "Array key Validation"
}
]
}
}
And this validation rules:
$rules = [
'data' => ['required','array'],
'data.*' => ['exists:table,id']
];
How I can validate array key using Laravel?
maybe it will helpful for you
$rules = ([
'name' => 'required|string', //your field
'children.*.name' => 'required|string', //your 1st nested field
'children.*.children.*.name => 'required|string' //your 2nd nested field
]);
The right way
This isn't possible in Laravel out of the box, but you can add a new validation rule to validate array keys:
php artisan make:rule KeysIn
The rule should look roughly like the following:
class KeysIn implements Rule
{
public function __construct(protected array $values)
{
}
public function message(): string
{
return ':attribute contains invalid fields';
}
public function passes($attribute, $value): bool
{
// Swap keys with their values in our field list, so we
// get ['foo' => 0, 'bar' => 1] instead of ['foo', 'bar']
$allowedKeys = array_flip($this->values);
// Compare the value's array *keys* with the flipped fields
$unknownKeys = array_diff_key($value, $allowedKeys);
// The validation only passes if there are no unknown keys
return count($unknownKeys) === 0;
}
}
You can use this rule like so:
$rules = [
'data' => ['required','array', new KeysIn(['foo', 'bar'])],
'data.*' => ['exists:table,id']
];
The quick way
If you only need to do this once, you can do it the quick-and-dirty way, too:
$rules = [
'data' => [
'required',
'array',
fn(attribute, $value, $fail) => count(array_diff_key($value, $array_flip([
'foo',
'bar'
]))) > 0 ? $fail("{$attribute} contains invalid fields") : null
],
'data.*' => ['exists:table,id']
];
I think this is what you are looking:
$rules = [
'data.checkThisKeyForExists.value' => ['exists:table,id']
];

How to set file post properly PhpUnit

I'm trying to set a test to upload a file.
In the controller I need to check if everyting is ok (form validation).
The problem is the response gives me an error $request->dataFile->getClientOriginalExtension() , (vendor/symfony/http-foundation/File/UploadedFile.php)
Looks like the dataFile, or request or.... I dont know how to set it.
/**
#test
#group formPostFile
*/
public function formPostFile()
{
$test_file_path = base_path().'/httpdocs/test/Excel.xlsx';
$this->assertTrue(file_exists($test_file_path), $test_file_path.' Test file does not exist');
$_FILE = [
'filename' => [
'name' => $test_file_path,
'type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'size' => 10336,
'tmp_name' => $test_file_path,
'error' => 0
]
];
$data = [
'id' => '2',
'dataFile' => $_FILE
];
$response = $this->post('/excel', $data);
dd($response->getContent());
}
Utilise the Symfony/Illuminate class UploadedFile
$file = new UploadedFile(
$test_file_path,
$test_file_path,
filesize($test_file_path),
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
null,
true
);
LastParameter is testMode and should be true, i believe this will work out in your code, utilise it in a similar fashion as the array you already have like so.
$data = [
'id' => '2',
'dataFile' => $file
];

Set image maximum file size with validator

I am implementing image upload in Yii2 using File Input Widget as shown in http://demos.krajee.com/widget-details/fileinput. May I know how to set the uploaded file size limit?
I have added:
['image', 'file', 'extensions' => ['png', 'jpg', 'gif'], 'maxSize' => 1024 * 1024 * 1024],
inside the model's rules() but it does not seem to work.
Hope someone can advise. Thanks.
In View:
<?php $form = ActiveForm::begin(['enableClientValidation' => false, 'options' => [ 'enctype' => 'multipart/form-data']]); ?>
<?php
echo $form->field($model, 'image')->widget(FileInput::classname(), [
'options'=>['accept'=>'image/*', 'multiple'=>true],
'pluginOptions'=>['allowedFileExtensions'=>['jpg', 'jpeg', 'gif','png']]
]);
?>
<?php ActiveForm::end(); ?>
In Controller:
$model = new IMAGEMODEL();
Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/web/uploads/PROJECT/';
if ($model->load(Yii::$app->request->post())) {
// get the uploaded file instance. for multiple file uploads
// the following data will return an array
$image = UploadedFile::getInstance($model, 'image');
// store the source file name
$model->FILENAME = $image->name;
$ext = end((explode(".", $image->name)));
// generate a unique file name
$model->AVATAR = Yii::$app->security->generateRandomString().".{$ext}";
$model->STD_ID=$_POST['IMAGEMODEL']['STD_ID'];
// the path to save file, you can set an uploadPath
// in Yii::$app->params (as used in example below)
$path = Yii::$app->params['uploadPath'] . $model->AVATAR;
if($model->save()){
$image->saveAs($path);
Yii::$app->session->setFlash('success', 'Image uploaded successfully');
return $this->redirect(['view', 'id'=>$id]);
} else {
Yii::$app->session->setFlash('error', 'Fail to save image');
}
}
In Model:
public function rules()
{
return [
[['STD_ID', 'FILENAME'], 'required'],
[['FILENAME'], 'string'],
[['LAST_UPD_ON'], 'safe'],
[['STD_ID'], 'string', 'max' => 50],
[['LAST_UPDATE_BY'], 'string', 'max' => 150],
[['image', 'FILENAME'], 'safe'],
['image', 'file', 'extensions' => ['png', 'jpg', 'gif'], 'maxSize' => 1024 * 1024 * 1],
];
}
1) maxSize parameter expects number of bytes. In your example you set 1 Gb. For 2 Mb it should be:
['image', 'file', 'extensions' => ['png', 'jpg', 'gif'], 'maxSize' => 1024 * 1024 * 2],
2) Also check upload_max_filesize INI setting.
3) Make sure pass the instance of yii\web\UploadedFile by calling getInstance() method (for multiple files use getInstances()) before validate:
$this->image = UploadedFile::getInstance($this, 'image');
you can also set image dimension using this along with max file size
['image', 'image', 'minWidth' => 250, 'maxWidth' => 250,'minHeight' => 250, 'maxHeight' => 250, 'extensions' => 'jpg, gif, png', 'maxSize' => 1024 * 1024 * 2],
this allows you to upload maximum of 2mb with 250px width and 250px height
You can set in your view pluginOptions of the FileInput widget this property: 'maxFileSize' => 2048. It will be something like this:
widget(FileInput::classname(), [
'options' => ['multiple'=>true, 'accept'=>'image/*'],
'pluginOptions'=>[
'allowedFileExtensions'=>['jpg','gif','png'],
...
'maxFileSize' => 2048,
...
]
]);

Returning user input after AJAX call in Drupal 7 hook_form_FORM_ID_alter

I am using the hook_form_FORM_ID_alter in Drupal 7 to create a custom form so that the user can enter and edit data which is then attached to a custom node type.
For a new node the default number of input boxes in a group is 10, this can then be added to in groups of 5. When the node is reloaded for editing the saved data is used to create the form with whatever number of inputs have been saved previously and also the ability to add more fields in the same manner as required.
I have managed to get both the initial version of the form and the editing version to work using the following code however when the 'add five' button is pressed and the AJAX called (in both cases), any values which have been entered without saving are removed.
<?php
/**
* Implements hook_form_FORM_ID_alter().
*/
function entries_form_form_entries_node_form_alter(&$form, &$form_state, $form_id) {
$node = $form['#node'];
// fieldset
$form["section"] = array(
'#type' => 'fieldset',
'#title'=> 'Section 1',
);
$form["section"]["termwrapper"] = array(
"#type" => 'container',
"#attributes" => array(
"id" => 'groupWrapper',
),
);
$form["section"]["termwrapper"]["terms"]["#tree"] = TRUE;
if(!isset($form_state['fired'])){
$form_state['terms'] = $node->entries_form['term'];
}
foreach ($form_state['terms'] as $key => $values) {
$form["section"]["termwrapper"]["terms"][$key] = array(
'#type' => 'textfield',
'#size' => 20,
'#attributes' => array(
'class' => array('left'),
),
'#value' => $values,
);
}
$form['section']['addFive_button'] = array(
'#type' => 'submit',
'#value' => t('+5'),
'#submit' => array('entries_form_add_five_submit'),
'#ajax' => array(
'callback' => 'entries_form_commands_add_callback',
'wrapper' => 'groupWrapper',
),
'#prefix' => "<div class='clear'></div>",
);
dpm($form_state);
}
function entries_form_commands_add_callback($form, $form_state) {
return $form["section"]["termwrapper"];
}
function entries_form_add_five_submit($form, &$form_state){
$form_state['rebuild'] = TRUE;
$form_state['fired'] = 1;
$values = $form_state['values'];
$form_state['terms'] = $values['terms'];
$numterms = count($values['terms']);
$addfivearray = array_fill($numterms,5,'');
$form_state['terms'] = array_merge($values['terms'],$addfivearray);
}
/**
* Implements hook_node_submit().
*/
function entries_form_node_submit($node, $form, &$form_state) {
$values = $form_state['values'];
$node->entries_form['term'] = $values['term'];
}
/**
* Implements hook_node_prepare().
*/
function entries_form_node_prepare($node) {
if (empty($node->entries_form)){
$node->entries_form['term'] = array_fill(0, 10, '');
}
}
/**
* Implements hook_node_load().
*/
function entries_form_node_load($nodes, $types) {
if($types[0] == 'entries'){
$result = db_query('SELECT * FROM {mytable} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)))->fetchAllAssoc('nid');
foreach ($nodes as &$node) {
$node->entries_form['term'] = json_decode($result[$node->nid]->term);
}
}
}
/**
* Implements hook_node_insert().
*/
function entries_form_node_insert($node) {
if (isset($node->entries_form)) {
db_insert('mytable')
->fields(array(
'nid' => $node->nid,
'term' => json_encode($node->entries_form['term']),
))
->execute();
}
}
How can I keep the values which have been typed in and retain the ajax functionality?
Any help or pointers much appreciated. This is my first dip into Drupal so I'm sure there is something which hopefully is quite obvious that I'm missing.
Ok, I think I finally have the answer.
Within the foreach that builds the form input boxes I had set '#value' => $values, when it seems that '#default_value' => $values, should have been set instead.
The updated section of the code that is now working for me is as follows
foreach ($form_state['terms'] as $key => $values) {
$form["section"]["termwrapper"]["terms"][$key] = array(
'#type' => 'textfield',
'#size' => 20,
'#attributes' => array(
'class' => array('left'),
),
'#default_value' => $values,
);
}
Seems to be as simple as that. Hope this helps someone else.

Downloadable product : add file links to downloadable product programmatically

I am trying to add link to downloadable product programmatically, below is the code on which i am working.
$linkfile = array();
$_highfilePath = $FolderPath.DS.$fname;
$linkfile[] = array(
'file' => $filePath,
'name' => $fname,
'size' => filesize($filePath),
'status' => 'new'
);
$linkFileName = Mage::helper('downloadable/file')->moveFileFromTmp(
Mage_Downloadable_Model_Link::getBaseTmpPath(),
Mage_Downloadable_Model_Link::getBasePath(),
$linkfile
);
$linkModel = Mage::getModel('downloadable/link')->setData(array(
'product_id' => $product->getId(),
'sort_order' => 0,
'number_of_downloads' => 0, // Unlimited downloads
'is_shareable' => 2, // Not shareable
'link_url' => '',
'link_type' => 'file',
'link_file' => json_encode($linkfile),
'sample_url' => $SamplePathUrl,
'sample_file' => json_encode($linkfile),
'sample_type' => 'file',
'use_default_title' => true,
'default_price' => 0,
'price' => 0,
'store_id' => 0,
'website_id' => $product->getStore()->getWebsiteId(),
));
and this is the error i get An error occurred while saving the file(s)..
Please help
Impossible to diagnose with certainty without more information. Here's the code for the call that's failing:
/**
* Checking file for moving and move it
*
* #param string $baseTmpPath
* #param string $basePath
* #param array $file
* #return string
*/
public function moveFileFromTmp($baseTmpPath, $basePath, $file)
{
if (isset($file[0])) {
$fileName = $file[0]['file'];
if ($file[0]['status'] == 'new') {
try {
$fileName = $this->_moveFileFromTmp(
$baseTmpPath, $basePath, $file[0]['file']
);
} catch (Exception $e) {
Mage::throwException(Mage::helper('downloadable')->__('An error occurred while saving the file(s).'));
}
}
return $fileName;
}
return '';
}
A good place to start would be checking filesystem permissions, making sure your datatypes match the types specified in the function comments, and making sure all files and directories exist.

Resources