零基础搭建yii2图片上传模块需绕过gii陷阱、路径权限报错和csrf拦截三类卡点;模型须建在common/models/下并重写tablename()返回带前缀表名;表单enctype必须为multipart/form-data且禁用ajax与客户端验证;通过配置urlmanager路由实现http://localhost/upload访问。

零基础搭建一个能上传图片并存入数据库的Yii2文件上传模块,需要绕过Gii生成器的默认陷阱、避开路径权限报错、跳过CSRF拦截导致表单提交失败这三类高频卡点。
创建上传专用模型
在 common/models/ 下新建 UploadImage.php,不要放在 backend/models/ 或 frontend/models/ —— 否则多端调用时会因命名空间冲突报错。
写入以下内容,注意 【必须重写 tableName() 返回带前缀的表名】,否则 Yii2 默认按类名推导为 upload_image,而你实际建的表可能是 images:
use yii\db\ActiveRecord;
class UploadImage extends ActiveRecord
{
public static function tableName()
{
return '{{%images}}'; // 用 {{%}} 包裹,兼容表前缀配置
}
public function rules()
{
return [
[['url', 'module'], 'required'],
[['status'], 'integer', 'default' => 1],
[['url'], 'string', 'max' => 255],
[['module'], 'string', 'max' => 15],
];
}
}
配置上传根路径别名
打开 common/config/bootstrap.php,在文件末尾追加一行:
Yii::setAlias('@uploadPath', dirname(dirname(__DIR__)) . '/frontend/web/uploads');
这行代码定义了物理存储路径。如果漏掉,后续 saveAs() 会抛出 “Directory not writable” 异常——因为插件根本找不到可写的目录。
再打开 frontend/config/params.php,添加:'assetDomain' => 'http://localhost/yii2/advanced/frontend/web/uploads',
这个域名用于生成图片访问URL,【必须与 Web 服务器实际监听地址完全一致】,否则预览图加载404。
控制器中实现上传逻辑
在 frontend/controllers/UploadController.php 中写入:
namespace frontend\controllers;
use common\models\UploadImage;
use yii\web\Controller;
use yii\web\UploadedFile;
use Yii;
class UploadController extends Controller
{
public function actionIndex()
{
$model = new UploadImage();
if ($this->request->isPost) {
$image = UploadedFile::getInstance($model, 'url');
if ($image && $model->validate()) {
$dir = Yii::getAlias('@uploadPath') . '/' . date('Ymd');
@mkdir($dir, 0777, true);
$fileName = time() . '_' . mt_rand(1000, 9999) . '.' . $image->extension;
$fullPath = $dir . '/' . $fileName;
if ($image->saveAs($fullPath)) {
$model->url = str_replace(Yii::getAlias('@uploadPath'), '', $fullPath);
$model->module = 'article';
$model->save(false);
return $this->redirect(['view', 'id' => $model->id]);
}
}
}
return $this->render('index', ['model' => $model]);
}
public function actionView($id)
{
$model = UploadImage::findOne($id);
return $this->render('view', ['model' => $model]);
}
}
视图中嵌入上传表单
在 frontend/views/upload/index.php 中写入:
use yii\helpers\Html;
?>
上传新图片
'options' => ['enctype' => 'multipart/form-data'],
'enableAjaxValidation' => false,
'enableClientValidation' => false,
]); ?>
= $form->field($model, 'url')->fileInput(['accept' => 'image/*']) ?>
= Html::submitButton('上传', ['class' => 'btn btn-primary']) ?>
关键点:表单 enctype 必须设为 multipart/form-data,否则 UploadedFile::getInstance() 拿不到二进制流;【禁用 Ajax 验证和客户端验证】,否则上传字段会因无值被前端拦截,连 POST 请求都发不出去。
注册路由并测试访问
打开 frontend/config/main.php,在 components 数组同级位置添加:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'upload' => 'upload/index',
'upload/view/
],
],
确保 Web 服务器 DocumentRoot 指向 frontend/web/,然后浏览器访问 http://localhost/upload 即可看到上传表单。











