Writing a subscribe method of RabbitMQ in PHP - php

I have a function as defined below:
public function subscribe($someQueue)
{
$callback = function($msg){
return $msg->body;
};
$this->channel->basic_consume( $someQueue, '', FALSE, TRUE, FALSE, FALSE, $callback);
while(count($this->channel->callbacks)) {
$this->channel->wait();
}
}
I'm using the following function:
Note: Following lines are in a different class file, hence creating object of the class that contains the above function.
$objRMQ = new RabbitMQ();
$msgBody = $objRMQ->subscribe("someQueue");
echo "message body returned from someMethod: ".$msgBody;
Basically, I want to return body of every message to the caller function that is published to the queue.
Current output:
message body returned from subscribe: NULL
Expected output:
holla, this is your message from queue

Since this question is old but still unanswered, I'll give a brief explanation. You've probably already figured out the answer by now, but this might help someone else searching in future.
The key concept here is "asynchronous execution".
When you subscribe to a channel using the basic_consume method, you are not asking for the callback to be executed once, immediately, but for it to be executed once a message becomes available, and then every time another message is available.
In the case of AMQPLib, you wait for new messages by repeatedly calling the wait() method; i.e. here:
while(count($this->channel->callbacks)) {
$this->channel->wait();
}
Thinking about this carefully, there are two mistakes in your code:
The line return $msg->body has nowhere to return to. The call will happen somewhere deep in the implementation of the wait() method, and you get no output from $this->channel->wait(), so have no way of doing anything with that returned value.
On the other side, when you call $objRMQ->subscribe("someQueue") from your other class, you are expecting it to return something, but that function has no return statement. The only return statement is inside the anonymous function you passed to basic_consume.
The solution is basically to do all your processing of the message - echo $msg->body, or whatever real processing you want to do - inside the callback. If you really want to gather data as messages come in, you could save it to some variable accessible outside the callback, but remember that you will at some point need to break out of the wait() loop in order to do anything with that data.

Related

what is the difference between return redirect('/') and Redirect::to('/')->send(); function in laravel

First code working. See Below
The second code not working. See Below
Anyone can help provide the documentation for this code Redirect::to('/')->send();
The ->send() method should only be used in places where you cannot return a response directly. And even then, it should be used as few times as possible.
Normally, a request will go through a list of middlewares, end up in a controller which will return a response and exit through another list of middlewares. This is the normal way of returning a response.
When you use the send() function, you interrupt the pipeline and send the response back immediately.
Now, the reason only send() works in your case is because you are redirecting from a constructor and a constructor cannot have a return value. Because of this, the second example will never work.
I would encourage you to use a middleware for this check instead. This way the check is reusable and you can return a redirect response without interrupting the pipeline.

Testing method with no output

I have the following method I want to test:
class SomeObject {
public function actionFromSomeController() {
$obj = new OtherObject();
$obj -> setAttributes();
$obj -> doAction();
}
}
class OtherObject {
private $_attr;
public function setAttributes() {
$this -> _attr = 'something';
Database :: execute('INSERT INTO table VALUES (' . $this -> _attr . ')');
$fileObj = new FileObj();
$content = $fileObj -> getSomeFileContent();
// do something else
}
public function doAction() {
echo $this -> _attr;
}
}
Now I want to test this method, its output depends on database content and one file on the server. It does a lot of things on the way, and the output is just one ID and success => 1.
How should I test it properly?
Some ideas on how to test small code pieces like this:
Generate test-data and pass it to your methods (also, fake database return data or file contents)
Use echo / var_dump() / die() to check property and variable content at different positions in your methods
Also use these commands to check whether execution reaches a certain point (for example to see whether a function got called or not)
If something doesn't work as expected without an error message: Check line by line with the above methods until you find the problem
Consider using interfaces and dependency injection if your code gets bigger - this is a bit over-the-top for this amount of code, but can be a tremendous time-saver when your application becomes big
Testing is never an automatic process and you will always have to think about what makes sense to do and what not. These things to do are never magic but basic PHP.
You should consider letting your scripts throw errors/exceptions if something goes wrong. Writing "silent" applications is almost never good since you can, if you really need a silent execution for production environments, just turn off error reporting and have the same effect. Many PHP functions return something special on failure and/or success and you can check for this. Database handlers do so, too. Do yourself a favor and use these return values!

PDO sets server response code?

I'm making an ajax query to a framework that we use. I am unable to set the server response code except by setting it where the PDO execute method is called.
The pattern works like this:
An ajax query runs, posting to a file, action.php, that validates inputs. If inputs are valid, we call a function in the business logic (application.php), which then calls the underlying PDO insert/save method. If we get a good save, we return TRUE in our action.php function.
In my ajax call, I have a .done() function that confirms the save took place by checking xhr.status. I want to set xhr.status to 201 when we have a successful save, by calling http_response_code(201);. This works if I actually do so in the PDO layer, right after the execute() method, but I can't get it to work anywhere else. Obviously, that is not the right place to set a response code.
Sorry the question is so abstract. Here is a little example of the code that isn't working:
$resInfo = new ResInfo();
if($resInfo = saveResident()){
http_response_code(201);
}
return true;
The response code is not set here. Instead, it is set in the PDO method that saveResident() calls.
Anyone else ever have a similar issue?
EDIT:
I realized that saveResident() returns a copy of the saved object rather than a boolean, so I needed to separate the call to it from persisting the saved object:
if(saveResident()){
$resInfo = saveResident();
http_response_code(201);
}
If you say:
it works within saveResident()
saveResident() runs successfully.
And not right after in that if statement.
I would guess that saveResident returns false, an empty array or nothing at all. $resInfo is not used after all.

How to organize server side ajax scripts

Much of my work lately has involved expanding and bug fixing ajax actions. But the action lists are fairly unmanageable in size, and since I was not the original author and the comments are sparse, I spend a great deal of time tracing the code paths and trying to figure out which jquery event triggered the action and if it sent the proper data with the request.
Right now the ajax request scripts are basically just about a hundred if-else blocks split up into different files based loosely on their function.
Is there a relevant design pattern or a php idiom to help me better organize the php part of the ajax requests?
I was thinking of maybe making some sort of dispatch interface. (Don't know if it is a good or workable idea.) where I can register actions and somehow indicate what data they require. The dispatcher would then call the function from the appropriate place. Then I could route all ajax requests through a single script and organize my functions however I want. And I can have an overview of what data is required to call a certain action without reading its implementation line by line. I would potentially have access to my server-side class heirarchy from the client side.
Does this sound workable? Is this safe? Are there other ways that might work better? The inspiration for this was basically smalltalk style message passing. My major worry is that I am going to introduce a cross-side request forgery vulnerability or that there is already one present in the code and due to it being difficult to read, I missed it.
I use a RPC-style mechanism to achieve what I think you want.
Disclaimer: I've successfully implemented this scheme in JS+PHP and JS+Python, so it is workable. But it might not be secure. You have to take all appropriate verification steps to make sure it is secure (especially w.r.t. to code/SQL injection and XSS attacks)
The idea is to have a single PHP script that processes the RPC requests, receiving the method name and its argument through both GET and POST, and outputs JSON back to the Javascript side.
For instance, on the client side:
API.rpc('getItemById', 1532, function(item) { console.log(item); });
would write
Object(id=1532,name="foo",whatever="bar")
on the console.
The communication protocol I use is the following:
the client sends an HTTP request to the RPC handler script, using
either GET or POST. The restrictions are that the 'method' must
always be provided in the GET, and that all arguments must be
URL-encoded. Otherwise, all arguments are given as key=value pairs and can be part of the request (GET) or the payload (POST)
the server always responds with an HTTP 200 (otherwise it means that a very nasty thing happened). It responds only with JSON data. The returned object has at least 2 members.
the 'success' member is always there, and indicates if the call succeeded - i.e. that no exception was thrown
if successful, the 'ret' members contains the return value of the function
if an exception was thrown, the 'message' member contains the exception message (I prefer sending the whole backtrace here, but that's certainly not good for sensitive environments)
(1) On the javascript side (assuming jQuery, coding as I think, so this may be buggy):
API = function() {
this.rpc = function(method, args, callback) {
return $.ajax({
url: 'rpcscript.php?method='+encodeURIComponent(args.method),
data: args,
type: 'post', //only the method name is sent as a GET arg
dataType: 'json'
error: function() {
alert('HTTP error !'); // This is e.g. an HTTP 500, or 404
},
success: function(data) {
if (data.success) {
callback(data.ret);
} else {
alert('Server-side error:\n'+data.message);
}
},
});
}
}
You can then add shortcut functions such as syncRPC() to perform synchronous calls, etc.
(2) On the PHP side (slightly modified running code):
class MyAPI
{
function getItemById($id)
{
// Assuming the $db is a database connection returning e.g. an associative array with the result of the SQL query. Note the (int) typecast to secure the query - all defensive measures should be used as usual.
return $db->query("SELECT * FROM item WHERE id = ".(int)$id.";");
}
}
class RemoteProcedureCall
{
function __construct()
{
$this->api = new MyAPI();
}
function serve()
{
header("Content-Type: application/json; charset=utf-8");
try
{
if (!isset($_GET['method']))
throw new Exception("Invalid parameters");
$methodDesc = array($this->api, $_GET['method']);
if (!method_exists($methodDesc[0], $methodDesc[1]) || !is_callable($methodDesc))
throw new Exception("Invalid parameters");
$method = new ReflectionMethod($methodDesc[0], $methodDesc[1]);
$params = array();
foreach ($method->getParameters() as $param)
{
// The arguments of the method must be passed as $_POST, or $_GET
if (isset($_POST[$param->getName()]))
// OK, arg is in $_POST
$paramSrc = $_POST[$param->getName()];
elseif (!in_array($param->getName(),array('action','method'))
&& isset($_GET[$param->getName()])
&& !isset($paramSrc[$param->getName()]))
// 'action' and 'method' are reserved $_GET arguments. Arguments for the RPC method
// can be any other args in the query string, unless they are already in $_POST.
$paramSrc = $_GET[$param->getName()];
if (!isset($paramSrc))
{
// If the argument has a default value (as specified per the PHP declaration
// of the method), we allow the caller to use it - that is, not sending the
// corresponding parameter.
if ($param->isDefaultValueAvailable())
$p = $param->getDefaultValue();
else
throw new Exception("Invalid parameters");
}
else
{
$p = $paramSrc;
}
$params[$param->getName()] = $p;
unset($paramSrc);
}
$ret = $method->invokeArgs($db, $params);
echo json_encode(array('success' => true, 'ret' => $ret));
}
catch (Exception $e)
{
echo json_encode(array('success' => false, 'message' => $e->getMessage()."\n".$e->getBacktrace()));
}
}
};
$rpc = RemoteProcedureCall();
$rpc->serve();
There are many application-specific assumptions here, including the kind of exceptions that may be thrown, the reserved keywords, etc ...
Anyway I hope this provides a good starting point for your problem.
You can have a look here: http://www.phpapi.org/
From description:
"This is the skeleton upon which you can develop a web-system from a simple Web Calculator to the most sofisticated CRM/ERP/CMS/ETC. What PHP-API provides is: a general structure of the code, a very simple extendable API code structure,JavaScript connectivity with the API ( with an easy way of adding new modules/method handlers ), ...."

Gearman & PHP: Proper Way For a Worker to Send Back a Failure

The PHP docs are a bit fuzzy on this one, so I'm asking it here. Given this worker code:
<?php
$gmworker= new GearmanWorker();
$gmworker->addServer();
$gmworker->addFunction("doSomething", "doSomethingFunc");
while($gmworker->work());
function doSomethingFunc()
{
try {
$value = doSomethingElse($job->workload());
} catch (Exception $e) {
// Need to notify the client of the error
}
return $value;
}
What's the proper way to notify the client of any error that took place? Return false? Use GearmanJob::sendFail()? If it's the latter, do I need to return from my doSomethingFunc() after calling sendFail()? Should the return value be whatever sendFail() returns?
The client is using GearmanClient::returnCode() to check for failures. Additionally, simply using "return $value" seems to work, but should I be using GearmanJob::sendData() or GearmanJob::sendComplete() instead?
This may not the be the best way to do it, but it is the method i have used in the past and it has worked well for me.
I use sendException() followed by sendFail() in the worker to return a job failure. The exception part is optional but i use it so the client can error and know roughly why it failed. After the sendFail I return nothing else.
As an example this is a the method that the worker registers as the callback for doing work:
public function doJob(GearmanJob $job)
{
$this->_gearmanJob = $job;
try{
//This method does the actual work
$this->_doJob($job->functionName());
}
catch (Exception $e) {
$job->sendException($e->getMessage());
$job->sendFail();
}
}
After sendFail() do not return anything else, otherwise you may get strange results such as the jobserver thinking the job ended ok.
As regards returning data, i use sendData() if i am returning data in chunks (such as streaming transcoded video, or any 'big' data where i don't want to move around one large blobs) at various intervals during my job with a sendComplete() at the end. Otherwise if I only want to return my data in one go at the end of the job I only use sendComplete().
Hope this helps.

Categories