0

我正在尝试从 Web 界面执行一些 PostgreSQL DB 命令。我使用 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 完成?
4

2 回答 2

3

不要乱用密码提示,最好在%APPDATA%\postgresql\pgpass.conf. 格式为

hostname:port:database:username:password

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

如果您真的打算与提示进行交互,您可以尝试人们经常用于此类任务的Expect库......免责声明:我从未在 Windows 上使用过它,也不知道它在那里工作得如何,或者如果这确实是必要的。也许您的 fwrite 只是缺少一个终止换行符。

于 2012-05-16T20:54:33.660 回答
0

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

为了解决这个问题,我不得不修改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 周的时间来解决这个问题,所以我希望它对某人有所帮助。

于 2012-05-18T18:44:56.277 回答