Send a file through a POST request with http_socket in CakePHP? - php

I need to make a HTTP POST call to a Hudson CI server from CakePHP. The call is parametrized and contains a few key/value pairs. Some of those are in fact files which need to be uploaded.
Since I'm using CakePHP, I'd rather use the HttpSocket class which comes with the framework rather then try and write my own cURL based implementation.
So far, the call looks like this:
$result = $http->post($apiCall, $params, $auth);
$apiCall being the URI of the Hudson REST API.
$params being an array of parameters which go with the POST call.
$auth containing a user/pass for Basic Auth which configured with this is instance of Hudson.
I'm a bit puzzled though: what would I need to do to also included files in my $params array?
We are running Hudson v1.371 which should - as far as I've gathered - support file uploads coming from a parametrized build call.
Thanks!

I don't know if the HttpSocket class handles multipart Http requests. But you can create it manually. I've done this in my CakePHP GData Plugin that includes functionality for uploading videos to YouTube. The save method in the YouTubeVideo model creates a multipart Http request with the first part containing an XML document with meta data about the video and the second part is the binary contents of the video file being uploaded:
// The boundary string is used to identify the different parts of a
// multipart http request
$boundaryString = 'Next_Part_' . String::uuid();
// Build the multipart body of the http request
$body = "--$boundaryString\r\n";
$body.= "Content-Type: application/atom+xml; charset=UTF-8\r\n";
$body.= "\r\n";
$body.= $doc->saveXML()."\r\n";
$body.= "--$boundaryString\r\n";
$body.= "Content-Type: {$data[$this->alias]['file']['type']}\r\n";
$body.= "Content-Transfer-Encoding: binary\r\n";
$body.= "\r\n";
$body.= file_get_contents($data[$this->alias]['file']['tmp_name'])."\r\n";
$body.= "--$boundaryString--\r\n";
$this->request = array(
'method' => 'POST',
'uri' => array(
'host' => 'uploads.gdata.youtube.com',
'path' => '/feeds/api/users/default/uploads',
),
'header' => array(
'Content-Type' => 'multipart/related; boundary="' . $boundaryString . '"',
'Slug' => $data[$this->alias]['file']['name']
),
'auth' => array(
'method' => 'OAuth',
),
'body' => $body,
);
This might get you there.

I tried using typical syntax $result = $HttpSocket->post($url,$data,$request); and it works for me. Btw, there are some instances that httpsocket sends blank data (which I haven't resolved yet) so I used cURL for instead of this.
Also, make sure you're using multipart form for your form. :)

Related

Upload data using selling-partner-api in Amazon using PHP

I have successfully encrypted the required parameters, but I am posting the data to this URL
https://tortuga-prod-na.s3-external-1.amazonaws.com/%2FNinetyDays/amzn1.tortuga.3.xxxxx-xxx-xxxx-xxx-xxxxxxx.xxxxx
Drops me this error AuthorizationHeaderMalformedThe authorization header is malformed; incorrect service "execute-api". This endpoint belongs to "s3".9DD75A286E7422B6rxCxNZ3veB/3ZJ1qrtvleA0JaHTPqprLYe3I5mM/LYLLEVPL6iKGv0irGmV1O9SS4AcmPsM/8/I=
$headers = [
'Content-Type: text/plain; charset=utf-8',
'X-Amz-Content-Sha256: UNSIGNED-PAYLOAD',
'X-Amz-Date: 20210105T095435Z',
'Authorization: AWS4-HMAC-SHA256 Credential={ access-key-when-create-IAM }/20210105/us-east-1/execute-api/aws4_request, SignedHeaders=host;x-amz-access-token;x-amz-content-sha256;x-amz-date, Signature={generated through auth process}',
];
I have lost no idea what's wrong. Any help will be appreciated.
Change service from 'execute-api' to 's3'

PHP Soap Request headers not working correctly with a variable?

I've been trying to create a concatenated url to use in a SOAPAction POST using php curl.
I've encountered an intersting issue with the SOAP Api i'm trying to access.
If i use the httpheaders array as:
$header = array(
"Content-Type: text/xml",
"SOAPAction: http://tempuri.org/IProductsService/getProduct"
);
I have no issues. It goes through and the response is exactly what i would expect.
However, if i use it like this:
$A = "ProductsService";
$B = "getProduct";
$soapAction = "SOAPAction: http://tempuri.org/I" . $A . "/" . $B;
$headerTest = array(
"Content-Type: text/xml",
$soapAction
);
It doesn't work. (yes there is an I on the soap action i need to use)
I've tried various different ways of doing this. With soap action in the array, without soap action in the array. Syntatically in PHP it IS correct. However i keep getting the response from the api stating "ActionNotSupported". It says it cannot be processed due to a contractFilter mismatch at the endpointDispatcher.
Does anyone know why? And what i might be doing wrong?

Performing a Resumable Upload in PHP - Google Cloud Storage

I want to achieve this workflow from my server, using PHP and a service account. Basically, I just want to generate a resume URI on my server, send it on my client and do the upload from my client. But the PHP SDK doesn't provide a method to do this !
I do not want to use Signed URL, as they do not allow me to control the file being uploaded. I just want to make a simple POST, like described in the page I linked, using the credentials (the Bearer token) loaded by the PHP SDK.
Is there anyway to do this without re-coding the entire auth part ?
Do you want to reproduce the steps provided in [1] to save the resumable session URI using PHP?
If this is the case, I can think on that you may build a simple PHP POST request using the file_get_contents() function (use http_build_query() function [2] to generate a URL-encoded query string to specify POST variables).
For example, for a resumable session (as shown in the documentaion [1]):
POST https://www.googleapis.com/upload/storage/v1/b/myBucket/o?uploadType=resumable HTTP/1.1
Authorization: Bearer [YOUR_AUTH_TOKEN]
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/jpeg
X-Upload-Content-Length: 2000000
{
"name": "myObject"
}
You may try a PHP script for making this POST request. A possible option for a PHP script would be similar to this:
<?php
$post = http_build_query(array('name'=>'myObject')); // POST variable "name"
// Create the HTTP Headers
$headers = array(
'http' => array(
'method' => 'POST',
'header' => "Content-type: application/json\r\n"."charset=UTF-8\r\n"."X-Upload-Content-Type: image/jpeg\r\n"."X-Upload-Content-Length: 2000000\r\n",
'content' => $post
)
);
$s_context = stream_context_create($headers);
$uri = file_get_contents('https://www.googleapis.com/upload/storage/v1/b/myBucket/o?uploadType=resumable', false, $s_context);
?>
Could you try this PHP script and post your results?
[1] https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload
[2] http://php.net/manual/en/function.http-build-query.php

attach file as multipart/form-data content-type - Laravel

I am using FreshDesk API as a ticketing system. When trying to send an attachment, it was stated that it should be sent as multipart/form-data content-type. Could someone explain how this is done?!
How I am sending attachments:
$json = json_encode(
array(
"helpdesk_note" => array(
"body" => Input::get('reply'),
"user_id" => $requester_id,
"attachments" => Input::get('photo'),
"private" => true
)
)
);
I don't know how you're querying the API but in case you're using CURL, just set the appropriate header:
curl_setopt($ch , CURL_HTTPHEADER , "Content-Type: multipart/form-data" );
Personally I would recommend Guzzle which has a clean and straightforward API.
In Guzzle you can modify your headers in a more OO-Way. There are several ways to accomplish your task. On possible approach could be:
$client = new GuzzleHttp\Client();
$request = $client->createRequest('POST', 'https://url.com/to/post/to');
$request->setHeader('content-type', 'multipart/form-data');
// Set the data you need to
$response = $client->send($request);
var_dump($response);
Guzzle btw, is a piece of cake to integrate with Laravel. Just require it in your composer.json and you're good to go!

Upload File via RESTful API?

I was trying to make an RESTful API call to upload videos through POST method. What I am lacking is that I don't know the best practices for writing this kind of API as well I don't find any resource on the internet to follow. Right now I am doing this:
I am working in PHP and zend framework ( Zend_Rest_Route ).
First approach:
using file_get_contents on client side and POST it to API using curl, and on server side using file_put_contents to write that data and sending an appropriate response.
Second:
using Zend_File_Treansfer to receive file at server side, and putting address of my upload api end point in zend_form with setting method as post. In this case file is uploaded to server, but after submitting the form, the url in address bar points to the api server and never comes back to the form.
Am I doing it right?, if not do let me know what are the best practices and how to accomplish this.
Thank you for your time.
Something like this worked for me:
public function postAttachment($fileName, $fileMimetype, $fileContents, $postURL, $username, $password)
{
$auth = base64_encode($username . ':' . base64_decode($password));
$header = array("Authorization: Basic ".$auth);
array_push($header, "Accept: */*");
$boundary = "----------------------------".substr(md5(rand(0,32000)), 0, 12);
$data = "";
$data .= "--".$boundary."\r\n";
//Collect Filedata
$data .= "Content-Disposition: form-data; name=\"file\"; filename=\"".$fileName."\"\r\n";
$data .= "Content-Type: ".$fileMimetype."\r\n";
$data .= "\r\n";
$data .= $fileContents."\r\n";
$data .= "--".$boundary."--";
// add more parameters or files here
array_push($header, 'Content-Type: multipart/form-data; boundary='.$boundary);
$params = array('http' => array(
'method' => 'POST',
'protocol_version' => 1.1,
'user_agent' => 'File Upload Agent',
'header' => $header,
'content' => $data
));
$ctx = stream_context_create($params);
$fp = fopen($postURL, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with ".$postURL." ".$php_errormsg);
}
$responseBody = #stream_get_contents($fp);
if ($responseBody === false) {
throw new Exception("Problem reading data from ".$postURL.", ".$php_errormsg);
}
}
If you want to post several files, or add other multi-part parameters, it's easy to add these in other boundaries too.
I found some of this code on another post, and you can probably find similar code in the PHP wiki (http://www.php.net/manual/en/function.stream-context-create.php#90411). BUT ... That code was not properly handling the carriage return + line feeds and my server was summarily rejecting that post. In addition, that the older code was also using HTTP version 1.0 -- (which does not re-use sockets). When using HTTP 1.1 sockets are re-used when posting lots of files. (This works with HTTPS too.) I added my own user agent - If your are tricking some server into thinking this is a browser post, you might want to change the user agent to spoof a browser.
have you tried adding a redirect to end of your controller action that handles the upload? (if not you really should as its good practice to redirect after post) (make sure you redirect AFTER your logic has executed). In essence the 'page' that receives the post data should just work on the data, and any information you want to return to the user about that post action should be given to them on the page you redirect them to.
[form]--POST-->['post' controller action]--redirect (302)-->[page with success/failure info]

Categories