使用PHP转义CURL @符号

时间:2009-03-15 18:30:35

标签: php curl escaping

我正在编写一个php应用程序,通过curl数据提交以注册iContact电子邮件列表。但是我一直收到无效的电子邮件地址错误。我想这可能是因为我正在逃避@符号,所以它看起来像%40而不是@。另外,根据curl_setopt的php文档和CURLOPT_POSTFIELDS:

  

要在HTTP中发布的完整数据   “POST”操作。要发布文件,   用@前缀文件名并使用   完整路径。

那么,有没有将@符号作为post数据通过php中的curl传递而不先通过urlencode运行?

6 个答案:

答案 0 :(得分:13)

首先在您的数据阵列上使用http_build_query(),然后再将其传递给curl_setopt(),这会导致它将表单作为application/x-www-form-encoded而不是multipart/form-data发送(因此@未解释)。

另外,为什么你真的关心电子邮件地址中的@?只有@是第一个字符,而不是中间的某个字符才重要。

答案 1 :(得分:5)

在搜索PHP curl手册后,我发现如果post字段是字符串而不是文件,如果使用multipart / form-data编码发布,则没有信息可以转义第一个'@'。

我解决这个问题的方法是在文本开头添加一个空白。虽然我们的后端API将剥离空白,因此它可以删除空白并恢复原始文本。我不知道天气Twitter API会削减用户输入的空白​​。

如果是这样,此解决方法也适用于您。

如果有任何人在使用PHP curl和multipart / form-data编码时找到了逃避第一个'@'的方法,请告诉我们。

答案 2 :(得分:4)

我遇到了同样的问题,虽然卷曲本身而不是PHP卷曲。

当使用curl的字段选项“-F”时,POST中不会发送前导@符号,而是指示curl发送文件名,该文件名会立即成为POST的一部分。

幸运的是,curl提供了另一个选项'--form-string',其行为与'-F'相同,只是不解析'form-string'选项。

例如,如果你想使用curl来POST field1的值为“@value”而file1的文件是“testfile.txt”你可以这样做:

curl "http://www.url.com" --form-string "field1=@value" -F "file1=@testfile.txt"

答案 3 :(得分:4)

这是 true 解决方案,可以同时支持包含@文件字符串。

PHP 5.6或更高版本的解决方案:

  • 使用CURLFile代替@

PHP 5.5或更高版本的解决方案:

  • 启用CURLOPT_SAFE_UPLOAD
  • 使用CURLFile代替@

PHP 5.3或更高版本的解决方案:

  • 自己构建多部分内容体。
  • 自己更改Content-Type标题。

以下代码段将为您提供帮助:D

<?php

/**
 * For safe multipart POST request for PHP5.3 ~ PHP 5.4.
 * 
 * @param resource $ch cURL resource
 * @param array $assoc "name => value"
 * @param array $files "name => path"
 * @return bool
 */
function curl_custom_postfields($ch, array $assoc = array(), array $files = array()) {

    // invalid characters for "name" and "filename"
    static $disallow = array("\0", "\"", "\r", "\n");

    // initialize body
    $body = array();

    // build normal parameters
    foreach ($assoc as $k => $v) {
        $k = str_replace($disallow, "_", $k);
        $body[] = implode("\r\n", array(
            "Content-Disposition: form-data; name=\"{$k}\"",
            "",
            filter_var($v), 
        ));
    }

    // build file parameters
    foreach ($files as $k => $v) {
        switch (true) {
            case false === $v = realpath(filter_var($v)):
            case !is_file($v):
            case !is_readable($v):
                continue; // or return false, throw new InvalidArgumentException
        }
        $data = file_get_contents($v);
        $v = call_user_func("end", explode(DIRECTORY_SEPARATOR, $v));
        list($k, $v) = str_replace($disallow, "_", array($k, $v));
        $body[] = implode("\r\n", array(
            "Content-Disposition: form-data; name=\"{$k}\"; filename=\"{$v}\"",
            "Content-Type: application/octet-stream",
            "",
            $data,
        ));
    }

    // generate safe boundary 
    do {
        $boundary = "---------------------" . md5(mt_rand() . microtime());
    } while (preg_grep("/{$boundary}/", $body));

    // add boundary for each parameters
    array_walk($body, function (&$part) use ($boundary) {
        $part = "--{$boundary}\r\n{$part}";
    });

    // add final boundary
    $body[] = "--{$boundary}--";
    $body[] = "";

    // set options
    return curl_setopt_array($ch, array(
        CURLOPT_POST       => true,
        CURLOPT_POSTFIELDS => implode("\r\n", $body),
        CURLOPT_HTTPHEADER => array(
            "Expect: 100-continue",
            "Content-Type: multipart/form-data; boundary={$boundary}", // change Content-Type
        ),
    ));

}

?>

答案 4 :(得分:1)

@ PatricDaryll的回答是正确的,但我需要做一些研究来了解在哪里使用这个http_build_query函数。

澄清和总结,而不是:

     curl_setopt($ch, CURLOPT_POSTFIELDS, $array);

您将使用:

     curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($array));

简单但令人困惑......如果你给了他一个字符串或一个数组,curl就足够聪明了。

答案 5 :(得分:0)

为了逃避非文件数据中的@符号,您需要执行以下操作。 在文本字符串前面加上NULL字符

$postfields = array(
    'upload_file' => '@file_to_upload.png',
    'upload_text' => sprintf("\0%s", '@text_to_upload')
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://example.com/upload-test');
curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
curl_exec($curl);
curl_close($curl);