Смешивание нескольких значений для одного и того же ключа и загрузки файлов с использованием cURL и PHP - PullRequest
10 голосов
/ 31 декабря 2008

Я столкнулся с ограничением в привязках cURL для PHP. Похоже, что нет простого способа отправить одинаковые значения для одного и того же ключа для постполей. Большинство обходных путей, с которыми мне приходилось сталкиваться, заключались в создании полей записей в кодировке URL вручную (tag = foo & tag = bar & tag = baz) вместо использования версии CURLOPT_POSTFIELDS с ассоциативным массивом.

Кажется, что довольно часто нужно поддерживать, поэтому я чувствую, что, должно быть, что-то упустил. Действительно ли это единственный способ обработки нескольких значений для одного и того же ключа?

Хотя этот обходной путь может считаться работоспособным (если не очень раздражающим), моя главная проблема заключается в том, что мне нужно иметь возможность задавать несколько значений для одного и того же ключа, а также поддерживать загрузку файлов. Насколько я могу судить, для загрузки файла более или менее необходимо использовать версию связанного массива CURLOPT_POSTFIELDS. Поэтому я чувствую, что застрял.

Я опубликовал об этой проблеме более подробно в списке рассылки cURL PHP в надежде, что у кого-то есть какие-то идеи по этому поводу.

Предложения и советы о том, где я могу получить дополнительную информацию по этому вопросу, очень приветствуются!

Ответы [ 7 ]

11 голосов
/ 01 января 2009

Я закончил писать свою собственную функцию для создания пользовательской строки CURLOPT_POSTFIELDS с multipart / form-data. Что за боль.

function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
    // $postfields is an assoc array.
    // Creates a boundary.
    // Reads each postfields, detects which are @files, and which values are arrays
    // and dumps them into a new array (not an assoc array) so each key can exist
    // multiple times.
    // Sets content-length, content-type and sets CURLOPT_POSTFIELDS with the
    // generated body.
}

Я смог использовать этот метод следующим образом:

curl_setopt_custom_postfields($ch, array(
    'file' => '@/path/to/file',
    'tag' => array('a', 'b', 'c'),
));

Я не уверен в стеках CURLOPT_HTTPHEADER, поэтому, так как этот метод вызывает его, я убедился, что функция позволит пользователю при необходимости указать дополнительные заголовки.

У меня есть полный код в этом сообщении в блоге .

3 голосов
/ 31 декабря 2008

Если вы используете tag[] вместо tag для имени, PHP сгенерирует для вас массив , другими словами, вместо

tag=foo&tag=bar&tag=baz

Вам нужно

tag[]=foo&tag[]=bar&tag[]=baz

Обратите внимание, что когда urlen-код для передачи это должно стать

tag%5B%5D=foo&tag%5B%5D=bar&tag%5B%5D=baz
2 голосов
/ 10 января 2010

Я столкнулся с той же проблемой. Но я смог решить это таким образом.

for($cnt = 0; $cnt < count($siteRows); $cnt++)
{
    $curlParams['site_ids['.$cnt.']'] = $siteRows[$cnt]->site_id; 
}

Работает и с файлами:

for($cnt = 0; $cnt < count($imageRows); $cnt++)
{
    $curlParams['product_images['.$cnt.']'] = '@'.$imageRows[$cnt]->full_path;
}
2 голосов
/ 06 ноября 2009

Я получил его с помощью:

curl_setopt($ch, CURLOPT_POSTFIELDS,array('tag[0]'=>'val0','tag[1]'=>'val1'));

затем $_POST приводит к: $_POST['tag'][0] = 'val0' и $_POST['tag'][1] = 'val1'

1 голос
/ 01 января 2009

Имбус и Пол, спасибо за ваш вклад.

Если бы у меня был контроль над формой, которую я отправляю, я, вероятно, мог бы найти альтернативное решение этой проблемы. Тем не менее, я не имею никакого контроля над формой. И я почти уверен, что программное обеспечение, читающее пост, не является PHP и не подчиняется стандартам tag [].

Даже если это так, cURL, похоже, тоже не подчиняется синтаксису тега []. В основном, я попробовал следующее, и ни один не работал ...

curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@/pathtofile', 'tag[]' => array('a', 'b', 'c'));

curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@/pathtofile', 'tag' => array('a', 'b', 'c'));

И снова, я не думаю, что передача тега [] в любом случае сработает, поскольку форма, на которую я отправляю сообщение, на самом деле ищет тег, а не тег [].

Я действительно начинаю чувствовать, что привязки cURL PHP действительно не поддерживают это. Что кажется мне таким удивительным. Кажется, что он может сделать буквально что-нибудь еще, но он не может сделать что-то простое, как это?

1 голос
/ 31 декабря 2008

Я думаю, что установленным стандартом для нескольких значений в одном ключе (или в одном и том же ключе) является его объединение с разделителем, например для множественного выбора списков параметров в элементах формы. Я считаю, что этот разделитель является символом табуляции (\t) или символом трубы (|).

Если имя ключа оканчивается на [] (например, tag[]), PHP автоматически преобразует значения в массив для вашего удобства.

0 голосов
/ 04 октября 2013

Я нашел этот ответ в Интернете и хочу опубликовать его здесь, прежде чем он исчезнет:

http://yeehuichan.wordpress.com/2011/08/07/sending-multiple-values-with-the-same-namekey-in-curl-post/

function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
    $algos = hash_algos();
    $hashAlgo = null;
    foreach ( array('sha1', 'md5') as $preferred ) {
        if ( in_array($preferred, $algos) ) {
            $hashAlgo = $preferred;
            break;
        }
    }
    if ( $hashAlgo === null ) { list($hashAlgo) = $algos; }
    $boundary =
        '----------------------------' .
        substr(hash($hashAlgo, 'cURL-php-multiple-value-same-key-support' . microtime()), 0, 12);

    $body = array();
    $crlf = "\r\n";
    $fields = array();
    foreach ( $postfields as $key => $value ) {
        if ( is_array($value) ) {
            foreach ( $value as $v ) {
                $fields[] = array($key, $v);
            }
        } else {
            $fields[] = array($key, $value);
        }
    }
    foreach ( $fields as $field ) {
        list($key, $value) = $field;
        if ( strpos($value, '@') === 0 ) {
            preg_match('/^@(.*?)$/', $value, $matches);
            list($dummy, $filename) = $matches;
            $body[] = '--' . $boundary;
            $body[] = 'Content-Disposition: form-data; name="' . $key . '"; filename="' . basename($filename) . '"';
            $body[] = 'Content-Type: application/octet-stream';
            $body[] = '';
            $body[] = file_get_contents($filename);
        } else {
            $body[] = '--' . $boundary;
            $body[] = 'Content-Disposition: form-data; name="' . $key . '"';
            $body[] = '';
            $body[] = $value;
        }
    }
    $body[] = '--' . $boundary . '--';
    $body[] = '';
    $contentType = 'multipart/form-data; boundary=' . $boundary;
    $content = join($crlf, $body);
    $contentLength = strlen($content);

    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Length: ' . $contentLength,
        'Expect: 100-continue',
        'Content-Type: ' . $contentType,
    ));

    curl_setopt($ch, CURLOPT_POSTFIELDS, $content);

}

И использовать его:

curl_setopt_custom_postfields($ch, array(
    'file' => '@a.csv',
    'name' => array('James', 'Peter', 'Richard'),
));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...