プログラミングや電子工作などについての記事がほとんどです

PHP 文字列を比較するときの注意(パスワード認証の実装など)

4 件のコメント

先日PHPをいじっているときに躓いたところについてメモ。txtファイルから引っ張ってきた文字列と、フォームの送信データの一致を確認したいときに上手くいかなくて1時間ほど悩みました。例えばパスワードの一致不一致を判定するときなんかにそのまま使えそうなノウハウですね。同じことで困ってるどなたかの役に立つと信じてシェアします。

文字列比較の演算子は===を使う

文字列を比較する際に、他の言語と同様に==を使っていたのですが、どうもよくないらしいです。 この演算子を使っていると数値と文字列の比較をする際に、文字列が数値に変換されるようです。

では、何を使うか。===を使うのです。他の言語ではあまり見慣れないのですが、これも同値性を返す演算子です。 二つの違いは、型の相互変化を行うかどうかにあります。 (PHP: 比較演算子 - Manual) ==は型の相互変換を行ったうえで比較をし、===は同じ型の変数を比較することを前提に比較をします。 ですので、文字列同士を比較する際には、===を使う必要があるのです。

参考サイト
素晴らしき自動的な世界~或いは「型のない」世界~ - がるの健忘録

余計な半角スペースなどを取り除く

今回特に悩んだのはこの部分でした。 テキストファイルから文字列を抜き出すときに半角スペースが一緒に取り出されてしまうことがあります。 これをフォームに直接入力したものを比較すると一致の判定が上手くいきません。

例えば、フォームから値を取ってきて、テキストから読みだした文字列$sampleと比較する「$_POST('input') === $sample」みたいな場合ですね。 フォームで、「pass」と入力し、$sampleのテキストも「pass」を読み込みました。 どうしてかわからないけれども、echoで表示したところ$sampleの中身は「pass 」というもので、そりゃあ一致しないよなという自体でした。 この半角スペースがどう入ったかよくわからないのですが、そろえる為に入力した文字に半角スペースを加える記述をしたのですが、結果はfalse。 文字コードが違うのか、単純な半角スペースではないのかどうかわかりませんが、上手くいきませんでした。 よくよく考えたら、半角スペースを加えるよりは、取り除く方が素直な解決法だと思いました。 ここで使える関数がtrim()というものです。(PHP: trim - Manual) これは引数に与えた文字列の最初と末尾にあるスペースやタブなどを除去してくれます。 trim($sample)としてやることで、「pass 」が「pass」になってくれます。 こうして先ほどの比較文はtrueと上手くいったのでした。 trimは汎用性の高い文字処理関数なので積極的に取り入れていきたいですね。

いきなりはじめるPHP~ワクワク・ドキドキの入門教室~
谷藤賢一
リックテレコム
売り上げランキング: 3,435

【2016/10/24追記】改行コードなどが文字列の中ほどにある場合

上でご紹介したパターンでは文字列の最後に半角スペースが存在するというものでした。 txtファイルから読み出した場合改行(\n)が含まれることが多いはずです。 こちらもうまく読み出しのタイミングでパースできていれば問題ないのですが、比較の際に邪魔になることがあります。 改行も文字列の末尾にあれば問題ないのですが、文の間にちょくちょく挟まるパターンだとtrim()が適用できません。 文字列の頭、末尾以外にある文字を置き換える方法について説明します。

「trim(string $str)」は$strの開始や末尾のタブやスペース、キャリッジリターンなどを削除してくれる関数です。すなわち"hoge や" hoge"、あるいは"hoge\n"などはうまく"hoge"にしてくれます。 ただし"hogehoge hogehoge"のように文字列の最初と最後以外に消したいものがあっても消すことはありません。 こういうときにはstr_replace()を使うとよいでしょう。 たとえばstr_replace( " ", "", "hogehoge hogehoge")としてやると"hogehogehogehoge"のように空白を出力してくれます。 第一引数が検索文字列、第二引数が置換文字列、第三引数は検索・置換対象の文字列です。
PHP: str_replace - Manual

4 件のコメント :

  1. 初コメ失礼します。
    参考になりました。
    私もtxtファイルから読み込んだ値との比較でどうし一致事象が発生、【余計な半角スペースなどを取り除く】からヒントを得て無事可決しました。
    私の場合は、改行コードが悪さ?をしていたらしく、「str_replace」で改行コードを削除したらうまくいきました。

    返信削除
    返信
    1. コメントいただきありがとうございます。
      参考になったとのご感想、記事執筆の励みになります。

      改行コードも文字列比較における問題の要素としては可能性が十分有り得そうですね。
      今回私がご紹介したtrim関数では文字列のはじめと終わりのスペースや改行にしか対応できなかったので、コメントを参考にstr_replace関数を用いた例も記事に追記させていただきました。

      削除
  2. 返信ありがとうございます。そして記事加執ご苦労さまです。
    私も1時間以上は悩んで試行錯誤していましたが、原因が変わってしまえば何のことはなく...。
    同じ事象が発生した時には悩まなくて済みますし、自分が1つ賢くなった?と言い聞かせています。
    またお邪魔しま~す。

    返信削除
    返信
    1. 私もプログラミングでは問題の原理を理解できたときに成長があるような気がしています。

      今後も技術関係の記事を更新していくつもりですので是非読んでいただければ幸いです。

      削除