后台代码实现
我的文件列表Mian读取配置信息解析json登录token(cmd为count)解析jason(cmd不为count)获取用户文件个数获取用户文件列表源码
共享文件列表main获取共享文件个数前端分页请求包获得普通共享文件列表共享文件排行榜源码
我的文件列表
业务逻辑是,点击我的文件,会在展示界面展示出该用户所有文件单机图标会显示选项下载,分享,删除,属性单机空白处会显示选型,会显示选项:按下载量排序/按下载量排序/刷新/上传其中上传操作也可以点击界面中的上传图标,然后会弹出窗口选择要上传的文件,上传过程是一个toolbar会显示进度在传输列表中
实质是两张表联查 file_info, user_file_list ,做了物理分页,根据指令按照pv字段做升序降序排列
Mian
读取配置文件 read_cfg();拿到数据库连接
while (FCGI_Accept() >= 0)等待连接
业务主要分两种,一是只想知道用户有多少个文件,另一个是普通排序,按照pv升降序排序;均为post请求;为post请求时,由环境变量cmd拿到请求指令,由buf缓冲区拿到数据
cmd为count,获取用户文件个数if (strcmp(cmd, “count”) == 0) ,查表 get_user_files_count(user, ret); //获取用户文件个数
cmd为normal;pvacs;pvdesc;获取用户文件列表 get_user_filelist(cmd, user, start, count);
需要注意的是,在fcgi程序中,直接fread是从标准输入读,就是从web服务器读;直接printf就是往标准输出,也是往web服务器(cgi程序利用I.O重定向技术)
int main()
{
//count 获取用户文件个数
//display 获取用户文件信息,展示到前端
char cmd[20];
char user[USER_NAME_LEN];
char token[TOKEN_LEN];
//读取数据库配置信息
read_cfg();
//阻塞等待用户连接
while (FCGI_Accept() >= 0)
{
// 获取URL地址 "?" 后面的内容
char *query = getenv("QUERY_STRING");
//解析命令
query_parse_key_value(query, "cmd", cmd, NULL);
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cmd = %s\n", cmd);
char *contentLength = getenv("CONTENT_LENGTH");
int len;
printf("Content-type: text/html\r\n\r\n");
if( contentLength == NULL )
{
len = 0;
}
else
{
len = atoi(contentLength); //字符串转整型
}
if (len <= 0)
{
printf("No data from standard input.<p>\n");
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "len = 0, No data from standard input\n");
}
else
{
char buf[4*1024] = {0};
int ret = 0;
ret = fread(buf, 1, len, stdin); //从标准输入(web服务器)读取内容
if(ret == 0)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "fread(buf, 1, len, stdin) err\n");
continue;
}
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "buf = %s\n", buf);
if (strcmp(cmd, "count") == 0) //count 获取用户文件个数
{
get_count_json_info(buf, user, token); //通过json包获取用户名, token
//验证登陆token,成功返回0,失败-1
ret = verify_token(user, token); //util_cgi.h
get_user_files_count(user, ret); //获取用户文件个数
}
//获取用户文件信息 127.0.0.1:80/myfiles&cmd=normal
//按下载量升序 127.0.0.1:80/myfiles?cmd=pvasc
//按下载量降序127.0.0.1:80/myfiles?cmd=pvdesc
else
{
int start; //文件起点
int count; //文件个数
get_fileslist_json_info(buf, user, token, &start, &count); //通过json包获取信息
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "user = %s, token = %s, start = %d, count = %d\n", user, token, start, count);
//验证登陆token,成功返回0,失败-1
ret = verify_token(user, token); //util_cgi.h
if(ret == 0)
{
get_user_filelist(cmd, user, start, count); //获取用户文件列表
}
else
{
char *out = return_status("111"); //token验证失败错误码
if(out != NULL)
{
printf(out); //给前端反馈错误码
free(out);
}
}
}
}
}
return 0;
}
读取配置信息
读取到MySQL配置文件信息
void read_cfg()
{
//读取mysql数据库配置信息
get_cfg_value(CFG_PATH, "mysql", "user", mysql_user);
get_cfg_value(CFG_PATH, "mysql", "password", mysql_pwd);
get_cfg_value(CFG_PATH, "mysql", "database", mysql_db);
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "mysql:[user=%s,pwd=%s,database=%s]", mysql_user, mysql_pwd, mysql_db);
//读取redis配置信息
//get_cfg_value(CFG_PATH, "redis", "ip", redis_ip);
//get_cfg_value(CFG_PATH, "redis", "port", redis_port);
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "redis:[ip=%s,port=%s]\n", redis_ip, redis_port);
}
解析json登录token(cmd为count)
cmd为count时,此时的json包格式为
{
"token": "9e894efc0b2a898a82765d0a7f2c94cb",
user:xxxx
}
此时,解析jason拿到token和username
//解析的json包, 登陆token
int get_count_json_info(char *buf, char *user, char *token)
{
int ret = 0;
/*json数据如下
{
"token": "9e894efc0b2a898a82765d0a7f2c94cb",
user:xxxx
}
*/
//解析json包
//解析一个json字符串为cJSON对象
cJSON * root = cJSON_Parse(buf);
if(NULL == root)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_Parse err\n");
ret = -1;
goto END;
}
//返回指定字符串对应的json对象
//用户
cJSON *child1 = cJSON_GetObjectItem(root, "user");
if(NULL == child1)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "child1->valuestring = %s\n", child1->valuestring);
strcpy(user, child1->valuestring); //拷贝内容
//登陆token
cJSON *child2 = cJSON_GetObjectItem(root, "token");
if(NULL == child2)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "child2->valuestring = %s\n", child2->valuestring);
strcpy(token, child2->valuestring); //拷贝内容
END:
if(root != NULL)
{
cJSON_Delete(root);//删除json对象
root = NULL;
}
return ret;
}
解析jason(cmd不为count)
作用是为了拿到user,token,start,count,用来给普通/升/降序同时物理分页查询准备
//解析的json包
int get_fileslist_json_info(char *buf, char *user, char *token, int *p_start, int *p_count)
{
int ret = 0;
/*json数据如下
{
"user": "yoyo"
"token": xxxx
"start": 0
"count": 10
}
*/
//解析json包
//解析一个json字符串为cJSON对象
cJSON * root = cJSON_Parse(buf);
if(NULL == root)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_Parse err\n");
ret = -1;
goto END;
}
//返回指定字符串对应的json对象
//用户
cJSON *child1 = cJSON_GetObjectItem(root, "user");
if(NULL == child1)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "child1->valuestring = %s\n", child1->valuestring);
strcpy(user, child1->valuestring); //拷贝内容
//token
cJSON *child2 = cJSON_GetObjectItem(root, "token");
if(NULL == child2)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
strcpy(token, child2->valuestring); //拷贝内容
//文件起点
cJSON *child3 = cJSON_GetObjectItem(root, "start");
if(NULL == child3)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_start = child3->valueint;
//文件请求个数
cJSON *child4 = cJSON_GetObjectItem(root, "count");
if(NULL == child4)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_count = child4->valueint;
END:
if(root != NULL)
{
cJSON_Delete(root);//删除json对象
root = NULL;
}
return ret;
}
获取用户文件个数
数据库查询操作 sprintf(sql_cmd, “select count from user_file_count where user=”%s"", user);
将结果封装进tmp int ret2 = process_result_one(conn, sql_cmd, tmp);
//获取用户文件个数
void get_user_files_count(char *user, int ret)
{
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
long line = 0;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "msql_conn err\n");
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
sprintf(sql_cmd, "select count from user_file_count where user=\"%s\"", user);
char tmp[512] = {0};
//返回值: 0成功并保存记录集,1没有记录集,2有记录集但是没有保存,-1失败
int ret2 = process_result_one(conn, sql_cmd, tmp); //指向sql语句
if(ret2 != 0)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s 操作失败\n", sql_cmd);
goto END;
}
line = atol(tmp); //字符串转长整形
END:
if(conn != NULL)
{
mysql_close(conn);
}
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "line = %ld\n", line);
//给前端反馈的信息
return_login_status(line, ret);
}
获取用户文件列表
get_user_filelist(char *cmd, char *user, int start, int count)需要参数cmd,user,start,count(这两个参数在前端设置好)
- cmd为normal
普通查询只做了物理分页,==limit %d, %d", user, start, count==
if(strcmp(cmd, "normal") == 0) //获取用户文件信息
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 limit %d, %d", user, start, count);
}
- cmd为pvasc
升序查询按照pv排序同时做了物理分页,==order by pv asc limit %d, %d", user, start, count)==
else if(strcmp(cmd, "pvasc") == 0) //按下载量升序
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 order by pv asc limit %d, %d", user, start, count);
}
- cmd为pvdesc
降序查询按照pv排序同时做了物理分页,==order by pv desc limit %d, %d", user, start, count==
else if(strcmp(cmd, "pvdesc") == 0) //按下载量降序
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 order by pv desc limit %d, %d", user, start, count);
}
进行查询 if (mysql_query(conn, sql_cmd) != 0)
生成结果集 res_set = mysql_store_result(conn);/生成结果集/
对结果集进行处理
数据库的查询结果是一行行的,游标依次往下拿到每一个字段的值,封装进jason对象 cJSON_AddItemToArray(array, item);再封装进数组cJSON_AddItemToObject(root, “files”, array)代表所有文件的列表,再将该数组封装进root根对象转为字符串发送前端 int get_user_filelist(char *cmd, char *user, int start, int count)
{
int ret = 0;
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
cJSON *root = NULL;
cJSON *array =NULL;
char *out = NULL;
char *out2 = NULL;
MYSQL_RES *res_set = NULL;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "msql_conn err\n");
ret = -1;
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
//多表指定行范围查询
if(strcmp(cmd, "normal") == 0) //获取用户文件信息
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 limit %d, %d", user, start, count);
}
else if(strcmp(cmd, "pvasc") == 0) //按下载量升序
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 order by pv asc limit %d, %d", user, start, count);
}
else if(strcmp(cmd, "pvdesc") == 0) //按下载量降序
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 order by pv desc limit %d, %d", user, start, count);
}
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s 在操作\n", sql_cmd);
if (mysql_query(conn, sql_cmd) != 0)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s 操作失败:%s\n", sql_cmd, mysql_error(conn));
ret = -1;
goto END;
}
res_set = mysql_store_result(conn);/*生成结果集*/
if (res_set == NULL)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "smysql_store_result error: %s!\n", mysql_error(conn));
ret = -1;
goto END;
}
ulong line = 0;
//mysql_num_rows接受由mysql_store_result返回的结果结构集,并返回结构集中的行数
line = mysql_num_rows(res_set);
if (line == 0)//没有结果
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "mysql_num_rows(res_set) failed:%s\n", mysql_error(conn));
ret = -1;
goto END;
}
MYSQL_ROW row;
root = cJSON_CreateObject();
array = cJSON_CreateArray();
// mysql_fetch_row从使用mysql_store_result得到的结果结构中提取一行,并把它放到一个行结构中。
// 当数据用完或发生错误时返回NULL.
while ((row = mysql_fetch_row(res_set)) != NULL)
{
//array[i]:
cJSON* item = cJSON_CreateObject();
//mysql_num_fields获取结果中列的个数
/*for(i = 0; i < mysql_num_fields(res_set); i++)
{
if(row[i] != NULL)
{
}
}*/
/*
{
"user": "yoyo",
"md5": "e8ea6031b779ac26c319ddf949ad9d8d",
"time": "2017-02-26 21:35:25",
"filename": "test.mp4",
"share_status": 0,
"pv": 0,
"url": "http://192.168.31.109:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
"size": 27473666,
"type": "mp4"
}
*/
//-- user 文件所属用户
if(row[0] != NULL)
{
cJSON_AddStringToObject(item, "user", row[0]);
}
//-- md5 文件md5
if(row[1] != NULL)
{
cJSON_AddStringToObject(item, "md5", row[1]);
}
//-- createtime 文件创建时间
if(row[2] != NULL)
{
cJSON_AddStringToObject(item, "time", row[2]);
}
//-- filename 文件名字
if(row[3] != NULL)
{
cJSON_AddStringToObject(item, "filename", row[3]);
}
//-- shared_status 共享状态, 0为没有共享, 1为共享
if(row[4] != NULL)
{
cJSON_AddNumberToObject(item, "share_status", atoi( row[4] ));
}
//-- pv 文件下载量,默认值为0,下载一次加1
if(row[5] != NULL)
{
cJSON_AddNumberToObject(item, "pv", atol( row[5] ));
}
//-- url 文件url
if(row[6] != NULL)
{
cJSON_AddStringToObject(item, "url", row[6]);
}
//-- size 文件大小, 以字节为单位
if(row[7] != NULL)
{
cJSON_AddNumberToObject(item, "size", atol( row[7] ));
}
//-- type 文件类型: png, zip, mp4……
if(row[8] != NULL)
{
cJSON_AddStringToObject(item, "type", row[8]);
}
cJSON_AddItemToArray(array, item);
}
cJSON_AddItemToObject(root, "files", array);
out = cJSON_Print(root);
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s\n", out);
END:
if(ret == 0)
{
printf("%s", out); //给前端反馈信息
}
else
{ //失败
/*
获取用户文件列表:
成功:文件列表json
失败:{"code": "015"}
*/
out2 = NULL;
out2 = return_status("015");
}
if(out2 != NULL)
{
printf(out2); //给前端反馈错误码
free(out2);
}
if(res_set != NULL)
{
//完成所有对数据的操作后,调用mysql_free_result来善后处理
mysql_free_result(res_set);
}
if(conn != NULL)
{
mysql_close(conn);
}
if(root != NULL)
{
cJSON_Delete(root);
}
if(out != NULL)
{
free(out);
}
return ret;
}
源码
/**
* @file myfiles_cgi.c
* @brief 用户列表展示CGI程序
* @author Mike
* @version 2.0
* @date 2017年2月27日
*/
#include "fcgi_config.h"
#include "fcgi_stdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "make_log.h" //日志头文件
#include "util_cgi.h"
#include "deal_mysql.h"
#include "cfg.h"
#include "cJSON.h"
#include <sys/time.h>
#define MYFILES_LOG_MODULE "cgi"
#define MYFILES_LOG_PROC "myfiles"
//mysql 数据库配置信息 用户名, 密码, 数据库名称
static char mysql_user[128] = {0};
static char mysql_pwd[128] = {0};
static char mysql_db[128] = {0};
//redis 服务器ip、端口
//static char redis_ip[30] = {0};
//static char redis_port[10] = {0};
//读取配置信息
void read_cfg()
{
//读取mysql数据库配置信息
get_cfg_value(CFG_PATH, "mysql", "user", mysql_user);
get_cfg_value(CFG_PATH, "mysql", "password", mysql_pwd);
get_cfg_value(CFG_PATH, "mysql", "database", mysql_db);
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "mysql:[user=%s,pwd=%s,database=%s]", mysql_user, mysql_pwd, mysql_db);
//读取redis配置信息
//get_cfg_value(CFG_PATH, "redis", "ip", redis_ip);
//get_cfg_value(CFG_PATH, "redis", "port", redis_port);
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "redis:[ip=%s,port=%s]\n", redis_ip, redis_port);
}
//解析的json包, 登陆token
int get_count_json_info(char *buf, char *user, char *token)
{
int ret = 0;
/*json数据如下
{
"token": "9e894efc0b2a898a82765d0a7f2c94cb",
user:xxxx
}
*/
//解析json包
//解析一个json字符串为cJSON对象
cJSON * root = cJSON_Parse(buf);
if(NULL == root)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_Parse err\n");
ret = -1;
goto END;
}
//返回指定字符串对应的json对象
//用户
cJSON *child1 = cJSON_GetObjectItem(root, "user");
if(NULL == child1)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "child1->valuestring = %s\n", child1->valuestring);
strcpy(user, child1->valuestring); //拷贝内容
//登陆token
cJSON *child2 = cJSON_GetObjectItem(root, "token");
if(NULL == child2)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "child2->valuestring = %s\n", child2->valuestring);
strcpy(token, child2->valuestring); //拷贝内容
END:
if(root != NULL)
{
cJSON_Delete(root);//删除json对象
root = NULL;
}
return ret;
}
//返回前端情况
void return_login_status(long num, int token_flag)
{
char *out = NULL;
char *token;
char num_buf[128] = {0};
if(token_flag == 0)
{
token = "110"; //成功
}
else
{
token = "111"; //失败
}
//数字
sprintf(num_buf, "%ld", num);
cJSON *root = cJSON_CreateObject(); //创建json项目
cJSON_AddStringToObject(root, "num", num_buf);// {"num":"1111"}
cJSON_AddStringToObject(root, "code", token);// {"code":"110"}
out = cJSON_Print(root);//cJSON to string(char *)
cJSON_Delete(root);
if(out != NULL)
{
printf(out); //给前端反馈信息
free(out); //记得释放
}
}
//获取用户文件个数
void get_user_files_count(char *user, int ret)
{
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
long line = 0;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "msql_conn err\n");
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
sprintf(sql_cmd, "select count from user_file_count where user=\"%s\"", user);
char tmp[512] = {0};
//返回值: 0成功并保存记录集,1没有记录集,2有记录集但是没有保存,-1失败
int ret2 = process_result_one(conn, sql_cmd, tmp); //指向sql语句
if(ret2 != 0)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s 操作失败\n", sql_cmd);
goto END;
}
line = atol(tmp); //字符串转长整形
END:
if(conn != NULL)
{
mysql_close(conn);
}
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "line = %ld\n", line);
//给前端反馈的信息
return_login_status(line, ret);
}
//解析的json包
int get_fileslist_json_info(char *buf, char *user, char *token, int *p_start, int *p_count)
{
int ret = 0;
/*json数据如下
{
"user": "yoyo"
"token": xxxx
"start": 0
"count": 10
}
*/
//解析json包
//解析一个json字符串为cJSON对象
cJSON * root = cJSON_Parse(buf);
if(NULL == root)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_Parse err\n");
ret = -1;
goto END;
}
//返回指定字符串对应的json对象
//用户
cJSON *child1 = cJSON_GetObjectItem(root, "user");
if(NULL == child1)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
//LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "child1->valuestring = %s\n", child1->valuestring);
strcpy(user, child1->valuestring); //拷贝内容
//token
cJSON *child2 = cJSON_GetObjectItem(root, "token");
if(NULL == child2)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
strcpy(token, child2->valuestring); //拷贝内容
//文件起点
cJSON *child3 = cJSON_GetObjectItem(root, "start");
if(NULL == child3)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_start = child3->valueint;
//文件请求个数
cJSON *child4 = cJSON_GetObjectItem(root, "count");
if(NULL == child4)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_count = child4->valueint;
END:
if(root != NULL)
{
cJSON_Delete(root);//删除json对象
root = NULL;
}
return ret;
}
//获取用户文件列表
//获取用户文件信息 127.0.0.1:80/myfiles&cmd=normal
//按下载量升序 127.0.0.1:80/myfiles?cmd=pvasc
//按下载量降序127.0.0.1:80/myfiles?cmd=pvdesc
int get_user_filelist(char *cmd, char *user, int start, int count)
{
int ret = 0;
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
cJSON *root = NULL;
cJSON *array =NULL;
char *out = NULL;
char *out2 = NULL;
MYSQL_RES *res_set = NULL;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "msql_conn err\n");
ret = -1;
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
//多表指定行范围查询
if(strcmp(cmd, "normal") == 0) //获取用户文件信息
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 limit %d, %d", user, start, count);
}
else if(strcmp(cmd, "pvasc") == 0) //按下载量升序
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 order by pv asc limit %d, %d", user, start, count);
}
else if(strcmp(cmd, "pvdesc") == 0) //按下载量降序
{
//sql语句
sprintf(sql_cmd, "select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 order by pv desc limit %d, %d", user, start, count);
}
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s 在操作\n", sql_cmd);
if (mysql_query(conn, sql_cmd) != 0)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s 操作失败:%s\n", sql_cmd, mysql_error(conn));
ret = -1;
goto END;
}
res_set = mysql_store_result(conn);/*生成结果集*/
if (res_set == NULL)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "smysql_store_result error: %s!\n", mysql_error(conn));
ret = -1;
goto END;
}
ulong line = 0;
//mysql_num_rows接受由mysql_store_result返回的结果结构集,并返回结构集中的行数
line = mysql_num_rows(res_set);
if (line == 0)//没有结果
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "mysql_num_rows(res_set) failed:%s\n", mysql_error(conn));
ret = -1;
goto END;
}
MYSQL_ROW row;
root = cJSON_CreateObject();
array = cJSON_CreateArray();
// mysql_fetch_row从使用mysql_store_result得到的结果结构中提取一行,并把它放到一个行结构中。
// 当数据用完或发生错误时返回NULL.
while ((row = mysql_fetch_row(res_set)) != NULL)
{
//array[i]:
cJSON* item = cJSON_CreateObject();
//mysql_num_fields获取结果中列的个数
/*for(i = 0; i < mysql_num_fields(res_set); i++)
{
if(row[i] != NULL)
{
}
}*/
/*
{
"user": "yoyo",
"md5": "e8ea6031b779ac26c319ddf949ad9d8d",
"time": "2017-02-26 21:35:25",
"filename": "test.mp4",
"share_status": 0,
"pv": 0,
"url": "http://192.168.31.109:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
"size": 27473666,
"type": "mp4"
}
*/
//-- user 文件所属用户
if(row[0] != NULL)
{
cJSON_AddStringToObject(item, "user", row[0]);
}
//-- md5 文件md5
if(row[1] != NULL)
{
cJSON_AddStringToObject(item, "md5", row[1]);
}
//-- createtime 文件创建时间
if(row[2] != NULL)
{
cJSON_AddStringToObject(item, "time", row[2]);
}
//-- filename 文件名字
if(row[3] != NULL)
{
cJSON_AddStringToObject(item, "filename", row[3]);
}
//-- shared_status 共享状态, 0为没有共享, 1为共享
if(row[4] != NULL)
{
cJSON_AddNumberToObject(item, "share_status", atoi( row[4] ));
}
//-- pv 文件下载量,默认值为0,下载一次加1
if(row[5] != NULL)
{
cJSON_AddNumberToObject(item, "pv", atol( row[5] ));
}
//-- url 文件url
if(row[6] != NULL)
{
cJSON_AddStringToObject(item, "url", row[6]);
}
//-- size 文件大小, 以字节为单位
if(row[7] != NULL)
{
cJSON_AddNumberToObject(item, "size", atol( row[7] ));
}
//-- type 文件类型: png, zip, mp4……
if(row[8] != NULL)
{
cJSON_AddStringToObject(item, "type", row[8]);
}
cJSON_AddItemToArray(array, item);
}
cJSON_AddItemToObject(root, "files", array);
out = cJSON_Print(root);
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "%s\n", out);
END:
if(ret == 0)
{
printf("%s", out); //给前端反馈信息
}
else
{ //失败
/*
获取用户文件列表:
成功:文件列表json
失败:{"code": "015"}
*/
out2 = NULL;
out2 = return_status("015");
}
if(out2 != NULL)
{
printf(out2); //给前端反馈错误码
free(out2);
}
if(res_set != NULL)
{
//完成所有对数据的操作后,调用mysql_free_result来善后处理
mysql_free_result(res_set);
}
if(conn != NULL)
{
mysql_close(conn);
}
if(root != NULL)
{
cJSON_Delete(root);
}
if(out != NULL)
{
free(out);
}
return ret;
}
int main()
{
//count 获取用户文件个数
//display 获取用户文件信息,展示到前端
char cmd[20];
char user[USER_NAME_LEN];
char token[TOKEN_LEN];
//读取数据库配置信息
read_cfg();
//阻塞等待用户连接
while (FCGI_Accept() >= 0)
{
// 获取URL地址 "?" 后面的内容
char *query = getenv("QUERY_STRING");
//解析命令
query_parse_key_value(query, "cmd", cmd, NULL);
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "cmd = %s\n", cmd);
char *contentLength = getenv("CONTENT_LENGTH");
int len;
printf("Content-type: text/html\r\n\r\n");
if( contentLength == NULL )
{
len = 0;
}
else
{
len = atoi(contentLength); //字符串转整型
}
if (len <= 0)
{
printf("No data from standard input.<p>\n");
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "len = 0, No data from standard input\n");
}
else
{
char buf[4*1024] = {0};
int ret = 0;
ret = fread(buf, 1, len, stdin); //从标准输入(web服务器)读取内容
if(ret == 0)
{
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "fread(buf, 1, len, stdin) err\n");
continue;
}
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "buf = %s\n", buf);
if (strcmp(cmd, "count") == 0) //count 获取用户文件个数
{
get_count_json_info(buf, user, token); //通过json包获取用户名, token
//验证登陆token,成功返回0,失败-1
ret = verify_token(user, token); //util_cgi.h
get_user_files_count(user, ret); //获取用户文件个数
}
//获取用户文件信息 127.0.0.1:80/myfiles&cmd=normal
//按下载量升序 127.0.0.1:80/myfiles?cmd=pvasc
//按下载量降序127.0.0.1:80/myfiles?cmd=pvdesc
else
{
int start; //文件起点
int count; //文件个数
get_fileslist_json_info(buf, user, token, &start, &count); //通过json包获取信息
LOG(MYFILES_LOG_MODULE, MYFILES_LOG_PROC, "user = %s, token = %s, start = %d, count = %d\n", user, token, start, count);
//验证登陆token,成功返回0,失败-1
ret = verify_token(user, token); //util_cgi.h
if(ret == 0)
{
get_user_filelist(cmd, user, start, count); //获取用户文件列表
}
else
{
char *out = return_status("111"); //token验证失败错误码
if(out != NULL)
{
printf(out); //给前端反馈错误码
free(out);
}
}
}
}
}
return 0;
}
共享文件列表
业务逻辑,点击QT界面的共享列表,会显示背当前用户共享的文件,且是普通排序
点击图标会显示取消分享,属性点击空白处会选项显示排行榜
共享文件列表主要涉及的是file_info和share_file_list两张表查询
main
cmd为count,代表获取该用户共享出去的文件个数,只返回给前端共享了的文件个数
if (strcmp(cmd, "count") == 0) //count 获取用户文件个数
{
get_share_files_count(); //获取共享文件个数
}
解析jason包拿到拿到count,start
如果cmd为normal,则就按照查询顺序显示共享文件列表
如果cmd为pvdesc,则将查询结果按照pv字段降序排列显示共享文件列表
如果cmd为pvasc,则将查询结果按照pv字段升序排列显示为共享文件列表
获取共享文件个数
get_share_files_count(),当cmd为count,则只需要查询共享文件个数
从user_file_count查询处用户的共享文件个数
void get_share_files_count()
{
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
long line = 0;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "msql_conn err\n");
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
sprintf(sql_cmd, "select count from user_file_count where user=\"%s\"", "xxx_share_xxx_file_xxx_list_xxx_count_xxx");
char tmp[512] = {0};
int ret2 = process_result_one(conn, sql_cmd, tmp); //指向sql语句
if(ret2 != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 操作失败\n", sql_cmd);
goto END;
}
line = atol(tmp); //字符串转长整形
END:
if(conn != NULL)
{
mysql_close(conn);
}
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "line = %ld\n", line);
printf("%ld", line); //给前端反馈的信息
}
前端分页请求包
get_fileslist_json_info
这个包是前端发送的post数据,封装的是物理分页的信息,然后再根据URL上的指令去做业务逻辑判断
解析包拿到start,count
//解析的json包
int get_fileslist_json_info(char *buf, int *p_start, int *p_count)
{
int ret = 0;
/*json数据如下
{
"start": 0
"count": 10
}
*/
//解析json包
//解析一个json字符串为cJSON对象
cJSON * root = cJSON_Parse(buf);
if(NULL == root)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cJSON_Parse err\n");
ret = -1;
goto END;
}
//文件起点
cJSON *child2 = cJSON_GetObjectItem(root, "start");
if(NULL == child2)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_start = child2->valueint;
//文件请求个数
cJSON *child3 = cJSON_GetObjectItem(root, "count");
if(NULL == child3)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_count = child3->valueint;
END:
if(root != NULL)
{
cJSON_Delete(root);//删除json对象
root = NULL;
}
return ret;
}
获得普通共享文件列表
get_share_filelist(int start, int count)
查出share_file_list所有记录,同时根据md5查file_info表部分文件信息并进行物理分页
从结果集中将记录进行一行行封装成对象;将封装好的对象加入数组;将数组加到跟对象root,将root转为字符串输出
//获取共享文件列表
//获取用户文件信息 127.0.0.1:80/sharefiles&cmd=normal
int get_share_filelist(int start, int count)
{
int ret = 0;
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
cJSON *root = NULL;
cJSON *array =NULL;
char *out = NULL;
char *out2 = NULL;
MYSQL_RES *res_set = NULL;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "msql_conn err\n");
ret = -1;
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
//sql语句
sprintf(sql_cmd, "select share_file_list.*, file_info.url, file_info.size, file_info.type from file_info, share_file_list where file_info.md5 = share_file_list.md5 limit %d, %d", start, count);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 在操作\n", sql_cmd);
if (mysql_query(conn, sql_cmd) != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 操作失败: %s\n", sql_cmd, mysql_error(conn));
ret = -1;
goto END;
}
res_set = mysql_store_result(conn);/*生成结果集*/
if (res_set == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "smysql_store_result error!\n");
ret = -1;
goto END;
}
ulong line = 0;
//mysql_num_rows接受由mysql_store_result返回的结果结构集,并返回结构集中的行数
line = mysql_num_rows(res_set);
if (line == 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "mysql_num_rows(res_set) failed\n");
ret = -1;
goto END;
}
MYSQL_ROW row;
root = cJSON_CreateObject();
array = cJSON_CreateArray();
// mysql_fetch_row从使用mysql_store_result得到的结果结构中提取一行,并把它放到一个行结构中。
// 当数据用完或发生错误时返回NULL.
while ((row = mysql_fetch_row(res_set)) != NULL)
{
//array[i]:
cJSON* item = cJSON_CreateObject();
//mysql_num_fields获取结果中列的个数
/*for(i = 0; i < mysql_num_fields(res_set); i++)
{
if(row[i] != NULL)
{
}
}*/
/*
{
"user": "yoyo",
"md5": "e8ea6031b779ac26c319ddf949ad9d8d",
"time": "2017-02-26 21:35:25",
"filename": "test.mp4",
"share_status": 1,
"pv": 0,
"url": "http://192.168.31.109:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
"size": 27473666,
"type": "mp4"
}
*/
//-- user 文件所属用户
if(row[0] != NULL)
{
cJSON_AddStringToObject(item, "user", row[0]);
}
//-- md5 文件md5
if(row[1] != NULL)
{
cJSON_AddStringToObject(item, "md5", row[1]);
}
//-- createtime 文件创建时间
if(row[2] != NULL)
{
cJSON_AddStringToObject(item, "time", row[2]);
}
//-- filename 文件名字
if(row[3] != NULL)
{
cJSON_AddStringToObject(item, "filename", row[3]);
}
//-- shared_status 共享状态, 0为没有共享, 1为共享
cJSON_AddNumberToObject(item, "share_status", 1);
//-- pv 文件下载量,默认值为0,下载一次加1
if(row[4] != NULL)
{
cJSON_AddNumberToObject(item, "pv", atol( row[4] ));
}
//-- url 文件url
if(row[5] != NULL)
{
cJSON_AddStringToObject(item, "url", row[5]);
}
//-- size 文件大小, 以字节为单位
if(row[6] != NULL)
{
cJSON_AddNumberToObject(item, "size", atol( row[6] ));
}
//-- type 文件类型: png, zip, mp4……
if(row[7] != NULL)
{
cJSON_AddStringToObject(item, "type", row[7]);
}
cJSON_AddItemToArray(array, item);
}
cJSON_AddItemToObject(root, "files", array);
out = cJSON_Print(root);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s\n", out);
END:
if(ret == 0)
{
printf("%s", out); //给前端反馈信息
}
else
{ //失败
out2 = NULL;
out2 = return_status("015");
}
if(out2 != NULL)
{
printf(out2); //给前端反馈错误码
free(out2);
}
if(res_set != NULL)
{
//完成所有对数据的操作后,调用mysql_free_result来善后处理
mysql_free_result(res_set);
}
if(conn != NULL)
{
mysql_close(conn);
}
if(root != NULL)
{
cJSON_Delete(root);
}
if(out != NULL)
{
free(out);
}
return ret;
}
共享文件排行榜
操作redis “FILE_NAME_HASH”和“FILE_PUBLIC_ZSET”两张表和MySQL“share_file_list”,完成redis和MySQL数据交互int get_ranking_filelist(int start, int count)拿到mysql中共享文件的数量,拿到redis中的共享文件的数量进行比较
不相等,更新redis数据,删除redis中所有数据( FILE_PUBLIC_ZSET,FILE_NAME_HASH) ;再将mysql中的数据导入到mysql:查出share_file_list中md5,filename和pv字段,游标提取结果集每一行(md5+filename组成fileid和pv字段作为score一起添加到zset;将组合的fileid作为fileld,filename作为value添加到hash表) 将zset按照score降序排序,其中排序有分页参数start,end;将排序后的集合从FILE_NAME_HASH取出filename,从FILE_PUBLIC_ZSET取出pv字段封装成对象;再将数据封装成对象转字符串后发送给前端 printf("%s", out),会在QT界面点击排行榜时候显示
源码
/**
* @file sharefiles_cgi.c
* @brief 共享文件列表展示CGI程序
* @author Mike
* @version 2.0
* @date 2017年3月7日21:46:57
*/
#include "fcgi_config.h"
#include "fcgi_stdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "make_log.h" //日志头文件
#include "util_cgi.h"
#include "deal_mysql.h"
#include "redis_keys.h"
#include "redis_op.h"
#include "cfg.h"
#include "cJSON.h"
#include <sys/time.h>
#define SHAREFILES_LOG_MODULE "cgi"
#define SHAREFILES_LOG_PROC "sharefiles"
//mysql 数据库配置信息 用户名, 密码, 数据库名称
static char mysql_user[128] = {0};
static char mysql_pwd[128] = {0};
static char mysql_db[128] = {0};
//redis 服务器ip、端口
static char redis_ip[30] = {0};
static char redis_port[10] = {0};
//读取配置信息
void read_cfg()
{
//读取mysql数据库配置信息
get_cfg_value(CFG_PATH, "mysql", "user", mysql_user);
get_cfg_value(CFG_PATH, "mysql", "password", mysql_pwd);
get_cfg_value(CFG_PATH, "mysql", "database", mysql_db);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "mysql:[user=%s,pwd=%s,database=%s]", mysql_user, mysql_pwd, mysql_db);
//读取redis配置信息
get_cfg_value(CFG_PATH, "redis", "ip", redis_ip);
get_cfg_value(CFG_PATH, "redis", "port", redis_port);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "redis:[ip=%s,port=%s]\n", redis_ip, redis_port);
}
//获取共享文件个数
void get_share_files_count()
{
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
long line = 0;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "msql_conn err\n");
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
sprintf(sql_cmd, "select count from user_file_count where user=\"%s\"", "xxx_share_xxx_file_xxx_list_xxx_count_xxx");
char tmp[512] = {0};
int ret2 = process_result_one(conn, sql_cmd, tmp); //指向sql语句
if(ret2 != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 操作失败\n", sql_cmd);
goto END;
}
line = atol(tmp); //字符串转长整形
END:
if(conn != NULL)
{
mysql_close(conn);
}
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "line = %ld\n", line);
printf("%ld", line); //给前端反馈的信息
}
//解析的json包
int get_fileslist_json_info(char *buf, int *p_start, int *p_count)
{
int ret = 0;
/*json数据如下
{
"start": 0
"count": 10
}
*/
//解析json包
//解析一个json字符串为cJSON对象
cJSON * root = cJSON_Parse(buf);
if(NULL == root)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cJSON_Parse err\n");
ret = -1;
goto END;
}
//文件起点
cJSON *child2 = cJSON_GetObjectItem(root, "start");
if(NULL == child2)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_start = child2->valueint;
//文件请求个数
cJSON *child3 = cJSON_GetObjectItem(root, "count");
if(NULL == child3)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cJSON_GetObjectItem err\n");
ret = -1;
goto END;
}
*p_count = child3->valueint;
END:
if(root != NULL)
{
cJSON_Delete(root);//删除json对象
root = NULL;
}
return ret;
}
//获取共享文件列表
//获取用户文件信息 127.0.0.1:80/sharefiles&cmd=normal
int get_share_filelist(int start, int count)
{
int ret = 0;
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
cJSON *root = NULL;
cJSON *array =NULL;
char *out = NULL;
char *out2 = NULL;
MYSQL_RES *res_set = NULL;
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "msql_conn err\n");
ret = -1;
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
//sql语句
sprintf(sql_cmd, "select share_file_list.*, file_info.url, file_info.size, file_info.type from file_info, share_file_list where file_info.md5 = share_file_list.md5 limit %d, %d", start, count);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 在操作\n", sql_cmd);
if (mysql_query(conn, sql_cmd) != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 操作失败: %s\n", sql_cmd, mysql_error(conn));
ret = -1;
goto END;
}
res_set = mysql_store_result(conn);/*生成结果集*/
if (res_set == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "smysql_store_result error!\n");
ret = -1;
goto END;
}
ulong line = 0;
//mysql_num_rows接受由mysql_store_result返回的结果结构集,并返回结构集中的行数
line = mysql_num_rows(res_set);
if (line == 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "mysql_num_rows(res_set) failed\n");
ret = -1;
goto END;
}
MYSQL_ROW row;
root = cJSON_CreateObject();
array = cJSON_CreateArray();
// mysql_fetch_row从使用mysql_store_result得到的结果结构中提取一行,并把它放到一个行结构中。
// 当数据用完或发生错误时返回NULL.
while ((row = mysql_fetch_row(res_set)) != NULL)
{
//array[i]:
cJSON* item = cJSON_CreateObject();
//mysql_num_fields获取结果中列的个数
/*for(i = 0; i < mysql_num_fields(res_set); i++)
{
if(row[i] != NULL)
{
}
}*/
/*
{
"user": "yoyo",
"md5": "e8ea6031b779ac26c319ddf949ad9d8d",
"time": "2017-02-26 21:35:25",
"filename": "test.mp4",
"share_status": 1,
"pv": 0,
"url": "http://192.168.31.109:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
"size": 27473666,
"type": "mp4"
}
*/
//-- user 文件所属用户
if(row[0] != NULL)
{
cJSON_AddStringToObject(item, "user", row[0]);
}
//-- md5 文件md5
if(row[1] != NULL)
{
cJSON_AddStringToObject(item, "md5", row[1]);
}
//-- createtime 文件创建时间
if(row[2] != NULL)
{
cJSON_AddStringToObject(item, "time", row[2]);
}
//-- filename 文件名字
if(row[3] != NULL)
{
cJSON_AddStringToObject(item, "filename", row[3]);
}
//-- shared_status 共享状态, 0为没有共享, 1为共享
cJSON_AddNumberToObject(item, "share_status", 1);
//-- pv 文件下载量,默认值为0,下载一次加1
if(row[4] != NULL)
{
cJSON_AddNumberToObject(item, "pv", atol( row[4] ));
}
//-- url 文件url
if(row[5] != NULL)
{
cJSON_AddStringToObject(item, "url", row[5]);
}
//-- size 文件大小, 以字节为单位
if(row[6] != NULL)
{
cJSON_AddNumberToObject(item, "size", atol( row[6] ));
}
//-- type 文件类型: png, zip, mp4……
if(row[7] != NULL)
{
cJSON_AddStringToObject(item, "type", row[7]);
}
cJSON_AddItemToArray(array, item);
}
cJSON_AddItemToObject(root, "files", array);
out = cJSON_Print(root);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s\n", out);
END:
if(ret == 0)
{
printf("%s", out); //给前端反馈信息
}
else
{ //失败
out2 = NULL;
out2 = return_status("015");
}
if(out2 != NULL)
{
printf(out2); //给前端反馈错误码
free(out2);
}
if(res_set != NULL)
{
//完成所有对数据的操作后,调用mysql_free_result来善后处理
mysql_free_result(res_set);
}
if(conn != NULL)
{
mysql_close(conn);
}
if(root != NULL)
{
cJSON_Delete(root);
}
if(out != NULL)
{
free(out);
}
return ret;
}
//获取共享文件排行版
//按下载量降序127.0.0.1:80/sharefiles?cmd=pvdesc
int get_ranking_filelist(int start, int count)
{
/*
a) mysql共享文件数量和redis共享文件数量对比,判断是否相等
b) 如果不相等,清空redis数据,从mysql中导入数据到redis (mysql和redis交互)
c) 从redis读取数据,给前端反馈相应信息
*/
int ret = 0;
char sql_cmd[SQL_MAX_LEN] = {0};
MYSQL *conn = NULL;
cJSON *root = NULL;
RVALUES value = NULL;
cJSON *array =NULL;
char *out = NULL;
char *out2 = NULL;
char tmp[512] = {0};
int ret2 = 0;
MYSQL_RES *res_set = NULL;
redisContext * redis_conn = NULL;
//连接redis数据库
redis_conn = rop_connectdb_nopwd(redis_ip, redis_port);
if (redis_conn == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "redis connected error");
ret = -1;
goto END;
}
//connect the database
conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
if (conn == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "msql_conn err\n");
ret = -1;
goto END;
}
//设置数据库编码,主要处理中文编码问题
mysql_query(conn, "set names utf8");
//===1、mysql共享文件数量
sprintf(sql_cmd, "select count from user_file_count where user=\"%s\"", "xxx_share_xxx_file_xxx_list_xxx_count_xxx");
ret2 = process_result_one(conn, sql_cmd, tmp); //指向sql语句
if(ret2 != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 操作失败\n", sql_cmd);
ret = -1;
goto END;
}
int sql_num = atoi(tmp); //字符串转长整形
//===2、redis共享文件数量
int redis_num = rop_zset_zcard(redis_conn, FILE_PUBLIC_ZSET);
if(redis_num == -1)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "rop_zset_zcard 操作失败\n");
ret = -1;
goto END;
}
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "sql_num = %d, redis_num = %d\n", sql_num, redis_num);
//===3、mysql共享文件数量和redis共享文件数量对比,判断是否相等
if(redis_num != sql_num)
{//===4、如果不相等,清空redis数据,重新从mysql中导入数据到redis (mysql和redis交互)
//a) 清空redis有序数据
rop_del_key(redis_conn, FILE_PUBLIC_ZSET);
rop_del_key(redis_conn, FILE_NAME_HASH);
//b) 从mysql中导入数据到redis
//sql语句
strcpy(sql_cmd, "select md5, filename, pv from share_file_list order by pv desc");
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 在操作\n", sql_cmd);
if (mysql_query(conn, sql_cmd) != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s 操作失败: %s\n", sql_cmd, mysql_error(conn));
ret = -1;
goto END;
}
res_set = mysql_store_result(conn);/*生成结果集*/
if (res_set == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "smysql_store_result error!\n");
ret = -1;
goto END;
}
ulong line = 0;
//mysql_num_rows接受由mysql_store_result返回的结果结构集,并返回结构集中的行数
line = mysql_num_rows(res_set);
if (line == 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "mysql_num_rows(res_set) failed\n");
ret = -1;
goto END;
}
MYSQL_ROW row;
// mysql_fetch_row从使用mysql_store_result得到的结果结构中提取一行,并把它放到一个行结构中。
// 当数据用完或发生错误时返回NULL.
while ((row = mysql_fetch_row(res_set)) != NULL)
{
//md5, filename, pv
if(row[0] == NULL || row[1] == NULL || row[2] == NULL)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "mysql_fetch_row(res_set)) failed\n");
ret = -1;
goto END;
}
char fileid[1024] = {0};
sprintf(fileid, "%s%s", row[0], row[1]); //文件标示,md5+文件名
//增加有序集合成员
rop_zset_add(redis_conn, FILE_PUBLIC_ZSET, atoi(row[2]), fileid);
//增加hash记录
rop_hash_set(redis_conn, FILE_NAME_HASH, fileid, row[1]);
}
}
//===5、从redis读取数据,给前端反馈相应信息
//char value[count][1024];
value = (RVALUES)calloc(count, VALUES_ID_SIZE); //堆区请求空间
if(value == NULL)
{
ret = -1;
goto END;
}
int n = 0;
int end = start + count - 1;//加载资源的结束位置
//降序获取有序集合的元素
ret = rop_zset_zrevrange(redis_conn, FILE_PUBLIC_ZSET, start, end, value, &n);
if(ret != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "rop_zset_zrevrange 操作失败\n");
goto END;
}
root = cJSON_CreateObject();
array = cJSON_CreateArray();
//遍历元素个数
for(int i = 0; i < n; ++i)
{
//array[i]:
cJSON* item = cJSON_CreateObject();
/*
{
"filename": "test.mp4",
"pv": 0
}
*/
//-- filename 文件名字
char filename[1024] = {0};
ret = rop_hash_get(redis_conn, FILE_NAME_HASH, value[i], filename);
if(ret != 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "rop_hash_get 操作失败\n");
ret = -1;
goto END;
}
cJSON_AddStringToObject(item, "filename", filename);
//-- pv 文件下载量
int score = rop_zset_get_score(redis_conn, FILE_PUBLIC_ZSET, value[i]);
if(score == -1)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "rop_zset_get_score 操作失败\n");
ret = -1;
goto END;
}
cJSON_AddNumberToObject(item, "pv", score);
cJSON_AddItemToArray(array, item);
}
cJSON_AddItemToObject(root, "files", array);
out = cJSON_Print(root);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "%s\n", out);
END:
if(ret == 0)
{
printf("%s", out); //给前端反馈信息
}
else
{ //失败
out2 = NULL;
out2 = return_status("015");
}
if(out2 != NULL)
{
printf(out2); //给前端反馈错误码
free(out2);
}
if(res_set != NULL)
{
//完成所有对数据的操作后,调用mysql_free_result来善后处理
mysql_free_result(res_set);
}
if(redis_conn != NULL)
{
rop_disconnect(redis_conn);
}
if(conn != NULL)
{
mysql_close(conn);
}
if(value != NULL)
{
free(value);
}
if(root != NULL)
{
cJSON_Delete(root);
}
if(out != NULL)
{
free(out);
}
return ret;
}
int main()
{
char cmd[20];
//读取数据库配置信息
read_cfg();
//阻塞等待用户连接
while (FCGI_Accept() >= 0)
{
// 获取URL地址 "?" 后面的内容
char *query = getenv("QUERY_STRING");
//解析命令
query_parse_key_value(query, "cmd", cmd, NULL);
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "cmd = %s\n", cmd);
printf("Content-type: text/html\r\n\r\n");
if (strcmp(cmd, "count") == 0) //count 获取用户文件个数
{
get_share_files_count(); //获取共享文件个数
}
else
{
char *contentLength = getenv("CONTENT_LENGTH");
int len;
if( contentLength == NULL )
{
len = 0;
}
else
{
len = atoi(contentLength); //字符串转整型
}
if (len <= 0)
{
printf("No data from standard input.<p>\n");
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "len = 0, No data from standard input\n");
}
else
{
char buf[4*1024] = {0};
int ret = 0;
ret = fread(buf, 1, len, stdin); //从标准输入(web服务器)读取内容
if(ret == 0)
{
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "fread(buf, 1, len, stdin) err\n");
continue;
}
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "buf = %s\n", buf);
//获取共享文件信息 127.0.0.1:80/sharefiles&cmd=normal
//按下载量升序 127.0.0.1:80/sharefiles?cmd=pvasc
//按下载量降序127.0.0.1:80/sharefiles?cmd=pvdesc
int start; //文件起点
int count; //文件个数
get_fileslist_json_info(buf, &start, &count); //通过json包获取信息
LOG(SHAREFILES_LOG_MODULE, SHAREFILES_LOG_PROC, "start = %d, count = %d\n", start, count);
if (strcmp(cmd, "normal") == 0)
{
get_share_filelist(start, count); //获取共享文件列表
}
else if(strcmp(cmd, "pvdesc") == 0)
{
get_ranking_filelist(start, count);//获取共享文件排行版
}
}
}
}
return 0;
}