【问题标题】:C++ [Libcurl] Downloading a file from a php server and save it on memoryC++ [Libcurl] 从 php 服务器下载文件并将其保存在内存中
【发布时间】:2020-04-09 19:04:01
【问题描述】:

您好,我正在尝试使用从我的 php 文件中检索的 libcurl 下载文件,该文件在检索下载文件之前检查用户是否已登录 c++ 客户端,问题是客户端永远无法到达要保存的下载文件它进入内存而不是写入磁盘我能做什么?我正在使用此示例进行测试。我还需要补充一点,我已经测试过无需登录即可直接下载文件,一切都很好,但登录大小永远为 0,我永远无法访问该文件。提前致谢。

    struct MemoryStruct {
  char *memory;
  size_t size;
};

static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
  size_t realsize = size * nmemb;
  struct MemoryStruct *mem = (struct MemoryStruct *)userp;

  char *ptr = realloc(mem->memory, mem->size + realsize + 1);
  if(ptr == NULL) {
    /* out of memory! */ 
    printf("not enough memory (realloc returned NULL)\n");
    return 0;
  }

  mem->memory = ptr;
  memcpy(&(mem->memory[mem->size]), contents, realsize);
  mem->size += realsize;
  mem->memory[mem->size] = 0;

  return realsize;
}

int main(void)
{
  CURL *curl_handle;
  CURLcode res;

  struct MemoryStruct chunk;

  chunk.memory = malloc(1);  /* will be grown as needed by the realloc above */ 
  chunk.size = 0;    /* no data at this point */ 

  curl_global_init(CURL_GLOBAL_ALL);

  /* init the curl session */ 
  curl_handle = curl_easy_init();

  /* specify URL to get */ 
  curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.example.com/");

  /* send all data to this function  */ 
  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

  /* we pass our 'chunk' struct to the callback function */ 
  curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

  /* some servers don't like requests that are made without a user-agent
     field, so we provide one */ 
  curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

  /* get it! */ 
  res = curl_easy_perform(curl_handle);

  /* check for errors */ 
  if(res != CURLE_OK) {
    fprintf(stderr, "curl_easy_perform() failed: %s\n",
            curl_easy_strerror(res));
  }
  else {
    /*
     * Now, our chunk.memory points to a memory block that is chunk.size
     * bytes big and contains the remote file.
     *
     * Do something nice with it!
     */ 

    printf("%lu bytes retrieved\n", (unsigned long)chunk.size);
  }

  /* cleanup curl stuff */ 
  curl_easy_cleanup(curl_handle);

  free(chunk.memory);

  /* we're done with libcurl, so clean it up */ 
  curl_global_cleanup();

  return 0;
}

php代码是这样的

$path = '../file.dll';

                    if (file_exists($path))
                    {
                        $mm_type="application/octet-stream";
                        header("Pragma: public");
                        header("Expires: 0");
                        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
                        header("Cache-Control: public");
                        header("Content-Description: File Transfer");
                        header("Content-Type: " . $mm_type);
                        header("Content-Length: " .(string)(filesize($path)) );
                        header('Content-Disposition: attachment; filename="'.basename($path).'"');
                        header("Content-Transfer-Encoding: binary\n");
                        readfile($path);
                        }

【问题讨论】:

  • 无关:为什么要摆弄手动内存管理?只需使用 std::string 和 append(reinterpret_cast<char*>(contents), realsize);
  • @TedLyngmo 谢谢你的回答,我可以在没有 php 登录的情况下下载文件,一切都很好,但问题是当客户端对 php 文件 (download.php) 发出获取请求时什么都没有检索到我不知道为什么...我还测试了一种将文件写入磁盘的方法,它与download.php一起使用(他们在登录后下载了正确的文件)但是使用内存方法它不...
  • @TedLyngmo 我还需要处理内存管理,因为我在将其映射到我的父进程之前将其写入内存。

标签: php c++ libcurl


【解决方案1】:

从php sn-p 很难说,但我会添加选项来跟踪重定向并打开详细模式,以便能够更详细地跟踪 libcurl 正在做的事情。我还将删除所有手动内存管理。您所做的一切都可以用一个简单的std::string 代替。

此示例适用于您发送的php,但我无法测试您提到的登录内容:

#include <curl/curl.h>

#include <iostream>
#include <sstream>
#include <string>

static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb,
                                  void* userp) {
    size_t realsize = size * nmemb;
    auto& mem = *static_cast<std::string*>(userp);
    mem.append(static_cast<char*>(contents), realsize);
    return realsize;
}

int main(void) {
    CURL* curl_handle;
    CURLcode res;

    std::string chunk;

    curl_global_init(CURL_GLOBAL_ALL);

    curl_handle = curl_easy_init();
    curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.example.com/");
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &chunk);
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

    // added options that may be required
    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);  // redirects
    curl_easy_setopt(curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1L); // corp. proxies etc.
    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); // we want it all
    // curl_easy_setopt(curl_handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);

    res = curl_easy_perform(curl_handle);

    if(res != CURLE_OK) {
        std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << '\n';
    } else {
        std::cout << chunk.size() << " bytes retrieved\n";
    }

    curl_easy_cleanup(curl_handle);
    curl_global_cleanup();
}

【讨论】:

  • 谢谢!让它与这个一起工作 - > curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); // 重定向 curl_easy_setopt(curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1L); // 公司代理等 curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); // 我们都想要
猜你喜欢
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-05
相关资源
最近更新 更多