HP ALM 11 Загрузка вложения с использованием PHP и cURL

Мне нужно загрузить вложение к тесту в HP ALM 11. Для этого я создал пользовательскую функцию PHP на основе cURL для использования REST API ALM. Это код:

public function attachment($project, $domain, $entity, $id, $filename)
{
    $qc = $this->qc_cookie;
    $ckfile = $this->ckfile;
    $eol = "\n\n";
    $mime_boundary=md5(time());

    $file_to_upload = '--'.$mime_boundary. $eol;
    $file_to_upload .= 'Content-Disposition: form-data; name="filename"';
    $file_to_upload .= $eol;
    $file_to_upload .= $filename;
    $file_to_upload .= $eol;
    $file_to_upload .= $eol;
    $file_to_upload .= '--'.$mime_boundary. $eol;
    $file_to_upload .= 'Content-Disposition: form-data; name="description"';
    $file_to_upload .= $eol;
    $file_to_upload .= 'Test';
    $file_to_upload .= $eol;
    $file_to_upload .= $eol;
    $file_to_upload .= '--'.$mime_boundary. $eol;
    $file_to_upload .= 'Content-Disposition: form-data; name="file"; filename="'.$filename.'"';
    $file_to_upload .= $eol;
    $file_to_upload .= 'Content-Type: text/plain';
    $file_to_upload .= $eol;
    $file_to_upload .= 'Content-Transfer-Encoding: base64' . $eol . $eol;
    $handle = fopen($filename, 'r');
    $file_to_upload .=  fread($handle,filesize($filename));
    $file_to_upload .= $eol;
    $file_to_upload .= '--'.$mime_boundary.'--'. $eol.$eol;
    fclose($handle);

    $header = array("POST /qcbin/rest/domains/".$domain."/projects/".$project."/".$entity.'/'.$id.'/attachments'." HTTP/1.1",
        'Content-Type: multipart/form-data; boundary='.$mime_boundary,
        //'Content-Length: '.strlen($file_to_upload)
        );
    curl_setopt($qc, CURLOPT_HTTPHEADER, $header);   
    curl_setopt($qc, CURLOPT_POSTFIELDS, $file_to_upload); 
    curl_setopt($qc, CURLOPT_COOKIEFILE, $ckfile);
    curl_setopt($qc, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($qc, CURLOPT_URL, $this->url."/qcbin/rest/domains/".$this->domain."/projects/".$this->project."/".$entity."/".$id.'/attachments');
    return curl_exec($qc);
}

Когда я отправляю запрос на указанный URL-адрес, я получаю следующую ошибку от ALM:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<QCRestException>
    <Id>qccore.general-error</Id>
    <Title>Illegal multi-part arguments. Attachment wasn't created.</Title>
    <StackTrace>java.lang.IllegalArgumentException: Illegal multi-part arguments. Attachment wasn't created.&#xD;
at org.hp.qc.web.restapi.attachments.AttachmentsResource.createAttachmentMutliPart(AttachmentsResource.java:141)&#xD;
at sun.reflect.GeneratedMethodAccessor985.invoke(Unknown Source)&#xD;
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)&#xD;
at java.lang.reflect.Method.invoke(Method.java:597)&#xD;
...

Я хотел бы знать, что я делаю неправильно. Я следую указанной структуре полей POST, которая находится в справочнике по API. Спасибо.


person Libo    schedule 03.04.2013    source источник


Ответы (1)


Я только что решил эту проблему и очень счастлив. Моя проблема заключалась в том, что я определял границу в заголовке с помощью тире так же, как они указаны в теле. Это было неправильно.

Вот пример (на основе документов REST API), который работал у меня:

Заголовки:

Content-Type: multipart/form-data; boundary=myboundary

Тело:

--myboundary
Content-Disposition: form-data; name="filename"

anna.txt
--myboundary
Content-Disposition: form-data; name="file"; filename="anna.txt"

banana
--myboundary--

Я по-прежнему не могу загружать бинарные вложения, но для меня это большое улучшение.

Изменить. Для загрузки файлов любого типа у меня работал следующий код powershell:

$contents = gc "my file path"
$body = @"
--boundary
Content-Disposition: form-data; name="filename"

$name
--boundary
Content-Disposition: form-data; name="file"; filename="$name"

$contents
--boundary--
"@

$headers = @{"Content-Length" = $body.Length; "Content-Type" = "multipart/form-data; boundary=$boundary"}

Invoke-RestMethod -Uri "ALM attachment URI" -Method Post -ContentType "multipart/form-data;boundary=boundary" -WebSession $global:session -Body $body

Изменить: вот мое последнее обновление - функция python, которая успешно загружает вложение через REST API. Обратите внимание, что это часть большой библиотеки, но, надеюсь, вы уловили идею:

def upload_attachment(self, entity_type, id, file_name):
        """
        Name
            upload_attachment
        Description
            Uploads an attachment to the supplied entity
        Parameters
            entity_type: the entity type - i.e. 'test-instance', 'run', etc.
            id: the integer id of the entity
            file_name: the name of the file in the local filesystem
        Returns
        """
        print 'Uploading attachment to %s id=%s' % (entity_type, id)
        with open(file_name, 'rb') as file:
            bin_data = file.read()
        qurl = '%s/qcbin/rest/domains/%s/projects/%s/%s/%s/attachments' % \
            (self.url, self.domain, self.project, entity_type, id)
        headers = {'Content-Type' : 'multipart/form-data; boundary=uploadboundary'}
        body = """--uploadboundary
Content-Disposition: form-data; name="filename"

%s
--uploadboundary
Content-Disposition: form-data; name="file"; filename="%s"

%s
--uploadboundary--""" % (file_name, file_name, bin_data)

    rsp = self.session.post(qurl, data=body, headers=headers)
    if rsp.status_code != 201:
            raise Exception('Failed to upload %s - code=%s message=%s' % \
            (file_name, rsp.status_code, rsp.text))

Я надеюсь, что кто-то найдет это полезным.

Изменить: код не работал, так как он является частью большей библиотеки. Вот пример того, как опубликовать простой текстовый файл с именем «hello.txt» с содержимым «Hello!!» Он был создан с кодом сверху:

Заголовки:

'Content-Type': 'multipart/form-data; boundary=uploadboundary'

Тело:

--uploadboundary
Content-Disposition: form-data; name="filename"

hello.txt
--uploadboundary
Content-Disposition: form-data; name="file"; filename="hello.txt"

Hello!!
--uploadboundary--
person musner    schedule 12.04.2013