我正在编写一个php应用程序,通过curl数据提交以注册iContact电子邮件列表。但是我一直收到无效的电子邮件地址错误。我想这可能是因为我正在逃避@符号,所以它看起来像%40而不是@。另外,根据curl_setopt的php文档和CURLOPT_POSTFIELDS:
要在HTTP中发布的完整数据 “POST”操作。要发布文件, 用@前缀文件名并使用 完整路径。
那么,有没有将@符号作为post数据通过php中的curl传递而不先通过urlencode运行?
答案 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 解决方案,可以同时支持包含@
和文件的字符串。
CURLFile
代替@
。CURLOPT_SAFE_UPLOAD
。CURLFile
代替@
。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);