在psql查询上使用proc_open()进行交互式提示

时间:2012-05-16 18:15:58

标签: php postgresql proc-open

我正在尝试从Web界面执行一些PostgreSQL数据库命令。 我使用proc_open()来管道到Windows命令提示符。 因为psql(和所有其他postgres命令)不接受密码作为选项,我必须将密码发送到写入流。 下面的代码导致浏览器挂起。要么未创建资源,要么未正确管道密码。欢迎提出任何建议。

$cmd = '""C:\\Program files\\PostgreSQL\\9.0\\bin\\psql.exe" --host localhost --port 5432 -U postgres --dbname $database_name --command "$query""';
$p=proc_open($cmd, 
             array(array("pipe","r"), array("pipe","w"), array("pipe","w")), 
             $pipes);
if (is_resource($p)){
  fwrite($pipes[0],"mypassword");
  fclose($pipes[0]);
  proc_terminate($p);
  proc_close($p);                         
}

[你会注意到命令中疯狂的双重引用 - 出于某种原因显然需要Windows。]

欢迎解决这个问题的方法:

  • 我之前尝试过使用system()和exec(),但放弃了,因为他们没有处理交互式提示。在php中有更好的选择吗?
  • pg_query()是与postgres DB交互的主要命令,但不支持pg_dump和pg_restore操作。有没有另一种方法来备份和恢复二进制postgres .backup文件,可以用PHP完成?

2 个答案:

答案 0 :(得分:3)

不要乱用密码提示,最好在%APPDATA%\postgresql\pgpass.conf中输入一个条目。格式为

hostname:port:database:username:password

确保选择运行网络服务器进程的用户的%APPDATA%

如果您真的开始与提示进行交互,您可以尝试人们经常用于执行此类任务的Expect库...免责声明:我从未在Windows上使用它不知道它在那里有多好,或者它是否真的有必要。也许你的fwrite只是缺少终止换行符。

答案 1 :(得分:0)

正如@ c-ramseyer建议的那样,通过proc_open()来模拟交互式提示是不可取的。 PostgreSQL提供了两种方法来通过交互式提示来提供密码。方法(1)是将其作为环境变量提供,如另一个答案所示。方法(2)是在DB用户的pgpass.conf directiory中创建%appinfo%文件。 (要从Windows命令提示符处找到该目录,请执行echo %appinfo%。)有关如何创建此单线程配置文件,请参阅postgresql。由于我仍然不理解的原因,这些方法都不适合我。

要解决此问题,我必须修改ph_hda.conf文件(PostgreSQL客户端身份验证配置文件)以禁用身份验证。该文件位于postgresql/data目录中。我在底部注释掉了2行默认设置,并用

替换了它们
#TYPE  DATABASE     USER        CIDR-ADDRESS       METHOD
host    all         all         127.0.0.1/32       trust     
host    all         all         ::1/128            trust

现在,如果我从php调用postgres,我会包含--no-password选项,并且吸盘工作正常。请注意,此解决方案并不安全,只有在我的情况下才有意义,因为它用于内部公司应用程序,并且计算机脱机运行。此方法不应用于生产站点,您的数据库将被黑客入侵。这是php代码。

$commande_restore = '""'.$postgres_bin_directory.'pg_restore" --host 127.0.0.1 --port 5432 -U postgres --no-password  -d '.$database_name.' '.$restore_file.'"';
$this->execute($commande_restore);      

function execute($cmd, $env = null){
  $proc=proc_open($cmd,array(0=>array('pipe','r'),1=>array('pipe','w'),2=>array('pipe','w')),$pipes, null, $env = null);
  //fwrite($pipes[0],$stdin);  //add to argument if you want to pass stdin                  
  fclose($pipes[0]);
  $stdout=stream_get_contents($pipes[1]);        fclose($pipes[1]);
  $stderr=stream_get_contents($pipes[2]);        fclose($pipes[2]);
  $return=proc_close($proc);    
  return array( 'stdout'=>$stdout, 'stderr'=>$stderr, 'return'=>$return );
}

我花了将近2周的时间来解决这个问题,所以我希望它可以帮助别人。