SoftOver
 
Recommended


User login


 

Capturing Ruby Output with PHP

    PHP provides a lot of different functions to run external commands, but looks like only 'exec' allows to capture output.

We will need it captured first of all to clean HTML special symbols out of it (second reason is noted at the end of this post).

Unfortunately 'exec' does not accept environment settings, so we will need to embed them in the command itself. We also want to be able to use ruby 'require' without tricks with getting current file location - it means that we should run ruby from the script location.

Here is one of ways to achieve desired:

function run_ruby($script='-v', $exec='ruby')
{
  $output="<div class=\"output\"><pre>\n";
  $output.="&gt; $exec $script\n";
  $script_root='~/cgi-bin';
  $gem_home='~/bin/ruby';
  $ruby_path='~/bin/ruby/bin';
  $cmd="cd $script_root; GEM_HOME=$gem_home PATH=$ruby_path:\$PATH $exec $script 2>&1";
  exec($cmd,$result);
  $trans = array('>' => '&gt;', '<' => '&lt;', '&' => '&amp;');
  $output.=strtr(implode($result,"\n"),$trans);
  $output.='</pre></div>';
  print $output;
}
$exec is a parameter to be able to run gem executables instead of ruby (e.g. 'spec' from rspec gem)

Running this function from php is strait forward:

<?php run_ruby('[your script]') ?%>
And here is a result (with default "script" -v):
> ruby -v
ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-linux]
Please note that there is no safety net in this script, one can run something dangerous like:
<?php run_ruby('-rf /','rm') ?%>
On the other hand anybody can have this dangerous functionality in the ruby code that is run, so the only way to prevent this is to limit access to this function. Another problem is that ruby will be invoked on every page load - and here captured output comes handy again. You can always save output in the cache (any framework has a cache) and serve it from there.

O-ops, almost forgot. This function generates wraps output in a section with class "output". Style that I use (just copy and paste it to your css):

.output {
  background: #333;
  color: #fff;
  width: 95%;
  border: 3px inset #000;
  padding: 10px;
  font-size: 1.6em;
  overflow: auto;
  margin: 4px 0px;
  width: 95%;
}