<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 废墟 <r.anerg@gmail.com> <http://anerg.com>
// +----------------------------------------------------------------------
/** 配置实例
    'FILE_UPLOAD_TYPE' => 'Oss',
    'UPLOAD_TYPE_CONFIG' => array(
        'access_id' => 'access_id', //阿里云Access Key ID
        'access_key' => 'access_key', //阿里云Access Key Secret
        'bucket' => 'bucket' //阿里云的bucket
    ),
 */
namespace Think\Upload\Driver;
use OSS\Core\OssException;
class Oss {
    const OSS_HOST = 'oss.aliyuncs.com';
    /**
     * 上传文件根目录
     * @var string
     */
    private $rootPath;
    /**
     * 上传错误信息
     * @var string
     */
    private $error  = '';
    private $config = array(
        'access_id'  => '', //阿里云Access Key ID
        'access_key' => '', //阿里云Access Key Secret
        'bucket'     => '', //空间名称
        'timeout'    => 90, //超时时间
        'region'     => 'qingdao', //区域
        'endpoint'   => '', //内外网 外网传空 内网随便传
    );
    /**
     * 构造函数，用于设置上传根路径
     * @param array  $config FTP配置
     */
    public function __construct($config) {
        /* 默认FTP配置 */
        $this->config = array_merge($this->config, $config);
    }
    /**
     * 检测上传根目录(阿里云上传时支持自动创建目录，直接返回)
     * @param string $rootpath   根目录
     * @return boolean true-检测通过，false-检测失败
     */
    public function checkRootPath($rootpath) {
        /* 设置根目录 */
        $this->rootPath = trim($rootpath, './') . '/';
        return true;
    }
    /**
     * 检测上传目录(阿里云上传时支持自动创建目录，直接返回)
     * @param  string $savepath 上传目录
     * @return boolean          检测结果，true-通过，false-失败
     */
    public function checkSavePath($savepath) {
        return true;
    }
    /**
     * 检测上传目录
     * @param  string $savepath 上传目录
     * @return boolean          检测结果，true-通过，false-失败
     */
    public function checkrealSavePath($savepath){
        /* 检测并创建目录 */
        if (!$this->mkdir($savepath)) {
            return false;
        } else {
            /* 检测目录是否可写 */
            if (!is_writable($this->rootPath . $savepath)) {
                $this->error = '上传目录 ' . $savepath . ' 不可写！';
                return false;
            } else {
                return true;
            }
        }
    }
    /**
     * 创建文件夹 (阿里云上传时支持自动创建目录，直接返回)
     * @param  string $savepath 目录名称
     * @return boolean          true-创建成功，false-创建失败
     */
    public function mkdir($savepath) {
        $dir = format_url($this->rootPath.$savepath,2);
        if(is_dir($dir)){return true;}
        if(mkdirs($dir, 0777)){return true;} else {$this->error = "目录 {$savepath} 创建失败！";return false;}
    }
    /**
     * 保存指定文件
     * @param  array   $file    保存的文件信息
     * @param  boolean $replace 同名文件是否覆盖
     * @return boolean          保存状态，true-成功，false-失败
     */
    public function save($file, $replace = true) {
        $linshifilename='';
        if (str_exists($file['tmp_name'], 'base64,')) {
            $this->checkrealSavePath( $file['savepath'] );            
            $linshifilename=format_url($this->rootPath . $file['savepath'] . $file['savename'],2);
            preg_match('/(.*)base64,(.*)/', $file['tmp_name'], $matches);
            $base64 = $matches['2'];
            $base64 = base64_decode($base64);
            $ress = file_put_contents($linshifilename,$base64);
            if($ress!==false && file_exists($linshifilename)){
                $file['tmp_name']=$linshifilename;
            }else{
                $this->error = '文件上传保存错误！';
                return false;
            }            
        }
        
        $object = $this->rootPath . $file['savepath'] . $file['savename'];//想要保存文件的名称
        vendor('aliyun.autoload');
        $endpoint ='oss-cn-'.$this->config['region'].'.aliyuncs.com';//你的阿里云OSS地址
        $ossClient = new \OSS\OssClient($this->config['access_id'], $this->config['access_key'], $endpoint);
        $result=$ossClient->uploadFile($this->config['bucket'],$object,$file['tmp_name']);
        if($result['info']['url']){
            if($linshifilename && file_exists($linshifilename))unlink($linshifilename);
            return $result['info']['url'];
        }else{
            $this->error = $e->getMessage() . "\n";
            return false;
        }
    }
    public function uploadList($data){
        $basepath=$this->rootPath.'image/';
        if(empty($data['path']))$data['path']=$basepath;
        $prefix = $data['path'];//限定返回的Object key必须以Prefix作为前缀。注意使用prefix查询时，返回的key中仍会包含Prefix。
        $delimiter = '/';//用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现Delimiter字符之间的Object作为一组元素: CommonPrefixes。
        $nextMarker = '';//设定结果从Marker之后按字母排序的第一个开始返回。
        $maxkeys = 1000;//限定此次返回Object的最大数，如果不设定，默认为100，MaxKeys取值不能大于1000。
        $options = array(
            'delimiter' => $delimiter,
            'prefix' => $prefix,
            'max-keys' => $maxkeys,
            'marker' => $nextMarker,
        );
        vendor('aliyun.autoload');
        $endpoint ='oss-cn-'.$this->config['region'].'.aliyuncs.com';//你的阿里云OSS地址
        $ossClient = new \OSS\OssClient($this->config['access_id'], $this->config['access_key'], $endpoint);
        $listObjectInfo = $ossClient->listObjects($this->config['bucket'], $options);
        $listObject = $listObjectInfo->getObjectList();//文件列表
        $listPrefix = $listObjectInfo->getPrefixList();//目录列表
        $file_list=array();
        $i=0;
        //图片扩展名
        $ext_arr = explode(',', C('UPLOAD_IMGEXTS'));
        foreach ($listPrefix as $item){//目录
            $file_list[$i]['filename'] = $this->prefixInfoParse($item);
            $file_list[$i]['is_dir'] = true; //是否文件夹
            $file_list[$i]['has_file'] = 1; //文件夹是否包含文件
            $file_list[$i]['filesize'] = 0; //文件大小
            $file_list[$i]['is_photo'] = false; //是否图片
            $file_list[$i]['filetype'] = ''; //文件类别，用扩展名判断
            $i++;
        }
        $domain ='http://'.$this->config['bucket'].'.oss-cn-'.$this->config['region'].'.aliyuncs.com/';
        foreach ($listObject as $item){//文件
            $file_list[$i] = $this->objectInfoParse($item);
            $file_ext = strtolower(pathinfo($file_list[$i]['filename'], PATHINFO_EXTENSION));
            $file_list[$i]['is_dir'] = false; //是否文件夹
            $file_list[$i]['has_file'] = false; //文件夹是否包含文件
            $file_list[$i]['is_photo'] = in_array($file_ext, $ext_arr); //是否图片
            $file_list[$i]['filetype'] = $file_ext; //文件类别，用扩展名判断
            $i++;
        }
        $order = empty($data['order']) ? 'name' : strtolower($data['order']);
        $sorts = array();
        foreach ($file_list as $row) {
            $sorts['size'][] = $row['filesize'];
            $sorts['type'][] = $row['filetype'];
            $sorts['name'][] = $row['filename'];
            //$sorts['datetime'][] = $row['datetime']; //时间排序
        }
        if ($order == 'name') {array_multisort($sorts['name'], SORT_ASC, $file_list);}
        if ($order == 'size') {array_multisort($sorts['size'], SORT_DESC, $file_list);}
        if ($order == 'type') {array_multisort($sorts['type'], SORT_ASC, $file_list);}
        $moveup_dir_path = preg_replace('/(.*?)[^\/]+\/$/', '$1', $prefix);
        if(strlen($moveup_dir_path)<strlen($basepath))$moveup_dir_path=$basepath;
        $result=array();
        //相对于根目录的上一级目录
        $result['moveup_dir_path'] = $moveup_dir_path;
        //相对于根目录的当前目录
        $result['current_dir_path'] = $prefix;
        //当前目录的URL
        $result['current_url'] = $domain.$prefix;
        //文件数
        $result['total_count'] = count($file_list);
        //文件列表数组
        $result['file_list'] = $file_list;
        return $result;
    }
    /* 解析 prefixInfo 类 */
    private function prefixInfoParse(PrefixInfo $prefixInfo){
        return basename($prefixInfo->getPrefix());
    }
    /* 解析 objectInfo 类 */
    public function objectInfoParse(ObjectInfo $objectInfo) {        
        return array(
            'filename'      => basename($objectInfo->getKey()),
            'filesize'      => $objectInfo->getSize(),
            'datetime'      => $objectInfo->getLastModified(),
        );
    }
    /**
     * 获取最后一次上传错误信息
     * @return string 错误信息
     */
    public function getError() {
        return $this->error;
    }
    private function hex_to_base64($str) {
        $result = '';
        for ($i = 0; $i < strlen($str); $i += 2) {
            $result .= chr(hexdec(substr($str, $i, 2)));
        }
        return base64_encode($result);
    }
}
?>