<commit_before><?php
    namespace Think\Upload\Driver\Qiniu;

    class QiniuStorage
    {

        public $QINIU_RSF_HOST = 'http://rsf.qbox.me';
        public $QINIU_RS_HOST = 'http://rs.qbox.me';
        public $QINIU_UP_HOST = 'http://up.qiniu.com';
        public $timeout = '';

        public function __construct($config)
        {
            $this->sk = $config['secretKey'];
            $this->ak = $config['accessKey'];
            $this->domain = $config['domain'];
            $this->bucket = $config['bucket'];
            $this->timeout = isset($config['timeout']) ? $config['timeout'] : 3600;
        }

        static function sign($sk, $ak, $data)
        {
            $sign = hash_hmac('sha1', $data, $sk, true);

            return $ak . ':' . self::Qiniu_Encode($sign);
        }

        static function signWithData($sk, $ak, $data)
        {
            $data = self::Qiniu_Encode($data);

            return self::sign($sk, $ak, $data) . ':' . $data;
        }

        public function accessToken($url, $body = '')
        {
            $parsed_url = parse_url($url);
            $path = $parsed_url['path'];
            $access = $path;
            if (isset($parsed_url['query'])) {
                $access .= "?" . $parsed_url['query'];
            }
            $access .= "\n";

            if ($body) {
                $access .= $body;
            }

            return self::sign($this->sk, $this->ak, $access);
        }

        public function UploadToken($sk, $ak, $param)
        {
            $param['deadline'] = $param['Expires'] == 0 ? 3600 : $param['Expires'];
            $param['deadline'] += time();
            $data = ['scope' => $this->bucket, 'deadline' => $param['deadline']];
            if (!empty($param['CallbackUrl'])) {
                $data['callbackUrl'] = $param['CallbackUrl'];
            }
            if (!empty($param['CallbackBody'])) {
                $data['callbackBody'] = $param['CallbackBody'];
            }
            if (!empty($param['ReturnUrl'])) {
                $data['returnUrl'] = $param['ReturnUrl'];
            }
            if (!empty($param['ReturnBody'])) {
                $data['returnBody'] = $param['ReturnBody'];
            }
            if (!empty($param['AsyncOps'])) {
                $data['asyncOps'] = $param['AsyncOps'];
            }
            if (!empty($param['EndUser'])) {
                $data['endUser'] = $param['EndUser'];
            }
            $data = json_encode($data);

            return self::SignWithData($sk, $ak, $data);
        }

        public function upload($config, $file)
        {
            $uploadToken = $this->UploadToken($this->sk, $this->ak, $config);

            $url = "{$this->QINIU_UP_HOST}";
            $mimeBoundary = md5(microtime());
            $header = ['Content-Type' => 'multipart/form-data;boundary=' . $mimeBoundary];
            $data = [];

            $fields = [
                'token' => $uploadToken,
                'key'   => $config['saveName'] ?: $file['fileName'],
            ];

            if (is_array($config['custom_fields']) && $config['custom_fields'] !== []) {
                $fields = array_merge($fields, $config['custom_fields']);
            }

            foreach ($fields as $name => $val) {
                array_push($data, '--' . $mimeBoundary);
                array_push($data, "Content-Disposition: form-data; name=\"$name\"");
                array_push($data, '');
                array_push($data, $val);
            }

            //文件
            array_push($data, '--' . $mimeBoundary);
            $name = $file['name'];
            $fileName = $file['fileName'];
            $fileBody = $file['fileBody'];
            $fileName = self::Qiniu_escapeQuotes($fileName);
            array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\"");
            array_push($data, 'Content-Type: application/octet-stream');
            array_push($data, '');
            array_push($data, $fileBody);

            array_push($data, '--' . $mimeBoundary . '--');
            array_push($data, '');

            $body = implode("\r\n", $data);
            $response = $this->request($url, 'POST', $header, $body);

            return $response;
        }

        public function dealWithType($key, $type)
        {
            $param = $this->buildUrlParam();
            $url = '';

            switch ($type) {
                case 'img':
                    $url = $this->downLink($key);
                    if ($param['imageInfo']) {
                        $url .= '?imageInfo';
                    } elseif ($param['exif']) {
                        $url .= '?exif';
                    } elseif ($param['imageView']) {
                        $url .= '?imageView/' . $param['mode'];
                        if ($param['w'])
                            $url .= "/w/{$param['w']}";
                        if ($param['h'])
                            $url .= "/h/{$param['h']}";
                        if ($param['q'])
                            $url .= "/q/{$param['q']}";
                        if ($param['format'])
                            $url .= "/format/{$param['format']}";
                    }
                    break;
                case 'video': //TODO 视频处理
                case 'doc':
                    $url = $this->downLink($key);
                    $url .= '?md2html';
                    if (isset($param['mode']))
                        $url .= '/' . (int)$param['mode'];
                    if ($param['cssurl'])
                        $url .= '/' . self::Qiniu_Encode($param['cssurl']);
                    break;

            }

            return $url;
        }

        public function buildUrlParam()
        {
            return $_REQUEST;
        }

        //获取某个路径下的文件列表
        public function getList($query = [], $path = '')
        {
            $query = array_merge(['bucket' => $this->bucket], $query);
            $url = "{$this->QINIU_RSF_HOST}/list?" . http_build_query($query);
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);

            return $response;
        }

        //获取某个文件的信息
        public function info($key)
        {
            $key = trim($key);
            $url = "{$this->QINIU_RS_HOST}/stat/" . self::Qiniu_Encode("{$this->bucket}:{$key}");
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', [
                'Authorization' => "QBox $accessToken",
            ]);

            return $response;
        }

        //获取文件下载资源链接
        public function downLink($key)
        {
            $key = urlencode($key);
            $key = self::Qiniu_escapeQuotes($key);
            $url = "http://{$this->domain}/{$key}";

            return $url;
        }

        //重命名单个文件
        public function rename($file, $new_file)
        {
            $key = trim($file);
            $url = "{$this->QINIU_RS_HOST}/move/" . self::Qiniu_Encode("{$this->bucket}:{$key}") . '/' . self::Qiniu_Encode("{$this->bucket}:{$new_file}");
            trace($url);
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);

            return $response;
        }

        //删除单个文件
        public function del($file)
        {
            $key = trim($file);
            $url = "{$this->QINIU_RS_HOST}/delete/" . self::Qiniu_Encode("{$this->bucket}:{$key}");
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);

            return $response;
        }

        //批量删除文件
        public function delBatch($files)
        {
            $url = $this->QINIU_RS_HOST . '/batch';
            $ops = [];
            foreach ($files as $file) {
                $ops[] = "/delete/" . self::Qiniu_Encode("{$this->bucket}:{$file}");
            }
            $params = 'op=' . implode('&op=', $ops);
            $url .= '?' . $params;
            trace($url);
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);

            return $response;
        }

        static function Qiniu_Encode($str)
        {// URLSafeBase64Encode
            $find = ['+', '/'];
            $replace = ['-', '_'];

            return str_replace($find, $replace, base64_encode($str));
        }

        static function Qiniu_escapeQuotes($str)
        {
            $find = ["\\", "\""];
            $replace = ["\\\\", "\\\""];

            return str_replace($find, $replace, $str);
        }

        /**
         * 请求云服务器
         * @param  string   $path    请求的PATH
         * @param  string   $method  请求方法
         * @param  array    $headers 请求header
         * @param  resource $body    上传文件资源
         * @return bool
         */
        private function request($path, $method, $headers = null, $body = null)
        {
            $ch = curl_init($path);

            $_headers = ['Expect:'];
            if (!is_null($headers) && is_array($headers)) {
                foreach ($headers as $k => $v) {
                    array_push($_headers, "{$k}: {$v}");
                }
            }

            $length = 0;
            $date = gmdate('D, d M Y H:i:s \G\M\T');

            if (!is_null($body)) {
                if (is_resource($body)) {
                    fseek($body, 0, SEEK_END);
                    $length = ftell($body);
                    fseek($body, 0);

                    array_push($_headers, "Content-Length: {$length}");
                    curl_setopt($ch, CURLOPT_INFILE, $body);
                    curl_setopt($ch, CURLOPT_INFILESIZE, $length);
                } else {
                    $length = @strlen($body);
                    array_push($_headers, "Content-Length: {$length}");
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
                }
            } else {
                array_push($_headers, "Content-Length: {$length}");
            }

            // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
            array_push($_headers, "Date: {$date}");

            curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
            curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
            curl_setopt($ch, CURLOPT_HEADER, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

            if ($method == 'PUT' || $method == 'POST') {
                curl_setopt($ch, CURLOPT_POST, 1);
            } else {
                curl_setopt($ch, CURLOPT_POST, 0);
            }

            if ($method == 'HEAD') {
                curl_setopt($ch, CURLOPT_NOBODY, true);
            }

            $response = curl_exec($ch);
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            list($header, $body) = explode("\r\n\r\n", $response, 2);
            if ($status == 200) {
                if ($method == 'GET') {
                    return $body;
                } else {
                    return $this->response($response);
                }
            } else {
                $this->error($header, $body);

                return false;
            }
        }

        /**
         * 获取响应数据
         * @param  string $text 响应头字符串
         * @return array        响应数据列表
         */
        private function response($text)
        {
            $headers = explode(PHP_EOL, $text);
            $items = [];
            foreach ($headers as $header) {
                $header = trim($header);
                if (strpos($header, '{') !== false) {
                    $items = json_decode($header, 1);
                    break;
                }
            }

            return $items;
        }
<commit_msg>fix qiniu uploader<commit_after><?php
    namespace Think\Upload\Driver\Qiniu;
    
    class QiniuStorage
    {
        
        public $QINIU_RSF_HOST = 'http://rsf.qbox.me';
        public $QINIU_RS_HOST = 'http://rs.qbox.me';
        public $QINIU_UP_HOST = 'http://up-z2.qiniu.com';
        public $timeout = '';
        
        public function __construct($config)
        {
            $this->ak = $config['accessKey'];
            $this->sk = $config['secrectKey'];
            $this->domain = $config['domain'];
            $this->bucket = $config['bucket'];
            $this->timeout = isset($config['timeout']) ? $config['timeout'] : 3600;
        }
        
        static function sign($ak, $sk, $data)
        {
            $sign = hash_hmac('sha1', $data, $sk, true);
            
            return $ak . ':' . static::Qiniu_Encode($sign);
        }
        
        static function signWithData($ak, $sk, $data)
        {
            $data = static::Qiniu_Encode($data);
            
            return static::sign($ak, $sk, $data) . ':' . $data;
        }
        
        public function accessToken($url, $body = '')
        {
            $parsed_url = parse_url($url);
            $path = $parsed_url['path'];
            $access = $path;
            if (isset($parsed_url['query'])) {
                $access .= "?" . $parsed_url['query'];
            }
            $access .= "\n";
            
            if ($body) {
                $access .= $body;
            }
            
            return static::sign( $this->ak,$this->sk, $access);
        }
        
        public function UploadToken($sk, $ak, $param)
        {
            $param['deadline'] = $param['Expires'] == 0 ? 3600 : $param['Expires'];
            $param['deadline'] += time();
            $data = ['scope' => $this->bucket, 'deadline' => $param['deadline']];
            if (!empty($param['CallbackUrl'])) {
                $data['callbackUrl'] = $param['CallbackUrl'];
            }
            if (!empty($param['CallbackBody'])) {
                $data['callbackBody'] = $param['CallbackBody'];
            }
            if (!empty($param['ReturnUrl'])) {
                $data['returnUrl'] = $param['ReturnUrl'];
            }
            if (!empty($param['ReturnBody'])) {
                $data['returnBody'] = $param['ReturnBody'];
            }
            if (!empty($param['AsyncOps'])) {
                $data['asyncOps'] = $param['AsyncOps'];
            }
            if (!empty($param['EndUser'])) {
                $data['endUser'] = $param['EndUser'];
            }
            $data = json_encode($data);
            
            return static::SignWithData($ak, $sk, $data);
        }
        
        public function upload($config, $file)
        {
            $uploadToken = $this->UploadToken( $this->ak,$this->sk, $config);
            
            $url = "{$this->QINIU_UP_HOST}";
            $mimeBoundary = md5(microtime());
            $header = ['Content-Type' => 'multipart/form-data;boundary=' . $mimeBoundary];
            $data = [];
            
            $fields = [
                'token' => $uploadToken,
                'key'   => $config['saveName'] ?: $file['fileName'],
            ];
            
            if (is_array($config['custom_fields']) && $config['custom_fields'] !== []) {
                $fields = array_merge($fields, $config['custom_fields']);
            }
            
            foreach ($fields as $name => $val) {
                array_push($data, '--' . $mimeBoundary);
                array_push($data, "Content-Disposition: form-data; name=\"$name\"");
                array_push($data, '');
                array_push($data, $val);
            }
            
            //文件
            array_push($data, '--' . $mimeBoundary);
            $name = $file['name'];
            $fileName = $file['fileName'];
            $fileBody = $file['fileBody'];
            $fileName = static::Qiniu_escapeQuotes($fileName);
            array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\"");
            array_push($data, 'Content-Type: application/octet-stream');
            array_push($data, '');
            array_push($data, $fileBody);
            
            array_push($data, '--' . $mimeBoundary . '--');
            array_push($data, '');
            
            $body = implode("\r\n", $data);
            $response = $this->request($url, 'POST', $header, $body);
            
            return $response;
        }
        
        public function dealWithType($key, $type)
        {
            $param = $this->buildUrlParam();
            $url = '';
            
            switch ($type) {
                case 'img':
                    $url = $this->downLink($key);
                    if ($param['imageInfo']) {
                        $url .= '?imageInfo';
                    } elseif ($param['exif']) {
                        $url .= '?exif';
                    } elseif ($param['imageView']) {
                        $url .= '?imageView/' . $param['mode'];
                        if ($param['w'])
                            $url .= "/w/{$param['w']}";
                        if ($param['h'])
                            $url .= "/h/{$param['h']}";
                        if ($param['q'])
                            $url .= "/q/{$param['q']}";
                        if ($param['format'])
                            $url .= "/format/{$param['format']}";
                    }
                    break;
                case 'video': //TODO 视频处理
                case 'doc':
                    $url = $this->downLink($key);
                    $url .= '?md2html';
                    if (isset($param['mode']))
                        $url .= '/' . (int)$param['mode'];
                    if ($param['cssurl'])
                        $url .= '/' . static::Qiniu_Encode($param['cssurl']);
                    break;
                
            }
            
            return $url;
        }
        
        public function buildUrlParam()
        {
            return $_REQUEST;
        }
        
        //获取某个路径下的文件列表
        public function getList($query = [], $path = '')
        {
            $query = array_merge(['bucket' => $this->bucket], $query);
            $url = "{$this->QINIU_RSF_HOST}/list?" . http_build_query($query);
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);
            
            return $response;
        }
        
        //获取某个文件的信息
        public function info($key)
        {
            $key = trim($key);
            $url = "{$this->QINIU_RS_HOST}/stat/" . static::Qiniu_Encode("{$this->bucket}:{$key}");
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', [
                'Authorization' => "QBox $accessToken",
            ]);
            
            return $response;
        }
        
        //获取文件下载资源链接
        public function downLink($key)
        {
            $key = urlencode($key);
            $key = static::Qiniu_escapeQuotes($key);
            $url = "http://{$this->domain}/{$key}";
            
            return $url;
        }
        
        //重命名单个文件
        public function rename($file, $new_file)
        {
            $key = trim($file);
            $url = "{$this->QINIU_RS_HOST}/move/" . static::Qiniu_Encode("{$this->bucket}:{$key}") . '/' . static::Qiniu_Encode("{$this->bucket}:{$new_file}");
            trace($url);
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);
            
            return $response;
        }
        
        //删除单个文件
        public function del($file)
        {
            $key = trim($file);
            $url = "{$this->QINIU_RS_HOST}/delete/" . static::Qiniu_Encode("{$this->bucket}:{$key}");
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);
            
            return $response;
        }
        
        //批量删除文件
        public function delBatch($files)
        {
            $url = $this->QINIU_RS_HOST . '/batch';
            $ops = [];
            foreach ($files as $file) {
                $ops[] = "/delete/" . static::Qiniu_Encode("{$this->bucket}:{$file}");
            }
            $params = 'op=' . implode('&op=', $ops);
            $url .= '?' . $params;
            trace($url);
            $accessToken = $this->accessToken($url);
            $response = $this->request($url, 'POST', ['Authorization' => "QBox $accessToken"]);
            
            return $response;
        }
        
        static function Qiniu_Encode($str)
        {
            // URLSafeBase64Encode
            $find = ['+', '/'];
            $replace = ['-', '_'];
            
            return str_replace($find, $replace, base64_encode($str));
        }
        
        static function Qiniu_escapeQuotes($str)
        {
            $find = ["\\", "\""];
            $replace = ["\\\\", "\\\""];
            
            return str_replace($find, $replace, $str);
        }
        
        /**
         * 请求云服务器
         * @param  string   $path    请求的PATH
         * @param  string   $method  请求方法
         * @param  array    $headers 请求header
         * @param  resource $body    上传文件资源
         * @return bool
         */
        private function request($path, $method, $headers = null, $body = null)
        {
            $ch = curl_init($path);
            
            $_headers = ['Expect:'];
            if (!is_null($headers) && is_array($headers)) {
                foreach ($headers as $k => $v) {
                    array_push($_headers, "{$k}: {$v}");
                }
            }
            
            $length = 0;
            $date = gmdate('D, d M Y H:i:s \G\M\T');
            
            if (!is_null($body)) {
                if (is_resource($body)) {
                    fseek($body, 0, SEEK_END);
                    $length = ftell($body);
                    fseek($body, 0);
                    
                    array_push($_headers, "Content-Length: {$length}");
                    curl_setopt($ch, CURLOPT_INFILE, $body);
                    curl_setopt($ch, CURLOPT_INFILESIZE, $length);
                } else {
                    $length = @strlen($body);
                    array_push($_headers, "Content-Length: {$length}");
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
                }
            } else {
                array_push($_headers, "Content-Length: {$length}");
            }
            
            // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
            array_push($_headers, "Date: {$date}");
            
            curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
            curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
            curl_setopt($ch, CURLOPT_HEADER, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
            
            if ($method == 'PUT' || $method == 'POST') {
                curl_setopt($ch, CURLOPT_POST, 1);
            } else {
                curl_setopt($ch, CURLOPT_POST, 0);
            }
            
            if ($method == 'HEAD') {
                curl_setopt($ch, CURLOPT_NOBODY, true);
            }
            
            $response = curl_exec($ch);
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            list($header, $body) = explode("\r\n\r\n", $response, 2);
            if ($status == 200) {
                if ($method == 'GET') {
                    return $body;
                } else {
                    return $this->response($response);
                }
            } else {
                $this->error($header, $body);
                
                return false;
            }
        }
        
        /**
         * 获取响应数据
         * @param  string $text 响应头字符串
         * @return array        响应数据列表
         */
        private function response($text)
        {
            $headers = explode(PHP_EOL, $text);
            $items = [];
            foreach ($headers as $header) {
                $header = trim($header);
                if (strpos($header, '{') !== false) {
                    $items = json_decode($header, 1);
                    break;
                }
            }
            
            return $items;
        }
        
{'fraction_non_alphanumeric': 0.16823671497584541, 'fraction_numerical': 0.0023752012882447666, 'mean_word_length': 1.3579496915045088, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1361736', 'n_tokens_mistral': 7250, 'n_tokens_neox': 7009, 'n_words': 1212}