I want to connect to IBM Bluemix through the MQTT protocol using PHP to subscribe to messages come from IoT Foundation.
I use this code:
<?php
require("../phpMQTT.php");
$config = array(
'org_id' => 't9m318',
'port' => '1883',
'app_id' => 'phpmqtt',
'iotf_api_key' => 'my api key',
'iotf_api_secret' => 'my api secret',
'device_id' => 'phpmqtt'
);
$config['server'] = $config['org_id'] .'.messaging.internetofthings.ibmcloud.com';
$config['client_id'] = 'a:' . $config['org_id'] . ':' .$config['app_id'];
$location = array();
// initialize client
$mqtt = new phpMQTT($config['server'], $config['port'], $config['client_id']);
$mqtt->debug = false;
// connect to broker
if(!$mqtt->connect(true, null, $config['iotf_api_key'], $config['iotf_api_secret'])){
echo 'ERROR: Could not connect to IoT cloud';
exit();
}
$topics['iot-2/type/+/id/phpmqtt/evt/+/fmt/json'] =
array("qos"=>0, "function"=>"procmsg");
$mqtt->subscribe($topics, 0);
// process messages
while ($mqtt->proc(true)) {
}
// disconnect
$mqtt->close();
function procmsg($topic, $msg) {
echo "Msg Recieved: $msg";
}
?>
But the browser show this message:
Fatal error: Maximum execution time of 30 seconds exceeded in /Library/WebServer/Documents/phpMQTT/phpMQTT.php on line 167
subscribe is not meant to run in the web browser as it has an infinite look, its best being run from the command line.
If you are using the subscribe method to receive messages you can look at persistent msgs and breaking out of the loop on msg receipt.
There is an example of how to use phpMQTT in the web browser in the file
web-app.php of this respository https://github.com/vvaswani/bluemix-iotf-device-tracker
You don't provide very much information about what you want to achieve by doing this; do you want to keep sending messages to the browser until the page is closed in the browser?
Server Sent Events or Websockets might be a better bet, and PHP might not be the best choice for this, because it uses up quite a lot of memory per connection (compared to node.js for example).
However if you just want to remove the 30 second PHP timeout, then you can use this function:
http://php.net/manual/en/function.set-time-limit.php
Or set max_execution_time in php.ini:
http://php.net/manual/en/info.configuration.php
Setting the maximum execution time to 0 should stop it from timing out.
But be warned that PHP and/or your webserver will have a limited number of concurrent HTTP connections.
Related
Environment/Background:
Using PHP Stomp library to send and receive message from ActiveMQ (v5.4.3).
Steps:
Client sends a message with reply-to & correlation-id headers to request queue (say /queue/request)
Subscribe to the response queue (say /queue/response)
Read frame
ack
unsubscribe
The above steps works fine when there is no pending message or pending message < n. In my case, n =200. When the number of pending message is > 200, the message is not delivered. The process waits till timeout and finally timeout without response. I can see the message (using admin UI) after timeout. Here is the code that I'm using for this case:
<?php
// make a connection
$con = new Stomp("tcp://localhost:61616");
// Set read timeout.
$con->setReadTimeout(10);
// Prepare request variables.
$correlation_id = rand();
$request_queue = '/queue/com.domain.service.request';
$response_queue = '/queue/com.domain.service.response';
$selector = "JMSCorrelationID='$correlation_id'";
$headers = array('correlation-id' => $correlation_id, 'reply-to' => $response_queue);
$message = '<RequestBody></RequestBody>';
// send a message to the queue.
$con->send($request_queue, $message, $headers);
// subscribe to the queue
$con->subscribe($response_queue, array('selector' => $selector, 'ack' => 'auto'));
// receive a message from the queue
$msg = $con->readFrame();
// do what you want with the message
if ( $msg != null) {
echo "Received message with body\n";
var_dump($msg);
// mark the message as received in the queue
$con->ack($msg);
} else {
echo "Failed to receive a message\n";
}
unset($con);
Other findings:
Sending messages from one file (say from sender.php) and receive using another script (say receiver.php) working fine.
Allows to send more than 1000 message in the same request queue(and eventually processed and placed in response queue). So it doesn't look like memory issue.
Funny enough, while waiting for timeout, if I browse the queue on admin UI, I get the response.
By default, the stomp broker that I use set the prefetch size to 1.
Without knowing more my guess is that you have multiple consumers and one is hogging the messages in it's prefetch buffer, the default size is 1000 I think. To debug situations like this it's usually a good idea to look at the web console or connect with jconsole and inspect the Queue MBean to see the stats for in-flight messages, number of consumers etc.
Answering my own question.
The problem I'm facing is exactly what is described in http://trenaman.blogspot.co.uk/2009/01/message-selectors-and-activemq.html and the solution is to increase the maxPageSize as specified in ActiveMQ and maxPageSize
As you can match that the 200 is not a varying number, but the default value of maxPageSize.
More references:
http://activemq.2283324.n4.nabble.com/Consumer-is-not-able-to-pick-messages-from-queue-td2531722.html
https://issues.apache.org/jira/browse/AMQ-2217
https://issues.apache.org/jira/browse/AMQ-2745
After a user signs up on my website i need to send a soap request in a method that is not blocking to the user. If the soap server is running slow I don't want the end user to have to wait on it. Is there a way I can send the request and let my main PHP application continue to run without waiting from a response from the soap server? If not, is there a way to set a max timeout on the soap request, and handle functionality if the request is greater than a max timeout?
Edit:
I would ideally like to handle this with a max timeout for the request. I have the following:
//ini_set('default_socket_timeout', 1);
$streamOptions = array(
'http'=>array(
'timeout'=>0.01
)
);
$streamContext = stream_context_create($streamOptions);
$wsdl = 'file://' . dirname(__FILE__) . '/Service.wsdl';
try{
if ( file_get_contents( $wsdl ) ) {
$this->_soapClient = new SoapClient($wsdl,
array(
'soap_version' => SOAP_1_2,
'trace' => true,
'stream_context' => $streamContext
)
);
$auth = array('UserName' => $this->_username, 'Password' => $this->_password);
$header = new SoapHeader(self::WEB_SERVICE_URL, "WSUser", $auth);
$this->_soapClient->__setSoapHeaders(array($header));
}//if
}
catch(Exception $e){
echo "we couldnt connect". $e;
}
$this->_soapClient->GetUser();
I set the timeout to 0.01 to try and force the connection to timeout, but the request still seems to fire off. What am I doing wrong here?
I have had the same issues and have implemented solution !
I have implemented
SoapClient::__doRequest();
To allow multiple soap calls using
curl_multi_exec();
Have a look at this asynchronous-soap
Four solutions:
Use AJAX to do the SOAP -> Simplest SOAP example
Use AJAX to call a second PHP file on your server which does the SOAP (best solution imo)
Put the SOAP request to the end of your PHP file(s) (not the deluxe solution)
Use pcntl_fork() and do everything in a second process (I deprecate that, it might not work with every server configuration)
Depending on the way you implement this, PHP has plenty of timeout configurations,
for example socket_set_timeout(), or stream_set_timeout() (http://php.net/manual/en/function.stream-set-timeout.php)
I'm using a web service to send SMS in PHP. The code in like below:
$options = array(
'login' => 'yourusername',
'password' => 'yourpassword'
);
$client = new SoapClient('http://sms.hostiran.net/webservice/?WSDL', $options);
try
{
$messageId = $client->send(destination mobile number, 'test sms');
sleep(3);
print ($client->deliveryStatus($messageId));
var_dump($client->accountInfo());
}
catch (SoapFault $sf)
{
print $sf->faultcode."\n";
print $sf->faultstring."\n";
}
The problem is that when i run this code on a WAMP server, it runs rapidly.But when i use this code in an ubuntu server, the speed of running this code is very low.
Is there any configuration in php.ini to solve this problem ?
Thanks!
First, you need to remove sleep(3). That makes it take an extra 3 seconds.
Second, it looks like the sms provider is in Iran so it'd be best for you to get a web server in Iran.
As far as I know there is no reason why a Ubuntu server would be slower at SOAP than a Windows server
If you want to try and speed up the webpage what you should do is instead of running the SOAP request on page load you save the request to a database and then have a cron that runs every few minutes, pulls the requests out of the database, and makes the request.
I'm establishing an SMPP connection via PHP using this free library. To receive a message, I'm using the following code, given in the example:
<?php
$GLOBALS['SMPP_ROOT'] = dirname(__FILE__); // assumes this file is in the root
require_once $GLOBALS['SMPP_ROOT'].'/protocol/smppclient.class.php';
require_once $GLOBALS['SMPP_ROOT'].'/transport/tsocket.class.php';
// Construct transport and client
$transport = new TSocket('your.smsc.com',2775);
$transport->setRecvTimeout(60000); // for this example wait up to 60 seconds for data
$smpp = new SmppClient($transport);
// Activate binary hex-output of server interaction
$smpp->debug = true;
// Open the connection
$transport->open();
$smpp->bindReceiver("USERNAME","PASSWORD");
// Read SMS and output
$sms = $smpp->readSMS();
echo "SMS:\n";
var_dump($sms);
// Close connection
$smpp->close();
?>
It works perfectly well, when I run the script in the browser window and send the SMS from my phone within given 60 seconds, but I don't quite understand how to make it work for a long time. I mean, like in real-life situation, when it should run on the background and trigger some events when receiving an SMS. How do I do that? Because now, I need to refresh the page every time to get an SMS, and it only works once. Thanks in advance.
If your solution needs to run within a browser, you shouldn't connect to the SMPP server directly from your script. It would lead to a single user scenario.
You should put a endless loop around the readSMS call and make it a console application which runs as a daemon. Then you write the result of readSMS into a database and read this from your web application. With this you could use html refresh or some fancy ajax querying the database and presenting the incoming sms.
Usually SMPP receiver connections run in blocking mode on the socket (no timeout), because either you receive either a SMS, or an enquire_link (which needs to be answered by a enquire_link_resp - your library does this automatically). Whenever you read a SMS, process it (put it in the database) and call readSMS again - it will block until the next SMS comes in.
You can try this.
<?php
set_time_limit(0);
$GLOBALS['SMPP_ROOT'] = dirname(__FILE__); // assumes this file is in the root
require_once $GLOBALS['SMPP_ROOT'].'/protocol/smppclient.class.php';
require_once $GLOBALS['SMPP_ROOT'].'/transport/tsocket.class.php';
// Construct transport and client
$transport = new TSocket('your.smsc.com',2775);
$transport->setRecvTimeout(60000); // for this example wait up to 60 seconds for data
$smpp = new SmppClient($transport);
// Activate binary hex-output of server interaction
$smpp->debug = true;
// Open the connection
$transport->open();
$smpp->bindReceiver("USERNAME","PASSWORD");
while(1) {
// Read SMS and output
$sms = $smpp->readSMS();
echo "SMS:\n";
var_dump($sms);
}
// Close connection
$smpp->close();
?>
Try to use another library
composer require glushkovds/php-smpp
To receive sms:
<?php
require_once 'vendor/autoload.php';
$service = new \PhpSmpp\Service\Listener(['your.smsc.com'], 'login', 'pass');
$service->listen(function (\PhpSmpp\SMPP\Unit\Sm $sm) {
if ($sm instanceof \PhpSmpp\Pdu\DeliverSm) {
var_dump($sm->message);
}
});
I'm bulding a PHP client (I have already a C# client) as proof of concept. The PHP client will connect with the same .NET server using SOAP. As example I'm using the game blackjack.
Now first the C# client works perfect, but there is an issue in the PHP. After much debugging I found out that PHP always uses a new connection for every remote server call. This makes it impossible to program a game.
For example, I have a PHP file that just sets up the client like this (client.php):
try {
$client = #new soapClient("http://localhost:8000/BlackJack/Service?wsdl",
array(
"trace" => 1,
"exceptions" => 0,
"cache_wsdl" => 0)
);
} catch (Exception $e) {
print 'Caught exception: ' . $e->getMessage() . "\n";
}
Then in my main file (ill be using jQuery and ajax calls to load it dynamically but now im just testing) I have the following code (blackJackClient.php):
require_once("client.php");
$ini = ini_set("soap.wsdl_cache_enabled","0");
$BetAmountPost = 100;
print_r($result = $client->buttonDeal_Click(array("BetAmount" => (string)$BetAmountPost))->buttonDeal_ClickResult);
print_r($result = $client->PlayerMoney()->PlayerMoneyResult);
The first call will start a new game (Deal) and the player his bet amount (for example 100) gets subtracted from the total amount (1000). So what do I get returned in result is money = 900.
The following commando will ask what money I currently have, and one expects to get returned 900, but no instead I have 1000 (my starting amount).
So my question is how can I make it that all call's are made in 1 session so we still use the same connection?
Thanks!
Since SOAP uses the HTTP protocol, and HTTP is stateless, there is no way to keep your connection open during the session of the game.
Instead, you should send your user's authentication with every request to the server.