Posts Tagged ‘PHP’

Mod Security converts PUT requests to GET requests

Sunday, September 18th, 2022 | Tech

Recently, I was on an admin system on one of my websites and noticed that some of the AJAX requests had stopped working. They worked for fetching data, and creating it, but I could not update to delete anything. I tried another website. It happened there, too.

Initially, Slim was telling me it was a 405 Method Now Allowed. But I could see I was sending a PUT and the exception said it must be of type PUT. Very weird. In the end, I decided to output the $_SERVER[‘REQUEST_METHOD’] to see what was going on. It said it was a GET request.

I pulled up Paw, my desktop request client, and manually sent a PUT request to a file I had created to print the request method. It too said GET. By this point then, I knew that it probably Apache converting the request from a PUT to a GET. Or more likely that I was sending a PUT but it was returning a 403 Forbidden as a GET request for some reason.

The answer eventually came in the form of Mod Security. It uses something called OWASP ModSecurity 2.9 Core Rule Set v3.3.2 which allows GET and POST requests but denies PUT and DELETE requests. I am not sure why this is as they are legitimate verbs to be using, but when I altered this to allow PUT requests, everything started working fine again.

Deploying to cPanel using git

Monday, February 15th, 2021 | Programming

cPanel now has support for deploying via git. Here is a quick guide on deploying PHP applications.

Upgrade Composer

The Composer version is old and will need an upgrade. To do this, you need to log into the server as root and run:

composer self-update

Install your SSH key

To avoid having to enter your password every time you push, log into cPanel and add your public SSH key. You can paste the id_rsa into the box and leave the name as default. Once added, go to the manage key and activate it.

Create a git repo

In cPanel, go into the git section and create a new repo. You can place it anywhere so perhaps a good place to put it is:

/home/username/git/repo-name

Add a remote

Back on your own computer, add the new cPanel repo as a remote.

git remote add cpanel ssh://username@example.com/home/username/git/repo-name

Add a cPanel config file

If you need to run any additional tasks, add a .cpanel.yml file to the root of your repo.

deployment:
  tasks:
    - composer install
    - /bin/cp -a /home/username/git/repo-name/public /home/username/public_html

5. Add a .cpanel.yml script

Push your code

Do a standard git push to deploy.

git push cpanel master

You can find the logs in /home/username/.cpanel/logs/ to find out if everything went as planned.

Upgrading LAC to Slim 4

Wednesday, October 28th, 2020 | Programming

Last month, I published an upgrade guide to Slim 4 covering the changes that most people will need to make.

I recently upgraded the Leeds Anxiety Clinic and this project has some further complexities, so this post will elaborate on all of the changes I made, in case my original blog post did not cover some of the issues that you are also running into.

Things to do in advance

The old service layer calls no longer work:

$db = $this->ci->db;

And need to be updated to:

$db = $this->ci->get('db');

However, Slim 3’s service container already supports this syntax, so you can go ahead and update your code in advance.

If you are passing the container into controller functions, you need to typecast it.

use Psr\Container\ContainerInterface;

class Controller {
    __construct(ContainerInterface $ci) {}
}

If you pull the request out from the service container, you cannot do that in Slim 4. For example, if you have a render helper that relies on the request being in the container, you will have to start manually passing that into your render help from the page route closure.

Dependencies

You will want all of these:

"slim/slim": "4.*",
"slim/psr7": "1.*",
"slim/http": "1.*",
"php-di/php-di": "^6.1",

I did wonder if I could remove my other PSR-7 library that I use for Mailgun, nyholm/psr7, but the answer is no.

Instanciating the app

We now create the container and then the app, and you can recursively pass in the container.

$container = new \DI\Container;

$container->set('serviceA', function() use ($container) {
    return new ServiceA($container->get('serviceB'));
});

\Slim\Factory\AppFactory::setContainer($container);
$app = \Slim\Factory\AppFactory::create();

Throwing not found exceptions

If you manually throw not found exceptions or other HTTP exceptions, Slim 3 has them located here:

Slim\Exception\NotFoundException

Slim 4 moves it to here:

Slim\Exception\HttpNotFoundException

Error handling

If you want Slim 4’s default error handling, you need:

$errorMiddleware = $app->addErrorMiddleware(true, true, true);

And if you want to handle HTTP errors (such as not found), you can use:

$errorMiddleware->setErrorHandler(
    Slim\Exception\HttpNotFoundException::class,
    function (Psr\Http\Message\ServerRequestInterface $request) use ($container) {
        $controller = new App\Controller\ExceptionController($container);
        return $controller->notFound($request);
    });

You can also set your own error handling:

$errorMiddleware->setDefaultErrorHandler(
        function (Psr\Http\Message\ServerRequestInterface $request,
        Throwable $exception) use ($container) {
            $controller = new App\Controller\ExceptionController($container);
            return $controller->error($request, $exception);
        });

This means you will need to create your own response object in any exception controller you use.

public function notFound(Request $request)
{
    $response = new \Slim\Psr7\Response;
    return $this->render($response, 'not-found.html');
}

Custom middleware

The way we pass through middleware has changed. The old way:

public function __invoke($request, $response, $next)
{
    $response = $next($request, $response);
    return $response;
}

The new way:

public function __invoke($request, $handler)
{
    return $handler->handle($request);
}

That change alone probably won’t do what you want it to do out-of-the-box, so you might need to do some reading up and adapt it to your specific middleware depending on function.

Custom middleware wants to go towards the bottom after you define your routes, but before the error middleware.

Upgrading from Slim 3 to Slim 4

Friday, September 18th, 2020 | Programming

Slim is one of my favourite PHP microframeworks and many websites are built on Slim 3. I have recently moved to Slim 4 and thought I would document the upgrade process for anyone else looking to make the leap.

Dependencies

Slim 3 came with its own dependency injection container. This is no longer the case. Therefore, we need to bring one in, such as php-di that Slim supports out-of-the-box. We will also need a PSR-7 library and the Slim HTTP helpers.

"slim/slim": "4.*",
"slim/psr7": "1.*",
"slim/http": "1.*",
"php-di/php-di": "^6.1",

Creating the app

In Slim 3, we created the app and then accessed the container.

$app = new \Slim\App([
    'settings' => []
]);

$container = $app->getContainer();

In Slim 4, we create the container then attached it to the app.

$container = new \DI\Container();
\Slim\Factory\AppFactory::setContainer($container);
$app = \Slim\Factory\AppFactory::create();

You can still access the container in the old way and inject dependencies into it, but you need to manually pass it into the app as above.

Accessing dependencies

Now we are using our PSR-11 DI of choice, we need to change how we access our dependencies. Previously, wee could use the Slim shorthand.

$db = $this->ci->db;

Now we need to use the PSR-11 standard.

$db = $this->ci->get('db');

Exception handling

Previously, we could set error handling using the dependency injection container.

$container['notFoundHandler'] = function ($container) {
    return function ($request, $response) use ($container) {
        $controller = new \App\Controller\ExceptionController($container);
        return $controller->notFound($request, $response);
    };
};

In Slim 4, we need to use the bundled middleware.

$errorMiddleware = $app->addErrorMiddleware(true, true, true);

$errorMiddleware->setErrorHandler(
    Slim\Exception\HttpNotFoundException::class,
    function (Psr\Http\Message\ServerRequestInterface $request) use ($container) {
        $controller = new App\Controller\ExceptionController($container);
        return $controller->notFound($request);
    });

This also means changing the exception controller, too, if you use one. In Slim 3, we would still get a response object passed in.

    public function notFound(Request $request, Response $response)
    {
        return $this->render($response, 'not-found.html');
    }

With Slim 4, we need to create our own.

    public function notFound(Request $request)
    {
        $response = new \Slim\Psr7\Response;
        return $this->render($response, 'not-found.html');
    }

That should take care of most of the changes. If you run into anything else, let me know, and I’ll update this article.

Slim Framework course

Saturday, July 25th, 2020 | News

Learn Slim microframework with my new course. You will build your first six projects including a searchable music catalogue, e-commerce project listings and member login and authentication system. Watch the course trailer below or preview the course.

Doctrine ORM course

Monday, June 8th, 2020 | News, Programming

My new course on Doctrine ORM is now available. If you are a PHP developer, adding Doctrine to your CV is a much=sought-after skill to have, being used by Symfony and thousands of other projects.

Here’s the trailer:

Slim PHP 3.12.3

Friday, December 6th, 2019 | Programming

If you’re using the Slim framework in PHP, there is a breaking change between 3.12.2 and 3.12.3. You’ll need to change where you are inheriting your class from.

- use Interop\Container\ContainerInterface;
+ use Psr\Container\ContainerInterface;

Rauma 4.0 released

Monday, February 4th, 2019 | Programming

I’m pleased to announce the release of the next major version of Rauma, 4.0.

Rauma is a full-stack PHP framework that gives you database, templating, session, authentication and many other functions out of the box. It’s the framework behind many of Worfolk Online’s websites.

Not much as changed in the 4.0 release, but it gets a major version bump because it’s a breaking change. Here’s what you need to know:

Authentication has been overhauled. The auth service now includes an isLoggedIn function to be a bit more verbose than checking for data. More importantly, you can now extend the base Authorisation class and create your own. This allows you to cache more data, connect to other services and implement persistent logins.

We’ve also deprecated the user description field, in favour of the new attributes feature that was added in version 3.6.

Two other things to be aware of:

There are now a set of proxy objects for things like JsonResponse so that you don’t have to import them from a different namespace.

This bumps the PHP version requirement from 5.6 to 7.1. This allows us to bring in a load of cool new stuff, including a far more up-to-date version of PHPUnit.

It’s available now on GitHub and Packagist.

Photo credit: Brett Donovan.

Heroku for PHP course

Wednesday, March 14th, 2018 | News, Programming

I’m pleased to announce the launch of my new course, Heroku for PHP. I love Heroku as a hosting platform, and there were no Udemy courses on how to use it with PHP. So, I’ve filled the gap. For a very reasonable $29.99.

You can check it out here, and that link will save you an additional $10, too.

How to serve .well-known on Heroku

Saturday, April 22nd, 2017 | Programming

If you want to use Apple Pay on your website, you need to serve a file from inside the .well-known directory. This is a nightmare.

For a start, you can’t create a directory called .well-known on Mac. So you have to find another solution. mod_rewrite to the rescue perhaps? You may be able to get this working, but I couldn’t. I just got a 403 permission denied on Heroku.

client denied by server configuration: /app/public/.well-known

So I decided to try Alias instead.

This was easy to configure on my localhost. I created a directory without the period and then used Alias to map it.

Alias "/.well-known" "/Users/me/Projects/ProjectName/well-known"

To configure it in Heroku, I created a custom Apache configuration file.

Alias "/.well-known" "${HEROKU_APP_DIR}/well-known"

And then configured my Procfile to load this.

web: vendor/bin/heroku-php-apache2 -C heroku-apache.conf public/

So far, so good. Except this didn’t work either because I had not given the directory permission in the Apache config. So I expanded my custom config file.

<Directory "${HEROKU_APP_DIR}/well-known">
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

This got it working. However, it took my homepage offline. It seems that when you include a custom Apache configuration file, it knocks out the standard DirectoryIndex that Heroku has. Or, there is something else really obviously wrong that I am missing. That’s entirely possible, but I haven’t spotted it yet.

And I did manage to fix it by adding in a new DirectoryIndex to my .htaccess file.

DirectoryIndex index.php

Finally, you have Heroku serving the directory correctly.