Php use move_uploaded_file() from json data structure - php

I recive the data by json angular request, but I don´t have ($_FILES['name']['tmp_name']) format, so i can´t use move_uploaded_file()
WEB Json data
avatar {
contentType "application/pdf"
data "data:application/pdf;base64,JVBERi0xLjcNCiW1tbW1DQoxIDAgb2JqDQo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFIvTGFuZyhlcy1DTykgL1N0cnVjdFRyZWVSb290IDMxIDAgUi9NYXJrSW5mbzw8L01hcmtlZCB0cnVlPj4vTWV0YWRhdGEgMjMyIDAgUi9WaWV3ZXJQcmVmZXJlbmNlcyAyMzMgMCBSPj4NCmVuZG9iag0KMiAwIG9iag0KPDwvVHlwZS9QYWdlcy9Db3VudCA0L0tpZHNbIDMgMCBSIDE3IDAgUiAyMiAwIFIgMjYgMCBSXSA+Pg0KZW5kb2JqDQozIDAgb2JqDQo8PC9UeXBlL1BhZ2UvUGFyZW50IDIgMCBSL1Jlc291cmNlczw8L1hPYmplY3Q8PC9JbWFnZTUgNSAwIFIvSW1hZ2U3IDcgMCBSPj4vRXh0R1N0YXRlPDwvR1M2IDYgMCBSL0dTMTAgMTAgMCB…Dg5NiAwMDAwMCBuDQowMDAwMzU4MDc2IDAwMDAwIG4NCjAwMDAzNTgxMjIgMDAwMDAgbg0KdHJhaWxlcg0KPDwvU2l6ZSAyMzUvUm9vdCAxIDAgUi9JbmZvIDMwIDAgUi9JRFs8MDlEM0VCOEI1NzE4NTg0MEIxMjA3MkEyMUM2RkNEOTg+PDA5RDNFQjhCNTcxODU4NDBCMTIwNzJBMjFDNkZDRDk4Pl0gPj4NCnN0YXJ0eHJlZg0KMzU4ODcyDQolJUVPRg0KeHJlZg0KMCAwDQp0cmFpbGVyDQo8PC9TaXplIDIzNS9Sb290IDEgMCBSL0luZm8gMzAgMCBSL0lEWzwwOUQzRUI4QjU3MTg1ODQwQjEyMDcyQTIxQzZGQ0Q5OD48MDlEM0VCOEI1NzE4NTg0MEIxMjA3MkEyMUM2RkNEOTg+XSAvUHJldiAzNTg4NzIvWFJlZlN0bSAzNTgxMjI+Pg0Kc3RhcnR4cmVmDQozNjM3MzINCiUlRU9G"
filename "manualversion1.pdf"
size 363915
}
descripPretensiones "gsdfgfgdfdgf"
fecFin "2021-06-17T05:00:00.000Z"
PHP
In this part i dont have any response of try catch, no error o problem, but my file never is upload to my folder
$data = json_decode(file_get_contents('php://input'), true);
$fileName= $data["avatar"]["filename"];
try {
if(move_uploaded_file(base64_decode($data['avatar']['data']), $finalRute)){
echo 'file update';
}
} catch (Exception $e) {
echo 'Excepción capturada: ', $e->getMessage(), "\n";
}

You have the data encoded as base64 in memory. You will have to do something to write the data to disk instead of using move_uploaded_file, which is designed for moving a temp file on disk to a different location. The most straightforward would be file_put_contents.
Something like:
file_put_contents($finalRute, base64_decode(explode(',', $data['avatar']['data'])[1]));
code edited per AbraCadaver's comments about omitting data:application/pdf;base64,

Related

Getting Data From a Huge JSON File and Transfer it to CSV or SQL

Originally I have JSON file containing 1Million+ books Information and Size is approx 3.1 GB.
I want to transfer this data to some other format to use it more comfortably in sql or csv or other.
Is there any way to do it in simple way.
I know php but 3.1GB is so huge for my system to handle.
suggest any other language(with code to do the same i only understand php) or application that can do the same.
used halaxa/json-machine.
Usage in case of iteration over JSON is the same as in case of json_decode, but it will not hit memory limit no matter how big your file is. No need to implement anything, just your foreach.
Example:
$users = \JsonMachine\JsonMachine::fromFile('500MB-users.json');
foreach ($users as $id => $user) {
// process $user as usual
}
See github readme for more details.
One alternative here is to use the salsify/jsonstreamingparser
You need to create your own Listener.
$testfile = '/path/to/file.json';
$listener = new MyListener();
$stream = fopen($testfile, 'r');
try {
$parser = new \JsonStreamingParser\Parser($stream, $listener);
$parser->parse();
fclose($stream);
} catch (Exception $e) {
fclose($stream);
throw $e;
}

PHP: image mime type from image bytes

Introduction
I have a base64 image string retrieved from a database: $imageBase64Str
I need to retrieve the mime from this content and display the image. This is what the following code does:
function imgMime($imgBytes){
if(is_null($imgBytes)){
return(false);
}
if(strlen($imgBytes)<12){
return(false);
}
$file = tmpfile();
if(!fwrite($file,$imgBytes,12)){
fclose($file);
return(false);
}
$path = stream_get_meta_data($file)['uri'];
$mimeCode=exif_imagetype($path);
fclose($file);
if(!$mimeCode){
return(false);
}
return(image_type_to_mime_type($mimeCode));
}
$imageBytes=base64_decode($imageBase64Str,true);
if(!$imageBytes){
throw new Exception("cannot decode image base64");
}
$imageMime=imgMime($imageBytes);
if(!$imageMime){
throw new Exception("cannot recognize image mime");
}
header('Content-type: '.$imageMime);
echo($imageBytes);
Question
The issue I have with this solution is that it requires me to write the 12 first bytes of the content to a temporary file. I am wondering whether there could be a simple way to avoid this without having to maintain a set of mimes manually. Also, I would like to avoid calling an external program (through exec for example) so that my code remains portable.
Ideally
I wish there was a php function like exif_imagetype_from_bytes. My imgMime function would be simpler:
function imgMime($imgBytes){
if(is_null($imgBytes)){
return(false);
}
if(strlen($imgBytes)<12){
return(false);
}
$mimeCode=exif_imagetype($imgBytes);
if(!$mimeCode){
return(false);
}
return(image_type_to_mime_type($mimeCode));
}
$imageBytes=base64_decode($imageBase64Str,true);
if(!$imageBytes){
throw new Exception("cannot decode image base64");
}
$imageMime=imgMime($imageBytes);
if(!$imageMime){
throw new Exception("cannot recognize image mime");
}
header('Content-type: '.$imageMime);
echo($imageBytes);
Edit: Solution based on selected answer
Thanks a lot to #Kunal Raut for the answer that allowed me to come up with the following solution:
function imgMime($imgBytes){
if(is_null($imgBytes)){
return(false);
}
if(strlen($imgBytes)<12){
return(false);
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime=$finfo->buffer($imgBytes);
if(strncmp($mime, "image/", 6) != 0){
return(false);
}
return($mime);
}
$imageBytes=base64_decode($imageBase64Str,true);
if(!$imageBytes){
throw new Exception("cannot decode image base64");
}
$imageMime=imgMime($imageBytes);
if(!$imageMime){
throw new Exception("cannot recognize image mime");
}
header('Content-type: '.$imageMime);
echo($imageBytes);
This solution is a lot more elegant IMHO.
The issue I have with this solution is that it requires me to write the 12 first bytes of the content to a temporary file. I am wondering whether there could be a simple way to avoid this without having to maintain a set of mimes manually.
This is because of this part of your code
if(!fwrite($file,$imgBytes,12)){
fclose($file);
return(false);
}
It makes you write minimum 12 bytes of data in the file and then lets the execution move forward.You can skip this if() and solve your first problem.
I wish there was a php function like exif_imagetype_from_bytes. My imgMime function would be simpler
Yes there is such function which returns you the type of the base64_decoded string.
finfo_buffer()
For more details regarding this function Click Here.
Use of function
Check out this

Print html before downloading zip file

Hello fellow coders !
I am looking for a solution to show a html page while my php code prepares a .zip which is then downloaded. The reason is because sometimes the zips are quite bigger and take time to make.
The HTML page would be a basic "Please wait while your .zip files is being prepared".
The PHP side used is Symfony. So I come into my getInboxExportAction function by calling https://myapi.com/orders/orderid/inbox/export.
The download function (makeExportDownloadRequestResponse) works fine. But if I add a flush after making my $response, the .zip is printed to the html, instead of being downloaded...
public function getInboxExportAction(Request $request, $orderId)
{
$response = new Response($this->twig->render('base.html.twig',
['content' => '
<h1>Download</h1>
<p>Your zip is being prepared for download, please wait...</p>
']));
$response->headers->set('Content-Type', 'text/html');
//Here I would like to echo + flush my html.
//Then stop the flush and continue my code
$receivedOrder = $this->fetchRequestedReceivedOrder($orderId);
if (!$receivedOrder instanceof ReceivedOrder) {
return $receivedOrder;
}
if (!$receivedOrder->getSentorder()) {
$this->makeErrorResponse('Sent order was not found', Response::HTTP_BAD_REQUEST);
}
return $this->makeExportDownloadRequestResponse($receivedOrder->getSentorder(), $request->get('format'));
}
I am also very open to any other ideas anyone would have to fix this issue :)
Thanks,
Edit : My $this->makeExportDownloadRequestResponse() function returns a response, not a path. We unlink the file on the server for storage reasons.
$content = file_get_contents($zipTmpFile);
unlink($zipTmpFile);
$response = new Response($content);
$dispositionHeader = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT,
'myFile_' . date('Y_m_d_h_i_s') . '.zip');
$response->headers->set('Content-Disposition', $dispositionHeader);
return $response;
Second edit : I understand that what I'm trying to do (change the content-type within one call) I generally frowned upon. I'm currently trying to think of a more elegant solution.
In your getInboxExportAction, just return a response with your text.
Then, in this response, add a <meta http-equiv="refresh" content="1;url=xxx"> tag to redirect the user to another action that will generate the zip file.
You can also handle this redirection with javascript.
Note that you can use a StreamedResponse to handle the zip download: https://symfony.com/doc/current/components/http_foundation.html#streaming-a-response
The most important thing is you set $response->headers->set('Content-Type', 'text/html');, the browser will not download the .zip file.
If your makeExportDownloadRequestResponse method can return the absolute .zip file path (or you can calculate it), you can try:
public function getInboxExportAction(Request $request, $orderId)
{
$response = new Response($this->twig->render('base.html.twig',
['content' => '
<h1>Download</h1>
<p>Your zip is being prepared for download, please wait...</p>
']));
$response->headers->set('Content-Type', 'text/html');
//Here I would like to echo + flush my html.
//Then stop the flush and continue my code
$receivedOrder = $this->fetchRequestedReceivedOrder($orderId);
if (!$receivedOrder instanceof ReceivedOrder) {
return $receivedOrder;
}
if (!$receivedOrder->getSentorder()) {
$this->makeErrorResponse('Sent order was not found', Response::HTTP_BAD_REQUEST);
}
// prepare the to be downloaded zip file
// then, do sth to get the .zip file path
$zipFilePath = $this->makeExportDownloadRequestResponse($receivedOrder->getSentorder(), $request->get('format'));
// re-set header
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename=whateverName.zip');
header('Content-Length: ' . filesize($zipFilePath));
readfile($zipFilePath);
}
It will let browser downloads the zip file.
Finally, If your function is work as an API, and you need a frontend JS to execute it, try with Blob class on JS.
You can indeed use a StreamedResponse to get it rid of this issue. About the fact that the whole .wip file content being displayed because of the flush, try to call ob_flush before

Send Imagick image with HttpRequest (POST)

How can I send an imagic-image with http post without writing image to a disk? The code below isn't working.
// function returns an Imagick Object
$image = $this->generateLvlImage($avatarUrl, $lvl);
// I want to send it with http post
$postRequest = new \HttpRequest($uploadUrl, \HttpRequest::METH_POST);
$postRequest->addRawPostData('photo='.(string)$image);
try {
$postRequest->send();
if ($postRequest->getResponseCode() === 200) {
$response = $postRequest->getResponseBody();
} else {
throw new \Exception('post.failed');
}
} catch (\HttpException $e) {
throw new \Exception($e->getMessage());
}
It's really hard to say for sure without knowing exactly who/what you're attempting to submit it to. Typically, you would base64_encode the image and then base64_decode it on the other end.
$postRequest->addRawPostData('photo='.base64_encode($image->getImageBlob()));
Edit: If you want to send it via multi-part form data then I couldn't give you an answer without plagiarising someoneelses work, so here is a tutorial on it: http://blog.cloudspokes.com/2013/01/reblog-post-multipartform-data-with.html

Save output data in image format

I am saving the data as jpeg file but it is not saving properly.
$file= drupal_http_request('https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CnRvAAAAwMpdHeWlXl-lH0vp7lez4znKPIWSWvgvZFISdKx45AwJVP1Qp37YOrH7sqHMJ8C-vBDC546decipPHchJhHZL94RcTUfPa1jWzo-rSHaTlbNtjh-N68RkcToUCuY9v2HNpo5mziqkir37WU8FJEqVBIQ4k938TI3e7bf8xq-uwDZcxoUbO_ZJzPxremiQurAYzCTwRhE_V0&sensor=true&key=AIzaSyDGsEo0x-oqsIDVn0EaTx6mN1BMXkAhZDs');
$handle=fopen("/public/image.jpeg",'w');
fwrite($handle,$file->data);
fclose($handle);
The output : $file->data is :" IHDRddpâ•TIDATxÚílUåÇkbæ....."
Save yourself the headache - use system_retrieve_file()
$result = system_retrieve_file($url, 'public://image.jpeg');
I imagine your current code isn't working because you're not using a proper URI to the public folder, but you might may as well use the API where available.
Instead file function you can use copy like this:
try{
copy($source, $destination);
}catch(Exception $e) {
echo "<br/>\n unable to copy '$fileName'. Error:$e";
}

Categories