PHP NATS sending result out of the function - php

I am having some trouble regarding PHP NATS. I am getting and printing msg body values. Everything is working fine. Just returning result is the problem. Here is the code
function connect(){
require_once __DIR__ . "/../../vendor/autoload.php";
$connectionOptions = new \Nats\ConnectionOptions();
$connectionOptions->setHost('localhost')->setPort(4222);
$c = new Nats\Connection($connectionOptions);
$c->connect();
$c->request('sayhello', 'Marty McFly', function ($response) {
echo $response->getBody();
return $response->getBody();
});
}
echo is working and printing values, while return isn't returning anything if I use like this.
$res = connect():
print_r($res);

You are echoing from the scope of the anonymous function, and returning from the scope of connect() function.
One approach you can take is callback, you can make your function to take a Closure as an argument and run it from within connect() with the result as an argument:
function connect(\Closure $callback){
require_once __DIR__ . "/../../vendor/autoload.php";
$connectionOptions = new \Nats\ConnectionOptions();
$connectionOptions->setHost('localhost')->setPort(4222);
$c = new Nats\Connection($connectionOptions);
$c->connect();
$c->request('sayhello', 'Marty McFly', function ($response) use ($callback) {
echo $response->getBody();
$callback(response->getBody());
});
}
And you would use it as follows:
connect(function ($result) {
// here you've got an access to the $response->getBody() from connect function
});

Related

send TCP message in loop

I am trying to send a tcp message in a script with reading from stdin in a loop. The problem is that the server only receives the connection, not the message. Everything works if I remove the loop.
#!/bin/php
<?php
use React\Socket\ConnectionInterface;
use React\Socket\TcpConnector;
require dirname(__DIR__) . '/vendor/autoload.php';
while (true) {
$line = trim(fgets(STDIN));
echo "try to send $line\n";
try {
$client = new TcpConnector();
$client
->connect('tcp://127.0.0.1:8080')
->then(
function (ConnectionInterface $connection) use ($line) {
echo "fulfilled\n";
$connection->write($line);
$connection->end();
},
function () {
echo "rejected\n";
},
function () {
echo "onProgress\n";
}
);
} catch (Throwable $e) {
echo $e->getMessage();
}
// break; // work with this break
}
with this code, when I send
./console.php
foo
try to send foo
bar
try to send bar
On the server side :
new connection: tcp://127.0.0.1:40936
new connection: tcp://127.0.0.1:40944
If I remove the loop :
./console.php
foo
try to send foo
fulfilled
Note: work great with telnet
Ok, some question about ratchet in a loop tel me the answer.
The loop wait the end of script before run... It never happen in this case.
We need to run $loop->run() at the right time.
The corrected code :
#!/bin/php
<?php
use React\EventLoop\Loop;
use React\Socket\ConnectionInterface;
use React\Socket\TcpConnector;
require dirname(__DIR__) . '/vendor/autoload.php';
while (true) {
$line = trim(fgets(STDIN));
echo "try to send $line\n";
try {
$loop = Loop::get();
$client = new TcpConnector($loop);
$client
->connect('tcp://127.0.0.1:8080')
->then(
function (ConnectionInterface $connection) use ($line) {
echo "fulfilled\n";
$connection->write($line);
$connection->end();
},
function () {
echo "rejected\n";
},
function () {
echo "onProgress\n";
}
);
$loop->run();
} catch (Throwable $e) {
echo $e->getMessage();
}
}
I think your solution fits your use case, just beware that $line = trim(fgets(STDIN)); will always block your code, because it waits on your input.
To simplify your example a bit more:
#!/bin/php
<?php
use React\EventLoop\Loop;
use React\Socket\ConnectionInterface;
use React\Socket\TcpConnector;
require dirname(__DIR__) . '/vendor/autoload.php';
while (true) {
$line = trim(fgets(STDIN));
echo "try to send $line\n";
$loop = Loop::get();
$client = new TcpConnector($loop);
$client
->connect('tcp://127.0.0.1:8080')
->then(
function (ConnectionInterface $connection) use ($line) {
echo "fulfilled\n";
$connection->write($line);
$connection->end();
},
function () {
echo "rejected\n";
}
);
$loop->run();
}
Your try-catch does actually nothing here, so you won't need it. This is because of the promise behavior in ReactPHP. If an exception is thrown inside a promise, you can only see it if you explicitly catch it or define a behavior if the promise gets rejected, e.g. like this:
// your reject
function () {
echo "rejected\n";
}
// my suggested reject
function (Exception $error) {
echo 'Error: ' . $error->getMessage() . PHP_EOL;
}
You can also take a look at https://github.com/clue/reactphp-stdio as an alternative approach for your use case.

My laravel API only returns empty curly bracket

This is the response I get when making a get request to my API
enter image description here
The code below is my current code
function getDNSData(string $domain)
{
$dns = new Dns();
try {
$records = json_encode($dns->getRecords($domain));
return $records;
} catch(CouldNotFetchDns $e) {
dd($e);
return ["errors" => $e];
}
}
I used die dump function to check if data was being passed through correctly and that worked
Using json_decode i couldnt get it to work either
diedumpResult

Array to string conversion SOAP

So i have the following soap function , i call it in my code a few times , but it gives me the notice of an array to string conversion on line 5.
public function soap($login,$functionName,$api_key,$params,$optional = array(),$n=1){
try{
$client = new SoapClient('http://4dealer.ru/soap/?WSDL');
$hash = md5($login . $functionName . md5($api_key));
$result = $client->$functionName($login,$hash,$params,$optional);
}catch (SoapFault $E){
if($n<3){
sleep(1);
return $this->soap($login,$functionName,$api_key,$params,$optional,$n+1);
}
}
return $result;
}
can you put your call code ? the 5 line is:
$client->$functionName
you should see what are you passing to method that make this error

Cannot redeclare class in PHP error

new to PHP. Using the SLIM framework and the routing has been tested and is working fine. Have two files index.php and API.php. index.php is:
<?php
require 'vendor/autoload.php';
require_once 'API.php';
//Turn on error checking
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);
//Create a new SLIM app
$app = new \Slim\Slim();
$app->response->headers->set('Content-Type', 'application/json');
$app->get('/', function() use($app) {
$app->response->setStatus(200);
echo "InstaAPI\n";
});
$app->run();
?>
API is:
<?php
class DbHandler{
protected static $conn;
function __construct() {
//Static self notation is different
if(!isset(self::$conn)) {
//same as self.connect
$this->connect();
}
}
function __destruct(){
if(isset(self::$conn)){
self::$conn->close();
}
}
function connect(){
$config = parse_ini_file('../../config2.ini');
// Try and connect to the database
self::$conn = mysqli_connect('localhost',$config['username'],$config['password'],$config['dbname']);
if(self::$conn===FALSE) {
header("HTTP/1.1 500 Internal Server Error");
header("Content-Type: application/json");
$response = array("Response"=>"Failed to connect to the database");
echo json_encode($response);
die();
}
else{
echo "Fine!!";
}
}//end connect
}//end class
?>
I am getting the error: PHP Fatal error: Cannot redeclare class DbHandler in ../API.php on line 62. Not sure why this is happening. I am using require_once and still getting the same error. Could someone give me some pointers to what I might be doing wrong please?
the code of Api.php is less than 62 lines. looks like there is extra code below it. consider deleting extra lines

How to prevent ob_start() output when an error occur?

Please, consider the following example:
template.php:
<?php
echo $vars['arr'];
echo " -------- ";
echo $vars['obj'];
?>
test.php:
<?php
$file = "template.php";
$vars = array( 'arr' => array(), 'obj' => new StdClass() );
var_dump( json_encode($vars) );
function loadFile($file, $vars)
{
try
{
if (is_array($vars) && !empty($vars)) {
extract($vars);
}
ob_start();
include $file;
return ob_get_clean();
}
catch (Exception $e)
{
return false;
}
}
loadFile($file, $vars);
?>
This code will output:
string(19) "{"arr":[],"obj":{}}"
PHP Catchable fatal error: Object of class stdClass could not be converted to string in template.php
The problem here is, in the template.php I am considering $vars to be an array() however 1 of the elements is an Object as you can see from the json output.
Adding a simple checking in the template to verify if the ekement is an array or not would solve the problem, however I would need to this to multiple elements, elements, so, not very good =) so, I trying to find a way to prevent the error in the moment of binding the template and $vars.
Thank you
simply turn error_reporting off while parsing:
$old_level = error_reporting(0); // no errors, preserve old error reporting level
ob_start();
include $file;
$content = ob_get_clean();
error_reporting($old_level); // reset error reporting level
return $content;
Note: This will only hide errors that aren't very critical.
In order to catch a Catchable Fatal Error, see this question: How can I catch a "catchable fatal error" on PHP type hinting?
You need to register an error handler using set_error_handler:
function handleError($errno, $errstr, $errfile, $errline) {
// handle error
// return true, so the normal php handler doesn't get called
return true;
}
set_error_handler('handleError');
If you want to integrate you handler cleanly into other code which also sets error_handlers, you might consider restoring the error handler afterwards using restore_error_handler
You might try checking to see if the values are an object first, and then using the PHP function to convert to an array.
Note, this section of your code:
if (is_array($vars) && !empty($vars)) {
extract($vars);
}
After that, if I'm reading your code correctly, you have a variable possibly called $vars that could be an object. So, you could do this:
if (is_object($vars)) {
$vars = get_object_vars($vars);
}
That should convert it to what you need. Of course, you may need to experiment a bit to make sure it fits your scenario. Thanks!
You can use __toString() method in your class to avoid the error. You can set the __toString() method with any value you need, maybe return an array.
http://www.php.net/manual/en/language.oop5.magic.php#object.tostring
Another option, is use array_walk :
function checkObj(&$vars){
if (is_object($vars)) {
$vars = get_object_vars($vars);
}
}
array_walk($vars, "checkObj");
Since you are using ob_start(), you can pass it a call-back that will check for any errors. It should even work with fatal errors. Inside your call-back use something like "error_get_last" to check for any error and just return false if it's not null, like so:
WARNING: I've not tested this code, but I use something similar myself.
<?php
$file = "template.php";
$vars = array( 'arr' => array(), 'obj' => new StdClass() );
var_dump( json_encode($vars) );
function loadFile($file, $vars)
{
try
{
if (is_array($vars) && !empty($vars)) {
extract($vars);
}
ob_start('errorHandler');
include $file;
return ob_get_clean();
}
catch (Exception $e)
{
return false;
}
}
function errorHandler($pBuffer)
{
$lastError = error_get_last();
// Uh-oh, an error has occurred.
if ($lastError !== NULL)
{
return FALSE;
}
// No problems.
return $pBuffer;
}
loadFile($file, $vars);
?>

Categories