fopen on url and bytestream - php

i have a question about fopen() and base64 comunication.
The scenario is that: i have a service A that must fetch from url a resource (png/jpeg or pdf). The code is that:
$uri = urldecode($_POST['uri']);
$imgfile = $uri;
$handle = fopen($uri, 'r');
$imagebinary = '';
while (!feof($handle)) {
$c = fgetc($handle);
if($c === false) break;
$imagebinary .= $c;
}
fclose($handle);
$return = base64_encode($imagebinary);
Now i have JQUERY function that send this $return (something like that: 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs') to another PHP service, named B.
B service take this string and try to save it on disk. In the specific the service B try to save the file on amazon s3, the code is that:
// in $imagedata is saved the string generated by service A
$imagedata = $_POST['serviceA_base64encodedfile'];
// $contentType taken from switch function on $ext
// for example 'image/png'
$filename = sha1(uniqid()) . '.' . $ext;
$full_filename = $path . '/' . $filename;
$stream = fopen('data://' . $contentType . ';base64,' . $imagedata, 'r');
fseek($stream, 0);
$opt = array(
'fileUpload' => $stream,
'acl' => AmazonS3::ACL_PUBLIC,
'contentType' => $contentType
);
$s3 = new AmazonS3(AWS_KEY, AWS_SECRET_KEY);
$response = $s3->create_object($bucket, $filename, $opt);
But the image that being saved is corrupted, in additionals this images or pdf have less bytes then orginal.
I need realy help :D

I'm not 100% sure this will work, but why not base64_decode the data back to binary, then write the data to a temporary file and send it to amazon from that location. Something like (untested):
// in $imagedata is saved the string generated by service A
$imagedata = base64_decode($_POST['serviceA_base64encodedfile']);
if (!$imagedata){
//Handle invalid base64 encoded data
}
// $contentType taken from switch function on $ext
// for example 'image/png'
$filename = sha1(uniqid()) . '.' . $ext;
$full_filename = $path . '/' . $filename;
$tmpfname = tempnam("/tmp", "image_to_upload");
$populated = file_put_contents($tmpfname,$imagedata);
if (!$populated){
//handle write failures
}
$opt = array(
'fileUpload' => "/tmp/".$tmpfname,
'acl' => AmazonS3::ACL_PUBLIC,
'contentType' => $contentType
);
$s3 = new AmazonS3(AWS_KEY, AWS_SECRET_KEY);
$response = $s3->create_object($bucket, $full_filename, $opt);
I'm also presuming on the last call, that $full_filename is where you want to store the file on the s3 server... though you can just use $file_name.

Related

file_put_contents save a corrupted image [base64] [duplicate]

I'm using Nihilogic's "Canvas2Image" JavaScript tool to convert canvas drawings to PNG images.
What I need now is to turn those base64 strings that this tool generates, into actual PNG files on the server, using PHP.
In short, what I'm currently doing is to generate a file on the client side using Canvas2Image, then retrieve the base64-encoded data and send it to the server using AJAX:
// Generate the image file
var image = Canvas2Image.saveAsPNG(canvas, true);
image.id = "canvasimage";
canvas.parentNode.replaceChild(image, canvas);
var url = 'hidden.php',
data = $('#canvasimage').attr('src');
$.ajax({
type: "POST",
url: url,
dataType: 'text',
data: {
base64data : data
}
});
At this point, "hidden.php" receives a data block that looks like data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABE...
From this point on, I'm pretty much stumped. From what I've read, I believe that I'm supposed to use PHP's imagecreatefromstring function, but I'm not sure how to actually create an actual PNG image from the base64-encoded string and store it on my server.
Please aid!
You need to extract the base64 image data from that string, decode it and then you can save it to disk, you don't need GD since it already is a png.
$data = 'data:image/png;base64,AAAFBfj42Pj4';
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
file_put_contents('/tmp/image.png', $data);
And as a one-liner:
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
An efficient method for extracting, decoding, and checking for errors is:
if (preg_match('/^data:image\/(\w+);base64,/', $data, $type)) {
$data = substr($data, strpos($data, ',') + 1);
$type = strtolower($type[1]); // jpg, png, gif
if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
throw new \Exception('invalid image type');
}
$data = str_replace( ' ', '+', $data );
$data = base64_decode($data);
if ($data === false) {
throw new \Exception('base64_decode failed');
}
} else {
throw new \Exception('did not match data URI with image data');
}
file_put_contents("img.{$type}", $data);
Try this:
file_put_contents('img.png', base64_decode($base64string));
file_put_contents docs
I had to replace spaces with plus symbols str_replace(' ', '+', $img); to get this working.
Here is the full code
$img = $_POST['img']; // Your data 'data:image/png;base64,AAAFBfj42Pj4';
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
file_put_contents('/tmp/image.png', $data);
Hope that helps.
It worth to say that discussed topic is documented in RFC 2397 - The "data" URL scheme (https://www.rfc-editor.org/rfc/rfc2397)
Because of this PHP has a native way to handle such data - "data: stream wrapper" (http://php.net/manual/en/wrappers.data.php)
So you can easily manipulate your data with PHP streams:
$data = 'data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';
$source = fopen($data, 'r');
$destination = fopen('image.gif', 'w');
stream_copy_to_stream($source, $destination);
fclose($source);
fclose($destination);
Taken the #dre010 idea, I have extended it to another function that works with any image type: PNG, JPG, JPEG or GIF and gives a unique name to the filename
The function separate image data and image type
function base64ToImage($imageData){
$data = 'data:image/png;base64,AAAFBfj42Pj4';
list($type, $imageData) = explode(';', $imageData);
list(,$extension) = explode('/',$type);
list(,$imageData) = explode(',', $imageData);
$fileName = uniqid().'.'.$extension;
$imageData = base64_decode($imageData);
file_put_contents($fileName, $imageData);
}
Well your solution above depends on the image being a jpeg file. For a general solution i used
$img = $_POST['image'];
$img = substr(explode(";",$img)[1], 7);
file_put_contents('img.png', base64_decode($img));
Total concerns:
$data = 'data:image/png;base64,AAAFBfj42Pj4';
// Extract base64 file for standard data
$fileBin = file_get_contents($data);
$mimeType = mime_content_type($data);
// Check allowed mime type
if ('image/png'==$mimeType) {
file_put_contents('name.png', $fileBin);
}
http://php.net/manual/en/wrappers.data.php
http://php.net/manual/en/function.mime-content-type.php
One-linear solution.
$base64string = 'data:image/png;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';
file_put_contents('img.png', base64_decode(explode(',',$base64string)[1]));
This code works for me check below code:
<?php
define('UPLOAD_DIR', 'images/');
$image_parts = explode(";base64,", $_POST['image']);
$image_type_aux = explode("image/", $image_parts[0]);
$image_type = $image_type_aux[1];
$image_base64 = base64_decode($image_parts[1]);
$file = UPLOAD_DIR . uniqid() . '.png';
file_put_contents($file, $image_base64);
?>
based on drew010 example I made a working example for easy understanding.
imagesaver("data:image/jpeg;base64,/9j/4AAQSkZJ"); //use full base64 data
function imagesaver($image_data){
list($type, $data) = explode(';', $image_data); // exploding data for later checking and validating
if (preg_match('/^data:image\/(\w+);base64,/', $image_data, $type)) {
$data = substr($data, strpos($data, ',') + 1);
$type = strtolower($type[1]); // jpg, png, gif
if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
throw new \Exception('invalid image type');
}
$data = base64_decode($data);
if ($data === false) {
throw new \Exception('base64_decode failed');
}
} else {
throw new \Exception('did not match data URI with image data');
}
$fullname = time().$type;
if(file_put_contents($fullname, $data)){
$result = $fullname;
}else{
$result = "error";
}
/* it will return image name if image is saved successfully
or it will return error on failing to save image. */
return $result;
}
try this...
$file = $_POST['file']; //your data in base64 'data:image/png....';
$img = str_replace('data:image/png;base64,', '', $file);
file_put_contents('img/imag.png', base64_decode($img));
PHP has already a fair treatment base64 -> file transform
I use to get it done coding this way:
$blob=$_POST['blob']; // base64 coming from an url, for example
//Now, let's save the image file:
file_put_contents('myfile.png',file_get_contents($blob));
Assuming you have filename in $filename and your base64encoded string in $testfile my oneliner:
file_put_contents($filename,base64_decode(explode(',', $testfile)[1]))
This function should work. this has the photo parameter that holds the base64 string and also path to an existing image directory should you already have an existing image you want to unlink while you save the new one.
public function convertBase64ToImage($photo = null, $path = null) {
if (!empty($photo)) {
$photo = str_replace('data:image/png;base64,', '', $photo);
$photo = str_replace(' ', '+', $photo);
$photo = str_replace('data:image/jpeg;base64,', '', $photo);
$photo = str_replace('data:image/gif;base64,', '', $photo);
$entry = base64_decode($photo);
$image = imagecreatefromstring($entry);
$fileName = time() . ".jpeg";
$directory = "uploads/customer/" . $fileName;
header('Content-type:image/jpeg');
if (!empty($path)) {
if (file_exists($path)) {
unlink($path);
}
}
$saveImage = imagejpeg($image, $directory);
imagedestroy($image);
if ($saveImage) {
return $fileName;
} else {
return false; // image not saved
}
}
}
It's simple :
Let's imagine that you are trying to upload a file within js framework, ajax request or mobile application (Client side)
Firstly you send a data attribute that contains a base64 encoded
string.
In the server side you have to decode it and save it in a local
project folder.
Here how to do it using PHP
<?php
$base64String = "kfezyufgzefhzefjizjfzfzefzefhuze"; // I put a static base64 string, you can implement you special code to retrieve the data received via the request.
$filePath = "/MyProject/public/uploads/img/test.png";
file_put_contents($filePath, base64_decode($base64String));
?>
If you want to randomly rename images, and store both the image path on database as blob and the image itself on folders this solution will help you. Your website users can store as many images as they want while the images will be randomly renamed for security purposes.
Php code
Generate random varchars to use as image name.
function genhash($strlen) {
$h_len = $len;
$cstrong = TRUE;
$sslkey = openssl_random_pseudo_bytes($h_len, $cstrong);
return bin2hex($sslkey);
}
$randName = genhash(3);
#You can increase or decrease length of the image name (1, 2, 3 or more).
Get image data extension and base_64 part (part after data:image/png;base64,) from image .
$pos = strpos($base64_img, ';');
$imgExten = explode('/', substr($base64_img, 0, $pos))[1];
$extens = ['jpg', 'jpe', 'jpeg', 'jfif', 'png', 'bmp', 'dib', 'gif' ];
if(in_array($imgExten, $extens)) {
$imgNewName = $randName. '.' . $imgExten;
$filepath = "resources/images/govdoc/".$imgNewName;
$fileP = fopen($filepath, 'wb');
$imgCont = explode(',', $base64_img);
fwrite($fileP, base64_decode($imgCont[1]));
fclose($fileP);
}
# => $filepath <= This path will be stored as blob type in database.
# base64_decoded images will be written in folder too.
# Please don't forget to up vote if you like my solution. :)
I hope this will help you.
I solved this issue with core php method.
My solved code as below.
$base64string = 'BASE64 STRING GOES HERE';
$uploadpath = 'YOUR UPLOAD DIR PATH';
$parts = explode(";base64,", $base64string); //THIS WILL GET THE ORIGINAL FILE ENCODE STRING
$imagebase64 = base64_decode($parts[1]); //THIS WILL GET THE DECODED IMAGE STRING
$file = $uploadpath . uniqid() . '.png'; // THIS WILL GIVE THE FILE NAME AND SET THE FILE PATH
file_put_contents($file, $imagebase64); // THIS FUNCTION WILL STORE THE IMAGE TO GIVEN PATH WITH FILE_NAME

Laravel: Save Base64 .png file to public folder from controller

I send a png image file to controller in base64 via Ajax. I've already test and sure that controller has received id but still can't save it to public folder.
Here is my controller
public function postTest() {
$data = Input::all();
//get the base-64 from data
$base64_str = substr($data->base64_image, strpos($data->base64_image, ",")+1);
//decode base64 string
$image = base64_decode($base64_str);
$png_url = "product-".time().".png";
$path = public_path('img/designs/' . $png_url);
Image::make($image->getRealPath())->save($path);
// I've tried using
// $result = file_put_contents($path, $image);
// too but still not working
$response = array(
'status' => 'success',
);
return Response::json( $response );
}
Intervention Image gets binary data using file_get_content function:
Reference : Image::make
Your controller should be look like this:
public function postTest() {
$data = Input::all();
$png_url = "product-".time().".png";
$path = public_path().'img/designs/' . $png_url;
Image::make(file_get_contents($data->base64_image))->save($path);
$response = array(
'status' => 'success',
);
return Response::json( $response );
}
$data = Input::all();
$png_url = "perfil-".time().".jpg";
$path = public_path() . "/img/designs/" . $png_url;
$img = $data['fileo'];
$img = substr($img, strpos($img, ",")+1);
$data = base64_decode($img);
$success = file_put_contents($path, $data);
print $success ? $png_url : 'Unable to save the file.';
$file = base64_decode($request['image']);
$safeName = str_random(10).'.'.'png';
$success = file_put_contents(public_path().'/uploads/'.$safeName, $file);
print $success;
This is an easy mistake.
You are using public_path incorrectly. It should be:
$path = public_path() . "/img/designs/" . $png_url;
Also, I would avoid your method of sending the image. Look at a proper upload in a form and use Laravel's Input::file method.
My solution is:
public function postTest() {
$data = Input::all();
//get the base-64 from data
$base64_str = substr($data->base64_image, strpos($data->base64_image, ",")+1);
//decode base64 string
$image = base64_decode($base64_str);
Storage::disk('local')->put('imgage.png', $image);
$storagePath = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix();
echo $storagePath.'imgage.png';
$response = array(
'status' => 'success',
);
return Response::json( $response );
}
what am i doing is using basic way
$file = base64_decode($request['profile_pic']);
$folderName = '/uploads/users/';
$safeName = str_random(10).'.'.'png';
$destinationPath = public_path() . $folderName;
file_put_contents(public_path().'/uploads/users/'.$safeName, $file);
//save new file path into db
$userObj->profile_pic = $safeName;
}
Store or save base64 images in the public folder image and return file path.
$folderPath = public_path() . '/' . 'images/';
$image_parts = explode(";base64,", $image);
$image_type_aux = explode("image/", $image_parts[0]);
$image_type = $image_type_aux[1];
$image_base64 = base64_decode($image_parts[1]);
$uniqid = uniqid();
$file = $folderPath . $uniqid . '.' . $image_type;
file_put_contents($file, $image_base64);
return $file;
Actually, Input::all() returns an array of inputs so you have following:
$data = Input::all();
Now your $data is an array not an object so you are trying to access the image as an object like:
$data->base64_image
So, it's not working. You should try using:
$image = $data['base64_image'];
Since it's (base64_image) accessible from $_POST then Input::file('base64_image') won't work because Input::file('base64_image') checks the $_FILES array and it's not there in your case.
Here is my solution for the file upload from base_64.
public static function uploadBase64File(Request $request, $requestName = 'imageData', $fileName = null, $uploadPath = 'uploads/images/')
{
try {
$requestFileData = $request->$requestName;
// decode the base64 file
$file = base64_decode(preg_replace(
'#^data:([^;]+);base64,#',
'',
$request->input($requestName)
));
if (in_array($file, ["", null, ' '])) {
return null;
}
//handle base64 encoded images here
if ($fileName == null) {
$fileName = Str::random(10);
}
$extension = '.' . explode('/', explode(':', substr($requestFileData, 0, strpos($requestFileData, ';')))[1])[1];
$filePath = $uploadPath . '' . $fileName . '' . $extension;
// dd($extension);
if (!File::exists(public_path($uploadPath))) {
File::makeDirectory(public_path($uploadPath), 0777, true);
}
// dd($filePath);
$ifImageUploadSuccessful = File::put(public_path($filePath), $file);
if (!$ifImageUploadSuccessful) {
return null;
}
return '/' . $filePath;
// throw new Exception("Unable To upload Image");
} catch (Exception $e) {
// dd($e);
throw new Exception($e->getMessage());
}
}
I'v done it!!
I replaced
$data->base64_image to $_POST['base64_image'] and then use
$result = file_put_contents($path, $image);
instead of Image::make($image->getRealPath())->save($path);
But this doesn't look like a laravel ways. I you have another way that look more elegant please tell me!

Adding an image to a JSON WebService -PHP

Is there any way that I can send images via my JSON Webservice?
Here is my code which looks for new images in a specific folder and return some data including (path, id which is the name of image file and the creation time of the file):
function getAllNewPhotos($lastCHK) {
$dirPath = 'c:\my_images';
$files1 = scandir($dirPath);
$files = array_diff($files1, array('.', '..'));
$newFiles = array();
foreach ($files as $file) {
$createTime = filectime($dirPath . '/' . $file);
$path_data = pathinfo($dirPath . '/' . $file);
if ($createTime > $lastCHK) {
$newFiles[] = array(
'path' => $dirPath . '\\' . $file,
'ID' => $path_data['filename'],
'dateImagAdded' => date('Y-m-d H:i:s', $createTime),
);
}
}
return ($newFiles);
}
Is there any way to send the real image along with the other data which I have already passed?
If you need more clarification, please let me know which part you need more clarification.
Thanks
You can use base64 to encode your image
$imagedata = file_get_contents("/path/to/image.jpg");
// alternatively specify an URL, if PHP settings allow
$base64 = base64_encode($imagedata);

Why Response::download() won't download anything except PDF in Laravel 4?

This is the line of code which is giving me sick.
return Response::download(storage_path().'/file/' . $file->id . "." . $file->file->extension);
The files are uploaded and given an id which they are saved under e.g. 25.pdf this works fine if the file is a PDF but doesn't for anything else e.g. PNG. we upgraded from Laravel 3 to 4 to try to overcome this problem.
Any ideas?
EDIT:
I just uploaded a test text file with the word test in it once I uploaded it and then downloaded it I opened it, there were 3 blank lines and the letters te!!!!!I downloaded it through sftp and the file is correctly stored on the server so it is defiantly the download procedure!
I used this function instead of any of the Laravel stuff. :/
(Stolen from other places around the web)
public static function big_download($path, $name = null, array $headers = array()) {
if (is_null($name))
$name = basename($path);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$pathParts = pathinfo($path);
// Prepare the headers
$headers = array_merge(array(
'Content-Description' => 'File Transfer',
'Content-Type' => finfo_file($finfo, $path),
'Content-Transfer-Encoding' => 'binary',
'Expires' => 0,
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Pragma' => 'public',
'Content-Length' => File::size($path),
'Content-Disposition' => 'inline; filename="' . $name . '.' . $pathParts['extension'] . '"'
), $headers);
finfo_close($finfo);
$response = new Symfony\Component\HttpFoundation\Response('', 200, $headers);
// If there's a session we should save it now
if (Config::get('session.driver') !== '') {
Session::save();
}
// Below is from http://uk1.php.net/manual/en/function.fpassthru.php comments
session_write_close();
ob_end_clean();
$response->sendHeaders();
if ($file = fopen($path, 'rb')) {
while (!feof($file) and (connection_status() == 0)) {
print(fread($file, 1024 * 8));
flush();
}
fclose($file);
}
// Finish off, like Laravel would
Event::fire('laravel.done', array($response));
$response->foundation->finish();
exit;
}
One may ask, How can i get path to file in laravel?
Path to file can be achieved like:
public function getDownload(){
$file = public_path()."/downloads/info.pdf";
$headers = array('Content-Type: application/pdf',);
return Response::download($file, 'info.pdf',$headers);
}
function will download file from : 'project/public/download' folder.
(don't forget to set-up routes and controller by your self)
Try including the MIME in the return:
$file = storage_path().'/file/' . $file->id . "." . $file->file->extension;
return Response::download($file, 200, array('content-type' => 'image/png'));
If you are using Windows, go to php.ini and then uncomment "extension=php_fileinfo.dll" section and then use this code:
Route::get('file/download', function()
{
$file = public_path(). '\download\myfile.png';
return Response::download($file);
});

function not uploading remote pdfs

I have 2 functions: one that uses chunked uploading and the other that uploads the entire file
public function chunkedUpload($file, $filename = false, $path = '', $overwrite = true)
{
if (file_exists($file)) {
if ($handle = #fopen($file, 'r')) {
// Set initial upload ID and offset
$uploadID = null;
$offset = 0;
// Read from the file handle until End OF File, uploading each chunk
while ($data = fread($handle, $this->chunkSize)) {
$chunkHandle = fopen('php://temp', 'rw');
fwrite($chunkHandle, $data);
$this->OAuth->setInFile($chunkHandle);
// On subsequent chunks, use the upload ID returned by the previous request
if (isset($response['body']->upload_id)) {
$uploadID = $response['body']->upload_id;
}
$params = array('upload_id' => $uploadID, 'offset' => $offset);
$response = $this->fetch('PUT', self::CONTENT_URL, 'chunked_upload', $params);
$offset += mb_strlen($data, '8bit');
fclose($chunkHandle);
}
// Complete the chunked upload
$filename = (is_string($filename)) ? $filename : basename($file);
$call = 'commit_chunked_upload/' . $this->root . '/' . $this->encodePath($path . $filename);
$params = array('overwrite' => (int) $overwrite, 'upload_id' => $uploadID);
$response = $this->fetch('POST', self::CONTENT_URL, $call, $params);
return $response;
} else {
throw new Exception('Could not open ' . $file . ' for reading');
}
}
// Throw an Exception if the file does not exist
throw new Exception('Local file ' . $file . ' does not exist');
}
public function putFile($file, $filename = false, $path = '', $overwrite = true)
{
if (file_exists($file)) {
if (filesize($file) <= 157286400) {
$filename = (is_string($filename)) ? $filename : basename($file);
$call = 'files/' . $this->root . '/' . $this->encodePath($path . $filename);
// If no filename is provided we'll use the original filename
$params = array(
'filename' => $filename,
'file' => '#' . str_replace('\\', '\\', $file) . ';filename=' . $filename,
'overwrite' => (int) $overwrite,
);
$response = $this->fetch('POST', self::CONTENT_URL, $call, $params);
return $response;
}
throw new Exception('File exceeds 150MB upload limit');
}
// Throw an Exception if the file does not exist
throw new Exception('Local file ' . $file . ' does not exist');
}
I have tested these functions from the same server directory and they both work fine; however, chunkedUpload is able to upload from remote http:// and ftp:// urls but putFile is not able to. Why does this happen? Is there a problem within these two functions that might cause this?
this is because file_exists does not work on remote servers
file_exists() in PHP 5 does not accept URLs only local path names
use curl to send a head request instead
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'your url');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
var_dump($size);

Categories