Hi I am trying to send an image. The documentation states that I can send a file using multipart/form-data.
Here is my code:
// I checked it, there really is a file.
$file = File::get(Storage::disk('local')->path('test.jpeg')) // it's the same as file_get_contents();
// Here I use the longman/telegram-bot library.
$serverResponse = Request::sendPhoto([
'chat_id' => $this->tg_user_chat_id,
'photo' => $file
]);
// Here I use Guzzle because I thought that there might be an
// error due to the longman/telegram-bot library.
$client = new Client();
$response = $client->post("https://api.telegram.org/$telegram->botToken/sendPhoto", [
'multipart' => [
[
'name' => 'photo',
'contents' => $file
],
[
'name' => 'chat_id',
'contents' => $this->tg_user_chat_id
]
]
]);
Log::info('_response', ['_' => $response->getBody()]);
Log::info(env('APP_URL') . "/storage/$url");
Log::info('response:', ['_' => $serverResponse->getResult()]);
Log::info('ok:', ['_' => $serverResponse->getOk()]);
Log::info('error_code:', ['_' => $serverResponse->getErrorCode()]);
Log::info('raw_data:', ['_' => $serverResponse->getRawData()]);
In both cases, I get this response:
{\"ok\":false,\"error_code\":400,\"description\":\"Bad Request: invalid file HTTP URL specified: Wrong URL host\"}
Other download methods (by ID and by link) work. Can anyone please point me in the right direction?
Using the php-telegram-bot
library, sendPhoto can be used like so:
<?php
require __DIR__ . '/vendor/autoload.php';
use Longman\TelegramBot\Telegram;
use Longman\TelegramBot\Request;
// File
$file = Request::encodeFile('/tmp/image.jpeg');
// Bot
$key = '859163076:something';
$telegram = new Telegram($key);
// sendPhoto
$chatId = 000001;
$serverResponse = Request::sendPhoto([
'chat_id' => $chatId,
'photo' => $file
]);
The trick is to use Request::encodeFile to read the local image.
Related
I am using the Slack Web API Wrapper (https://github.com/palanik/slack-php) trying to upload files to the slack api with the files->upload function with multipart/form-data . However, I only get a error message: "no_file_data".
Here is my code:
include 'vendor/autoload.php';
$slack = new wrapi\slack\slack('api-key');
$file = new CurlFile(realpath(dirname(__FILE__) . '/dir/dir/test.jpg'), 'image/png');
$id = 'XXXX';
$reply = $slack->files->upload
(
[
[
'name' => 'file.jpg',
'channel' => $id,
'file' => $file,
'filetype' => 'jpg',
'filename' => 'test.jpg'
]
]
);
Any ideas of what I am doing wrong? I have tried review the other threads here... The test.jpg-file is not the error source.
I am uploading a file to my API built on laravel. In my code below, the data is sent to the API. But how can i get the file that was uploaded to the API ?
Controller
$file = $request->file('imported-file');
$name = $file->getClientOriginalName();
$path ='/Users/desktop/Folder/laravelapp/public/Voice/';
$client = new \GuzzleHttp\Client();
$fileinfo = array(
'message' => 'Testing content',
'recipient' => "102425",
);
$res = $client->request('POST', $url, [
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
]);
API Controller
if (!empty('FileInfo')) {
return response()->json([
'status' => 'error',
'file_content' => $request->file('FileContents'),
'media'=>$request->hasFile('FileContents'),
]);
}
This is the response, i get "file":null,"file_content":{},"media":true
Why is the file content empty when media is showing true meaning there is a file ?
There can be multiple reasons :
Check your content type. Sometimes we forget to specify multipart/form-data and the request is sent with generic application/x-form-urlencoded etc.
Secondly if you are using jQuery, then set :
contentType: false,
processData: false,
cache: false
This will help your form request no getting converted to string payload and not forcing ajax to set content type. try using FormData.
Update : Found similar answer in this post has detailed answer for this.
I'm using the Azure OCR Service to get the text of an image back (
https://learn.microsoft.com/de-de/azure/cognitive-services/Computer-vision/QuickStarts/PHP).
So far everything is up and running, but now I would like to use a local file instead of an already uploaded one.
$url->setQueryVariables($parameters);
$request->setMethod(HTTP_Request2::METHOD_POST);
// Request body
$request->setBody("{body}"); // Replace with the body, for example, "{"url": "http://www.example.com/images/image.jpg"}
Unfortunately I don't know how to pass the raw binary as the body of my POST request in PHP.
At first, when we refer local file, we should use 'Content-Type': 'application/octet-stream' in a header, then we can send requests that use a stream resource as the body.
Here's my working code using Guzzle for your reference:
<?php
require 'vendor/autoload.php';
$resource = fopen('./Shaki_waterfall.jpg', 'r');
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', 'https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze', [
'query' => [
'visualFeatures' => 'Categories',
'details' => '',
'language' => 'en'
],
'headers' => [
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => '<Ocp-Apim-Subscription-Key>'
],
'body' => $resource
]);
echo $res->getBody();
Using HTTP_Request2:
<?php
require_once 'HTTP/Request2.php';
$request = new Http_Request2('https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze');
$url = $request->getUrl();
$headers = array(
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => '<Ocp-Apim-Subscription-Key>',
);
$request->setHeader($headers);
$parameters = array(
'visualFeatures' => 'Categories',
'details' => '',
'language' => 'en',
);
$url->setQueryVariables($parameters);
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setBody(fopen('./Shaki_waterfall.jpg', 'r'));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
I create excel file and proteced some field in this file. In Office excel all fine my some cell locked for edit, begin I upload my excel file in google drive with convert - true (Whether to convert this file to the corresponding Google Docs format. (Default: false)) But in google spread sheet I can edit locked cell, how to locked in google spread sheet some cell ?
create excel file
$phpExcel = new \PHPExcel();
$ews = $phpExcel->getSheet(0);
$ews->setTitle(Reports::LIST_AOG);
$ews->getProtection()->setSheet(true);
$ews
->getStyle('E6:F36')
->getProtection()->setLocked(
\PHPExcel_Style_Protection::PROTECTION_UNPROTECTED
);
and now I can edit only E6:F36 cell in my file in computer, then upload in google drive
$insertArray = [
'mimeType' => $fileUpload->getMimeType(),
'uploadType' => 'media',
'data' => file_get_contents($fileUpload),
'convert' => true
];
$service = new \Google_Service_Drive($client->getGoogleClient());
$file = new \Google_Service_Drive_DriveFile();
$file->setTitle($nameFile);
$file->setMimeType($fileUpload->getMimeType());
try {
$createdFile = $service->files->insert($file, $insertArray);
$spreadsheetId = $createdFile->getId();
} catch (\Exception $e) {
$view = $this->view((array)GoogleDriveController::ERROR_OCCURRED . $e->getMessage(), 400);
return $this->handleView($view);
}
I fing for google spreadsheet api bundle asimlqt/php-google-spreadsheet-client but not find how to protected
$serviceRequest = new DefaultServiceRequest($arrayAccessTokenClient['access_token']);
ServiceRequestFactory::setInstance($serviceRequest);
$spreadsheetService = new SpreadsheetService();
$spreadsheet = $spreadsheetService->getSpreadsheetById($spreadsheetId);
$worksheetFeed = $spreadsheet->getWorksheets();
$cellFeed = $worksheet->getCellFeed();
$cellFeed->editCell(1, 1, 'developer');
$cellFeed->editCell(1, 2, 'hors');
$cellFeed->editCell(10, 2, 'sum');
or how to protected cell with asimlqt/php-google-spreadsheet-client ?
and In google spread sheet I can any edit any cell (((( Who knows hot to protected cell in google spreat sheet ?
UPDATE
I read Google Sheets API and try create request, this I have
$arrayAccessTokenClient = json_decode($client->getGoogleClient()->getAccessToken(), true);
$serviceRequest = new DefaultServiceRequest($arrayAccessTokenClient['access_token']);
ServiceRequestFactory::setInstance($serviceRequest);
$spreadsheetService = new SpreadsheetService();
$spreadsheet = $spreadsheetService->getSpreadsheetById($spreadsheetId);
$worksheetFeed = $spreadsheet->getWorksheets();
$worksheet = $worksheetFeed->getByTitle(Reports::LIST_AOG);
$addProtectedRange['addProtectedRange'] = [
'protectedRange' => [
'range' => [
'sheetId' => $worksheet->getGid(),
'startRowIndex' => 3,
'endRowIndex' => 4,
'startColumnIndex' => 0,
'endColumnIndex' => 5,
],
'description' => "Protecting total row",
'warningOnly' => true
]
];
$guzzle = new Client();
$putTeam = $guzzle
->post('https://sheets.googleapis.com/v4/spreadsheets/'.$spreadsheetId.':batchUpdate?key='.$arrayAccessTokenClient['access_token'],
[],
json_encode($addProtectedRange)
)
->send()
->getBody(true);
$answer = json_decode($putTeam, true);
But have
Client error response
[status code] 401
[reason phrase] Unauthorized
[url] https://sheets.googleapis.com/v4/spreadsheets/1M_NFvKMZ7Rzbj9ww86AJRMto1UesIy71840r2sxbD5Y:batchUpdate?key=myAccessToken
Early I have Google Api Clien with access token and I can change cell and update with google spread sheet and work fine but https://sheets.googleapis.com/v4/spreadsheets/'.$spreadsheetId.':batchUpdate?key='.$arrayAccessTokenClient['access_token'],
return 401 and I not understand why and how to correct. Help
I think google spreadsheets allow the editing of protected MSExcel sheets the moment they become Google docs. The rules for MSExcel doesn't always apply to Google Sheets. Reading from Adding Named or Protected Ranges:
The following spreadsheets.batchUpdate request contains two request
objects. The first gives the range A1:E3 the name "Counts". The second
provides a warning-level protection to the range A4:E4. This level
protection still allows cells within the range to be edited, but
prompts a warning prior to making the change.
This thread also shares the same view.
However, if it's a google spreadsheet file you want to protect, check this guide.
I read documentation and
$addProtectedRange['requests'] = [
'addProtectedRange' => [
'protectedRange' => [
'range' => [
'sheetId' => $worksheetGid,
'startRowIndex' => $startRowIndex,
'endRowIndex' => $endRowIndex,
'startColumnIndex' => $startColumnIndex,
'endColumnIndex' => $endColumnIndex,
],
'description' => "Protecting total row",
'warningOnly' => false,
'editors' => [
'users' => [
"shuba.ivan.vikt#gmail.com"
]
]
],
]
];
This file_get_contents variant, because Guzzle not returned json response from google, like this:
{
"protectedRangeId": number,
"range": {
object(GridRange)
},
"namedRangeId": string,
"description": string,
"warningOnly": boolean,
"requestingUserCanEdit": boolean,
"unprotectedRanges": [
{
object(GridRange)
}
],
"editors": {
object(Editors)
},
}
I create new question for this for Guzzle reasponse
This is variant for update protected edit cell
$addProtectedRangeJson = json_encode($addProtectedRange);
$url = 'https://sheets.googleapis.com/v4/spreadsheets/' . $spreadsheetId . ':batchUpdate';
$opts = array('http' =>
array(
'method' => 'POST',
'header' => "Content-type: application/json\r\n" .
"Authorization: Bearer $arrayAccessTokenClient\r\n",
'content' => $addProtectedRangeJson
)
);
$context = stream_context_create($opts);
$response = file_get_contents($url, FALSE, $context);
$answer = json_decode($response, TRUE);
$addProtectedRangeUpdate['requests'] = [
'updateProtectedRange' => [
'protectedRange' => [
'protectedRangeId' => $protectedRangeId,
'warningOnly' => false,
'editors' => [
'users' => [
"shuba.ivan.vikt#gmail.com"
]
]
],
'fields' => "namedRangeId,warningOnly,editors"
]
];
$addProtectedRangeUpdateJson = json_encode($addProtectedRangeUpdate);
$optsUpdate = array('http' =>
array(
'method' => 'POST',
'header' => "Content-type: application/json\r\n" .
"Authorization: Bearer $arrayAccessTokenClient\r\n",
'content' => $addProtectedRangeUpdateJson
)
);
$contextUpdate = stream_context_create($optsUpdate);
$responseUpdate = file_get_contents($url, FALSE, $contextUpdate);
$answerUpdate = json_decode($responseUpdate, TRUE);
and this is Guzzle, but Guzzle without google json response this is bad I wait maybe who know what is it problem, because standard php function file_get_contents work very well and I have json google response. But without response this variant work normal, cell protected in spread sheet
$guzzle = new Client();
$postCell = $guzzle
->post('https://sheets.googleapis.com/v4/spreadsheets/' . $spreadsheetId . ':batchUpdate',
[],
$addProtectedRangeJson
)
->addHeader('Authorization', 'Bearer ' . $arrayAccessTokenClient)
->addHeader('Content-type', 'application/json')
;
$postCell
->send()
->getBody(true)
;
$contents = (string) $postCell->getBody();// get body that I post -> my request, not response
$contents = $postCell->getBody()->getContents();// not find getContents, ask me did you mean to call getContentMd5
$answer = json_decode($postCell->getResponse()->getBody(), true);
I am able to upload a file to an API endpoint using Postman.
I am trying to translate that into uploading a file from a form, uploading it using Laravel and posting to the endpoint using Guzzle 6.
Screenshot of how it looks in Postman (I purposely left out the POST URL)
Below is the text it generates when you click the "Generate Code" link in POSTMAN:
POST /api/file-submissions HTTP/1.1
Host: strippedhostname.com
Authorization: Basic 340r9iu34ontoeioir
Cache-Control: no-cache
Postman-Token: 6e0c3123-c07c-ce54-8ba1-0a1a402b53f1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileContents"; filename=""
Content-Type:
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileInfo"
{ "name": "_aaaa.txt", "clientNumber": "102425", "type": "Writeoff" }
----WebKitFormBoundary7MA4YWxkTrZu0gW
Below is controller function for saving the file and other info. The file uploads correctly, I am able to get the file info.
I think the problem I am having is setting the multipart and headers array with the correct data.
public function fileUploadPost(Request $request)
{
$data_posted = $request->input();
$endpoint = "/file-submissions";
$response = array();
$file = $request->file('filename');
$name = time() . '_' . $file->getClientOriginalName();
$path = base_path() .'/public_html/documents/';
$resource = fopen($file,"r") or die("File upload Problems");
$file->move($path, $name);
// { "name": "test_upload.txt", "clientNumber": "102425", "type": "Writeoff" }
$fileinfo = array(
'name' => $name,
'clientNumber' => "102425",
'type' => 'Writeoff',
);
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [env('API_USERNAME'), env('API_PASSWORD')],
'multipart' => [
[
'name' => $name,
'FileContents' => fopen($path . $name, 'r'),
'contents' => fopen($path . $name, 'r'),
'FileInfo' => json_encode($fileinfo),
'headers' => [
'Content-Type' => 'text/plain',
'Content-Disposition' => 'form-data; name="FileContents"; filename="'. $name .'"',
],
// 'contents' => $resource,
]
],
]);
if($res->getStatusCode() != 200) exit("Something happened, could not retrieve data");
$response = json_decode($res->getBody());
var_dump($response);
exit();
}
The error I am receiving, screenshot of how it displays using Laravel's debugging view:
The way you are POSTing data is wrong, hence received data is malformed.
Guzzle docs:
The value of multipart is an array of associative arrays, each
containing the following key value pairs:
name: (string, required) the form field name
contents:(StreamInterface/resource/string, required) The data to use in the
form element.
headers: (array) Optional associative array of custom headers to use with the form element.
filename: (string) Optional
string to send as the filename in the part.
Using keys out of above list and setting unnecessary headers without separating each field into one array will result in making a bad request.
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [ env('API_USERNAME'), env('API_PASSWORD') ],
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
]);
$body = fopen('/path/to/file', 'r');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
http://docs.guzzlephp.org/en/latest/quickstart.html?highlight=file
In Laravel 8 with guzzle I am using this:
The idea is that you are reading the file with fread or file_get_content, then you can use the Laravel getPathname() which points to the file in /tmp
$response = $this
->apiClient
->setUserKey($userToken)
->post(
'/some/url/to/api',
[
'multipart' => [
'name' => 'avatar',
'contents' => file_get_contents($request->file('avatar')->getPathname()),
'filename' => 'avata.' . $request->file('avatar')->getClientOriginalExtension()
]
]
);