SVG from PHP script is not working in img src - php

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

Related

PHP get image from server

I am trying to display an image from a PHP server.
Here it is my function:
function get_file($path) {
$fileToGet = $GLOBALS['homedir'].$path;
//echo $fileToGet.PHP_EOL;
if (file_exists($fileToGet)) {
//echo 'file exists';
header('Content-Type: image/png');
header('Content-Length: '.filesize($fileToGet));
echo file_get_contents($file);
}
}
I am using the browser or postman and the image is invalid.
What I am missing?
I edited a little bit your function:
function get_file( $path ){
$fileToGet = $GLOBALS['homedir'];
if( substr( $fileToGet, -1) != '/' ){
// add trailing slash if needed
$fileToGet .= '/';
}
$fileToGet .= $path;
if (file_exists($fileToGet)) {
header('Content-Type: image/png');
header('Content-Length: '.filesize($fileToGet));
echo file_get_contents($fileToGet);
}
}
Just a security hint: if $path comes from the user there may be a problem because he will be able to access to some other file.
Think about this code:
get_file( $_GET['path'] );
then the user can call this url
yoursite/yourpage.php?path=../../../mypreciousimage.png
You're not outputting the contents of the file you're reading:
file_get_contents($file);
You'll need to echo it:
echo file_get_contents($file);
Or:
readfile($file);
You'll probably also want to add exit; to the end of that function, to ensure that no other code runs and that no other output gets sent.
Try
print file_get_contents($file);
Instead of
file_get_contents($file);

After downloading file, it is corrupted

I'm currently making a controller to download files from the server.
It all happens in the index action:
public function indexAction() {
$schuurName = $this->_getParam('storageID');
$fileName = $this->_getParam('fileName');
$name = explode('.', $fileName)[0];
$path = '..' . DIRECTORY_SEPARATOR . 'schuren' . DIRECTORY_SEPARATOR . $schuurName . DIRECTORY_SEPARATOR . $fileName;
if (file_exists($path)) {
$mimeType = mime_content_type($fileName);
header('Content-Type: ' . $mimeType);
header('Content-Length: ' . filesize($path));
header('Content-Disposition: attachment; filename=' . $name . ';');
$resource = fopen($path, 'r');
while (!feof($resource)) {
$chunk = fread($resource, 4096);
echo $chunk;
}
$this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
}
else {
echo 'file doesn\'t exist';
}
}
So the downloading works right now, I'm testing it with an image of 725 bytes. The problem is.. The image is corrupted so it couldn't be seen/edited. What am I doing wrong in my code?
Thanks!
You should use binary mode. Use the 'rb' flag.
From the php Manual : If you do not specify the 'b' flag when working with binary files, you may experience strange problems with your data, including broken image files and strange problems with \r\n characters.
http://www.php.net/manual/en/function.fopen.php

Increasing security on imageUpload, issues with img src="image.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();
}
?>

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