PHP
cocos2d-x

Cocos2d-xでサーバーにファイルアップロード

はじめに

ゲームにおいてファイルをアップロードする事はそんなに無いけど
端末変更時のセーブデータ移行などをしたい場合
ゲーム内で生成したデータをサーバーにアップロードしたい場合に役立つ

準備すること

事前知識(Part1~Part2)
アップロードサーバー
Cocos2d-xでのファイルアップロード機構
PHPでのファイル受信処理

Upload.cpp
void Upload::upData(){
    //アップロードしたいfileNameとfliePath
    std::string fileName = "sample.png";
    std::string filePath = "ファイルの置いてあるパス" + StringUtils::format("%s", fileName.c_str());

    //HTTPマルチパートフォームデータ送信の為の区切り、改行など
    std::string boundary = "---------------------------14737809831466499882746641449";
    std::string lineEnd = "\r\n";
    std::string hyphens = "--";

    //ファイルパスからバイナリを取得し文字列として代入する
    Data fileData = FileUtils::getInstance()->getDataFromFile(filePath.c_str());
    unsigned char* bytes = fileData.getBytes();
    std::string data;
    for (unsigned int i = 0; i < fileData.getSize(); i++){
        data += bytes[i];
    }


    //ファイルアップロード時、ファイルと一緒に認証データを送信したい時
    std::map<std::string, std::string> postData = std::map<std::string, std::string>();
    postData["data"] = "complete";
    postData["player"] = StringUtils::format("%i", 1);

    //送信データ作成
    std::string body;
    body += setDataStr(postData);
    body += lineEnd + "Content-Disposition: form-data; name=\"mobileFile\"; filename=\"" + fileName + "\"";
    body += lineEnd + "Content-Type: application/octet-stream";
    body += lineEnd + lineEnd + data;
    body += lineEnd + hyphens + boundary + hyphens + lineEnd;


    auto request = new cocos2d::network::HttpRequest();
    request->setUrl("送信URL");
    request->setRequestType(cocos2d::network::HttpRequest::Type::POST);
    request->setResponseCallback([=](cocos2d::network::HttpClient* client, cocos2d::network::HttpResponse* response){
        if (response->isSucceed()) {
            std::vector<char> *buffer = response->getResponseData();

            //printf("Http Test, dump data: ");
            //for (unsigned int i = 0; i < buffer->size(); i++){ printf("%c", (*buffer)[i]); }
            //printf("\n");
            //if (buffer->size() == 4) return;
        }else {

        }
    });

    std::vector<std::string> contentType;
    contentType.push_back("Content-Type: multipart/form-data; boundary=" + boundary);
    request->setHeaders(contentType);
    request->setRequestData(body.data(), body.size());
    request->setTag("UPLOAD FILE");

    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
    //log("%s", body.c_str());
}

std::string Upload::setDataStr(std::map<std::string, std::string>& postMap){
    if (postMap.size() == 0) {
        return "";
    }

    std::string boundary = "---------------------------14737809831466499882746641449";
    std::string lineEnd = "\r\n";
    std::string hyphens = "--";

    std::string postString = "";
    postString += lineEnd + hyphens + boundary;
    for (auto iter = postMap.begin(); iter != postMap.end(); ++iter) {
        postString += lineEnd + "Content-Disposition: form-data; name=\"" + iter->first + "\"";
        postString += lineEnd + lineEnd + iter->second;
        if ((++iter)-- != postMap.end()) {
            postString += lineEnd + hyphens + boundary;
        }
    }

    postString += lineEnd + hyphens + boundary;

    return postString;
}

知っていると便利

いまさら聞けないHTTPマルチパートフォームデータ送信
このサイトではHTTPマルチパートフォームデータ送信の仕方が書いてある
これを読むと上記プログラムで何をしているかわかる

sample.php
<?php
//認証する場合
if($_POST["data"] == "complete") {
    $inputData = $_POST;
}else{ exit; }

if ($inputData == NULL) { exit; }

$playerNo = $inputData["player"];

//アップロードファイルを作る時のname
$base = 'mobileFile';
$file = basename($_FILES[$base]['name']);

//アップロードするパスを入力、この時フォルダーが無いと失敗
$uploaddir = 'アップロードフォルダーパス';
existCreateDirectry($uploaddir);

$uploadfile = $uploaddir . $file;

if (move_uploaded_file($_FILES[$base]['tmp_name'], $uploadfile)) {
    //echo "uploaded:".$file;
}else {
    //echo "error";
}

function existCreateDirectry($uploaddir){
    if(!file_exists($uploaddir)){
        if(mkdir($uploaddir, 0777)){
            chmod($uploaddir, 0777);
            //echo "作成に成功しました";
        }else{
            //echo "作成に失敗しました";
        }
    }else{
        //echo "作成しようとしたディレクトリは既に存在します";
    }
}

次回

plistの使い方