<?php
/**
* 小文件存储组件
*
*/
class SmallFileStorage
{
/**
* 服务器配置信息
* @var array{
* 'host'=>'...'
* 'port'=>...
* }
*/
public $serverConfig = array('host'=>'10.130.84.211','port'=>13000);
/**
* http get请求
* @param string $cgiPath
* @return 返回正文
*/
private function httpGet($cgiPath)
{
$fp = @fsockopen($this->serverConfig['host'], $this->serverConfig['port'], $errno, $errstr, 3);
if($fp === false) {
print('connect time out error');
return false;
}
stream_set_timeout($fp,1); //设置超时为1s
$ret = @fwrite($fp,"GET $cgiPath HTTP/1.0\r\n\r\n");
if($ret === false) {
print('write error');
return false;
}
$response_data = @fread($fp,512);
$OKSTR = '200 OK';
$okPos = stripos($response_data,$OKSTR);
if($okPos !== false) {
var_dump($response_data);
//暂且假设第一次读取就能读到Content-Length
//TODO
$CLSTR = 'Content-Length:';
$clPos = stripos($response_data,$CLSTR,$okPos+strlen($OKSTR));
if($clPos === false) return false;
$clEndPos = strpos($response_data,"\r\n",$clPos+strlen($CLSTR));
if($clEndPos === false) return false;
$contentLen = intval(substr($response_data,$clPos+strlen($CLSTR),$clEndPos-$clPos-strlen($CLSTR)));
//长度不应该为0
if($contentLen <= 0) return false;
//获取正文内容
$pattern_str = "\r\n\r\n";
$pattern_pos = strrpos($response_data,$pattern_str);
if($pattern_pos !== false) {
$partData = substr($response_data,$pattern_pos+strlen($pattern_str));
while(strlen($partData) < $contentLen) {
$response_data = @fread($fp,$contentLen-strlen($partData));
if(empty($response_data)) return false;
$partData .= $response_data;
}
return $partData;
}
}
print('read unexpected error');
return false;
}
/**
* http 上传文件,以字符串形式上传
* 由于小文件上传为异部操作,并且提前做了分享,所以必需保证数据处理可靠,必要情况下要重试
* @param string $cgiPath
* @param $data string 上传内容
* @return bool
*/
private function httpPostFile($data,$cgiPath)
{
$fp = @fsockopen($this->serverConfig['host'], $this->serverConfig['port'], $errno, $errstr, 3);
if($fp === false) {
print('connect time out error');
return false;
}
stream_set_timeout($fp,1); //设置超时为1s
//一次性写入
$line_1 = "POST $cgiPath HTTP/1.0\r\n";
$line_2 = "Content-Type: application/x-www-form-urlencoded\r\n";
$line_3 = "Content-length: ".strlen($data)."\r\n\r\n";
$ret = @fwrite($fp,$line_1.$line_2.$line_3);
if($ret === false) {
print('write error');
return false;
}
//数据量比较大,一次写不完
for($written = 0; $written < strlen($data); $written += $fwrite) {
$fwrite = fwrite($fp, substr($data, $written));
if ($fwrite === false) {
print('write error');
return false;
}
if ($fwrite === 0) {
break;
}
}
$response_data = @fread($fp, 32);
if(empty($response_data)) {
print('read error');
return false;
}
fclose($fp);
//解析返回码
return stripos($response_data,'200 OK') === false ? false : true;
}
/**
* 文件夹创建
* @param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>,
* 'name'=>,
* )
*/
public function dirCreate($info)
{
$cgiName = '/store_dir_create?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/*
*删除一个目录
*@param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>
* )
*/
public function dirDelete($info)
{
$cgiName = '/store_dir_delete?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/*
*删除一个目录
*@param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>
* )
*/
public function dirList($info)
{
$cgiName = '/store_dir_list?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/**
* 小文件内网上传,为性能考虑,文件夹提前手动建好
* @param $data 文件内容
* @param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>,
* 'name'=>,
* 'fsize'=>,
* 'offset'=>,
* )
*/
public function fileUpload($data,$info)
{
$cgiName = '/store_file_upload?';
$cgiPath = $cgiName.http_build_query($info);
return $this->httpPostFile($data,$cgiPath);
}
/*
*删除一个文件
*@param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>,
* 'name'=>,
* )
*/
public function fileDelete($info)
{
$cgiName = '/store_file_delete?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/*
*查询文件是上传的状态
*@param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>,
* 'name'=>,
* )
*/
public function fileQuery($info)
{
$cgiName = '/store_file_query?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/*
*下载指定的文件
*@param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>,
* 'name'=>,
* 'offset'=>,
* 'length'=>
* )
*/
public function fileDownload($info)
{
$cgiName = '/store_file_download?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/**
* 小文件外网下载
* @param $info array(
* 'buid'=>,
* 'uin'=>,
* 'dir_path'=>,
* 'name'=>,
* 'time'=>,
* )
* @return string 文件跳转url
*/
public function fileOuterDownload($info)
{
//生成外网key
//
$cgiName = '/store_get_key?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
if($response_code === false) {
return false;
}
//多带了一个time参数,不要紧
$preUrl = 'http://szmain.fcloud.store.qq.com/store_file_download?'.http_build_query($info).'&key='.$response_code;
return $preUrl;
}
/*
*以下函数为raw系列的函数,主要针对不需要uin上传和下载的场景
*/
/*
*fileRawUpload($array,&$uuid)
*@param $data;
*@param array(
* buid=>'',
* filename=>'',
* fsize=>'',
* offset=>''
*)
*@return string httpretcode;
*/
public function fileRawUpload($data,$info,&$uuid)
{
$cgiName = '/store_raw_upload?';
$uuid = md5($info['filename']."".time());
$info['uuid'] = $uuid;
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpPostFile($data,$cgiPath);
//TODO
//解析返回码
return $response_code;
}
/**
* 小文件内网下载
* @param $info array(
* 'buid'=>,
* 'uuid'=>,
* 'name'=>,
* 'time'=>,
* 'ip'=>
* )
* @return string 文件跳转url
*/
public function fileInnerRawDownload($info)
{
//生成外网key
//
$cgiName = '/store_raw_download?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
return $response_code;
}
/**
* 小文件外网下载
* @param $info array(
* 'buid'=>,
* 'uuid'=>,
* 'name'=>,
* 'time'=>,
* 'ip'=>
* )
* @return string 文件跳转url
*/
public function fileOuterRawDownload($info)
{
//生成外网key
//
$cgiName = '/store_get_key?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
if($response_code === false) {
return false;
}
//多带了一个time参数,不要紧
$preUrl = 'http://szmain.fcloud.store.qq.com/store_raw_download?'.http_build_query($info).'&key='.$response_code;
return $preUrl;
}
/**
* 小文件查询
* @param $info array(
* 'buid'=>,
* 'uuid'=>
* )
* @return string http返回码
*/
public function fileRawQuery($info)
{
//生成外网key
//
$cgiName = '/store_raw_query?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
/**
* 小文件删除
* @param $info array(
* 'buid'=>,
* 'uuid'=>
* )
* @return string http返回码
*/
public function fileRawDelete($info)
{
//生成外网key
//
$cgiName = '/store_raw_delete?';
$cgiPath = $cgiName.http_build_query($info);
$response_code = $this->httpGet($cgiPath);
//TODO
//解析返回码
return $response_code;
}
}