如何在PHP中运行Ruby/Python脚本并传递参数?

8 投票
5 回答
11988 浏览
提问于 2025-04-16 09:32

我需要把HTML转换成相应的Markdown格式文本。

注意:用PHP和Python快速简单的方法

因为我在用PHP编程,有些人推荐了Markdownify来完成这个任务,但不幸的是,这个代码没有更新,实际上它是不能用的。在sourceforge.net/projects/markdownify上有个“注意:不再支持 - 你想维护这个项目吗?联系我!Markdownify是一个用PHP写的HTML到Markdown的转换器。可以把它看作是html2text.php的继任者,因为它设计更好,性能更强,处理边缘情况更少。”

根据我所了解,我只有两个不错的选择:

  • Python:Aaron Swartz的html2text.py

  • Ruby:Singpolyma的html2markdown.rb,基于Nokogiri

所以,从PHP中,我需要传递HTML代码,调用Ruby/Python脚本,然后接收输出。

(顺便说一下,有人这里问了一个类似的问题(“如何从PHP调用Ruby脚本?”),但对我来说没有实用的信息)。

根据Tin Man的建议,我得到了这个:

PHP代码:

$t='<p><b>Hello</b><i>world!</i></p>';
$scaped=preg_quote($t,"/");
$program='python html2md.py';

//exec($program.' '.$scaped,$n); print_r($n); exit; //Works!!!

$input=$t;

$descriptorspec=array(
   array('pipe','r'),//stdin is a pipe that the child will read from
   array('pipe','w'),//stdout is a pipe that the child will write to
   array('file','./error-output.txt','a')//stderr is a file to write to
);

$process=proc_open($program,$descriptorspec,$pipes);

if(is_resource($process)){
    fwrite($pipes[0],$input);
    fclose($pipes[0]);
    $r=stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    $return_value=proc_close($process);
    echo "command returned $return_value\n";
    print_r($pipes);
    print_r($r);
}

Python代码:

#! /usr/bin/env python
import html2text
import sys
print html2text.html2text(sys.argv[1])
#print "Hi!" #works!!!

用上面的代码,我得到了这个:

命令返回1 数组 ( [0] => 资源ID #17 1 => 资源ID #18 )

而“error-output.txt”文件显示:

追踪(最近的调用在最前面): 文件“html2md.py”,第5行,在 print html2text.html2text(sys.argv1) IndexError: 列表索引超出范围

有什么想法吗???


Ruby代码(仍在分析中

#!/usr/bin/env ruby
require_relative 'html2markdown'
puts HTML2Markdown.new("<h1>#{ ARGF.read }</h1>").to_s

只是记录一下,我之前尝试使用PHP最简单的“exec()”,但在处理一些HTML语言中非常常见的特殊字符时遇到了一些问题。

PHP代码:

echo exec('./hi.rb');
echo exec('./hi.py');

Ruby代码:

#!/usr/bin/ruby
puts "Hello World!"

Python代码:

#!usr/bin/python
import sys
print sys.argv[1]

这两者都能正常工作。但当字符串稍微复杂一点时:

$h='<p><b>Hello</b><i>world!</i></p>';
echo exec("python hi.py $h");

它完全不工作。

这是因为HTML字符串需要对特殊字符进行转义。我使用了这个:

$t='<p><b>Hello</b><i>world!</i></p>';
$scaped=preg_quote($t,"/");

现在它像我说的那样工作了这里

我正在运行: Fedora 14 ruby 1.8.7 Python 2.7 perl 5.12.2 PHP 5.3.4 nginx 0.8.53

5 个回答

2

在Ruby代码中使用一个变量,然后从PHP代码中把这个变量作为参数传递给Ruby脚本。接着,让Ruby脚本把处理后的结果输出到标准输出(stdout),这样PHP就可以读取到这些结果。

5

在Python中,可以让PHP把变量作为命令行参数传递过来,然后在Python里通过sys.argv获取这些参数(这是一种存储传递给Python的命令行参数的列表),接着让Python打印输出,最后PHP再把这个输出显示出来。举个例子:

#!usr/bin/python
import sys

print "Hello ", sys.argv[1] # 2nd element, since the first is the script name

PHP:

<?php
echo exec('python script.py Rafe');
?>

在Ruby中,过程基本上也是一样的。

12

可以让PHP通过proc_open来打开Ruby或Python脚本,并把HTML数据通过标准输入(STDIN)传给这个脚本。Ruby或Python脚本会读取这些数据并处理,然后通过标准输出(STDOUT)把结果返回给PHP脚本,最后退出。这种方法在Perl、Ruby或Python中很常见,因为它可以直接访问错误输出(STDERR),如果出现问题也不需要临时文件,不过相对来说稍微复杂一些。

另外一种方法是先把数据从PHP写入一个临时文件,然后使用systemexec或者类似的函数来调用Ruby或Python脚本,打开并处理这个文件,最后通过它们的标准输出打印结果。

编辑:

可以查看@Jonke的回答,了解“Ruby中STDIN的最佳实践”,里面有简单的例子说明如何用Ruby读取标准输入并写入标准输出。还有“如何在Python中从stdin读取”也有一些不错的示例。

下面是一个简单的例子,展示如何调用一个Ruby脚本,通过PHP的标准输入管道传递一个字符串,并读取Ruby脚本的标准输出:

把这个保存为“test.php”:

<?php
$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
   2 => array("file", "./error-output.txt", "a") // stderr is a file to write to
);
$process = proc_open('ruby ./test.rb', $descriptorspec, $pipes);

if (is_resource($process)) {
    // $pipes now looks like this:
    // 0 => writeable handle connected to child stdin
    // 1 => readable handle connected to child stdout
    // Any error output will be appended to /tmp/error-output.txt

    fwrite($pipes[0], 'hello world');
    fclose($pipes[0]);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // It is important that you close any pipes before calling
    // proc_close in order to avoid a deadlock
    $return_value = proc_close($process);

    echo "command returned $return_value\n";
}
?>

把这个保存为“test.rb”:

#!/usr/bin/env ruby

puts "<b>#{ ARGF.read }</b>"

运行PHP脚本会得到:

Greg:Desktop greg$ php test.php 
<b>hello world</b>
command returned 0

这个PHP脚本打开了Ruby解释器,然后运行Ruby脚本。PHP会把“hello world”发送给它。Ruby把接收到的文本用粗体标签包裹起来,然后输出,PHP再把这个结果捕获并输出。整个过程没有临时文件,也没有在命令行上传递参数,如果需要的话可以传递很多数据,而且速度也很快。你也可以用Python或Perl代替Ruby。

编辑:

如果你有:

HTML2Markdown.new('<h1>HTMLcode</h1>').to_s

作为示例代码,那么你可以开始用以下代码开发Ruby解决方案:

#!/usr/bin/env ruby

require_relative 'html2markdown'

puts HTML2Markdown.new("<h1>#{ ARGF.read }</h1>").to_s

假设你已经下载了HTML2Markdown代码,并且它在当前目录下,同时你正在运行Ruby 1.9.2。

撰写回答