多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
{% raw %} # Symfony 上传文件 > 原文: [http://zetcode.com/symfony/uploadfile/](http://zetcode.com/symfony/uploadfile/) Symfony 上传文件教程显示了如何在 Symfony 应用中上传文件。 在示例中,我们使用普通形式发送文件; 我们不使用表单构建器。 ## Symfony Symfony 是一组可重用的 PHP 组件和一个用于 Web 项目的 PHP 框架。 Symfony 于 2005 年发布为免费软件。Symfony 的原始作者是 Fabien Potencier。 Symfony 受 Spring 框架和 Ruby on Rails 的极大启发。 ## 上传文件 为了上传文件,`form`必须将`enctype`设置为`multipart/form-data`,并且`input`的类型设置为`file`。 同样,在 PHP 的`php.ini`中,文件上传由`file_uploads`选项控制。 ## Symfony 文件上传示例 在示例中,我们有一个带有一个输入字段的简单表单:要上传的文件。 提交表单后,我们验证 CSRF 令牌并加载图像,检索其名称,并将文件存储在`var`目录中。 ### 创建一个 Symfony 项目并安装包 composer 工具用于生成 Symfony 骨架项目并安装必要的包。 ```php $ composer create-project symfony/skeleton upload $ cd upload ``` 我们创建一个新的 Symfony 项目,然后转到项目目录。 ```php $ composer require maker annotations twig ``` 我们为 Web 开发安装了三个基本的 Symfony 包:`annotations`,`maker`和`twig`。 这些是生成路由,控制器和模板所必需的。 ```php $ composer require symfony/security-csrf $ composer require symfony/monolog-bundle ``` 跨站点请求伪造需要`security-csrf`包,而日志记录则需要`monolog-bundle`包。 ```php $ composer require server --dev $ composer require symfony/profiler-pack --dev ``` 在开发阶段,我们还安装了内置服务器和分析器。 ### 构建 Symfony 应用 我们定义了要上传图像的目录。 `config/services.yaml` ```php parameters: upload_dir: '../var/uploads' services: # default configuration for services in *this* file _defaults: autowire: true autoconfigure: true public: false bind: $uploadDir: '%upload_dir%' ``` 我们定义一个参数,其中包含应将图像上传到的目录的名称。 `upload_dir`参数绑定到可以注入的`$uploadDir`变量。 ```php $ php bin/console make:controller HomeController ``` 我们创建一个`HomeController`。 控制器将表单发送给客户端。 `src/Controller/HomeController.php` ```php <?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; class HomeController extends AbstractController { /** * @Route("/", name="home") */ public function index() { return $this->render('home/index.html.twig'); } } ``` 这是一个简单的控制器,可将包含 Web 表单的视图发送给用户。 `templates/home/index.html.twig` ```php {% extends 'base.html.twig' %} {% block title %}Home page{% endblock %} {% block body %} <form action="doUpload" method="post" enctype="multipart/form-data"> <input type="hidden" name="token" value="{{ csrf_token('upload') }}" /> <div> <label>File to upload:</label> <input type="file" name="myfile"> </div> <button type="submit">Send</button> </form> {% endblock %} ``` 此视图创建一个表单。 它定义了`multipart/form-data`编码类型和`file`输入。 此外,它还具有 CSRF 隐藏输入令牌。 ```php $ php bin/console make:controller UploadController ``` 我们创建一个`UploadController`来响应表单提交。 我们不需要为该控制器生成的树枝模板; 因此,我们将其删除。 `src/Controller/UploadController.php` ```php <?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use App\Service\FileUploader; use Psr\Log\LoggerInterface; class UploadController extends AbstractController { /** * @Route("/doUpload", name="upload") */ public function index(Request $request, string $uploadDir, FileUploader $uploader, LoggerInterface $logger) { $token = $request->get("token"); if (!$this->isCsrfTokenValid('upload', $token)) { $logger->info("CSRF failure"); return new Response("Operation not allowed", Response::HTTP_BAD_REQUEST, ['content-type' => 'text/plain']); } $file = $request->files->get('myfile'); if (empty($file)) { return new Response("No file specified", Response::HTTP_UNPROCESSABLE_ENTITY, ['content-type' => 'text/plain']); } $filename = $file->getClientOriginalName(); $uploader->upload($uploadDir, $file, $filename); return new Response("File uploaded", Response::HTTP_OK, ['content-type' => 'text/plain']); } } ``` 在`UploadController`中,我们检查 CSRF 令牌,从请求中获取文件,然后调用上载器服务`upload()`方法。 ```php public function index(Request $request, string $uploadDir, FileUploader $uploader, LoggerInterface $logger) { ``` 我们注入了请求对象,上传目录参数,`FileUploader`服务和记录器。 ```php $token = $request->get("token"); if (!$this->isCsrfTokenValid('upload', $token)) { $logger->info("CSRF failure"); return new Response("Operation not allowed", Response::HTTP_BAD_REQUEST, ['content-type' => 'text/plain']); } ``` 我们检索令牌并使用`isCsrfTokenValid()`方法对其进行验证。 如果验证失败,我们将记录事件并发送简单的响应`"Operation not allowed"`和`Response::HTTP_BAD_REQUEST`响应代码。 ```php $file = $request->files->get('myfile'); if (empty($file)) { return new Response("No file specified", Response::HTTP_UNPROCESSABLE_ENTITY, ['content-type' => 'text/plain']); } ``` 我们检查用户是否使用`empty()`方法指定了格式的任何文件。 如果输入字段为空,我们将使用`Response::HTTP_UNPROCESSABLE_ENTITY`响应代码将纯文本`"No file specified"`发送回客户端。 ```php $filename = $file->getClientOriginalName(); ``` 我们使用`getClientOriginalName()`获得文件名。 ```php $uploader->upload($uploadDir, $file, $filename); ``` 我们调用上载器服务`upload()`方法,该方法将文件移动到所选目录。 我们向该方法传递目录名,文件数据和文件名。 ```php return new Response("File uploaded", Response::HTTP_OK, ['content-type' => 'text/plain']); ``` 如果一切正常,我们将使用`Response::HTTP_OK`响应代码将简单的消息`"File uploaded"`发送回客户端。 `src/Service/FileUploader.php` ```php <?php namespace App\Service; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Psr\Log\LoggerInterface; class FileUploader { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function upload($uploadDir, $file, $filename) { try { $file->move($uploadDir, $filename); } catch (FileException $e){ $this->logger->error('failed to upload image: ' . $e->getMessage()); throw new FileException('Failed to upload file'); } } } ``` `FileUploader`服务使用`move()`将文件移动到上传目录。 当操作失败时,我们抛出`FileException`。 这将导致生成错误页面。 `templates/home/index.html.twig` ```php {% extends 'base.html.twig' %} {% block title %}Home page{% endblock %} {% block body %} <form action="doUpload" method="post" enctype="multipart/form-data"> <input type="hidden" name="token" value="{{ csrf_token('upload') }}" /> <div> <label>File to upload:</label> <input type="file" name="myfile"> </div> <button type="submit">Send</button> </form> {% endblock %} ``` 该模板包含表单。 `templates/bundles/TwigBundle/Exception/error.html.twig` ```php {% extends "base.html.twig" %} {% block title %} Problem detected {% endblock %} {% block body %} <div> <p> There was a problem: {{ exception.message }} </p> </div> {% endblock %} ``` 我们覆盖了 Twig 的`error.html.twig`模板。 我们需要创建此确切的目录路径:`templates`目录内的`bundles/TwigBundle/Exception/`。 发生`FileException`时,将为用户生成此错误视图。 `templates/base.html.twig` ```php <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{% block title %}Welcome!{% endblock %}</title> {% block stylesheets %}{% endblock %} </head> <body> {% block body %}{% endblock %} {% block javascripts %}{% endblock %} </body> </html> ``` 这是基本的 Twig 模板。 在本教程中,我们展示了如何在 Symfony 应用中上传文件。 您可能也会对以下相关教程感兴趣: [Symfony 简介](/symfony/intro/), [Symfony DBAL 教程](/symfony/dbal/), [Symfony 表单教程](/symfony/form/), [Symfony 服务教程](/symfony/service/) , [Symfony 验证教程](/symfony/validation/), [PHP 教程](/lang/php/)。 {% endraw %}