Catching syntax error and custom error reporting - slim

I am using slim framework 3 . I am new to this framework. I am working on catching the errors and returning the custom JSON error and message.
I used this code to catch notFoundHandler error :
$container['notFoundHandler'] = function ($c) {
return function ($request, $response) use ($c) {
return $c['response']
->withStatus(404)
->withHeader('Content-Type', 'application/json')
->write('Page not found');
};
};
But I am able to catch the normal syntax error.
It is showing Warning: fwrite() expects parameter 2 to be string, array given in X-api\controllers\Products.php on line 42
Instead of this message, I want my custom error to handle syntax error reporting.
I used this also,
$container['phpErrorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
//Format of exception to return
$data = [
'message' => "hello"
];
return $container->get('response')->withStatus($response->getStatus())
->withHeader('Content-Type', 'application/json')
->write(json_encode($data));
};
};
But not working for me.

The default error handler can also include detailed error diagnostic information. To enable this you need to set the displayErrorDetails setting to true:
$configuration = [
'settings' => [
'displayErrorDetails' => true,
],
];
$c = new \Slim\Container($configuration);
$app = new \Slim\App($c);
Note this is not appropriate for production applications, since it may reveal some details you would want not to reveal. You can find more in Slim docs.
EDIT
If you need to handle parseErrors, then you need to define phpErrorHandler in your container, just like you did define notFoundHandler.
$container['phpErrorHandler'] = function ($container) {
return function ($request, $response, $error) use ($container) {
return $container['response']
->withStatus(500)
->withHeader('Content-Type', 'text/html')
->write('Something went wrong!');
};
};
Note: this will work with PHP7+ only, because in older versions parseErrors cannot be catched.

I have used this short of code in my dependencies.php
$container['errorHandler'] = function ($c) {
return function ($request, $response) use ($c) {
$data = [
'message' => "Syntex error"
];
return $c['response']
->withStatus(200)
->withHeader('Content-Type', 'application/json')
->write(json_encode($data));
};
};
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting, so ignore it
return;
}
throw new \ErrorException($message, 0, $severity, $file, $line);
});
Now its working for me.

Related

Slim 3 - How to add multiple middleware classes on a route?

I know how to add multiple middleware class in $app:
$app->add( new Middlewares\VerifyCsrfToken() );
$app->add( new Middlewares\RemoveTrailingSlash() );
But how on route?
$app->get('/', function($request, $response){
return $response;
})->add( new Middlewares\VerifyCsrfToken() )
->add( new Middlewares\RemoveTrailingSlash() );
As noted in the comments, add() returns an instance of the Route object, so you can simply chain multiple add()s together.
This unit test shows how to do it:
$app = new App();
$app->get('/', function ($req, $res) {
return $res->write('Center');
})->add(function ($req, $res, $next) {
$res->write('In1');
$res = $next($req, $res);
$res->write('Out1');
return $res;
})->add(function ($req, $res, $next) {
$res->write('In2');
$res = $next($req, $res);
$res->write('Out2');
return $res;
});

Slim 3 blackholing errors

I have a small slim 3 app, and when I throw an exception slim simply shows the generic error message:
Slim Application Error
A website error has occurred. Sorry for the temporary inconvenience.
In slim 2 you can do something like this to turn on debug mode giving you backtraces etc:
$app->config('debug', true);
In slim 3 there doesn't seem to be one. Additionally, it seems to be overriding my exception and error handlers.
How can I get slim to spit out errors, or at least to call my error handlers (Which pipe the output to kint for debug information)
Looking through the source, it's possible to initialize slim 3 with error display like so:
$app = new \Slim\App(['settings' => ['displayErrorDetails' => true]]);
I'm not sure if it's possible to change this setting after the fact without replacing the errorHandler altogether.
To show full stack trace on default exception handler use what j-v said.
If you want to handle exceptions in Slim yourself then you need to override Slim's default exception handler as it will be used before your "not in Slim" error handler:
$app = new \Slim\App();
$container = $app->getContainer();
$container['errorHandler'] = function(ServerRequestInterface $request, ResponseInterface $response, Exception $exception) {
//Handle exception here
}
Error handling is rather well documented: Official Docs
$app = new \Slim\App();
$c = $app->getContainer();
$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!');
};
};
Error handling is best solution to this. You can do something like to see Error Trace
$app = new \Slim\App();
$container = $app->getContainer();
$container['phpErrorHandler'] = $container['errorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'text/html')
->write('Something went wrong!<br><br>' .
nl2br($error->getTraceAsString()));
};
};
Make displayErrorDetails->true.
You will find cause of error.
$config = ['settings' => [
'addContentLengthHeader' => true,
'displayErrorDetails' => true
]];
$app = new \Slim\App($config)

Test a REST get request

How do I test a GET request of a REST API with PHPUnit 4.1? I use the Slim PHP-Framework and could manage to test the response code but not the body or header.
This is what I have so far:
TestClass:
class AssetTest extends PHPUnit_Framework_TestCase
{
public function request($method, $path, $options = array())
{
// Capture STDOUT
ob_start();
// Prepare a mock environment
Environment::mock(array_merge(array(
'REQUEST_METHOD' => $method,
'PATH_INFO' => $path,
'SERVER_NAME' => 'slim-test.dev',
), $options));
$app = new \Slim\Slim();
$this->app = $app;
$this->request = $app->request();
$this->response = $app->response();
// Return STDOUT
return ob_get_clean();
}
public function get($path, $options = array()){
$this->request('GET', $path, $options);
}
public function testGetAssets(){
$this->get('/asset');
$this->assertEquals('200', $this->response->status());
}
}
If my JSON response of http://example.com/asset looks like this (Code 200):
[
{
"AssetID": "4b0be88b9e853",
"AssetStatusID": "1"
}
]
Everything is good. To get the body of response just call the
$response->getBody() and use json_decode to decode this response. To get the header call the $response->getHeaders().
In your case it will by $this->response->getBody(). So your test
method will be look like this
public function testGetAssets(){
$this->get('/asset');
$response = json_decode($this->response->getBody(), true); //response body
$headers = $this->response->getHeaders() //response headers
$this->assertEquals('200', $this->response->status());
}
This answer is respect to the latest version of guzzlehttp i.e. 6.0

Modify Exception Handling using Hooks in Dancer

I'm trying to set up a hook to catch all exceptions and errors thrown from my Dancer application ( an API ) and pass them to a function that sets the HTTP status code and returns the hash ( serialized as JSON ).
Everything works fine when I use try/catch, but when I move it to a hook it runs the code but the response is formed using the default error mechanism instead of my function.
This is the hook I'm using:
# Handle errors
hook on_handler_exception => sub {
my $e = shift;
debug "ON HANDLER EXCEPTION";
return API::Exception->handle($e); # sets status code and returns hash depending on the exception
};
I also tried using halt instead of return to stop any further processing of the exception but it didn't alter anything.
How would I accomplish this with Dancer? Thanks.
use the "on_route_exception" hook instead ...
hook on_route_exception => sub
{
my ( $exception ) = #_;
error( $exception );
status( 'error' );
halt( { errors => [ { message => 'An unhandled exception occurred', code => 0 } ] } );
};
Have a look at the code of Dancer::Error.
I think something like
my $content = Dancer::Engine->engine("template")->apply_renderer($template_name, $ops);
return Dancer::Response->new(
status => $self->code,
headers => ['Content-Type' => 'text/html'],
content => $content);
from the _render_html method could help you.

open_basedir restriction in effect. File() is not within the allowed path(s) and Uncaught CurlException: 3: No URL set! thrown in base_facebook.php

protected function makeRequest($url, $params, $ch=null) {
if (!$ch) {
$ch = curl_init();
}
$opts = self::$CURL_OPTS;
if ($this->useFileUploadSupport()) {
$opts[CURLOPT_POSTFIELDS] = $params;
} else {
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
}
$opts[CURLOPT_URL] = $url;
// disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
// for 2 seconds if the server does not support this header.
if (isset($opts[CURLOPT_HTTPHEADER])) {
$existing_headers = $opts[CURLOPT_HTTPHEADER];
$existing_headers[] = 'Expect:';
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
} else {
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
}
curl_setopt_array($ch, $opts);
$result = curl_exec($ch);
if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
self::errorLog('Invalid or no certificate authority found, '.
'using bundled information');
curl_setopt($ch, CURLOPT_CAINFO,
dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
$result = curl_exec($ch);
}
if ($result === false) {
$e = new FacebookApiException(array(
'error_code' => curl_errno($ch),
'error' => array(
'message' => curl_error($ch),
'type' => 'CurlException',
),
));
curl_close($ch);
throw $e;
}
curl_close($ch);
return $result;
}
I have built a facebook app, but something went wrong in this piece of code of base_facebook.php.
Whole code is here. All i get everytime are this 2 errors -
1.Warning: curl_setopt_array() [function.curl-setopt-array]: open_basedir restriction in effect. File() is not within the allowed path(s): (/home/:/usr/lib/php:/tmp) in /home/a2424901/public_html/base_facebook.php on line 802
2.Uncaught CurlException: 3: No URL set! thrown in /home/a2424901/public_html/base_facebook.php on line 814
Here is the code of my facebook app i.e.(index.php)
Yeap, non-obvious error message.
But it means, that realpath() returns empty value:
File() is not within the allowed path(s)...
Make sure, that the file passed to realpath() function really exists in the specified path.
Other exceptions in your example were caused by this problem.
By the way, it's good practice to wrap all weak spots (in your example - Facebook API calls) in try-catch blocks.