微信請(qǐng)求函數(shù)
const uploadTask = wx.uploadFile({
url: 'http://ip地址/echo.cgi',
filePath: that.data.cutImgUrl,
name: 'file',
formData: {
'user': '/home/nginx/html/image/logo'
},
success: function (res) {
var data = res.data;
console.log(" res.data" + res.data);
that.setData({ display: "hied" });
}
})
接下來(lái)我們看下前端傳遞的數(shù)據(jù)是怎樣的格式
<title>FastCGI echo</title><h1>FastCGI echo</h1>
Request number 1, Process ID: 3520<p>
Standard input:<br>
<pre>
----------------------------753651501054604630337800
Content-Disposition: form-data; name="user"
/home/nginx/html/image/logo
----------------------------753651501054604630337800
Content-Disposition: form-data; name="file"; filename="touristappid.o6zAJs5MrQFix1tcXqPxSNHp7TYM.Qqpwv0q7GmO074368faff93b1673d56dd872406e5d09.jpg"
Content-Type: image/jpeg
數(shù)據(jù)區(qū)
----------------------------753651501054604630337800--
</pre><p>
Request environment:<br>
<pre>
FCGI_ROLE=RESPONDER
SCRIPT_FILENAME=fcgi/echo.cgi
QUERY_STRING=
REQUEST_METHOD=POST
CONTENT_TYPE=multipart/form-data; boundary=--------------------------753651501054604630337800
CONTENT_LENGTH=10532
SCRIPT_NAME=/echo.cgi
REQUEST_URI=/echo.cgi
DOCUMENT_URI=/echo.cgi
DOCUMENT_ROOT=
SERVER_PROTOCOL=HTTP/1.1
REQUEST_SCHEME=http
GATEWAY_INTERFACE=CGI/1.1
SERVER_SOFTWARE=nginx/1.13.5
REMOTE_ADDR=168.160.111.53
REMOTE_PORT=55809
SERVER_ADDR=
SERVER_PORT=
SERVER_NAME=localhost
REDIRECT_STATUS=200
HTTP_REFERER=https://servicewechat.com/touristappid/devtools/page-frame.html
HTTP_HOST=
HTTP_CONTENT_TYPE=multipart/form-data; boundary=--------------------------753651501054604630337800
HTTP_CONTENT_LENGTH=10532
HTTP_CONNECTION=close
</pre><p>
Initial environment:<br>
<pre>
TOMCAT_HOME=/opt/apache-tomcat-8.0.46
XDG_SESSION_ID=1
ANDROID_HOME=
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=
GRADLE_HOME=
SSH_TTY=/dev/pts/10
ANT_HOME=/usr/share/ant/
NDK_HOME=
USER=
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
PYTHON_LIBS=/usr/lib/python2.7
PYTHON_CFLAGS=/usr/include
MAIL=
PATH=
PWD=
JAVA_HOME=
ANDROID_SDK=
LANG=zh_CN.UTF-8
SHLVL=2
HOME=
LANGUAGE=zh_CN:zh
LOGNAME=
CLASSPATH=
SSH_CONNECTION=
LESSOPEN=| /usr/bin/lesspipe %s
ANDROID_NDK=
XDG_RUNTIME_DIR=/run/user/1000
LESSCLOSE=/usr/bin/lesspipe %s %s
</pre><p>
我需要的是文件的名字
filename="touristappid.o6zAJs5MrQFix1tcXqPxSNHp7TYM.Qqpwv0q7GmO074368faff93b1673d56dd872406e5d09.jpg"
文件存放路徑/home/nginx/html/image/logo,
文件具體內(nèi)容也就是data這塊。
接下來(lái)來(lái)看看后端接口
#include <fcgi_stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <dirent.h>
#include <pthread.h>
#include <fcgiapp.h>
#include <sys/time.h>
#include <time.h>
#include <mysql/mysql.h>
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid) //解決獲取線程ID的問(wèn)題
#include "qsi.h"
#include "cJSON.h"
#define TEMP_BUF_MAX_LEN 51200
#define FILE_NAME_LEN 256
#define USER_NAME_LEN 256
#define THREAD_COUNT 10 //線程數(shù)
static int counts[THREAD_COUNT];
//FCGX_Request request;
static pthread_mutex_t pthread_mutex = PTHREAD_MUTEX_INITIALIZER;
int MUX_THREAD_TEST = 0;
char upload_error[256] = "/home/log/upload_error.log"; //日志文件目錄
/*
功能:獲取已經(jīng)上傳過(guò)后的文件列表,(文件名,MD5值)
參數(shù):
filePath 文件路徑
folderPath 文件夾路徑
返回值:成功0 失敗返回-1
*/
int getChunkList(char *filePath, char *folderPath, FCGX_Request request)
{
/*
將目錄下的所用文件組成一個(gè)文件列表,返回到前端
*/
char fullpath[256];
memset(fullpath, 0x00, 256);
sprintf(fullpath, "%s/%s", filePath, folderPath);
//創(chuàng)建一個(gè)文件jSON對(duì)象
cJSON * allfile = cJSON_CreateArray();
cJSON * fullnode= cJSON_CreateObject();
char * out = NULL;
if(NULL == fullpath)
{
FCGX_FPrintF(request.out,"%s", "enter path null!\n");
return -1;
}
DIR *dirp = opendir(fullpath); //打開目錄
if(dirp == NULL)
{
FCGX_FPrintF(request.out,"%s", "open dir err");
return -1;
}
struct dirent * dentp = NULL;
//讀取目錄下文件
while((dentp = readdir(dirp)))
{
if((strcmp(".", dentp->d_name)) == 0 || (strcmp("..", dentp->d_name)) == 0)
{
continue;
}
//不是目錄文件
if(dentp->d_type == DT_REG)
{
struct stat filestruct;
char newfilepath[256];
sprintf(newfilepath, "%s/%s", fullpath, dentp->d_name);
stat(newfilepath, &filestruct);
//創(chuàng)建一個(gè)jSON對(duì)象
cJSON *chunkList = NULL;
if(strcmp(folderPath, dentp->d_name ) == 0)
{
chunkList = cJSON_CreateObject();
cJSON_AddStringToObject(chunkList, "filename", dentp->d_name);
FCGX_FPrintF(request.out,"%s", cJSON_Print(chunkList));
cJSON_Delete(chunkList);
return 0;
}
else
{
cJSON_AddItemToArray(allfile, chunkList = cJSON_CreateObject());
cJSON_AddStringToObject(chunkList, "filename", dentp->d_name);
cJSON_AddNumberToObject(chunkList, "indexof", atoi(dentp->d_name));
}
}
else
{
return 0;
}
}
cJSON_AddItemToObject(fullnode, "chunkList", allfile);
FCGX_FPrintF(request.out,"%s", cJSON_Print(fullnode));
cJSON_Delete(fullnode);
return 0;
}
/*
判斷文件夾是否存在,文件夾不存在創(chuàng)建文件夾,
文件夾存在判斷里面的內(nèi)容是否正確,
如果文件存在就組織文件的json格式返回給前端,
如果文件不存在就返回目錄下的所用文件返回給前端
*/
/*
功能:判斷文件夾是否存在,不存在創(chuàng)建一個(gè)文件夾
參數(shù):
filepath 文件夾路徑
filename 文件夾名稱
返回值:成功返回0 失敗返回-1
*/
int folderIsExit(char *filepath, char *filename, FCGX_Request request)
{
char fullpath[256] = {0};
memset(fullpath, 0x00, sizeof(fullpath));
char new_file_name[256] = {0};
sprintf(new_file_name, "%s", filename);
sprintf(fullpath, "%s/%s", filepath, filename);
char errlog[256] = {0};
FCGI_FILE *fp = NULL;
if(access(fullpath, W_OK) == 0)
{
//目錄存在且有寫的權(quán)限 遍歷目錄下所有文件組織文件鏈表
if(getChunkList(filepath, filename, request))
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "error: getChunkList function error!\r\n");
fp = FCGI_fopen(upload_error,"ab+" );
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
}
}
else
{
//目錄不存在或沒(méi)有寫的權(quán)限
if(mkdir(fullpath, S_IRWXU|S_IRWXG|S_IRWXO) == -1) //0777
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "error:dir create error occurred mkdir function error!\r\n");
fp = FCGI_fopen(upload_error,"ab+" );
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
FCGX_FPrintF(request.out, "create dir error occurred!");
FCGX_FFlush(request.out);
}
else
{
pthread_mutex_lock(&pthread_mutex);
cJSON *fileinfo = cJSON_CreateObject();
cJSON_AddStringToObject(fileinfo, "fileName", new_file_name);
FCGX_FPrintF(request.out,"%s", cJSON_Print(fileinfo));
cJSON_Delete(fileinfo);
pthread_mutex_unlock(&pthread_mutex);
FCGX_FFlush(request.out);
}
}
FCGX_FFlush(request.in);
return 0;
}
/*
功能:在指定長(zhǎng)度的字符串中查找字符串
參數(shù):
(in) full_data 查找字符串
(in) full_data_len 查找長(zhǎng)度長(zhǎng)度
(in) substr 要查找的字符串
返回值:成功返回要查找的字符串的初始位置 失敗返回NULL
*/
char* memstr(char* full_data, int full_data_len, char* substr)
{
if (full_data == NULL || full_data_len <= 0 || substr == NULL)
{
return NULL;
}
if (*substr == '\0')
{
return NULL;
}
int sublen = strlen(substr);
char* cur = full_data;
int last_possible = full_data_len - sublen + 1;
int i = 0;
for (i = 0; i < last_possible; i++)
{
if (*cur == *substr)
{
if (memcmp(cur, substr, sublen) == 0)
{
// found
return cur;
}
}
cur++;
}
return NULL;
}
/**
* @brief 解析上傳的post數(shù)據(jù) 保存到本地臨時(shí)路徑
* 同時(shí)得到文件上傳者、文件名稱、文件大小
*
* @param len (in) post數(shù)據(jù)的長(zhǎng)度
* @param user (out) 文件上傳者
* @param file_name (out) 文件的文件名
* @param p_size (out) 文件大小
*
* @returns
* 0 succ, -1 fail
*/
int recv_save_file(long len, char *user, char *filename, long *p_size,
FCGX_Request request, char *filepath)
{
char log[526] = {0};
int ret = 0;
char *file_buf = NULL;
char *begin = NULL;
char *p = NULL, *q = NULL, *k = NULL;
int fd = 0;
int ret2 = 0;
char *heto = NULL;
char *to = NULL;
int totallen = 0;
char * toen = NULL;
int num = 0;
char errlog[256] = {0};
int FragmentName = 0;
char FragmentNum[50] = {0};
char FPATH[256] = {0};
char content_text[TEMP_BUF_MAX_LEN] = {0}; //文件頭部信息
char boundary[TEMP_BUF_MAX_LEN] = {0}; //分界線信息
FCGI_FILE *fp = NULL;
#if 0
if(!opendir(filepath))
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "error:upload file dir is NULL!\r\n");
fp = FCGI_fopen(upload_error, "ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
ret = -1;
goto END;
}
#endif
//==========> 開辟存放文件的 內(nèi)存 <===========
file_buf = (char *)malloc(len);
memset(file_buf,0x00, sizeof(file_buf));
if (file_buf == NULL)
{
goto END;
}
for(int i=0; i<len; i++) //讀取標(biāo)準(zhǔn)輸入
{
file_buf[i] = FCGX_GetChar(request.in);
}
begin = file_buf; //內(nèi)存起點(diǎn)
p = begin;
p = strstr(begin, "\r\n");
if (p == NULL)
{
ret = -1;
goto END;
}
//拷貝分界線
strncpy(boundary, begin, p - begin);
boundary[p-begin] = '\0'; //字符串結(jié)束符
p += 2;//\r\n
//已經(jīng)處理了p-begin的長(zhǎng)度
len -= (p-begin);
begin = p;
p = strstr(begin, "\r\n");
if(p == NULL)
{
ret = -1;
goto END;
}
strncpy(content_text, begin, p-begin); //拷貝Content-Disposition這一行內(nèi)容
content_text[p-begin] = '\0';
p += 2;//\r\n
len -= (p-begin);
//========================================獲取文件上傳者
//Content-Disposition: form-data; user="mike"; filename="xxx.jpg"; md5="xxxx"; size=10240\r\n ↑
q = begin;
q = strstr(begin, "name=");
//Content-Disposition: form-data; user="mike"; filename="xxx.jpg"; md5="xxxx"; size=10240\r\n ↑
q += strlen("name=");
q++; //跳過(guò)第一個(gè)"
//Content-Disposition: form-data; user="mike"; filename="xxx.jpg"; md5="xxxx"; size=10240\r\n ↑
k = strchr(q, '"');
strncpy(user, q, k-q); //拷貝用戶名
user[k-q] = '\0';
//FCGI_printf("user = %s\n" , user);
//去掉一個(gè)字符串兩邊的空白字符
//trim_space(user); //util_cgi.h
//========================================獲取文件名字
//"; filename="xxx.jpg"; md5="xxxx"; size=10240\r\n
// ↑
begin = k;
q = begin;
q = strstr(begin, "filename=");
//"; filename="xxx.jpg"; md5="xxxx"; size=10240\r\n
// ↑
q += strlen("filename=");
q++; //跳過(guò)第一個(gè)"
//"; filename="xxx.jpg"; md5="xxxx"; size=10240\r\n ↑
k = strchr(q, '"');
strncpy(filename, q, k-q); //拷貝文件名
filename[k-q] = '\0';
begin = p;
p = strstr(begin, "\r\n");
p += 4;//\r\n\r\n
len -= (p-begin);
//下面才是文件的真正內(nèi)容
begin = p;
//find file's end
p = memstr(begin, len, boundary);//util_cgi.h, 找文件結(jié)尾
if (p == NULL)
{
ret = -1;
goto END;
}
else
{
p = p - 2;//\r\n
}
//解析獲的文件編號(hào) 獲取總片數(shù)
heto = p + 2;
to = NULL;
to = strstr(heto, "\r\n");
to += 4;
totallen = 0;
toen = strstr(to, "\r\n");
toen += 4;
to = toen;
toen = strstr(to, "\r\n");
totallen = toen - to;
memset(FragmentNum, 0x00, sizeof(FragmentNum));
strncpy(FragmentNum, to, toen - to); //獲取片段總數(shù)
num = atoi(FragmentNum);
toen+= 2;
to = toen;
toen = strstr(to, "\r\n");
toen += 2;
to = toen;
toen = strstr(to, "\r\n");
toen += 4;
to = toen;
toen = strstr(to, "\r\n");
memset(FragmentNum, 0x00, sizeof(FragmentNum));
strncpy(FragmentNum, to, toen - to);
FragmentName = atoi(FragmentNum);
sprintf(FPATH, "%s/%s", filepath, FragmentNum);
fd = open(FPATH, O_CREAT|O_WRONLY, 0644);
if (fd < 0)
{
ret = -1;
goto END;
}
//ftruncate會(huì)將參數(shù)fd指定的文件大小改為參數(shù)length指定的大小
ftruncate(fd, (p-begin));
write(fd, begin, (p-begin));
close(fd);
END:
free(file_buf);
file_buf = NULL;
FCGX_FFlush(request.in);
memset(log, 0x00, strlen(log));
memset(FragmentNum, 0x00, strlen(FragmentNum));
memset(FPATH, 0x00, strlen(FPATH));
memset(content_text, 0x00, strlen(content_text));
memset(boundary, 0x00, strlen(boundary));
if(begin)
{
begin = NULL;
}
if(p)
{
p = NULL;
}
if(q)
{
q = NULL;
}
if(k)
{
k = NULL;
}
if(heto)
{
heto = NULL;
}
if(to)
{
to = NULL;
}
if(toen)
{
toen = NULL;
}
return ret;
}
/*
功能:獲取文件大小
參數(shù):
path 文件路徑
返回值:成功返回文件大小 失敗返回-1
*/
int getfilesize(char *path)
{
FILE *pf = fopen(path, "rb");
if (pf==NULL)
{
return -1;
}
else
{
fseek(pf, 0, SEEK_END);
int size = ftell(pf);
fclose(pf);
return size;
}
}
/*
功能:將多個(gè)文件合并為一個(gè)文件, 同時(shí)刪除片段文件
參數(shù):
part_f_path 片段文件路徑
filepath 合并后文件路徑
filename 合并后文件名
返回值: 成功返回 0 失敗返回-1
*/
int merge(char *part_f_path , int part_num, char *filepath, char *filename, FCGX_Request request)
{
char newpath[part_num][600]; //代表路徑
for(int i=0; i<part_num; i++)
{
memset(newpath[i], 0x00, sizeof(newpath[i]));
}
char fullpath[500] = {0};
memset(fullpath, 0x00, sizeof(fullpath));
sprintf(fullpath, "%s/%s",filepath, filename);
for (int i = 0; i < part_num; i++)
{
sprintf(newpath[i], "%s/%d", part_f_path, i);
}
FCGI_FILE *pfw = fopen(fullpath, "wb");
for (int i = 0; i < part_num; i++)
{
int length = getfilesize(newpath[i]);
if (length != -1)
{
FCGI_FILE *pfr = FCGI_fopen(newpath[i], "rb"); //讀取
for (int j = 0; j < length; j++)
{
char ch = fgetc(pfr);
fputc(ch, pfw); //寫入
}
FCGI_fclose(pfr);
remove(newpath[i]);
}
}
FCGI_fclose(pfw);
return 0;
}
int wx_recv_save_file(long len, char *user, char *filepath, char *filename,
long *p_size, FCGX_Request request)
{
char fullpath[256] = {0};
char newfile[256] = {0};
char file_md5[256] = {0};
char newname[256] = {0};
int ret = 0;
int num = 1;
char head_name[256] = {0};
char *end_name = NULL;
char *file_buf = NULL;
char *begin = NULL;
char *p = NULL, *q = NULL, *k = NULL;
FCGI_FILE * fd = NULL;
int ret2 = 0;
char *heto = NULL;
char *to = NULL;
int totallen = 0;
char * toen = NULL;
char *filepath_head = NULL, *filepath_end = NULL;
char path[256] = {0};
int FragmentName = 0;
char FragmentNum[50] = {0};
char FPATH[256] = {0};
char *f = NULL, *e = NULL;
char content_text[TEMP_BUF_MAX_LEN] = {0}; //文件頭部信息
char boundary[TEMP_BUF_MAX_LEN] = {0}; //分界線信息
char errlog[256] = {0};
FCGI_FILE *fp = NULL;
#if 0
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "debug info: write funcition start !\r\n");
fp = FCGI_fopen(upload_error,"ab+" );
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
#endif
//==========> 開辟存放文件的 內(nèi)存 <===========
file_buf = (char *)malloc(len);
memset(file_buf, 0x00, len);
if (file_buf == NULL)
{
goto END;
}
if (file_buf == NULL)
{
goto END;
}
pthread_mutex_lock(&pthread_mutex);
for(int i = 0; i < len; i++) //讀取標(biāo)準(zhǔn)輸入
{
file_buf[i] = FCGX_GetChar(request.in);
}
pthread_mutex_unlock(&pthread_mutex);
//===========> 開始處理前端發(fā)送過(guò)來(lái)的post數(shù)據(jù)格式 <============
begin = file_buf; //內(nèi)存起點(diǎn)
p = begin;
p = strstr(begin, "\r\n");
if (p == NULL)
{
ret = -1;
goto END;
}
//拷貝分界線
strncpy(boundary, begin, p-begin);
boundary[p-begin] = '\0'; //字符串結(jié)束符 拿到分界線
p += 2;//\r\n
//已經(jīng)處理了p-begin的長(zhǎng)度
len -= (p-begin);
begin = p;
p = strstr(begin, "\r\n");
if(p == NULL)
{
ret = -1;
goto END;
}
strncpy(content_text, begin, p-begin); //拷貝Content-Disposition這一行內(nèi)容
content_text[p-begin] = '\0';
p += 2; //\r\n
len -= (p - begin);
/*******************************/
filepath_head = p + 2;
filepath_end = strstr(filepath_head, "\r\n");
strncpy(path, filepath_head, filepath_end - filepath_head);
if(NULL == filepath)
{
filepath = path;
}
↑
q = begin;
q = strstr(begin, "name=");
q += strlen("name=");
q++; //跳過(guò)第一個(gè)"
k = strchr(q, '"');
strncpy(user, q, k-q); //拷貝用戶名
user[k-q] = '\0';
begin = k;
q = begin;
q = strstr(begin, "filename=");
↑
q += strlen("filename=");
q++; //跳過(guò)第一個(gè)"
k = strchr(q, '"');
strncpy(file_md5, q, k-q); //拷貝文件名
file_md5[k-q] = '\0';
p+=2;
begin = p;
p = strstr(begin, "\r\n");
p += 2;//\r\n
len -= (p-begin);
begin = p;
p = strstr(begin, "\r\n");
p+=2;
len -= (p-begin);
begin = p;
f = strstr(begin, "name=");
f += strlen("name=");
f++;
e = strchr(f, '"');
strncpy(newfile, f, e - f);
#if 0
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "debug info: newfile =%s\r\n", newfile);
fp = FCGI_fopen(upload_error,"ab+" );
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
#endif
p = strstr(begin, "\r\n");
p+=2;
len -= (p-begin);
begin = p;
p = strstr(begin, "\r\n");
p+=4;
len -= (p-begin);
//下面才是文件的真正內(nèi)容
begin = p;
len -= (p - begin);
p = memstr(begin, len, boundary);
if (p == NULL)
{
ret = -1;
goto END;
}
else
{
p = p - 2;//\r\n
}
sprintf(fullpath, "%s/%s", filepath, file_md5);
if(!opendir(filepath))
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "error:upload file dir is NULL!\r\n");
fp = FCGI_fopen(upload_error, "ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
ret = -1;
goto END;
}
#if 0
/*
判斷文件是否存在
*/
while(access(fullpath, F_OK) != -1)
{
end_name = strrchr(file_md5, '.');
strncpy(head_name, file_md5, end_name - file_md5);
sprintf(file_md5, "%s(%d)%s", head_name, num, end_name);
sprintf(fullpath, "%s/%s", filepath, file_md5);
num++;
};
#endif
fd = FCGI_fopen(fullpath, "wb+");
if (fd < 0)
{
ret = -1;
goto END;
}
FCGI_fwrite(begin, 1, (p-begin), fd);
FCGI_fclose(fd);
END:
if(file_buf)
{
free(file_buf);
file_buf = NULL;
}
FCGX_FFlush(request.in);
memset(fullpath, 0x00, strlen(fullpath));
if(begin)
{
begin = NULL;
}
if(p)
{
p = NULL;
}
if(q)
{
q = NULL;
}
if(k)
{
k = NULL;
}
if(heto)
{
heto = NULL;
}
if(to)
{
to = NULL;
}
if(toen)
{
toen = NULL;
}
if(filepath_head)
{
filepath_head = NULL;
}
if(filepath_end)
{
filepath_end = NULL;
}
if(end_name)
{
end_name = NULL;
}
memset(head_name, 0x00, strlen(head_name));
memset(content_text, 0x00, TEMP_BUF_MAX_LEN);
memset(boundary, 0x00, TEMP_BUF_MAX_LEN);
memset(file_md5, 0x00, sizeof(file_md5));
return ret;
}
/*
線程處理函數(shù)
*/
static void *doit(void *a)
{
int rc, i, thread_id;
thread_id = (int)((long)a);
pid_t pid = gettid();
char *server_name;
#if 1
pthread_mutex_lock(&pthread_mutex);
char errlog[256];
MUX_THREAD_TEST++;
sprintf(errlog, "-- pthread %d start MUX_THREAD_TEST= %d --\r\n", pid, MUX_THREAD_TEST);
FCGI_FILE *fp = NULL;
fp = FCGI_fopen(upload_error,"ab+" );
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
#endif
int count = 0;
int flag = 0;
long len = 0.0;
int ret = 0;
char user[56] = {0}; //文件上傳者
long size = 0;
char get_filePath[20] = "filepath";
char get_fileName[20] = "filename";
char get_fileMd5Value[56] = "fileMd5Value";
char get_chunks[56] = "chunks";
char *filepath = NULL;
FCGX_Request request;
FCGX_InitRequest(&request, 0, 0); //初始化request
for (;;)
{
static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Some platforms require accept() serialization, some don't.. */
pthread_mutex_lock(&accept_mutex);
rc = FCGX_Accept_r(&request);
pthread_mutex_unlock(&accept_mutex);
if (rc < 0)
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "pthread tid = %d, FCGX_Accept_r error!\r\n", pid);
fp = FCGI_fopen(upload_error,"ab+" );
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
break;
}
server_name = FCGX_GetParam("SERVER_NAME", request.envp); //從環(huán)境變量中獲取SERVER_NAME名
FCGX_FPrintF(request.out,"Content-type: text/html; charset=UTF-8\r\n\r\n");
char *contentLength = FCGX_GetParam("CONTENT_LENGTH", request.envp); //獲取環(huán)境變量
char *querystring = FCGX_GetParam("QUERY_STRING", request.envp);
char name[256] = "method";
char *method = get_query_string(querystring, name);
char *filename = get_query_string(querystring, get_fileName);
char *fileMd5Value = get_query_string(querystring, get_fileMd5Value);
char *chunks = get_query_string(querystring, get_chunks);
#if 0
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "doit MUX_THREAD_TEST= %d\r\n", MUX_THREAD_TEST);
fp = FCGI_fopen(upload_error,"ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
if(NULL == method)
{
FCGX_FPrintF(request.out,"{\"result\": false, \"msg\":method is NULL!}");
FCGX_FFlush(request.out);
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "method is NULL error tid = %d MUX_THREAD_TEST= %d\r\n", pid, MUX_THREAD_TEST);
fp = FCGI_fopen(upload_error, "ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
goto END;
}
#endif
if(strcasecmp(method, "check") == 0) //判斷文件是否存在
{
char filepath[256] = "../file";
if(!folderIsExit(filepath, fileMd5Value, request))
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "%s dir ok!\r\n", fileMd5Value);
fp = FCGI_fopen(upload_error,"ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
FCGX_Finish_r(&request);
}
else
{
FCGX_FPrintF(request.out, "crean %s dir error!", fileMd5Value);
FCGX_Finish_r(&request);
}
}
else if(strcasecmp(method, "merge") == 0)
{
char filepath[600] ={0};
int int_chunks = atoi(chunks);
sprintf(filepath, "../file/%s", fileMd5Value);
if(merge(filepath , int_chunks, filepath, filename, request) < 0)
{
FCGX_FPrintF(request.out, "merge function error!");
FCGX_FFlush(request.out);
FCGX_Finish_r(&request);
}
else
{
FCGX_FPrintF(request.out, "merge function ok!");
FCGX_FFlush(request.out);
FCGX_Finish_r(&request);
}
}
else if(strcasecmp(method, "upload") == 0)
{
char new_file_name[256] = {0};
char new_filemd5_value[256] = {0};
sprintf(new_file_name, "%s", filename);
sprintf(new_filemd5_value, "%s", fileMd5Value);
if (contentLength != NULL)
{
time_t timer; //time_t就是long int 類型
struct tm *tblock;
timer = time(NULL);
tblock = localtime(&timer);
len = strtol(contentLength, NULL, 10); //字符串轉(zhuǎn)long, 或者atol
cJSON *fileinfo = cJSON_CreateObject();
cJSON_AddStringToObject(fileinfo, "fileName", new_file_name);
cJSON_AddStringToObject(fileinfo, "fileMd5Value", new_filemd5_value);
cJSON_AddNumberToObject(fileinfo, "len", len);
cJSON_AddStringToObject(fileinfo, "time", asctime(tblock));
FCGX_FPrintF(request.out,"%s", cJSON_Print(fileinfo));
cJSON_Delete(fileinfo);
FCGX_FFlush(request.out);
}
else
{
len = 0;
}
if (len <= 0)
{
FCGX_FPrintF(request.out, "No data from standard input\n");
FCGX_FFlush(request.out);
ret = -1;
}
else
{
char filepath[600] ={0};
sprintf(filepath, "../file/%s", fileMd5Value);
if (recv_save_file(len, user, filename, &size, request, filepath) < 0)
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "%s write error!\r\n", new_file_name);
fp = FCGI_fopen(upload_error, "ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
ret = -1;
goto END;
}
else
{
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "%s write ok!\r\n", new_file_name);
fp = FCGI_fopen(upload_error, "ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
}
}
FCGX_Finish_r(&request);
}
else if(strcasecmp(method, "wxupload") == 0)
{
#if 0
pthread_mutex_lock(&pthread_mutex);
char log[25] = {0};
MUX_THREAD_TEST++;
sprintf(log, "%d pid = %d", MUX_THREAD_TEST, pid);
write_log(upload_error, log, strlen(log));
memset(log, 0x00, strlen(log));
pthread_mutex_unlock(&pthread_mutex);
#endif
if (contentLength != NULL)
{
filepath = NULL;
len = strtol(contentLength, NULL, 10);
#if 0
pthread_mutex_lock(&pthread_mutex);
sprintf(errlog, "contentLength pthread tid = %d MUX_THREAD_TEST= %d !\r\n", pid, MUX_THREAD_TEST);
fp = FCGI_fopen(upload_error, "ab+");
FCGI_fwrite(errlog, 1, strlen(errlog), fp);
FCGI_fclose(fp);
memset(errlog, 0x00, strlen(errlog));
pthread_mutex_unlock(&pthread_mutex);
#endif
if(wx_recv_save_file(len, user, filepath, filename, &size, request) < 0)
{
FCGX_FPrintF(request.out, "{\"result\": false, \"msg\": file read data error, see upload_error.log!}");
FCGX_FFlush(request.out);
FCGX_Finish_r(&request);
continue;
}
else
{
FCGX_FPrintF(request.out, "{\"result\": true, \"msg\":file upload ok!}");
FCGX_FFlush(request.out);
MUX_THREAD_TEST++;
}
}
else
{
FCGX_FPrintF(request.out, "contentLength is NULL tid=%d!}", pid);
goto END;
}
END:
FCGX_Finish_r(&request);
}
else
{
FCGX_FPrintF(request.out,"{\"result\": false, \"msg\":tid = %d input function name error!}", pid);
FCGX_FFlush(request.out);
FCGX_Finish_r(&request);
}
}
return NULL;
}
int main()
{
long i;
pthread_t id[THREAD_COUNT];
FCGX_Init();
for (i = 1; i < THREAD_COUNT; i++)
{
pthread_create(&id[i], NULL, doit, (void*)i);
//pthread_detach(id[i]);
}
doit(0);
return 0;
}
編譯腳本
#!/bin/bash
src="/home/UploadFile/src"
cgi="/home/UploadFile/cgi"
inc="/home/UploadFile/include"
obj="/home/UploadFile/obj"
rm ${obj}/qsi.o
rm ${obj}/upload.o
rm ${obj}/cJSON_cgi.o
rm ${cgi}/upload.cgi
g++ -c -I ${inc} -DTBSVIDEODEAL_CGI -std=c++11 -o ${obj}/qsi.o ${src}/qsi.cpp
g++ -c -I ${inc} -DTBSVIDEODEAL_CGI -std=c++11 -o ${obj}/upload.o ${src}/upload.c
g++ -c -I ${inc} -DTBSVIDEODEAL_CGI -std=c++11 -o ${obj}/cJSON_cgi.o ${src}/cJSON.c
g++ -o ${cgi}/upload.cgi -g ${obj}/qsi.o ${obj}/upload.o ${obj}/cJSON_cgi.o -L /usr/local/lib -Wl,-Bstatic -l:libfcgi.a -Wl,-Bdynamic -lpthread -lmysqlclient
cp ${cgi}/upload.cgi ${cgi}/upload.fcgi