I want to use the power of Matplotlib (fantastic python graphing library) in an existing php application of mine. Before embarking on the specifics of my application, I tried to get a super simple demo up and running, which proved far more difficult than I had expected.
This is my very simple matplotlib example:
#!/usr/bin/env python import sys import matplotlib matplotlib.use('Agg') from pylab import * plot([1,2,3]) savefig(sys.stdout)
I then tried to call it from a simply PHP script using
exec('python my_python_script.py', $output);
Each line outputted by python to stdout goes into an element of the array $output. One simply prints each element followed by a carriage return from PHP to the browser.
However the output was corrupted and would not render as a png file. Running the python script from the command line and piping to a file gave a valid image though. Turning off the png image headers gave me a page of machine code, which looked identical to what I got by using file_get_contents to stream the valid png image that I previously piped from the command line.
In desperation, I saved each file from my browser and dropped them into a hex editor. Here, I found that the genuine png file contained a line feed character (0x0D) just after the first line, that my corrupt file did not. This caused a 2 character offset to occur to the rest of the file, hence the corruption.
If you know why this occurs, please let me know. In the mean time, here is my working PHP script complete with a bandaid solution:
<?php header("Content-type: image/png"); $stuff = exec('python python_graph.py', $output); foreach($output as $key=>$value){ if($key==1) print chr(0x0D); //Newline feed after PNG declaration if($key>0) print "\n"; print $value; } ?>
And here is the image in all its glory.
Found out while doing something almost identical to you (WHY does PHP have no decent graphing libraries) – PHP’s exec is NOT binary safe. Shell_exec might be, but proc_open certainly is. A code example below (pretty much straight from the PHP docs):
$descriptorspec = array(
0 => array(“pipe”, “r”), // stdin is a pipe that the child will read from
1 => array(“pipe”, “w”), // stdout is a pipe that the child will write to
);
$process = proc_open(dirname(__FILE__).”/Graph.py”, $descriptorspec, $pipes);
if (is_resource($process)){
fwrite($pipes[0], json_encode($this->output, JSON_PRETTY_PRINT));
fclose($pipes[0]);
header (‘Content-Type: image/png’);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
$return_value = proc_close($process);
}
Thanks Alasdair. I think you’ve nailed it.
Take a look at https://github.com/vivesweb/graph-php. Is a class for do simple tasks as matplotlib, but written in pure PHP. Matplotlib is a big and good tool, and graph-php is in its beginnings, but it can already make many basic graphs very similar to those of MatPlotLib. I hope it helps.