Recover the source first. Get the deployed tree into version control, reproduce
a build on a clean machine, and reconcile it with whatever repository exists. Until that is true
nothing else can be done safely, and it is usually a week rather than a project.
Then migrate the runtime, in a copy. The application runs on the new version alongside
the old one until it behaves identically. Nobody switches on a Friday. This is where the mysql_*
call count from day one turns into a schedule.
Close the security gaps as you go. Parameterised queries, password rehashing on
login, secrets out of the tree. These are done during the migration rather than as a second project,
because the code is already open.
Where a piece genuinely cannot be touched, route around it. Occasionally one
capability is too central to edit safely — pricing, invoicing, anything every transaction
passes through. That one moves out to a small service beside the application, reading through
a seam, with nothing inside the original changed. See the bypass.