Increasing security on imageUpload, issues with img src="image.php" - php

Cant seem to get the php script to execute and fetch the image script, the image placeholder.jpg is sored outside of the public_html webroot, here is what i do
Show image .php file
<img src="image.php?image=<?php echo urlencode('placeholder.jpg') ?>"/>
image.php
<?php
$file = basename(urldecode($_GET['image']));
$fileDir = '/noaccess/avatars/';
if (file_exists($fileDir . $file))
{
$contents = file_get_contents($fileDir . $file);
header('Content-type: image/jpg');
echo $contents;
}
?>

It is EXTREMELY unsecured to run that kind of script, because you are giving hackers access to your file system remember they can use ../ to navigate up the folders,
but anyway try this:
<?php
$file = basename(urldecode($_GET['image']));
$fileDir = $_SERVER['DOCUMENT_ROOT'] . 'noaccess/avatars/';
if (file_exists($fileDir . $file))
{
$imageRes = imagecreatefromjpeg($fileDir . $file);
header('Content-Type: image/jpeg');
// Output the image
#imagepng($imageRes);
// Free up memory
#imagedestroy($imageRes);
die();
}
?>

Related

SVG from PHP script is not working in img src

I'm trying to open SVG file first in PHP and then return this data:
$file = dirname(__FILE__) . $_GET["file"] . ".svg";
if (!file_exists($file)) {
$file = dirname(__FILE__) . $_GET["file"] . ".png";
if (!file_exists($file)) {
throw new NotFoundHttpException();
} else
header('Content-Type: image/png');
} else
header('Content-Type: image/svg+xml');
$content = file_get_contents($file);
return $content;
And in HTML:
<img src="script.php?file=someimage">
Problem is that its not showing SVG images in the tag. It works, if I set script.php?file=someimage to the URL string of my browser, but not inside the tag. PNG works fine. If i set just
<img src="someimage.svg">
it also works perfect.
embed and object tags works, but I need img.
UPDATE:
The problem was in Yii2, I send headers wrong way. In some reason it works for PNG, but not for SVG.
It should be done like that:
Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
Yii::$app->response->headers->add('Content-Type', 'image/svg+xml');
Looks like you forgot the /. Try replacing these lines where appropriate:
$file = dirname(__FILE__) . '/' . $_GET["file"] . ".svg";
// ...
$file = dirname(__FILE__) '/' . $_GET["file"] . ".png";
dirname() gives back a string without a trailing slash, so it was trying to open /path/to/scriptdirsomefile.svg.
Security
Also, I noticed that your script can be made to do bad things, such as exposing arbitrary files on the server. You can prevent a lot of exploits by doing some basic sanitizing of $_GET['file'] before starting:
$_GET['file'] = preg_replace('#/#', '_', $_GET['file']);
Change return $content; to echo $content;
So if the image files are on the same directory, it will be:
<?php
$file = $_GET["file"] . ".svg";
if (!file_exists($file)) {
$file = $_GET["file"] . ".png";
if (!file_exists($file)) {
throw new NotFoundHttpException();
} else
header('Content-Type: image/png');
} else
header('Content-Type: image/svg+xml');
$content = file_get_contents($file);
echo $content;
?>
Working example #1 (showing svg):
http://www.createchhk.com/SOanswers/subc/index.php
Working example #2 (showing png):
http://www.createchhk.com/SOanswers/subc/index2.php

After download rename source file in php

I loop .jpg file from my uploads/document and show it in my page and then i click to download one by one file and after I download .jpg from source in folder uploads\document\ the real file from my folder will be rename to other name.
I try these:
<?php
foreach (glob('uploads/document/' . '/*.{jpg}', GLOB_BRACE) as $file) {
echo '<a class="snapchat" download="' . basename($file) . '" href="/uploads/document' . '/' . basename($file) . '">' . basename($file) .
'</a><br/>';
rename('/uploads/document' . '/' . basename($file) ,'Mynew' );
}
?>
Any solution for these?
First : you cannot rename the source file before download , so you need to rename it after download
You can do that by PHP header() Function all you need is another php script to handle the download and rename the file,
Like :
1- Main PHP
<?php
$dir = 'files/';//uploads/document/
foreach (glob("$dir*.{jpg}", GLOB_BRACE) as $file) {
echo '<a class="snapchat" download="'.basename($file).'" href="download.php?fn='.basename($file).'">'.basename($file).'</a><br/>';
}
?>
2 - download.php
<?php
$dir = 'files/';//uploads/document/
$file = $dir.$_GET['fn'];
if (file_exists($file))
{
$type = 'image/jpeg';
header('Content-Type:'.$type);
header('Content-Length: ' . filesize($file));
readfile($file);
rename($file, $dir."mynewName");
exit();
}
else // file not exists Or has been downloaded before
{
header('HTTP/1.0 403 Forbidden');/* Retern Forbidden */
/*OR*/
//header("Location: 404.php?".$file); /* Redirect browser */
exit();
}
?>

PHP: search in other directories if image is exist and print the image

ok I edited my answer i found out how to find the file in the directories but my problem is it won't print the image. here's my code.
<?php
$file = 'testimage.png';
$dir = array(
$_SERVER['DOCUMENT_ROOT'] . "/folderA/",
$_SERVER['DOCUMENT_ROOT'] . "/folderB/"
);
foreach($dir as $d)
{
if(file_exists( $d . $file ))
{
$file = $file;
}
}
$imgPng = imageCreateFromPng($file);
header("Content-type: image/png");
imagePng($imgPng);
?>
why is not printing the image?
One way to do this without adding a bunch of code would be to set up the include_path to look in the image folders, either by modifying include_path in php.ini, or modifying it in the script:
ini_set('include_path', '/new/include/path');
Then use the "use_include_path" option in fopen.
Since you're looking across all the php folders, be sure to sanity check the image file name.
The problem may be because $imgPng = imageCreateFromPng($file); cannot find the file. You need to specify the path to your image $d. $file. Check the comments in code below.
<?php
$file = 'testimage.png';
$dir = array($_SERVER['DOCUMENT_ROOT'] . "/folderA/", $_SERVER['DOCUMENT_ROOT'] . "/folderB/");
foreach ($dir as $d) {
if (file_exists($d . $file)) {
$file = $file;
//i don't know the purpose of this but i think you want to do $file = $d . $file
}
}
//$imgPng = imageCreateFromPng($file); //can't find the image, should be
$imgPng = imageCreateFromPng($d . $file);
header("Content-type: image/png");
imagePng($imgPng);
?>
<?php
$file = 'testimage.png';
$dir = [
$_SERVER['DOCUMENT_ROOT'] . "/pathA/",
$_SERVER['DOCUMENT_ROOT'] . "/pathB/"];
foreach( $dir as $d )
{
if( file_exists( $d . $file ))
{
//set image if found in the directories
$image = $d . $file;
}
else
{
//is not found in directories
$image = null;
}
}
$img = imagecreatefrompng($image);
header("Content-type: image/png");
imagepng($img);
imagedestroy();
?>

Serving documents outside the web root folder.

I have a function called "viewDoc" which is supposed to go to a folder outside the web root and fetch a file for me. It seams to work ok with images (Jpgs etc) but with PDF's it just outputs a blank gray page as demonstrated here - http://www.tutorplanner.com/userimage/viewdoc/12787622467.pdf
Can anyone see what I'm doing wrong as I've been scratching my head over this for a day!
public function viewDoc($doc) {
$path_parts = pathinfo($_SERVER['REQUEST_URI']);
$file = $doc;
$fileDir = '/var/uploads/';
if (file_exists($fileDir . $file))
{
$contents = file_get_contents($fileDir . $file);
//print_r($contents);
header('Content-Type: ' . mime_content_type($fileDir . $file));
header('Content-Length: ' . filesize($fileDir . $file));
readfile($contents);
}
}
readfile is used with the parameter of a file name - NOT text.
Two examples that would work (file_get_contents):
public function viewDoc($doc) {
$path_parts = pathinfo($_SERVER['REQUEST_URI']);
$file = $doc;
$fileDir = '/var/uploads/';
$filePath = $fileDir . $file;
if (file_exists($filePath))
{
$contents = file_get_contents($filePath);
header('Content-Type: ' . mime_content_type($filePath));
header('Content-Length: ' . filesize($filePath));
echo $contents;
}
}
or (readfile):
public function viewDoc($doc) {
$path_parts = pathinfo($_SERVER['REQUEST_URI']);
$file = $doc;
$fileDir = '/var/uploads/';
$filePath = $fileDir . $file;
if (file_exists($filePath))
{
header('Content-Type: ' . mime_content_type($filePath));
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
}
}
I also added the $filePath variable for you, as there's no reason to concat the string multiple times.
Edit
As extra security, to Yazmat's comment, you can use $file = str_replace(array('..', '/'), '', $doc); as this would remove all references to other directories (however, with the slash it would also remove access to sub directories, so you might want to skip that, dependend on your code and file structure).
You have a great security issue here, anyone can access anything on your server with the function you wrote. I realy advise you to not use it and just put your files (that should be accessible) on a public web directory.

Keeping some files private

I was trying to create a directory of private files that could only be accessed when a user logs in. To do this, I used a folder outside the web directory, and then php to access it, if allowed.
Here's an example:
function display_movie($file){
printf("`<video id='movie' width='960' height='416' controls='controls' onerror='fix()'>`<br/>
`<source src='movie.php?file=%s' type='video/ogg; codecs=\"theora, vorbis\"'>
</video>", rawurlencode($file)`);
}
This works great for images, but breaks the media player. Also, I've only tested this locally on a Linux machine.
Any ideas? Thanks.
This is in movie.php...
if(file_exists($fileDir . md5($file) . $ext)) {
$contents = file_get_contents($fileDir . md5($file) . $ext);
}
header('Content-type: video/ogg');
echo $contents;
What is with the <br /> in you're movie.php ?
Did you tryed to see if movie.php echoes the file contents ? ( view source on you're page , then copy the movie source src "movie.php?file=..." and paste it in you're browser , see if it get's the movie out ) .
Allso you need to move the header and echo inside the if statement , if that file doens't exist you can echo a different standard movie :
if(file_exists($fileDir . md5($file) . $ext)) {
$contents = file_get_contents($fileDir . md5($file) . $ext);
} else {
$contents = file_get_contents($fileDir . md5(MOVIE_NOT_FOUND));
}
header('Content-type: video/ogg');
echo $contents;
Where MOVIE_NOT_FOUND is a constant, movie you whant to display if the requested one is not found .
One other thing you could do is enter you're full uri to the movie php in you're source src ( like "http://localhost/some/uri/movie.php?file=..."
From where do you get $fileDir , $file and $ext in you're movie.php ?
Edit: should take care of the file_get_contents problem you have
$file = $fileDir . md5($file) . $ext;
header('Content-type: video/ogg');
//set aditional headers you may whant here
ob_clean();
flush();
if( file_exists($file) )
{
readfile($file);
} else {
readfile($fileDir . md5(MOVIE_NOT_FOUND));
}
exit;

Categories