douyang2530 2018-01-28 19:46
浏览 97
已采纳

Yii2文件上传返回UPLOAD_ERR_PARTIAL

Images fail to upload when I create a new item but on updating the newly created item the file is successfully uploaded. Any reasons?
Trending News Model

class TrendingNews extends \yii\db\ActiveRecord
{
    const EVENT_ADD_TRENDING_NEWS = 'add-trending-news';
      public $featuredFile;

      public function init() {
         $this->on(self::EVENT_ADD_TRENDING_NEWS, [$this, 'saveToLog']);
      }
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'trending_news';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['headline_text','news_info', 'news_url', 'author', 'published', 'date_added', 'date_modified'], 'required'],
            [['headline_text', 'image_url', 'news_info', 'news_url'], 'string'],
            [['date_added', 'date_modified'], 'safe'],
            [['author'], 'string', 'max' => 20],
            [['published'], 'string', 'max' => 2],
            [['featuredFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'headline_text' => 'Headline',
            'image_url' => 'Image Url',
            'news_info' => 'Source',
            'news_url' => 'News Url',
            'author' => 'Author',
            'published' => 'Published',
            'date_added' => 'Date Added',
            'date_modified' => 'Date Modified',
            'featuredFile' => 'Featured Image',
        ];
    }

    public function uploadBanner()
    {
        if ($this->validate()) {
           $ymd = date("Ymd");
           $save_path = \Yii::getAlias('@backend') . '/web/uploads/' . $ymd . '/';
            if (!file_exists($save_path)) {
                mkdir($save_path, 0777, true);
            }
            $fileName = "trending_".Yii::$app->security->generateRandomString(20);
            $this->featuredFile->saveAs($save_path . $fileName .'.' . $this->featuredFile->extension);
            $this->image_url = $ymd . '/'. $fileName . '.' . $this->featuredFile->extension;
            return true;
        } else {
            return false;
        }
    }

    public function upload()
    {
        if ($this->validate()) {
           $ymd = date("Ymd");
           $save_path = \Yii::getAlias('@backend') . '/web/uploads/' . $ymd . '/';
            if (!file_exists($save_path)) {
                mkdir($save_path, 0777, true);
            }

            $fileName = Yii::$app->security->generateRandomString(20);

            $this->featuredFile->saveAs($save_path . $fileName .'.' . $this->featuredFile->extension);
            $this->image_url = $ymd . '/'. $fileName . '.' . $this->featuredFile->extension;
            return true;
        } else {
            return false;
        }
    }

    public function beforeSave($insert)
    {
        if (parent::beforeSave($insert)) {
            if ($this->isNewRecord) {
              $this->date_added = date("YmdHis");
              $this->author =   Yii::$app->user->identity->id;
            } 
            else {
               $this->date_modified = date("YmdHis"); 
            }
            return true;
        }
        else{
            return false;
        }
    }

    public function saveToLog($event)
    {
       //assigning attributes
       // echo 'mail sent to admin using the event';
       $app_log_model = new AppLog();
       $app_log_model->log_time = date("YmdHis");
       $app_log_model->log_activity = 'Added a trending news';
       $app_log_model->user_id = Yii::$app->user->identity->id;
       $app_log_model->device = "1";
       if ($app_log_model->save()) {
           return true;
       } else {
           return $app_log_model->getErrors() ;
       }
    }
}

usage

public function actionCreate()
{
    $model = new TrendingNews();

    if ($model->load(Yii::$app->request->post())) {
        $model->featuredFile = UploadedFile::getInstance($model, 'featuredFile');

        if(isset($model->featuredFile)){
            $model->upload();
            $model->save(false);
        } else {
            // file is uploaded successfully
            $model->save();
            //$model->trigger(BlogArticle::EVENT_EDIT_ARTICLE);
        }
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('create', [
            'model' => $model,
        ]);
    }
}
public function actionUpdate($id)
{
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post())) {
        $model->featuredFile = UploadedFile::getInstance($model, 'featuredFile');
        if(isset($model->featuredFile)){
            $model->upload();
            $model->save(false);
        } else {
            $model->save();
        }
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('update', [
            'model' => $model,
        ]);
    }
}

the app log shows this

$_FILES = [
    'TrendingNews' => [
        'name' => [
            'featuredFile' => 'another_evento.jpg'
        ]
        'type' => [
            'featuredFile' => ''
        ]
        'tmp_name' => [
            'featuredFile' => ''
        ]
        'error' => [
            'featuredFile' => 3
        ]
        'size' => [
            'featuredFile' => 0
        ]
    ]
]

featuredFile is not a database field Is there something that is being done wrong? I am using xampp,tried on a live server and the issue is same

  • 写回答

1条回答 默认 最新

  • dongou3158 2018-01-28 22:16
    关注

    You are doing it wrong if you have to require a file input on insert and not on the update you should add a scenario for it so that it asks you to provide file when adding a new record only.

    Secondly you are using the same ActiveRecord model and added a custom attribute in it to be used as a file input and in the upload() function you are calling validate() and returning false if not validated but on the same time you are not checking for true or false in you controller action and on the very next line you are calling $model->save(false) with false so technically your script would never intimate the user if there is any validation error.

    The file should be uploaded after the record is saved not before saving the record so that there are no extra files uploaded in case of error, although you want the file to be required on insert so technically if file is not uploaded the record should not be saved, and for this reason we have transactions for database insertions you should use a transaction block to save the rcord and the file along with it

    You should only call the validate() method for file uploading if you have a separate FormModel for file uploading otherwise you should load the instance from the UploadedFile to the model field and call the $model->save() which will automatically validate the model before saving you should just check for the empty filename before uploading so that when you are updating any record and not submitting a file the previous file should be kept as is.

    You need to update your validation rules to the following first

    /**
         * @inheritdoc
         */
        public function rules()
        {
            return [
                [['headline_text','news_info', 'news_url', 'author', 'published', 'date_added', 'date_modified'], 'required'],
                [['headline_text', 'image_url', 'news_info', 'news_url'], 'string'],
                [['date_added', 'date_modified'], 'safe'],
                [['author'], 'string', 'max' => 20],
                [['published'], 'string', 'max' => 2],
                 [ [ 'featuredFile' ] , 'required' , 'on' => 'insert' ] ,
                [ [ 'featuredFile' ] , 'file' , 'extensions' => 'png, jpg' , 'maxSize' => 200000 , 'tooBig' => 'Limit is 500KB' ] ,
            ];
        }
    

    Change the upload() function to the following

     public function upload( $ymd , $fileName ) {
            if ( $this->featuredFile !== null && $this->featuredFile->name !== '' ) {
                $save_path = \Yii::getAlias ( '@backend' ) . '/web/uploads/' . $ymd . '/';
                if ( !file_exists ( $save_path ) ) {
                    mkdir ( $save_path , 0777 , true );
                }
    
                if ( !$this->featuredFile->saveAs ( $save_path . $fileName ) ) {
                    $this->addError ( 'featuredFile' , 'File could not be uploaded' );
                    throw new \Exception ( 'File upload error' );
                }
            }
        }
    

    Then add another method inside your model to remove old file in case of new file uploaded on update

     public function unlinkOldFile( $filename ) {
            if ( $filename !== '' ) {
                $save_path = \Yii::getAlias ( '@backend' ) . '/web/uploads/' . $filename;
                unlink ( $save_path );
            }
        }
    

    after that change your create and update actions to the following so that they use transation blocks for database operations

    public function actionCreate() {
        $model = new TrendingNews(['scenario'=>'insert']);
    
        if ( $model->load ( Yii::$app->request->post () ) ) {
    
            $model->featuredFile = UploadedFile::getInstance ( $model , 'featuredFile' );
    
            if ( $model->featuredFile !== null ) {
                $ymd = date ( "Ymd" );
                $fileName = Yii::$app->security->generateRandomString ( 20 ) . '.' . $model->featuredFile->extension;
                $model->image_url = $ymd . '/' . $fileName;
            }
    
    
            $transaction = Yii::$app->db->beginTransaction ();
    
            try {
                if ( !$model->save () ) {
                    throw new \Exception ( 'Error Occoured' );
                }
    
                $model->upload ( $ymd , $fileName );
    
                $transaction->commit ();
    
                return $this->redirect ( [ 'view' , 'id' => $model->id ] );
            } catch ( \Exception $ex ) {
                $transaction->rollBack ();
            }
        }
        return $this->render ( 'create' , [
            'model' => $model ,
            ] );
    }
    
    public function actionUpdate( $id ) {
        $model = $this->findModel ( $id );
    
        if ( $model->load ( Yii::$app->request->post () ) ) {
            $model->featuredFile = UploadedFile::getInstance ( $model , 'featuredFile' );
    
            //$oldFile = '';
            $oldFile = $model->image_url;
    
            if ( $model->featuredFile !== null ) {
    
                $ymd = date ( "Ymd" );
    
                $fileName = Yii::$app->security->generateRandomString ( 20 ) . '.' . $model->featuredFile->extension;
    
                $model->image_url = $ymd . '/' . $fileName;
    
            }
    
            $transaction = Yii::$app->db->beginTransaction ();
    
            try {
                if ( !$model->save () ) {
                    throw new \Exception ( 'Model error' );
                }
    
                $model->upload ( $ymd , $fileName );
    
                $model->unlinkOldFile ( $oldFile );
    
                $transaction->commit ();
                return $this->redirect ( [ 'view' , 'id' => $model->id ] );
            } catch ( Exception $ex ) {
                $transaction->rollBack ();
            }
        }
        return $this->render ( 'update' , [
            'model' => $model ,
            ] );
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥170 如图所示配置eNSP
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥15 键盘指令混乱情况下的启动盘系统重装