Staying on CodeIgniter 3 done responsibly
The framework core is the easy part
Bringing the system folder up to the latest CodeIgniter 3 release is usually quick, provided nobody edited core files. The first thing we do is compare your system folder with a clean copy of the same release. Any differences are changes someone made directly in the framework, and each one has to be understood and moved into an extension class in application/core before the core can be replaced.
What newer PHP releases break
The harder work is in application code and third-party libraries. The trouble spots are familiar to us: libraries that still call the removed mysql functions or mcrypt, each() loops and create_function, count() on values that are not arrays, string and number comparisons that now behave differently, and required parameters placed after optional ones. Recent PHP releases also deprecate dynamic properties, and CodeIgniter 3 relies on those when the loader attaches a model or library to a controller. We run the code through static analysis for the target release, turn error reporting fully on in staging, and click through every screen with logging enabled, because much of this only shows at runtime.
Hardening without rewriting
Older CodeIgniter 3 projects share a set of weak points. Queries are built by joining strings with input from the request. Passwords are stored with MD5 or SHA1. The global XSS filter is trusted in place of escaping output. The encryption key is empty or the same in every environment, and sessions sit in a folder other accounts can read. None of these needs a new framework to fix. We replace string-built queries with bindings or the Query Builder, migrate passwords to password_hash on next login, add CSRF protection and escaping in views, and move sessions to the database or Redis.
Bringing in Composer
CodeIgniter 3 can load Composer packages through a single config setting. Turning it on lets us retire libraries that were pasted into application/libraries or third_party years ago and replace them with maintained packages for mail, PDFs, spreadsheets and payment gateways. It also opens the door to PHPUnit, so the riskiest calculations can finally be covered by tests.
Knowing when to stop
We advise staying on CodeIgniter 3 when the application is stable, change requests are modest and the code can run on a supported PHP release. We advise planning a move when you need features the old structure fights against, when a required library has no maintained version, or when your compliance team asks for a framework under active development. For code that is older still, or only loosely based on a framework, see legacy PHP modernization.