don't have enough reputation to tag this properly (ruby,PHP,socket,rescue)
I haven't practised my PHP in a long time, as I've been doing more Ruby scripting. I'm kind of embarrassed to ask for help with this.
I know, in Ruby, that I can use rescue to prevent the script from crashing in the case of error, and I'm hoping to achieve the same thing with PHP.
For example, in Ruby:
require 'socket'
begin puts "Connecting to host..."
host = TCPSocket.new("169.121.77.3", 333)
# This will (intentionally) fail to connect, triggering the rescue clause.
rescue puts "Something went wrong."
# Script continues to run, allowing, for example, the user to correct the host IP.
end
My PHP code is a little messy - it's been quite a long time.
function check_alive($address,$service_port) {
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo socket_strerror(socket_last_error());
}
else {
echo null;
}
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo socket_strerror(socket_last_error($socket));
return 1;
}
else {
echo null;
}
socket_close($socket);
return 0; }
$hosts = [...];
// list of hosts to check
foreach($hosts as $key=>$host) {
check_alive($hosts);
}
Essentially, I have an array of hosts, and I'd like to check to see if they're alive. It's not necessary for ALL hosts to be alive, so here's where I'm stuck - the first dead host in the array crashes the script.
Any suggestions would be very much appreciated - I'm willing to accept that I don't fully understand socket connections in PHP.
The PHP equivalent is:
try { ... } catch (...) { ... }
If you're using PHP 5.5, there also is:
try { ... } catch (...) { ... } finally { ... }
You can have several catch clauses, each catching a different exception class.
The finally part is always run, including when an exception got raised.
The following is the PHP equivalent for exception handling:
try { // equivalent of Ruby `begin`
} catch(Exception $e) { // equivalent of Ruby `rescue(e)`
}
Related
I have a site that uses a lot of apis to other places. I've been using curl and a bunch of if(!something) to do it, but I want to switch to a more robust solution, so I'm trying to use guzzle. But I am not sure how to handle the exceptions.
I did this..
class Api {
...
function request ($params) {
tries = 0;
while (tries < 3) {
try {$resp = $client->request(params);
} catch (\GuzzleHttpException $e) {
some stuff
if ($tries > 2) {
LOG error( failure info);
return [];
}
sleep 1;
++$tries;
}
break;
}
return $resp;
}
So my question is how do I better identify the errors here. I want to know why it failed... connection, 500, 404, timeout, etc. Don't know how to "stack" Exceptions. Guzzle has many different except types. (+ I'm on php 8 so errors should be exceptions too I think. ) Some guidance??
I'm using Flysystem SFTP in Laravel 8. I've multiple accounts for sftp and I'm looping on every one for making adapter and then reading files from server. This all is working through console command and is registered in Schedule. The issue is when any of the connection fails due to username or password issue, it stops the execution of schedule task and skips the remaining. How can I check if connection is successful or not and continue to my next sftp connection. Thanks in advance.
foreach ($credentials as $cred) {
try {
$driver = Storage::createSFtpDriver($cred);
if($driver->exists('/reports/')) {
//Other code
} else {
continue;
}
} catch (Exception $e) {
continue;
}
}
See SFTP V3, there SftpConnectionProvider reads:
connectivity checker (must be an implementation of League\Flysystem\PhpseclibV2\ConnectivityChecker to check if a connection can be established (optional, omit if you don't need some special handling for setting reliable connections)
So the answer is SftpConnectivityChecker implements ConnectivityChecker
... to be passed into SftpConnectionProvider constructor. That interface only has one single method to override:
public class SftpConnectivityChecker implements ConnectivityChecker {
public function isConnected(SFTP $connection): bool {
$connected = false
// TODO: inspect the $connection status.
return $connected;
}
}
Likely to be configured alike this:
'sftp' => [
'connectivityChecker' => 'SftpConnectivityChecker'
]
And don't use continue, but handle the exception instead of ignoring it.
I don't know if it is good way or not but in my case, it is working fine. I just solved it by applying \ with Exception class and it is going fine.
foreach($credentials as $cred){
try {
$driver = Storage::createSFtpDriver($cred);
if($driver->exists('/report/')){
echo "Found for ".$cred["username"];
}
else{
continue;
}
}
catch (\Exception $e) {
continue;
}
}
I'm querying a whole bunch of addresses, some are online and some are not. I can't seem to get around this error however, even catching the exception fails :(
dns_get_record(): A temporary server error occurred.
try {
$result = dns_get_record('_minecraft._tcp.' . $addr, DNS_SRV);
}
catch (Exception $e) {
return [$addr,$port];
}
If this error occurs, I want to continue the script, skipping the record, however currently the script just halts.
Any help appreciated!!
I can't catch this exception too. And how I understood it's a bug of php:
https://bugs.php.net/bug.php?id=73149
But I found another solution. You can use # when you call this function. This symbol kill all errors when you call this one. And it will looks like that:
$dns = #dns_get_record($domain, DNS_A);
if(!$dns){
return false;
}
I was able to get the IP (A record) for a host using the below PHP function
gethostbynamel(string $hostname): array|false
Reference: gethostbynamel — Get a list of IPv4 addresses corresponding to a given Internet host name
try this:
try {
$dns = dns_get_record($domain, DNS_A);
}
catch (Exception $e) {
if ($e->getMessage() !== 'dns_get_record(): A temporary server error occurred.') {
throw $e;
}
$dns = false;
}
Currently, i am trying a simple code of sending/receiving messages using ZMQ. The code is as below
/* Create new queue object, there needs to be a server at the other end */
$queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5555");
/* Assign socket 1 to the queue, send and receive */
$retries = 5;
$sending = true;
/* Start a loop */
do {
try {
/* Try to send / receive */
if ($sending) {
echo "Sending message\n";
$queue->send("This is a message", ZMQ::MODE_NOBLOCK);
$sending = false;
} else {
echo "Got response: " . $queue->recv(ZMQ::MODE_NOBLOCK) . "\n";
echo 'Complete';
break;
}
} catch (ZMQSocketException $e) {
/* EAGAIN means that the operation would have blocked, retry */
if ($e->getCode() === ZMQ::ERR_EAGAIN) {
echo " - Got EAGAIN, retrying ($retries)\n";
} else {
die(" - Error: " . $e->getMessage());
}
}
/* Sleep a bit between operations */
usleep(5);
} while (--$retries);
When i run this script in console, my output is
Sending message
Got response:
Complete
I believe that though there are no errors thrown, but still my message is not actually sent. I also ran netstat command but i didn't found any process listening on port 5555. Ideally there should be one(current). But no exception is thrown while making connection.
Is there something which i am missing?
When you say no process is listening on port 5555, it probably means that your server is not up and running. Your client will not throw any errors even if there is no server, it just sets up and waits for the server to come online (with your particular setup here, at least).
In this case, since you're using non-blocking mode, it'll send your message on the first pass through the loop (why are you sending the message in the loop at all?), but it won't actually send anything because the server isn't there. Then it'll attempt to receive on the second pass through the loop, but since the socket isn't ready to receive it looks like it'll just fail silently, without throwing an exception. Since no exception is thrown, it gets to your break statement, quits the loop, and you're done.
First things first, your send call should happen before the loop, it's something you want to do only once.
Then, when you recv, store the result in a variable and test for emptiness. Leave the try/catch code. The result should be something like this:
/* Create new queue object, there needs to be a server at the other end */
$queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5555");
/* Assign socket 1 to the queue, send and receive */
$retries = 5;
echo "Sending message\n";
$queue->send("This is a message", ZMQ::MODE_NOBLOCK);
/* Start a loop */
do {
try {
/* Try to receive */
$response = $queue->recv(ZMQ::MODE_NOBLOCK);
if (!empty($response)) {
echo "Got response: " . $response . "\n";
echo 'Complete';
break;
}
else {
echo "we probably haven't even sent the original request yet, retrying ($retries)\n";
}
}
catch (ZMQSocketException $e) {
/* EAGAIN means that the operation would have blocked, retry */
if ($e->getCode() === ZMQ::ERR_EAGAIN) {
echo " - Got EAGAIN, retrying ($retries)\n";
} else {
die(" - Error: " . $e->getMessage());
}
}
/* Sleep a bit between operations */
usleep(5);
} while (--$retries);
echo "END OF LINE";
... keep in mind this is a minor fix to the client code that makes it behave a little more rationally, I still believe your actual problem is that the server isn't running.
Please add the server code. You are showing the client code. Since the problem seems to be in the server, and you also state that the server is not visible with netstat, the problem is most probably there.
This question already has answers here:
Synchronized functions in PHP
(6 answers)
Closed 9 years ago.
I've got a php application that requires to make a connection to a server which authenticates with a token, this token stays valid until connection is lost.
When another connection is made while the first is still open my application crashes because the token is different from the currently connected one...
public function connect()
{
$Socket = fsockopen("192.168.1.1", 1234);
if ($Socket !== false) {
stream_set_timeout($Socket, static::TIMEOUT_SEC, static::TIMEOUT_USEC);
$this->socket = $Socket;
$this->sendeverything;
}
}
How am I able to run a function like:
function gogogo() {
connect();
}
multiple times without having them running simultaneously
Sorry for my bad english
Most easy solution would be to have a is_connected function:
function connect() {
if(is_already_connected()) {
return;
}
// ... your connect logic
}
In the is_already_connected() you'll have to write some intelligent code to determine if there is an open connection.
You can also create a kind of singleton connection (although this suggestion would probably instantiate a lot of debate about the use of singletons ;))
Try something like this...
<?php
class Connection {
public $Socket = null;
public function connect(){
// Checking if Socket already has a pointer :P
if((bool)$this->Socket){
return true;
}
$this->Socket = fsockopen("192.168.1.1", 1234);
if ($this->Socket !== false) {
stream_set_timeout($this->Socket, static::TIMEOUT_SEC, static::TIMEOUT_USEC);
$this->sendeverything();
}
}
}
$myconnect = new Connection();
$myconnect->connect();
$myconnect->connect();
?>
As mentioned in this question you can use sem_aquire for this. Something like:
function connect(){
$key = "192.168.1.1:1234" ;
try{
$sem = sem_get( $SEMKey);
sem_acquire($sem);
//Do connecty stuff here
sem_release($sem);
}catch(Exception $ex){
//Exception handling
}finally{
//Finally only available in PHP 5.5 place this in catch and try if < 5.5
sem_release($sem);
}
}
Note that this is entirely untested and wont work on windows. If you are on windows you can use flock - again as mentioned in the above question.