最近刚写完一个cocos2dx,从客户端上传到php服务器的简单测试程序,代码可以复制直接运行
在阅读代码前最好可以先花点时间了解一点php 和libcurl的相关知识,并不会花费太长时间,由于我做的时候对php不是特别熟悉,所有使用libcurl拼凑表单的时候出现一个问题,花了我一阵时间去解决。下方代码只是简单的demo,代码有些粗糙,但对于大家的理解应该影响不大
我使用XAMMP中的Apache服务器,php脚本放在\xampp\htdocs\目录下,并在当前目录创建upload文件夹用来存放上传的文件
1:
ReceiveFile.php
<?php
/* 设定上传目录 */
$dest_dir='./upload';
/* 检测上传目录是否存在 */
if( !is_dir($dest_dir) || !is_writeable($dest_dir) )
{
die("上传目录 ".$dest_dir." 不存在或无法写入");
}
/* 设置允许上传文件的类型 */
$type=array("rar","zip","txt","c","JPG");
/* 获取上传文件信息 */
// $upfile=&$HTTP_POST_FILES['file'];
$upfile=$_FILES["file"];
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
/* 获取文件后缀名函数 */
function fileext($filename)
{
return substr(strrchr($filename, '.'), 1);
}
//echo "Temp file: " . fileext($upfile['name'] . "<br />";
/* 判断上传文件类型 */
if( !in_array( strtolower( fileext($upfile['name'] ) ),$type) )
{
$text=implode(",",$type);
echo "对不起,您只能上传以下类型文件: ",$text,"<br>";
}
else
{
/* 设置文件名为"日期_文件名" */
$dest=$dest_dir.'/'.date("ymdHis")."_".$upfile['name'];
/* 移动上传文件到指定文件夹 */
$state=move_uploaded_file($upfile['tmp_name'],$dest);
if ($state)
{
print("文件上传成功!<br>");
print("文件名:".$dest."<br>");
print("上传的文件大小:".( round($upfile['size'] / 1024,2) )." KB<br>");
}
else
{
/* 处理错误信息 */
switch($upfile['error'])
{
case 1 : die("上传文件大小超出 php.ini:upload_max_filesize 限制<br>");
case 2 : die("上传文件大小超出 MAX_FILE_SIZE 限制<br>");
case 3 : die("文件仅被部分上传<br>");
case 4 : die("没有文件被上传<br>");
case 5 : die("找不到临时文件夹<br>");
case 6 : die("文件写入失败<br>");
}
}
}
?>
2:
upload.html 表单:
<form method="post" enctype="multipart/form-data" action="ReceiveFile.php">
<input type="file" name="file" id="file" />
<input type="submit" name="submit" value="submit" />
</form>
可以直接运行upload.html,如http://127.0.0.1/WD/upload.html
则会出现页面,选择相应的文件上传则会提示
注:php页面会有上传大小超过1M的限制
3:
接下来就要最重要的部分了,使用libcurl库来实现upload.html表单,实现上传功能
Httpupload.h
#ifndef COMMON_LINUX_HTTP_UPLOAD_H__
#define COMMON_LINUX_HTTP_UPLOAD_H__
#include <map>
#include <string>
using std::map;
class HTTPUpload {
<span style="white-space:pre"> </span>public:
static bool SendRequest(const string &url,
const map<string, string> ¶meters,
const string &upload_file,
const string &file_part_name,
const string &proxy,
const string &proxy_user_pwd,
const string &ca_certificate_file,
string *response_body,
long *response_code,
string *error_description);
static bool MySendRequest( const string &upload_file);
private:
// Checks that the given list of parameters has only printable
// ASCII characters in the parameter name, and does not contain
// any quote (") characters. Returns true if so.
static bool CheckParameters(const map<string, string> ¶meters);
// No instances of this class should be created.
// Disallow all constructors, destructors, and operator=.
HTTPUpload();
explicit HTTPUpload(const HTTPUpload &);
void operator=(const HTTPUpload &);
~HTTPUpload();
};
#endif // COMMON_LINUX_HTTP_UPLOAD_H__
Httpupload.cpp
#include <assert.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <stdio.h>
#include <vector>
#include "stdafx.h"
#include "HttpUpload.h"
using namespace cocos2d;
using namespace std;
// Callback to get the response data from server.
static size_t WriteCallback(void *ptr, size_t size,
size_t nmemb, void *userp) {
if (!userp)
return 0;
string *response = reinterpret_cast<string *>(userp);
size_t real_size = size * nmemb;
response->append(reinterpret_cast<char *>(ptr), real_size);
std::cout << response << endl;
return real_size;
}
static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
// static
bool HTTPUpload::SendRequest(const string &url,
const map<string, string> ¶meters,
const string &upload_file, //"E:\\install.res.1041.zip"
const string &file_part_name, //"upload_file_minidump",
const string &proxy,
const string &proxy_user_pwd,
const string &ca_certificate_file,
string *response_body,
long *response_code,
string *error_description) {
if (response_code != NULL)
*response_code = 0;
if (!CheckParameters(parameters))
return false;
curl_global_init(CURL_GLOBAL_ALL);
CURL *curl = curl_easy_init();
if (error_description != NULL)
*error_description = "No Error";
if (!curl) {
return false;
}
CURLcode err_code = CURLE_OK;
(curl_easy_setopt)(curl, CURLOPT_URL, url.c_str());
(curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent);
// Set proxy information if necessary.
if (!proxy.empty())
(curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str());
if (!proxy_user_pwd.empty())
(curl_easy_setopt)(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str());
if (!ca_certificate_file.empty())
(curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
// Add form file.
(curl_formadd)(&formpost, &lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, upload_file.c_str(),
CURLFORM_END);
(curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);
// Disable 100-continue header.
struct curl_slist *headerlist = NULL;
char buf[] = "Expect:";
// struct curl_slist* (curl_slist_append)(struct curl_slist *, const char *);
//*(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append");
headerlist = (curl_slist_append)(headerlist, buf);
(curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist);
if (response_body != NULL) {
(curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
(curl_easy_setopt)(curl, CURLOPT_WRITEDATA,
reinterpret_cast<void *>(response_body));
}
// Fail if 400+ is returned from the web server.
(curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1);
err_code = (curl_easy_perform)(curl);
if (response_code != NULL) {
(curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code);
}
if (error_description != NULL)
*error_description = (curl_easy_strerror)(err_code);
(curl_easy_cleanup)(curl);
if (formpost != NULL) {
(curl_formfree)(formpost);
}
if (headerlist != NULL) {
(curl_slist_free_all)(headerlist);
}
// dlclose(curl_lib);
return err_code == CURLE_OK;
}
// static
bool HTTPUpload::CheckParameters(const map<string, string> ¶meters) {
for (map<string, string>::const_iterator pos = parameters.begin();
pos != parameters.end(); ++pos) {
const string &str = pos->first;
if (str.size() == 0)
return false; // disallow empty parameter names
for (unsigned int i = 0; i < str.size(); ++i) {
int c = str[i];
if (c < 32 || c == '"' || c > 127) {
return false;
}
}
}
return true;
}
//重写把数据读入上传数据流函数
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
FILE *fptr = (FILE*)userp;
size_t m_size = fread(buffer, size, nmemb, fptr);
return m_size;
}
在任意地方调用下方代码,则实现将 E:\\3.0.25.63.zip 文件上传到php服务器的upload目录下
CCLOG("################################################################################################ Begin send dump file");
string strPath = "E:\\3.0.25.63.zip";
std::map<string, string> parameters;
string response, error;
const char * url = "http://127.0.0.1/WD/ReceiveFile.php";
bool success = HTTPUpload::SendRequest(url,
parameters,
strPath.c_str(),
//"upload_file_minidump",
"",
"","","",
&response,
NULL,
&error);
以上代码是个简单的demo,代码相当粗糙,但应该对大家的理解影响不打,代码还有很大的优化空间,大家可以进行优化和扩展空间,期望大家一起完善!