I am trying to send direct message with JAXL in the name of a user (authenticated application with xmpp_login). In the jaxl facebook chat example there exist a message echo structure, still it redirects received XMPPStanza to the sender. But trying to generate XMPPStanza to send performs nothing with
$client->send($stanza);
here is my XMPPStanza initialization code
$stanza = new XMPPMsg(null);
$stanza->from = $client->full_jid->to_string();
$stanza->to = 'example-facebook-id#chat.facebook.com';
$stanza->type = 'chat';
$stanza->body = 'test message';
$client->send($stanza);
To sum it up, How can i send message from server in the name of the client via JAXL?
EDIT
I forgot to mention i am using JAXL v3 and thought about appending full code and system configuration would be more helpful.
<?php
define('FACEBOOKBOT_PHP', TRUE);
// Include XMPP Engine 'JAXL'
// Path might be alter in time.
// require_once ROOT_DIR.'/JAXL/jaxl.php';
require_once '/var/www/JAXL/jaxl.php';
require_once '/var/www/JAXL/xmpp/xmpp_msg.php';
function sendMessage($client)
{
// // $stanza = new XMPPMsg(null);
// // $stanza->from = $client->full_jid->to_string();
// // $stanza->to = $to;
// // $stanza->type = 'chat';
// // $stanza->body = 'test message 1';
// // foreach ($stanza->childrens as $value)
// // {
// // $value->ns = 'jabber:client';
// // }
// // $client->send($stanza);
$msg = new XMPPMsg(array('to'=>'example-user-id-and-it-got-to-work-i-checked-on-below-echo-stanza#chat.facebook.com'), 'test message');
$client->send($msg);
_info("test messages sent");
}
$user = 'gokhanbarisaker'; // my user id (www.facebook.com/gokhanbarisaker)
// $user = $argv[1]; // User name or facebook id
$jidSuffix = '#chat.facebook.com'; // Facebook chat account suffix
$appKey = 'example-app-key'; // Taken from developer.facebook.com
// $appKey = $argv[2]; // Facebook app token
$accessToken = 'example-access-token'; // Facebook user token - tried both app token tool on developer.facebook.com and token provided after user login both posses xmpp-login permission
// $accessToken = $argv[3];
$client = new JAXL( array( // (required) credentials
'jid' => $user.$jidSuffix,
'fb_app_key' => $appKey,
'fb_access_token' => $accessToken,
// force tls (facebook require this now)
'force_tls' => true,
// (required) force facebook oauth
'auth_type' => 'X-FACEBOOK-PLATFORM',
// (optional)
//'resource' => 'resource',
'log_level' => JAXL_INFO,
'priv_dir' => '.'
));
$client->add_cb('on_auth_success', function()
{
global $client;
_info("got on_auth_success cb, jid ".$client->full_jid->to_string());
$client->set_status("available!", "dnd", 10);
// Here is the part where i tried to send message. In addition, i tried to call this function wherever i can on the code.
sendMessage($client);
});
$client->add_cb('on_auth_failure', function($reason)
{
global $client;
$client->send_end_stream();
_info("got on_auth_failure cb with reason $reason");
});
$client->add_cb('on_chat_message', function($stanza)
{
global $client;
// echo back incoming message stanza
$stanza->to = $stanza->from;
$stanza->from = $client->full_jid->to_string();
$client->send($stanza);
_info("echo message sent");
sendMessage($client);
});
$client->add_cb('on_disconnect', function()
{
_info("got on_disconnect cb");
});
$client->start();
echo "done\n";
?>
System configuration:
Ubuntu 12.04.01 LTS
Apache 2.2.22
PHP 5.3.10
Terminal command to execute;
> php facebookbot.php
A few things you should try and see if they help you debug this:
Set 'log_level' => JAXL_DEBUG, and check logs to see what exactly Jaxl sends out to facebook. If you can, update the question with outgoing stanza so that we can verify whats really wrong here.
If you are using facebook id's to send out messages, remember you need to send message 'to'=>'-4#chat.facebook.com'. Note the negative sign.
Facebook is quite smart in catching spammers in their network. If you are trying to send out too many similar messages within a short time, facebook servers will reply back with appropriate error to the bot (they can even disable your chat account temporarily). Check the logs to see if you are gettings any such error response back from the facebook servers.
try:
$msg = new XMPPMsg(array('to'=>'example-facebook-id#chat.facebook.com'), 'test message');
$client->send($msg);
Related
i am struggling with google API. I am creating a website where I would like to read the groups of which the authenticated user is a member.
I have read everything about the subject, but many examples are very old and in the meantime things have changed.
This is the code I'm testing:
<?php
require 'lib/google-api/vendor/autoload.php';
// Creating new google client instance
$client = new Google_Client();
// Enter your Client ID
$client->setClientId('***.apps.googleusercontent.com');
// Enter your Client Secrect
$client->setClientSecret('***');
// Enter the Redirect URL
$client->setRedirectUri('***');
$client->setApplicationName("Test");
// Adding those scopes which we want to get (email & profile Information)
$client->addScope("email");
$client->addScope("profile");
$client->addScope("https://www.googleapis.com/auth/admin.directory.group.readonly");
$client->addScope("https://www.googleapis.com/auth/admin.directory.group.member.readonly");
if(isset($_GET['code'])){
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
if(!isset($token["error"])){
$client->setAccessToken($token['access_token']);
// getting profile information
$google_oauth = new Google_Service_Oauth2($client);
$google_account_info = $google_oauth->userinfo->get();
// Storing data into database
$email = $google_account_info->email;
$full_name = $google_account_info->name;
echo $email . "<br>";
// this is needed only if you need to perform
// domain-wide admin actions, and this must be
// an admin account on the domain; it is not
// necessary in your example but provided for others
$client->setSubject('***');
// set the authorization configuration using the 2.0 style
$client->setAuthConfig("***.json");
$adminService = new Google_Service_Directory($client);
$googleGroups = $adminService->groups->listGroups(array('domain'=>'mydomain.com'));
$groups = $googleGroups->getGroups();
}
}
?>
I am getting the following error
Uncaught Google_Service_Exception: {
"error": "unauthorized_client",
"error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
}
I have already done a Google Workspace Domain-Wide Delegation of Authority (https://developers.google.com/admin-sdk/directory/v1/guides/delegation) and I created a user to impersonate with read permissions on groups and users.
Where am I doing wrong? Thank you!
After some testing I made it work...
First of all i needed to give rights to the service account, not just at the one to impersonate.
$client = new Google_Client();
// Client ID
$client->setClientId(***);
// Client Secrect
$client->setClientSecret(***);
// Redirect URL
$client->setRedirectUri('https://www.mywebsite.com');
$client->setApplicationName('App name');
// Scopes for group reading, profile and email info
$client->addScope('https://www.googleapis.com/auth/admin.directory.group.readonly');
$client->addScope('https://www.googleapis.com/auth/userinfo.email');
$client->addScope('https://www.googleapis.com/auth/userinfo.profile');
if(isset($_GET['code'])){
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
if(!isset($token["error"])){
$client->setAccessToken($token['access_token']);
$google_oauth = new Google_Service_Oauth2($client);
// User info
$google_account_info = $google_oauth->userinfo->get();
$email = $google_account_info->email;
// Service account info
$client->setAuthConfig('***.json');
// Who i want to impersonate
$client->setSubject('admin#website.com');
$service = new Google_Service_Directory($client);
// Search groups of the logged user
$optParams = array(
'domain' => 'mywebsite.com',
'userKey' => $email
);
$googleGroups = $service->groups->listGroups($optParams);
$groups = $googleGroups->getGroups();
That's all :)
I was performing Google Sign in on Android Application for the first time. At the client side, I obtained the access token and sent to the PHP server via POST.
By referring to Google's Documentation, the code I used in backend is as follows:
$id_token = $_POST['id_token'];
$CLIENT_ID = "** MY WEB APPLICATION CLIENT ID **";
$client = new Google_Client(['client_id' => $CLIENT_ID]);
$client->setAuthConfigFile('client_secret.json');
...
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
} else {
echo "Invalid Token";
}
When obtaining user id, the error is : "Cannot use object of type Google_Auth_LoginTicket as array"
I am pretty new to Google sign in. Please point out what all has gone wrong.
Found It. I made some modifications to the code
$token_data = $client->verifyIdToken($id_token)->getAttributes();
$user_id = $token_data['payload']['sub'];
Now the user id is retrieved fine.
I can connect to the server but cannot read the acknowledgements messages sent by the gcm server. I want to know how to retrieve the XML sent by gcm server.
Here is my code :
<?php
require 'jaxl/jaxl.php';
$sender = 'sender id';
$client = new \JAXL(array(
'jid'=>$sender,
'pass'=>'pass',
'auth_type'=>'PLAIN',
'host' => 'gcm.googleapis.com',
'port' => '5235',
'force_tls' => true,
'strict' => FALSE,
'ssl' => TRUE,
'log_level' => JAXL_DEBUG,
'log_path'=> 'ex.txt'
));
$client->add_cb('on_message_stanza', function($msg) {
echo 'now what!!';
});
$client->add_cb('on_auth_success', function() {
echo 'it should';
global $client;
global $sender;
$namespace = 'google:mobile:data';
$arr=array("hello"=>"world");
$json_data=json_encode($arr,JSON_UNESCAPED_SLASHES);
$arr = array('to'=>'server','message_id'=>'123','data'=>$arr);
$json = json_encode($arr);
$xml = new JAXLXml('gcm',$namespace,array(),$json);
$msg = new JAXLXml('message','',array('id'=>'123'),'');
$msg->cnode($xml);
$client->send($msg);
});
$client->add_cb('on_error_message',function()
{
global $client;
echo 'error<br/>';
_info('got on_error_message cb jid'.$client->full_jid->to_string());
});
In the callback 'on_auth_success', i am sending a message to gcm server directed to my server id, it is sending a negative acknowledgement 'nack' which i can see in the log, but I don't know how to receive that in php code.
The XML received by gcm as per log is :
<message>
<data:gcm xmlns:data="google:mobile:data">{"message_id":"123","from":"someid",
"error_description":"","error":"BAD_REGISTRATION",
"message_type":"nack"}</data:gcm></message>
Oh, I got it, since the response message didn't had any type, I have to add the callback 'on__message', with 2 underscore, because middle value is the value of type attribute of the message which the response don't have.
For an ACK, you can use message type 'normal', so the cb would look like below (I am just logging response):
$client->add_cb('on_normal_message', function($stanza) {
global $client;
// echo back incoming message stanza
//$stanza->to = $stanza->from;
//$stanza->from = $client->full_jid->to_string();
//$client->send($stanza);
_info('Received response******'.$stanza->to_string());
});
Also: in the example, you need to add
$client->start();
For us newbies.
Then it works fine with GCM.
im working on a PHP project based on Symfony 2.2.11 and I installed the socketo related to the following tutorial http://socketo.me/docs/install to make my chat script working.
ServerCommand.php // Code of the command line that starts the WebSocket server
$oLoop = Factory::create();
// Listen for the web server to make a ZeroMQ push after an ajax request
$oContext = new Context($oLoop);
$oPull = $oContext->getSocket(\ZMQ::SOCKET_PULL);
// LET IT 127.0.0.1
$oPull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$oPull->on('message', array($oChat, 'onMessage'));
// Set up our WebSocket server for clients wanting real-time updates
$oWebSock = new Server($oLoop);
$oWebSock->listen(7979, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new IoServer(
new HttpServer(
new WsServer(
new WampServer(
$oChat
)
)
),
$oWebSock
);
$oLoop->run();
After a message is being added to database :
MessagesController.php
....
// This is our new stuff
$oContext = new \ZMQContext();
$oSocket = $oContext->getSocket(\ZMQ::SOCKET_PUSH, 'PushMe');
$oSocket->connect("tcp://mydomain:5555");
$aData = array(
'topic' => 'message',
'sUsername' => $oUserCurrent->getUsername(),
'sMessage' => $sMessage
);
$oSocket->send(json_encode($aData));
.....
The chat service :
Chat.php
/**
* A lookup of all the topics clients have subscribed to
*/
public function onSubscribe(ConnectionInterface $conn, $topic)
{
// When a visitor subscribes to a topic link the Topic object in a lookup array
$subject = $topic->getId();
$ip = $conn->remoteAddress;
if (!array_key_exists($subject, $this->subscribedTopics))
{
$this->subscribedTopics[$subject] = $topic;
}
$this->clients[] = $conn->resourceId;
echo sprintf("New Connection: %s" . PHP_EOL, $conn->remoteAddress);
}
/**
* #param string JSON'ified string we'll receive from ZeroMQ
*/
public function onMessage($jData)
{
$aData = json_decode($jData, true);
var_dump($aData);
if (!array_key_exists($aData['topic'], $this->subscribedTopics)) {
return;
}
$topic = $this->subscribedTopics[$aData['topic']];
// This sends out everything to multiple users, not what I want!!
// re-send the data to all the clients subscribed to that category
$topic->broadcast($aData);
}
JS code that receives data :
messages.html.twig :
var conn = new ab.Session(
'ws://mydomain:7979' // The host (our Ratchet WebSocket server) to connect to
, function() { // Once the connection has been established
conn.subscribe('message', function(topic, data)
{
console.log(topic);
console.log(data);
});
}
, function() { // When the connection is closed
console.warn('WebSocket connection closed');
}
, { // Additional parameters, we're ignoring the WAMP sub-protocol for older browsers
'skipSubprotocolCheck': true
}
);
So everytings working perfectly, when I send a new Message, it goes to DB then it lands on the page of the chat.
PROBLEM :
The data lands wherever the JS script is, and the result is that all users can get the same recorded message
ASKING :
How can I make data lands in a specific user page ?
Thank you
You are using Ratchet on backend side, right?
So, here you have very good example of case you need:
http://socketo.me/docs/hello-world
You should keep your client connections inside $clients property (not collection of resources id!). So, you can choose one element from this collection and send a message only to this client.
Example:
public function onSubscribe(ConnectionInterface $conn, $topic)
{
// When a visitor subscribes to a topic link the Topic object in a lookup array
$subject = $topic->getId();
$ip = $conn->remoteAddress;
if (!array_key_exists($subject, $this->subscribedTopics))
{
$this->subscribedTopics[$subject] = $topic;
}
$this->clients[] = $conn; // you add connection to the collection
$conn->send("Hello new user!"); // you send a message only to this one user
}
I've written a twitter api application using the following tutorial:
http://www.youtube.com/watch?v=GQaPt-gQVRI
How can I modify the script to generate a timeline stream that is specific to a user so that the application when run will show user's timeline stream and not mine (since i wrote the app and therefore it has my twitter credentials)
Thanks
the php application validates my twitter credentials using the following:
<?php
require 'tmhOAuth.php'; // Get it from: https://github.com/themattharris/tmhOAuth
// Use the data from http://dev.twitter.com/apps to fill out this info
// notice the slight name difference in the last two items)
$connection = new tmhOAuth(array(
'consumer_key' => 'my key',
'consumer_secret' => 'my secret',
'user_token' => 'my token', //access token
'user_secret' => 'my user secret' //access token secret
));
// set up parameters to pass
$parameters = array();
if ($_GET['count']) {
$parameters['count'] = strip_tags($_GET['count']);
}
if ($_GET['screen_name']) {
$parameters['screen_name'] = strip_tags($_GET['screen_name']);
}
if ($_GET['twitter_path']) { $twitter_path = $_GET['twitter_path']; } else {
$twitter_path = '1.1/statuses/user_timeline.json';
}
$http_code = $connection->request('GET', $connection->url($twitter_path), $parameters );
if ($http_code === 200) { // if everything's good
$response = strip_tags($connection->response['response']);
if ($_GET['callback']) { // if we ask for a jsonp callback function
echo $_GET['callback'],'(', $response,');';
} else {
echo $response;
}
} else {
echo "Error ID: ",$http_code, "<br>\n";
echo "Error: ",$connection->response['error'], "<br>\n";
So without having to pass a new username in the api call, how can i add a snippet to require the user to log in? and if i add that snippet for the user to log in, will the api automatically populate the authentication strings with the user's?
You can send a get request to the following url to get a users timeline.
https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi&count=2
You can replace the parameters screen_name with the username you want to access, and you can replace count with the number of tweets you would like to get, count is optional and doesn't have to be included.
You can read more about statuses/user_timeline on the office twitter API site: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
If you wish to get a user to sign in then your best bet would be to use the twitteroauth library by abraham
Download and include in your project, then include the library and start a session.
require("twitteroauth/twitteroauth.php");
session_start();
Then create a new instance and authenticate with your app details. You can set a url to redirect to when the user authenticates. You also need to cache your tokens.
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET');
$request_token = $twitteroauth->getRequestToken('http://example.com/loggedin.php');
$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
Redirect the user to twitter to authenticate
header('Location: '.$twitteroauth->getAuthorizeURL($request_token['oauth_token']));
In the file that you set twitter to redirect to you need to re-authenticate using the tokens created. Twitter will also add a parameter to your url which you use to create a access token for that user. Now when you send GET requests to twitter, it does it on behalf of the user logged in.
require("twitteroauth/twitteroauth.php");
session_start();
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
$user_info = $twitteroauth->get('account/verify_credentials');
print_r($user_info);
You can get additional details from $user_info which you can cache or store in a database, which will allow you to remember users that have already authenticated. You will need to use oauth_token and oauth_secret, something like this.
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', 'OAUTH_TOKEN', 'OAUTH_SECRET');