1

I'm new to Joomla and PHP dev so bear with me.

Pulling some simple data after a quiz to draw a certificate image. I need users to click on a link and download that image.

Once again, I can get something working outside of Joomla but not within. I haven't even gotten to the dynamically created image yet and running into issues with just a static one, namely the file downloaded is invalid.

Here's one script I was able to get working outside of Joomla, using the template preview as an existing image:

<?php
header("Content-type: image/png");  
header('Content-Disposition: attachment; filename="template_preview.png"');  
readfile('template_preview.png');  

When downloaded the image is correct.

However, in my Joomla file:

<?php defined('_JEXEC') or die;
require_once("includes/variables_certificate.php"); 
header("Content-type: image/png");  
header("Content-Type: application/octet-stream");  
header('Content-Disposition: attachment; filename="template_preview.png"');  
$filename = JPATH_SITE.'/templates/'.$this->template.'/template_preview.png';  
readfile($filename);  

I get an invalid image. This isn't even the part where I'm pulling in the dynamic image yet :/

Any ideas?

The only other thread I could find from Joomla was here and not quite the same issue: Forcing file download in PHP - inside Joomla framework Also followed a bunch of examples in here: http://php.net/manual/en/function.header.php

Thanks all in advance!

#############################################

Partial Solution working for static image (thanks @Chris!), trying to get the dynamic image to work though

download.php:

<?php
require_once("includes/variables_certificate.php");
defined('_JEXEC') or die;
// $filename = JPATH_SITE.'/templates/'.$this->template.'/template_preview.png'; //works
$filename = JURI::root().'index.php?tmpl=certgenerator&quizmod='.$quizmod; //Not working

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="certificate.png"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
ob_clean();
flush();
readfile($filename);
exit;

and the certgenerator.php:

defined('_JEXEC') or die;
require_once("includes/variables_certificate.php");

$image_file = JPATH_SITE.'templates/'.$this->template.'/images/certificate_page.png'; 
$my_img = imagecreatefrompng ($image_file);
$font_size_big = 24;
$text_color = imagecolorallocate( $my_img, 0, 255, 0 );
$font_file = JPATH_SITE.'templates/'.$this->template.'/FelipaRegular.ttf';  

imagefttext( $my_img, $font_size_big, 0, 55, 75, $text_color, $font_file, "why u no work"); //if commented out image displays but not font obviously, as it's written now it returns a blank page
imagestring( $my_img, 4, 30, 25, "works", $text_color ); //works but doesn't include font

header( "Content-type: image/png" );
imagepng( $my_img );

imagecolordeallocate( $text_color );
imagedestroy( $my_img );
Community
  • 1
  • 1
Gisto
  • 887
  • 2
  • 16
  • 32
  • Check to see if the image exists by doing something like `error_log($filename)` and check the php error log or you can comment out the header calls and `echo` it. If the path to it exists. Otherwise see my answer. Also, you don't need a second content-type header – Chris McKnight Jul 28 '12 at 00:53

1 Answers1

2

Use output buffering and flush the file to the browser. Might also want to be sure that defined('_JEXEC') returns true.

<?php
require_once("includes/variables_certificate.php");
defined('_JEXEC') or die;
$filename = JPATH_SITE.'/templates/'.$this->template.'/template_preview.png';

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
ob_clean();
flush();
readfile($filename);
exit;
Chris McKnight
  • 8,540
  • 4
  • 29
  • 31
  • You rock! Any ideas on how to call a dynamic image? The link I was using for that was `JURI::root().'index.php?tmpl=certgenerator&mod='.$mod` but when I put that in for the filename it returns an empty image. It seems to prefer a local path vs an absolute one...but the image has to be generated through Joomla. Again, thank you so much! – Gisto Jul 28 '12 at 14:10
  • Sure. Whatever script you put the above code in just have an `img` tag to the web url of it. Let's say you call it `image.php` and the site is `http://example.com`. Then, `` would output the image. Try that but use ` – Chris McKnight Jul 28 '12 at 16:57
  • Sorry, not quite following :( So let's say your code above is on `download.php` and my script that creates the image is `certgenerator.php` What should `$filename=` ? I tried setting it to `$filename=JURI:base() . 'index.php?tmpl=certgenerator&mod='.$mod` but that returns a 0 byte file. (Or should I break this out to a new question?) Thank you!! – Gisto Jul 29 '12 at 13:20
  • (added an edit to make it clearer - if there's an easier way also very open to suggestions. Thank you!) – Gisto Jul 29 '12 at 13:48
  • Oh right you're flushing the image as a download to the browser. You could just pull out the first 4 header function calls and put a single one, header ('Content-type: image/png'); and you could use the image tag. Is that what you're wanting to do? – Chris McKnight Jul 29 '12 at 19:08
  • I think so and just tried that, didn't work but I might not be doing it right. I need the image created and downloaded with just one click. So when a user clicks a link for `http://example.com/index.php?tmpl=download&mod=5` the image is generated by `index.php?tmpl=certgenerator&mod=5`and then they're given that "Save As" prompt. (If there's an easy way to combine - great!) When I tried different values for $filename it seemed to fail on absolute links but worked with /paths/to/image. Not sure if that's causing the problem or not. Could using f(open) be a solution? – Gisto Jul 29 '12 at 20:52
  • Well readfile takes a file path on the server such as `/home/username/public_html/image.png`. An easy way to combine them into one would be make a POST request to the page and do a download or if it's a GET request just show the image. – Chris McKnight Jul 30 '12 at 00:20