I have data stored in a table that is base64 encoded binary file data. I am migrating this data from a version 7x install of BMC Remedy HelpDesk to Jira Service Desk. I would like to be able to send the binary file data directly to Jira via the attachment api. I really do not want to have to create the file locally on my filesystem first. Is there a way to feed the binary data to PHP's CURLFile?
Here is the example code I am using to post a local file via the api:
$process=curl_init($url);
$headers = array(
'X-Atlassian-Token: nocheck',
'Content-Type: multipart/form-data',
'Authorization: Basic XXX'
);
$cfile = new CURLFile("/path/to/file.jpg");
$cfile->setPostFilename("uploaded.jpg");
$data = array('file'=>$cfile);
curl_setopt_array(
$process,
array(
CURLOPT_POST=>true,
CURLOPT_VERBOSE=>1,
CURLOPT_POSTFIELDS=>$data,
CURLOPT_SSL_VERIFYHOST=> 0,
CURLOPT_SSL_VERIFYPEER=> 0,
CURLOPT_RETURNTRANSFER=>true,
CURLOPT_HEADER=>false,
CURLOPT_HTTPHEADER=> $headers
)
);
$result=curl_exec($process);
$ch_error = curl_error($process);
if ($ch_error) {
print "cURL Error: " . $ch_error;
} else {
print "\n" . $result . "\n";
}
curl_close($process);
Related
hello all
i am receiving the http post request from html form to my action.php file and then this php file is writing these values into a text file.
now i want the php file to send the data it receives to a remote http server for further processing (i am using a simple python http server)
here is my php code :
<?php
$data1 = $_REQUEST['key1'];
$data2 = $_REQUEST['key2'];
$data3 = $_REQUEST['key3'];
$data4 = $_REQUEST['key4'];
$data5 = $_REQUEST['key5'];
$fp = fopen('datafile.txt', 'w+');
fwrite($fp, implode("\n", [$data1, $data2, $data3, $data4, $data5]));
fclose($fp);
// example data
$data = array(
'key1'=> $data1,
'key2'=> $data2,
'key3'=> $data3,
'key4'=> $data4,
'key5'=> $data5
);
// build post body
$body = http_build_query($data); // foo=bar&baz=boom
// options, headers and body for the request
$opts = array(
'http'=>array(
'method'=>"POST",
'header'=>"Accept-language: en\r\n",
'data' => $body
)
);
// create request context
$context = stream_context_create($opts);
// do request
$response = file_get_contents('http://2.22.212.12:42221', false, $context)
?>
but when i submit the form , only the datafile.txt file is generated and no post request is sent to the remote python server
what am i doing wrong ?
I would highly recommend using Guzzle, but the docs for stream_context_create use fopen() instead of file_get_contents(), so that might one factor.
Another is the header. The comments on the doc page set the header this way for POST requests:
'header'=> "Content-type: application/x-www-form-urlencoded\r\n"
. "Content-Length: " . strlen($body) . "\r\n",
Take a look at the answers here too for more examples.
I just started using the BING translate API to do a small volume of translations into most of their supported languages and that works pretty well.
There is a GitHub project that has simple PHP code for making the API call to Microsoft. You mostly just need the API key, and it can be customized pretty easily.
Text-Translation-API-V3-PHP
// NOTE: Be sure to uncomment the following line in your php.ini file.
// ;extension=php_openssl.dll
// **********************************************
// *** Update or verify the following values. ***
// **********************************************
// Replace the subscriptionKey string value with your valid subscription key.
$key = 'ENTER KEY HERE';
$host = "https://api.cognitive.microsofttranslator.com";
$path = "/translate?api-version=3.0";
// Translate to German and Italian.
$params = "&to=de&to=it";
$text = "Hello, world!";
if (!function_exists('com_create_guid')) {
function com_create_guid() {
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0x0fff ) | 0x4000,
mt_rand( 0, 0x3fff ) | 0x8000,
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
}
function Translate ($host, $path, $key, $params, $content) {
$headers = "Content-type: application/json\r\n" .
"Content-length: " . strlen($content) . "\r\n" .
"Ocp-Apim-Subscription-Key: $key\r\n" .
"X-ClientTraceId: " . com_create_guid() . "\r\n";
// NOTE: Use the key 'http' even if you are making an HTTPS request. See:
// http://php.net/manual/en/function.stream-context-create.php
$options = array (
'http' => array (
'header' => $headers,
'method' => 'POST',
'content' => $content
)
);
$context = stream_context_create ($options);
$result = file_get_contents ($host . $path . $params, false, $context);
return $result;
}
$requestBody = array (
array (
'Text' => $text,
),
);
$content = json_encode($requestBody);
$result = Translate ($host, $path, $key, $params, $content);
// Note: We convert result, which is JSON, to and from an object so we can pretty-print it.
// We want to avoid escaping any Unicode characters that result contains. See:
// http://php.net/manual/en/function.json-encode.php
$json = json_encode(json_decode($result), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo $json;
I also have a Google Cloud account and am looking for something similar for a few languages that Google supports that BING does not. For v2, it is not too hard to call Google to make the return the translations.
I found this GitHub project that seems to work for v2 API calls with an API key, but unfortunately I think that is a fee-for-service program now ?
google-cloud-php-translate
That also seems to work pretty well if you have an API key. If you are using v3, they apparently updated the libraries and support. You can make a CURL call from the command line and they have some of that documented on their website, but I am looking for a way to make the call using a PHP file.
require 'vendor/autoload.php';
use Google\Cloud\Translate\TranslateClient;
$translate = new TranslateClient([
'key' => 'APIKEY'
]);
// Translate text from english to french.
$result = $translate->translate('Hello world!', [
'target' => 'fr'
]);
echo $result['text'] . "\n";
// Detect the language of a string.
$result = $translate->detectLanguage('Greetings from Michigan!');
echo $result['languageCode'] . "\n";
// Get the languages supported for translation specifically for your target language.
$languages = $translate->localizedLanguages([
'target' => 'en'
]);
foreach ($languages as $language) {
echo $language['name'] . "\n";
echo $language['code'] . "\n";
}
// Get all languages supported for translation.
$languages = $translate->languages();
foreach ($languages as $language) {
echo $language . "\n";
}
Not sure that is even possible, but the best I can come up with is something like this based upon the command line CURL, but the authentication is wrong and fails. I do have the .json file for my Project/Service credentials. The ${PROJECT_ID} I presume is the project ID for the account, and Bearer $(gcloud auth application-default print-access-token) I am not sure about. There are some instructions about how to obtain that through the CLI, but is there a way to get that via a PHP file ? Like I say, the v2 version works fine.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://translation.googleapis.com/v3beta1/projects/${PROJECT_ID}/locations/global:detectLanguage");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\n mimeType: 'text/plain',\n content: 'Omnia Gallia est divisa in tres partes'\n}");
curl_setopt($ch, CURLOPT_POST, 1);
$headers = array();
$headers[] = 'Authorization: Bearer $(gcloud auth application-default print-access-token)';
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
} else {
echo $result;
}
curl_close ($ch);
There might be clues here, but it talks about exporting the path for the credentials file and running PHP scripts from the command line instead of from a server.
Google Cloud Translate API Samples
I have an irrational dislike for using client libraries, so I didn't install the Google PHP library. From what I can tell, the only way to get the authentication to work is to actually go through the whole Oauth2 process. I think the PHP library handles some of that for you, but this code should work as a standalone solution.
First, make sure you've got your Google Cloud Platform account set up, then create a project, then enable the Translation API, after that, create and configure an API key before creating and configuring an OAuth 2.0 client (make sure you enter the correct redirect url). Nothin' to it! ;-)
If you succeed in getting all of that squared away, you should be good to go!
The page effectively redirects the user to the same page they were just on, but includes the results of a GET request in the url. The response contains a code, that can be used to make another GET request in order to retrieve the access token, and once you've got the access token, you can make a POST request to perform the actual translation.
<?php
$clientId = "{your client id}";
$clientSecret = "{your client secret}";
$clientRedirectURL = "{your redirect URL}";
$login_url = 'https://accounts.google.com/o/oauth2/v2/auth?scope=' . urlencode('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/cloud-translation') . '&redirect_uri=' . urlencode($clientRedirectURL) . '&response_type=code&client_id=' . $clientId . '&access_type=online';
if (!isset($_GET['code'])){
header("location: $login_url");
} else {
$code = filter_var($_GET['code'], FILTER_SANITIZE_STRING);
$curlGet = '?client_id=' . $clientId . '&redirect_uri=' . $clientRedirectURL . '&client_secret=' . $clientSecret . '&code='. $code . '&grant_type=authorization_code';
$url = 'https://www.googleapis.com/oauth2/v4/token' . $curlGet;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$data = curl_exec($ch);
$data = json_decode($data, true);
curl_close($ch);
$accessToken = $data['access_token'];
$apiKey = "{your api key}";
$projectID = "{your project id}";
$target = "https://translation.googleapis.com/v3/projects/$projectID:translateText?key=$apiKey";
$headers = array(
"Content-Type: application/json; charset=utf-8",
"Authorization: Bearer " . $accessToken,
"x-goog-encode-response-if-executable: base64",
"Accept-language: en-US,en;q=0.9,es;q=0.8"
);
$requestBody = array();
$requestBody['sourceLanguageCode'] = "en";
$requestBody['targetLanguageCode'] = "pt";
$requestBody['contents'] = array("So, I guess this thing works?");
$requestBody['mimeType'] = "text/plain";
$ch = curl_init($target);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestBody));
$data = curl_exec($ch);
curl_close($ch);
echo $data;
}
Also, I found this tutorial quite helpful.
This probably won't evaluate:
'Authorization: Bearer $(gcloud auth application-default print-access-token)'
It's rather:
// $cmd = 'gcloud auth application-default login';
$cmd = 'gcloud auth application-default print-access-token';
$token = shell_exec($cmd);
besides it probably should be a service account.
It seems google/cloud replaces google/cloud-translate. For Translate, you could edit the translate-v2.json or add translate-v3beta1.json; but v3beta1 has a whole other REST API than v2 ...
I'm try to create folder, using microsoft graph API. In microsoft graph explorer, all work fine, but my php code return an error:
$name = 'newFolder'; $access_token = '123..';
$link = 'https://graph.microsoft.com/v1.0/me/drive/root/children';
$data = array(
"name" => $name,
"folder" => array()
);
$curl=curl_init();
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_URL,$link);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,'POST');
curl_setopt($curl,CURLOPT_HEADER,false);
curl_setopt($curl,CURLOPT_HTTPHEADER, array('Authorization: Bearer '.$access_token, 'Content-Type: application/json'));
curl_setopt($curl,CURLOPT_POSTFIELDS, $data);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,0);
$out = curl_exec($curl);
$codeCurl = curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
this is response of '$out': 400 BadRequest, Unable to read JSON request payload. Please ensure Content-Type header is set and payload is of valid JSON format. I'm can't understand, what wrong? json data is correct, headers too..
The microsoft graph API documentation shows this example request for create folder:
POST /me/drive/root/children
Content-Type: application/json
{
"name": "New Folder",
"folder": { },
"#microsoft.graph.conflictBehavior": "rename"
}
To get this part of the request : "folder": { } you could either put "folder" => new stdClass() in your $data array or keep this "folder" => array() and use json_encode($data, JSON_FORCE_OBJECT). If you use JSON_FORCE_OBJECT, all arrays will be encoded as objects.
I had the same problem, but error in the response was a bit different: Property folder in payload has a value that does not match schema. I am using "folder" => new stdClass() and it works fine.
The right way is using "json_encode()" to put data in a right format. And correct format for the folder was $folderParameters = ["name" => $name, "folder" => ["childCount" => '0']]; (thank Create folder on OneDrive with API)
The right code is :
$link = 'https://graph.microsoft.com/v1.0/me/drive/root/children';
$data = [
"name" => $name,
"folder" => ["childCount" => '0']
];
$headers = [
'Authorization: Bearer '.$access_token,
'Content-Type: application/json'
];
$curl=curl_init();
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_URL,$link);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,'POST');
curl_setopt($curl,CURLOPT_HEADER,false);
curl_setopt($curl,CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,0);
$out = curl_exec($curl);
$codeCurl = curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
I'm contributing data to the opencellid.org website. They have several API options to submit data but the only bulk method requires an HTTP POST file upload with the API key as a POST field. Formats acceptable are CSV, JSON and CLF3. I store the data in an SQL database for internal use and periodically submit data to opencellid.
At the moment the script that I use to submit the data to opencellid queries the SQL DB for the most recent measurements and then saves it as a CSV file on the server and then immediately uploads it via HTTP POST. In my eyes this is inelegant.
So my question is, can you POST upload a CSV file directly from an array without first having to actually create a CSV file on the server?
Here's the code snippet we currently use.
//Create and save CSV
$output = fopen("opencellid.csv","w") or die();
fputcsv($output, array_keys($celldata[0]));
foreach($celldata as $cell) {
fputcsv($output, $cell);
}
fclose($output) or die();
//Upload CSV
$target_url = 'http://opencellid.org/measure/uploadCsv';
$file_name_with_full_path = realpath('./opencellid.csv');
$post = array('key' => 'opencellidapikey',
'datafile'=>'#'.$file_name_with_full_path.";type=text/plain");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$target_url);
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
$postresult = curl_exec ($ch);
Can anyone suggest a way to directly upload a CSV from an array?
I managed to capture the csv data in to a variable using fputcsv to php://output with output buffering. Since the service only allows multipart format for the submission, you need to construct the payload like this.
<?php
//Construct your csv data
$celldata = array(
array(
"heading1",
"heading2",
"heading3",
),
array(
1,
2,
3,
),
array(
4,
5,
6,
)
);
//Output to php://output
ob_start();
$outstream = fopen("php://output", 'w');
foreach($celldata as $cell) {
fputcsv($outstream, $cell);
}
fclose($outstream) or die();
$csv_data = ob_get_clean();
$url = 'http://opencellid.org/measure/uploadCsv';
// Taken from http://stackoverflow.com/questions/3085990/post-a-file-string-using-curl-in-php
// form field separator
$delimiter = '-------------' . uniqid();
// file upload fields: name => array(type=>'mime/type',content=>'raw data')
$fileFields = array(
'datafile' => array(
'type' => 'text/plain',
'content' => $csv_data,
),
);
// all other fields (not file upload): name => value
$postFields = array(
'key' => 'opencellidapikey', //Put your api key here
);
$data = '';
// populate normal fields first (simpler)
foreach ($postFields as $name => $content) {
$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="' . $name . '"';
$data .= "\r\n\r\n";
$data .= $content;
$data .= "\r\n";
}
// populate file fields
foreach ($fileFields as $name => $file) {
$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="' . $name . '";' .
' filename="' . $name . '"' . "\r\n";
$data .= 'Content-Type: ' . $file['type'] . "\r\n";
$data .= "\r\n";
$data .= $file['content'] . "\r\n";
}
$data .= "--" . $delimiter . "--\r\n";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_HTTPHEADER , array(
'Content-Type: multipart/form-data; boundary=' . $delimiter,
'Content-Length: ' . strlen($data)));
curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
curl_setopt($handle, CURLOPT_RETURNTRANSFER,1);
$result = curl_exec($handle);
var_dump($result);
I get API key error, but it should work.
Intreesting question. The only thing I can think of is that you echo the "csv data" with headers of a post and that it's a csv file. That should not create a file on the server afaik. Not sure fully how to approach it, but if you run set apache headers or whichever server system you're using. Give it a shot and let me know if it works.
I'm trying to write a phing build task that will upload a asset to github here. Unfortunately this means I need to write it in a PHP file rather than in CLI (This is the release API for GitHub http://developer.github.com/v3/repos/releases/#upload-a-release-asset). Effectively this is building the CLI query here but in PHP Releasing a build artifact on github
So I've got a generic curl post function and am now customizing the hell out of it
/**
* Send a POST request using cURL
*
* #param UriInterface $url The url and request containing the post information
* #param array $options Extra options for cURL. This can also override the defaults
*
* #return string The response of the object
*/
private function curl_post(UriInterface $url, array $options = array())
{
$this->log('Attempting to upload file with URL ' . $url->toString(), Project::MSG_INFO);
$defaults = array(
CURLOPT_POST => 1,
CURLOPT_HEADER => 1,
CURLOPT_FRESH_CONNECT => 1,
CURLOPT_FORBID_REUSE => 1,
CURLOPT_TIMEOUT => 4,
CURLOPT_POSTFIELDS => $url->getQuery(),
);
// Initiate CURL
$ch = curl_init($url->toString());
// Create the full params
$params = array_merge($options, $defaults);
curl_setopt_array($ch, $params);
if(!$result = curl_exec($ch))
{
$this->log(curl_error($ch), Project::MSG_ERR);
return curl_error($ch);
}
curl_close($ch);
return $result;
}
For the sake of this post it doesn't really matter about UriInterface I've checked it's giving the correct result :)
Then I call this with:
$pageUrl = "https://uploads.github.com/repos/" . $this->owner . '/' . $this->repo . "/releases/" . $this->version . "/assets?name=";
$fullUrl = $pageUrl . $filename;
$headers = array(
'Content-Type: ' . $header,
'Accept: application/vnd.github.manifold-preview',
'Authorization: token TOKEN',
);
$options = array(
CURLOPT_SSL_VERIFYPEER => false, // Despite SSL is 100% supported to suppress the Error 60 currently thrown
CURLOPT_HTTPHEADER => $headers,
CURLOPT_BINARYTRANSFER => 1 // --data-binary
);
// Create the Uri object
$url = new Uri($fullUrl);
$url->setQuery(array('file' => "#$filename"));
$response = $this->curl_post($url, $options);
The first log outputs Attempting to upload file with URL https://uploads.github.com/repos/JoomJunk/Accordion/releases/3.0.2/assets?file=#mod_accordion-3.0.2.zip
Which looks like the correct URL from what I've read about the curl function and based on the API (please feel free to say if this isn't true!) however I'm hitting an error Failed connect to uploads.github.com:1; No error in the log of the curl_error() function.
Does anyone have any ideas/help they can give? If you want more information the full Phing task can be found at https://github.com/JoomJunk/Accordion/blob/development/build/phingext/GituploadTask.php
Your API doc says Send the raw binary content of the asset as the request body. So your POSTFIELDS should be:
CURLOPT_POSTFIELDS => file_get_contents("file.zip"),
You didn't mention what you have in your $header variable. It should be application/zip
// 'Content-Type: ' . $header,
'Content-Type: application/zip',