I'm very new with YII2. I want to create a download function to the file that was uploaded before. I've referred how to create action download at Gridview in Yii2. However, when I click button download, it load the blank page. Here the code.
At gridview
<?=GridView::widget([
'dataProvider'=>$dataProvider,
'id'=>'mygrid',
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'project_name',
'project_file',
'created_date',
[
'class' => 'yii\grid\ActionColumn',
],
['attribute'=>'Download',
'format'=>'raw',
'value' => function($data)
{
return
Html::a('Download file', ['firstyear/download', 'id' => $data->id],['class' => 'btn btn-primary']);
}
],
]
]);
?>
At actionDownload
public function actionDownload($id)
{
$download = Firstyear::findOne($id);
$path=Yii::getAlias('#webroot').'/uploads/'.$download->project_file;
if (file_exists($path)) {
return Yii::$app->response->sendFile($path);
}
}
At actionCreate (upload file)
public function actionCreate()
{
$model = new Firstyear();
if ($model->load(Yii::$app->request->post()))
{
$project =$model->project_name;
$model->file= UploadedFile::getInstance($model,'file');
$model-> file->saveAs('uploads/'.$project.'.'.$model->file->extension);
$model->project_file='uploads/'.$project.'.'.$model->file->extension;
$model->save();
Yii::$app->getSession()->setFlash('success','Data saved!');
return $this->redirect(['view','id'=> $model->id]);
}
else {
return $this ->renderAjax('create', [
'model'=>$model,
]);
}
}
Thanks.
I suspect that the $path is not correct, in the action create, you already include the uploads folder in your $model->project_file
public function actionCreate()
{
$model = new Firstyear();
if ($model->load(Yii::$app->request->post()))
{
.......
$model->project_file='uploads/'.$project.'.'.$model->file->extension;
$model->save();
....
}
}
but you use it again in actionDownlaod
public function actionDownload($id)
{
.....
$path=Yii::getAlias('#webroot').'/uploads/'.$download->project_file;
if (file_exists($path)) {
return Yii::$app->response->sendFile($path);
}
}
you should try to remove the uploads folder in the actionDownlaod, and added some debug message
public function actionDownload($id)
{
.....
$path=Yii::getAlias('#webroot').'/'.$download->project_file;
if (file_exists($path)) {
return Yii::$app->response->sendFile($path);
} else {
throw new NotFoundHttpException("can't find {$download->project_file} file");
}
}
Related
public function actionIndex() {
$this->layout = 'landing';
$loginForm = new LoginForm();
if (\Yii::$app->request->getIsPost()) {
$loginForm->load(\Yii::$app->request->post());
if ($loginForm->validate()) {
$user = $loginForm->getUser();
\Yii::$app->user->login($user);
return $this->goHome();
}
}
}
method goHome() sends to the home page. I have added '' => 'site/index' to the URL Manager earlier to send people to the SiteController and Index action, but Yii2 does not do anything. How to set up a correct home page rule?
You should write homeUrl parameter on config/main.php. For example:
return [
'id' => 'app-frontend',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'homeUrl' => ['some/home-url-example'],
'modules' => [
...
],
...
]
I am trying to add captcha validation based on scenario, for which I am first retrieving number of failed attempts from database. For which I am using checkattempts() function. Based on the result I am displaying captcha in view and adding scenario condition in controller as below.
In LoginForm model:
public function rules()
{
return [
[['username', 'password'], 'required', 'on'=>'loginpage'],
[['username', 'password'], 'required', 'on'=>'withCaptcha'],
[['reference_url'], 'safe'],
[['verifyCode'], 'captcha', 'skipOnEmpty' => true,'on'=>'withCaptcha'],
['username','email', 'on'=>'loginpage', 'message'=> 'Please enter a valid email address'],
['password', 'validatePassword', 'on'=>'loginpage'],
['password', 'validatePassword', 'on'=>'withCaptcha'],
];
}
public function checkattempts($uname)
{
$user = \frontend\models\User::findByEmail($uname);
$ip = $this->get_client_ip();
if($user){
$data = (new Query())->select('*')
->from('login_attempts')
->where(['ip' => $ip])->andWhere(['user_ref_id' => $user->id])
->one();
if($data["attempts"] >=3){
return true;
}else{
return false;
}
}
return false;
}
in SiteController.php controller
public function actionLogin() {
if (!\Yii::$app->user->isGuest) {
return $this->redirect(Yii::$app->getUrlManager()->getBaseUrl() . '/../../');
}
$model = new \common\models\LoginForm();
$model->scenario = 'loginpage';
$captcha = false;
if(Yii::$app->request->post()){
$post_variables =Yii::$app->request->post('LoginForm');
if ($model->checkattempts($post_variables['username'])) {
$model->scenario = 'withCaptcha';
$captcha = true;
}
}
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->login(); print_r($model->getErrors()); exit;
} else {
return $this->render('login', [
'model' => $model, 'captcha' => $captcha,
]);
}
In my login.php view:
<?php if($captcha) { ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(),
['template' => '<div class="captcha_img">{image}</div>'
. '<a class="refreshcaptcha" href="#">'
. Html::img('/images/imageName.png',[]).'</a>'
. 'Verification Code{input}',
])->label(FALSE); ?>
<?php } ?>
In my controller when I am tring to print model errors at $model->login() function it is giving below error everytime even though the verification code is correct.
Array ( [verifycode] => Array ( [0] => The verification code is incorrect. ) )
Why is it failing every time. Is there any mistake in the code written?
Thanks in advance
I'm coding a multiple upload function for my website. The upload was successful. But it's only save the first value to my database. Example i upload 3 files name 1.jpg, 2.jpg, 3.jpg. Then it will upload the 3 files successfully but save only the 1.jpg's name to database.
My controllers
public function actionCreate()
{
$model = new Resource3d();
if ($model->load(Yii::$app->request->post())) {
$model->files = UploadedFile::getInstances($model, 'files');
foreach ($model->files as $files){
$files->saveAs('uploads/resource3d/' . $files->baseName . $files->extension);
$model->path = '../web/uploads/resource3d/'. $files->baseName . $files->extension;
$model->name = $files->baseName;
$model->save();
}
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
My models:
public $files;
public function rules()
{
return [
[['name', 'path'], 'string', 'max' => 255],
[['files'], 'file', 'skipOnEmpty' => false, 'maxFiles' => 0],
];
}
Please help.
Thank you.
You are creating single object of your model Resource3d. You need to create multiple object if you want to save multiple records.
Try this :
public function actionCreate()
{
$model = new Resource3d();
if ($model->load(Yii::$app->request->post())) {
$model->files = UploadedFile::getInstances($model, 'files');
foreach ($model->files as $files){
$res_model = new Resource3d();
$res_model->load(Yii::$app->request->post());
$files->saveAs('uploads/resource3d/' . $files->baseName . $files->extension);
$res_model->path = '../web/uploads/resource3d/'. $files->baseName . $files->extension;
$res_model->name = $files->baseName;
$res_model->save();
}
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
This is just an example, change it according to your need.
Going to change image field in model by changing value in hidden field:
View:
<?= HTML::activeHiddenInput($model, 'image_clean', [
'id' => 'cleaner',
'name' => 'cleaner',
'value' => false
])
?>
<?=
Html::button('Remove logo', [
'id' => 'btn_clean',
])
?>
at the end of view:
<?php
$this->registerJs(<<<JS
$('#btn_clean').on('click', function() {
alert('Going to remove logo'); // Reachable!
$('#cleaner').val(true);
});
JS
);
?>
Model:
public $image_clean; // Remove logo
public function rules() {
return [
//...
[['image_clean'], 'boolean'],
//...
];
}
public function attributeLabels() {
return [
//...
'image_clean' => 'Remove logo',
//...
];
}
public function beforeValidate() {
if($this->image_clean) { } // Never!
return parent::beforeValidate();
}
public function beforeSave($insert) {
if($this->image_clean) { } // Never!
return parent::beforeSave($insert);
}
Unfortunately, $this->image_clean in model's beforeValidate / beforeSave always false. Why?
Javascript btn_clean handler works as it should be.
Hiddeninput's name overrides default one.
So, I just remove 'name' => 'cleaner'. It's not required
I have a yii2 project, I am developing on my windows localhost and hosting remotely on linux.
Locally (windows) every thing is perfect.
While on linux, I have $model->id = null after $nodel->save(), although data is saved.
public function actionCreate() {
$model = new AppBreakingNews();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
I have tried die($model->id) after the save, it printed null.
Moreover, when I click on the update icon in the grid view, I am facing the same problem.
The AppBreakingNews is as follows:
<?php
namespace app\models\appmodels;
use app\models\BreakingNews;
use yii\behaviors\TimestampBehavior;
class AppBreakingNews extends BreakingNews {
public function behaviors() {
return [
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => date('Y-m-d H:i:s'),
],
];
}
}
Notice that appBreakingNews extends the model BreakingNews that is generated by yii2 without any change.
Thanks in advance..
Please try to save model->save(false); because i think it validate something from model file.
public function actionCreate() {
$model = new AppBreakingNews();
if ($model->load(Yii::$app->request->post()) && $model->save(false)) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
or can you please print your model file here.