Slim 4 - PUT request

I made a function to update the password of an user in my DB like this:

public function updatePatientPassword($email, $old_password, $new_password){
	$dbPassword = $this->readPasswordByEmail($email);
	if($dbPassword == $old_password){
		$stmt = $this->conn->prepare("UPDATE usersSET password = ? WHERE email = ?");
		$stmt->bind_param("ss", $new_password, $email);
		if($stmt->execute()){
			return PASSWORD_CHANGED;
		}
		else{
			return PASSWORD_NOT_CHANGED;
		}
	}
	else{
		return PASSWORD_DONT_MATCH;
	}
}

And in the index.php I made a PUT request like this:

$app->put('/updateUserPassword', function(Request $request, Response $response) {
$request_data = $request->getParsedBody();
if(!emptyParameters(array('email', 'old_password', 'new_password'), $request, $response)){
	$request_data = $request->getParsedBody();
	$email = $request_data['email'];
	$old_password = $request_data['old_password'];
	$new_password = $request_data['new_password'];

	$db = new DbOperations;
	$result = $db->updateUserPassword($email, $old_password, $new_password);
	if($result == PASSWORD_CHANGED){
		$message = array();
		$message['Error'] = false;
		$message['Result'] = 'Password changed';

		$response->getBody()->write(json_encode($message));

		return $response
			->withHeader('Content-type', 'application/json')
			->withStatus(200);
	}
	elseif($result == PASSWORD_NOT_CHANGED){
		$message = array();
		$message['Error'] = true;
		$message['Result'] = 'Password not changed';

		$response->getBody()->write(json_encode($message));

		return $response
			->withHeader('Content-type', 'application/json')
			->withStatus(200);
	}
	elseif($result == PASSWORD_DONT_MATCH){
		$message = array();
		$message['Error'] = true;
		$message['Result'] = 'Password incorrect';

		$response->getBody()->write(json_encode($message));

		return $response
			->withHeader('Content-type', 'application/json')
			->withStatus(200);
	}
}
else{
	return $response
		->withHeader('Content-type', 'application/json')
		->withStatus(422);
}

});

The problem is when I try the request using postman cuz it tells me that there are empty parameters but if instead of $app->put I use $app->post there are no erros.
Would you know why this is happening?

Thx

Hi @Ernes

I think you need $app->addBodyParsingMiddleware(); for PUT with JSON or XML payload.

So instead of $app->post I have to write $app->addBodyParsingMiddleware();?

I mean you have to add the BodyParsingMiddleware in your bootstrap file.

Example:

<?php
 
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
 
require __DIR__ . '/../vendor/autoload.php';
 
$app = AppFactory::create();

$app->addBodyParsingMiddleware(); // <<<---- here
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);
 
$app->put('/users/password', function (Request $request, Response $response, $args): Response {
    $data = $request->getParsedBody();
    $html = var_export($data, true);
    $response->getBody()->write($html);

    return $response;
});
 
$app->run();

Read more: https://akrabat.com/receiving-input-into-a-slim-4-application/

Nope, It’s still telling that the parameters are empty, but when I make a GET or a POST with parameters there are no errors

The BodyParsingMiddleware will only parse the body if the request header Content-Type contains a supported value. Supported values are:

  • application/json
  • application/x-www-form-urlencoded
  • application/xml
  • text/xml

What Content-Type do you use in your PUT request?

Can you show us an example request?

Edit: I have testet the PUT method succesfully without the MethodOverrideMiddleware.

Here is the code:

<?php

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

//$app->setBasePath('/slim4-hello-world');

$app->addBodyParsingMiddleware(); // <<<--- add this middleware!
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);

$app->get('/', function (Request $request, Response $response, $args): Response {
    $response->getBody()->write('Hello, World');

    return $response;
});

$app->put('/users/password', function (Request $request, Response $response, $args): Response {
    $data = $request->getParsedBody();

    $response = $response->withHeader('Content-Type', 'application/json');
    $response->getBody()->write(json_encode($data));

    return $response;
});

$app->run();

Make sure that you set the correct Content-Type and JSON Request body in postman:

I had some PUT urls in a rest api i wrote a while ago in slim 3 and I got bored of trying to make it work…

So I just parsed the body myself, I have a few guys around that know mime stuff so we stitched this together, not sure how good the implementation is but it certainly worked for what i needed it to do

function parseMultipartFormBody($data)
{
$return = [];

//all data up to first \r\n is mime boundary
$boundary = substr($data, 0, (strpos($data, "\r\n")));

//split based on boundary and filter out garbage
$sections = array_filter(explode($boundary, $data));

foreach ($sections as $section)
{
    $name;
    $value;
    $matches;

    if (preg_match('#\r\nContent-Disposition:\s+form-data;\s+name="(.+)"\r\n\r\n#', $section, $matches))
    {
        //name is capture group second match
        $name = $matches[1];

        //start of value is index of name match + length of name match
        $start = strpos($section, $matches[0]) + strlen($matches[0]);

        //take the rest of string from end of name to boundary as data could have valid \r\n
        $value = substr($section, $start, strlen($section));

        //strip the trailing feed
        $value = preg_replace('#\r\n$#', '', $value);

        $return[$name] = $value;
    }
}
return $return;

}