上传文件到COS桶
本文最后更新于 2023-07-07,文章内容可能已经过时。
官方文档:https://cloud.tencent.com/document/product/436/7749
// 先声明所需的方法
void get_cos_text(char *upload_host, char *object_name, char *upload_secret_id, char *upload_secret_key, char *upload_authorization);
int upload_text(char *filepath, char *upload_host, char *object_name, char *upload_authorization);
char* iso8601(char expire_time[32]);
void quote(char *source, char *target);
void sha1Hex(char *str, char *newString);
/**
* 上传文件到cos桶中
* 先获取文件名和拼接存储路径,再获取时间拼接成申请单,之后根据cos桶名和地区拼接cos地址,获取上传许可,上传
* filepath 上传文件的绝对路径
* log_secret_id cos平台的secret_id
* log_secret_key cos平台的secret_key
* log_bucket_name_appid cos平台的bucket_name_appid
* log_upload_region cos平台的upload_region
*/
int upload_log(char *filepath, char *SECRET_ID, char *SECRET_KEY, char * bucket_name_appid,char *region)
{
logger(6, LOG_SERVICE, "*********************开始上传文件,filepath=%s",filepath);
if (access(filepath, 0) != 0) {
logger(3, LOG_SERVICE, "文件不存在,filepath=%s", filepath);
return -1;
}
// 文件名称,filename获取认证时使用,objectname为上传时作为存储桶里的绝对路径
char *filename = strrchr(filepath, '/') +1;
logger(6, LOG_SERVICE, "filename=%s\n", filename);
char device_id[32] = {0};
get_device_id(device_id);
logger(6, LOG_SERVICE, "device_id=%s\n", device_id);
char objectname[100] = {0};
sprintf(objectname, "/%s/%s", device_id,filename );
logger(6, LOG_SERVICE, "objectname=%s\n", objectname);
// 文件过期时间
char expire_time[32] = {0};
iso8601(expire_time);
char apply_payload[156] = {0};
sprintf(apply_payload, "{\"MediaType\": \"TEXT\", \"MediaName\": \"%s\", \"ExpireTime\": \"%s\"}", filename, expire_time);
logger(6, LOG_SERVICE, "apply_payload=%s\n", apply_payload);
int ret = -1;
// 2. 拼接上传的cos地址
char upload_host[100] = {0};
sprintf(upload_host, "%s.cos.%s.myqcloud.com", bucket_name_appid, region);
logger(6, LOG_SERVICE, "upload_host=%s\n", upload_host);
char upload_authorization[512] = {0};
get_cos_text(upload_host, objectname, SECRET_ID, SECRET_KEY, upload_authorization);
logger(6, LOG_SERVICE, "upload_suthorization=%s", upload_authorization);
ret = upload_text(filepath, upload_host, objectname, upload_authorization);
logger(6, LOG_SERVICE, "ret = %d", ret);
if (ret == 0)
{
logger(6, LOG_SERVICE, "上传文件%s成功!",objectname);
} else {
logger(6, LOG_SERVICE, "上传文件%s失败!",objectname);
}
return ret;
}
void get_cos_text(char *upload_host, char *object_name, char *upload_secret_id, char *upload_secret_key, char *upload_authorization)
{
// 1. 生成keytime(表示签名有效时长)
long start_timestamp = time(NULL);
long end_timestamp = start_timestamp + 6000;
char key_time[32] = {0};
sprintf(key_time, "%ld;%ld", start_timestamp, end_timestamp);
logger(6, LOG_SERVICE, "key_time%s",key_time);
// 2. 生成SignKey(使用HMAC函数生成消息摘要,函数需要指定一个散列函数,一个密钥,一个消息,一个接收的变量,之后将其通过HexEncode转换为十六进制)
unsigned char sSHA[20] = {0};
unsigned int nSHALen = 20;
HMAC(EVP_sha1(), upload_secret_key, strlen(upload_secret_key), (const unsigned char*)key_time, strlen(key_time), sSHA, &nSHALen);
char sign_key[40] = {0};
HexEncode(sSHA, sign_key, 20);
logger(6, LOG_SERVICE, "sign_key%s",sign_key);
// 3. 生成 UrlParamList 和 HttpParameters
// char *urlParamList="";
// char *httpParameters="";
// 4. 生成 HeaderList 和 HttpHeaders(header_list是传入的参数名称,HttpHeaders是参数名称和值,里面的符号需要转义)
char *header_list = "content-type;date;host";
char http_headers[1300] = {0};
char *content_type = "content-type=text/plain";
char encoded_content_type[30] = {0};
struct tm *sttime;
quote(content_type, encoded_content_type);
sttime = localtime(&start_timestamp);
char encoded_date[50] = {0};
strftime(upload_date, sizeof(upload_date), "%a, %d %b %Y %H:%M:%S GMT", sttime);
quote(upload_date, encoded_date);
sprintf(http_headers, "%s&date=%s&host=%s", encoded_content_type, encoded_date, upload_host);
logger(6, LOG_SERVICE, "eaderList 和 HttpHeaders");
// 5. 生成 HttpString
char http_string[1500] = {0};
sprintf(http_string, "put\n%s\n%s\n%s\n", object_name, "", http_headers);
char hashed_http_string[64] = {0};
sha1Hex(http_string, hashed_http_string);
logger(6, LOG_SERVICE, "HttpString");
// 6. 生成 StringToSign,使用 SHA1 对 HttpString 计算的消息摘要,16进制小写形式,用到第五步的HttpString
char string_to_sign[100] = {0};
sprintf(string_to_sign, "sha1\n%s\n%s\n", key_time, hashed_http_string);
logger(6, LOG_SERVICE, "StringToSign");
// 7. 生成 Signature,用到第二步的signkey,第六步的StringToSign
unsigned char skShaSign[20] = {0};
HMAC(EVP_sha1(), sign_key, strlen(sign_key), (const unsigned char*)string_to_sign, strlen(string_to_sign), skShaSign, &nSHALen);
char signature[40] = {0};
HexEncode(skShaSign, signature, 20);
logger(6, LOG_SERVICE, "Signature");
// 8.生成签名,拼接好的签名赋值给upload_authorization
sprintf(upload_authorization, "q-sign-algorithm=sha1&q-ak=%s&q-sign-time=%s&q-key-time=%s&q-header-list=%s&q-url-param-list=%s&q-signature=%s", upload_secret_id, key_time, key_time, header_list, "", signature);
logger(6, LOG_SERVICE, "upload_authorization");
}
int upload_text(char *filepath, char *upload_host, char *object_name, char *upload_authorization)
{
int ret = -1;
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl)
{
// 拼接发送目标url
char upload_url[256] = {0};
sprintf(upload_url, "https://%s%s", upload_host, object_name);
logger(6, LOG_SERVICE, "upload_url=%s", upload_url);
// 拼接头部header
struct curl_slist *upload_headers = NULL;
char upload_header_item[1500] = {0};
sprintf(upload_header_item, "Host: %s", upload_host);
upload_headers = curl_slist_append(upload_headers, upload_header_item);
upload_headers = curl_slist_append(upload_headers, "Content-Type: text/plain");
sprintf(upload_header_item, "Authorization: %s", upload_authorization);
upload_headers = curl_slist_append(upload_headers, upload_header_item);
sprintf(upload_header_item, "Date: %s", upload_date);
upload_headers = curl_slist_append(upload_headers, upload_header_item);
// 读取文件
FILE *hd_src;
hd_src = fopen(filepath, "rb");
// 拼接上传请求
curl_easy_setopt(curl, CURLOPT_URL, upload_url);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); // 关闭证书认证
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_PUT, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, upload_headers);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, upload_read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, upload_write_callback);
// 发起上传请求
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
logger(3, LOG_SERVICE, "上传文件执行curl失败!1");
} else {
long respCode = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respCode);
logger(6, LOG_SERVICE, "上传文件执行curl成功,responseCode=%ld", respCode);
logger(6, LOG_SERVICE, "uploadResponse=%s\n", upload_response);
if (respCode == 200) {
ret = 0;
}
}
fclose(hd_src);
// clean
curl_easy_cleanup(curl);
curl_slist_free_all(upload_headers);
} else {
logger(3, LOG_SERVICE, "上传curl初始化失败!2");
}
return ret;
}
char* iso8601(char expire_time[32])
{
time_t t_time, after;
struct tm *t_tm;
t_time = time(NULL);
after = t_time + 3600*24*30*2;
t_tm = localtime(&after);
if (t_tm == NULL)
return NULL;
if(strftime(expire_time, 32, "%FT%T%z", t_tm) == 0)
return NULL;
expire_time[25] = expire_time[24];
expire_time[24] = expire_time[23];
expire_time[22] = ':';
expire_time[26] = '\0';
return expire_time;
}
void HexEncode(const unsigned char* input, char* output, int len)
{
static const char* const lut = "0123456789abcdef";
char addOutStr[128] = {0};
char tempStr[2] = {0};
size_t i;
for (i = 0; i < len; ++i)
{
const unsigned char c = input[i];
tempStr[0] = lut[c >> 4];
strcat(addOutStr, tempStr);
tempStr[0] = lut[c & 15];
strcat(addOutStr, tempStr);
}
strncpy(output, addOutStr, 128);
}
void quote(char *source, char *target)
{
// Tue, 10 Jan 2023 06:44:07 GMT
// Tue%2C%2010%20Jan%202023%2006%3A44%3A07%20GMT
int i;
int j=0;
for(i = 0; source[i] != '\0'; i++)
{
if(source[i] != ' ' && source[i] != ',' && source[i] != ':' && source[i] != '/')
{
target[j++] = source[i];
}
else if (source[i] == ' ')
{
target[j++] = '%';
target[j++] = '2';
target[j++] = '0';
}
else if(source[i] == ',')
{
target[j++] = '%';
target[j++] = '2';
target[j++] = 'C';
}
else if(source[i] == ':')
{
target[j++] = '%';
target[j++] = '3';
target[j++] = 'A';
}
else if(source[i] == '/')
{
target[j++] = '%';
target[j++] = '2';
target[j++] = 'F';
}
}
target[j] = '\0';
}
void sha1Hex(char *str, char *newString)
{
char buf[3];
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX sha1;
SHA1_Init(&sha1);
SHA1_Update(&sha1, str, strlen(str));
SHA1_Final(hash, &sha1);
int i;
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
{
snprintf(buf, sizeof(buf), "%02x", hash[i]);
strcat(newString, buf);
}
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 周日
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果