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:
- situs dokumentasi php.net
- Artikel CURL: permintaan POST, konten komposit
- wikipedia: multipart / form-data
- RFC7578
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!