2019-02-28に更新

PHP5.3のプロジェクトをPHP7.2にした時の流れ

誰かが作っていたものを10年くらい前に引き継いで今も継続している案件がある。何度かサーバーは変わったが、とはいえかなり古いものなのでPHP5.3で動作していた。
ただ、お客さんの依頼で使用したいパッケージで5.3では動かないものが出てきたので、サーバー移転ついでにPHP7.2にした話。

環境

  • フレームワークなし
  • composerあり

やり方

基本的にはとりあえずPHP7.2の環境で動作させてひたすら修正していくだけ。ローカルでも一時的に借りたVPSとかでも何でも良い。自分の場合はDockerを使った。Dockerの詳細は興味ない人もいると思うので最後の方に書く。

PHP5.3というのがわりと微妙なところで、結構面倒な部分が出てくる。大きな山となったのは下記2つだった。

register_globals

古いプロジェクトなのでregister_globalsが有効化されており、しっかりとこの機能を利用して作られてしまっている。今の人は知らないかもしれないが、$_GETとか$_POSTとかで受け取る値が自動的に変数となってしまう機能。例えば$_GET['mode']とかがあったら$mode変数として使える便利機能。

http://php.net/manual/ja/security.globals.php

これはPHP5.4で削除されているので当然プロジェクト全体でエラーになる。(特にガッツリ時間をもらっているプロジェクトでもないので、新規機能追加とかは行っているがこの辺のリファクタリングは行われていない)

対処方法

extract($_POST, EXTR_SKIP);
extract($_GET, EXTR_SKIP);

解決方法としては一番ひどい方法だと思うが、動かなくなるよりはまし。というか元々ひどすぎるのでそれほど変わらない。そもそも今後フレームワーク化してこういった処理は全部消したいので、とりあえず段階的な対応。

MySQL接続

mysql_connectと関連関数が使われていた。これはPHP7では削除されるので、PDOに置き換える必要がある。

しかし、前述したとおりフレームワークが使われていないのでmysql_queryをラップした関数が色々と作成されており、ほとんどのページでその関数群が使われている。基本的にはPHP7にするとほとんどのページが動かなくなる。徐々にEloquentに置き換えてはいたが、そんなに少ない量でもないため全部をすぐ置き換えるのには無理がある。

そのため、消えたmysql_*関数を全部用意することにした。

define('MYSQL_ASSOC', 'assoc');
$conn = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $user, $pass);

function mysql_query($query)
{
    global $conn;

    return $conn->query($query);
}

function mysql_fetch_assoc($statement)
{
    return $statement->fetch(PDO::FETCH_ASSOC);
}

function mysql_fetch_array($statement, $mode)
{
    return mysql_fetch_assoc($statement);
}

function mysql_numrows($statement)
{
    return $statement->rowCount();
}

function mysql_insert_id()
{
    global $conn;

    return $conn->lastInsertId();
}

function mysql_free_result($statement)
{
    $statement->closeCursor();
}

function mysql_error()
{
    global $conn;

    $info = $conn->errorInfo();
    if (isset($info[1])) {
        return $info[2];
    }
    return null;
}

function mysql_errno()
{
    global $conn;

    $info = $conn->errorInfo();
    if (isset($info[1])) {
        return $info[1];
    }
    return null;
}

function mysql_close($link = null)
{

}

解決方法としては一番ひどい方法だと思うが、動かなくなるよりはまし。というか元々ひどすぎるのでそれほど変わらない。そもそも今後フレームワーク化してこういった処理は全部消したいので、とりあえず段階的な対応。

ちなみに今回は使っていないので詳しくは知らないが
dshafik/php7-mysql-shim: A shim for ext/mysql in PHP 7+
というのもあるらしい。

PEAR

PEARは古いプログラムもあるので、下記の様な処理があると全部エラーになる。

$var =& Foo::factory();

上記の&がエラーになるので削除していく。

まとめ

基本的な対応は上記だが、あとはバージョンの違いでちょっとしたエラーとかも出るので見つけ次第修正していく。本当はテストである程度網羅されている事が望ましいが、古いスクラッチプロジェクトなので当然テストもない。(最近はちょこちょこCI含め追加しているが全く足りない)

一通り確認したので先日PHP7.2が走っているサーバーに移転を完了した。

ただし、プロジェクトがひどすぎる関係でこれは完成でなくあくまでも分岐点なので、最終的にはLaravelを入れて全部そちらに移行などしたい。既に一部の完全に分離できるバッチ処理等はこのプロジェクトに組み込まずGoで書いていたりする。

マイクロサービス化は色々とメリットデメリットがあげられているが、こういった古すぎるプロジェクトに関しては可能なところを分離していくと要らない部分を捨てやすくて良い。(もちろんやり過ぎはよくないと思う)

おまけでDocker

FROM php:7.2-apache

RUN apt-get update && apt-get install -y git zlib1g-dev
RUN curl -sS https://getcomposer.org/installer | php
RUN mv composer.phar /usr/local/bin/composer
RUN a2enmod rewrite
RUN docker-php-ext-install pdo_mysql mbstring zip

```yml:docker-compose.yml
version: '2'
volumes:
mysql_data:
driver: 'local'
services:
mysql:
image: mysql:5.7.19
volumes:
- mysql_data:/var/lib/mysql
- ./mysql:/etc/mysql/conf.d
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=true

phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
- PMA_HOST=mysql
- PMA_USER=root
- PMA_PASSWORD=
ports:
- 8201:80

app:
image: myapp/php:7.2
depends_on:
- mysql
working_dir: /var/www/html
volumes:
- .:/var/www/html
- ./php/php.ini:/usr/local/etc/php/conf.d/myphp.ini
ports:
- "8200:80"
tty: true
stdin_open: true


```ini:php.ini log_errors = On error_log = /dev/stderr date.timezone = "Asia/Tokyo"

conf:config.cnf [mysqld] sql_mode=''

ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント