PHP代碼篇(五)--如何將圖片文件上傳到另外一臺服務上

来源:https://www.cnblogs.com/camg/archive/2019/08/26/11410109.html
-Advertisement-
Play Games

說,我有一個需求,就是一個臨時功能。由於工作開發問題,我們有一個B項目,需要有一個商品添加的功能,涉及到添加商品內容,比如商品名字,商品描述,商品庫存,商品圖片等。後臺商品添加的介面已經寫完了,但是問題是目前沒有後臺頁面,就是產品還沒有出後臺詳細頁面。前端已經完備了,上線了。後臺還需要工作時間處理。 ...


  說,我有一個需求,就是一個臨時功能。由於工作開發問題,我們有一個B項目,需要有一個商品添加的功能,涉及到添加商品內容,比如商品名字,商品描述,商品庫存,商品圖片等。後臺商品添加的介面已經寫完了,但是問題是目前沒有後臺頁面,就是產品還沒有出後臺詳細頁面。前端已經完備了,上線了。後臺還需要工作時間處理。所以目前的處理方法是在我們已經存在的A項目後臺中,添加一個對B項目添加商品的功能。

  

  一、當下問題

  1、在我們已有的A項目中,新增一個添加商品的功能,這個本來是沒有什麼問題的,因為目前A項目中本身就已經連接了B項目的資料庫,所以商品屬性的新增和修改都沒什麼問題。主要是商品圖片的上傳這裡,有點問題。B項目已經對外提供了上傳圖片的介面,但是由於我確實對前端不是特別熟悉。所以在A項目中的後臺JS中調取B項目的上傳圖片的介面時,一直提示"CORS",這裡應該是存在一個跨域的問題,雖然我PHP介面端已經對跨域做了處理(入口文件處),但是貌似JS這邊也需要相應的調整。

// [ 應用入口文件 ]
//入口文件index.php  
namespace think;

// 載入基礎文件
require __DIR__ . '/thinkphp/base.php';

// 支持事先使用靜態方法設置Request對象和Config對象
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type,XFILENAME,XFILECATEGORY,XFILESIZE,authorization");
// 執行應用並響應
Container::get('app')->bind('api')->run()->send();

   2、無奈小白JS功底不夠扎實,所以我這邊準備通過A項目中調取後臺PHP介面,然後通過在PHP代碼中接受web端參數,然後再轉發,調取B項目中上傳圖片的介面,試圖完成功能。於是先通過Postman介面工具測試了一下B項目上傳圖片的介面是否有效。如圖3,發現確實沒有什麼問題,於是就準備如此處理。

 

 

  3、但是實際是,在調取時,我們常用的傳參數方式是GET或者POST方式,但是我們知道文件上傳是通過$_FILES接受,下麵是B項目的上傳圖片的控制器代碼(用的是TP5.1),接受是通過內置的file方式。

    /**上傳圖片
     * @param Request $request
     */
    public function uploadImg(Request $request){
        $file = $request->file('image');
        $type = $request->post('type', 0);
        // 移動到框架應用根目錄/uploads/ 目錄下
        $upload_path = config('common.upload_path');
        switch ($type) {
            case 1://門店
                $path = $upload_path['shop_img'];
                break;
            case 2://投票活動
                $path = $upload_path['vote_img'];
                break;
            case 3://投票活動參賽圖片
                $path = $upload_path['vote_contestant_img'];
                break;
            case 4://會員店鋪logo圖片
                $path = $upload_path['member_shop'];
                break;
            case 5://自營商品圖片
                $path = $upload_path['self_goods'];
                break;
            default:
                $path = $upload_path['common'];
                break;
        }
        $save_path = env('root_path').$path;
        $info = $file->validate(['ext'=>'jpg,jpeg,png,gif'])->move($save_path);
        if($info){
            $return = [
                'extension' => $info->getExtension(),
                'image_path' => $path.$info->getSaveName(),
                'image_name' => $info->getFilename(),
            ];
            $this->apiResult(CustomError::OPERATION_SUCCSESS, $return);
        }else{
            $this->apiResult(CustomError::OPERATION_FAILED, [],  $file->getError());
        }
    }

   4、所以在轉發A項目web端傳來的,文件內容,就有點不知所措了。該死,該死。

//文件上傳接受參數
array(1) {
  ["file_upload"] => array(5) {
    ["name"] => string(8) "timg.jpg"
    ["type"] => string(10) "image/jpeg"
    ["tmp_name"] => string(22) "C:\Windows\php73CE.tmp"
    ["error"] => int(0)
    ["size"] => int(355565)
  }
}

   5、所以按剛纔設想的,簡單做下轉發還是不行,這裡面參數的傳輸方式應該還有另外一種,就是文件的類型。鑒於是通過Postman方式上傳成功,這個工具確實很推薦多多學習,他不僅作為一個第三方中間為我們驗證介面是否可用,更給我們提供了調取介面的各種代碼Damo,如圖3中標識的Code處,就是獲取Damo的按鈕。我們點擊可以看見Postman給我提供了三種,調取介面的方式。

<?php
//1、HttpRequest 發送http請求
$request = new HttpRequest();
$request->setUrl('http://jszapi.dev.jingjinglego.com/index.php/index/uploadImg');
$request->setMethod(HTTP_METH_POST);

$request->setHeaders(array(
  'cache-control' => 'no-cache',
  'Connection' => 'keep-alive',
  'Content-Length' => '39091',
  'Content-Type' => 'multipart/form-data; boundary=--------------------------296608706222243058746908',
  'Accept-Encoding' => 'gzip, deflate',
  'Host' => 'jszapi.dev.jingjinglego.com',
  'Postman-Token' => 'dc010150-b166-4dec-a33f-959a65c91c71,be7315cb-ae21-404f-89fa-dddf5973eb3a',
  'Cache-Control' => 'no-cache',
  'Accept' => '*/*',
  'User-Agent' => 'PostmanRuntime/7.15.2',
  'content-type' => 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
));

$request->setBody('------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="image"; filename="785da43beca5a474.jpg"
Content-Type: image/jpeg


------WebKitFormBoundary7MA4YWxkTrZu0gW--');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

 

<?php
//2、pecl_http  需要開啟PECL HTTP 擴展
$client = new http\Client;
$request = new http\Client\Request;

$body = new http\Message\Body;
$body->addForm(NULL, array(
  array(
    'name' => 'image',
    'type' => null,
    'file' => '/E:/MyBooks/網站圖標/網站素材/785da43beca5a474.jpg',
    'data' => null
  )
));

$request->setRequestUrl('http://jszapi.dev.jingjinglego.com/index.php/index/uploadImg');
$request->setRequestMethod('POST');
$request->setBody($body);

$request->setHeaders(array(
  'cache-control' => 'no-cache',
  'Connection' => 'keep-alive',
  'Content-Length' => '39091',
  'Content-Type' => 'multipart/form-data; boundary=--------------------------296608706222243058746908',
  'Accept-Encoding' => 'gzip, deflate',
  'Host' => 'jszapi.dev.jingjinglego.com',
  'Postman-Token' => 'dc010150-b166-4dec-a33f-959a65c91c71,3216cc22-be61-4d4b-8d41-c5178848b54f',
  'Cache-Control' => 'no-cache',
  'Accept' => '*/*',
  'User-Agent' => 'PostmanRuntime/7.15.2'
));

$client->enqueue($request)->send();
$response = $client->getResponse();

echo $response->getBody();
<?php
//3、cURL  是一個非常強大的開源庫,支持很多協議,包括HTTP、FTP、TELNET等,我們使用它來發送HTTP請求。
//它給我們帶來的好處是可以通過靈活的選項設置不同的HTTP協議參數,並且支持HTTPS。CURL可以根據URL首碼是“HTTP” 還是“HTTPS”自動選擇是否加密發送內容。
$curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "http://jszapi.dev.jingjinglego.com/index.php/index/uploadImg", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"image\"; filename=\"785da43beca5a474.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--", CURLOPT_HTTPHEADER => array( "Accept: */*", "Accept-Encoding: gzip, deflate", "Cache-Control: no-cache", "Connection: keep-alive", "Content-Length: 39091", "Content-Type: multipart/form-data; boundary=--------------------------296608706222243058746908", "Host: jszapi.dev.jingjinglego.com", "Postman-Token: dc010150-b166-4dec-a33f-959a65c91c71,982e059e-bd8b-4db9-83c4-3fd52c8ed82f", "User-Agent: PostmanRuntime/7.15.2", "cache-control: no-cache", "content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" ), )); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; }

  6、如上面3個代碼片段,但是後來驗證後,發現1/3的參數,不知道是怎麼傳輸的,2的參數很容易看懂,但是運用的話需要開啟擴展,這個目前不太合適,所以┭┮﹏┭┮。

 

二、寫在心裡

  1、這個上傳的問題,確實卡住了,感覺有點難過。其實每次都會遇見一個自己的困難,經常遇見,周末下午的時候,我在家打開電腦,打來遠程,準備登陸下ftp拉下代碼,發現一直連不上,心裡那個煩啊。但是還是通過遠程工具(嚮日葵),將代碼拉下來了。想這個圖片上傳到底怎麼弄了,之前也看過,關於通過ftp的方式上傳圖片,但是後來查看了相關文章需要在php.ini中開啟,所以也作罷。

#開啟ftp擴展支持
extension=php_ftp.dll

  2、經常遇見困難,經常覺得自己很LOW但是,已經工作了這麼久,發現其實問題最後又都解決了,但是現在回想,卻忘了到底是怎麼解決的,所以寫這個博文主要也是想記錄下。一直到下午4點多,深圳的天氣今年悶熱居多,中午我已經昧著良心午休了1個小時,所以現在到現在心裡還有些許內疚,唉。

  3、但是還是找不到解決的方法,頭疼的厲害,好熱。怎麼辦,我決定靠在椅子上休息下,於是我還是決定躺在沙發上睡會。剛躺下,想著這怎麼辦呢。

  -----------------------base64---------------------------華麗的分割線

  我突然想到了base64這個讀起來,朗朗上口的函數,對如果現將圖片轉換成base64字元串,再通過POST方式傳送給B項目,然後再B項目中對字元串進行解碼,生成圖片,保存到B項目,然後返回圖片路徑,不就可以了嗎。於是我有推了一遍,發現沒有疏忽。於是覺得應該是解決了。

 

三、解決圖片上傳問題

  1、A接受web傳來圖片臨時文件,

    #上傳圖片京手指 1:圖片保留到本地
    public function uploadJszImg()
    {$path = config('business.jsz_file_tem');
        $file = request()->file('file_upload');
        $info = $file->validate(['ext'=>'jpg,jpeg,png,gif'])->move($path);//圖片保存到本地
        $img_one = $path.$info->getSaveName();//圖片路徑
        $img_base = imgToBase64($img_one);//獲取圖片base64編碼格式
        deleteFileWay($path);//刪除臨時文件
        $url = config('business.jsz_api')['baseImg'];
        $data = [
            'base_string'=> $img_base,
            'path' => 'upload/goods_img',
        ];
        $res = http_api($url,$data,1);
        $res = json_decode($res,true);
        if($res['data']){
            $return = ['code'=>1,'message'=>'成功','data'=>'jszapi.dev.jingjinglego.com'.$res['data']];
        }else{
            $return = ['code'=>0,'message'=>'失敗'];
        }
        return $return;
    }  

  2、並轉換成base64字元串,

/**
 * 獲取圖片的Base64編碼(不支持url)
 * @param $img_file 傳入本地圖片地址
 * @return string
 */
function imgToBase64($img_file) {
    $img_base64 = '';
    if (file_exists($img_file)) {
        $app_img_file = $img_file; // 圖片路徑
        $img_info = getimagesize($app_img_file); // 取得圖片的大小,類型等
        //echo '<pre>' . print_r($img_info, true) . '</pre><br>';
        $fp = fopen($app_img_file, "r"); // 圖片是否可讀許可權
        if ($fp) {
            $filesize = filesize($app_img_file);
            $content = fread($fp, $filesize);
            $file_content = chunk_split(base64_encode($content)); // base64編碼
            switch ($img_info[2]) {           //判讀圖片類型
                case 1: $img_type = "gif";
                    break;
                case 2: $img_type = "jpg";
                    break;
                case 3: $img_type = "png";
                    break;
            }
            $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content;//合成圖片的base64編碼
        }
        fclose($fp);
    }
    return $img_base64; //返回圖片的base64
}

  3、B接受A項目傳來參數

    /**
     * 將base64字元串轉換成圖片並保存在本地
     * @param Request $request
     * @return void
     */
    public function baseImg(Request $request)
    {
        $base_string = $request->post('base_string', '');
        if (!$base_string) {
            $this->apiResult(CustomError::MISSING_PARAMS);
        }
        $path = $request->post('path', '');
        if (!$path) {
            $this->apiResult(CustomError::MISSING_PARAMS);
        }
        $request = base64_image_content($base_string, $path);//解碼
        if($request){
            $this->apiResult(CustomError::OPERATION_SUCCSESS, $request);
        }else{
            $this->apiResult(CustomError::OPERATION_FAILED);
        }
    }

  4、對字元解析解碼

/**
 * [將Base64圖片轉換為本地圖片並保存]
 * @param  [Base64] $base64_image_content [要保存的Base64]
 * @param  [目錄] $path [要保存的路徑]
 */
function base64_image_content($base64_image_content,$path){
    //匹配出圖片的格式
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)){
        $type = $result[2];
        $new_file = $path."/".date('Ymd',time())."/";
        if(!file_exists($new_file)){
            //檢查是否有該文件夾,如果沒有就創建,並給予最高許可權
            mkdir($new_file, 0700);
        }
        $new_file = $new_file.time().".{$type}";
        if (file_put_contents($new_file, base64_decode(str_replace($result[1], '', $base64_image_content)))){
            return '/'.$new_file;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

  5、最後返回上傳好的圖片路徑

:結束


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在這裡講一講這個案例的實現思路吧(個人見解)。。核心思想:為防止頁面刷新時倒計時失效的解決方案是:當每次刷新一次頁面時都執行一個函數 即下麵講到的 setStyle() 函數。這個函數會根據當前的 cookie 值判斷 是否處於倒計時階段 ,因為 cookie 值不會隨著 網頁的刷新而改變。 最後面 ...
  • 原生JS模擬滾動條 求滾動條的高度   可視內容區的高度 / 內容區的實際高度 = 滾動條的高度 / 滑道的高度 求內容區top的值   內容區距離頂部的距離 / (內容區的實際高度 可視內容區域的高度 ) = 滾動條距離頂部的距離 / ( 滑道的高度 滾動條的高度) 使用onm ...
  • 下載地址:http://kafka.apache.org/downloads http://mirror.bit.edu.cn/apache/kafka/2.3.0/kafka_2.12-2.3.0.tgz zookeeper.properties修改dataDir server.propertie ...
  • 跨域安全訪問API oauth2是一種用戶授權標準,jwt是傳遞token的一種消息標準,shiro是一個授權框架 1、JWT JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用於作為JSON對象在各方之間安全地傳輸信息。該信息可以被驗證 ...
  • 文章首發於公眾號 松花皮蛋的黑板報 作者就職於京東,在穩定性保障、敏捷開發、高級JAVA、微服務架構有深入的理解 為了避免分散式系統單點異常引發的系統可靠性和高可用問題,可行的辦法就是數據冗餘,也稱為複製集,那麼複製集是怎麼管理的呢? 實際上管理方式可以有去中心化副本集和中心化副本集兩種。 去中心化 ...
  • 我想從python播放我的歌曲(mp3),你能給我一個最簡單的命令嗎? 這不正確: 解決方案 試試這個。它過於簡單但可能不是最好的方法。 請註意,支持MP3是有限的。 安裝很簡單 - ...
  • 1、環境 2、編譯 預處理: gcc E main.c o main.i 編譯: gcc S main.i o main.s //同時做語法檢查 彙編: gcc c main.s o main.o 鏈接: gcc main.o o main.exe 3、4996錯誤 4、預處理 4.1 巨集 巨集定義 ...
  • 1.add添加 2.discard刪除 3.update批量添加 4.intersection取交集 5.union取並集 6.difference取差集 7.symmetric_difference對稱差集 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...