Làm cách nào để đặt dữ liệu biểu mẫu nhiều phần trong PHP?

Mặc dù chúng tôi triển khai PSR-18 bằng cách sử dụng Guzzle - thông qua HttPlug - tôi không muốn sử dụng các lớp cụ thể của Guzzle trong cơ sở mã của mình, vì điều đó có thể ngăn chúng tôi di chuyển suôn sẻ sang một bản tóm tắt HTTP khác. Và nó không tương thích với PSR-18

Gửi yêu cầu đăng bài

Có hai phương thức gửi dữ liệu với yêu cầu POST; . Đầu tiên là bản dịch cấu trúc GET sang phần thân POST

POST /a/post/url HTTP/1.1
Host: www.domain.ext
Content-Type: application/x-www-form-urlencoded

field=value&another+field=another+value

Phần thân này có thể đạt được thông qua PHP's

 method="post" action="https://..." enctype="multipart/form-data">
     type="text" name="name" />
     type="file" name="file" />

3

$body = http_build_query(
    ['field' => 'value', 'another field' => 'another value'], 
    '', 
    '&', 
    PHP_QUERY_RFC1738
);

Nhưng sử dụng phương pháp tạo yêu cầu POST này không cho phép gửi tệp đính kèm. Đối với những tình huống đó, bạn sẽ cần dùng đến multipart/form-data

nhiều phần/biểu mẫu dữ liệu

Tệp đính kèm không chỉ là dữ liệu (nhị phân) của tệp, nó là tên tệp, loại nội dung và thông tin meta có thể khác. Vì điều này cần một số hình thức cấu trúc, loại nội dung multipart/form-data đã được giới thiệu trong

 method="post" action="https://..." enctype="multipart/form-data">
     type="text" name="name" />
     type="file" name="file" />

6

Thực tế, những gì đoạn mã trên làm là tạo một yêu cầu giống như thế này

POST /a/post/url HTTP/1.1
Host: www.domain.ext
Content-Type: multipart/format-data; boundary="a.random.boundary"

--a.random.boundary
Content-Disposition: form-data; name="name"
Content-Length: 4

name
--a.random.boundary
Content-Disposition: form-data; name="file"; filename="screenshot.png"
Content-Type: image.png

{$screenshotData}
--a.random.boundary--

Và mặc dù điều này có thể thực hiện được khi sử dụng giao diện PSR-18 và PSR-15, nhưng nó yêu cầu một số kiến ​​thức về cách thức hoạt động của phần này trong thông số kỹ thuật HTTP

$boundary = 'a.random.boundary';
$request = (new RequestFactory())
    ->createRequest('POST', 'https://www.domain.ext/a/post/url')
    ->withHeader('Content-Type', "multipart/form-data; boundary=\"{$boundary}\"")
    ->withBody((new StreamFactory())->createStream("--{$boundary}" . "\r\n".
"Content-Disposition: form-data; name=\"name\"" . "\r\n" .
"\r\n" . 
"{$name}" . "\r\n" . 
"--{$boundary}" . "\r\n" .    
"Content-Disposition: form-data; name=\"file\"; filename=\"screenshot.php\"" . "\r\n" .
"Content-Type: image/png" . "\r\n" .
"\r\n" . 
"{$screenShotData}" . "\r\n" .
"--{$boundary}--"));

$this->httpClient->sendRequest($request);

Đây là rất nhiều công việc và nó có một vài cạm bẫy; . Nhưng khi tôi cố gắng gửi tệp tới JIRA, tôi nhận được thông báo lỗi là

 method="post" action="https://..." enctype="multipart/form-data">
     type="text" name="name" />
     type="file" name="file" />

7. Sau khi gỡ lỗi khá nhiều, tôi nhận thấy rằng JIRA (hoặc Java) yêu cầu
 method="post" action="https://..." enctype="multipart/form-data">
     type="text" name="name" />
     type="file" name="file" />

8 làm ký tự dòng mới

Bây giờ tôi có thể tạo một thư viện đẹp cho, nhưng tôi hơi lười, vì vậy tôi thường chuyển sang Packagist trước để xem có ai đã làm việc này chưa. Khi tìm kiếm Packagist cho các gói để xử lý tất cả những điều này cho tôi, bạn sẽ tìm thấy một số gói, nhưng các gói nổi bật là lượt tải xuống và các ngôi sao khôn ngoan.

 method="post" action="https://..." enctype="multipart/form-data">
     type="text" name="name" />
     type="file" name="file" />

9

Trình tạo luồng nhiều phần

Trình tạo luồng nhiều phần là một gói được tạo bởi nhóm cũng chịu trách nhiệm về HttPlug. Nó - như tên cho thấy - thực sự có nghĩa là xây dựng các luồng nhiều phần

Trình tạo cho Luồng PSR-7 nhiều phần. Trình tạo tạo các luồng độc lập từ bất kỳ triển khai PSR-7 nào

Để tạo yêu cầu tuân thủ PSR-7 với nội dung nhiều phần, chúng tôi cần tạo một phiên bản của trình tạo luồng nhiều phần

use Http\Message\MultipartStream\MultipartStreamBuilder;

$builder = new MultipartStreamBuilder($streamFactory);
$builder->addResource(
    'file', 
    fopen('/path/to/uploaded/file', 'r'), 
    [
        'filename' => 'filename.ext', 
        'headers' => ['Content-Type' => 'application/octet-stream']
    ]
);

$request = $requestFactory
    ->createRequest('POST', 'https://...')
    ->withHeader('Content-Type', 'multipart/form-data; boundary="' . $builder->getBoundary() . '"')
    ->withBody($builder->build());

$response = $client->sendRequest($request);    

Điều thú vị về thư viện này là nó trả về một thể hiện của

POST /a/post/url HTTP/1.1
Host: www.domain.ext
Content-Type: application/x-www-form-urlencoded

field=value&another+field=another+value
0. Ngẫu nhiên cùng một loại đối tượng
POST /a/post/url HTTP/1.1
Host: www.domain.ext
Content-Type: application/x-www-form-urlencoded

field=value&another+field=another+value
1 mong đợi

Nhược điểm của thư viện này là trình tạo luồng không phải là bất biến. Việc đưa nó vào ứng dụng của bạn có thể hơi phức tạp vì bộ chứa DI của bạn sẽ trả về một phiên bản mới của trình tạo luồng mỗi khi nó được đưa vào. Bên cạnh đó, tôi thích tiêm dựa trên giao diện, đó là sở thích cá nhân. Một cách giải quyết nhỏ cho vấn đề này có thể dễ dàng tạo ra thông qua một nhà máy


declare(strict_types=1);

use Http\Message\MultipartStream\MultipartStreamBuilder;
use Psr\Http\Message\StreamFactoryInterface;

final class MultipartStreamBuilderFactory implements MultipartStreamBuilderFactoryInterface
{
    /** @var StreamFactoryInterface */
    private $streamFactory;

    public function __construct(StreamFactoryInterface $streamFactory)
    {
        $this->streamFactory = $streamFactory;
    }

    public function build(): MultipartStreamBuilder
    {
        return new MultipartStreamBuilder($this->streamFactory);
    }
}

Bây giờ bạn không phải lo lắng về việc nhà máy bị chia sẻ giữa các tài nguyên khác nhau;

Kịch câm Symfony

Mặc dù nó không hiển thị trên tìm kiếm của Packagist nhưng Symfony cũng có một thành phần để làm việc này cho bạn. Mục tiêu chính của gói này là nhằm mục đích sử dụng để tạo thư MIME và chủ yếu tập trung vào thư email - MIME là từ viết tắt của Phần mở rộng thư Internet đa năng. Nhưng nó cũng có một tính năng - hiện được đánh dấu là thử nghiệm - có thể được sử dụng để tạo các tin nhắn nhiều phần; . Tính năng này được mô tả trong tài liệu của

Để gửi biểu mẫu có tải lên tệp, bạn có trách nhiệm mã hóa nội dung theo loại nội dung nhiều phần/biểu mẫu dữ liệu. Thành phần Symfony Mime làm cho nó có một vài dòng mã

[. ]

Tuyên bố này là một phần đúng; . Nhưng nếu bạn đang sử dụng ứng dụng khách tuân thủ PSR-18 thì cần thêm một vài dòng nữa

use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\Multipart\FormDataPart;

$formFields = [
    'regular_field' => 'some value',
    'file_field' => DataPart::fromPath('/path/to/uploaded/file'),
];

$request = $requestFactory
    ->createRequest('POST', 'https://...');

$formData = new FormDataPart($formFields);
$preparedHeaders = $formData->getPreparedHeaders();
foreach ($preparedHeaders->getNames() as $header) {
    $request = $request->withHeader(
        $header, 
        $preparedHeaders->get($header)->getBodyAsString()
    );
}

$request = $request->withBody(
    $streamFactory->createStream($formData->bodyToString())
);

$response = $client->sendRequest($request);

Phần kết luận

Bạn có thể tự tạo một thông báo nhiều phần, nhưng bạn có thể gặp phải các sự cố không mong muốn - chẳng hạn như ký tự dòng mới không tương thích. Rất có thể bạn không phải là người đầu tiên gặp phải tình huống như vậy và rất có thể đó đã là một vấn đề được giải quyết. Một ví dụ về điều này là

 method="post" action="https://..." enctype="multipart/form-data">
     type="text" name="name" />
     type="file" name="file" />

9

Hai thư viện trừu tượng máy khách HTTP chính - Guzzle và Symfony HttpClient - có nhiều chức năng tích hợp sẵn mà PSR-18 không cung cấp. Điều này làm cho khi sử dụng PSR-18, bạn có thể cần có thêm kiến ​​thức về cách HTTP thực sự hoạt động. Cá nhân tôi không nghĩ rằng đây là một điều xấu. Đây là những cơ hội mới vì giờ đây chúng ta có thể sử dụng các ứng dụng khách chỉ thực hiện các yêu cầu và chuyển tất cả các chức năng bổ sung sang các gói riêng biệt chịu trách nhiệm duy nhất và bạn chỉ cần thêm vào cơ sở mã của mình nếu bạn thực sự sử dụng chúng

Làm cách nào để sử dụng dữ liệu biểu mẫu nhiều phần trong php?

Tạo biểu mẫu HTML . enctype="multipart/form-data" . Nó chỉ định loại nội dung nào sẽ được sử dụng khi gửi biểu mẫu.

Làm cách nào để gửi tệp ở dạng dữ liệu trong php?

Create a PHP file and put the below code and save it. Store form data in . txt file
Enter Your Text Here:

Dữ liệu biểu mẫu nhiều phần được gửi như thế nào?

Trong nhiều phần, mỗi trường được gửi có loại nội dung, tên tệp và dữ liệu được phân tách bằng ranh giới với trường khác . Không cần mã hóa dữ liệu vì ranh giới duy nhất. Dữ liệu nhị phân được gửi như nó là. Máy chủ đọc cho đến khi chuỗi ranh giới tiếp theo.

Làm cách nào để tạo dữ liệu biểu mẫu trong php?

Chúng ta có thể tạo và sử dụng biểu mẫu trong PHP. Để lấy dữ liệu biểu mẫu, chúng ta cần sử dụng PHP superglobals $_GET và $_POST. .
$name=$_POST["name"];//nhận giá trị trường tên trong biến $name
$password=$_POST["password"];//nhận giá trị trường mật khẩu trong biến $password
tiếng vang "Xin chào. $name, mật khẩu của bạn là. $mật khẩu";