Link to home
Start Free TrialLog in
Avatar of nikez2k4
nikez2k4Flag for United Kingdom of Great Britain and Northern Ireland

asked on

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
Avatar of nikez2k4
nikez2k4
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

Any ideas guys???

MOZ
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?
Ahh i get ya - hold on i'll try that now :)

MOZ
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.
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
Can you replace

exec( ..... );

with

echo ...;

to see what the actual command you are executing is.
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;
?>
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
// Print it
$word->PrintOut();

All the parameters are defaulted and this works on my version 11.0
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
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!
Let's try and get the GS working as I think this is the route you really want.
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
Now run the "after" command at the command prompt.




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.
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
Sorry forgot about the bottom $_FILES variables......have replaced them all with $uploadDir and it does exactly the same thing.

MOZ
ASKER CERTIFIED SOLUTION
Avatar of Richard Quadling
Richard Quadling
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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