I have created a app in php. How i can save the profile pictures of the users? Will that be a good idea to save them in db using base64 encode, like this
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAWgBaAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAAB..." />
or anything else
It's a good idea/practice usually only for very small CSS images that are going to be used together (like CSS sprites) when IE compatibility doesn't matter, and saving the request is more important than cacheability.
It has a number of notable downsides:
Doesn't work at all in IE6 and 7.
Works for resources only up to 32k in size in IE8. This is the limit
that applies after base64 encoding. In other words, no longer than
32768 characters.
It saves a request, but bloats the HTML page instead! And makes
images uncacheable. They get loaded every time the containing page or
style sheet get loaded.
Base64 encoding bloats image sizes by 33%.
If served in a gzipped resource, data: images are almost certainly
going to be a terrible strain on the server's resources! Images are
traditionally very CPU intensive to compress, with very little
reduction in size.
Store images in your server and store the path to images in the database. This will reduce extra overload on database server.
Its better to store file path in database rather storing files in databases. Datbases are for structured data, not for blobs. Moreover database storage is usually more expensive than file system storage. Servers doesn't need any special coding or processing to access images in the file system
Copy base64 image "src" to a textbox using javascript. Post a form with base64 url textbox. Its better to save url in database rather saving a file in database.
You can save your base64 image by using this PHP code:
<?php
define('UPLOAD_DIR', 'images/');
$base64img=$_POST['base64img'];
if (stristr($base64img, "data:image/jpeg;base64,")) {
$base64img = str_replace('data:image/jpeg;base64,', '', $base64img);
$uid=time();
$data = base64_decode($base64img);
$file = UPLOAD_DIR . $uid.'.jpg';
file_put_contents($file, $data);
}elseif (stristr($base64img, "data:image/png;base64,")) {
$base64img = str_replace('data:image/png;base64,', '', $base64img);
$uid=time();
$data = base64_decode($base64img);
$file = UPLOAD_DIR . $uid.'.png';
file_put_contents($file, $data);
}elseif (stristr($base64img, "data:image/jpg;base64,")) {
$base64img = str_replace('data:image/jpg;base64,', '', $base64img);
$uid=time();
$data = base64_decode($base64img);
$file = UPLOAD_DIR . $uid.'.jpg';
file_put_contents($file, $data);
}
?>
Related
I try to use lazyload but it's load image poorly so I want to use thumbnail so it can load faster and save bandwidth. There's a lot of source code that I can use for reducing image data and resolution, I am trying to merge it with my upload.php but it doesn't work, I'm trying move_upload_path and copy below move_upload_path, it work and storing in more than one folder but it's not showing up on my MySQL database. Here's my code (I'm not using the new one that storing in multiple folder path)
<?php
echo "<pre>";
print_r($_FILES['my_image']);
echo "</pre>";
$img_name = $_FILES['my_image']['name'];
$img_size = $_FILES['my_image']['size'];
$tmp_name = $_FILES['my_image']['tmp_name'];
$error = $_FILES['my_image']['error'];
if ($error === 0) {
if ($img_size > 125000000) {
$em = "Sorry, your file is too large.";
header("Location: index1.php?error=$em");
}else {
$img_ex = pathinfo($img_name, PATHINFO_EXTENSION);
$img_ex_lc = strtolower($img_ex);
$allowed_exs = array("jpg", "jpeg", "png");
if (in_array($img_ex_lc, $allowed_exs)) {
$new_img_name = uniqid("IMG-", true).'.'.$img_ex_lc;
$img_upload_path = 'uploads/'.$new_img_name;
move_uploaded_file($tmp_name, $img_upload_path);
$sql = "INSERT INTO images(image_url)
VALUES('$new_img_name')";
mysqli_query($conn, $sql);
header("Location: index.php");
}else {
$em = "You can't upload files of this type";
header("Location: index.php?error=$em");
}
}
}else {
$em = "unknown error occurred!";
header("Location: index.php?error=$em");
}
Php's Upload is for a one-time copy from a remote site to your site.
Lazyload, <picture>, and WebP are for speeding up the rendering of your page to users.
INSERTing images into your database is [usually] the wrong approach. Instead, store the image on disk and INSERT the URL pointing to it into the database. Then use <img...> to allow for HTML to fetch the image in parallel after the text on the page has been loaded. This, then, allows for lazyload, etc. to be used.
It is possible to have an image 'inline' by using base64 encoding and using as 'data' in <img...>. This might be useful for thumbnails, but I have decided that it is rarely worth the hassle.
PHP has the "image*()" routines for scaling (etc) images. I would use these for a one-time transformation to a different size (for <picture>) or better compression (WebP) or thumbnail.
It is also possible to use a PHP script to dynamically build an image. I would not use this for repeated build. I use something like this to experiment with different croppings, etc: <img src=".../crop.php?w=...>.
<img ... height=123 width=234> is an easy way to make a thumbnail (or other size) of a picture from the original. However, it requires the client to download the original, then, change the height and width, so it is not optimal for performance.
When storing an image in MySQL, be sure to use, say, MEDIUMBLOB. That it is limited to 16MB (not the 120MB that you are checking for). I don't know if MySQL can INSERT a blob bigger than that, in spite of having LONGBLOB which theoretically can hold 4GB. I hesitate because of various other limits in the encoding and transmission of the image from client to server.
I suspect that PNG files are bigger than the equivalent JPG. If space and download speed mater more than "lossy", consider converting PNGs to JPGs. Or even test the relative sizes when you initially acquire (Upload) each PNG.
If you will be storing images on your machine and serving from your machine, be aware of the web server's (Apache?) limitations on where things can be placed.
There are a bunch of questions of with the same title as this one.
For instance
How to output images using php?
Output as an image using PHP
How to output image and download using php
Invariably the answer is some variation of
add header('Content-type: image/jpeg'); to your code
Which is an important part of the answer, no doubt, but leaves out some vital steps I really cannot work out.
Now, there is obvious benefit to fetching an image using php when the image is situated below the root directory.
So suppose you have a web page
<?php
require_once("load_a_scripts.php");
print("lots of html");
// fetch image from below root directory and output in HTML
?>
<img id="this_one" src="" height="200" width="200" />
And you want to output the image this_one, above?
PHP can be used to fetch the required file using readfile(), but that will not be terribly useful here (at best you will get random unicode output instead of a proper image here).
The solution to prevent garbled output is to use
header('Content-type: image/jpeg');
This clearly seems inappropriate here. Not only is there output, which would make setting the header impossible, but even if this course of action is successful, the best that one can hope for is a download prompt for the image. Again, this is not desired functionality.
So some solutions suggest some external code, like "image.php" that will have its own header and will fetch the image, and so on. However, there's again some issues with this.
How will image.php know what what image it is you want?
<?php header('Content-Type:'.$photo);
if(isset($photo)&&isset($type)){
if(strlen($photo)>15||strlen($type)>6){
die();
}
$photo = strtolower($photo);
$photo = preg_replace('/[^a-z0-9 -]+/', '', $photo);
$photo = str_replace(' ', '-', $photo);
$photo = trim($photo, '-');
$type = strtolower($type);
$type = preg_replace('/[^a-z0-9 -]+/', '', $type);
$type = str_replace(' ', '-', $type);
$type = trim($type, '-');
readfile('../img/'.$user_id.$photo);
}
The parameters relating to the image name ($photo) and mime ($type) can hypothetically be sent using GET, but again, what sends these parameters, and how?
Some answers seemed to indicate that you could directly link to the external image.php as if it were an image
<img src="image.php" />
But this again raises the question about how image.php knows what the values for $photo and $type.
You have two basic options: first, using an external image-loader/handler script (e.g. <img src="image.php?i=sunshine.jpg" />); second, base64-encoding the image data (e.g. <img src="data:image/png;base64, i26dfdXAd..." />). The second option will make your HTML bloat like there's no tomorrow. So let's simply look at the image.php handler approach.
How does the handler know what image to show? It'll need a query string, e.g. image.php?i=sunshine.jpg; or image.php?i=sunshine&x=jpg; or image.php?i=sunshine&x=jpg&s=600, if you wanted to load a particular size, and so on. You will have to use that format in your HTML source, there's no script that would automagically know what image to load. Then, it's "who" (you), not "what", that sends the parameters. You'll want to make sure that the variables are properly sanitized (as your sample handler is doing); like any user-modifiable input, they shouldn't be trusted, especially anywhere near filesystem operations (directory traversal, etc.). These variables will be available as $_GET['i'], $_GET['x'], etc. to your handler script.
If you feel like URL parameters are a hassle, or just look dirty, you could always rewrite URLs. Link an image as <img src="images/sunshine.jpg" />, and have a .htaccess rewrite rule in place in the /images/ folder (containing only your script) that passes all image requests to your handler script. See the "htaccess redirect all images to handler" Q/A for an example. You could also use this approach for handling down-scaled image versions, with source URLs like <img src="images/sunshine__600.jpg" /> mapped to a rewrite rule.
On the use of readfile() (the most memory-friendly way of blurting out large chunks of data), as long as you output the header('Content-type: image/jpeg'); (or other appropriate MIME header) before your readfile() call, it will work in the desired way. That is to say, browser won't know the difference between images served directly from the filesys by the webserver, or images served from outside the webroot with a handler. It's just data with an image HTTP header.
Edit: Bonus. Coded a minimalist safe-to-deploy file-handler.
<?php
/*
* Receive image call as: <img src="img.php?i=name.jpg" />
* Output matching image file from $basepath directory
*/
$basepath = '../images/'; // Path to image folder
$mimes = [ // Allowed image types:
'jpg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'svg' => 'image/svg+xml',
];
!isset($_GET['i']) && die(); // Nothing to do here.
// Parse & Verify Extension
$ext = strtolower(pathinfo($_GET['i'], PATHINFO_EXTENSION));
!isset($mimes[$ext]) && die('Invalid filetype!'); // If MIME N/A: die!
// Parse & Sanitize Filename
$file = basename($_GET['i']);
$file = preg_replace('#[^[:alnum:] ._-]#', '', $file);
$filepath = realpath($basepath . $file);
$filepath === false && die('Invalid filename!'); // If image N/A: die!
// Output MIME header and image:
header('Content-Type:' . $mimes[$ext]);
readfile($filepath);
exit;
If you need to accommodate jpeg etc. variants, simply a) duplicate the MIME definitions in the $mimes array, or b) add an extension normalization routine. If you need to access images in subfolders, e.g. ?i=sun/shine.jpg, rework the filename parse/sanitize routine without basename. (Be sure you're safe from directory traversal!). Characters other than [:alnum:] ._-] are removed from the requested filename. Modify the regex as necessary.
I have upload one image and want to store it in base64 encoded format in database. for some images it is not working to store in database.
In my local system it is working for all images but on live server it not stores some of images in base64 format in mysql database . my code to store image in database is below,
$handle = $_FILES["file_name"]["tmp_name"];
$fileObj = $req->files->get('file_name');
$filename = $fileObj->getClientOriginalName();
$fileInfo = pathinfo($filename);
$fileExt = $fileInfo['extension'];
$file1 = $req->files->get('file_name');
$mime = $file1->getMimeType();
$fileName = base64_encode(file_get_contents($handle));
$File = new File();
$File->file_name = $fileName;
$File->save();
from above code if I chane below line then it is working
$fileName = (file_get_contents($handle));
but I want to store it in base64 encoded format in mysql database
in my data table this field's type is "long blob".
If you base64 the image, the column should be longtext. Blob are for binary.
But think again before storing files to database.
Storing image to database is a bad practice because whenever your app layer (in your case, php) retrieve the images, it will increase your memory usage and if you are retrieving list, your server can easily out of memory if multiple users are using the same function.
Storing data as base64 make it worse because the data size is bigger (8/6)
The best practice is to store the file in a file server and only the necessary meta or link in the database.
Storing image details instead saving a blob is better. You can store all images on another server or the same server in a folder and store the path , name of that image in mysql. To retrieve it you can simple get the file from the path stored in mysql.
I am trying to take a pic upload from a mobile device to a server. We are building with PhoneGap (Javascript), so we are having turn it into a string in order to send it to the server. I am having problems once I receive it, to turn it back into a readable image file.
Simply put, I need to take a string and a file name sent to me, decode it, convert it into a .png, then crop it into a circular image.
This is what I have going on currently
if (isset($_POST['file']))
{
//Result variable
$result = false;
$pic = base64_decode($_POST['file']);
$filename = $_POST['filename'];
if (strlen($pic) > 9 )
{
$fh = fopen("/var/www/pics/events/".$filename, 'w') or die("can't open file");
fwrite($fh, $pic);
fclose($fh);
}
}
I think I can get the rest of the code to work if I can figure out what I am doing wrong here that makes it not save properly as a image file? The file uploads correctly, but it stores with out an extension, and when I point to it in my browser, it comes up like it is supposed to be an image file, but never displays the image. That little broken picture icon with the colored shapes is what I get when I direct to it's location.
Do I need to be aware of what image type is being sent during this process at all? How is it knowing if it is a .gif, .jpg/jpeg, .png, etc...?
Thanks in advance for any help!
Nathan
For Security reasons you should sanitize the file name to prevent directory traversal.
On a brighter note, make sure the file is saved with the proper extension; if you are already saving with the correct extension you could have an encoding issue from the app.
If neither of the previous possibilities are the case make sure that your String Size does not exceed the maximum POST size limit in your php.ini; if that is the case increase the size limit.
After doing research, I found that it is more recommended to save the image name in database and the actual image in a file directory. Two of the few reasons is that it is more safer and the pictures load a lot quicker. But I don't really get the point of doing this procedure because every time I retrieve the pictures with the firebug tool i can find out the picture path in the file directory which can lead to potential breach.
Am I doing this correctly or it is not suppose to show the complete file directory path of the image?
PHP for saving image into database
$images = retrieve_images();
insert_images_into_database($images);
function retrieve_images()
{
$images = explode(',', $_GET['i']);
return $images;
}
function insert_images_into_database($images)
{
if(!$images) //There were no images to return
return false;
$pdo = get_database_connection();
foreach($images as $image)
{
$path = Configuration::getUploadUrlPath('medium', 'target');
$sql = "INSERT INTO `urlImage` (`image_name`) VALUES ( ? )";
$prepared = $pdo->prepare($sql);
$prepared->execute(array($image));
echo ('<div><img src="'. $path . $image . '" /></div>');
}
}
One method to achieve what you originally intended to do by storing images in database is still continue to serve image via a PHP script, thus:
Shielding your users from knowing the actual path of an image.
You can, and should have, images stored outside of your DocumentRoot, so that they are not able to be served by web server.
Here's one way you can achieve that through readfile():
<?php
// image.php
// Translating file_id to image path and filename
$path = getPathFromFileID($_GET['file_id']);
$image = getImageNameFromFileID($_GET['file_id']);
// Actual full path to the image file
// Hopefully outside of DocumentRoot
$file = $path.$image;
if (userHasPermission()) {
readfile($file);
}
else {
// Better if you are actually outputting an image instead of echoing text
// So that the MIME type remains compatible
echo "You do not have the permission to load the image";
}
exit;
You can then serve the image by using standard HTML:
<img src="image.php?file_id=XXXXX">
You can use .htaccess to protect your images.
See here:
http://michael.theirwinfamily.net/articles/csshtml/protecting-images-using-php-and-htaccess
I'm also working on a project which stores the url path of images on the database (Amazon RDS) and the actual images in a cloud managed file system in Amazon S3.
The decision to do so came primarily with the concern of price, scalability and ease of implementation.
Cheaper: Firstly, it is cheaper to store data in a file system (Amazon S3) compared to a database (Amazon EC2 / RDS).
Scalable: And since the repository of images may grow pretty big in the future, you might also need to ensure that you have the adequate capacity to serve them. On this point, it is easier to scale up a filesystem compared to a database. In fact, if you are using cloud storage (like Amazon S3), you don't even need to worry about having not enough space as it has been managed for you by Amazon! you would just need to pay for what you use.
Ease of Implementation: In terms of implementation, storing images in a file system is much easier. If you were to serve images directly from databases, you would probably need to implement additional logic to convert blob files into html src blob strings to serve images. And from the look of it, this might actually take up quite substantial processing power which might slow your web server down.
On the other hand, if you were to use a filesystem, all you would require is to put down the url path of the image from the database to the src attribute of the image and its all done!
Security: As for security of the images, i have changed the image name to a timestamp concatenated with a random string so that it will prove really difficult for someone to browse for pictures without knowing the file name.
ie. 1342772480UexbblEY7Xj3Q4VtZ.png
Hope this helps!
NB: Please edit my post if you find anything wrong here! this is just my opinion and everyone is welcome to edit!