php - Yii2 Kartik-v fileiput: Get uploaded images when wrapped in the array of $_FILES instead of $_POST
Get the solution ↓↓↓I am developing my app using the yii2-formwizard widget. I have gotten it working fine in all the other parts and even submits a single image perfectly. The problem comes when I try to submit multiple images. I get the$_POST
array with form model values and the image model as an empty array inside the$_POST
, but then all the image model values are wrapped in an array of$_FILES
. How do I go about solving this as I have never dealt with such before? Here are the relevant codes:
_form view
<?php
use yii\helpers\Html;
use kartik\widgets\ActiveForm;
use kartik\builder\Form;
use kartik\datecontrol\DateControl;
use kartik\widgets\Select2;
use buttflattery\formwizard\FormWizard;
use yii\helpers\ArrayHelper;
use kartik\file\FileInput;
/**
* @var yii\web\View $this
* @var common\models\Listing $model
* @var yii\widgets\ActiveForm $form
*/
?>
<?php
echo FormWizard::widget([
'theme' => FormWizard::THEME_MATERIAL,
'labelFinish' => 'Submit',
// 'formOptions'=>[
// 'options'=>['enctype'=>'multipart/form-data'],
// ],
'steps' => [
[
'model'=>$listingModel,
'title'=>'Basic',
'description'=>'Give us the details of the list',
'formInfoText'=>'Fill all required fields',
'fieldConfig' => [
'created_by' => false, //hide a specific field
'updated_at' => false, //hide a specific field
'created_at' => false, //hide a specific field
'expires_on' => false, //hide a specific field
'status' => false, //hide a specific field
'listing_type_id' => false, //hide a specific field
'latitude' => false, //hide a specific field
'longitude' => false, //hide a specific field
'listing_title' => ['type' => Form::INPUT_TEXT, 'options' => ['placeholder' => 'Enter Listing Title...', 'maxlength' => 50]],
'country' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\Country::find()->all(), 'country_id', 'country_name'),
'options' => [
'prompt'=>'Select Country',
'onchange'=>'
$.post( "'.Yii::$app->urlManager->createUrl('listing/select-state?id=').'"+$(this).val(), function( data ) {
$( "select#state_id" ).html( data );
});
'
]
]
],
'states' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\States::find()->all(), 'state_id', 'state_name'),
'options' => [
'id'=>'state_id',
'prompt'=>'Select Select the Country First',
'onchange'=>'
$.post( "'.Yii::$app->urlManager->createUrl('listing/select-area?id=').'"+$(this).val(), function( data ) {
$( "select#area_code" ).html( data );
});
'
]
]
],
'area_id' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\Areas::find()->all(), 'area_id', 'area_name'),
'options' => [
'prompt'=>'Please Select the State/Region First',
'id' => 'area_code'
],
]
],
'physical_address' => ['type' => Form::INPUT_TEXT, 'options' => ['placeholder' => 'Enter The Actual Physical Address...', 'maxlength' => 50]],
'neighborhood' => ['type' => Form::INPUT_TEXT, 'options' => ['placeholder' => 'Enter The Nearby Landmark or Neighbourhood...', 'maxlength' => 50]],
'address' => [
'widget' => \kalyabin\maplocation\SelectMapLocationWidget::className(),
'options' => [
'attributeLatitude' => 'latitude',
'attributeLongitude' => 'longitude',
'googleMapApiKey' => 'AIzaSyDU30XgKi1ik7wpWteHUENKVH_d09sTqRg',
'draggable' => true,
],
]
]
],
[
'model'=>$model,
'title'=>'Prices and More',
'description'=>'Give us the details of the list',
'formInfoText'=>'Fill all required fields',
'fieldConfig' => [
// 'only' => ['property_category', 'sub_category_id', 'available_from', 'desc', 'price', 'currency_id', 'price_conditions', 'deposit', 'agent_commission', 'other_payments'],
'only' => ['property_category', 'sub_category_id', 'price', 'currency_id'],
'property_category' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\PropertyCategory::find()->all(), 'category_id', 'category_name'),
'options' => [
'id'=>'state_id',
'prompt'=>'Select Property Category',
'onchange'=>'
$.post( "'.Yii::$app->urlManager->createUrl('listing/select-property-category?id=').'"+$(this).val(), function( data ) {
$( "select#sub_category_value" ).html( data );
});
'
]
]
],
'sub_category_id' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\PropertySubCategory::find()->all(), 'sub_category_id', 'name'),
'options' => [
'prompt'=>'Please Select the Property Category First',
'id' => 'sub_category_value'
],
]
],
'currency_id' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\Currency::find()->all(), 'currency_id', 'title'),
]
],
'price' => ['type' => Form::INPUT_TEXT, 'options' => ['placeholder' => 'Enter Price...']],
]
],
[
'model'=>$model,
'title'=>'Features',
'description'=>'Give us the details of the list',
'formInfoText'=>'Fill all required fields',
'fieldConfig' => [
// 'only' => ['beds', 'baths', 'rooms', 'living_area', 'living_size', 'floor', 'total_floors', 'build_year', 'car_spaces', 'fully_furnished', 'property_features'],
'only' => ['property_features'],
'property_features' => [
'widget' => Select2::class, //widget class name
'options' => [
'data' => ArrayHelper::map(common\models\PropertyFeatures::find()->all(), 'feature_id', 'feature_name', 'featuresType.type_name'),
'options' => ['multiple' => true, 'placeholder' => 'Select Property Features ...']
]
],
]
],
[
'model'=>$imageModel,
'title'=>'Images',
'description'=>'Give us the details of the list',
'formInfoText'=>'Fill all required fields',
'fieldConfig' => [
'only' => ['image'],
'image' => [
'multifield'=>true,
'widget' => FileInput::classname(),
'options' =>[
'options' => [
'multiple' => true,
'accept' => 'image/*',
'pluginOptions' => [
'showCaption' => false,
'showRemove' => false,
'showUpload' => false,
'browseClass' => 'btn btn-primary btn-block',
'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ',
'browseLabel' => 'Attach Listing Images',
'allowedFileExtensions' => ['jpg','gif','png'],
'overwriteInitial' => false
],
],
],
]
]
],
]
]);
?>
Controller Action
/**
* Creates a new Property model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionProperty()
{
$listingModel = new Listing;
$imageModel = new ListingImages;
$model = new Property;
if ($listingModel->load(Yii::$app->request->post()) && $imageModel->load(Yii::$app->request->post()) && $model->load(Yii::$app->request->post())) {
$transaction = Yii::$app->db->beginTransaction();
try {
$listingModel->listing_type_id = $listingModel->listingType('Property');
$listingModel->created_by = Yii::$app->user->id;
if ($flag = $listingModel->save(false)) {
$model->listing_id = $listingModel->listing_id;
$model->physical_address = $listingModel->physical_address;
$model->neighborhood = $listingModel->neighborhood;
$model->area_id = $listingModel->area_code;
$model->address = $listingModel->physical_address;
$model->latitude = $listingModel->latitude;
$model->longitude = $listingModel->longitude;
$model->created_by = Yii::$app->user->id;
$flag = $model->save(false);
foreach ($_FILES['ListingImages']['name']['image'] as $key => $image) {
$image = $imageModel->uploadImage();
$imageModel->created_by = Yii::$app->user->id;
$imageModel->listing_id = $listingModel->listing_id;
$imageModel->active = 'Y';
if ($flag = $imageModel->save()) {
if ($image !== false) {
$path = $imageModel->getImageFile();
$image->saveAs($path);
}
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $listingModel->listing_id]);
} else {
$transaction->rollBack();
}
} catch (Exception $e) {
$transaction->rollBack();
}
} else {
return $this->render('create', [
'listingModel' => $listingModel, 'model' => $model, 'form' => '_property', 'imageModel' => $imageModel,
]);
}
}
ListingImages model
<?php
namespace common\models;
use Yii;
use yii\web\UploadedFile;
use yii\helpers\FileHelper;
/**
* This is the model class for table "listing_images".
*
* @property int $image_id
* @property int $listing_id
* @property string $image_url_link generated filename on server
* @property string $updated_at
* @property string $created_at
* @property int $created_by
* @property string $active
* @property string $filename source filename from client
*
* @property Listing $listing
*/
class ListingImages extends \yii\db\ActiveRecord
{
const PERMISSIONS_PRIVATE = 10;
const PERMISSIONS_PUBLIC = 20;
public $filename;
public $image;
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'listing_images';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['listing_id', 'image_url_link', 'created_by', 'active'], 'required'],
[['listing_id', 'created_by'], 'integer'],
[['updated_at', 'created_at', 'filename'], 'safe'],
[['active'], 'string'],
[['image_url_link'], 'string', 'max' => 80],
[['listing_id'], 'exist', 'skipOnError' => true, 'targetClass' => Listing::className(), 'targetAttribute' => ['listing_id' => 'listing_id']],
// [['image'], 'file', 'extensions'=>'jpg, gif, png'],
// [['image'], 'file', 'maxSize'=>'2048000'],
// [['image'], 'file','maxFiles' => 30],
[['image'], 'file', 'extensions' => ['png', 'jpg', 'gif'], 'maxSize' => 2048000, 'maxFiles' => 30],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'image_id' => Yii::t('app', 'Image ID'),
'listing_id' => Yii::t('app', 'Listing ID'),
'image_url_link' => Yii::t('app', 'Listing Image'),
'updated_at' => Yii::t('app', 'Updated At'),
'created_at' => Yii::t('app', 'Created At'),
'created_by' => Yii::t('app', 'Created By'),
'active' => Yii::t('app', 'Active'),
];
}
/**
* @return \yii\db\ActiveQuery
*/
public function getListing()
{
return $this->hasOne(Listing::className(), ['listing_id' => 'listing_id']);
}
/**
* fetch stored image file name with complete path
* @return string
*/
public function getImageFile()
{
$directory = Yii::$app->params['uploadPath'];
if (!is_dir($directory)) {
FileHelper::createDirectory($directory);
}
return isset($this->image_url_link) ? $directory . '/' . $this->image_url_link : null;
}
/**
* fetch stored image url
* @return string
*/
public function getImageUrl()
{
$directory = Yii::$app->params['uploadUrl'];
// return a default image placeholder if your source image_url_link is not found
$image_url_link = isset($this->image_url_link) ? $this->image_url_link : 'default_user.jpg';
return $directory . $image_url_link;
}
/**
* Process upload of image
*
* @return mixed the uploaded image instance
*/
public function uploadImage() {
// get the uploaded file instance. for multiple file uploads
// the following data will return an array (you may need to use
// getInstances method)
$image = UploadedFile::getInstance($this, 'image');
// if no image was uploaded abort the upload
if (empty($image)) {
return false;
}
// store the source file name
$tmp = explode(".", $image->name);
$ext = end($tmp);
// generate a unique file name
$this->image_url_link = Yii::$app->security->generateRandomString().".{$ext}";
// the uploaded image instance
return $image;
}
/**
* Process deletion of image
*
* @return boolean the status of deletion
*/
public function deleteImage() {
$file = $this->getImageFile();
// check if file exists on server
if (empty($file) || !file_exists($file)) {
return false;
}
// check if uploaded file can be deleted on server
if (!unlink($file)) {
return false;
}
// if deletion successful, reset your file attributes
$this->image_url_link = null;
$this->filename = null;
return true;
}
}
Note that the other part of the code is working fine. I have only twisted some few parts to get a favourable results. Here is the submitted data via the form. The part that is really confusing me is that wrapped in the $_FILES array at the end of this code that has all the uploaded files information.
$_POST = [
'_csrf-backend' => '_ioSvkoWdYDTEG_L4AHgnyQSEe7pZOqEWwQfPANPbM2uGkbIKHo8y5ZAGriqT4XsQCBkl5sOnvweT31wUx01kg==',
'Listing' => [
'listing_title' => 'tyguhijokpl[',
'country' => '2',
'states' => '4',
'area_id' => '1537',
'physical_address' => 'yghbunjikmol,',
'neighborhood' => 'gvybhunjimko,l',
'address' => 'Dandora phase 4, Nairobi, Kenya',
'latitude' => '-1.2423923',
'longitude' => '36.90438449999999',
],
'Property' => [
'property_category' => '1',
'sub_category_id' => '2',
'currency_id' => '1',
'price' => '897465123',
'property_features' => [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
],
],
'ListingImages' => [
'image' => [
'',
],
],
];
$_FILES = [
'ListingImages' => [
'name' => [
'image' => [
'coins-1015125_1920.jpg',
'computer-768608_1920.jpg',
'content-is-king-1132259_1920.jpg',
'content-marketing.jpg',
'contentpyramid.png',
'cup-of-coffee-1280537_1920.jpg',
'ecommerce-3546296_1920.jpg',
'email-3249062_1280.png',
],
],
'type' => [
'image' => [
'image/jpeg',
'image/jpeg',
'image/jpeg',
'image/jpeg',
'image/png',
'image/jpeg',
'image/jpeg',
'image/png',
],
],
'tmp_name' => [
'image' => [
'C:\\xampp\\tmp\\php8AF1.tmp',
'C:\\xampp\\tmp\\php8B02.tmp',
'C:\\xampp\\tmp\\php8B03.tmp',
'C:\\xampp\\tmp\\php8B23.tmp',
'C:\\xampp\\tmp\\php8B34.tmp',
'C:\\xampp\\tmp\\php8B35.tmp',
'C:\\xampp\\tmp\\php8B46.tmp',
'C:\\xampp\\tmp\\php8B47.tmp',
],
],
'error' => [
'image' => [
0,
0,
0,
0,
0,
0,
0,
0,
],
],
'size' => [
'image' => [
364796,
275881,
310313,
301511,
119458,
508911,
219479,
242737,
],
],
],
];
Answer
Solution:
i created this extension a few months back. The files that you submitted will be in the$_FILES
array and not the$_POST
and you need to call theUploadedFile::getInstances('image')
to get all the images you selected to upload and then iterate on them to upload, you can access all the properties listed here for every image.
And you are not creating the new object every time you are inserting the image inside theforeach ($_FILES['ListingImages']['name']['image'] as $key => $image) {
which will show only the last image inserted , your$imageModel
is initialized in the start of the action whereas you should have it inside theforeach
too
$imageInstances=UploadedFile::getInstances('image');
foreach ($imageInstances as $instance) {
$imageModel=new ListingImages();
$image = $imageModel->uploadImage($instance);
$imageModel->created_by = Yii::$app->user->id;
$imageModel->listing_id = $listingModel->listing_id;
$imageModel->active = 'Y';
if ($flag = $imageModel->save()) {
if ($image !== false) {
$path = $imageModel->getImageFile();
$image->saveAs($path);
}
}
}
and inside youuploadImage()
use this instance to access thename
,type
,size
andextension
of the image to assign to the specific fields
/**
* Process upload of image
*
* @return mixed the uploaded image instance
*/
public function uploadImage($image) {
// get the uploaded file instance. for multiple file uploads
// the following data will return an array (you may need to use
// getInstances method)
// store the source file name
$tmp = explode(".", $image->name);
$ext = end($tmp);
// generate a unique file name
$this->image_url_link = Yii::$app->security->generateRandomString().".{$ext}";
// the uploaded image instance
return $image;
}
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: undefined array key php
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.