Freezing the Kohana layer

Kohana 3.3, on a project that earns money every day. The framework is effectively finished. The repository barely moves, the community left years ago. Nobody will approve a rewrite, and I have stopped asking. This is a normal situation and it deserves a better plan than “someday we migrate”. The plan we settled on is a freeze. Pin the exact framework version and vendor it. Not “3.3.*”, the exact commit. The build must be reproducible in five years, when the original download link is dead. ...

March 4, 2016 · 2 min · Murat Useinov

Kohana on PHP 7: whose problem is it

The test suite went green on the PHP 7 release candidate on the second try. I expected worse. Then I opened modules/ and the mood changed. The core mostly works. The community is patching compatibility in the 3.3 branch on GitHub right now, and the fixes are small: deprecated PHP 4 style constructors, changed engine behavior in dark corners. Whoever says the framework is dead is not reading the commit log. It is not dead. It is volunteers. ...

September 8, 2015 · 2 min · Murat Useinov

Composer in a legacy Kohana project

require APPPATH.'../vendor/autoload.php'; One line in bootstrap.php. This month it became the whole strategy for a project we decided to keep on Kohana. The framework is quiet, the project is alive. These two facts have to coexist somehow. The plan: nothing new gets written the Kohana way. New dependencies come through Composer, and Kohana’s autoloader and Composer’s autoloader live together fine. First candidate was the HTTP client. We talk to two external APIs, and the code around Request_Client_External was not pretty. Guzzle is better in every way. But Guzzle does not spread through the codebase. There is an interface: ...

January 22, 2015 · 2 min · Murat Useinov

Host header is user input

$link = 'https://'.$_SERVER['HTTP_HOST'].'/reset/'.$token; I wrote this line. More than once. It builds the link for a password reset email, and it looks like it reads something about the server. It does not. Host comes from the client, same as any other header. Kohana 3.3.4 shipped this month with a fix around exactly this, and the topic is bigger than one framework. The attack is short. Someone requests a password reset for your email address and puts his own domain into the Host header. The application trusts the header, builds the link, sends it. You receive a real email from a real site with a link to evil.example and your real token in the path. You click. He collects the token. Host header poisoning, and no framework protects you from it out of the box. ...

December 23, 2014 · 2 min · Murat Useinov

Composer next to Kohana bootstrap

One line in bootstrap.php, above Kohana::init(): require DOCROOT.'vendor/autoload.php'; That is the whole integration. Kohana keeps its modules and its underscore autoloader. Composer brings Packagist. Two autoloaders in one process, and they do not collide: Composer packages use namespaces, Kohana classes have underscores, the lookups never meet. { "require": { "guzzlehttp/guzzle": "~5.0" } } This setup runs in production on one of my projects for a few months. Zero problems from the autoloading side. The problems, when they came, were from me. ...

November 23, 2014 · 2 min · Murat Useinov

Kohana is not developed anymore. Now what

The commit log of kohana/kohana on GitHub. I opened it in the summer and counted: a few merges a month, then fewer, then nothing. This year the official development basically stopped. Our projects did not stop working on that day. But the question came to my inbox three times since, so here is the answer. What to do with a working Kohana product depends on which of four situations you are in. ...

November 19, 2014 · 2 min · Murat Useinov

Cascading filesystem: the best idea in Kohana

Kohana::find_file(). One function, maybe forty lines. If I could keep only one thing from Kohana, this is the one. It looks for every file in order: application/, then modules, then system/. First found wins. Config, views, classes, i18n, everything goes through the same lookup. In practice: a module ships a config file, you put a file with the same name into application/config/, change one key. The module does not know. Nothing under modules/ is touched. ...

November 16, 2014 · 2 min · Murat Useinov

Kohana ORM and my first real N+1

Fifty one queries. That is what the SQL panel of the Kohana profiler showed for one catalog page. Fifty posts on the page. Nothing changed in the code. The page took two seconds because there was more data than in spring, and the code was written for spring. $post->author->name in a loop. One query for the list of posts, then one more for the author of every post, inside the foreach. The line looks innocent, and that is the problem: lazy loading hides the price. You write the relation, you go home early, and the bill comes in six months. ...

November 12, 2014 · 2 min · Murat Useinov

HMVC in Kohana: a request inside a request

Request::factory('widgets/stats') inside a controller. A colleague looked at this line last week and asked the question I hear most often about Kohana: you already have a request, why make another one? I keep answering it at the desk. So I will write it down once. Short notes, mostly backend, mostly PHP. This is the first. The answer is composition. Take a dashboard. A stats block, a recent orders block, a notifications block. Each one needs its own data and its own logic. You can put all of it into one action. It works. In a month it is 300 lines and nobody wants to open it. ...

November 10, 2014 · 2 min · Murat Useinov