Я пишу php-приложение, которое отправляет через curl-данные, чтобы подписаться на список электронной почты iContact. Однако я продолжаю получать неверную ошибку адреса электронной почты. Я думаю, это может быть связано с тем, что я избегаю символа @, поэтому он выглядит как% 40 вместо @. Кроме того, согласно документации php для curl_setopt с CURLOPT_POSTFIELDS:
Полные данные для публикации в HTTP Операция "POST". Чтобы опубликовать файл, добавьте имя файла с помощью @и используйте полный путь.
Итак, есть ли все равно, чтобы передать символ @в качестве пост-данных через curl в php, не запуская сначала через urlencode?
Ответ 1
Используйте http_build_query()
в своем массиве данных перед тем, как передать его в curl_setopt()
, что приведет к его отправке формы как application/x-www-form-encoded
вместо multipart/form-data
(и, следовательно, @не интерпретируется).
И почему вы действительно волнуете @в адресе электронной почты? Это имеет значение только в том случае, если @является первым символом, а не где-то посередине.
Ответ 2
После поиска PHP curl manual, я обнаружил, что нет информации, чтобы избежать первого "@, если поле post является строкой вместо файла, если сообщение с кодировкой multipart/form-data.
Как я работал над этой проблемой, префикс пустой в начале текста. Хотя наш бэкэнд-API будет удалять пробелы, чтобы он мог удалить пустой и восстановить исходный текст. Я не знаю, что погода Twitter API будет обрезать пробелы при вводе пользователя.
Если это так, это обходное решение также работает для вас.
Если кто-то нашел способ избежать первого "@" при использовании PHP curl с кодировкой multipart/form-data, сообщите нам об этом.
Ответ 3
Я столкнулся с одной и той же проблемой, хотя и с завитом, а не с завихрением PHP.
При использовании параметра поля curl '-F
' главный символ @не будет отправлен в POST, но вместо этого будет инструктировать curl для отправки имени файла, которое сразу же удастся заменить символ как часть POST.
К счастью, curl предлагает еще один вариант "--form-string
", который ведет себя так же, как "-F
", за исключением того, что параметр "form-string" не анализируется.
В качестве примера, если вы хотите использовать curl для поля POST1 со значением "@value" и file1 с файлом "testfile.txt", вы можете сделать это следующим образом:
curl "http://www.url.com" --form-string "field1=@value" -F "file1=@testfile.txt"
Ответ 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
),
));
}
?>
Ответ 5
@PatricDaryll ответ правильный, но мне нужно было сделать несколько исследований, чтобы понять, где использовать эту http_build_query.
Чтобы уточнить и обобщить, вместо выполнения:
curl_setopt($ch, CURLOPT_POSTFIELDS, $array);
Вы будете использовать:
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($array));
Простой, но запутанный... завиток достаточно умен, чтобы понять, дали ли вы ему строку или массив.
Ответ 6
Чтобы избежать знака @в данных, отличных от файла, вам необходимо сделать следующее.
Подготовьте текстовую строку символом 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);