Search code examples
phplibcurldesire2learn

Uploading a package to repository using PHP + curl


I need to upload a SCORM package from PHP to D2L instance. I have all needed keys and data, because other queries (for e.g GET request for getting user profile data). I've also tested uploading from Advanced REST plugin for Chrome and it worked correctly, giving Repository.LRWSPublishResult with new learning object id etc.

When I'm trying to do the upload from PHP using CURL (my code is based on GettingStartedSample) I always get "Object moved to /d2l/error/404" response. I've read that this may be caused by 'https' prefix of URL and I should use CURLOPT_FOLLOWLOCATION option, but it does not help. It follows the redirection and returns empty response.

I do a PUT request to

/d2l/api/lr/1.0/objects/?repositoryId=REPO_ID

Does someone have the working code for this and could give me some tips? Thanks!


Solution

  • Here is some PHP code:

    $apiRoute = "/d2l/api/lr/1.0/objects/?repositoryId=" . $repoID;
    
    $id = uniqid();
    $data = "--" . $id . "\r\n".
            "Content-Disposition: form-data; name=\"Resource\"; filename=\"HW_SCORM.zip\"\r\n".
            "Content-Type: application/zip\r\n".
            "\r\n".
            file_get_contents("HW_SCORM.zip") . "\r\n".
            "--" . $id . "--";
    
    $uri = $opContext->createAuthenticatedUri($apiRoute, "PUT");
    
    curl_setopt($ch, CURLOPT_URL, $uri);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
      "Content-Type: multipart/form-data; boundary=" . $id,
      "Content-Length: " . strlen($data))
    );
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);                                                                     
    
    $response = curl_exec($ch);
    

    It will send something like the following:

    Content-Type: multipart/form-data; boundary=ba5567548ef846b595f2d8f0ee5a1ca4
    Accept: */*
    Content-Length: {size}
    
    --ba5567548ef846b595f2d8f0ee5a1ca4
    Content-Disposition: form-data; name="Resource"; filename="HW_SCORM.zip"
    Content-Type: application/zip
    
    {file_data}
    --ba5567548ef846b595f2d8f0ee5a1ca4--
    

    And in response you should see something like

    HTTP/1.1 100 Continue
    
    HTTP/1.1 200 OK
    Cache-Control: no-cache, no-store
    Pragma: no-cache
    Content-Length: 73
    Content-Type: application/json; charset=UTF-8
    Expires: -1
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    Date: Wed, 17 Apr 2013 21:02:42 GMT
    
    {"IdentId":15805,"Version":1,"ExecutionMessage":null,"ExecutionStatus":0}
    

    Random guess: If you forget the trailing newline after the file contents and before the end boundary marker, it looks like the LOR will send the 303 response telling you to go to the 404 page.