【发布时间】:2010-12-10 06:13:03
【问题描述】:
我需要从 PHP 脚本创建一个 ejabberd 用户。我还需要能够将新用户添加到预定义的共享名册中。
我应该直接使用exec() 拨打ejabberdctl 还是有更好的方法?
【问题讨论】:
我需要从 PHP 脚本创建一个 ejabberd 用户。我还需要能够将新用户添加到预定义的共享名册中。
我应该直接使用exec() 拨打ejabberdctl 还是有更好的方法?
【问题讨论】:
ejabberdctl 在这种特定情况下是迄今为止最简单的。其他选项是:
在 PHP 中实现完整的客户端 XMPP (!)
在 Erlang 中实现一个模块来代理请求:PHPErlang 通信需要通过套接字,并且会涉及到大量的编组 (!)
【讨论】:
exec() 运行ejabberdctl 命令时,我都会得到回复:erlexec: HOME must be set
感谢jldupont's adviceejabberdctl 将是最简单的解决方案,我克服了遇到的障碍并找到了可行的解决方案。
默认情况下,apache 的用户没有正确的权限来成功运行ejabberdctl(这是有充分理由的)。所以为了让它工作,你必须用sudo来调用它。但是...sudo 需要密码,这会带来两个问题:
解决方案(适用于 Ubuntu) - 在/etc/sudoers 末尾添加此行:
www-data ALL= (ejabberd) NOPASSWD: /usr/sbin/ejabberdctl
sudoers 文件和 ejabberdctl 的路径可能因其他 Linux 发行版而异。这允许 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 代码,以便不只是任何人都可以使其执行。除了明显的安全风险外,它还可能使您的服务器面临拒绝服务攻击。
【讨论】:
www-data ALL= (ejabberd) NOPASSWD: /usr/sbin/ejabberdctl,以便 ejabberdctl 不会以 root 身份运行,而是以用户 ejabberd 身份运行。在您的代码中执行ejabberdctl,如下所示:sudo -u ejabberd ejabberdctl。
如果您想在 XMPP 协议中使用 PHP 以一种干净且安全的方式执行此操作,我建议您使用此示例脚本 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 $
【讨论】:
最简单的方法是使用 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 );
【讨论】:
我在 2016 年遇到了这个问题,实现这个问题的方法比接受的答案和投票最高的答案要简单得多。
https://github.com/fabiang/xmpp
这是我为添加用户编写的类:
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);
}
}
{访问,注册,[{允许,全部}]}。
最后是使用这个类的示例代码:
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 证书,库调用将失败。要么放置一个有效的证书,要么用下面的 sn-p 替换 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
);
【讨论】:
我已经用 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 -XPOST 127.0.0.1:5281/api/register -d '{"user":"lucky","host":"data.com","password":"test"}'
要适用于 php,您可以使用标准 curl ,而上面的代码是未发布的ejabberd doc中包含的最新curl代码,
我只是应用它并从 doc ejabber 中对其进行分析,然后将其调整为在 ejabberd config xml 上创建的 ejabberd url 路径
【讨论】: