<?php
namespace imcat;

/**
 * UEditor编辑器通用上传类
 */
class comUpload
{
    private 
$fileField; //文件域名
    
private $file; //文件上传对象
    
private $base64; //文件上传对象
    
private $config; //配置信息
    
private $oriName; //原始文件名
    
private $fileName; //新文件名
    
private $fullName; //完整文件名,即从当前配置目录开始的URL
    
private $filePath; //完整文件名,即从当前配置目录开始的URL
    
private $fileSize; //文件大小
    
private $fileType; //文件类型
    
private $stateInfo; //上传状态信息,
    
public $stateMap = array();

    
/**
     * @param string $fileField 表单名称
     * @param array $config 配置项
     * @param type upload/remote/base64
     */
    
function __construct($fileField, $config, $type="upload"){
        
$this->stateMap = basLang::ucfg('cfglibs.upload');
        
$this->stateMap['ERROR_TYPE_NOT_ALLOWED'] = $this->stateMap['ERROR_TYPE_NOT_ALLOWED'];
        
$this->fileField = $fileField;
        
$this->config = $config;
        
$this->type = $type;
        if (
$type == "remote") {
            
$this->saveRemote();
        } else if(
$type == "base64") {
            
$this->upBase64();
        } else {
            
$this->upFile();
        }
    }

    
/**
     * 上传文件的主处理方法
     * @return mixed
     */
    
private function upFile(){
        
$file = $this->file = $_FILES[$this->fileField];
        if (!
$file) {
            
$this->stateInfo = $this->getStateInfo("ERROR_FILE_NOT_FOUND");
            return;
        }
        if (
$this->file['error']) {
            
$this->stateInfo = $this->getStateInfo($file['error']);
            return;
        } else if (!
file_exists($file['tmp_name'])) {
            
$this->stateInfo = $this->getStateInfo("ERROR_TMP_FILE_NOT_FOUND");
            return;
        } else if (!
is_uploaded_file($file['tmp_name'])) {
            
$this->stateInfo = $this->getStateInfo("ERROR_TMPFILE");
            return;
        }
        
$this->oriName = $file['name'];
        
$this->fileSize = $file['size'];
        
$this->fileType = $this->getFileExt();
        
$this->fullName = $this->getFullName();
        
$this->fileName = $this->getFileName();
        
//检查文件大小是否超出限制
        
if (!$this->checkSize()){
            
$this->stateInfo = $this->getStateInfo("ERROR_SIZE_EXCEED");
            return;
        }
        
//检查是否不允许的文件格式
        
if (!$this->checkType()) {
            
$this->stateInfo = $this->getStateInfo("ERROR_TYPE_NOT_ALLOWED");
            return;
        }
        
//移动文件
        
if (!move_uploaded_file($file["tmp_name"], $this->fullName)) {
            
$this->stateInfo = $this->getStateInfo("ERROR_FILE_MOVE");
        }else{
            
$this->upEnd();
        }
    }

    
/**
     * 处理base64编码的图片上传
     * @return mixed
     */
    
private function upBase64(){
        
$base64Data = $_POST[$this->fileField];
        
$img = base64_decode($base64Data);
        
$this->fileSize = strlen($img);
        
$this->oriName = 'base64_'.$this->fileSize.'_'.basKeyid::kidRand('f',4).'.png'; //$this->config['oriName']; //
        
$this->fileType = $this->getFileExt();
        
$this->fullName = $this->getFullName();
        
$this->fileName = $this->getFileName();
        
//检查文件大小是否超出限制
        
if (!$this->checkSize()) {
            
$this->stateInfo = $this->getStateInfo("ERROR_SIZE_EXCEED");
            return;
        }
        
//移动文件
        
if (!(comFiles::put($this->fullName, $img))) { //移动失败
            
$this->stateInfo = $this->getStateInfo("ERROR_WRITE_CONTENT");
        } else { 
//移动成功
            
$this->upEnd();
        }

    }

    
/**
     * 拉取远程图片
     * @return mixed
     */
    
private function saveRemote($imgUrl=''){
        if(empty(
$imgUrl)){
            
$imgUrl = htmlspecialchars($this->fileField);
            
$imgUrl = str_replace("&amp;", "&", $imgUrl); 
        }
        
//http开头验证
        
if (strpos($imgUrl, "http") !== 0) {
            
$this->stateInfo = $this->getStateInfo("ERROR_HTTP_LINK");
            return;
        }
        
//获取请求头并检测死链
        
$heads = get_headers($imgUrl);
        if (!(
stristr($heads[0], "200") && stristr($heads[0], "OK"))) {
            
$this->stateInfo = $this->getStateInfo("ERROR_DEAD_LINK");
            return;
        }
        
// Content-Type验证
        
if (@stristr($heads['Content-Type'], "image")) { 
            
$this->stateInfo = $this->getStateInfo("ERROR_HTTP_CONTENTTYPE");
            return;
        }
//*/
        //打开输出缓冲区并获取远程图片
        
ob_start();
        
$context = stream_context_create(
            array(
'http' => array(
                
'follow_location' => false // don't follow redirects
            
))
        );
        
readfile($imgUrl, false, $context);
        
$img = ob_get_contents();
        
ob_end_clean();
        
$pinfo = parse_url($imgUrl); // 'http://xxx.cn/dir/file.jpg?x-oss-process=image/resize,m_fill,h_170,w_230;
        
$this->oriName = isset($pinfo['path']) ? basename($pinfo['path']) : basename($imgUrl);
        
$this->fileSize = strlen($img);
        
$this->fileType = $this->getFileExt();
        
$this->fullName = $this->getFullName();
        
$this->fileName = $this->getFileName();
        
//检查文件大小是否超出限制
        
if (!$this->checkSize()) {
            
$this->stateInfo = $this->getStateInfo("ERROR_SIZE_EXCEED");
            return;
        }
        
//移动文件
        
if (!(comFiles::put($this->fullName, $img))) { //移动失败
            
$this->stateInfo = $this->getStateInfo("ERROR_WRITE_CONTENT");
        } else { 
//移动成功
            
$this->upEnd();
        }
    }

    
// 上传End
    
private function upEnd(){
        
$this->stateInfo = $this->stateMap[0];
        if(
in_array($this->fileType,array('.jpg','.jpeg'))){
            
comImage::compress($this->fullName);
            
//$res[] = self::compcut($full, $max);
        
}
    }

    
// 上传错误检查
    
private function getStateInfo($errCode){
        
$msg = isset($this->stateMap[$errCode]) ? $this->stateMap[$errCode] : $this->stateMap["ERROR_UNKNOWN"];
        
$msg = "$errCode:$msg";
        return 
$msg;
    }

    
// 获取文件扩展名
    
private function getFileExt($flag='0'){
        if(
$flag){ // file.php+ 1.jpg
            
$ext = strtolower(strchr($this->oriName, '.'));
        }else{
            
$ext = strtolower(strrchr($this->oriName, '.'));
        }
        if(empty(
$ext)){ //  && $this->type=='remote'
            
$ext = '.jpg';    
        } 
//处理类似图片:http://mmbiz.qpic.cn/mmbiz/kCd...gtw/0
        
return $ext;
    }

    
// 重命名文件
    
private function getFullName(){
        
$_parts = req('_parts'); 
        
$_dir = req('_dir'); 
        
$ndir = in_array($_parts,array('files')) && usrPerm::issup();
        if(
$ndir){
            
$folder = DIR_STATIC.'/'.$_dir;
        }else{
            
$folder = comStore::getTmpDir();
        } 
//dump($folder);
        
return $folder . '/' . $this->getFileName();
    }

    
// 获取文件名
    
private function getFileName(){
        
$ext = $this->getFileExt();
        
$upren = basReq::val('upren','auto');
        if(
$upren=='auto'){ // || in_array($this->type,array('remote','base64'))
            
$name = basKeyid::kidTemp().$ext;
        }else{
            if(
in_array($this->type,array('remote','base64'))){
                
$org = $this->oriName;
            }else {
                
$org = str_replace(array($ext),array(''),$this->file["name"]);    
            }
            
$org = basStr::filKey($org,'()-.@_~[]'); //-._@()[]
            
$org = str_replace(array('‘','’','“','”'),array("[",']','[',']'),$org);
            
$name ="{$org}~".basKeyid::kidRand('f',4).$ext;
        }
        return 
$this->fileName = strtolower($name);
    }

    
// 文件类型检测
    
private function checkType(){
        
$exf = $this->getFileExt(1);
        
$ext = $this->getFileExt();
        
$f1 = preg_match("/[^A-Za-z0-9_\.\-\@]/", $exf); // file.php+ 1.jpg
        
$f2 = preg_match("/\.(asp|aspx|jsp|php|exe|sh|bat|com)$/", $ext); // |asa|cdx|cer|php2|php3|php4
        
if($f1 || $f2){
            
$this->fileType = $exf;
            
$this->stateInfo = "Error `$ext`!"; 
            return 
false; //"Error `$ext`!";
        
}
        
$flag = $this->config["allowFiles"]==='(supper)' ? true : in_array($ext, $this->config["allowFiles"]);
        return 
$flag;
    }
    
// 文件大小检测
    
private function checkSize(){
        
$flag = $this->config["maxSize"]==='(supper)' ? true : $this->fileSize <= ($this->config["maxSize"]*1024 );
        return 
$flag;
    }

    
/**
     * 获取当前上传成功文件的各项信息
     * @return array
     */
    
function getFileInfo(){
        return array(
            
"state" => $this->stateInfo,
            
"url" => comStore::fixTmpDir($this->fullName),
            
"title" => $this->fileName,
            
"original" => $this->oriName,
            
"type" => $this->fileType,
            
"size" => $this->fileSize
        
);
    }

}