Using GhostScript to create PDF files - Where do I start?

Hi guys,

I have been given the task of finding out how to convert verious documents to PDF using PHP. We have a PHP server ready and waiting and I was reading an article that showed me how to create a PDF from a PostScript file using GhostScript.

I have followed it through, however there was no information on howto actually install GhostScript and get it to work with PHP.

I have looked at the installation guide that is provided with Ghostscript, however this seems to just be an application and command line interpreter.

Can someone help me as I have no idea where to start. How do I install GS on our server so I can use PHP's exec() function to convert the PS file to PDF?

Just for completeness the article showed this code which is what I am using:

================================================================================================
<?php
// Turn on error reporting
error_reporting(E_ALL);

// Create a page with a message and abort the script (error reporting for the user)
function print_message($s)
{
      die('<html><body><h1>Warning!</h1>'.$s.'</body></html>');
}

// Check the file was uploaded
if(!count ($_FILES || $_FILES['infile']['error'] || strcmp($_FILES['infile']['type'], 'application/postscript')))
      {print_message('No file uploaded or ipload error!');}

// Try running the file through Ghostscript
exec('gs -sDEVICE=pdfwrite -r300 -sOutputFile='.$_FILES['infile']['tmp_name'].'.pdf -dNOPAUSE -dBATCH'.$_FILES['infile']['tmp_name'], $a, $n);

if($n)
      {print_message('Unable to convert file. Please ensure that you have used the proper format and try again.');}

// Output the headers to tell the browser what type of file is being outputted, how long it is and how we want it displayed
header('Content-Type: application/pdf');
header('Content-Disposition: filename="'.$_FILES['infile']['name'].'.pdf%20"');
header('Content-Length: '.filesize($_FILES['infile']['tmp_name'].'.pdf'));

// Dump the PDF file and delete it from the PHP folder
readfile($_FILES['infile']['tmp_name'].'pdf');
unlink($_FILES['infile']['tmp_name'].'pdf');
?>
================================================================================================

As you can see PHP's exec() function simply calls 'gs' to invoke the GhostScript application......HOW??!?!

Any help would be appreciated - please dont just provide links....I really need someone to explain how to do this.

Thanks,
MOZZER
LVL 1
nikez2k4Asked:
Who is Participating?
 
Richard QuadlingSenior Software DeveloperCommented:
....  -dBATCH'.$uploadFile, .....

No space between BATCH and the filename.
0
 
nikez2k4Author Commented:
Any ideas guys???

MOZ
0
 
Richard QuadlingSenior Software DeveloperCommented:
Ah.

Where is gs actually installed? exec is not going to use the PATH to locate the program for you.

So, if GS is in C:\Program Files\GhostScript\bin\gs.exe, then ...

exec('"C:/Program Files/GhostScript/bin/gs.exe" -sDEVICE=pdfwrite -r300 -sOutputFile='.$_FILES['infile']['tmp_name'].'.pdf -dNOPAUSE -dBATCH'.$_FILES['infile']['tmp_name'], $a, $n);



Can you ...

replace exec with echo and then exit on the next line. What are you trying to execute?
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
nikez2k4Author Commented:
Ahh i get ya - hold on i'll try that now :)

MOZ
0
 
Richard QuadlingSenior Software DeveloperCommented:
If the filenames have spaces in them this is going to be a REAL issue.

There is a bug in windows CMD that only allow 1 set of double quotes.

Nothing directly that PHP can do.

The solution is to build a .BAT file containing the complete statement with all the quotes and then use exec() to run that batch file.

That works fine.
0
 
nikez2k4Author Commented:
Hmmm - it seems to work....as it doesnt just send me a warning now.

However it just sits there and doesnt even time out - it's as if Ghostscript is waiting for something.

I can't find a gs.exe application in the version i downloaded (latest) - but there is a command line version....maybe that's the problem. Any ideas?

The exec() script i am using now is:

exec('"C:\Program Files\gs\gs8.54\bin\gswin32c.exe" -sDEVICE=pdfwrite -r300 -sOutputFile='.$_FILES['infile']['tmp_name'].'.pdf -dNOPAUSE -dBATCH'.$_FILES['infile']['tmp_name'], $a, $n);

MOZ
0
 
Richard QuadlingSenior Software DeveloperCommented:
Can you replace

exec( ..... );

with

echo ...;

to see what the actual command you are executing is.
0
 
Richard QuadlingSenior Software DeveloperCommented:
Remember to convert / to \\ for windows files. $_FILES will have / in them which is no good for the cli.

Personally, I would construct the command as a string and use ...

<?php
// just before your exec.
$s_command_line = <<<END_CLI
C:/Progra~1/gs/gs8.54/bin/gswin32c.exe -sDEVICE=pdfwrite -r300 -sOutputFile={$_FILES['infile']['tmp_name']}.pdf -dNOPAUSE -dBATCH {$_FILES['infile']['tmp_name']}
END_CLI;

echo "Before : $s_command_line\n";

$s_command_line = str_replace(array("\\", "/"), DIRECTORY_SEPARATOR, $s_command_line);

echo "After : $s_command_line\n";

exec($s_command_line, $a_results, $i_level);

echo 'Results : ' . var_export($a_results, True) . ' ' . $i_level;
?>
0
 
nikez2k4Author Commented:
I will have a go at that in a second mate - I just want to try somehting else first.

I have been messing around with the COM object for Microsoft Word and have managed to create a Word document and save it to a specified location.

What i would like to do is open a document using COM and print the file to a file (Postscript printer I have set up). I have written a macro that does this and it works perfectly, however it still asks for the filename. I have taken the VBA code from the macro so maybe I could convert the process into PHP and use COM to print the document to create a Postscript file?

Here is the code:

****************************************************************************************
Sub PrintPostscript()
'
' PrintPostscript Macro
' Macro recorded 21/07/2006 by MARSHALL
'
    Application.PrintOut FileName:="", Range:=wdPrintAllDocument, Item:= _
        wdPrintDocumentContent, Copies:=1, Pages:="", PageType:=wdPrintAllPages, _
        ManualDuplexPrint:=False, Collate:=True, Background:=True, PrintToFile:= _
        False, PrintZoomColumn:=0, PrintZoomRow:=0, PrintZoomPaperWidth:=0, _
        PrintZoomPaperHeight:=0
End Sub
****************************************************************************************

Any ideas?

MOZZER
0
 
Richard QuadlingSenior Software DeveloperCommented:
// Print it
$word->PrintOut();

All the parameters are defaulted and this works on my version 11.0
0
 
nikez2k4Author Commented:
Ok mate....found a couple of parameters and have come up with this code:

********************************************************************************
<?php
error_reporting(E_ALL);

// starting word
$word = new COM("word.application") or die("Unable to instantiate Word");
echo "Loaded Word, version {$word->Version}\n";

//bring it to front
$word->Visible = true;

$word->ActivePrinter = "\\\\resources\\Resources";

//open an empty document
$word->Documents->Add();

//do some weird stuff
$word->Selection->TypeText("This is a test...");
$word->Documents[1]->SaveAs("D:\inetpub\wwwroot\school\pdf\output\document.doc");


$word->ActiveDocument->PrintOut();

//closing word
//$word->Quit();

//free the object
//$word = null;
?>
********************************************************************************

This opens word on the server and saves the document and sends it to print on the Resources network printer. This is the Postscript printer setup to generate the PS file.

It gets to the save screen and stops (logically) to ask for a filename and location. Is there any way I can automate this so I can tell Word where I want the file saving and what to call it?

Thanks,
MOZZER
0
 
Richard QuadlingSenior Software DeveloperCommented:
When you recorded the process, did you have to enter the details?

If they are NOT saved in the macro, then Word is NOT asking for them, but an external library.

Personally, I would NOT use word like this. Imagine 20 users all at the same time - 20 instances of word! EEEK!
0
 
Richard QuadlingSenior Software DeveloperCommented:
Let's try and get the GS working as I think this is the route you really want.
0
 
nikez2k4Author Commented:
Hey,

Ok back to GS - sorry just wanted to see if i could do it with COM.....worth a try :)

I have used the code you mentioned to output what is happening and this is what it printed:

******************************************************************************************************
Before : C:/Progra~1/gs/gs8.54/bin/gswin32c.exe -sDEVICE=pdfwrite -r300 -sOutputFile=C:\PHP\uploadtemp\phpEC5D.tmp.pdf -dNOPAUSE -dBATCH C:\PHP\uploadtemp\phpEC5D.tmp

After : C:\Progra~1\gs\gs8.54\bin\gswin32c.exe -sDEVICE=pdfwrite -r300 -sOutputFile=C:\PHP\uploadtemp\phpEC5D.tmp.pdf -dNOPAUSE -dBATCH C:\PHP\uploadtemp\phpEC5D.tmp

Results : array ( 0 => 'AFPL Ghostscript 8.54 (2006-05-17)', 1 => 'Copyright (C) 2005 artofcode LLC, Benicia, CA. All rights reserved.', 2 => 'This software comes with NO WARRANTY: see the file PUBLIC for details.', 3 => 'Loading NimbusMonL-Regu font from C:\\Program Files\\gs\\fonts/n022003l.pfb... 2573384 1100442 1915728 616670 1 done.', 4 => '%%[ ProductName: AFPL Ghostscript ]%%', 5 => '%%[Page: 1]%%', 6 => '%%[LastPage]%%', ) 0
******************************************************************************************************

I am presuming that the results showing "'AFPL Ghostscript 8.54 (2006-05-17)" means that it is at least connecting to the GS program?

Does this all look ok?
MOZZER
0
 
Richard QuadlingSenior Software DeveloperCommented:
Now run the "after" command at the command prompt.




0
 
Richard QuadlingSenior Software DeveloperCommented:
ARGH!! You dozy bugger.

You cannot access the tmp files as they are for PHP's use.

Use move_uploaded_file() to move the file from the temp are to somewhere else and use that file in the command_line.
0
 
nikez2k4Author Commented:
Hmmmm ok sort of a restult :)

I have managed to get the code working and its created the PDF file :)

Bad news? Its a 0 byte file and the submission page still times out. Here is the code:

***********************************************************************************************
<?php
// Turn on error reporting
error_reporting(E_ALL);

// Create a page with a message and abort the script (error reporting for the user)
function print_message($s)
      {die('<html><body><h1>Warning!</h1>'.$s.'</body></html>');}

// Check the file was uploaded
if(!count ($_FILES || $_FILES['infile']['error'] || strcmp($_FILES['infile']['type'], 'application/postscript')))
      {print_message('No file uploaded or ipload error!');}

// Set the location for the uploaded file
$uploadDir      = 'D:\inetpub\wwwroot\school\pdf\output\\';
$uploadFile      = $uploadDir.basename($_FILES['infile']['name']);

if(!move_uploaded_file($_FILES['infile']['tmp_name'], $uploadFile))
      {print_message('Unable to move temporary file!');}

// Try running the file through Ghostscript
exec('"C:\Program Files\gs\gs8.54\bin\gswin32c.exe" -sDEVICE=pdfwrite -r300 -sOutputFile='.$uploadFile.'.pdf -dNOPAUSE -dBATCH'.$uploadFile, $a, $n);

if($n)
      {print_message('Unable to convert file. Please ensure that you have used the proper format and try again.');}

// Output the headers to tell the browser what type of file is being outputted, how long it is and how we want it displayed
header('Content-Type: application/pdf');
header('Content-Disposition: filename="'.$_FILES['infile']['name'].'.pdf%20"');
header('Content-Length: '.filesize($_FILES['infile']['tmp_name'].'.pdf'));

// Dump the PDF file and delete it from the PHP folder
readfile($_FILES['infile']['tmp_name'].'pdf');
unlink($_FILES['infile']['tmp_name'].'pdf');
?>
***********************************************************************************************

It's as if it is either waiting for something or its crashed.....any ideas?

MOZZER
0
 
nikez2k4Author Commented:
Sorry forgot about the bottom $_FILES variables......have replaced them all with $uploadDir and it does exactly the same thing.

MOZ
0
 
nikez2k4Author Commented:
God damn it....

Ok I am very embarassed to say that I have fixed the problem....it was a spacing problem - however I am going to blame it on the guide i followed as it doesnt clearly show a space lol.....

Here is the final code to create a PDF from a PostScript file:

****************************************************************************************
<?php
// Turn on error reporting
error_reporting(E_ALL);

// Create a page with a message and abort the script (error reporting for the user)
function print_message($s)
      {die('<html><body><h1>Warning!</h1>'.$s.'</body></html>');}

// Check the file was uploaded
if(!count ($_FILES || $_FILES['infile']['error'] || strcmp($_FILES['infile']['type'], 'application/postscript')))
      {print_message('No file uploaded or ipload error!');}

// Set the location for the uploaded file
$uploadDir      = 'D:\inetpub\wwwroot\school\pdf\output\\';
$uploadFile      = $uploadDir.basename($_FILES['infile']['name']);

if(!move_uploaded_file($_FILES['infile']['tmp_name'], $uploadFile))
      {print_message('Unable to move temporary file!');}

// Try running the file through Ghostscript
exec('"C:\Program Files\gs\gs8.54\bin\gswin32c.exe" -sDEVICE=pdfwrite -r300 -sOutputFile='.$uploadFile.'.pdf -dNOPAUSE -dBATCH '.$uploadFile, $a, $n);

if($n)
      {print_message('Unable to convert file. Please ensure that you have used the proper format and try again.');}

// Comment out the lines below if you want the PDF file to be saved, otherwise it will display the PDF in the browser

// Output the headers to tell the browser what type of file is being outputted, how long it is and how we want it displayed
header('Content-Type: application/pdf');
header('Content-Disposition: filename="'.$uploadFile.'.pdf%20"');
header('Content-Length: '.filesize($uploadFile.'.pdf'));

// Dump the PDF file and delete it from the PHP folder
readfile($uploadFile.'.pdf');
unlink($uploadFile.'.pdf');
?>
****************************************************************************************

Cheers for helpin mate!
MOZZER
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.