i have this entry in my laravel 5.3 log
2016-12-22 17:23:37] local.ERROR:
GuzzleHttp\Exception\ClientException: Client error: POST
https://api.sparkpost.com/api/v1/transmissions resulted in a 400 Bad
Request response: { "errors": [ { "message": "Message generation
rejected", "description": "recipient address suppressed due to
customer p (truncated...)
why does it truncate an important error message? now i cannot figure out what is going wrong...
Because your request throws a Guzzle Exception, as a workaround, instead of calling $e->getMessage(), You can simply try:
$e->getResponse()->getBody()->getContents();
If you don't want to modify the report() method.
Worked nice for me.
The truncating is done by the Guzzle library. It only shows the first 120 characters of the response. I am assuming this is because responses could potentially be very long.
If you would like to see the full message, you should be able to customize how guzzle exceptions are handled.
Update the report() method in your app/Exceptions/Handler.php to something like:
public function report(Exception $exception)
{
// this is from the parent method
if ($this->shouldntReport($exception)) {
return;
}
// this is from the parent method
try {
$logger = $this->container->make(\Psr\Log\LoggerInterface::class);
} catch (Exception $ex) {
throw $exception; // throw the original exception
}
// this is the new custom handling of guzzle exceptions
if ($exception instanceof \GuzzleHttp\Exception\RequestException) {
// get the full text of the exception (including stack trace),
// and replace the original message (possibly truncated),
// with the full text of the entire response body.
$message = str_replace(
rtrim($exception->getMessage()),
(string) $exception->getResponse()->getBody(),
(string) $exception
);
// log your new custom guzzle error message
return $logger->error($message);
}
// make sure to still log non-guzzle exceptions
$logger->error($exception);
}
Note: this is done in the report method, so it only affects what is written to the log. If the exception is dumped to the terminal or to the browser, it will still show the truncated message.
as alternative solution:
hotfix RequestException.php
ta_integration/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
replace
$size = $body->getSize();
$summary = $body->read(120);
$body->rewind();
if ($size > 120) {
with for example:
$size = $body->getSize();
$summary = $body->read(999);
$body->rewind();
if ($size > 999) {
function
getResponseBodySummary
Edit vendor/guzzlehttp/psr7/src/Message.php
public static function bodySummary(MessageInterface $message, $truncateAt = 999)
Edit vendor/guzzlehttp/psr7/src/functions.php
function get_message_body_summary(MessageInterface $message, $truncateAt = 999)
None of these solutions here helped me. I found a solution here that helped. By the user sidk2020. Here is his solution in case the link breaks:
I did something very adventurous. I modified guzzel's exception handler
guzzel on purpose only reads up 120 bytes of info and prints truncated next to it.
The file is located at : /vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
So I modified that function and below is what my function looks like:
public static function getResponseBodySummary(ResponseInterface $response) {
$body = $response->getBody();
if (!$body->isSeekable() || !$body->isReadable()) {
return null;
}
$size = $body->getSize();
if ($size === 0) {
return null;
}
// Matches any printable character, including unicode characters:
// letters, marks, numbers, punctuation, spacing, and separators.
if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $body)) {
return null;
}
return $body;
}
In vendor/guzzlehttp/psr7/src/functions.php
there's this function:
function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
{
return Message::bodySummary($message, $truncateAt);
}
just change the $truncateAt = 120 to whatever you are confortable with
Related
Good day,
I modified this file.
vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php
This is the function I modified.
public function handleError($level, $message, $file = '', $line = 0, $context = [])
I made it send me an email. The email has the $message and the $file and the $line.
This is what the email said.
MESSAGE FILE vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php LINE 126
The message is blank, but it's running into an error in a file. I open the file.
public function delete($paths)
{
$paths = is_array($paths) ? $paths : func_get_args();
$success = true;
foreach ($paths as $path) {
try {
if (! #unlink($path)) { # the error is here
$success = false;
}
} catch (ErrorException $e) {
$success = false;
}
}
return $success;
}
I am confused. Why was the error not caught by the catch block? What type of error would not give a message to the error handler of laravel? Is there something I can do to get more information regarding the error?
This is our version of Laravel.
Laravel Framework version 5.1.45 (LTS)
First of all the question you have asked is misleading. What you are trying to do is add a custom error handler in laravel which you can achieve by following this URL .
The error you are facing might be caused due to file permission error.
And since there is the # sign before the function call unlink() any errors which are caused by it are suppressed.
Remove the # sign and if the file doesn't exists or if there is an error it would throw it and then catch block would catch it.
What is the best way to return errors from a PHP function, when the function has executed normally?
Example
public function login($user, $pw){
if(!$this->verifyUser($user))
// return error about invalid user
}
else if (!$this->verifyPw($pw)){
// return error about invalid pw
}
else {
// return OK
}
}
Caller - Return response as JSON for web UI
public function doLogin($user,$pw){
$res = $this->login($user, $pw);
return json_encode($res);
}
On one hand I could understand returning results as an array, but I feel like this does not make sense for such low level functions. Perhaps they should return error codes and then caller must lookup the error code string?
Assuming you are in an object, you basically have three major options:
store errors in something like $this->errors array and return false
have some kind of error-collector as a dependency for object, where you
call $this->collector->addError('blah blah'); and return false
throw an exception
For the first two approaches, you will have to check the return value, and based on that, pull the list of errors. But both of those options have the benefit of being able to collect multiple errors.
The exception approach is a bit lighter on coupling, but you can only get one error.
As for what to actually return, I would recommend going with error code + description string. But that string would not be returned by your class. Instead your error should be registered using some "placeholder", that later is translated:
$this->errors[] = [
'code' => 52,
'msg' => 'authentication.login.invalid-password',
];
When you pull the errors from your object, it would be basically a list of entries like this, And then you just run them through your translation service.
In a case of exception, that same information would reside in $e->getCode() and $e->getMessage(), when your object throws InvalidPassword exception.
For an API response the answer from tereško would be along the correct lines.
For a DOM response you can do the following:
I have used a response code only in the past for something so simple:
http://php.net/manual/en/function.http-response-code.php with code 401
public function login($user, $pw) {
header_remove(); # Clear all previous headers.
if( !$this->verifyUser($user) || !$this->verifyPw($pw) ){
http_response_code(401);
exit;
}
http_response_code(200);
exit;
}
jQuery:
$.ajax({
.......
statusCode: {
200: function() {
window.location.href = '/';
},
401: function() {
alert( "Login Failed" );
}
}
});
I don't understand how to properly create and return useful error messages with PHP to the web.
I have a class
class Foo {
const OK_IT_WORKED = 0;
const ERR_IT_FAILED = 1;
const ERR_IT_TIMED_OUT = 3;
public function fooItUp(){
if(itFooed)
return OK_IT_WORKED;
elseif(itFooedUp)
return ERR_IT_FAILED;
elseif(itFooedOut)
return ERR_IT_TIMED_OUT;
}
}
And another class that uses this class to do something useful, then return the result to the user. I am just wondering where I put the string value for all my error messages.
class Bar {
public function doFooeyThings(stuff){
$res = $myFoo->fooItUp();
// now i need to tell the user what happened, but they don't understand error codes
if($res === Foo::OK_IT_WORKED)
return 'string result here? seems wrong';
elseif ($res === Foo::ERR_IT_FAILED)
return Foo::ERR_IT_FAILED_STRING; // seems redundant?
elseif($res === Foo:ERR_IT_TIMED_OUT)
return $res; // return number and have an "enum" in the client (js) ?
}
}
You should avoid returning error states whenever possible. Use exceptions instead. If you've never used exceptions before you can read about them here
There multiple ways you can utilize exceptions in your example. You could create custom exceptions for every error or for every category of error. More on custom exceptions here or you could create an instance of the default Exception class supplying it the error messages as strings.
The code below follows the second approach:
class Foo {
const OK_IT_WORKED = 0;
const ERR_IT_FAILED = 1;
const ERR_IT_TIMED_OUT = 3;
public function fooItUp(){
if(itFooed)
return OK_IT_WORKED;
else if(itFooedUp)
throw new Exception("It failed")
else if(itFooedOut)
throw new Exception("Request timed out");
}
}
I'm sure you can think of some more elegant messages than the ones I used. Anyway, you can then go ahead and handle those exceptions on the caller method using try/catch blocks:
class Bar {
public function doFooeyThings(stuff){
try
{
$res = myFoo->fooItUp();
}
catch(Exception $e)
{
//do something with the error message
}
}
}
Whatever exception is thrown from fooItUp will be "caught" by the catch block and handled by your code.
Two things you should also consider are:
It's best not to show your users detailed information about errors because those information could be used by users with malicious intent
Ideally you should have some kind of global exception handling
One solution is to use exceptions in conjunction with set_exception_handler().
<?php
set_exception_handler(function($e) {
echo "Error encountered: {$e->getMessage()}";
});
class ErrorMessageTest
{
public function isOk()
{
echo "This works okay. ";
}
public function isNotOkay()
{
echo "This will not work. ";
throw new RuntimeException("Violets are red, roses are blue!! Wha!?!?");
}
}
$test = new ErrorMessageTest();
$test->isOk();
$test->isNotOkay();
The set_exception_handler() method takes a callable that will accept an exception as its parameter. This let's you provide your own logic for a thrown exception in the event it isn't caught in a try/catch.
Live Demo
See also: set_exception_handler() documentation
My custom error handler is not working with Slim 3 framework. Instead of getting a 500 error, I get a response with status 200 and the html error details are in the body.
Here is my minimal, verifiable and complete example:
$c = new \Slim\Container();
$c['errorHandler'] = function ($c) {
return function($request, $response, $exception) use ($c) {
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'text/html')
->write('Something went wrong!');
};
};
$app = new \Slim\App($c);
$app->any('/foo', function($request, $response, $args) {
$data = json_encode($request->nonExistingMethod()); // error!
return $response->withJson($data);
});
$app->run();
How do I need to refactor this sample to make it work? I suspect it's related with the Fatal nature of the error. But in this case how to deal with that?
Reference: http://www.slimframework.com/docs/handlers/error.html
Edit 1
For use in an api style web application, the final solution I'm using with minor changes from the response of this question:
function checkForError() {
$last = error_get_last();
if ($last) {
#header("HTTP/1.0 500 Internal Server Error");
echo json_encode($last); // optional, includes error details in json format
}
}
error_reporting(0);
register_shutdown_function('checkForError');
you cannot catch all errors like this
there is however one way to catch all except memory errors (or only those that tried to allocate more than your error handler needs)
function checkForError() {
$last = error_get_last();
if ($last) {
#header("HTTP/1.0 500 Internal Server Error");
echo 'we failed... sry';
}
}
register_shutdown_function('checkForError');
updated with 500 status header
I have php code that execute python cgi and I want to pass python trace (returned from cgi) as extra data to php exception how can I do this and how can I get that value from catch(Exception e) { (It should check if that extra value exesit or not).
I have code like this:
$response = json_decode(curl_exec($ch));
if (isset($response->error)) {
// how to send $response->trace with exception.
throw new Exception($response->error);
}
return $response->result;
and I use json-rpc library that should return that data to the user:
} catch (Exception $e) {
//catch all exeption from user code
$msg = $e->getMessage();
echo response(null, $id, array("code"=>200, "message"=>$msg));
}
Do I need to write new type of exception or can I do this with normal Exception? I would like to send everything that was thrown in "data" =>
You need to extend Exception class:
<?php
class ResponseException extends Exception
{
private $_data = '';
public function __construct($message, $data)
{
$this->_data = $data;
parent::__construct($message);
}
public function getData()
{
return $this->_data;
}
}
When throwing:
<?php
...
throw new ResponseException($response->error, $someData);
...
And when catching:
catch(ResponseException $e) {
...
$data = $e->getData();
...
}
Dynamic Property (not recommended)
Please note that this will cause deprecation error in PHP 8.2 and will stop working in PHP 9 according to one of the PHP RFC https://wiki.php.net/rfc/deprecate_dynamic_properties
As the OP asking about doing this task without extending Exception class, you can totally skip ResponseException class declaration. I really not recommend do it this way, unless you've got really strong reason (see this topic for more details: https://softwareengineering.stackexchange.com/questions/186439/is-declaring-fields-on-classes-actually-harmful-in-php)
In throwing section:
...
$e = new Exception('Exception message');
$e->data = $customData; // we're creating object property on the fly
throw $e;
...
and when catching:
catch(Exception $e) {
$data = $e->data; // Access data property
}
September 2018 edit:
As some of readers found this answer useful, I have added a link to another Stack Overflow question which explains the downsides of using dynamically declared properties.
Currently, your code converts the response text directly into an object without any intermediate step. Instead, you could always just keep the serialized (via JSON) text it and append it to the end of the Exception message.
$responseText = curl_exec($ch);
$response = json_decode($responseText);
if (isset($response->error)) {
throw new Exception('Error when fetching resource. Response:'.$responseText);
}
return $response->result;
Then you could just recover everything after "Response:" in your error log and optionally de-serialize it or just read it.
As an aside, I would also not count on the server sending JSON, you should verify that the response text was actually parseable as JSON and return a separate error for that if it isn't.