0

This question is market as answered in this thread:

How to POST an XML file using cURL on php?

But that answer wasn't really the correct answer in my opinion since it just show how to send XML code with cURL. I need to send an XML file.

Basically, I need this C# code to be converted to PHP:

public Guid? UploadXmlFile()
{
    var fileUploadClient = new WebClient();
    fileUploadClient.Headers.Add("Content-Type", "application/xml");
    fileUploadClient.Headers.Add("Authorization", "api " + ApiKey);

    var rawResponse = fileUploadClient.UploadFile(Url, FilePath);
    var stringResponse = Encoding.ASCII.GetString(rawResponse);

    var jsonResponse = JObject.Parse(stringResponse);
    if (jsonResponse != null)
    {
        var importFileId = jsonResponse.GetValue("ImportId");
        if (importFileId != null)
        {
            return new Guid(importFileId.ToString());
        }
    }
    return null;
}

I have tried in several ways and this is my latest try.

The cURL call:

/**
 * CDON API Call
 *
 */
function cdon_api($way, $method, $postfields=false, $contenttype=false)
{
    global $api_key;

    $contenttype = (!$contenttype) ? 'application/x-www-form-urlencoded' : $contenttype;

    $curlOpts = array(
        CURLOPT_URL => 'https://admin.marketplace.cdon.com/api/'.$method,
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_HTTPHEADER => array('Authorization: api '.$api_key, 'Content-type: '.$contenttype, 'Accept: application/xml')
    );

        if ($way == 'post')
        {
            $curlOpts[CURLOPT_POST] = TRUE;
        }
        elseif ($way == 'put')
        {
            $curlOpts[CURLOPT_PUT] = TRUE;
        }

        if ($postfields !== false)
        {
            $curlOpts[CURLOPT_POSTFIELDS] = $postfields;
        }

    # make the call
    $ch = curl_init();
    curl_setopt_array($ch, $curlOpts);
    $response = curl_exec($ch);
    curl_close($ch);

    return $response;
}

The File Export:

/**
 * Export products
 *
 */
function cdon_export()
{
    global $api_key;

    $upload_dir = wp_upload_dir();
    $filepath = $upload_dir['basedir'] . '/cdon-feed.xml';

    $response = cdon_api('post', 'importfile', array('uploaded_file' => '@/'.realpath($filepath).';type=text/xml'), 'multipart/form-data');

    echo '<br>Response 1: <pre>'.print_r(json_decode($response), true).'</pre><br>';

    $data = json_decode($response, true);

        if (!empty($data['ImportId']))
        {
            $response = cdon_api('put', 'importfile?importFileId='.$data['ImportId'], false, 'text/xml');

            echo 'Response 2: <pre>'.print_r(json_decode($response), true).'</pre><br>';

            $data = json_decode($response, true);
        }
}

But the output I get is this:


Response 1:

stdClass Object ( [Message] => The request does not contain a valid media type. )


I have experimented around with different types at the different places, application/xml, multipart/form-data and text/xml, but nothing works.

How do I do to make it work? How do I manage to send the XML file with cURL?

4
  • 1
    From the PHP manual "CURLOPT_POSTFIELDS: The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path." Commented Dec 14, 2017 at 23:17
  • @RamRaider Yes, as you see that's exactly how I do. But it won't work. Commented Dec 14, 2017 at 23:47
  • @RamRaider the @ approach was deprecated years ago, became unreliable 5.5, and even more unreliable in 5.6, and completely stopped working in 7.0, use CURLFile instead of @ Commented Dec 15, 2017 at 0:18
  • @hanshenrik - I was unaware of that, I still have php 5.3.2 so have never read about that in the manual :( time for an upgrade perhaps Commented Dec 15, 2017 at 6:23

1 Answer 1

1

to me, it looks like the C# code just does the equivalent of

function UploadXmlFile(): ?string {
    $ch = curl_init ( $url );
    curl_setopt_array ( $ch, array (
            CURLOPT_POST => 1,
            CURLOPT_HTTPHEADER => array (
                    "Content-Type: application/xml",
                    "Authorization: api " . $ApiKey 
            ),
            CURLOPT_POSTFIELDS => file_get_contents ( $filepath ),
            CURLOPT_RETURNTRANSFER => true 
    ) );
    $jsonResponse = json_decode ( ($response = curl_exec ( $ch )) );
    curl_close ( $ch );
    return $jsonResponse->importId ?? NULL;
}

but at least 1 difference, your PHP code adds the header 'Accept: application/xml', your C# code does not

Sign up to request clarification or add additional context in comments.

6 Comments

Hmm, the $response is empty now. It should contain json datas.
I agree. The trick is to set CURLOPT_POSTFIELD to a string so that cURL does not attempt to look into Content-Type as it otherwise would (and allows you to use the correct application/xml Content-Type). I've had to do the same for a SOAP client some time ago and this was a major stumbling block.
I added it as string and now I get The request does not contain a valid multipart content. whatever I do...
@PeterWesterlund then that's a bug with the api server, let the api devs know that when you send the header Content-Type: application/xml, the server try to parse it as Content-Type: Multipart/form-data. but it also means that fileUploadClient silently overwrites the Content-Type header when uploadFile is called, that's kinda shitty behavior, it should at least generate a warning.. and finally it means you must modify the curl code to transfer the file in multipart/form-data format, so remove the Content-Type: application/xml header, and (too long for comment)
@PeterWesterlund and replace CURLOPT_POSTFIELDS => file_get_contents ( $filepath ) with CURLOPT_POSTFIELDS => array(new CURLFile($filepath)) - now curl will upload the xml in multipart/form-data format
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.