1. 云栖社区>
  2. PHP教程>
  3. 正文

服务器基于PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码)

作者:用户 来源:互联网 时间:2017-12-01 13:52:18

客户端服务器文件图片代码

服务器基于PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码) - 摘要: 本文讲的是服务器基于PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码),问题背景:app在上传图片时,同时传递参数,支持传递多个图片。本文中的环境默认已经配好了服务器的CodeIgniter框架。事实上不使用这个框架也是可以的。一,服务器部分1,在controllers下的helpers新建文件upload_h

问题背景:app在上传图片时,同时传递参数,支持传递多个图片。本文中的环境默认已经配好了服务器的CodeIgniter框架。事实上不使用这个框架也是可以的。

一,服务器部分

1,在controllers下的helpers新建文件upload_helper.php

<?php/** * Make multifile array input complaint with CI_Upload.<br> * For use files[ ] input name you must use it method. * * @author porquero * * @example * In Controller<br> * $this->load->helper('upload');<br> * multifile_array();<br> * foreach ($_FILES as $file => $file_data) {<br> *    $this->upload->do_upload($file); * ... * * @link http://porquero.blogspot.com/2012/05/codeigniter-multifilearray-upload.html  */function multifile_array(){    if(count($_FILES) == 0)return;    $files = array();    $all_files = $_FILES['f_file']['name'];    $i = 0;    foreach ((array)$all_files as $filename) {$files[++$i]['name'] = $filename;$files[$i]['type'] = current($_FILES['f_file']['type']);next($_FILES['f_file']['type']);$files[$i]['tmp_name'] = current($_FILES['f_file']['tmp_name']);next($_FILES['f_file']['tmp_name']);$files[$i]['error'] = current($_FILES['f_file']['error']);next($_FILES['f_file']['error']);$files[$i]['size'] = current($_FILES['f_file']['size']);next($_FILES['f_file']['size']);    }    $_FILES = $files;}

说明:
a.注意里面的key为'f_file',这就要求app或web在上传,建表单的时候将此值对应上。
b.该文件主要是遍历$_FILES,通过current得到当前file的信息转存到数组里,然后返回。注意转存后索引是从1开始的。转存的字段有name/type/tmp_name/error/size,使用next移动$_FILES['f_file']['key']的指针。
2.views里新建upload_form.php,用来在web上模拟测试上传是否成功:

<html><head>    <title>Upload Form</title></head><body><?php echo $error;?><?php $data = array('type'=>'shop', 'id'=>'1');?><?php echo form_open_multipart('upload/web_upload', '', $data);?><input type="file" name="f_file[]" multiple="multiple" size="20" /><br /><br /><input type="submit" value="upload" /></form></body></html>
注意:
a,这里使用了CI框架的form_open_multipart新建一个multipart的表单,访问的是控制器upload里的web_upload方法,第三个参数$data,用于模拟向服务器传递的post请求参数。当然你也可以在下面加几个<input>.
b,input里name对应的是f_file[],这个是跟 服务器那边统一好的。
c,若要支持多文件上传加上multiple="multiple",不加的话一次只能上传一个文件。

3,views下新建upload_success.php,显示上传成功后的界面。

<html><head>    <title>Upload Form</title></head><body><h3>Your file was successfully uploaded!</h3><ul>    <?php foreach ($upload_data as $item => $value):?><li><?php echo $item;?>: <?php echo $value;?></li>    <?php endforeach; ?></ul><p><?php echo anchor('upload', 'Upload Another File!'); ?></p></body></html>

注意:这里的$upload_data是控制器上传成功后传给view的数据。

4,接下来是最关键的一个类,在controllers文件夹下新建Upload.php,这是个控制器,上传最核心的。

<?phprequire_once APPPATH . 'controllers/base/BASE_CI_Controller.php';class Upload extends BASE_CI_Controller{    private $m_type = '';    private $m_id = '';    private $m_path = './application/cache/image';    private $m_error = array();    public function __construct()    {parent::__construct();$this->load->helper(array('form', 'url', 'upload'));//$this->load->model('picture_model');    }    public function index()    {$this->load->view('upload_form', array('error' => ' ' ));    }    public function app_upload(){$this->init_argc();multifile_array();foreach ($_FILES as $file => $file_data){    $this->do_upload($file);}if($this->m_error == NULL || count($this->m_error) == 0){    $this->output->set_output(json_encode(array('msg'=>'上传成功')));}else{    $this->output->set_output(json_encode($this->m_error));}    }    public function do_upload($file)    {$config['upload_path']      =  $this->m_path;$config['allowed_types']    = 'gif|jpg|png|jpeg';$config['max_size']     = 10240;$config['max_width']= 2000;$config['max_height']       = 2000;$config['file_name'] = Util::random_str();$this->load->library('upload', $config);if ( ! $this->upload->do_upload($file)){    $this->on_upload_error($this->upload->display_errors());}else{    $upload_data = $this->upload->data();    $this->on_upload_success($upload_data['file_name']);}    }    public function do_upload2($file)    {$config['upload_path']      =  $this->m_path;$config['allowed_types']    = 'gif|jpg|png|jpeg';$config['max_size']     = 10240;$config['max_width']= 2000;$config['max_height']       = 2000;$config['file_name'] = Util::random_str();$this->load->library('upload', $config);if ( ! $this->upload->do_upload($file)){    $error = array('error' => $this->upload->display_errors());    $this->load->view('upload_form', $error);}else{    $data = array('upload_data' => $this->upload->data());    $this->load->view('upload_success', $data);}    }    public function web_upload()    {multifile_array();foreach ($_FILES as $file => $file_data){    $this->do_upload2($file);}    }    private function init_argc() {$this->m_type = $this->getPost('type');$this->m_id = $this->getPost('id');$this->m_path = $this->getPath($this->m_type);    }    private function getPath($type){$path = './application/cache/image/shop';if($type == "shop"){    $path =  './application/cache/image/shop';}return $path;    }    private function on_upload_success($name){if($this->m_type == 'shop'){    //$this->picture_model->add_shop_picture($this->m_id, $this->m_type, $name);}else if($this->m_type == 'avatar'){    //$this->picture_model->add_user_avatar($this->m_id, $this->m_type, $name);}    }    private function on_upload_error($error){$this->m_error['msg'] = $error;    }}?>
解释如下:
a,这里Upload是继承的BASE_CI_Controller,也可以换成CI_Controller,在自己的Base_CI_Controller里封装了自己项目一些常用的安全校验逻辑;
b,我定义了m_type记录上传图片的类型,m_id是图片所属对象的id,m_path为路径,根据type不同路径可以做区分。m_error纪录错误。在构造函数里,注意把几个helper都load进来。除此外我还写了个Picture_model用来操作图片相关的数据库,如果不需要这个model,可以注释掉。
c,app_load()是暴露给app用来上传的,init_argc()初始化post传来的各种参数。然后就是调multifile_array();之后遍历上传。待上传完毕后根据m_error里是否为空,判断是该显示什么消息给app。在do_upload()里的Util::random_str()是个很简单的对时间戳md5,防止图片名字一样:
Util里的代码:

/**     * 产生新的token     * @return string     */    public static function token(){$curr = Util::time();return md5($curr);    }    public static function random_str(){return Util::token();    }

每次上传成功后都调on_upload_success() on_upload_error()进行更新数据库等操作。其中on_upload_success()要接收$upload_data['file_name']),表示上传成功后的文件的名字。
d,web_upload是给web上传图片用的,通过do_upload2()上传成功后就加载一个view来显示上传后的信息。PS:保证你对目的文件夹有可写权限。先用web测试下效果:http://localhost/~yanzi/city52/index.php/upload

服务器基于<a href=PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码)">

二,客户端:基于Volley的多文件/图片上传类的封装

这个比较简单,基于volley封装的,MultipartRequest.java

package com.android.nomnom.volley;import android.util.Log;import com.android.volley.AuthFailureError;import com.android.volley.NetworkResponse;import com.android.volley.Request;import com.android.volley.Response;import com.android.volley.VolleyLog;import com.android.volley.toolbox.HttpHeaderParser;import org.apache.http.entity.mime.MultipartEntity;import org.apache.http.entity.mime.content.FileBody;import org.apache.http.entity.mime.content.StringBody;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.nio.charset.Charset;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 功能: * * @author yanzi E-mail: [email protected] * @version 创建时间: 2015-08-09 下午4:32 */public class MultipartRequest extends Request<String>{    private MultipartEntity entity = new MultipartEntity();    private  Response.Listener<String> mListener;    private List<File> mFileParts;    private String mFilePartName;    private Map<String, String> mParams;    /**     * 单个文件+参数 上传     * @param url     * @param listener     * @param errorListener     * @param filePartName     * @param file     * @param params     */    public MultipartRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener,    String filePartName, File file, Map<String, String> params){super(Method.POST, url, errorListener);mFileParts = new ArrayList<File>();if(file != null && file.exists()){    mFileParts.add(file);}else{    VolleyLog.e("MultipartRequest---file not found");}mFilePartName = filePartName;mListener = listener;mParams = params;buildMultipartEntity();    }    /**     * 多个文件+参数上传     * @param url     * @param listener     * @param errorListener     * @param filePartName     * @param files     * @param params     */    public MultipartRequest(String url,Response.Listener<String> listener,Response.ErrorListener errorListener    , String filePartName,List<File> files, Map<String, String> params) {super(Method.POST, url, errorListener);mFilePartName = filePartName;mListener = listener;mFileParts = files;mParams = params;buildMultipartEntity();    }    @Override    protected Response<String> parseNetworkResponse(NetworkResponse response) {String parsed;try {    parsed = new String(response.data,    HttpHeaderParser.parseCharset(response.headers));} catch (UnsupportedEncodingException e) {    parsed = new String(response.data);}return Response.success(parsed,HttpHeaderParser.parseCacheHeaders(response));    }    @Override    protected void deliverResponse(String response) {mListener.onResponse(response);    }    @Override    public Map<String, String> getHeaders() throws AuthFailureError {Map<String, String> headers = super.getHeaders();if (headers == null || headers.equals(Collections.emptyMap())) {    headers = new HashMap<String, String>();}return headers;    }    @Override    public String getBodyContentType() {return entity.getContentType().getValue();    }    @Override    public byte[] getBody() throws AuthFailureError {ByteArrayOutputStream bos = new ByteArrayOutputStream();try{    entity.writeTo(bos);} catch (IOException e) {    VolleyLog.e("IOException writing to ByteArrayOutputStream");}return bos.toByteArray();    }    private void buildMultipartEntity() {if (mFileParts != null && mFileParts.size() > 0) {    for (File file : mFileParts) {entity.addPart(mFilePartName, new FileBody(file));    }    long l = entity.getContentLength();    Log.i("YanZi-volley", mFileParts.size() + "个,长度:" + l);}try {    if (mParams != null && mParams.size() > 0) {for (Map.Entry<String, String> entry : mParams.entrySet()) {    entity.addPart(    entry.getKey(),    new StringBody(entry.getValue(), Charset    .forName("UTF-8")));}    }} catch (UnsupportedEncodingException e) {    VolleyLog.e("UnsupportedEncodingException");}    }}

使用的话new一个request,然后add到queue里就可以了,我就不写示例了。下次介绍android上传/下载文件带进度条的实现。
参考:CodeIgniter http://codeigniter.org.cn/
---------------本文系原创,转载注明作者yanzi1225627

欢迎大家加入PHP CodeIgniter社区群460132647,备注yanzi服务器基于PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码)

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索客户端 , 服务器 , 文件 , 图片 代码 ,以便于您获取更多的相关知识。