PHPでハマったことをPHPの落とし穴と題して逐次書いていきたいと思います。

問題

ログインができない!動いている環境とPHPのバージョンも合わせたのになぜ!?

$_REQUEST$_COOKIEの値が入ってないぞ。

原因

$_REQUESTの中身はphp.iniのrequest_orderディレクティブの値に依存する。デフォルトではCookieのCが含まれてない。

PHP: コア php.ini ディレクティブに関する説明 - Manual

解決策

php.iniのrequest-orderディレクティブにCを追加する?

そうではなくCookieを使いたい場合はこういった環境依存のある$_REQUESTではなく$_COOKIEを使うべき。コードの意図も伝わりやすい。

しかし、一度大量に混入したcookie用途の$_REQUEST利用を全て修正するのは難しそうだ。単純にreplaceはできないので$_REQUESTでgrepして、文脈から判断するしかなさそうだ。

明確な理由がない限り$_REQUESTはおすすめできない。$_GET, $_POST, $_COOKIEを使うべきだ。

PHPのスーパーグローバル変数($_から始まるやつ)の扱いは名前が表す通り注意が必要だと思いました。

関連:レガシーPHP改善日記シリーズ

怖話リゾートバイトが途中で切れるバグを直しました。

PostgreSQLの調子で使ってたMySQLのtext型の最長を超えてるだけだった。

text: 65535Byte
mediumtext: 16777215Byte
longtext: 4294967295Byte

リゾートバイトは120KBぐらいの長編なのでmediumtextに変えて対応。

# RAILS_ROOT/db/migrate/20120127081325_alter_body_to_mediumtext_stories.rb 
class AlterBodyToMediumtextStories < ActiveRecord::Migration
  def up
    if Rails.env.production?
      execute 'ALTER TABLE stories MODIFY body mediumtext COLLATE utf8_unicode_ci;'
    end
  end

  def down
    if Rails.env.production?
      execute 'ALTER TABLE stories MODIFY body text COLLATE utf8_unicode_ci;'
    end
  end
end

超えてもエラーが出ないから気づかなかったなあ。