Redis "unknown command" error - php

I use Redis as session storage in my website (Laravel 4.2). Sometimes I get following errors. I guess ">" char broke the setex commands.
production.ERROR: exception 'Predis\ServerException' with message 'ERR unknown command '>'' in
production.ERROR: exception 'Predis\ServerException' with message 'ERR unknown command 'tml>''
production.ERROR: exception 'Predis\ServerException' with message 'ERR unknown command '</div>''
These errors occurs rarely on production server and I can't reproduce them. Do you have any idea why these errors occurs and how can I prevent them?
key: laravel:xxxxxxxxxxxxxxx
value: s:217:"a:4:{s:6:"_token";s:40:"xxxxxxxxxxx";s:4:"lang";s:2:"fr";s:9:"_sf2_meta";a:3:{s:1:"u";i:1461777248;s:1:"c";i:1461777248;s:1:"l";s:1:"0";}s:5:"flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}";
exception 'Predis\ServerException' with message 'ERR unknown command 'ml>'' in vendor/predis/predis/lib/Predis/Client.php:282
Update
Code example where I am using redis.
public function view($username = null)
{
$username = mb_strtolower($username);
$redis = $this->getRedis();
try{
$view = $redis->get(User::getCacheKeyByUsername($username));
}catch (\Exception $exception){
$view = null;
}
if($view === null || Session::has("admin")){
$user = User::where('username', '=', $username)->where("status", 1)->first();
if (empty($user)) {
return Redirect::to(Session::get("lang") . '/all');
}
$view = View::make("view", array("user" => $user));
if(!Session::has("admin")){
try{
$redis->setex(User::getCacheKeyByUsername($username), 3600, $view);
}catch (\Exception $exception){
Log::error($exception->getMessage());
}
}
}
return $view;
}

Ok, so basically what can I say from Your error log: redis doesn't like special characters like < and >, so You have to encode them.
Use htmlspecialchars to encode and htmlspecialchars_decode to decode data when retrieving.

something is wrong with your redis client. You can not reproduce it, because the error does not happen in your code, but in TCP communication between client and redis server.
i would suggest to update the question and mention what redis client module are you using. Is it predis?
If you are on unix, try compile and install phpredis. it is php module and I never had any problems with it.
Reproduction with telnet
Do telnet host port and follow instructions:
Normal request GET a would look like this:
*2
$3
get
$1
a
$-1
Now consider this - ask for gem a:
*2
$3
gem
$1
a
-ERR unknown command 'gem'
Protocol is valid, but command "gem" is invalid.
Now consider this:
*1
$3
ml>
-ERR unknown command 'ml>'
Here is your error. Valid protocol, invalid command.
Alternatively consider this:
*2
$3
get
$1
<html>
$-1
-ERR unknown command 'ml>'
Here is your error again. Invalid strlen("<html>");
Why this is redis client error and not user error:
Many redis clients uses PHP magic methods.
This means if you call $redis->bla(), they extract "bla" part and it parameters and forward them to the redis server.
However you can not do $redis->ml>(). This will be syntax error. So this is error from redis client, not from your code.
It also looks like part of HTML. It looks like you are storing HTML data in redis. I only can guess that the client does not compute strlen() or count() and send wrong information "down the telnet line".

Related

Library error: a socket error occurred in Symfony Messenger

In my Symfony project, there is a queue message handler, and I have an error that randomly appears during the execution:
[2022-10-12T07:31:40.060119+00:00] console.CRITICAL: Error thrown while running command "messenger:consume async --limit=10". Message: "Library error: a socket error occurred" {"exception":"[object] (Symfony\\Component\\Messenger\\Exception
TransportException(code: 0): Library error: a socket error occurred at /var/www/app/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php:62)
[previous exception] [object] (AMQPException(code: 0): Library error: a socket error occurred at /var/www/app/vendor/symfony/amqp-messenger/Transport/Connection.php:439)","command":"messenger:consume async --limit=10","message":"Library error: a socket error occurred"} []
The handler executes HTTP requests that could last some seconds and the whole process of a single message could even take more than one minute if APIs are slow. The strange thing is that the problem disappears for hours but then it randomly appears again. The more messages are sent to the queue, the easier it's to see the exception.
config\packages\messenger.yaml
framework:
messenger:
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
async:
dsn: "%env(MESSENGER_TRANSPORT_DSN)%"
options:
exchange:
name: async_exchange
queues:
async: ~
heartbeat: 45
write_timeout: 90
read_timeout: 90
retry_strategy:
max_retries: 0
routing:
# Route your messages to the transports
'App\Message\MessageUpdateRequest': async
App\MessageHandler\MessageUpdateRequestHandler.php
<?php
declare(strict_types=1);
namespace App\MessageHandler;
use App\Message\MessageUpdateRequest;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class MessageUpdateRequestHandler implements MessageHandlerInterface
{
public function __invoke(MessageUpdateRequest $message)
{
// Logic executing API requests...
return 0;
}
}
Environment
Symfony Messenger: 5.4.17
PHP: 8.1
RabbitMQ: 3.11.5
Things that I tried
upgrading Symfony Messenger to 5.4.17, using the fix available here;
adding the following options: heartbeat, write_timeout and read_timeout in the messenger.yaml file.
Related issues/links
https://github.com/php-amqp/php-amqp/issues/258
https://github.com/symfony/symfony/issues/32357
https://github.com/symfony/symfony/pull/47831
How can I fix this issue?
Regarding a socket error that occurs in Symfony Messenger, I always suggest following the step-wise approach and checking if you are missing anything. It should fix this type of error almost every time. Please follow these guidelines:
Verify that the RabbitMQ service is active and accessible.
Verify that the hostname, port, username, and password are listed in the messenger.yaml file are accurate.
In the messenger.yaml file, increase the heartbeat, write timeout, and read timeout settings.
Verify your use case to determine whether the max retries number in messenger.yaml is appropriate.
Look for any network problems that could be causing the socket error.
Make sure your PHP version is compatible with RabbitMQ and Symfony Messenger.
Verify that the server's resources (CPU, Memory, and Disk) are not used up.
Look for any relevant error messages in the PHP error log.
Determine whether there is a problem with the MessageUpdateRequestHandler class's logic.
Tip: Still stuck? Try to reproduce the error with a smaller message set and in a controlled environment to isolate the root cause that we may be missing.
Hope it helps. Happy debugging and good luck.

Catch HTTP client errors in Laravel 8

How do you catch errors thrown by the HTTP client (for example a time out) so that it doesn't throw the curl error in the Laraval debugger (in debug mode) before you can do anything with the error to avoid stopping the execution?
use Illuminate\Support\Facades\Http;
try {
$request = Http::post('https://example.com/post', [
'password' => 'guest']);
} catch(ConnectException $e)
{
//log error
}
//continue with another mode
Instead, I'm always getting the Laravel's Ignition error page
Illuminate\Http\Client\ConnectionException
cURL error 28: Failed to connect to example.com port 443: Timed out
and the error is not caught by my code. Is it possible that the laravel debugger always have priority and can't be overridden in debug mode?
This is almost certainly a namespacing issue.
You'll need either this at the top of the file:
use Illuminate\Http\Client\ConnectionException;
or do this:
} catch(\Illuminate\Http\Client\ConnectionException $e)
Otherwise, you're actually trying to catch something in the current namespace named ConnectionException (i.e. something like App\Controllers\ConnectionException), which will never exist.

Why try-catch isn't working with phpseclib library in Laravel 5.5?

I am working on one project that requires me to execute some commands on remote server. I am using Laravel 5.5 with package name "laravelcollective/remote" that uses SSH2 to connect with the remote server.
However, I am facing some really weird issues with some servers. I get the following error message on some of the servers.
production.ERROR: Connection closed prematurely {"exception":"[object] (ErrorException(code: 0): Connection closed prematurely at /home/username/application_name/public_html/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php:3821, RuntimeException(code: 0): Unable to connect to remote server. at /home/username/application_name/public_html/vendor/laravelcollective/remote/src/Connection.php:143)
I am using try-catch block to catch exceptions but I am unable to catch this exception. All other Exceptions like connection timed out are being caught by the try-catch block except this one.
I am using try catch block like this:
try {
$commands = array('sudo apt-get update','sudo apt-get upgrade -y');
SSH::run($commands);
} catch (\Exception $e){
report($e);
}
But the try-catch block stops working with this connection closed prematurely error. I don't know if I am missing something or there is some bug with the library, has anyone faced the same issue before? How can I catch this error the right way?
it's because an exception is not thrown, just an error. and an error cannot be caught.
I suggest you set a global error handler that converts all the errors to exceptions, as seen in this answer here and it would be a good idea to read other answers to that question too.
Generate a custom exception handler and then in a provider or in your public/index.php set your error handler

ZF2 PHP Exception

I'm building an application with ZF2.
I use ajax to POST some data on the application and when I trhrow a new Exception with this line:
throw new \Exception("Not Loged In.", 401);
The problem is everytime I throw a new error it returns a 500 even if I put anything as a second parameter of the exception.
Can anyone help me?
Thanks!
From zend framework's request lifecycle perspective every uncaught exception is an application error. You need a mechanism to convert that exceptions to meaningful HTTP responses before the framework convert them to an HTTP 50X for you.
For example, in your controller you can try something like below:
try {
$this->myService->tryToDoSomethingThatNeedsAuthentication();
} catch(AuthRequiredException $e) {
$this->getResponse()->setStatusCode($e->getCode()) // Assuming its 401
->setReasonPhrase($e->getMessage());
return;
} catch(\Exception) {
// handle other exceptions here
}
Problem is in your php configuration. Default Apache (or other server) hide details of your internal errors, so is returned short info:
Error 500 - internal server error
You must enable error_reporting:
in PHP:
http://php.net/manual/pl/function.error-reporting.php
or in php.ini in Apache configuration, and in .htaccess file it's possible. For developer's work you should show all errors.

PHP PECL oauth error "Unknown signature method"

I get an Exception on my production server when i try to instanciate the class "OAuthProvider" from pecl package oauth.
try {
$oauth = new OAuthProvider();
} catch(Exception $e) {
// Get the error here
}
The error message is : "Unknown signature method"
Have anyone got this error ?
OAuthProvider looks for the oauth_signature_method in either the Authorization header or REQUEST params (respectively) if you run a non-CLI SAPI.
Under the CLI SAPI you can set the parameters in the ctor:
$op = new OAuthProvider(array("oauth_signature_method" => OAUTH_SIG_METHOD_HMACSHA1));
This is PHP bug #68168 - some servers have an empty $_SERVER[HTTP_AUTHORIZATION] value, which is not correctly detected by the php oauth extension.

Categories