Forum How do I...?

Calling Prince from PHP - Can not make anything work

jimbrooking
Trying to call Prince from a PHP script. The Prince class instantiation apparently works - didn't throw an error - but any calls to the class to do something fail. The code is
<?php
//header('Content-Type: application/pdf');
//header('Content-Disposition: inline; filename="file.pdf"');

/*
 * Program: printToPDF.php
 * 
 * Function: Displays an HTML page rendered into PDF by the Prince program
 * 
 * Arguments are passed as a querystring:
 * 
 *      input=file.html
 *      css=cssfile.css (optional. Joomla templates will always be loaded ahead of this one.)
 * 
 */

require_once $_SERVER["DOCUMENT_ROOT"] . "/code/prince-php/prince.php";

$prince = new Prince('/usr/prince');
if(!$prince) die("<p>Prince instantiation failed</p>");
else echo "Prince instantiation OK<br />";

echo("<p>Server Document Root = " . $_SERVER['DOCUMENT_ROOT'] . "</p>");
$logLoc = $_SERVER['DOCUMENT_ROOT'] . '/prince_error.log';
echo("<p>Log file to $logLoc</p>");

if(!$prince->setLog($logLoc))die("<p>Error setting error log to $logLoc</p>");
$xmlString="<h1>Hello World</h1><p>This is a test. Did you guess?</p>";
if(!$prince->convert_string_to_passthru($xmlString))die("Error running Prince");
?>

and can be executed at http://www.fearringtonfha.org/code/printToPDF.php.

I have checked paths on my server and they look OK. The prince shell script seems to correctly point to the Prince binary, and both the calling script and the binary have 755 permissions. Also, the prince_error.log file is in the site's public_html directory, and has permissions of 666.

Looking for suggestions about where to look and what to do to get this running.

Thanks.
mikeday
Is it really "/usr/prince", and not "/usr/bin/prince"? What do you get if you run "which prince" from the terminal?
jimbrooking
I don't think I can run scripts directly - can't see any terminal access on my site. (Using hostmonster.com and cPanel.)

Three screen shots below show the directory structure to get to the script, yhe directory structure for the Prince binary, and the shell script itself.

usr_prince.jpg


usr_lib_prince_bin.jpg


prince_shell_script.jpg
  1. prince_shell_script.jpg8.0 kB
  2. usr_lib_prince_bin.jpg94.9 kB
  3. usr_prince.jpg87.5 kB
mikeday
The installation looks okay, so there is probably an issue running the Prince binary on the server, for example a library problem. Do you know which operating system the server is running? The easiest way to debug this is from the command line, but if that is not available then we need to get creative. How about try running the PHP command system("/usr/lib/prince/bin/prince") and check the return string? You can also pass a second argument to capture the process exit code (see system).
jimbrooking
Ran this:
<?php
function my_exec($cmd, $input='') 
         {$proc=proc_open($cmd, array(0=>array('pipe', 'r'), 1=>array('pipe', 'w'), 2=>array('pipe', 'w')), $pipes); 
          fwrite($pipes[0], $input);fclose($pipes[0]); 
          $stdout=stream_get_contents($pipes[1]);fclose($pipes[1]); 
          $stderr=stream_get_contents($pipes[2]);fclose($pipes[2]); 
          $rtn=proc_close($proc); 
          return array('stdout'=>$stdout, 
                       'stderr'=>$stderr, 
                       'return'=>$rtn 
                      ); 
         } 
// var_export(my_exec('echo -e $(</dev/stdin) | wc -l', 'h\\nel\\nlo')); 
$prince= "/home1/fearrin1" . "/usr/lib/prince/bin/prince";
var_export(my_exec($prince));
?>

with this result:
fnf.jpg


I can not tell what Unix is running on the server. (Or at least I don't know how to determine it programmatically.)
  1. fnf.jpg32.0 kB
mikeday
Great, that's exactly the error message we need to figure out what is going on. Since it is a shared library issue, try installing a Prince package with a statically linked binary, such as one of these:
- prince-8.0-linux-static.tar.gz
- prince-8.0-linux-amd64-static.tar.gz
jimbrooking
I did upload the 32-bit version and (I think) put the prince shell script and the /lib directory under /user. The full path to the shell script is /home1/fearrin1/usr/prince.

I spiffed up the output from the diagnostic program, which now looks like
<?php
function my_exec($cmd, $input='') {
    $proc=proc_open($cmd, array(0=>array('pipe', 'r'), 1=>array('pipe', 'w'), 2=>array('pipe', 'w')), $pipes); 
    fwrite($pipes[0], $input);fclose($pipes[0]); 
    $stdout=stream_get_contents($pipes[1]);fclose($pipes[1]); 
    $stderr=stream_get_contents($pipes[2]);fclose($pipes[2]); 
    $rtn=proc_close($proc); 
    return "<p>Call <b>$cmd</b> result:" .
           "<dl><dt>stdout</td><dd>$stdout</dd>" .
           "<dt>stderr</dt><dd>$stderr</dd>" .
           "<dt>return</dt><dd>$rtn</dd></dl>";
} 

$prince= "/home1/fearrin1" . "/usr/lib/prince/bin/prince";
echo(my_exec($prince));
?>

The output now reads
Call /home1/fearrin1/usr/lib/prince/bin/prince result:

stdout
Usage: prince [OPTIONS] file.xml Convert file.xml to file.pdf prince [OPTIONS] doc.html -o out.pdf Convert doc.html to out.pdf prince [OPTIONS] FILES... -o out.pdf Combine multiple files to out.pdf Try 'prince --help' for more information.
stderr
return
0

So it seems as though everything called from the prince binary/executable is being loaded properly.

However, my original test page, calling the shell script, fails. Here is the shell script:
#! /bin/sh
$PROGRAM="prince"
prefix=/home1/fearrin1/usr
exec $prefix/lib/$PROGRAM/bin/$PROGRAM --prefix="$prefix/lib/$PROGRAM" "\$@"

The test page is
<?php
//header('Content-Type: application/pdf');
//header('Content-Disposition: inline; filename="file.pdf"');

/*
 * Program: printToPDF.php
 * 
 * Function: Displays an HTML page rendered into PDF by the Prince program
 * 
 * Arguments are passed as a querystring:
 * 
 *      input=file.html
 *      css=cssfile.css (optional. Joomla templates will always be loaded ahead of this one.)
 * 
 */

require_once $_SERVER["DOCUMENT_ROOT"] . "/code/prince-php/prince.php";

$prince = new Prince('/home1/fearrin1/usr/prince');
if(!$prince) die("<p>Prince instantiation failed</p>");
else echo "Prince instantiation OK<br />";

echo("<p>Server Document Root = " . $_SERVER['DOCUMENT_ROOT'] . "</p>");
$logLoc = $_SERVER['DOCUMENT_ROOT'] . '/prince_error.log';
echo("<p>Log file to $logLoc</p>");

//if(!$prince->setLog($logLoc))die("<p>Error setting error log to $logLoc</p>");
$xmlString="<h1>Hello World</h1><p>This is a test. Did you guess?</p>";
if(!$prince->convert_string_to_passthru($xmlString))die("Error running Prince");
?>

The setLog call throws an error, so it's commented out. Then the prince->convert... call gives an error.

I apologise for bugging you like this for what must seem like stupid newbie questions but the fact is that while I am a decent programmer, I have little experience with the unix command line and shell scripts, so I do appreciate your patience.

It seems like we are getting closer....
mikeday
It's great that the binary works, that's the most important first step. Now, why is the shell script failing? What error do you get back from my_exec when you call the shell script?
jimbrooking
Sorry - brain not functioning well:
Call /home1/fearrin1/usr/prince result:

stdout
stderr
/home1/fearrin1/usr/prince: line 2: =prince: command not found /home1/fearrin1/usr/prince: line 4: /home1/fearrin1/usr/lib//bin/: No such file or directory /home1/fearrin1/usr/prince: line 4: exec: /home1/fearrin1/usr/lib//bin/: cannot execute: No such file or directory
return
126

I can see the problem is the double-slash. The path probably ought to be something like /home1/fearrin1/usr/lib/prince/bin.
mikeday
Oh, "$PROGRAM=prince" should just be "PROGRAM=prince", as you only need the leading $ when you evaluate the variable, not when you set it.
jimbrooking
Sorry - I should have seen that. Next rerun produces
Call /home1/fearrin1/usr/prince result:

stdout
stderr
prince: warning: failed to load external entity "$@" prince: $@: error: could not load input file prince: error: no input documents to process
return
1

which I assumes means it wants an argument to the call. Can I just substitute the path (on the server) to an XML or XHTML file?
mikeday
Yes, but the shell script should have "$@", not "\$@".
jimbrooking
I see - the "\" was an escape character - I'd copied/pasted from the install script. DOH!

Anyway, We're on the way and I won't be bugging you any more about this - at least for a few days. :wink:

OH - edited to say THANK YOU for your tolerance and persistence in getting this thing going.

The result of the last test is attached.
tryprince.pdf‎
  1. tryprince.pdf30.4 kB
mikeday
Glad to hear it's all working. :)