blog

Java、PHP、C++、MySQL、Apache、Linux、UnixなどのTechを紹介

PHP

PHPには、Linux、Mac、Windowsなどの異なるOS環境間で改行コードを内部的に自動で切り替えてくれるPHP_EOLという便利な定数が用意されている。Javaでの実装だとSystem.getProperty("line.separator")にあたると思う。PHP_EOLがPHPの内部ではどのように実装されているのか、いまさらながらPHP_EOLと改行コードについて書いてみた。

PHP_EOLが定義されているソースファイルをリーディングする

リーディングするソースコードのPHPバージョンはphp-5.3.1を使う。PHP_EOLの定義箇所は以下のヘッダファイルにあり、PHP_EOL以外の定義済み定数の大半もこのファイルで定義されている。

php-5.3.1/main/php.h の Line47 ~ 71あたり
#ifdef PHP_WIN32         

  #include "tsrm_win32.h"
    ・
    ・
  #define PHP_EOL "\r\n"
   // (OSがWindowsの場合に改行コードが\r\nになる)

#else
    ・ 
    ・ 
 #if defined(__MacOSX__) 
   // ※__MacOSX__このマクロはMacOS10では使われてない
   //   らしい。なのでここの条件分岐にMacOS10は入らない

   #define PHP_EOL "\r" 
    // (OSがMacOS9以前の場合に改行コードが\rになる) 

 #else

   #define PHP_EOL "\n" 
    // (OSがMacOS10、Linux、Unixなどの場合に\nになる) 

 #endif

#endif

このように、OS環境によって、if文で条件分岐し改行コードの文字表現を\r\n\r\nとdefineしているシンプルなソースコードである。わかりやすいように一覧表にまとめてみると以下の関係になり、ネットでも検索すれば同じような一覧内容は確認できる。

改行コード

各OS環境でPHP_EOLが出力する改行コードをASCIIコードで確認してみる

改行コードを標準出力しても分かりずらいので、PHPのord()関数をつかいASCIIコードに変換して出力してみたいと思う。(※Mac環境がないので、Linux、Windows環境のみで)

以下にASCIIコード一覧の抜粋があるが、そこにある太字のASCIIコードが返ってくることが予想できる。ここで問題なのがWindows環境であるCRLF(\r\n)である。そもそもCRLFというASCII文字は存在していない。いったいどのような値がかえるのか?

ASCIIコード

コマンドラインでスクリプトを実行した結果

下記、改行コードを生成するコマンドをOS環境を変えてコマンドラインから実行していってみる。またOS環境における差異を明確化させるために、strlen()関数で出力される改行コードの長さも測った。下記が結果内容である。
php -r 'echo ord(PHP_EOL);'  (改行コードをASCIIコードで出力)

Linux環境で実行した際の結果値:10
Windows環境で実行した際の結果値:13

php -r 'echo strlen(PHP_EOL);'  (改行コードの長さを出力)
Linux環境で実行した際の結果値:1
Windows環境で実行した際の結果値:2

これらの結果から、疑問であったWindows環境における改行コードのASCIIコードの値は13と出力された。ASCIIコード一覧と照らしてみると、13 = CR = \rになる。このような値が返ってきたのはCRLF自身が、ASCIIコードのCR(\r)とLF(\n)を並べて表現しているからである。現にstrlen()関数で長さを取得するとWindows環境(CRLF)では2という値がかえり、2byteの文字列であることがわかる。そのためord()関数にPHP_EOL定数がPHP内部でOS環境を判定して、\r\nをセットしても、先頭1byteの\r = 13が返ってくるというわけである。これはord()関数の異常というわけでなく、正常動作であった。

 
投稿日:2010/01/04 | カテゴリ:PHP | コメント・TrackBack:(0)
PHP

PHPで品質の高いプログラムを作製するのが、私の夢として持ちつづけている。プログラマの個人能力に影響されず品質を高めるにはどうすべきか? システマチックに自動で品質をチェックして、問題点(既存bug)を指摘してくれるツールがないかと、探してみた。 PSAT(the PHP static analysis tool)というツールを発見したが、ネットで利用している人は殆ど発見できず、とりあえず実験してみた。下記がセットアップ&検証までの情報である

導入方法

  1. rpmのダウンロード

  2. psat-0.1pre154-1.i386.rpm

    依存関係のある下記パッケージもダウンロードしておく

    aterm-2.4.2-1.i586.rpm
    sdf2-bundle-2.3.4pre15345-1.i586.rpm 
    strategoxt-0.17M2pre15559-1.i586.rpm
    
  3. Linux(Cent OS4.4)にインストール

    rpm -ivh aterm-2.4.2-1.i586.rpm
    rpm -ivh sdf2-bundle-2.3.4pre15345-1.i586.rpm
    rpm -ivh strategoxt-0.17M2pre15559-1.i586.rpm 
    rpm -ivh psat-0.1pre154-1.i386.rpm
    
  4. 解析方法

    psat -i ***.php

    オプション一覧
    
    -l 解析するターゲットとなるPHPファイルの指定
    -o 解析結果を標準出力ではなく、ファイル出力先
    -r バージョンの指定(PHP4:4、PHP5:5) 
    
  5. 解析結果内容

  6. target.phpというサンプルを使用

    psat -i target.php

    
    1. if ($a) {
    2.     //何らかの処理を行う
    3. } 
    4. 
    5. if (isset($a)) {
    6.     //何らかの処理を行う
    7. } 
    
    
    /** 
     * PSAT check (Correctness)
     * If(variable) to check 
     * the initialization of a variable
     */  
     if ($a){       } 
     if (isset($a)){       } 
    
    
    

    処理結果から分かるように、 問題の箇所があった場合(脆弱)にその箇所の直前にコメント分で 問題内容が挿入されるようだ。 ライン1のifは変数の正負判断しかしてないために、 ライン5のifと比べて、チェックが甘いといったところだろうか

  7. 解析結果内容(クラスの場合)

  8. targetClass.phpというサンプルを使用

    psat -r 4 -i targetClass.php

    
    1. class targetClass
    2. { 
    3.     public function test()
    4.     { 
    5.        //何らかの処理を行う
    6.     } 
    7. } 
    
     [ psat | error ] 
      targetClass.php: character 'p' 
      unexpected at line 5, column 5 
     
     [ psat | error ] {
     [ psat | error ] 
      public function test()
      [ psat | error ]  
    
    

    今回あえて、PHP4では実装されていない、メソッドの アクセス属性"public"をつけ実行してみたが、 今回の処理結果はツールのエラーで終わってしまった。 ためしに、rオプションをPHP5を指し示す-r 5で 行ってみたが同じくツールのエラーで終わってしまった

    結論

    psatに関して、まだ実務レベルでは利用するのは難しそうだ、今後に期待しよう

 
投稿日:2009/03/03 | カテゴリ:PHP | コメント・TrackBack:(0)