视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
PHP如何将图片文件上传到另外一台服务器上
2020-11-27 14:43:11 责编:小采
文档


  说,我有一个需求,就是一个临时功能。由于工作开发问题,我们有一个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-fa-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、但是还是找不到解决的方法,头疼的厉害,好热。怎么办,我决定靠在椅子上休息下,于是我还是决定躺在沙发上睡会。刚躺下,想着这怎么办呢。

  -----------------------base---------------------------华丽的分割线

  我突然想到了base这个读起来,朗朗上口的函数,对如果现将图片转换成base字符串,再通过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 = imgToBase($img_one);//获取图片base编码格式
 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、并转换成base字符串,

/**
 * 获取图片的Base编码(不支持url)
 * @param $img_file 传入本地图片地址
 * @return string
 */
function imgToBase($img_file) {
 $img_base = '';
 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(base_encode($content)); // base编码
 switch ($img_info[2]) { //判读图片类型
 case 1: $img_type = "gif";
 break;
 case 2: $img_type = "jpg";
 break;
 case 3: $img_type = "png";
 break;
 }
 $img_base = 'data:image/' . $img_type . ';base,' . $file_content;//合成图片的base编码
 }
 fclose($fp);
 }
 return $img_base; //返回图片的base
}

  3、B接受A项目传来参数

/**
 * 将base字符串转换成图片并保存在本地
 * @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 = base_image_content($base_string, $path);//解码
 if($request){
 $this->apiResult(CustomError::OPERATION_SUCCSESS, $request);
 }else{
 $this->apiResult(CustomError::OPERATION_FAILED);
 }
 }

  4、对字符解析解码

/**
 * [将Base图片转换为本地图片并保存]
 * @param [Base] $base_image_content [要保存的Base]
 * @param [目录] $path [要保存的路径]
 */
function base_image_content($base_image_content,$path){
 //匹配出图片的格式
 if (preg_match('/^(data:\s*image\/(\w+);base,)/', $base_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, base_decode(str_replace($result[1], '', $base_image_content)))){
 return '/'.$new_file;
 }else{
 return false;
 }
 }else{
 return false;
 }
}

  5、最后返回上传好的图片路径

:结束

总结

以上所述是小编给大家介绍的PHP如何将图片文件上传到另外一台服务器上,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

下载本文
显示全文
专题