From a5fc5767304cf2d31dcc52c982b6d40ba1d7b795 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= <lucas@codeccoop.org>
Date: Sat, 10 Feb 2024 03:37:02 +0100
Subject: [PATCH] feat: post multipart

---
 includes/class-http-client.php | 62 +++++++++++++++++++++++++++++++
 includes/class-multipart.php   | 68 ++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+)
 create mode 100644 includes/class-multipart.php

diff --git a/includes/class-http-client.php b/includes/class-http-client.php
index 82dde6f..588d4b1 100644
--- a/includes/class-http-client.php
+++ b/includes/class-http-client.php
@@ -2,6 +2,8 @@
 
 namespace WPCT_HB;
 
+require_once 'class-multipart.php';
+
 class Http_Client
 {
     public static function get($url, $headers = [])
@@ -29,6 +31,31 @@ class Http_Client
         return Http_Client::do_request($url, $args);
     }
 
+    public static function post_multipart($url, $data = [], $files = [], $headers = [])
+    {
+        $url = Http_Client::get_endpoint_url($url);
+        $multipart = new Multipart();
+        $multipart->add_array($data);
+        foreach ($files as $name => $path) {
+            $filename = basename($path);
+            $filetype = wp_check_filetype($filename);
+            if (!$filetype['type']) {
+                $filetype['type'] = mime_content_type($path);
+            }
+
+            $multipart->add_file($name, $path, $filetype['type']);
+        }
+        $headers = Http_Client::req_headers($headers, 'POST', $url);
+        $headers['Content-Type'] = $multipart->content_type();
+        $args = [
+            'method' => 'POST',
+            'headers' => $headers,
+            'body' => $multipart->data()
+        ];
+
+        return Http_Client::do_request($url, $args);
+    }
+
     public static function put($url, $data = [], $headers = [])
     {
         $url = Http_Client::get_endpoint_url($url);
@@ -44,6 +71,31 @@ class Http_Client
         return Http_Client::do_request($url, $args);
     }
 
+    public static function put_multipart($url, $data = [], $files = [], $headers = [])
+    {
+        $url = Http_Client::get_endpoint_url($url);
+        $multipart = new Multipart();
+        $multipart->add_array($data);
+        foreach ($files as $name => $path) {
+            $filename = basename($path);
+            $filetype = wp_check_filetype($filename);
+            if (!$filetype['type']) {
+                $filetype['type'] = mime_content_type($path);
+            }
+
+            $multipart->add_file($name, $path, $filetype['type']);
+        }
+        $headers = Http_Client::req_headers($headers, 'PUT', $url);
+        $headers['Content-Type'] = $multipart->content_type();
+        $args = [
+            'method' => 'PUT',
+            'headers' => $headers,
+            'body' => $multipart->data()
+        ];
+
+        return Http_Client::do_request($url, $args);
+    }
+
     public static function delete($url, $headers = [])
     {
         $url = Http_Client::get_endpoint_url($url);
@@ -114,12 +166,22 @@ function wpct_hb_post($url, $data = [], $headers = [])
     return Http_Client::post($url, $data, $headers);
 }
 
+function wpct_hn_post_multipart($url, $data = [], $files = [], $headers = [])
+{
+    return Http_Client::post_multipart($url, $data, $files, $headers);
+}
+
 // Performs a put request to Odoo
 function wpct_hb_put($url, $data = [], $headers = [])
 {
     return Http_Client::put($url, $data, $headers);
 }
 
+function wpct_hb_put_multipart($url, $data = [], $files = [], $headers = [])
+{
+    return Http_Client::put_multipart($url, $data, $files, $headers);
+}
+
 // Performs a delete request to Odoo
 function wpct_hb_delete($url, $headers = [])
 {
diff --git a/includes/class-multipart.php b/includes/class-multipart.php
new file mode 100644
index 0000000..68d6568
--- /dev/null
+++ b/includes/class-multipart.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace WPCT_HB;
+
+class Multipart
+{
+    const EOL = "\r\n";
+
+    private $_data = '';
+    private $_mime_boundary;
+
+    public function __construct()
+    {
+        $this->_mime_boundary = md5(microtime(true));
+    }
+
+    private function _add_part_header()
+    {
+        $this->_data .= '--' . $this->_mime_boundary . self::EOL;
+    }
+
+    public function add_array($data, $prefix = '')
+    {
+        foreach ($data as $key => $value) {
+            if (is_array($value)) {
+                if ($prefix)
+                    $this->add_array($value, $prefix . '[' . $key . ']');
+                else
+                    $this->add_array($value, $key);
+            } else {
+                if ($prefix)
+                    $this->add_part($prefix . '[' . (is_numeric($key) ? '' : $key) . ']', $value);
+                else
+                    $this->add_part($key, $value);
+            }
+        }
+    }
+
+    public function add_part($key, $value)
+    {
+        $this->_add_part_header();
+        $this->_data .= 'Content-Disposition: form-data; name="' . $key . '"' . self::EOL;
+        $this->_data .= self::EOL;
+        $this->_data .= $value . self::EOL;
+    }
+
+    public function add_file($key, $filename, $type, $content = null)
+    {
+        $this->_add_part_header();
+        $this->_data .= 'Content-Disposition: form-data; name="' . $key . '"; filename="' . basename($filename) . '"' . self::EOL;
+        $this->_data .= 'Content-Type: ' . $type . self::EOL;
+        $this->_data .= 'Content-Transfer-Encoding: binary' . self::EOL;
+        $this->_data .= self::EOL;
+        if (!$content) $this->_data .= file_get_contents($filename) . self::EOL;
+        else $this->_data .= $content . self::EOL;
+    }
+
+    public function content_type()
+    {
+        return 'multipart/form-data; boundary=' . $this->_mime_boundary;
+    }
+
+    public function data()
+    {
+        // add the final content boundary
+        return $this->_data .= '--' . $this->_mime_boundary . '--' . self::EOL . self::EOL;
+    }
+}
-- 
GitLab