Permintaan POST, konten komposit (multipart / form-data)

POST multipart / form-data


Memposting Data Komposit



Dalam kehidupan programmer mana pun, masalah muncul yang menangkap seseorang. Saya tidak suka solusi standar dan hanya itu! Dan terkadang terjadi bahwa solusi standar tidak berfungsi karena beberapa alasan. Beberapa orang mengabaikan tugas-tugas semacam itu, sementara yang lain suka menyelesaikannya. Anda bahkan dapat mengatakan bahwa mereka menemukannya sendiri. Salah satu tugas tersebut adalah mengirim file atau beberapa file menggunakan metode POST.



Beberapa orang mungkin akan mengatakan bahwa tugas ini sama sekali bukan tugas. Bagaimanapun, ada perpustakaan CURL yang luar biasa yang cukup sederhana dan memecahkan masalah ini dengan mudah! Tapi jangan terburu-buru. Ya, CURL adalah pustaka yang hebat, ya, ia memuat file, tetapi ... Seperti yang Anda ketahui, CURL memiliki sedikit fitur - file harus ditempatkan di hard drive Anda!



Sekarang mari kita bayangkan situasi berikut, Anda sedang membuat file secara dinamis atau sudah ada di memori dan Anda perlu mengirimkannya menggunakan metode POST ke server Web jarak jauh. Lalu apa yang terjadi? Apakah Anda perlu menyimpannya sebelum mengirimnya? Inilah yang akan dilakukan oleh 90% programmer. Mengapa mencari masalah yang tidak perlu jika solusinya terletak di permukaan? Tapi kami tidak bersama Anda dari 90% ini! Kami lebih baik, kami bisa menyelesaikan masalah apa pun. Mengapa kita membutuhkan tindakan ekstra? Pertama, ia menggunakan sistem file hard drive yang tidak cepat. Kedua, kami mungkin tidak memiliki akses ke sistem file, atau terlalu sedikit ruang yang dialokasikan di sana.



Lalu bagaimana kita bisa mengatasi masalah ini? Untuk melakukan ini, Anda perlu melihat bagaimana data sebenarnya dikirim dengan metode POST. Satu-satunya solusi adalah mentransfer file sebagai permintaan gabungan menggunakanmultipart / form-data . Teknik ini didokumentasikan dengan baik di RFC7578 . Mari kita lihat bagaimana isi permintaan POST multipart / form-data akan terlihat seperti:

POST /form.html HTTP / 1.1
Host: server.com
Perujuk: http://server.com/form.html
Agen Pengguna: Mozilla
Jenis-Konten: multi-bagian / data-formulir; batas = ------------- 573cf973d5228
Panjang Konten: 288
Koneksi: tetap hidup
Keep-Alive: 300
(baris kosong)
(bukaan hilang)
--------------- 573cf973d5228
Isi-Disposisi: form-data; name = "field"

teks
--------------- 573cf973d5228
Content-Disposition: formulir-data; name = "file"; filename = "sample.txt"
Jenis Konten: teks / biasa

File konten
--------------- 573cf973d5228--






Body kita terdiri dari dua bagian, pada bagian pertama kita berikan nilai form field name = "field" sama dengan: teks . Di bagian kedua, kami meneruskan nama bidang = "file" dengan konten file filename = "sample.txt": File konten . Di header, kami menunjukkan format konten permintaan POST - Content-Type: multipart / form-data , string pemisah bagian: boundary = ------------- 573cf973d5228 dan panjang pesan - Panjang-Konten: 288 .



Faktanya, tetaplah menulis program yang mengimplementasikan metode ini. Karena kami adalah orang pintar dan tidak menulis hal yang sama ratusan kali dalam proyek yang berbeda, kami akan mengatur semuanya dalam bentuk kelas yang menerapkan metode ini. Selain itu, mari kembangkan untuk opsi berbeda untuk mengirim file dan elemen formulir sederhana. Dan untuk membedakan keberadaan file di antara larik data POST, mari buat file terpisah - wadah dengan konten file dan datanya (nama dan ekstensi). Jadi, akan terlihat seperti ini:



<pre>
class oFile
{
 private $name;
 private $mime;
 private $content;

 public function __construct($name, $mime=null, $content=null)
 {
// ,  $content=null,    $name -   
  if(is_null($content))
  {
//     (,    )
   $info = pathinfo($name);
//            
   if(!empty($info['basename']) && is_readable($name))
    {
     $this->name = $info['basename'];
//  MIME  
     $this->mime = mime_content_type($name);
//  
     $content = file_get_contents($name);
//      
     if($content!==false) $this->content = $content;
       else throw new Exception('Don`t get content - "'.$name.'"');
    } else throw new Exception('Error param');
  } else
     {
//   
      $this->name = $name;
//      MIME    
      if(is_null($mime)) $mime = mime_content_type($name);
//   MIME 
      $this->mime = $mime;
//      
      $this->content = $content;
     };
 }

//    
 public function Name() { return $this->name; }

//    MIME
 public function Mime() { return $this->mime; }

//    
 public function Content() { return $this->content; }

};
</pre>


Sekarang, kelas itu sendiri untuk membentuk multipart / form-data body untuk permintaan POST:



<pre>
class BodyPost
 {
//    
  public static function PartPost($name, $val)
  {
   $body = 'Content-Disposition: form-data; name="' . $name . '"';
//     oFile
   if($val instanceof oFile)
    {
//   
     $file = $val->Name();
//  MIME  
     $mime = $val->Mime();
//   
     $cont = $val->Content();

     $body .= '; filename="' . $file . '"' . "\r\n";
     $body .= 'Content-Type: ' . $mime ."\r\n\r\n";
     $body .= $cont."\r\n";
    } else $body .= "\r\n\r\n".urlencode($val)."\r\n";
   return $body;
  }

//    POST    
  public static function Get(array $post, $delimiter='-------------0123456789')
  {
   if(is_array($post) && !empty($post))
    {
     $bool = false;
//       
     foreach($post as $val) if($val instanceof oFile) {$bool = true; break; };
     if($bool)
      {
       $ret = '';
//     ,   POST 
       foreach($post as $name=>$val)
        $ret .= '--' . $delimiter. "\r\n". self::PartPost($name, $val);
        $ret .= "--" . $delimiter . "--\r\n";
      } else $ret = http_build_query($post);
    } else throw new \Exception('Error input param!');
   return $ret;
  }
};
</pre>


Kelas ini terdiri dari beberapa metode. Metode PartPost membentuk bagian terpisah dari permintaan gabungan, dan metode Dapatkan menggabungkan bagian-bagian ini dan membentuk isi permintaan POST dalam format - multipart / form-data.



Kami sekarang memiliki kelas generik untuk mengirim isi permintaan POST. Tetap menulis program yang menggunakan kelas ini untuk mengirim file ke server Web jarak jauh. Mari gunakan perpustakaan CURL:



//  -  
include "ofile.class.php";
//      POST 
include "bodypost.class.php";

//       POST 
$delimiter = '-------------'.uniqid();

//   oFile  
$file = new oFile('sample.txt', 'text/plain', 'Content file');

//   POST 
$post = BodyPost::Get(array('field'=>'text', 'file'=>$file), $delimiter);

//   CURL
$ch = curl_init();

//      
curl_setopt($ch, CURLOPT_URL, 'http://server/upload/');
// ,    POST 
curl_setopt($ch, CURLOPT_POST, 1);
//   POST 
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

/*     :
     Content-Type -  , 
     boundary -   
     Content-Length -    */
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data; boundary=' . $delimiter,
'Content-Length: ' . strlen($post)));

//  POST    Web 
curl_exec($ch);


Jika CURL tidak cocok, maka pustaka ini dapat digunakan untuk mengirim melalui soket. Nah, sebenarnya tautan ke sumber:





Pada artikel berikutnya saya akan memberi Anda informasi tentang cara mengunduh file besar dari server Web jarak jauh dalam beberapa aliran dengan kecepatan yang ditentukan. Kepada semua orang yang membaca sampai akhir, terima kasih atas perhatiannya!



All Articles