View images in browser with no extension - php

I have a directory in my web app where I want to keep all the user profile pictures. Users can upload all types of images (png, jpg, gif). However, I want the image URL to be friendly, eg. http://example.com/static/picture/300-username, where the file is 300-username, but with no extension. I thought of removing the extension when the user uploads, and with a PHP controller, add a:
header('Content-Type: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png');
readfile('http://example.com/static/picture/300-username');
This has worked well. I was wondering however, if this can be done by placing an .htaccess file in the picture directory, with some sort of Header, that whatever file is read in this directory, will display as picture. Is this possible?

Don’t remove the extension, just offer extensionless URIs like /static/picture/300-username. Then add a line to your .htaccess:
Options +MultiViews
Apache will set the correct content type for you. See the documentation for Content Negotiation.

You can't specify multiple Content-Type like that.. You need to pass the correct header for each image served:
<?php
$user = '300-username';
$picture = 'http://example.com/static/picture/' . $user;
$info = getimagesize($picture);
$fp = fopen($picture, "rb");
if ($info && $fp) {
header("Content-type: {$info['mime']}");
fpassthru($fp);
exit;
} else {
// error
}
?>
(Code adapted from PHP's getimagesize() documentation.)

First your path need to be physically existent, else I don't think Apache can do anything for you.
However, here may be a workaround using a RewriteRule, keep the extension (by the way, I think it's bad practice to remove extension of a file, especially when they are not plain text files), and accept a requested file like 300-username to rewrite to 300-username.jpg.

Related

PHP file uploading security

I use file extension for validate uploading file like word excel pdf etc.?
But if user change their file extension then they can upload any file they want.
I want to function that check type of file if user change their file extension after that they should not be able to upload file.
Can any one help
You should also check the mimetypes, for example:
$allowedMimes = array('image/gif', 'image/jpeg', 'image/jpg', 'image/png', 'image/bmp', 'image/wbmp');
//getting the mime type (it can be different from the extension) Be careful!
$imgInfo = getimagesize(imagePath);
$type = strtolower($imgInfo['mime']);
//hey dude!! This is a fake image!!
if(!in_array($type, $allowedMimes)){
//We delete it!!
unlink(imagePath);
}else{
//do whatever with the image...
}
You can find more info about mime types here.
To be safe
Move all the files regardless of type out of the webroot.
Dont allow direct access to the file, use a loader to send the file
to the user if you have a download feature.
Force the download
Have a script, download.php or whatever, get the file's ID, verify who is logged in, and if everything checks out, fetch the file, read it out to the browser, and send the appropriate download headers.
header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename=file.ext');
header("Content-Length: " . filesize('../not_in_web_root/file.ext'));
header("Content-Transfer-Encoding: binary");
readfile('../not_in_web_root/file.ext');
exit;
Only accept files you want to accept by checking the extension and mimetype where possible. Its
even ok to even accept php as long as you dont allow it to execute or give user direct access to it.
If your only allowing images then use a function like getimagesize(), if it has a size its an image, but still dont allow direct access to it as PHP maybe embedded into it.
If you offer a filesystem feature to your users, make it a virtual one, based on values within a database not access to the real files.
You could possibly look at the mime type of the file? http://us2.php.net/manual/en/fileinfo.constants.php

Moving images from doc root for added security

My site uses bookmarklets to gather data from external sites, kinda like Pinterest. I'm concerned about security and want to move the images the bookmarklet gathers from the doc root up one level. My script has some hefty security checks in place, but I want to add this as a last line of defense.
How do I access my images within my script? Obviously using ../userimages/id/image.jpg wont work. I'm using Apache.
Thanks!
Proxy the image
You would use a proxy script to feed the images through like the following example:
// open the file in a binary mode
$name = '../userimages/id/image.jpg';
$fp = fopen($name, 'rb');
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
// you may like to set some cache headers here
// dump the picture and stop the script
fpassthru($fp);
exit;
This example is from the PHP manuals fpassthru() page. You would save this script somewhere in your servers document root/httpdocs folder.
"Spoofing" the URL to the image
The easiest way to give the PHP file the appearance of being an image file to a user/browser is to use Apaches mod_rewrite. Usually I use a URL structure something like this:
http://www.example.org/image-id/image.png
Where image-id is the unique identifier for that particular image. This way the file has the correct extensions of an image instead of .php.

Dynamically renaming jpeg files as they're being displayed to users

I'm trying to dynamically rename a jpeg image file as it's displayed to the user.
I have a file image_generate.php with the following code:
$file = $_GET['file'];
$imagepath = "path/to/image.jpg";
$image = imagecreatefromjpeg($imagepath);
header('Content-Type: image/jpeg');
$filename = "[site.com]_some_image_name_here";
header('Content-Disposition: attachment; filename="' . $filename . '.jpg"');
imagejpeg($image, NULL, 100);
imagedestroy($image); // Free up memory
And it's called by an html image tag like so:
<img src="image_generate.php?file=imagenamehere" />
So far, the output has the following results:
When I right-click on the image, and click "View Image," a download dialogue pops up and asks if I'd like to save the file "[site.com]_some_image_name_here.jpg" (I want this to happen)
If I right-click on the image, and click "Save Image As," or "Save Image," the filename that's to be saved shows up as the original filename (whatever the variable $file was able to fetch).
How can I fix the second part? I'd like to modify the filename of the image even when the user clicks "Save Image As" or "Save Image."
I DID try to change the code to this:
...
$rename = $filename . ".jpg";
imagejpeg($image, $rename, 100);
imagedestroy($image); // Free up memory
But the image fails to show up on the page with the html tag (shows up as a broken image).
I'm not very familiar with html headers and Content-Dispositions. I'm guessing there's an error in there somewhere..?
Any ideas?
Thank you for reading!
Edit: .htaccess below
<IfModule mod_rewrite.c>
RewriteEngine On
# Sends image download request to image_generate.php for parsing
RewriteRule ^path/from/img/tag/downloads/(.*).jpg$ path/to/image_generate.php?file=$1 [NC,L]
RewriteRule ^path/to/image_generate.php$ /home/path/to/image_generate.php [NC,L]
</IfModule>
Different browsers will have different behaviors.
For example, Internet Explorer doesn't try to fetch any header information before displaying the save file dialog when doing a Right Click > Save Image As (It automatically assumes you want to save the result of the request, regardless of what the result is). Neither does Firefox. Therefore, for IE & Firefox, it will be impossible to specify the filename by specifying it in the headers.
A more elegant and UA-compatible way of doing this would be by using Apache's mod_rewrite to do URL rewriting. URL rewriting allows you to reroute a request made to a URL towards another.
To set this up, you need to create a .htaccess file in the directory where image_generate.php is located containing the following:
RewriteEngine On
RewriteRule ^generated/([a-z0-9-]+)\.jpg$ generated_image.php?file=$1 [L]
Then, simply modify your HTML to point to your rewritten URL.
<img src="generated/imagenamehere.jpg" />
This also have the advantage of making your image generation completely seamless to the user (URL wise, it looks simply like a static image).
More information about mod_rewrite can be found here:
mod_rewrite - Apache HTTP Server
mod_rewrite Cheat Sheet (V2) - Added Bytes by Dave Child

Is directly linking to an image okay for images uploaded to the server with a custom PHP script?

For an image file (JPEG) that has been uploaded to the server via a PHP script (to a directory such as http://www.somedomain.com/images, is it a good idea to allow the client to get the image's direct address (such as http://www.somedomain.com/images/someimage.jpg and paste it into a WYWSIWYG text editor (such as TinyMCE)?
I am wondering if there is a preferable method where the direct address is encrypted?
Please, if I should just link directly to the image, just say so.
Thanks!
Note: I have modified this question from my original. Please see revisions if you are curious, but I think I was asking the question incorrectly. My apologies to the people who already answered.
As long as you check correctly WHAT is being uploaded, it shouldn't be a problem. So please at least use getimagesize or a similar function to make sure it's an image that's being uploaded, AND make sure the extension on the file is correct so that it will never be run through the PHP interpreter - to prevent someone from uploading an image with a PHP script attached.
BTW Here's a nice whitepaper on uploads and security : http://www.scanit.be/uploads/php-file-upload.pdf
Depending on the CPU Constraints of your web-hosting service you can write a service to 'serve' the images to your users.
Here is some very BASIC code, it needs spiffing up and cleaning up for XSS/etc...
<?php
$basePath = "/path/to/my/image/store/not/web/accessible/";
$file = NULL;
if (isset($_GET['file']))
$file = $_GET['file'];
if ($file != NULL)
{
$path = $basePath . $file;
// $file needs to be checked for people
// trying to hack you, but for the sake of simplicity
// i've left it out
$mime = mime_content_type($path);
$size = filesize($path);
header("Content-Length: " . $size);
header("Content-Type: " . $mime);
header('Expires: 0');
readfile($path); // Outputs the file to the output buffer
}
?>
Obviously you can put whatever security checks in here you want. But this way your files are below the web dir, and you can apply logic to thier accesibility. This is typically used more for FILE vs. Images, but you can do the same thing here.
Images Accessed like this
http://www.mysite.com/image.php?file=hello.jpg
And you can use mod_rewrite to rewrite urls like this:
`http://www.mysite.com/images/hello.jpg
Into the first url.
I Cannot stress enough the need for further security checking in the above example, it was intended to show you how to serve a file to the user using PHP. Please don't copy & use this verbatim.
Wordpress uses direct links for images. The permalink function simply puts the image on a page along with metadata for comments, but the images' SRC attributes still link directly to the image.
why are you concerned about revealing your image location. Hotlinking?
if so you can prevent hotlinking with htaccess
http://altlab.com/htaccess_tutorial.html
Didn't you get your answer already?
Every site reveals image location to the browser. It's just the way web works.
Got any reason to "encrypt" original location?

HTTP headers for jpg files after mod_rewrite

I'm using Apache's mod_rewrite to route requests for JPG files to a directory outside my web root.
It generally has been fine, but there are a few images that do not display. I then realized that when I use PHP's get_headers() function on my image URLs, they are all returning
Content-Type: text/html; charset=UTF-8 instead of the proper image/jpeg header types.
I have tried explicitly setting the Content-Type: image/jpeg header and still, none of my images return the correct headers - although most do display correctly, but I'm not sure why.
How can I assure a JPG file is sent with the correct header when redirecting via mod_rewrite?
This is what you could do. Create a PHP file that will get the right file and passes it through
<?php
$sImage = 'imagename.jpg';
header("Content-Type: image/jpeg");
header("Content-Length: " .(string)(filesize($sImage)) );
echo file_get_contents($sImage);
or
<?php
$sImage = 'imagename.jpg';
$rFP = fopen($sImage, 'rb');
header("Content-Type: image/jpeg");
header("Content-Length: " .(string)(filesize($sImage)) );
fpassthru($rFP);
exit;
or in your Apache vhost config or .htaccess file
RewriteRule … … [T=image/jpeg]
You can also set the Content-Type header field with mod_rewrite with the T flag:
RewriteRule … … [T=image/jpeg]
How about image which is not.jpg. Like .gif, ...
You'll need to use mime_content_type() (which is deprecated) or the fileinfo extension to determine which content-type to send.
Edit: I don't recommend this, but if you are working with a specific subset of file extensions, you could also create a small dictionary array of content-types and use the file extension to determine which one to send.

Categories