I have a fileupload function that is supposed to save files in different locations depending on which form was submitted.
First of all, I have in the same view the two ActiveForms to submit a file with (different variable in the field):
<?php $form = ActiveForm::begin(['action' => \yii\helpers\Url::to(['upload', 'id' => $model->id, 'mod' => 1]), 'options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file1')->fileInput(['style' => ''])->label(false) ?>
<?= Html::submitButton('Upload', ['class' => 'btn-success']) ?>
<?php ActiveForm::end(); ?>
and
<?php $form = ActiveForm::begin(['action' => \yii\helpers\Url::to(['upload', 'id' => $model->id, 'mod' => 0]), 'options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file2')->fileInput(['style' => ''])->label(false) ?>
<?= Html::submitButton('Upload', ['class' => 'btn-success']) ?>
<?php ActiveForm::end() ?>
To my understanding, this would then put those files in the variable in the corresponding model:
* #var file1
* #var file2
*/
class X extends \yii\db\ActiveRecord
{
/**
* #var UploadedFile file1 attribute
*/
public $file1;
/**
* #var UploadedFile file2 attribute
*/
public $file2;
with the 'action' pointing to upload, it should call the xController action:
public function actionUpload($id, $mod) {
$model = new X();
if($mod == 1){
$model->file1 = UploadedFile::getInstance($model, 'file1');
if($model->file1){
$path = 'uploads/docs1/'. $id .'/';
if(!is_dir($path)){
FileHelper::createDirectory($path);
$model->pwFile->saveAs($path . $model->file1->baseName . '.' . $model->file1->extension);
}else{
$files = \yii\helpers\FileHelper::findFiles($path);
if(empty($files) || is_null($files)){
$model->file1->saveAs($path . $model->file1->baseName . '.' . $model->file1->extension);
}else{
foreach($files as $file){
unlink($file);
}
$model->file1->saveAs($path . $model->file1->baseName . '.' . $model->file1->extension);
}
}
}
}else{
$model->file2 = UploadedFile::getInstance($model, 'file2');
if($model->file2){
$path = 'uploads/docs2/'. $id .'/';
if(!is_dir($path)){
FileHelper::createDirectory($path);
}
$model->file->saveAs($path . $model->file2->baseName . '.' . $model->file2->extension);
}
}
return $this->render('view', ['model' => $this->findModel($id)]);
}
This doesn't seem to work. The upload for file1 works alright, the file gets uploaded to the server and that's it. If I use the second form however, it loads the correct url but nothing gets saved on the server. What am I doing wrong?
You have a massive amount of duplicated code, which makes it harder to debug. I hacked away at it and I think the below is optimal. I've also changed a few things, which should be pretty easy for you to spot.
public function actionUpload($id, $mod) {
$model = new X();
if($mod == 1) {
$file = UploadedFile::getInstance($model, 'file1');
$path = 'uploads/docs1/'. $id .'/';
} else {
$file = UploadedFile::getInstance($model, 'file2');
$path = 'uploads/docs2/'. $id .'/';
}
if ($file->name != '') {
if(is_dir($path)){
$files = \yii\helpers\FileHelper::findFiles($path);
foreach($files as $file){
unlink($file);
}
}
FileHelper::createDirectory($path);
$file->saveAs($path . $file->name);
}
return $this->render('view', ['model' => $this->findModel($id)]);
}
I think this will work now, if not, give me a shout and I'll have another look.
Related
How can I redirect the user to a view page after uploading file?
Now it works only when I write id of db entry in view
I'm totally new to php and yii 2.
Controller
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->file && $model->validate()) {
$postFile = Yii::$app->request->post();
$directory = Yii::getAlias('#frontend/web/uploads');
$uid = Yii::$app->security->generateRandomString(6);
$fileName = $uid . '.' . $model->file->extension;
$filePath = $directory . '/' . $fileName;
$path = 'http://frontend.dev/uploads/' . $fileName;
$userinfo = new webminfo();
$userinfo->uid = $uid;
$userinfo->author_id = Yii::$app->user->id;
$userinfo->path = $filePath;
$userinfo->url = $path;
$userinfo->created_at = time();
$userinfo->ip = Yii::$app->getRequest()->getUserIP();
$userinfo->save();
if ($model->file->saveAs($filePath)) {
Yii::$app->session->setFlash('success', 'Success');
return $this->redirect(['view', 'id' => $userinfo->uid]);
}
}
else {
Yii::$app->session->setFlash('error', 'Error');
}
}
return $this->render('upload', ['model' => $model]);
}
public function actionView($id) {
$model = new webminfo();
return $this->render('view', [
'id' => $id,
'model' => $model,
]);
}
View
<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\helpers\Url;
use app\models\webminfo;
$this->title = 'View';
$this->params['breadcrumbs'][] = $this->title;
?>
Use $uid instead of $userinfo->uid as follows in your redirect function
return $this->redirect(['view', 'id' => $uid]);
I need to UPDATE record with out changing or deleting filename(i mean file) , OR reinsert file again so how i can do this?
here is my actionCreate, How i can write update?
public function actionCreate() {
$model = new Page;
if (isset($_POST['Page'])) {
$model->attributes = $_POST['Page'];
$model->filename = CUploadedFile::getInstance($model, 'filename');
if ($model->save()) {
if ($model->filename !== null) {
$dest = Yii::getPathOfAlias('application.uploads');
$model->filename->saveAs($dest . '/' . $model->filename->name);
$model->save();
}
$this->redirect(array('view', 'id' => $model->id));
}
}
$this->render('create', array(
'model' => $model,
));
}
So Please can anyone find a solution
If you don't need to change or delete filename in edit/update then ignore filename (and upload part) assuming the file is alrready uploaded and you don't wish to change/delete it.
public function actionUpdate($id) {
$model = $this->loadModel($id);
$file = $model->filename;
if (isset($_POST['Page'])) {
$model->attributes = $_POST['Page'];
$model->filename = $file;
if ($model->save()) {
$this->redirect(array('view', 'id' => $model->id));
}
}
$this->render('create', array(
'model' => $model,
));
}
Try this, it's working for me -
create a upload folder outside protected directory and also give read/write permission.
actionCreate function -
public function actionCreate() {
$model = new Page();
if(isset($_POST['Page']) && !empty($_POST['Page'])){
$model->attributes = $_POST['Page'];
$rand = rand(1, 999);
$myfile = CUploadedFile::getInstance($model, 'filename');
$fileName = "{$rand}-{$myfile}"; //Generate unique file name
if(!empty( $fileName)){
$model->filename = $fileName;
$target_dir = realpath( Yii::getPathOfAlias('application') . '/../upload');
$target_file = $target_dir . '/' . $fileName;
if(!$myfile->saveAs($target_file)){
$model->addError('filename', 'File saving error');
}
}
if(!$model->hasErrors() && $model->validate() && $model->save(false)) {
$this->redirect(array('view', 'id'=>$model->id, 'msg'=>'success'));
}
}
}
actionUpdate function -
public function actionUpdate() {
$model = Page::model()->findbyPK($id);
$model->scenario = 'update';
if(isset($_POST['Page']) && !empty($_POST['Page'])){
$model->attributes = $_POST['Page'];
if(empty($_POST['Page']['filename'])) { $file_name = $model->filename; } //store existing file name into a variable if your uploading a file on update
$rand = rand(1, 999);
$myfile = CUploadedFile::getInstance($model, 'filename');
$fileName = "{$rand}-{$myfile}"; //Generate unique file name
if($model->validate()) {
if(!empty($fileName)) {
$model->filename = $fileName;
$target_dir = realpath( Yii::getPathOfAlias( 'application' ) . '/../upload');
$target_file = $target_dir . '/' . $fileName;
if(!$myfile->saveAs($target_file)){
$model->addError('filename', 'File saving error');
}
}
else {
$model->filename = $file_name; //allow existing file name
}
if( !$model->hasErrors() && $model->save(false) ) {
$this->redirect(array('view', 'id'=>$model->id, 'msg'=>'update'));
}
}
}
In model rules array define this -
array('filename', 'file', 'types'=>'jpg, jpeg, bmp, gif, png', 'allowEmpty'=>true, 'on'=>'insert, update')
I have a Cache Configuration in my bootstrap.php file as
Cache::config('long', array(
'engine' => 'File',
'duration' => '+1 week',
'probability'=> 100,
'mask' => 0666,
'path' => CACHE . 'long' . DS,
));
and i am trying to clear cache when a setting is edited. Below is my admin_edit function
public function admin_edit($id = null) {
if (!$this->Setting->exists($id)) {
throw new NotFoundException(__('Invalid setting'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->Setting->save($this->request->data)) {
$this->Session->setFlash(__('The setting has been saved'));
$this->redirect(array('action'=> 'index'));
Cache::clear(false,'long');
Cache::gc();
}else {
$this->Session->setFlash(__('The setting could not be saved. Please, try again.'));
}
}else {
$options = array('conditions' => array('Setting.' . $this->Setting->primaryKey=> $id));
$this->request->data = $this->Setting->find('first', $options);
}
}
However, Cache::clear(false,'long') does not work and it does not clear the Cache. Not sure what is going wrong. Stuck for a few days now!
Please use below function in any controller and run that function where you want it will be clear all cache.
/**
* function to clear all cache data
* by default accessible only for admin
*
* #access Public
* #return void
*/
public function clear_cache() {
Cache::clear();
clearCache();
$files = array();
$files = array_merge($files, glob(CACHE . '*')); // remove cached css
$files = array_merge($files, glob(CACHE . 'css' . DS . '*')); // remove cached css
$files = array_merge($files, glob(CACHE . 'js' . DS . '*')); // remove cached js
$files = array_merge($files, glob(CACHE . 'models' . DS . '*')); // remove cached models
$files = array_merge($files, glob(CACHE . 'persistent' . DS . '*')); // remove cached persistent
foreach ($files as $f) {
if (is_file($f)) {
unlink($f);
}
}
if(function_exists('apc_clear_cache')):
apc_clear_cache();
apc_clear_cache('user');
endif;
$this->set(compact('files'));
$this->layout = 'ajax';
}
Once let me know if not working for you :)
Thanks
I'm using mongodb suite in yii framework, when assign CUploadedFile to public property image class model , get error :
MongoException
zero-length keys are not allowed, did you use $ with double quotes?
/var/www/html/bablog/protected/extensions/YiiMongoDbSuite/EMongoDocument.php(611)
model class :
...
public function rules() {
return array(
...
array('image', 'file',
'types'=>'jpg,jpeg, png' ,
'mimeTypes' => 'image/jpeg , image/pjpeg,image/png' ,
'safe'=>true,
'maxFiles' => 1 ,
'maxSize' => 1024 ,
'minSize' => 100 ,
),
);
}
add code :
echo '<pre>';
print_r(CUploadedFile::getInstance($model,'image'));
die();
output:
CUploadedFile Object
(
[_name:CUploadedFile:private] => download.jpg
[_tempName:CUploadedFile:private] => /tmp/phpC8GRRt
[_type:CUploadedFile:private] => image/jpeg
[_size:CUploadedFile:private] => 530
[_error:CUploadedFile:private] => 0
[_e:CComponent:private] =>
[_m:CComponent:private] =>
)
try :
1- declare image dynamic property in model , but define __set function in parent again get same error.
2- define protected property but CUploadedFile::getInstance($model,'image') requirement public property , As a result, get error :( :D .
Question :
1-For the above problem, what do I do?
2- Is there any way that we define our own attributes in mongodbsuite , Instead of get attributes public property in class?
Sorry for my poor English
tnx for All
finally i'm multiple upload files :
view file :
.....
<div class="row">
<?php echo $form->labelEx($model, 'image[0]'); ?>
<?php echo $form->fileField($model, 'image[0]'); ?>
<?php echo $form->error($model, 'image[0]'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model, 'image[1]'); ?>
<?php echo $form->fileField($model, 'image[1]'); ?>
<?php echo $form->error($model, 'image[1]'); ?>
</div>
.....
controller file:
<?php
public function actionCreate() {
$model = new Post;
$images = array();
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if (isset($_POST['Post'])) {
$countImage = count($_POST['Post']['image']);
$model->attributes = $_POST['Post'];
$model->status = $_POST['Status'];
$j = 0;
for ($i = 0; $i < $countImage; $i++) {
$imageTemp = new Post;
$imageTemp->image = CUploadedFile::getInstance($imageTemp, "image[$i]");
if (!empty($imageTemp->image)) {
$images[$j] = $imageTemp;
$j++;
}
unset($imageTemp);
}
if ($model->save()) {
foreach ($images as $i => $image) {
$namePic[$i] = Yii::app()->params['pathImages'] . Yii::app()->params['domainName'] . '-' . (string) $model->_id . '-' . time() . '-' . rand(1, 1000) . '.' . $image->image->getExtensionName();
$image->image->saveAs($namePic[$i]);
}
$model->image = $namePic;
$model->update(array('image'), true);
unset($images);
//$this->redirect(array('view', 'id' => $model->_id));
}
}
$this->render('create', array(
'model' => $model,
));
}
model :
public function rules() {
return array(....
array('image', 'file',
'types'=>'jpg, png' ,
'mimeTypes' => 'image/gif, image/jpeg' ,
'safe'=>true,
'maxFiles' => 3 ,
'maxSize' => 10240000 ,
),
....
);
}
finish :D
I hope it's been getting better
<?php
class UploadsController extends AppController {
var $name = 'Uploads';
var $components = array('Auth');
var $uses = array('Upload');
function beforeFilter() {
$this->Auth->allow('*');
}
function upload($event) {
App::import('Vendor', 'UploadedFiles', array('file' => 'UploadedFiles.php'));
$user = $this->Auth->user('id');
$this->set('user', $user);
if(!$this->Auth->user()) { $this->Session->setFlash(__('Please login.', true)); }
echo $user;
echo $event;
$vardir = date('d-m-Y');
$dir = 'img/gallery/'.$vardir.'/';
$thmbdir = 'img/gallery/'.$vardir.'/thumbnails/';
if(!is_dir($dir)) {
mkdir($dir, 0777);
mkdir($thmbdir, 0777);
}
$galleryPath = $dir;
$absGalleryPath = realpath($galleryPath) . '/';
$absThumbnailsPath = realpath($galleryPath . 'thumbnails/') . '/';
//Iterate through uploaded data and save the original file, thumbnail, and description.
while(($file = UploadedFiles::fetchNext()) !== null) {
$fileName = $file->getSourceFile()->getSafeFileName($absGalleryPath);
$file->getSourceFile()->save($absGalleryPath . '/' . $fileName);
$thumbFileName = $file->getThumbnail(1)->getSafeFileName($absThumbnailsPath);
$file->getThumbnail(1)->save($absThumbnailsPath . '/' . $thumbFileName);
$this->Upload->create();
$this->Upload->set(array(
'name' => $absGalleryPath . $fileName,
'width' => $file->getSourceFile()->getWidth(),
'height' => $file->getSourceFile()->getHeight(),
'description' => $file->getDescription(),
'event_id' => $event,
'user_id' => $user
));
$this->Upload->save();
}
}
}
Check the last part of the code where I try to save to the database. It doesn't save because $event and $users become empty. But when I echo them (line 17 and 18), they do appear on the page with correct values. It seems that they are being 'erased' in the while loop...
If I put some dummy data for 'event_id' => '123' and 'user_id' => '123', the scripts saves successfully. But if I use the variables, it doesn't save. What happens with my variables? Any idea?
Thanks
I'm guessing there's an error in your model. Try creating the array first, and printing it, and see if it creates the array correctly. Then make sure your model matches the array, ie. that the field types match the field types you input. '123' isn't the same as 123, since '123' is a string, and 123 is an integer.
i can think of a couple things i'd try though it's not to say you haven't already.
echo $user and $event the line just before and just after the while loop, to verify the problematic line.
set the variables to another temp variable:
$t_user = $user;
$t_event = $event;
then try using the $t_ variables in the loop.