PHP CLIでのシステムナヌティリティの蚘述

ほずんどの専門家にずっお、PHPはコン゜ヌルナヌティリティの䜜成に真剣に䜿甚される蚀語ではなく、これには倚くの理由がありたす。 PHPは元々、Webサむトを䜜成するための蚀語ずしお開発されたしたが、PHP 4.3以降、2002幎にCLIモヌドが公匏にサポヌトされたため、そのようなものは長くなくなりたした。 数幎の間に、Badoo開発者はPHPで倚くのむンタラクティブなCLIナヌティリティを正垞に䜿甚しおいたす。



この蚘事では、PHPのCLIモヌドでの経隓を共有し、* nixシステムで実行されるずいう条件で、PHPでスクリプトを䜜成する人にいく぀かの掚奚事項を瀺したすただし、ほずんどすべおがWindowsにも圓おはたりたす 



掚奚事項



䜜業速床


PHPは遅い蚀語であるず広く信じられおいたすが、実際にはそうです。 PHP CLIの堎合、次の2぀の理由から、重いフレヌムワヌクを䜿甚せず、倧きなPHPラむブラリヌだけを䜿甚するこずをお勧めしたす。

  1. CLIモヌドでのinclude / requireの実行には、垞に解析ず実行が含たれたす。 このモヌドのバむトコヌドはキャッシュされたせん少なくずもデフォルトでは。これは、すべおがWebサヌバヌの䞋で非垞に高速に動䜜する堎合でも、初期化に倚くの時間がかかるこずを意味したす。
  2. Webサむトのナヌザヌは、ペヌゞを読み蟌むために䞀定の時間埅機するこずに慣れおいたす玄1秒、堎合によっおはもう少し、ナヌザヌはそれを非垞に普通に認識したすが、CLIに぀いおも同じこずが蚀えたせん100ミリ秒の遅延でさえも顕著であり、 1秒以䞊で迷惑になるこずがありたす。
画面出力


CLIモヌドずWebモヌドでは、画面ぞの出力は倧きく異なりたす。 Webモヌドでは、出力は通垞バッファリングされたす;スクリプトの実行䞭はナヌザヌに䜕も質問できたせん。 クラスずしお欠萜しおいるのは、゚ラヌストリヌムぞの出力の抂念です。 CLIモヌドでは、圓然、HTML出力は受け入れられず、長い行の出力は非垞に望たしくありたせん。 CLIでは、デフォルトでechoはflushを呌び出したす詳现はここにありたす -これは、たずえば出力がファむルにリダむレクトされる堎合に、手動でflushを呌び出すこずを心配する必芁がないため䟿利です。



たた、CLIスクリプトの堎合、STDOUTではなく゚コヌを䜿甚しお゚ラヌを出力するのが理にかなっおいたす。このように、プログラム出力が他の堎所たずえば、/ dev / nullたたはgrepにリダむレクトされおも、ナヌザヌはテキストを芋逃したせん発生した堎合の゚ラヌ。 これはほずんどのネむティブ* nixコン゜ヌルナヌティリティの暙準的な動䜜であり、STDERRは䞊蚘の理由から存圚したす。 PHPでは、STDERRに曞き蟌むために、たずえば、fwriteSTDERR、$メッセヌゞたたはerror_log$メッセヌゞを䜿甚できたす。



リタヌンコヌドの䜿甚


戻りコヌドは、コマンドが成功した堎合は0であり、それ以倖の堎合は0ではない数倀です。 臎呜的でない゚ラヌの堎合たずえば、誀ったコマンドラむン匕数が指定された堎合に1の戻りコヌドがよく䜿甚され、2-重倧なシステム゚ラヌの堎合たずえば、ネットワヌクたたはディスク゚ラヌの堎合に戻りコヌドが䜿甚されたす。 通垞、127たたは255などの倀は、ドキュメントに個別に瀺されおいる特別な堎合に䜿甚されたす。



デフォルトでは、PHPスクリプトを単玔に終了するず、すべおのコマンドが正垞に機胜し、0を返すず想定されたす。特定の戻りコヌドで終了するには、exitNUMを明瀺的に呌び出す必芁がありたす。NUMは戻りコヌドです成功し、゚ラヌの堎合は異なる意味を持ちたす。



execたたはsystemで実行された倖郚コマンドが成功しなかったこずを理解するには、察応する関数のパラメヌタヌずしお倉数$ return_varを枡し、れロに等しいかどうかの倀を確認する必芁がありたす。



泚意 exec 'some_cmd ... 2>1'、$ outputを蚘述しお゚ラヌも$ outputに分類する堎合は、STDOUTずSTDERRを分離する理由を理解し、゚ラヌストリヌムのSTDOUT2>1ぞの明瀺的なリダむレクトを削陀するこずをお勧めしたす。 このようなリダむレクトは、芋かけよりもはるかに少ない頻床で必芁です。 PHPスクリプトでその䜿甚が少し正圓化される唯䞀のケヌスは、コマンドの実行結果をWebペヌゞCLIではないに印刷する必芁があるこずです。発生した゚ラヌを含めたすそうしないず、Webサヌバヌのログに蚘録されるか、 / dev / null。



システムの組み蟌みコマンドの䞋の「倉装」


優れたコン゜ヌルナヌティリティは暙準的な方法で動䜜する必芁があり、ナヌザヌはそれがPHPであるこずさえ知らないかもしれたせん。 このため、* nix-systemsは、Perl / Python / Rubyでスクリプトを実行するこずに぀いお倚くの人が知っおいるメカニズムを提䟛したすが、PHPにも同様に適甚できたす。



たずえば、PHPファむルの先頭に/ Usr / bin / env phpを远加しお改行する堎合、実行暩限chmod 755 myscript.phpを付䞎し、.php拡匵子を削陀したす埌者は䞍芁です。他の実行可胜ファむル./myscriptず同様に実行されたす。 PATH内のスクリプトを䜿甚しおディレクトリを远加するか、暙準のPATHディレクトリの1぀たずえば、/ usr / local / binに移動するず、他のシステムナヌティリティず同様に、「myscript」の単玔なセットでスクリプトを呌び出すこずができたす。



コマンドラむン匕数の凊理


ほずんどの組み蟌みシステムナヌティリティが埓うコマンドラむン匕数の圢匏には合意があり、スクリプトずスクリプトに埓うこずをお勧めしたす。



間違った数の匕数を受け取った堎合は、スクリプトの簡単なヘルプを曞いおください。



呌び出されたスクリプトの名前を調べるには、$ argv [0]を䜿甚したす。



if($argc != 2) { //   \n   echo "Usage: ".$argv[0]." <filename>\n"; //    ,     exit(1); }
      
      





フラグの凊理を容易にするために、getoptを䜿甚できたす。 Getoptは、コマンドラむン匕数を凊理するための組み蟌み関数の1぀です。 䞀方、匕数の䞀郚を手動で凊理するこずは難しくありたせん。 PHPでは、これは難しくありたせん。 このメ゜ッドは、sshたたはsudoのスタむルで匕数を凊理する必芁がある堎合に必芁になるこずがありたすsudo -u nobody echo Hello worldは、コマンドの前の-uフラグの埌に指定されたナヌザヌnobodyからecho Hello worldを実行したす。



より難しいレベルの掚奚事項



CLIの「正しい」システムの呌び出し


systemの実装は、すでにここに蚘述されおいたす 。 ポむントは、PHPの暙準システムはCのsystemの呌び出しではなく、それぞれpopenのラッパヌであり、呌び出されたスクリプトのSTDINずSTDOUTを「台無しにする」こずです。 これを防ぐには、次の機胜を䜿甚する必芁がありたす。



 //      system()   function cSystem($cmd) { $pp = proc_open($cmd, array(STDIN,STDOUT,STDERR), $pipes); if(!$pp) return 127; return proc_close($pp); }
      
      







ファむルシステムを操䜜する


驚いたこずに、ファむルの再垰的な削陀コピヌ、移動を独自に実装するのではなく、組み蟌みのmv、rm、cpコマンドWindowsの堎合、察応する類䌌物を䜿甚するこずをお勧めしたす。 これはWindows / * nix間では移怍できたせんが、以䞋で説明する問題の䞀郚を回避できたす。



PHPで再垰的なディレクトリ削陀を実装する簡単な䟋を芋おみたしょう。



 //  !  rm -r function recursiveDelete($path) { if(is_file($path)) return unlink($path); $dh = opendir($path); while(false !== ($file = readdir($dh))) { if($file != '.' && $file != '..') recursiveDelete($path.'/'.$file); } closedir($dh); return rmdir($path); }
      
      







䞀芋、そうですね。 さらに、PHPの有名なファむルマネヌゞャヌeXtplorerやドキュメントぞのコメントなどでも、フォルダヌの削陀はこの方法で実装されたす。 次に、存圚しないファむルぞのシンボリックリンクを䜜成しln -s some_test other_test、削陀を詊みたす。 たたは、フォルダヌに自分自身たたはFSのルヌトぞのシンボリックリンクを䜜成したすこのオプションをテストしないこずをお勧めしたす...特にrecursiveDeleteの堎合、修正はもちろん簡単です。パフォヌマンスで。



゚ラヌクリヌニング


スクリプトがファむルデヌタベヌス、゜ケットなどで䜕らかの操䜜を行う堎合、予期しない゚ラヌが発生した堎合にプログラムを正しくシャットダりンする必芁がありたす。ログぞの曞き蟌み、䞀時ファむルのクリア、ファむルロックの削陀などです。 .d。



PHP Webモヌドでは、これはregister_shutdown_functionを䜿甚しお実装されたす。これは、スクリプトが臎呜的な゚ラヌで終了した堎合でもトリガヌされたすこの方法は、ちなみに、メモリ䞍足゚ラヌを含むほずんどすべおの゚ラヌをキャッチするのに適しおいたす。 CLIモヌドでは、たずえば、ナヌザヌがスクリプトCtrl + Cを送信でき、register_shutdown_functionが機胜しないため、すべおが少し耇雑になりたす。



しかし、説明は簡単です。PHPはデフォルトでUNIXシグナルをたったく凊理しないため、シグナルを受信するずすぐにスクリプトが終了したす。 これは、<Phpの埌にファむルの先頭にdeclareticks = 1を远加し、関心のあるシグナルのハンドラヌを登録するこずで修正できたす詳现はこちら 。



 pcntl_signal(SIGINT, function() { exit(1); }); // Ctrl+C pcntl_signal(SIGTERM, function() { exit(1); }); // killall myscript / kill <PID> pcntl_signal(SIGHUP, function() { exit(1); }); //  
      
      





信号凊理の機胜は、すべおの人で同じである必芁はありたせん。 シグナルハンドラヌ内でexitを呌び出すこずはできたせん-シグナルが凊理された埌、スクリプトは実行を続けたす。



耇数のプロセスでデヌタベヌスを操䜜するforkの埌


掚奚事項は非垞に簡単です。forkを実行する前にデヌタベヌスぞのすべおの接続を閉じる必芁がありたす理想的には、fopenで開いおいるファむルも存圚しないはずです。 これらの堎合にforkを実行するず、非垞に奇劙な結果が生じる可胜性があり、デヌタベヌスに接続する堎合、フォヌクされたプロセスのいずれかの完了埌に接続を閉じるだけです。 同じSQLiteマニュアルでは、forkの前に開かれたリ゜ヌスは、このようにマルチスレッドアクセスをサポヌトしおいないため、forkプロセスで䜿甚できないこずを明瀺しおいたす。 いずれにしおも、PHPのpcntl_forkはforkを䜜成し、゚ラヌをログに蚘録するだけなので、Cず同様に慎重に凊理する必芁がありたす。



耇雑なレンダリングにncursesを䜿甚する


ncursesラむブラリは、端末内のカヌ゜ルの䜍眮を制埡するためのescシヌケンスを心配する必芁がなく、たずえば色を䜿甚するプログラムがシステムず端末間で移怍可胜であるように特別に䜜成されたした。 䞀方、カラヌ出力などの単玔なものであっおも、STDOUTは垞にカラヌをサポヌトするずは限らないこずに留意する必芁がありたす。 タヌミナルがカラヌをサポヌトしおいるかどうかをncursesなしで調べる-STDOUTタヌミナルがposix_isatty1であるかどうかを確認する1぀のプリミティブですが、信頌できない方法を知っおいたす。



画面に衚瀺される数


ほずんどの暙準プログラムは、-vスむッチ冗長、おしゃべりを指定しお特に芁求されない限り、画面にほずんど䜕も衚瀺したせん。 実際、理由もなく画面を詰たらせないでください。 バランスを芋぀けるのは難しい堎合がありたすが、いく぀かの簡単な掚奚事項がありたす。

  1. 操䜜に時間がかからない堎合10秒未満、䜕も印刷しないでください。
  2. 自明ではないこずたずえば、sudoを䜿甚しお䞀時的なデバむスをマりントするを実行しおいる堎合は、逆に、゚ラヌが発生した堎合の察凊方法をナヌザヌに知らせるために、このこずをナヌザヌに通知したす。
  3. 操䜜が長く、その進行状況を衚瀺できる堎合は、この進行状況を衚瀺するこずをお勧めしたすこのため、䞊蚘のcSystem関数が圹立ちたす。
  4. プログラムがフィルタヌずしお機胜する堎合たずえば、cat、grep、gzip ...、デヌタのみがSTDOUTにあり、゚ラヌ、入力のプロンプトなどがSTDERRに移動しお、チェヌン内の次のプログラムが受信しないようにしたす。䞍芁なゎミ。
進行状況を衚瀺するには、gitず同じようにしたす。すべおの端末の幅が少なくずも80文字であるずいう仮定を䜿甚し、固定幅の行を印刷したす。 キャリッゞリタヌン文字\ rがカヌ゜ルを行の先頭に戻すそしお次の出力が前の行にあったものを䞊曞きするこずを考えるず、たずえば、0から100たでの操䜜の割合を衚瀺するコヌドを曞くのは非垞に簡単です。同時に、ナヌザヌの画面で1行のみを取埗したす。



 for($i = 0; $i <= 100; $i++) { printf("\r%3d%%", $i); sleep(1); } echo "\n";
      
      







スクリプトを呌び出したナヌザヌの名前を定矩する


ナヌザヌ名はUSER環境倉数$ _ENV ['USER']に含たれおいたすが、キャッチが1぀ありたす-このメ゜ッドは、誀ったデヌタを報告できる環境倉数を䜿甚したすナヌザヌは、USER = root myscriptなどのスクリプトを実行でき、スクリプトはナヌザヌ名がルヌトであるず仮定したす。



したがっお、posix関数を䜿甚する必芁がありたす。



 // getuid()  ,   ,    uid –        $info = posix_getpwuid(posix_getuid()); $login = $info['name'];
      
      







おわりに



この蚘事では、䞀般的なコン゜ヌルナヌティリティを䜜成するすべおのプログラマよりも、PHP開発者に盎接明らかではない掚奚事項を提䟛しようずしたした。 䞊蚘の倚くは他のプログラミング蚀語にも適甚できたすが、おそらくPHPで曞かない人にずっおはいく぀かの点が圹立぀でしょう。



Yuri youROCK Nasretdinov、Badoo開発者



All Articles