从PHP创建ejabberd用户

10

我需要从PHP脚本创建一个ejabberd用户。 我还需要能够将新用户添加到预定义的共享花名册中。

我应该只使用exec()调用ejabberdctl,还是有更好的方法?

7个回答

10

这是我的最终解决方案:

感谢jldupont的建议,指出ejabberdctl是最简单的解决方案。我克服了遇到的障碍并拥有了一个可行的解决方案。

默认情况下,apache用户没有足够的权限成功运行ejabberdctl(原因很好)。所以为了使它工作,必须使用sudo调用它。但是...sudo需要密码,这产生了两个问题:

  1. apache用户没有密码。
  2. 即使有密码,也没有办法从PHP中输入它。

解决方案(针对Ubuntu)- 在/etc/sudoers的末尾添加此行:

www-data ALL= (ejabberd) NOPASSWD: /usr/sbin/ejabberdctl

对于其他Linux发行版,sudoers文件和ejabberdctl的路径可能会有所不同。这允许apache用户(www-data)仅以提升的特权运行ejabberdctl,而无需输入密码。

现在只需要PHP代码:

<?php
    $username = 'tester';
    $password = 'testerspassword';
    $node = 'myserver.com';
    exec('sudo -u ejabberd /usr/sbin/ejabberdctl register '.$username.' '.$node.' '.$password.' 2>&1',$output,$status);
    if($output == 0)
    {
        // Success!
    }
    else
    {
        // Failure, $output has the details
        echo '<pre>';
        foreach($output as $o)
        {
            echo $o."\n";
        }
        echo '</pre>';
    }
?>

安全性

需要注意的是,即使您只允许www-data运行一个命令,这也存在重大安全风险。如果您使用此方法,您需要确保通过某种身份验证来保护PHP代码,以防止任何人都能够执行它。除了显而易见的安全风险外,这可能会让您的服务器面临拒绝服务攻击。


1
将您的sudo行更改为www-data ALL= (ejabberd) NOPASSWD: /usr/sbin/ejabberdctl,以便ejabberdctl不作为root用户运行,而是作为用户ejabberd运行。在代码中像这样执行ejabberdctlsudo -u ejabberd ejabberdctl - nemo
我在Linux中遇到了同样的问题,(错误:sh:/bin/su:权限被拒绝), 解决方案(适用于Ubuntu)- 在/etc/sudoers的末尾添加此行: 如何在Linux中添加? - Purushottam
@Purushottam:Ubuntu是基于Debian的Linux发行版。每个Linux发行版都有自己处理某些事情的方式。我建议在您特定的Linux发行版中搜索sudoers文件的位置。 - Andrew Ensley
我已经尝试通过谷歌搜索,但仍无法解决。我正在使用CentOS Linux发行版,你能帮帮我吗? - Purushottam
出现以下错误, 您正在尝试运行“ejabberdctl”,它需要管理员权限,但需要更多信息才能这样做。 作为“root”进行身份验证 密码:密码:密码: - Purushottam
你应该能够从CentOS社区(http://wiki.centos.org/Documentation)中找到针对你特定情况的帮助。他们比我知道得多。 - Andrew Ensley

7

我在2016年遇到了这个问题,有比被接受的回答和得票最高的回答更简单的实现方法。

  1. 使用一个XMPP PHP库,最常用的是:

https://github.com/fabiang/xmpp

  1. 虽然这个库不支持直接添加用户,但你可以很容易地扩展它。

下面是我编写的添加用户的类:

use Fabiang\Xmpp\Util\XML;

/**
 * Register new user
 * @param string $username
 * @param string $password
 * @param string $email
 * @package XMPP\Protocol
 * @category XMPP
 */
class Register implements ProtocolImplementationInterface
{  
    protected $username;
    protected $password;
    protected $email;

    /**
     * Constructor.
     *
     * @param string $username
     * @param string $password
     * @param string $email
     */
    public function __construct($username, $password, $email)
    {
        $this->username = $username;
        $this->password = $password;
        $this->email = $email;
    }

    /**
     * Build XML message
     * @return type
     */
    public function toString()
    {
        $query = "<iq type='set' id='%s'><query xmlns='jabber:iq:register'><username>%s</username><password>%s</password><email>%s</email></query></iq>";        
        return XML::quoteMessage($query, XML::generateId(), (string) $this->username, (string) $this->password, (string) $this->email);
    }
}
  1. 您必须在ejabberd.cfg文件中启用带内注册,因为默认情况下被拒绝:

{access,register,[{allow,all}]}。

最后,这是使用此类的示例代码:

private function registerChatUser($name, $password, $email)
    {       
        $address = 'tcp://yourserverip:5222';
        $adminUsername = 'youradmin';
        $adminPassword = 'youradminpassword';

        $options = new Options($address);
        $options->setUsername($adminUsername)->setPassword($adminPassword);

        $client = new Client($options);         
        $client->connect();             

        $register = new Register($name, $password, $email);                 
        $client->send($register);   

        $client->disconnect();
    }

该库调用将会失败,如果服务器没有有效的SSL证书。请放置一个有效的证书,或使用下面的代码片段替换SocketClient.php中的此部分。
// call stream_socket_client with custom error handler enabled
$handler = new ErrorHandler(
    function ($address, $timeout, $flags) {
        $options = [
            'ssl' => [
                'allow_self_signed' => true,
                'verify_peer_name' => false,
            ],
        ];
        $context = stream_context_create($options);
        return stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context);
    },
    $this->address,
    $timeout,
    $flags
);

我尝试做同样的事情,但是出现了以下错误。在****/***/vendor/fabiang/xmpp/src/Connection/AbstractConnection.php的第308行捕获到未捕获的异常 'Fabiang\Xmpp\Exception\TimeoutException',并显示消息 'Connection lost after 20 seconds'。 - Mani Kandan
我遇到了这个错误:无法启用加密致命错误:未捕获的异常 'Fabiang\Xmpp\Exception\ErrorException' - Lakshmaji
@lakshmaji 我认为这个问题可以通过答案中的最后一步解决,即更新SocketClient.php的部分。 - Amr H. Abd Elmajeed
@AmrH.AbdelMajeed,我已经用你答案中的最后一步替换了现有代码,但出现了相同的错误。 - Lakshmaji
这对我没有什么影响,但它不会在ejabberd中创建任何用户,你有调试点吗? - Ankit Doshi
@AnkitDoshi 是的,你可以在registerChatUser函数中或者Register类的toString函数中使用你通常使用的任何日志记录器。同时,请仔细检查你的ejabberd服务器配置,并使用Ejabberd客户端(如pidgin)进行测试,然后再用代码进行测试。 - Amr H. Abd Elmajeed

4

在这种情况下,ejabberdctl是迄今为止最容易的选择。其他选项包括:

  • 在PHP中实现完整的客户端XMPP(!)

  • 在Erlang中实现一个模块来代理请求:PHP<-->Erlang通信需要通过套接字进行,会涉及大量编组(!)


嗯...我好像遇到了权限限制(或其他问题)。每当我尝试使用exec()运行ejabberdctl命令时,我会收到以下提示:erlexec: HOME must be set - Andrew Ensley
好的 - 我已经想出解决方案了。我很快会发布我的解决方案。谢谢你的建议。 - Andrew Ensley
你能提供一个链接或源代码,用于从PHP脚本创建ejabberd用户吗? - Harshit Sethi

1
如果您想使用PHP在XMPP协议中以清洁和安全的方式完成此操作,我建议使用此示例脚本register_user.php。这是一个可以在Jaxl PHP库中找到的示例。
下载Jaxl库并按以下方式使用:
JAXL $ php examples/register_user.php localhost
Choose a username and password to register with this server
username:test_user
password:test_pass
registration successful
shutting down...
JAXL $

0
我已经解决了与mod_register_web [1, 2]相关的问题。它不需要大量的代码,而且我认为足够安全。mod_register_web提供了一个带有简单POST表单的HTML页面来注册新用户。
在单独的HTTP监听器下启用模块(在我的情况下,端口5281)。仅使用“ip”参数使此端口仅对本地请求可用。
listen:
  port: 5280
  module: ejabberd_http
  web_admin: true
  http_bind: true
  ## register: true

ip: "127.0.0.1"   # Only local requests allowed for user registration
  port: 5281
  module: ejabberd_http
  register: true

modules:
  mod_register_web: {}

请求示例:

curl -XPOST 127.0.0.1:5281/register/new -d 'username=lucky&host=vHost&password=test&password2=test'

可以使用适当的库(已经在我的框架中)从 PHP 代码执行请求。


为什么在上面的例子中要设置两个密码?当我运行上述命令时,出现了curl: (52) Empty reply from server的错误提示。 - mayur panchal
为什么在上面的例子中要设置两个密码?因为它使用用户注册的POST方法,该方法也被网页使用。这两个密码字段对应于注册表单中的“密码”和“确认密码”。 - serkas

0

最简单的方法是使用mod_xmlrpc - 它允许您使用xmlrpc运行ejabberdctl命令。这很容易与诸如以下库一起使用:

https://github.com/gamenet/php-jabber-rpc

/* Add user to Jabber */
use \GameNet\Jabber\RpcClient;
use \GameNet\Jabber\Mixins\UserTrait;
$rpc = new RpcClient([
        'server' => 'jabber.org:4560',
        'host' => 'myhost.org',
        'debug' => false,
    ]);

$result=$rpc->createUser( $username, $password );

我尝试了上述方法,但出现以下错误:必须将传递给fXmlRpc\Transport\HttpAdapterTransport::__construct()的第一个参数是Http\Message\MessageFactory的实例,但却传递了Ivory\HttpAdapter\CurlHttpAdapter的实例。该错误发生在/var/www/html/php-jabber-rpc/lib/GameNet/Jabber/RpcClient.php的第140行。 - Lakshmaji

0
curl -XPOST 127.0.0.1:5281/api/register -d '{"user":"lucky","host":"data.com","password":"test"}'

要应用到 PHP 中,您可以使用标准的 cURL,上面的代码是未发布的 ejabberd 文档中包含的最新 cURL 代码。

我刚刚从 ejabberd 的文档中应用并分析了它,然后将其调整为在 ejabberd 配置 XML 中创建的 ejabberd URL 路径。


2
虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。 - Donald Duck
完整的JSON格式应该提交curl '{"user", "lucky", "master": "data.com", "password", "test"}',并且所有内容必须根据现有ejabberd文档中的语言和数据进行调整。 - Fikalefaza
当我运行上述命令时:curl: (52) 服务器返回空响应 - mayur panchal
您的ejabber数据可能存在错误,或者可能是其他原因,请再次检查。 - Fikalefaza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接